Commit 11b31250 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'acpi-6.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm

Pull ACPI updates from Rafael Wysocki:
 "These update the ACPICA code in the kernel to upstream version
  20240827, add support for ACPI-based enumeration of interrupt
  controllers on RISC-V along with some related irqchip updates, clean
  up the ACPI device object sysfs interface, add some quirks for
  backlight handling and IRQ overrides, fix assorted issues and clean up
  code.

  Specifics:

   - Check return value in acpi_db_convert_to_package() (Pei Xiao)

   - Detect FACS and allow setting the waking vector on reduced-hardware
     ACPI platforms (Jiaqing Zhao)

   - Allow ACPICA to represent semaphores as integers (Adrien Destugues)

   - Complete CXL 3.0 CXIMS structures support in ACPICA (Zhang Rui)

   - Make ACPICA support SPCR version 4 and add RISC-V SBI Subtype to
     DBG2 (Sia Jee Heng)

   - Implement the Dword_PCC Resource Descriptor Macro in ACPICA (Jose
     Marinho)

   - Correct the typo in struct acpi_mpam_msc_node member (Punit
     Agrawal)

   - Implement ACPI_WARNING_ONCE() and ACPI_ERROR_ONCE() and use them to
     prevent a Stall() violation warning from being printed every time
     this takes place (Vasily Khoruzhick)

   - Allow PCC Data Type in MCTP resource (Adam Young)

   - Fix memory leaks on acpi_ps_get_next_namepath() and
     acpi_ps_get_next_field() failures (Armin Wolf)

   - Add support for supressing leading zeros in hex strings when
     converting them to integers and update integer-to-hex-string
     conversions in ACPICA (Armin Wolf)

   - Add support for Windows 11 22H2 _OSI string (Armin Wolf)

   - Avoid warning for Dump Functions in ACPICA (Adam Lackorzynski)

   - Add extended linear address mode to HMAT MSCIS in ACPICA (Dave
     Jiang)

   - Handle empty connection_node in iasl (Aleksandrs Vinarskis)

   - Allow for more flexibility in _DSM args (Saket Dumbre)

   - Setup for ACPICA release 20240827 (Saket Dumbre)

   - Add ACPI device enumeration support for interrupt controller
     probing including taking dependencies into account (Sunil V L)

   - Implement ACPI-based interrupt controller probing on RISC-V
     (Sunil V L)

   - Add ACPI support for AIA in riscv-intc and add ACPI support to
     riscv-imsic, riscv-aplic, and sifive-plic (Sunil V L)

   - Do not release locks during operation region accesses in the ACPI
     EC driver (Rafael Wysocki)

   - Fix up the _STR handling in the ACPI device object sysfs interface,
     make it represent the device object attributes as an attribute
     group and make it rely on driver core functionality for sysfs
     attrubute management (Thomas Weißschuh)

   - Extend error messages printed to the kernel log when
     acpi_evaluate_dsm() fails to include revision and function number
     (David Wang)

   - Add a new AMDI0015 platform device ID to the ACPi APD driver for
     AMD SoCs (Shyam Sundar S K)

   - Use the driver core for the async probing management in the ACPI
     battery driver (Thomas Weißschuh)

   - Remove redundant initalizations of a local variable to NULL from
     the ACPI battery driver (Ilpo Järvinen)

   - Remove unneeded check in tps68470_pmic_opregion_probe() (Aleksandr
     Mishin)

   - Add support for setting the EPP register through the ACPI CPPC
     sysfs interface if it is in FFH (Mario Limonciello)

   - Fix MASK_VAL() usage in the ACPI CPPC library (Clément Léger)

   - Reduce the log level of a per-CPU message about idle states in the
     ACPI processor driver (Li RongQing)

   - Fix crash in exit_round_robin() in the ACPI processor aggregator
     device (PAD) driver (Seiji Nishikawa)

   - Add force_vendor quirk for Panasonic Toughbook CF-18 in the ACPI
     backlight driver (Hans de Goede)

   - Make the DMI checks related to backlight handling on Lenovo Yoga
     Tab 3 X90F less strict (Hans de Goede)

   - Enforce native backlight handling on Apple MacbookPro9,2 (Esther
     Shimanovich)

   - Add IRQ override quirks for Asus Vivobook Go E1404GAB and MECHREV
     GM7XG0M, and refine the TongFang GMxXGxx quirk (Li Chen, Tamim
     Khan, Werner Sembach)

   - Quirk ASUS ROG M16 to default to S3 sleep (Luke D. Jones)

   - Define and use symbols for device and class name lengths in the
     ACPI bus type code and make the code use strscpy() instead of
     strcpy() in several places (Muhammad Qasim Abdul Majeed)"

* tag 'acpi-6.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (70 commits)
  ACPI: resource: Add another DMI match for the TongFang GMxXGxx
  ACPI: CPPC: Add support for setting EPP register in FFH
  ACPI: PM: Quirk ASUS ROG M16 to default to S3 sleep
  ACPI: video: Add force_vendor quirk for Panasonic Toughbook CF-18
  ACPI: battery: use driver core managed async probing
  ACPI: button: Use strscpy() instead of strcpy()
  ACPI: resource: Skip IRQ override on Asus Vivobook Go E1404GAB
  ACPI: CPPC: Fix MASK_VAL() usage
  irqchip/sifive-plic: Add ACPI support
  ACPICA: Setup for ACPICA release 20240827
  ACPICA: Allow for more flexibility in _DSM args
  ACPICA: iasl: handle empty connection_node
  ACPICA: HMAT: Add extended linear address mode to MSCIS
  ACPICA: Avoid warning for Dump Functions
  ACPICA: Add support for Windows 11 22H2 _OSI string
  ACPICA: Update integer-to-hex-string conversions
  ACPICA: Add support for supressing leading zeros in hex strings
  ACPICA: Allow for supressing leading zeros when using acpi_ex_convert_to_ascii()
  ACPICA: Fix memory leak if acpi_ps_get_next_field() fails
  ACPICA: Fix memory leak if acpi_ps_get_next_namepath() fails
  ...
parents 64dd3b6a 3dd2fcf4
......@@ -6,28 +6,7 @@
* Copyright (C) 2014 ARM Ltd.
*/
#include <linux/acpi.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/pci.h>
#include <linux/pci-acpi.h>
#include <linux/pci-ecam.h>
#include <linux/slab.h>
#ifdef CONFIG_ACPI
/*
* Try to assign the IRQ number when probing a new device
*/
int pcibios_alloc_irq(struct pci_dev *dev)
{
if (!acpi_disabled)
acpi_pci_irq_enable(dev);
return 0;
}
#endif
/*
* raw_pci_read/write - Platform-specific PCI config space access.
......@@ -61,173 +40,3 @@ int pcibus_to_node(struct pci_bus *bus)
EXPORT_SYMBOL(pcibus_to_node);
#endif
#ifdef CONFIG_ACPI
struct acpi_pci_generic_root_info {
struct acpi_pci_root_info common;
struct pci_config_window *cfg; /* config space mapping */
};
int acpi_pci_bus_find_domain_nr(struct pci_bus *bus)
{
struct pci_config_window *cfg = bus->sysdata;
struct acpi_device *adev = to_acpi_device(cfg->parent);
struct acpi_pci_root *root = acpi_driver_data(adev);
return root->segment;
}
int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
{
struct pci_config_window *cfg;
struct acpi_device *adev;
struct device *bus_dev;
if (acpi_disabled)
return 0;
cfg = bridge->bus->sysdata;
/*
* On Hyper-V there is no corresponding ACPI device for a root bridge,
* therefore ->parent is set as NULL by the driver. And set 'adev' as
* NULL in this case because there is no proper ACPI device.
*/
if (!cfg->parent)
adev = NULL;
else
adev = to_acpi_device(cfg->parent);
bus_dev = &bridge->bus->dev;
ACPI_COMPANION_SET(&bridge->dev, adev);
set_dev_node(bus_dev, acpi_get_node(acpi_device_handle(adev)));
return 0;
}
static int pci_acpi_root_prepare_resources(struct acpi_pci_root_info *ci)
{
struct resource_entry *entry, *tmp;
int status;
status = acpi_pci_probe_root_resources(ci);
resource_list_for_each_entry_safe(entry, tmp, &ci->resources) {
if (!(entry->res->flags & IORESOURCE_WINDOW))
resource_list_destroy_entry(entry);
}
return status;
}
/*
* Lookup the bus range for the domain in MCFG, and set up config space
* mapping.
*/
static struct pci_config_window *
pci_acpi_setup_ecam_mapping(struct acpi_pci_root *root)
{
struct device *dev = &root->device->dev;
struct resource *bus_res = &root->secondary;
u16 seg = root->segment;
const struct pci_ecam_ops *ecam_ops;
struct resource cfgres;
struct acpi_device *adev;
struct pci_config_window *cfg;
int ret;
ret = pci_mcfg_lookup(root, &cfgres, &ecam_ops);
if (ret) {
dev_err(dev, "%04x:%pR ECAM region not found\n", seg, bus_res);
return NULL;
}
adev = acpi_resource_consumer(&cfgres);
if (adev)
dev_info(dev, "ECAM area %pR reserved by %s\n", &cfgres,
dev_name(&adev->dev));
else
dev_warn(dev, FW_BUG "ECAM area %pR not reserved in ACPI namespace\n",
&cfgres);
cfg = pci_ecam_create(dev, &cfgres, bus_res, ecam_ops);
if (IS_ERR(cfg)) {
dev_err(dev, "%04x:%pR error %ld mapping ECAM\n", seg, bus_res,
PTR_ERR(cfg));
return NULL;
}
return cfg;
}
/* release_info: free resources allocated by init_info */
static void pci_acpi_generic_release_info(struct acpi_pci_root_info *ci)
{
struct acpi_pci_generic_root_info *ri;
ri = container_of(ci, struct acpi_pci_generic_root_info, common);
pci_ecam_free(ri->cfg);
kfree(ci->ops);
kfree(ri);
}
/* Interface called from ACPI code to setup PCI host controller */
struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
{
struct acpi_pci_generic_root_info *ri;
struct pci_bus *bus, *child;
struct acpi_pci_root_ops *root_ops;
struct pci_host_bridge *host;
ri = kzalloc(sizeof(*ri), GFP_KERNEL);
if (!ri)
return NULL;
root_ops = kzalloc(sizeof(*root_ops), GFP_KERNEL);
if (!root_ops) {
kfree(ri);
return NULL;
}
ri->cfg = pci_acpi_setup_ecam_mapping(root);
if (!ri->cfg) {
kfree(ri);
kfree(root_ops);
return NULL;
}
root_ops->release_info = pci_acpi_generic_release_info;
root_ops->prepare_resources = pci_acpi_root_prepare_resources;
root_ops->pci_ops = (struct pci_ops *)&ri->cfg->ops->pci_ops;
bus = acpi_pci_root_create(root, root_ops, &ri->common, ri->cfg);
if (!bus)
return NULL;
/* If we must preserve the resource configuration, claim now */
host = pci_find_host_bridge(bus);
if (host->preserve_config)
pci_bus_claim_resources(bus);
/*
* Assign whatever was left unassigned. If we didn't claim above,
* this will reassign everything.
*/
pci_assign_unassigned_root_bus_resources(bus);
list_for_each_entry(child, &bus->children, node)
pcie_bus_configure_settings(child);
return bus;
}
void pcibios_add_bus(struct pci_bus *bus)
{
acpi_pci_add_bus(bus);
}
void pcibios_remove_bus(struct pci_bus *bus)
{
acpi_pci_remove_bus(bus);
}
#endif
......@@ -13,6 +13,7 @@ config 32BIT
config RISCV
def_bool y
select ACPI_GENERIC_GSI if ACPI
select ACPI_MCFG if (ACPI && PCI)
select ACPI_PPTT if ACPI
select ACPI_REDUCED_HARDWARE_ONLY if ACPI
select ACPI_SPCR_TABLE if ACPI
......@@ -188,6 +189,7 @@ config RISCV
select OF_EARLY_FLATTREE
select OF_IRQ
select PCI_DOMAINS_GENERIC if PCI
select PCI_ECAM if (ACPI && PCI)
select PCI_MSI if PCI
select RISCV_ALTERNATIVE if !XIP_KERNEL
select RISCV_APLIC
......
......@@ -12,8 +12,63 @@
#include <asm-generic/irq.h>
#define INVALID_CONTEXT UINT_MAX
void riscv_set_intc_hwnode_fn(struct fwnode_handle *(*fn)(void));
struct fwnode_handle *riscv_get_intc_hwnode(void);
#ifdef CONFIG_ACPI
enum riscv_irqchip_type {
ACPI_RISCV_IRQCHIP_INTC = 0x00,
ACPI_RISCV_IRQCHIP_IMSIC = 0x01,
ACPI_RISCV_IRQCHIP_PLIC = 0x02,
ACPI_RISCV_IRQCHIP_APLIC = 0x03,
};
int riscv_acpi_get_gsi_info(struct fwnode_handle *fwnode, u32 *gsi_base,
u32 *id, u32 *nr_irqs, u32 *nr_idcs);
struct fwnode_handle *riscv_acpi_get_gsi_domain_id(u32 gsi);
unsigned long acpi_rintc_index_to_hartid(u32 index);
unsigned long acpi_rintc_ext_parent_to_hartid(unsigned int plic_id, unsigned int ctxt_idx);
unsigned int acpi_rintc_get_plic_nr_contexts(unsigned int plic_id);
unsigned int acpi_rintc_get_plic_context(unsigned int plic_id, unsigned int ctxt_idx);
int __init acpi_rintc_get_imsic_mmio_info(u32 index, struct resource *res);
#else
static inline int riscv_acpi_get_gsi_info(struct fwnode_handle *fwnode, u32 *gsi_base,
u32 *id, u32 *nr_irqs, u32 *nr_idcs)
{
return 0;
}
static inline unsigned long acpi_rintc_index_to_hartid(u32 index)
{
return INVALID_HARTID;
}
static inline unsigned long acpi_rintc_ext_parent_to_hartid(unsigned int plic_id,
unsigned int ctxt_idx)
{
return INVALID_HARTID;
}
static inline unsigned int acpi_rintc_get_plic_nr_contexts(unsigned int plic_id)
{
return INVALID_CONTEXT;
}
static inline unsigned int acpi_rintc_get_plic_context(unsigned int plic_id, unsigned int ctxt_idx)
{
return INVALID_CONTEXT;
}
static inline int __init acpi_rintc_get_imsic_mmio_info(u32 index, struct resource *res)
{
return 0;
}
#endif /* CONFIG_ACPI */
#endif /* _ASM_RISCV_IRQ_H */
......@@ -311,29 +311,26 @@ void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size)
#ifdef CONFIG_PCI
/*
* These interfaces are defined just to enable building ACPI core.
* TODO: Update it with actual implementation when external interrupt
* controller support is added in RISC-V ACPI.
* raw_pci_read/write - Platform-specific PCI config space access.
*/
int raw_pci_read(unsigned int domain, unsigned int bus, unsigned int devfn,
int reg, int len, u32 *val)
int raw_pci_read(unsigned int domain, unsigned int bus,
unsigned int devfn, int reg, int len, u32 *val)
{
return PCIBIOS_DEVICE_NOT_FOUND;
}
struct pci_bus *b = pci_find_bus(domain, bus);
int raw_pci_write(unsigned int domain, unsigned int bus, unsigned int devfn,
int reg, int len, u32 val)
{
return PCIBIOS_DEVICE_NOT_FOUND;
if (!b)
return PCIBIOS_DEVICE_NOT_FOUND;
return b->ops->read(b, devfn, reg, len, val);
}
int acpi_pci_bus_find_domain_nr(struct pci_bus *bus)
int raw_pci_write(unsigned int domain, unsigned int bus,
unsigned int devfn, int reg, int len, u32 val)
{
return -1;
}
struct pci_bus *b = pci_find_bus(domain, bus);
struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
{
return NULL;
if (!b)
return PCIBIOS_DEVICE_NOT_FOUND;
return b->ops->write(b, devfn, reg, len, val);
}
#endif /* CONFIG_PCI */
......@@ -213,8 +213,8 @@ static int acpi_ac_probe(struct platform_device *pdev)
return -ENOMEM;
ac->device = adev;
strcpy(acpi_device_name(adev), ACPI_AC_DEVICE_NAME);
strcpy(acpi_device_class(adev), ACPI_AC_CLASS);
strscpy(acpi_device_name(adev), ACPI_AC_DEVICE_NAME);
strscpy(acpi_device_class(adev), ACPI_AC_CLASS);
platform_set_drvdata(pdev, ac);
......
......@@ -118,6 +118,11 @@ static const struct apd_device_desc wt_i2c_desc = {
.fixed_clk_rate = 150000000,
};
static const struct apd_device_desc wt_i3c_desc = {
.setup = acpi_apd_setup,
.fixed_clk_rate = 125000000,
};
static struct property_entry uart_properties[] = {
PROPERTY_ENTRY_U32("reg-io-width", 4),
PROPERTY_ENTRY_U32("reg-shift", 2),
......@@ -231,6 +236,7 @@ static const struct acpi_device_id acpi_apd_device_ids[] = {
{ "AMD0030", },
{ "AMD0040", APD_ADDR(fch_misc_desc)},
{ "AMDI0010", APD_ADDR(wt_i2c_desc) },
{ "AMDI0015", APD_ADDR(wt_i3c_desc) },
{ "AMDI0019", APD_ADDR(wt_i2c_desc) },
{ "AMDI0020", APD_ADDR(cz_uart_desc) },
{ "AMDI0022", APD_ADDR(cz_uart_desc) },
......
......@@ -136,8 +136,10 @@ static void exit_round_robin(unsigned int tsk_index)
{
struct cpumask *pad_busy_cpus = to_cpumask(pad_busy_cpus_bits);
cpumask_clear_cpu(tsk_in_cpu[tsk_index], pad_busy_cpus);
tsk_in_cpu[tsk_index] = -1;
if (tsk_in_cpu[tsk_index] != -1) {
cpumask_clear_cpu(tsk_in_cpu[tsk_index], pad_busy_cpus);
tsk_in_cpu[tsk_index] = -1;
}
}
static unsigned int idle_pct = 5; /* percentage */
......@@ -428,8 +430,8 @@ static int acpi_pad_probe(struct platform_device *pdev)
struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
acpi_status status;
strcpy(acpi_device_name(adev), ACPI_PROCESSOR_AGGREGATOR_DEVICE_NAME);
strcpy(acpi_device_class(adev), ACPI_PROCESSOR_AGGREGATOR_CLASS);
strscpy(acpi_device_name(adev), ACPI_PROCESSOR_AGGREGATOR_DEVICE_NAME);
strscpy(acpi_device_class(adev), ACPI_PROCESSOR_AGGREGATOR_CLASS);
status = acpi_install_notify_handler(adev->handle,
ACPI_DEVICE_NOTIFY, acpi_pad_notify, adev);
......
......@@ -436,8 +436,8 @@ static int acpi_processor_add(struct acpi_device *device,
}
pr->handle = device->handle;
strcpy(acpi_device_name(device), ACPI_PROCESSOR_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS);
strscpy(acpi_device_name(device), ACPI_PROCESSOR_DEVICE_NAME);
strscpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS);
device->driver_data = pr;
result = acpi_processor_get_info(device);
......@@ -985,7 +985,7 @@ int acpi_processor_evaluate_cst(acpi_handle handle, u32 cpu,
memcpy(&info->states[++last_index], &cx, sizeof(cx));
}
acpi_handle_info(handle, "Found %d idle states\n", last_index);
acpi_handle_debug(handle, "Found %d idle states\n", last_index);
info->count = last_index;
......
......@@ -29,11 +29,7 @@ ACPI_INIT_GLOBAL(u32, acpi_gbl_dsdt_index, ACPI_INVALID_TABLE_INDEX);
ACPI_INIT_GLOBAL(u32, acpi_gbl_facs_index, ACPI_INVALID_TABLE_INDEX);
ACPI_INIT_GLOBAL(u32, acpi_gbl_xfacs_index, ACPI_INVALID_TABLE_INDEX);
ACPI_INIT_GLOBAL(u32, acpi_gbl_fadt_index, ACPI_INVALID_TABLE_INDEX);
#if (!ACPI_REDUCED_HARDWARE)
ACPI_GLOBAL(struct acpi_table_facs *, acpi_gbl_FACS);
#endif /* !ACPI_REDUCED_HARDWARE */
ACPI_INIT_GLOBAL(struct acpi_table_facs *, acpi_gbl_FACS, NULL);
/* These addresses are calculated from the FADT Event Block addresses */
......
......@@ -1090,6 +1090,8 @@ struct acpi_port_info {
#define ACPI_ADDRESS_TYPE_IO_RANGE 1
#define ACPI_ADDRESS_TYPE_BUS_NUMBER_RANGE 2
#define ACPI_ADDRESS_TYPE_PCC_NUMBER 0xA
/* Resource descriptor types and masks */
#define ACPI_RESOURCE_NAME_LARGE 0x80
......
......@@ -450,7 +450,7 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = {
{{"_DSM",
METHOD_4ARGS(ACPI_TYPE_BUFFER, ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER,
ACPI_TYPE_PACKAGE),
ACPI_TYPE_ANY) | ARG_COUNT_IS_MINIMUM,
METHOD_RETURNS(ACPI_RTYPE_ALL)}}, /* Must return a value, but it can be of any type */
{{"_DSS", METHOD_1ARGS(ACPI_TYPE_INTEGER),
......
......@@ -174,6 +174,8 @@ acpi_status acpi_db_convert_to_package(char *string, union acpi_object *object)
elements =
ACPI_ALLOCATE_ZEROED(DB_DEFAULT_PKG_ELEMENTS *
sizeof(union acpi_object));
if (!elements)
return (AE_NO_MEMORY);
this = string;
for (i = 0; i < (DB_DEFAULT_PKG_ELEMENTS - 1); i++) {
......
......@@ -17,7 +17,8 @@ ACPI_MODULE_NAME("exconvrt")
/* Local prototypes */
static u32
acpi_ex_convert_to_ascii(u64 integer, u16 base, u8 *string, u8 max_length);
acpi_ex_convert_to_ascii(u64 integer,
u16 base, u8 *string, u8 max_length, u8 leading_zeros);
/*******************************************************************************
*
......@@ -249,6 +250,7 @@ acpi_ex_convert_to_buffer(union acpi_operand_object *obj_desc,
* base - ACPI_STRING_DECIMAL or ACPI_STRING_HEX
* string - Where the string is returned
* data_width - Size of data item to be converted, in bytes
* leading_zeros - Allow leading zeros
*
* RETURN: Actual string length
*
......@@ -257,7 +259,8 @@ acpi_ex_convert_to_buffer(union acpi_operand_object *obj_desc,
******************************************************************************/
static u32
acpi_ex_convert_to_ascii(u64 integer, u16 base, u8 *string, u8 data_width)
acpi_ex_convert_to_ascii(u64 integer,
u16 base, u8 *string, u8 data_width, u8 leading_zeros)
{
u64 digit;
u32 i;
......@@ -266,7 +269,8 @@ acpi_ex_convert_to_ascii(u64 integer, u16 base, u8 *string, u8 data_width)
u32 hex_length;
u32 decimal_length;
u32 remainder;
u8 supress_zeros;
u8 supress_zeros = !leading_zeros;
u8 hex_char;
ACPI_FUNCTION_ENTRY();
......@@ -293,7 +297,6 @@ acpi_ex_convert_to_ascii(u64 integer, u16 base, u8 *string, u8 data_width)
break;
}
supress_zeros = TRUE; /* No leading zeros */
remainder = 0;
for (i = decimal_length; i > 0; i--) {
......@@ -328,8 +331,17 @@ acpi_ex_convert_to_ascii(u64 integer, u16 base, u8 *string, u8 data_width)
/* Get one hex digit, most significant digits first */
string[k] = (u8)
hex_char = (u8)
acpi_ut_hex_to_ascii_char(integer, ACPI_MUL_4(j));
/* Supress leading zeros until the first non-zero character */
if (hex_char == ACPI_ASCII_ZERO && supress_zeros) {
continue;
}
supress_zeros = FALSE;
string[k] = hex_char;
k++;
}
break;
......@@ -379,6 +391,7 @@ acpi_ex_convert_to_string(union acpi_operand_object * obj_desc,
u32 string_length = 0;
u16 base = 16;
u8 separator = ',';
u8 leading_zeros;
ACPI_FUNCTION_TRACE_PTR(ex_convert_to_string, obj_desc);
......@@ -400,14 +413,26 @@ acpi_ex_convert_to_string(union acpi_operand_object * obj_desc,
* Make room for the maximum decimal number size
*/
string_length = ACPI_MAX_DECIMAL_DIGITS;
leading_zeros = FALSE;
base = 10;
break;
case ACPI_EXPLICIT_CONVERT_HEX:
/*
* From to_hex_string.
*
* Supress leading zeros and append "0x"
*/
string_length =
ACPI_MUL_2(acpi_gbl_integer_byte_width) + 2;
leading_zeros = FALSE;
break;
default:
/* Two hex string characters for each integer byte */
string_length = ACPI_MUL_2(acpi_gbl_integer_byte_width);
leading_zeros = TRUE;
break;
}
......@@ -422,17 +447,32 @@ acpi_ex_convert_to_string(union acpi_operand_object * obj_desc,
}
new_buf = return_desc->buffer.pointer;
if (type == ACPI_EXPLICIT_CONVERT_HEX) {
/* Append "0x" prefix for explicit hex conversion */
*new_buf++ = '0';
*new_buf++ = 'x';
}
/* Convert integer to string */
string_length =
acpi_ex_convert_to_ascii(obj_desc->integer.value, base,
new_buf,
acpi_gbl_integer_byte_width);
acpi_gbl_integer_byte_width,
leading_zeros);
/* Null terminate at the correct place */
return_desc->string.length = string_length;
if (type == ACPI_EXPLICIT_CONVERT_HEX) {
/* Take "0x" prefix into account */
return_desc->string.length += 2;
}
new_buf[string_length] = 0;
break;
......@@ -448,6 +488,7 @@ acpi_ex_convert_to_string(union acpi_operand_object * obj_desc,
* From ACPI: "If the input is a buffer, it is converted to a
* a string of decimal values separated by commas."
*/
leading_zeros = FALSE;
base = 10;
/*
......@@ -475,6 +516,7 @@ acpi_ex_convert_to_string(union acpi_operand_object * obj_desc,
*
* Each hex number is prefixed with 0x (11/2018)
*/
leading_zeros = TRUE;
separator = ' ';
string_length = (obj_desc->buffer.length * 5);
break;
......@@ -488,6 +530,7 @@ acpi_ex_convert_to_string(union acpi_operand_object * obj_desc,
*
* Each hex number is prefixed with 0x (11/2018)
*/
leading_zeros = TRUE;
separator = ',';
string_length = (obj_desc->buffer.length * 5);
break;
......@@ -528,7 +571,8 @@ acpi_ex_convert_to_string(union acpi_operand_object * obj_desc,
new_buf += acpi_ex_convert_to_ascii((u64) obj_desc->
buffer.pointer[i],
base, new_buf, 1);
base, new_buf, 1,
leading_zeros);
/* Each digit is separated by either a comma or space */
......
......@@ -437,6 +437,9 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info)
if (info->connection_node) {
second_desc = info->connection_node->object;
if (second_desc == NULL) {
break;
}
if (!(second_desc->common.flags & AOPOBJ_DATA_VALID)) {
status =
acpi_ds_get_buffer_arguments(second_desc);
......
......@@ -133,14 +133,15 @@ acpi_status acpi_ex_system_do_stall(u32 how_long_us)
* (ACPI specifies 100 usec as max, but this gives some slack in
* order to support existing BIOSs)
*/
ACPI_ERROR((AE_INFO,
"Time parameter is too large (%u)", how_long_us));
ACPI_ERROR_ONCE((AE_INFO,
"Time parameter is too large (%u)",
how_long_us));
status = AE_AML_OPERAND_VALUE;
} else {
if (how_long_us > 100) {
ACPI_WARNING((AE_INFO,
"Time parameter %u us > 100 us violating ACPI spec, please fix the firmware.",
how_long_us));
ACPI_WARNING_ONCE((AE_INFO,
"Time parameter %u us > 100 us violating ACPI spec, please fix the firmware.",
how_long_us));
}
acpi_os_stall(how_long_us);
}
......
......@@ -16,20 +16,11 @@
ACPI_MODULE_NAME("hwxfsleep")
/* Local prototypes */
#if (!ACPI_REDUCED_HARDWARE)
static acpi_status
acpi_hw_set_firmware_waking_vector(struct acpi_table_facs *facs,
acpi_physical_address physical_address,
acpi_physical_address physical_address64);
#endif
/*
* These functions are removed for the ACPI_REDUCED_HARDWARE case:
* acpi_set_firmware_waking_vector
* acpi_enter_sleep_state_s4bios
*/
#if (!ACPI_REDUCED_HARDWARE)
/*******************************************************************************
*
* FUNCTION: acpi_hw_set_firmware_waking_vector
......@@ -115,6 +106,12 @@ acpi_set_firmware_waking_vector(acpi_physical_address physical_address,
ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector)
/*
* These functions are removed for the ACPI_REDUCED_HARDWARE case:
* acpi_enter_sleep_state_s4bios
*/
#if (!ACPI_REDUCED_HARDWARE)
/*******************************************************************************
*
* FUNCTION: acpi_enter_sleep_state_s4bios
......
......@@ -25,6 +25,8 @@ acpi_ps_get_next_package_length(struct acpi_parse_state *parser_state);
static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state
*parser_state);
static void acpi_ps_free_field_list(union acpi_parse_object *start);
/*******************************************************************************
*
* FUNCTION: acpi_ps_get_next_package_length
......@@ -683,6 +685,39 @@ static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state
return_PTR(field);
}
/*******************************************************************************
*
* FUNCTION: acpi_ps_free_field_list
*
* PARAMETERS: start - First Op in field list
*
* RETURN: None.
*
* DESCRIPTION: Free all Op objects inside a field list.
*
******************************************************************************/
static void acpi_ps_free_field_list(union acpi_parse_object *start)
{
union acpi_parse_object *cur = start;
union acpi_parse_object *next;
union acpi_parse_object *arg;
while (cur) {
next = cur->common.next;
/* AML_INT_CONNECTION_OP can have a single argument */
arg = acpi_ps_get_arg(cur, 0);
if (arg) {
acpi_ps_free_op(arg);
}
acpi_ps_free_op(cur);
cur = next;
}
}
/*******************************************************************************
*
* FUNCTION: acpi_ps_get_next_arg
......@@ -751,6 +786,10 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state,
while (parser_state->aml < parser_state->pkg_end) {
field = acpi_ps_get_next_field(parser_state);
if (!field) {
if (arg) {
acpi_ps_free_field_list(arg);
}
return_ACPI_STATUS(AE_NO_MEMORY);
}
......@@ -820,6 +859,10 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state,
acpi_ps_get_next_namepath(walk_state, parser_state,
arg,
ACPI_NOT_METHOD_CALL);
if (ACPI_FAILURE(status)) {
acpi_ps_free_op(arg);
return_ACPI_STATUS(status);
}
} else {
/* Single complex argument, nothing returned */
......@@ -854,6 +897,10 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state,
acpi_ps_get_next_namepath(walk_state, parser_state,
arg,
ACPI_POSSIBLE_METHOD_CALL);
if (ACPI_FAILURE(status)) {
acpi_ps_free_op(arg);
return_ACPI_STATUS(status);
}
if (arg->common.aml_opcode == AML_INT_METHODCALL_OP) {
......
......@@ -282,7 +282,8 @@ acpi_rs_get_address_common(struct acpi_resource *resource,
/* Validate the Resource Type */
if ((address.resource_type > 2) && (address.resource_type < 0xC0)) {
if ((address.resource_type > 2) &&
(address.resource_type < 0xC0) && (address.resource_type != 0x0A)) {
return (FALSE);
}
......
......@@ -48,6 +48,7 @@ static void acpi_rs_dump_address_common(union acpi_resource_data *resource);
static void
acpi_rs_dump_descriptor(void *resource, struct acpi_rsdump_info *table);
#ifdef ACPI_DEBUGGER
/*******************************************************************************
*
* FUNCTION: acpi_rs_dump_resource_list
......@@ -160,6 +161,7 @@ void acpi_rs_dump_irq_list(u8 *route_table)
prt_element, prt_element->length);
}
}
#endif
/*******************************************************************************
*
......
......@@ -18,7 +18,6 @@ ACPI_MODULE_NAME("tbutils")
static acpi_physical_address
acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size);
#if (!ACPI_REDUCED_HARDWARE)
/*******************************************************************************
*
* FUNCTION: acpi_tb_initialize_facs
......@@ -56,7 +55,6 @@ acpi_status acpi_tb_initialize_facs(void)
return (AE_OK);
}
#endif /* !ACPI_REDUCED_HARDWARE */
/*******************************************************************************
*
......
......@@ -140,7 +140,7 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
(void)
acpi_os_delete_semaphore
(acpi_gbl_global_lock_semaphore);
acpi_gbl_global_lock_semaphore = NULL;
acpi_gbl_global_lock_semaphore = ACPI_SEMAPHORE_NULL;
acpi_os_delete_mutex(object->mutex.os_mutex);
acpi_gbl_global_lock_mutex = NULL;
......@@ -157,7 +157,7 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
object, object->event.os_semaphore));
(void)acpi_os_delete_semaphore(object->event.os_semaphore);
object->event.os_semaphore = NULL;
object->event.os_semaphore = ACPI_SEMAPHORE_NULL;
break;
case ACPI_TYPE_METHOD:
......
......@@ -154,7 +154,7 @@ acpi_status acpi_ut_init_globals(void)
/* Global Lock support */
acpi_gbl_global_lock_semaphore = NULL;
acpi_gbl_global_lock_semaphore = ACPI_SEMAPHORE_NULL;
acpi_gbl_global_lock_mutex = NULL;
acpi_gbl_global_lock_acquired = FALSE;
acpi_gbl_global_lock_handle = 0;
......
......@@ -75,6 +75,7 @@ static struct acpi_interface_info acpi_default_supported_interfaces[] = {
{"Windows 2019", NULL, 0, ACPI_OSI_WIN_10_19H1}, /* Windows 10 version 1903 - Added 08/2019 */
{"Windows 2020", NULL, 0, ACPI_OSI_WIN_10_20H1}, /* Windows 10 version 2004 - Added 08/2021 */
{"Windows 2021", NULL, 0, ACPI_OSI_WIN_11}, /* Windows 11 - Added 01/2022 */
{"Windows 2022", NULL, 0, ACPI_OSI_WIN_11_22H2}, /* Windows 11 version 22H2 - Added 04/2024 */
/* Feature Group Strings */
......
......@@ -120,6 +120,18 @@ acpi_status ACPI_INIT_FUNCTION acpi_enable_subsystem(u32 flags)
*/
acpi_gbl_early_initialization = FALSE;
/*
* Obtain a permanent mapping for the FACS. This is required for the
* Global Lock and the Firmware Waking Vector
*/
if (!(flags & ACPI_NO_FACS_INIT)) {
status = acpi_tb_initialize_facs();
if (ACPI_FAILURE(status)) {
ACPI_WARNING((AE_INFO, "Could not map the FACS table"));
return_ACPI_STATUS(status);
}
}
#if (!ACPI_REDUCED_HARDWARE)
/* Enable ACPI mode */
......@@ -137,18 +149,6 @@ acpi_status ACPI_INIT_FUNCTION acpi_enable_subsystem(u32 flags)
}
}
/*
* Obtain a permanent mapping for the FACS. This is required for the
* Global Lock and the Firmware Waking Vector
*/
if (!(flags & ACPI_NO_FACS_INIT)) {
status = acpi_tb_initialize_facs();
if (ACPI_FAILURE(status)) {
ACPI_WARNING((AE_INFO, "Could not map the FACS table"));
return_ACPI_STATUS(status);
}
}
/*
* Initialize ACPI Event handling (Fixed and General Purpose)
*
......
......@@ -10,7 +10,6 @@
#define pr_fmt(fmt) "ACPI: battery: " fmt
#include <linux/async.h>
#include <linux/delay.h>
#include <linux/dmi.h>
#include <linux/jiffies.h>
......@@ -50,8 +49,6 @@ MODULE_AUTHOR("Alexey Starikovskiy <astarikovskiy@suse.de>");
MODULE_DESCRIPTION("ACPI Battery Driver");
MODULE_LICENSE("GPL");
static async_cookie_t async_cookie;
static bool battery_driver_registered;
static int battery_bix_broken_package;
static int battery_notification_delay_ms;
static int battery_ac_is_broken;
......@@ -1207,7 +1204,7 @@ static int acpi_battery_update_retry(struct acpi_battery *battery)
static int acpi_battery_add(struct acpi_device *device)
{
int result = 0;
struct acpi_battery *battery = NULL;
struct acpi_battery *battery;
if (!device)
return -EINVAL;
......@@ -1219,8 +1216,8 @@ static int acpi_battery_add(struct acpi_device *device)
if (!battery)
return -ENOMEM;
battery->device = device;
strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS);
strscpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME);
strscpy(acpi_device_class(device), ACPI_BATTERY_CLASS);
device->driver_data = battery;
mutex_init(&battery->lock);
mutex_init(&battery->sysfs_lock);
......@@ -1260,7 +1257,7 @@ static int acpi_battery_add(struct acpi_device *device)
static void acpi_battery_remove(struct acpi_device *device)
{
struct acpi_battery *battery = NULL;
struct acpi_battery *battery;
if (!device || !acpi_driver_data(device))
return;
......@@ -1311,37 +1308,23 @@ static struct acpi_driver acpi_battery_driver = {
.remove = acpi_battery_remove,
},
.drv.pm = &acpi_battery_pm,
.drv.probe_type = PROBE_PREFER_ASYNCHRONOUS,
};
static void __init acpi_battery_init_async(void *unused, async_cookie_t cookie)
{
int result;
if (acpi_quirk_skip_acpi_ac_and_battery())
return;
dmi_check_system(bat_dmi_table);
result = acpi_bus_register_driver(&acpi_battery_driver);
battery_driver_registered = (result == 0);
}
static int __init acpi_battery_init(void)
{
if (acpi_disabled)
if (acpi_disabled || acpi_quirk_skip_acpi_ac_and_battery())
return -ENODEV;
async_cookie = async_schedule(acpi_battery_init_async, NULL);
return 0;
dmi_check_system(bat_dmi_table);
return acpi_bus_register_driver(&acpi_battery_driver);
}
static void __exit acpi_battery_exit(void)
{
async_synchronize_cookie(async_cookie + 1);
if (battery_driver_registered) {
acpi_bus_unregister_driver(&acpi_battery_driver);
battery_hook_exit();
}
acpi_bus_unregister_driver(&acpi_battery_driver);
battery_hook_exit();
}
module_init(acpi_battery_init);
......
......@@ -1203,6 +1203,9 @@ static int __init acpi_bus_init_irq(void)
case ACPI_IRQ_MODEL_LPIC:
message = "LPIC";
break;
case ACPI_IRQ_MODEL_RINTC:
message = "RINTC";
break;
default:
pr_info("Unknown interrupt routing model\n");
return -ENODEV;
......@@ -1459,6 +1462,7 @@ static int __init acpi_init(void)
acpi_hest_init();
acpi_ghes_init();
acpi_arm_init();
acpi_riscv_init();
acpi_scan_init();
acpi_ec_init();
acpi_debugfs_init();
......
......@@ -547,20 +547,20 @@ static int acpi_button_add(struct acpi_device *device)
!strcmp(hid, ACPI_BUTTON_HID_POWERF)) {
button->type = ACPI_BUTTON_TYPE_POWER;
handler = acpi_button_notify;
strcpy(name, ACPI_BUTTON_DEVICE_NAME_POWER);
strscpy(name, ACPI_BUTTON_DEVICE_NAME_POWER, MAX_ACPI_DEVICE_NAME_LEN);
sprintf(class, "%s/%s",
ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_POWER);
} else if (!strcmp(hid, ACPI_BUTTON_HID_SLEEP) ||
!strcmp(hid, ACPI_BUTTON_HID_SLEEPF)) {
button->type = ACPI_BUTTON_TYPE_SLEEP;
handler = acpi_button_notify;
strcpy(name, ACPI_BUTTON_DEVICE_NAME_SLEEP);
strscpy(name, ACPI_BUTTON_DEVICE_NAME_SLEEP, MAX_ACPI_DEVICE_NAME_LEN);
sprintf(class, "%s/%s",
ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_SLEEP);
} else if (!strcmp(hid, ACPI_BUTTON_HID_LID)) {
button->type = ACPI_BUTTON_TYPE_LID;
handler = acpi_lid_notify;
strcpy(name, ACPI_BUTTON_DEVICE_NAME_LID);
strscpy(name, ACPI_BUTTON_DEVICE_NAME_LID, MAX_ACPI_DEVICE_NAME_LEN);
sprintf(class, "%s/%s",
ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_LID);
input->open = acpi_lid_input_open;
......
......@@ -103,6 +103,11 @@ static DEFINE_PER_CPU(struct cpc_desc *, cpc_desc_ptr);
(cpc)->cpc_entry.reg.space_id == \
ACPI_ADR_SPACE_PLATFORM_COMM)
/* Check if a CPC register is in FFH */
#define CPC_IN_FFH(cpc) ((cpc)->type == ACPI_TYPE_BUFFER && \
(cpc)->cpc_entry.reg.space_id == \
ACPI_ADR_SPACE_FIXED_HARDWARE)
/* Check if a CPC register is in SystemMemory */
#define CPC_IN_SYSTEM_MEMORY(cpc) ((cpc)->type == ACPI_TYPE_BUFFER && \
(cpc)->cpc_entry.reg.space_id == \
......@@ -171,8 +176,11 @@ show_cppc_data(cppc_get_perf_ctrs, cppc_perf_fb_ctrs, wraparound_time);
#define GET_BIT_WIDTH(reg) ((reg)->access_width ? (8 << ((reg)->access_width - 1)) : (reg)->bit_width)
/* Shift and apply the mask for CPC reads/writes */
#define MASK_VAL(reg, val) (((val) >> (reg)->bit_offset) & \
#define MASK_VAL_READ(reg, val) (((val) >> (reg)->bit_offset) & \
GENMASK(((reg)->bit_width) - 1, 0))
#define MASK_VAL_WRITE(reg, prev_val, val) \
((((val) & GENMASK(((reg)->bit_width) - 1, 0)) << (reg)->bit_offset) | \
((prev_val) & ~(GENMASK(((reg)->bit_width) - 1, 0) << (reg)->bit_offset))) \
static ssize_t show_feedback_ctrs(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
......@@ -859,6 +867,7 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
/* Store CPU Logical ID */
cpc_ptr->cpu_id = pr->id;
spin_lock_init(&cpc_ptr->rmw_lock);
/* Parse PSD data for this CPU */
ret = acpi_get_psd(cpc_ptr, handle);
......@@ -1064,7 +1073,7 @@ static int cpc_read(int cpu, struct cpc_register_resource *reg_res, u64 *val)
}
if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
*val = MASK_VAL(reg, *val);
*val = MASK_VAL_READ(reg, *val);
return 0;
}
......@@ -1073,9 +1082,11 @@ static int cpc_write(int cpu, struct cpc_register_resource *reg_res, u64 val)
{
int ret_val = 0;
int size;
u64 prev_val;
void __iomem *vaddr = NULL;
int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu);
struct cpc_reg *reg = &reg_res->cpc_entry.reg;
struct cpc_desc *cpc_desc;
size = GET_BIT_WIDTH(reg);
......@@ -1108,8 +1119,34 @@ static int cpc_write(int cpu, struct cpc_register_resource *reg_res, u64 val)
return acpi_os_write_memory((acpi_physical_address)reg->address,
val, size);
if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
val = MASK_VAL(reg, val);
if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
cpc_desc = per_cpu(cpc_desc_ptr, cpu);
if (!cpc_desc) {
pr_debug("No CPC descriptor for CPU:%d\n", cpu);
return -ENODEV;
}
spin_lock(&cpc_desc->rmw_lock);
switch (size) {
case 8:
prev_val = readb_relaxed(vaddr);
break;
case 16:
prev_val = readw_relaxed(vaddr);
break;
case 32:
prev_val = readl_relaxed(vaddr);
break;
case 64:
prev_val = readq_relaxed(vaddr);
break;
default:
spin_unlock(&cpc_desc->rmw_lock);
return -EFAULT;
}
val = MASK_VAL_WRITE(reg, prev_val, val);
val |= prev_val;
}
switch (size) {
case 8:
......@@ -1136,6 +1173,9 @@ static int cpc_write(int cpu, struct cpc_register_resource *reg_res, u64 val)
break;
}
if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
spin_unlock(&cpc_desc->rmw_lock);
return ret_val;
}
......@@ -1486,9 +1526,12 @@ int cppc_set_epp_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls, bool enable)
/* after writing CPC, transfer the ownership of PCC to platform */
ret = send_pcc_cmd(pcc_ss_id, CMD_WRITE);
up_write(&pcc_ss_data->pcc_lock);
} else if (osc_cpc_flexible_adr_space_confirmed &&
CPC_SUPPORTED(epp_set_reg) && CPC_IN_FFH(epp_set_reg)) {
ret = cpc_write(cpu, epp_set_reg, perf_ctrls->energy_perf);
} else {
ret = -ENOTSUPP;
pr_debug("_CPC in PCC is not supported\n");
pr_debug("_CPC in PCC and _CPC in FFH are not supported\n");
}
return ret;
......
......@@ -439,23 +439,33 @@ static ssize_t description_show(struct device *dev,
char *buf)
{
struct acpi_device *acpi_dev = to_acpi_device(dev);
struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
union acpi_object *str_obj;
acpi_status status;
int result;
if (acpi_dev->pnp.str_obj == NULL)
return 0;
status = acpi_evaluate_object_typed(acpi_dev->handle, "_STR",
NULL, &buffer,
ACPI_TYPE_BUFFER);
if (ACPI_FAILURE(status))
return -EIO;
str_obj = buffer.pointer;
/*
* The _STR object contains a Unicode identifier for a device.
* We need to convert to utf-8 so it can be displayed.
*/
result = utf16s_to_utf8s(
(wchar_t *)acpi_dev->pnp.str_obj->buffer.pointer,
acpi_dev->pnp.str_obj->buffer.length,
(wchar_t *)str_obj->buffer.pointer,
str_obj->buffer.length,
UTF16_LITTLE_ENDIAN, buf,
PAGE_SIZE - 1);
buf[result++] = '\n';
kfree(str_obj);
return result;
}
static DEVICE_ATTR_RO(description);
......@@ -507,96 +517,97 @@ static ssize_t status_show(struct device *dev, struct device_attribute *attr,
}
static DEVICE_ATTR_RO(status);
/**
* acpi_device_setup_files - Create sysfs attributes of an ACPI device.
* @dev: ACPI device object.
*/
int acpi_device_setup_files(struct acpi_device *dev)
{
struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
acpi_status status;
int result = 0;
static struct attribute *acpi_attrs[] = {
&dev_attr_path.attr,
&dev_attr_hid.attr,
&dev_attr_modalias.attr,
&dev_attr_description.attr,
&dev_attr_adr.attr,
&dev_attr_uid.attr,
&dev_attr_sun.attr,
&dev_attr_hrv.attr,
&dev_attr_status.attr,
&dev_attr_eject.attr,
&dev_attr_power_state.attr,
&dev_attr_real_power_state.attr,
NULL
};
static bool acpi_show_attr(struct acpi_device *dev, const struct device_attribute *attr)
{
/*
* Devices gotten from FADT don't have a "path" attribute
*/
if (dev->handle) {
result = device_create_file(&dev->dev, &dev_attr_path);
if (result)
goto end;
}
if (attr == &dev_attr_path)
return dev->handle;
if (!list_empty(&dev->pnp.ids)) {
result = device_create_file(&dev->dev, &dev_attr_hid);
if (result)
goto end;
if (attr == &dev_attr_hid || attr == &dev_attr_modalias)
return !list_empty(&dev->pnp.ids);
result = device_create_file(&dev->dev, &dev_attr_modalias);
if (result)
goto end;
}
if (attr == &dev_attr_description)
return acpi_has_method(dev->handle, "_STR");
/*
* If device has _STR, 'description' file is created
*/
if (acpi_has_method(dev->handle, "_STR")) {
status = acpi_evaluate_object(dev->handle, "_STR",
NULL, &buffer);
if (ACPI_FAILURE(status))
buffer.pointer = NULL;
dev->pnp.str_obj = buffer.pointer;
result = device_create_file(&dev->dev, &dev_attr_description);
if (result)
goto end;
}
if (attr == &dev_attr_adr)
return dev->pnp.type.bus_address;
if (dev->pnp.type.bus_address)
result = device_create_file(&dev->dev, &dev_attr_adr);
if (acpi_device_uid(dev))
result = device_create_file(&dev->dev, &dev_attr_uid);
if (attr == &dev_attr_uid)
return acpi_device_uid(dev);
if (acpi_has_method(dev->handle, "_SUN")) {
result = device_create_file(&dev->dev, &dev_attr_sun);
if (result)
goto end;
}
if (attr == &dev_attr_sun)
return acpi_has_method(dev->handle, "_SUN");
if (acpi_has_method(dev->handle, "_HRV")) {
result = device_create_file(&dev->dev, &dev_attr_hrv);
if (result)
goto end;
}
if (attr == &dev_attr_hrv)
return acpi_has_method(dev->handle, "_HRV");
if (acpi_has_method(dev->handle, "_STA")) {
result = device_create_file(&dev->dev, &dev_attr_status);
if (result)
goto end;
}
if (attr == &dev_attr_status)
return acpi_has_method(dev->handle, "_STA");
/*
* If device has _EJ0, 'eject' file is created that is used to trigger
* hot-removal function from userland.
*/
if (acpi_has_method(dev->handle, "_EJ0")) {
result = device_create_file(&dev->dev, &dev_attr_eject);
if (result)
return result;
}
if (attr == &dev_attr_eject)
return acpi_has_method(dev->handle, "_EJ0");
if (dev->flags.power_manageable) {
result = device_create_file(&dev->dev, &dev_attr_power_state);
if (result)
return result;
if (attr == &dev_attr_power_state)
return dev->flags.power_manageable;
if (dev->power.flags.power_resources)
result = device_create_file(&dev->dev,
&dev_attr_real_power_state);
}
if (attr == &dev_attr_real_power_state)
return dev->flags.power_manageable && dev->power.flags.power_resources;
acpi_expose_nondev_subnodes(&dev->dev.kobj, &dev->data);
dev_warn_once(&dev->dev, "Unexpected attribute: %s\n", attr->attr.name);
return false;
}
end:
return result;
static umode_t acpi_attr_is_visible(struct kobject *kobj,
struct attribute *attr,
int attrno)
{
struct acpi_device *dev = to_acpi_device(kobj_to_dev(kobj));
if (acpi_show_attr(dev, container_of(attr, struct device_attribute, attr)))
return attr->mode;
else
return 0;
}
static const struct attribute_group acpi_group = {
.attrs = acpi_attrs,
.is_visible = acpi_attr_is_visible,
};
const struct attribute_group *acpi_groups[] = {
&acpi_group,
NULL
};
/**
* acpi_device_setup_files - Create sysfs attributes of an ACPI device.
* @dev: ACPI device object.
*/
void acpi_device_setup_files(struct acpi_device *dev)
{
acpi_expose_nondev_subnodes(&dev->dev.kobj, &dev->data);
}
/**
......@@ -606,41 +617,4 @@ int acpi_device_setup_files(struct acpi_device *dev)
void acpi_device_remove_files(struct acpi_device *dev)
{
acpi_hide_nondev_subnodes(&dev->data);
if (dev->flags.power_manageable) {
device_remove_file(&dev->dev, &dev_attr_power_state);
if (dev->power.flags.power_resources)
device_remove_file(&dev->dev,
&dev_attr_real_power_state);
}
/*
* If device has _STR, remove 'description' file
*/
if (acpi_has_method(dev->handle, "_STR")) {
kfree(dev->pnp.str_obj);
device_remove_file(&dev->dev, &dev_attr_description);
}
/*
* If device has _EJ0, remove 'eject' file.
*/
if (acpi_has_method(dev->handle, "_EJ0"))
device_remove_file(&dev->dev, &dev_attr_eject);
if (acpi_has_method(dev->handle, "_SUN"))
device_remove_file(&dev->dev, &dev_attr_sun);
if (acpi_has_method(dev->handle, "_HRV"))
device_remove_file(&dev->dev, &dev_attr_hrv);
if (acpi_device_uid(dev))
device_remove_file(&dev->dev, &dev_attr_uid);
if (dev->pnp.type.bus_address)
device_remove_file(&dev->dev, &dev_attr_adr);
device_remove_file(&dev->dev, &dev_attr_modalias);
device_remove_file(&dev->dev, &dev_attr_hid);
if (acpi_has_method(dev->handle, "_STA"))
device_remove_file(&dev->dev, &dev_attr_status);
if (dev->handle)
device_remove_file(&dev->dev, &dev_attr_path);
}
......@@ -783,6 +783,9 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
unsigned long tmp;
int ret = 0;
if (t->rdata)
memset(t->rdata, 0, t->rlen);
/* start transaction */
spin_lock_irqsave(&ec->lock, tmp);
/* Enable GPE for command processing (IBF=0/OBF=1) */
......@@ -819,8 +822,6 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
if (!ec || (!t) || (t->wlen && !t->wdata) || (t->rlen && !t->rdata))
return -EINVAL;
if (t->rdata)
memset(t->rdata, 0, t->rlen);
mutex_lock(&ec->mutex);
if (ec->global_lock) {
......@@ -847,7 +848,7 @@ static int acpi_ec_burst_enable(struct acpi_ec *ec)
.wdata = NULL, .rdata = &d,
.wlen = 0, .rlen = 1};
return acpi_ec_transaction(ec, &t);
return acpi_ec_transaction_unlocked(ec, &t);
}
static int acpi_ec_burst_disable(struct acpi_ec *ec)
......@@ -857,7 +858,7 @@ static int acpi_ec_burst_disable(struct acpi_ec *ec)
.wlen = 0, .rlen = 0};
return (acpi_ec_read_status(ec) & ACPI_EC_FLAG_BURST) ?
acpi_ec_transaction(ec, &t) : 0;
acpi_ec_transaction_unlocked(ec, &t) : 0;
}
static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 *data)
......@@ -873,6 +874,19 @@ static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 *data)
return result;
}
static int acpi_ec_read_unlocked(struct acpi_ec *ec, u8 address, u8 *data)
{
int result;
u8 d;
struct transaction t = {.command = ACPI_EC_COMMAND_READ,
.wdata = &address, .rdata = &d,
.wlen = 1, .rlen = 1};
result = acpi_ec_transaction_unlocked(ec, &t);
*data = d;
return result;
}
static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data)
{
u8 wdata[2] = { address, data };
......@@ -883,6 +897,16 @@ static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data)
return acpi_ec_transaction(ec, &t);
}
static int acpi_ec_write_unlocked(struct acpi_ec *ec, u8 address, u8 data)
{
u8 wdata[2] = { address, data };
struct transaction t = {.command = ACPI_EC_COMMAND_WRITE,
.wdata = wdata, .rdata = NULL,
.wlen = 2, .rlen = 0};
return acpi_ec_transaction_unlocked(ec, &t);
}
int ec_read(u8 addr, u8 *val)
{
int err;
......@@ -1323,6 +1347,7 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
struct acpi_ec *ec = handler_context;
int result = 0, i, bytes = bits / 8;
u8 *value = (u8 *)value64;
u32 glk;
if ((address > 0xFF) || !value || !handler_context)
return AE_BAD_PARAMETER;
......@@ -1330,13 +1355,25 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
if (function != ACPI_READ && function != ACPI_WRITE)
return AE_BAD_PARAMETER;
mutex_lock(&ec->mutex);
if (ec->global_lock) {
acpi_status status;
status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
if (ACPI_FAILURE(status)) {
result = -ENODEV;
goto unlock;
}
}
if (ec->busy_polling || bits > 8)
acpi_ec_burst_enable(ec);
for (i = 0; i < bytes; ++i, ++address, ++value) {
result = (function == ACPI_READ) ?
acpi_ec_read(ec, address, value) :
acpi_ec_write(ec, address, *value);
acpi_ec_read_unlocked(ec, address, value) :
acpi_ec_write_unlocked(ec, address, *value);
if (result < 0)
break;
}
......@@ -1344,6 +1381,12 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
if (ec->busy_polling || bits > 8)
acpi_ec_burst_disable(ec);
if (ec->global_lock)
acpi_release_global_lock(glk);
unlock:
mutex_unlock(&ec->mutex);
switch (result) {
case -EINVAL:
return AE_BAD_PARAMETER;
......
......@@ -118,8 +118,9 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
int type, void (*release)(struct device *));
int acpi_tie_acpi_dev(struct acpi_device *adev);
int acpi_device_add(struct acpi_device *device);
int acpi_device_setup_files(struct acpi_device *dev);
void acpi_device_setup_files(struct acpi_device *dev);
void acpi_device_remove_files(struct acpi_device *dev);
extern const struct attribute_group *acpi_groups[];
void acpi_device_add_finalize(struct acpi_device *device);
void acpi_free_pnp_ids(struct acpi_device_pnp *pnp);
bool acpi_device_is_enabled(const struct acpi_device *adev);
......
......@@ -748,6 +748,8 @@ static int acpi_pci_link_add(struct acpi_device *device,
if (result)
kfree(link);
acpi_dev_clear_dependencies(device);
return result < 0 ? result : 1;
}
......
......@@ -376,10 +376,8 @@ static int tps68470_pmic_opregion_probe(struct platform_device *pdev)
struct tps68470_pmic_opregion *opregion;
acpi_status status;
if (!dev || !tps68470_regmap) {
dev_warn(dev, "dev or regmap is NULL\n");
return -EINVAL;
}
if (!tps68470_regmap)
return dev_err_probe(dev, -EINVAL, "regmap is missing\n");
if (!handle) {
dev_warn(dev, "acpi handle is NULL\n");
......
......@@ -503,6 +503,13 @@ static const struct dmi_system_id irq1_level_low_skip_override[] = {
DMI_MATCH(DMI_BOARD_NAME, "B2502FBA"),
},
},
{
/* Asus Vivobook Go E1404GAB */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_BOARD_NAME, "E1404GAB"),
},
},
{
/* Asus Vivobook E1504GA */
.matches = {
......@@ -554,6 +561,12 @@ static const struct dmi_system_id irq1_level_low_skip_override[] = {
* to have a working keyboard.
*/
static const struct dmi_system_id irq1_edge_low_force_override[] = {
{
/* MECHREV Jiaolong17KS Series GM7XG0M */
.matches = {
DMI_MATCH(DMI_BOARD_NAME, "GM7XG0M"),
},
},
{
/* XMG APEX 17 (M23) */
.matches = {
......@@ -572,6 +585,12 @@ static const struct dmi_system_id irq1_edge_low_force_override[] = {
DMI_MATCH(DMI_BOARD_NAME, "GMxXGxx"),
},
},
{
/* TongFang GMxXGxX/TUXEDO Polaris 15 Gen5 AMD */
.matches = {
DMI_MATCH(DMI_BOARD_NAME, "GMxXGxX"),
},
},
{
/* TongFang GMxXGxx sold as Eluktronics Inc. RP-15 */
.matches = {
......
# SPDX-License-Identifier: GPL-2.0-only
obj-y += rhct.o
obj-y += rhct.o init.o irq.o
obj-$(CONFIG_ACPI_PROCESSOR_IDLE) += cpuidle.o
obj-$(CONFIG_ACPI_CPPC_LIB) += cppc.o
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2023-2024, Ventana Micro Systems Inc
* Author: Sunil V L <sunilvl@ventanamicro.com>
*/
#include <linux/acpi.h>
#include "init.h"
void __init acpi_riscv_init(void)
{
riscv_acpi_init_gsi_mapping();
}
/* SPDX-License-Identifier: GPL-2.0-only */
#include <linux/init.h>
void __init riscv_acpi_init_gsi_mapping(void);
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2023-2024, Ventana Micro Systems Inc
* Author: Sunil V L <sunilvl@ventanamicro.com>
*/
#include <linux/acpi.h>
#include <linux/sort.h>
#include <linux/irq.h>
#include "init.h"
struct riscv_ext_intc_list {
acpi_handle handle;
u32 gsi_base;
u32 nr_irqs;
u32 nr_idcs;
u32 id;
u32 type;
struct list_head list;
};
struct acpi_irq_dep_ctx {
int rc;
unsigned int index;
acpi_handle handle;
};
LIST_HEAD(ext_intc_list);
static int irqchip_cmp_func(const void *in0, const void *in1)
{
struct acpi_probe_entry *elem0 = (struct acpi_probe_entry *)in0;
struct acpi_probe_entry *elem1 = (struct acpi_probe_entry *)in1;
return (elem0->type > elem1->type) - (elem0->type < elem1->type);
}
/*
* On RISC-V, RINTC structures in MADT should be probed before any other
* interrupt controller structures and IMSIC before APLIC. The interrupt
* controller subtypes in MADT of ACPI spec for RISC-V are defined in
* the incremental order like RINTC(24)->IMSIC(25)->APLIC(26)->PLIC(27).
* Hence, simply sorting the subtypes in incremental order will
* establish the required order.
*/
void arch_sort_irqchip_probe(struct acpi_probe_entry *ap_head, int nr)
{
struct acpi_probe_entry *ape = ap_head;
if (nr == 1 || !ACPI_COMPARE_NAMESEG(ACPI_SIG_MADT, ape->id))
return;
sort(ape, nr, sizeof(*ape), irqchip_cmp_func, NULL);
}
static acpi_status riscv_acpi_update_gsi_handle(u32 gsi_base, acpi_handle handle)
{
struct riscv_ext_intc_list *ext_intc_element;
struct list_head *i, *tmp;
list_for_each_safe(i, tmp, &ext_intc_list) {
ext_intc_element = list_entry(i, struct riscv_ext_intc_list, list);
if (gsi_base == ext_intc_element->gsi_base) {
ext_intc_element->handle = handle;
return AE_OK;
}
}
return AE_NOT_FOUND;
}
int riscv_acpi_get_gsi_info(struct fwnode_handle *fwnode, u32 *gsi_base,
u32 *id, u32 *nr_irqs, u32 *nr_idcs)
{
struct riscv_ext_intc_list *ext_intc_element;
struct list_head *i;
list_for_each(i, &ext_intc_list) {
ext_intc_element = list_entry(i, struct riscv_ext_intc_list, list);
if (ext_intc_element->handle == ACPI_HANDLE_FWNODE(fwnode)) {
*gsi_base = ext_intc_element->gsi_base;
*id = ext_intc_element->id;
*nr_irqs = ext_intc_element->nr_irqs;
if (nr_idcs)
*nr_idcs = ext_intc_element->nr_idcs;
return 0;
}
}
return -ENODEV;
}
struct fwnode_handle *riscv_acpi_get_gsi_domain_id(u32 gsi)
{
struct riscv_ext_intc_list *ext_intc_element;
struct acpi_device *adev;
struct list_head *i;
list_for_each(i, &ext_intc_list) {
ext_intc_element = list_entry(i, struct riscv_ext_intc_list, list);
if (gsi >= ext_intc_element->gsi_base &&
gsi < (ext_intc_element->gsi_base + ext_intc_element->nr_irqs)) {
adev = acpi_fetch_acpi_dev(ext_intc_element->handle);
if (!adev)
return NULL;
return acpi_fwnode_handle(adev);
}
}
return NULL;
}
static int __init riscv_acpi_register_ext_intc(u32 gsi_base, u32 nr_irqs, u32 nr_idcs,
u32 id, u32 type)
{
struct riscv_ext_intc_list *ext_intc_element;
ext_intc_element = kzalloc(sizeof(*ext_intc_element), GFP_KERNEL);
if (!ext_intc_element)
return -ENOMEM;
ext_intc_element->gsi_base = gsi_base;
ext_intc_element->nr_irqs = nr_irqs;
ext_intc_element->nr_idcs = nr_idcs;
ext_intc_element->id = id;
list_add_tail(&ext_intc_element->list, &ext_intc_list);
return 0;
}
static acpi_status __init riscv_acpi_create_gsi_map(acpi_handle handle, u32 level,
void *context, void **return_value)
{
acpi_status status;
u64 gbase;
if (!acpi_has_method(handle, "_GSB")) {
acpi_handle_err(handle, "_GSB method not found\n");
return AE_ERROR;
}
status = acpi_evaluate_integer(handle, "_GSB", NULL, &gbase);
if (ACPI_FAILURE(status)) {
acpi_handle_err(handle, "failed to evaluate _GSB method\n");
return status;
}
status = riscv_acpi_update_gsi_handle((u32)gbase, handle);
if (ACPI_FAILURE(status)) {
acpi_handle_err(handle, "failed to find the GSI mapping entry\n");
return status;
}
return AE_OK;
}
static int __init riscv_acpi_aplic_parse_madt(union acpi_subtable_headers *header,
const unsigned long end)
{
struct acpi_madt_aplic *aplic = (struct acpi_madt_aplic *)header;
return riscv_acpi_register_ext_intc(aplic->gsi_base, aplic->num_sources, aplic->num_idcs,
aplic->id, ACPI_RISCV_IRQCHIP_APLIC);
}
static int __init riscv_acpi_plic_parse_madt(union acpi_subtable_headers *header,
const unsigned long end)
{
struct acpi_madt_plic *plic = (struct acpi_madt_plic *)header;
return riscv_acpi_register_ext_intc(plic->gsi_base, plic->num_irqs, 0,
plic->id, ACPI_RISCV_IRQCHIP_PLIC);
}
void __init riscv_acpi_init_gsi_mapping(void)
{
/* There can be either PLIC or APLIC */
if (acpi_table_parse_madt(ACPI_MADT_TYPE_PLIC, riscv_acpi_plic_parse_madt, 0) > 0) {
acpi_get_devices("RSCV0001", riscv_acpi_create_gsi_map, NULL, NULL);
return;
}
if (acpi_table_parse_madt(ACPI_MADT_TYPE_APLIC, riscv_acpi_aplic_parse_madt, 0) > 0)
acpi_get_devices("RSCV0002", riscv_acpi_create_gsi_map, NULL, NULL);
}
static acpi_handle riscv_acpi_get_gsi_handle(u32 gsi)
{
struct riscv_ext_intc_list *ext_intc_element;
struct list_head *i;
list_for_each(i, &ext_intc_list) {
ext_intc_element = list_entry(i, struct riscv_ext_intc_list, list);
if (gsi >= ext_intc_element->gsi_base &&
gsi < (ext_intc_element->gsi_base + ext_intc_element->nr_irqs))
return ext_intc_element->handle;
}
return NULL;
}
static acpi_status riscv_acpi_irq_get_parent(struct acpi_resource *ares, void *context)
{
struct acpi_irq_dep_ctx *ctx = context;
struct acpi_resource_irq *irq;
struct acpi_resource_extended_irq *eirq;
switch (ares->type) {
case ACPI_RESOURCE_TYPE_IRQ:
irq = &ares->data.irq;
if (ctx->index >= irq->interrupt_count) {
ctx->index -= irq->interrupt_count;
return AE_OK;
}
ctx->handle = riscv_acpi_get_gsi_handle(irq->interrupts[ctx->index]);
return AE_CTRL_TERMINATE;
case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
eirq = &ares->data.extended_irq;
if (eirq->producer_consumer == ACPI_PRODUCER)
return AE_OK;
if (ctx->index >= eirq->interrupt_count) {
ctx->index -= eirq->interrupt_count;
return AE_OK;
}
/* Support GSIs only */
if (eirq->resource_source.string_length)
return AE_OK;
ctx->handle = riscv_acpi_get_gsi_handle(eirq->interrupts[ctx->index]);
return AE_CTRL_TERMINATE;
}
return AE_OK;
}
static int riscv_acpi_irq_get_dep(acpi_handle handle, unsigned int index, acpi_handle *gsi_handle)
{
struct acpi_irq_dep_ctx ctx = {-EINVAL, index, NULL};
if (!gsi_handle)
return 0;
acpi_walk_resources(handle, METHOD_NAME__CRS, riscv_acpi_irq_get_parent, &ctx);
*gsi_handle = ctx.handle;
if (*gsi_handle)
return 1;
return 0;
}
static u32 riscv_acpi_add_prt_dep(acpi_handle handle)
{
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
struct acpi_pci_routing_table *entry;
struct acpi_handle_list dep_devices;
acpi_handle gsi_handle;
acpi_handle link_handle;
acpi_status status;
u32 count = 0;
status = acpi_get_irq_routing_table(handle, &buffer);
if (ACPI_FAILURE(status)) {
acpi_handle_err(handle, "failed to get IRQ routing table\n");
kfree(buffer.pointer);
return 0;
}
entry = buffer.pointer;
while (entry && (entry->length > 0)) {
if (entry->source[0]) {
acpi_get_handle(handle, entry->source, &link_handle);
dep_devices.count = 1;
dep_devices.handles = kcalloc(1, sizeof(*dep_devices.handles), GFP_KERNEL);
if (!dep_devices.handles) {
acpi_handle_err(handle, "failed to allocate memory\n");
continue;
}
dep_devices.handles[0] = link_handle;
count += acpi_scan_add_dep(handle, &dep_devices);
} else {
gsi_handle = riscv_acpi_get_gsi_handle(entry->source_index);
dep_devices.count = 1;
dep_devices.handles = kcalloc(1, sizeof(*dep_devices.handles), GFP_KERNEL);
if (!dep_devices.handles) {
acpi_handle_err(handle, "failed to allocate memory\n");
continue;
}
dep_devices.handles[0] = gsi_handle;
count += acpi_scan_add_dep(handle, &dep_devices);
}
entry = (struct acpi_pci_routing_table *)
((unsigned long)entry + entry->length);
}
kfree(buffer.pointer);
return count;
}
static u32 riscv_acpi_add_irq_dep(acpi_handle handle)
{
struct acpi_handle_list dep_devices;
acpi_handle gsi_handle;
u32 count = 0;
int i;
for (i = 0;
riscv_acpi_irq_get_dep(handle, i, &gsi_handle);
i++) {
dep_devices.count = 1;
dep_devices.handles = kcalloc(1, sizeof(*dep_devices.handles), GFP_KERNEL);
if (!dep_devices.handles) {
acpi_handle_err(handle, "failed to allocate memory\n");
continue;
}
dep_devices.handles[0] = gsi_handle;
count += acpi_scan_add_dep(handle, &dep_devices);
}
return count;
}
u32 arch_acpi_add_auto_dep(acpi_handle handle)
{
if (acpi_has_method(handle, "_PRT"))
return riscv_acpi_add_prt_dep(handle);
return riscv_acpi_add_irq_dep(handle);
}
......@@ -795,10 +795,7 @@ int acpi_device_add(struct acpi_device *device)
goto err;
}
result = acpi_device_setup_files(device);
if (result)
pr_err("Error creating sysfs interface for device %s\n",
dev_name(&device->dev));
acpi_device_setup_files(device);
return 0;
......@@ -861,6 +858,9 @@ static const char * const acpi_honor_dep_ids[] = {
"INTC1095", /* IVSC (ADL) driver must be loaded to allow i2c access to camera sensors */
"INTC100A", /* IVSC (RPL) driver must be loaded to allow i2c access to camera sensors */
"INTC10CF", /* IVSC (MTL) driver must be loaded to allow i2c access to camera sensors */
"RSCV0001", /* RISC-V PLIC */
"RSCV0002", /* RISC-V APLIC */
"PNP0C0F", /* PCI Link Device */
NULL
};
......@@ -1822,6 +1822,7 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
device->dev.parent = parent ? &parent->dev : NULL;
device->dev.release = release;
device->dev.bus = &acpi_bus_type;
device->dev.groups = acpi_groups;
fwnode_init(&device->fwnode, &acpi_device_fwnode_ops);
acpi_set_device_status(device, ACPI_STA_DEFAULT);
acpi_device_get_busid(device);
......@@ -2013,6 +2014,49 @@ void acpi_scan_hotplug_enabled(struct acpi_hotplug_profile *hotplug, bool val)
mutex_unlock(&acpi_scan_lock);
}
int acpi_scan_add_dep(acpi_handle handle, struct acpi_handle_list *dep_devices)
{
u32 count;
int i;
for (count = 0, i = 0; i < dep_devices->count; i++) {
struct acpi_device_info *info;
struct acpi_dep_data *dep;
bool skip, honor_dep;
acpi_status status;
status = acpi_get_object_info(dep_devices->handles[i], &info);
if (ACPI_FAILURE(status)) {
acpi_handle_debug(handle, "Error reading _DEP device info\n");
continue;
}
skip = acpi_info_matches_ids(info, acpi_ignore_dep_ids);
honor_dep = acpi_info_matches_ids(info, acpi_honor_dep_ids);
kfree(info);
if (skip)
continue;
dep = kzalloc(sizeof(*dep), GFP_KERNEL);
if (!dep)
continue;
count++;
dep->supplier = dep_devices->handles[i];
dep->consumer = handle;
dep->honor_dep = honor_dep;
mutex_lock(&acpi_dep_list_lock);
list_add_tail(&dep->node, &acpi_dep_list);
mutex_unlock(&acpi_dep_list_lock);
}
acpi_handle_list_free(dep_devices);
return count;
}
static void acpi_scan_init_hotplug(struct acpi_device *adev)
{
struct acpi_hardware_id *hwid;
......@@ -2032,11 +2076,21 @@ static void acpi_scan_init_hotplug(struct acpi_device *adev)
}
}
u32 __weak arch_acpi_add_auto_dep(acpi_handle handle) { return 0; }
static u32 acpi_scan_check_dep(acpi_handle handle)
{
struct acpi_handle_list dep_devices;
u32 count;
int i;
u32 count = 0;
/*
* Some architectures like RISC-V need to add dependencies for
* all devices which use GSI to the interrupt controller so that
* interrupt controller is probed before any of those devices.
* Instead of mandating _DEP on all the devices, detect the
* dependency and add automatically.
*/
count += arch_acpi_add_auto_dep(handle);
/*
* Check for _HID here to avoid deferring the enumeration of:
......@@ -2045,48 +2099,14 @@ static u32 acpi_scan_check_dep(acpi_handle handle)
* Still, checking for _HID catches more then just these cases ...
*/
if (!acpi_has_method(handle, "_DEP") || !acpi_has_method(handle, "_HID"))
return 0;
return count;
if (!acpi_evaluate_reference(handle, "_DEP", NULL, &dep_devices)) {
acpi_handle_debug(handle, "Failed to evaluate _DEP.\n");
return 0;
}
for (count = 0, i = 0; i < dep_devices.count; i++) {
struct acpi_device_info *info;
struct acpi_dep_data *dep;
bool skip, honor_dep;
acpi_status status;
status = acpi_get_object_info(dep_devices.handles[i], &info);
if (ACPI_FAILURE(status)) {
acpi_handle_debug(handle, "Error reading _DEP device info\n");
continue;
}
skip = acpi_info_matches_ids(info, acpi_ignore_dep_ids);
honor_dep = acpi_info_matches_ids(info, acpi_honor_dep_ids);
kfree(info);
if (skip)
continue;
dep = kzalloc(sizeof(*dep), GFP_KERNEL);
if (!dep)
continue;
count++;
dep->supplier = dep_devices.handles[i];
dep->consumer = handle;
dep->honor_dep = honor_dep;
mutex_lock(&acpi_dep_list_lock);
list_add_tail(&dep->node , &acpi_dep_list);
mutex_unlock(&acpi_dep_list_lock);
return count;
}
acpi_handle_list_free(&dep_devices);
count += acpi_scan_add_dep(handle, &dep_devices);
return count;
}
......@@ -2757,6 +2777,8 @@ static int __init acpi_match_madt(union acpi_subtable_headers *header,
return 0;
}
void __weak arch_sort_irqchip_probe(struct acpi_probe_entry *ap_head, int nr) { }
int __init __acpi_probe_device_table(struct acpi_probe_entry *ap_head, int nr)
{
int count = 0;
......@@ -2765,6 +2787,7 @@ int __init __acpi_probe_device_table(struct acpi_probe_entry *ap_head, int nr)
return 0;
mutex_lock(&acpi_probe_mutex);
arch_sort_irqchip_probe(ap_head, nr);
for (ape = ap_head; nr; ape++, nr--) {
if (ACPI_COMPARE_NAMESEG(ACPI_SIG_MADT, ape->id)) {
acpi_probe_count = 0;
......
......@@ -351,6 +351,20 @@ static const struct dmi_system_id acpisleep_dmi_table[] __initconst = {
DMI_MATCH(DMI_PRODUCT_NAME, "1025C"),
},
},
/*
* The ASUS ROG M16 from 2023 has many events which wake it from s2idle
* resulting in excessive battery drain and risk of laptop overheating,
* these events can be caused by the MMC or y AniMe display if installed.
* The match is valid for all of the GU604V<x> range.
*/
{
.callback = init_default_s3,
.ident = "ASUS ROG Zephyrus M16 (2023)",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "ROG Zephyrus M16 GU604V"),
},
},
/*
* https://bugzilla.kernel.org/show_bug.cgi?id=189431
* Lenovo G50-45 is a platform later than 2012, but needs nvs memory
......
......@@ -801,7 +801,8 @@ acpi_evaluate_dsm(acpi_handle handle, const guid_t *guid, u64 rev, u64 func,
if (ret != AE_NOT_FOUND)
acpi_handle_warn(handle,
"failed to evaluate _DSM %pUb (0x%x)\n", guid, ret);
"failed to evaluate _DSM %pUb rev:%lld func:%lld (0x%x)\n",
guid, rev, func, ret);
return NULL;
}
......
......@@ -254,6 +254,14 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "PCG-FRV35"),
},
},
{
.callback = video_detect_force_vendor,
/* Panasonic Toughbook CF-18 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Matsushita Electric Industrial"),
DMI_MATCH(DMI_PRODUCT_NAME, "CF-18"),
},
},
/*
* Toshiba models with Transflective display, these need to use
......@@ -549,6 +557,14 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir9,1"),
},
},
{
.callback = video_detect_force_native,
/* Apple MacBook Pro 9,2 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro9,2"),
},
},
{
/* https://bugzilla.redhat.com/show_bug.cgi?id=1217249 */
.callback = video_detect_force_native,
......@@ -896,7 +912,6 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
/* Lenovo Yoga Tab 3 Pro YT3-X90F */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
DMI_MATCH(DMI_PRODUCT_NAME, "CHERRYVIEW D1 PLATFORM"),
DMI_MATCH(DMI_PRODUCT_VERSION, "Blade3-10A-001"),
},
},
......
......@@ -355,7 +355,6 @@ static const struct dmi_system_id acpi_quirk_skip_dmi_ids[] = {
/* Lenovo Yoga Tab 3 Pro X90F */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
DMI_MATCH(DMI_PRODUCT_NAME, "CHERRYVIEW D1 PLATFORM"),
DMI_MATCH(DMI_PRODUCT_VERSION, "Blade3-10A-001"),
},
.driver_data = (void *)(ACPI_QUIRK_SKIP_I2C_CLIENTS |
......
......@@ -4,6 +4,7 @@
* Copyright (C) 2022 Ventana Micro Systems Inc.
*/
#include <linux/acpi.h>
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/cpu.h>
......@@ -189,17 +190,22 @@ static int aplic_direct_starting_cpu(unsigned int cpu)
}
static int aplic_direct_parse_parent_hwirq(struct device *dev, u32 index,
u32 *parent_hwirq, unsigned long *parent_hartid)
u32 *parent_hwirq, unsigned long *parent_hartid,
struct aplic_priv *priv)
{
struct of_phandle_args parent;
unsigned long hartid;
int rc;
/*
* Currently, only OF fwnode is supported so extend this
* function for ACPI support.
*/
if (!is_of_node(dev->fwnode))
return -EINVAL;
if (!is_of_node(dev->fwnode)) {
hartid = acpi_rintc_ext_parent_to_hartid(priv->acpi_aplic_id, index);
if (hartid == INVALID_HARTID)
return -ENODEV;
*parent_hartid = hartid;
*parent_hwirq = RV_IRQ_EXT;
return 0;
}
rc = of_irq_parse_one(to_of_node(dev->fwnode), index, &parent);
if (rc)
......@@ -237,7 +243,7 @@ int aplic_direct_setup(struct device *dev, void __iomem *regs)
/* Setup per-CPU IDC and target CPU mask */
current_cpu = get_cpu();
for (i = 0; i < priv->nr_idcs; i++) {
rc = aplic_direct_parse_parent_hwirq(dev, i, &hwirq, &hartid);
rc = aplic_direct_parse_parent_hwirq(dev, i, &hwirq, &hartid, priv);
if (rc) {
dev_warn(dev, "parent irq for IDC%d not found\n", i);
continue;
......
......@@ -4,8 +4,10 @@
* Copyright (C) 2022 Ventana Micro Systems Inc.
*/
#include <linux/acpi.h>
#include <linux/bitfield.h>
#include <linux/irqchip/riscv-aplic.h>
#include <linux/irqchip/riscv-imsic.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_irq.h>
......@@ -125,39 +127,50 @@ static void aplic_init_hw_irqs(struct aplic_priv *priv)
writel(0, priv->regs + APLIC_DOMAINCFG);
}
#ifdef CONFIG_ACPI
static const struct acpi_device_id aplic_acpi_match[] = {
{ "RSCV0002", 0 },
{}
};
MODULE_DEVICE_TABLE(acpi, aplic_acpi_match);
#endif
int aplic_setup_priv(struct aplic_priv *priv, struct device *dev, void __iomem *regs)
{
struct device_node *np = to_of_node(dev->fwnode);
struct of_phandle_args parent;
int rc;
/*
* Currently, only OF fwnode is supported so extend this
* function for ACPI support.
*/
if (!np)
return -EINVAL;
/* Save device pointer and register base */
priv->dev = dev;
priv->regs = regs;
/* Find out number of interrupt sources */
rc = of_property_read_u32(np, "riscv,num-sources", &priv->nr_irqs);
if (rc) {
dev_err(dev, "failed to get number of interrupt sources\n");
return rc;
}
/*
* Find out number of IDCs based on parent interrupts
*
* If "msi-parent" property is present then we ignore the
* APLIC IDCs which forces the APLIC driver to use MSI mode.
*/
if (!of_property_present(np, "msi-parent")) {
while (!of_irq_parse_one(np, priv->nr_idcs, &parent))
priv->nr_idcs++;
if (np) {
/* Find out number of interrupt sources */
rc = of_property_read_u32(np, "riscv,num-sources", &priv->nr_irqs);
if (rc) {
dev_err(dev, "failed to get number of interrupt sources\n");
return rc;
}
/*
* Find out number of IDCs based on parent interrupts
*
* If "msi-parent" property is present then we ignore the
* APLIC IDCs which forces the APLIC driver to use MSI mode.
*/
if (!of_property_present(np, "msi-parent")) {
while (!of_irq_parse_one(np, priv->nr_idcs, &parent))
priv->nr_idcs++;
}
} else {
rc = riscv_acpi_get_gsi_info(dev->fwnode, &priv->gsi_base, &priv->acpi_aplic_id,
&priv->nr_irqs, &priv->nr_idcs);
if (rc) {
dev_err(dev, "failed to find GSI mapping\n");
return rc;
}
}
/* Setup initial state APLIC interrupts */
......@@ -184,7 +197,11 @@ static int aplic_probe(struct platform_device *pdev)
* If msi-parent property is present then setup APLIC MSI
* mode otherwise setup APLIC direct mode.
*/
msi_mode = of_property_present(to_of_node(dev->fwnode), "msi-parent");
if (is_of_node(dev->fwnode))
msi_mode = of_property_present(to_of_node(dev->fwnode), "msi-parent");
else
msi_mode = imsic_acpi_get_fwnode(NULL) ? 1 : 0;
if (msi_mode)
rc = aplic_msi_setup(dev, regs);
else
......@@ -192,6 +209,11 @@ static int aplic_probe(struct platform_device *pdev)
if (rc)
dev_err(dev, "failed to setup APLIC in %s mode\n", msi_mode ? "MSI" : "direct");
#ifdef CONFIG_ACPI
if (!acpi_disabled)
acpi_dev_clear_dependencies(ACPI_COMPANION(dev));
#endif
return rc;
}
......@@ -204,6 +226,7 @@ static struct platform_driver aplic_driver = {
.driver = {
.name = "riscv-aplic",
.of_match_table = aplic_match,
.acpi_match_table = ACPI_PTR(aplic_acpi_match),
},
.probe = aplic_probe,
};
......
......@@ -28,6 +28,7 @@ struct aplic_priv {
u32 gsi_base;
u32 nr_irqs;
u32 nr_idcs;
u32 acpi_aplic_id;
void __iomem *regs;
struct aplic_msicfg msicfg;
};
......
......@@ -175,6 +175,7 @@ static const struct msi_domain_template aplic_msi_template = {
int aplic_msi_setup(struct device *dev, void __iomem *regs)
{
const struct imsic_global_config *imsic_global;
struct irq_domain *msi_domain;
struct aplic_priv *priv;
struct aplic_msicfg *mc;
phys_addr_t pa;
......@@ -257,8 +258,14 @@ int aplic_msi_setup(struct device *dev, void __iomem *regs)
* IMSIC and the IMSIC MSI domains are created later through
* the platform driver probing so we set it explicitly here.
*/
if (is_of_node(dev->fwnode))
if (is_of_node(dev->fwnode)) {
of_msi_configure(dev, to_of_node(dev->fwnode));
} else {
msi_domain = irq_find_matching_fwnode(imsic_acpi_get_fwnode(dev),
DOMAIN_BUS_PLATFORM_MSI);
if (msi_domain)
dev_set_msi_domain(dev, msi_domain);
}
}
if (!msi_create_device_irq_domain(dev, MSI_DEFAULT_DOMAIN, &aplic_msi_template,
......
......@@ -5,13 +5,16 @@
*/
#define pr_fmt(fmt) "riscv-imsic: " fmt
#include <linux/acpi.h>
#include <linux/cpu.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/irqchip.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/irqchip/riscv-imsic.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/spinlock.h>
#include <linux/smp.h>
......@@ -182,7 +185,7 @@ static int __init imsic_early_dt_init(struct device_node *node, struct device_no
int rc;
/* Setup IMSIC state */
rc = imsic_setup_state(fwnode);
rc = imsic_setup_state(fwnode, NULL);
if (rc) {
pr_err("%pfwP: failed to setup state (error %d)\n", fwnode, rc);
return rc;
......@@ -199,3 +202,62 @@ static int __init imsic_early_dt_init(struct device_node *node, struct device_no
}
IRQCHIP_DECLARE(riscv_imsic, "riscv,imsics", imsic_early_dt_init);
#ifdef CONFIG_ACPI
static struct fwnode_handle *imsic_acpi_fwnode;
struct fwnode_handle *imsic_acpi_get_fwnode(struct device *dev)
{
return imsic_acpi_fwnode;
}
static int __init imsic_early_acpi_init(union acpi_subtable_headers *header,
const unsigned long end)
{
struct acpi_madt_imsic *imsic = (struct acpi_madt_imsic *)header;
int rc;
imsic_acpi_fwnode = irq_domain_alloc_named_fwnode("imsic");
if (!imsic_acpi_fwnode) {
pr_err("unable to allocate IMSIC FW node\n");
return -ENOMEM;
}
/* Setup IMSIC state */
rc = imsic_setup_state(imsic_acpi_fwnode, imsic);
if (rc) {
pr_err("%pfwP: failed to setup state (error %d)\n", imsic_acpi_fwnode, rc);
return rc;
}
/* Do early setup of IMSIC state and IPIs */
rc = imsic_early_probe(imsic_acpi_fwnode);
if (rc) {
irq_domain_free_fwnode(imsic_acpi_fwnode);
imsic_acpi_fwnode = NULL;
return rc;
}
rc = imsic_platform_acpi_probe(imsic_acpi_fwnode);
#ifdef CONFIG_PCI
if (!rc)
pci_msi_register_fwnode_provider(&imsic_acpi_get_fwnode);
#endif
if (rc)
pr_err("%pfwP: failed to register IMSIC for MSI functionality (error %d)\n",
imsic_acpi_fwnode, rc);
/*
* Even if imsic_platform_acpi_probe() fails, the IPI part of IMSIC can
* continue to work. So, no need to return failure. This is similar to
* DT where IPI works but MSI probe fails for some reason.
*/
return 0;
}
IRQCHIP_ACPI_DECLARE(riscv_imsic, ACPI_MADT_TYPE_IMSIC, NULL,
1, imsic_early_acpi_init);
#endif
......@@ -5,6 +5,7 @@
*/
#define pr_fmt(fmt) "riscv-imsic: " fmt
#include <linux/acpi.h>
#include <linux/bitmap.h>
#include <linux/cpu.h>
#include <linux/interrupt.h>
......@@ -348,18 +349,37 @@ int imsic_irqdomain_init(void)
return 0;
}
static int imsic_platform_probe(struct platform_device *pdev)
static int imsic_platform_probe_common(struct fwnode_handle *fwnode)
{
struct device *dev = &pdev->dev;
if (imsic && imsic->fwnode != dev->fwnode) {
dev_err(dev, "fwnode mismatch\n");
if (imsic && imsic->fwnode != fwnode) {
pr_err("%pfwP: fwnode mismatch\n", fwnode);
return -ENODEV;
}
return imsic_irqdomain_init();
}
static int imsic_platform_dt_probe(struct platform_device *pdev)
{
return imsic_platform_probe_common(pdev->dev.fwnode);
}
#ifdef CONFIG_ACPI
/*
* On ACPI based systems, PCI enumeration happens early during boot in
* acpi_scan_init(). PCI enumeration expects MSI domain setup before
* it calls pci_set_msi_domain(). Hence, unlike in DT where
* imsic-platform drive probe happens late during boot, ACPI based
* systems need to setup the MSI domain early.
*/
int imsic_platform_acpi_probe(struct fwnode_handle *fwnode)
{
return imsic_platform_probe_common(fwnode);
}
#endif
static const struct of_device_id imsic_platform_match[] = {
{ .compatible = "riscv,imsics" },
{}
......@@ -370,6 +390,6 @@ static struct platform_driver imsic_platform_driver = {
.name = "riscv-imsic",
.of_match_table = imsic_platform_match,
},
.probe = imsic_platform_probe,
.probe = imsic_platform_dt_probe,
};
builtin_platform_driver(imsic_platform_driver);
......@@ -5,6 +5,7 @@
*/
#define pr_fmt(fmt) "riscv-imsic: " fmt
#include <linux/acpi.h>
#include <linux/cpu.h>
#include <linux/bitmap.h>
#include <linux/interrupt.h>
......@@ -510,18 +511,90 @@ static int __init imsic_matrix_init(void)
return 0;
}
static int __init imsic_populate_global_dt(struct fwnode_handle *fwnode,
struct imsic_global_config *global,
u32 *nr_parent_irqs)
{
int rc;
/* Find number of guest index bits in MSI address */
rc = of_property_read_u32(to_of_node(fwnode), "riscv,guest-index-bits",
&global->guest_index_bits);
if (rc)
global->guest_index_bits = 0;
/* Find number of HART index bits */
rc = of_property_read_u32(to_of_node(fwnode), "riscv,hart-index-bits",
&global->hart_index_bits);
if (rc) {
/* Assume default value */
global->hart_index_bits = __fls(*nr_parent_irqs);
if (BIT(global->hart_index_bits) < *nr_parent_irqs)
global->hart_index_bits++;
}
/* Find number of group index bits */
rc = of_property_read_u32(to_of_node(fwnode), "riscv,group-index-bits",
&global->group_index_bits);
if (rc)
global->group_index_bits = 0;
/*
* Find first bit position of group index.
* If not specified assumed the default APLIC-IMSIC configuration.
*/
rc = of_property_read_u32(to_of_node(fwnode), "riscv,group-index-shift",
&global->group_index_shift);
if (rc)
global->group_index_shift = IMSIC_MMIO_PAGE_SHIFT * 2;
/* Find number of interrupt identities */
rc = of_property_read_u32(to_of_node(fwnode), "riscv,num-ids",
&global->nr_ids);
if (rc) {
pr_err("%pfwP: number of interrupt identities not found\n", fwnode);
return rc;
}
/* Find number of guest interrupt identities */
rc = of_property_read_u32(to_of_node(fwnode), "riscv,num-guest-ids",
&global->nr_guest_ids);
if (rc)
global->nr_guest_ids = global->nr_ids;
return 0;
}
static int __init imsic_populate_global_acpi(struct fwnode_handle *fwnode,
struct imsic_global_config *global,
u32 *nr_parent_irqs, void *opaque)
{
struct acpi_madt_imsic *imsic = (struct acpi_madt_imsic *)opaque;
global->guest_index_bits = imsic->guest_index_bits;
global->hart_index_bits = imsic->hart_index_bits;
global->group_index_bits = imsic->group_index_bits;
global->group_index_shift = imsic->group_index_shift;
global->nr_ids = imsic->num_ids;
global->nr_guest_ids = imsic->num_guest_ids;
return 0;
}
static int __init imsic_get_parent_hartid(struct fwnode_handle *fwnode,
u32 index, unsigned long *hartid)
{
struct of_phandle_args parent;
int rc;
/*
* Currently, only OF fwnode is supported so extend this
* function for ACPI support.
*/
if (!is_of_node(fwnode))
return -EINVAL;
if (!is_of_node(fwnode)) {
if (hartid)
*hartid = acpi_rintc_index_to_hartid(index);
if (!hartid || (*hartid == INVALID_HARTID))
return -EINVAL;
return 0;
}
rc = of_irq_parse_one(to_of_node(fwnode), index, &parent);
if (rc)
......@@ -540,12 +613,8 @@ static int __init imsic_get_parent_hartid(struct fwnode_handle *fwnode,
static int __init imsic_get_mmio_resource(struct fwnode_handle *fwnode,
u32 index, struct resource *res)
{
/*
* Currently, only OF fwnode is supported so extend this
* function for ACPI support.
*/
if (!is_of_node(fwnode))
return -EINVAL;
return acpi_rintc_get_imsic_mmio_info(index, res);
return of_address_to_resource(to_of_node(fwnode), index, res);
}
......@@ -553,20 +622,14 @@ static int __init imsic_get_mmio_resource(struct fwnode_handle *fwnode,
static int __init imsic_parse_fwnode(struct fwnode_handle *fwnode,
struct imsic_global_config *global,
u32 *nr_parent_irqs,
u32 *nr_mmios)
u32 *nr_mmios,
void *opaque)
{
unsigned long hartid;
struct resource res;
int rc;
u32 i;
/*
* Currently, only OF fwnode is supported so extend this
* function for ACPI support.
*/
if (!is_of_node(fwnode))
return -EINVAL;
*nr_parent_irqs = 0;
*nr_mmios = 0;
......@@ -578,50 +641,13 @@ static int __init imsic_parse_fwnode(struct fwnode_handle *fwnode,
return -EINVAL;
}
/* Find number of guest index bits in MSI address */
rc = of_property_read_u32(to_of_node(fwnode), "riscv,guest-index-bits",
&global->guest_index_bits);
if (rc)
global->guest_index_bits = 0;
/* Find number of HART index bits */
rc = of_property_read_u32(to_of_node(fwnode), "riscv,hart-index-bits",
&global->hart_index_bits);
if (rc) {
/* Assume default value */
global->hart_index_bits = __fls(*nr_parent_irqs);
if (BIT(global->hart_index_bits) < *nr_parent_irqs)
global->hart_index_bits++;
}
/* Find number of group index bits */
rc = of_property_read_u32(to_of_node(fwnode), "riscv,group-index-bits",
&global->group_index_bits);
if (rc)
global->group_index_bits = 0;
if (is_of_node(fwnode))
rc = imsic_populate_global_dt(fwnode, global, nr_parent_irqs);
else
rc = imsic_populate_global_acpi(fwnode, global, nr_parent_irqs, opaque);
/*
* Find first bit position of group index.
* If not specified assumed the default APLIC-IMSIC configuration.
*/
rc = of_property_read_u32(to_of_node(fwnode), "riscv,group-index-shift",
&global->group_index_shift);
if (rc)
global->group_index_shift = IMSIC_MMIO_PAGE_SHIFT * 2;
/* Find number of interrupt identities */
rc = of_property_read_u32(to_of_node(fwnode), "riscv,num-ids",
&global->nr_ids);
if (rc) {
pr_err("%pfwP: number of interrupt identities not found\n", fwnode);
return rc;
}
/* Find number of guest interrupt identities */
rc = of_property_read_u32(to_of_node(fwnode), "riscv,num-guest-ids",
&global->nr_guest_ids);
if (rc)
global->nr_guest_ids = global->nr_ids;
/* Sanity check guest index bits */
i = BITS_PER_LONG - IMSIC_MMIO_PAGE_SHIFT;
......@@ -688,7 +714,7 @@ static int __init imsic_parse_fwnode(struct fwnode_handle *fwnode,
return 0;
}
int __init imsic_setup_state(struct fwnode_handle *fwnode)
int __init imsic_setup_state(struct fwnode_handle *fwnode, void *opaque)
{
u32 i, j, index, nr_parent_irqs, nr_mmios, nr_handlers = 0;
struct imsic_global_config *global;
......@@ -729,7 +755,7 @@ int __init imsic_setup_state(struct fwnode_handle *fwnode)
}
/* Parse IMSIC fwnode */
rc = imsic_parse_fwnode(fwnode, global, &nr_parent_irqs, &nr_mmios);
rc = imsic_parse_fwnode(fwnode, global, &nr_parent_irqs, &nr_mmios, opaque);
if (rc)
goto out_free_local;
......
......@@ -102,7 +102,7 @@ void imsic_vector_debug_show_summary(struct seq_file *m, int ind);
void imsic_state_online(void);
void imsic_state_offline(void);
int imsic_setup_state(struct fwnode_handle *fwnode);
int imsic_setup_state(struct fwnode_handle *fwnode, void *opaque);
int imsic_irqdomain_init(void);
#endif
......@@ -250,6 +250,85 @@ IRQCHIP_DECLARE(andes, "andestech,cpu-intc", riscv_intc_init);
#ifdef CONFIG_ACPI
struct rintc_data {
union {
u32 ext_intc_id;
struct {
u32 context_id : 16,
reserved : 8,
aplic_plic_id : 8;
};
};
unsigned long hart_id;
u64 imsic_addr;
u32 imsic_size;
};
static u32 nr_rintc;
static struct rintc_data *rintc_acpi_data[NR_CPUS];
#define for_each_matching_plic(_plic_id) \
unsigned int _plic; \
\
for (_plic = 0; _plic < nr_rintc; _plic++) \
if (rintc_acpi_data[_plic]->aplic_plic_id != _plic_id) \
continue; \
else
unsigned int acpi_rintc_get_plic_nr_contexts(unsigned int plic_id)
{
unsigned int nctx = 0;
for_each_matching_plic(plic_id)
nctx++;
return nctx;
}
static struct rintc_data *get_plic_context(unsigned int plic_id, unsigned int ctxt_idx)
{
unsigned int ctxt = 0;
for_each_matching_plic(plic_id) {
if (ctxt == ctxt_idx)
return rintc_acpi_data[_plic];
ctxt++;
}
return NULL;
}
unsigned long acpi_rintc_ext_parent_to_hartid(unsigned int plic_id, unsigned int ctxt_idx)
{
struct rintc_data *data = get_plic_context(plic_id, ctxt_idx);
return data ? data->hart_id : INVALID_HARTID;
}
unsigned int acpi_rintc_get_plic_context(unsigned int plic_id, unsigned int ctxt_idx)
{
struct rintc_data *data = get_plic_context(plic_id, ctxt_idx);
return data ? data->context_id : INVALID_CONTEXT;
}
unsigned long acpi_rintc_index_to_hartid(u32 index)
{
return index >= nr_rintc ? INVALID_HARTID : rintc_acpi_data[index]->hart_id;
}
int acpi_rintc_get_imsic_mmio_info(u32 index, struct resource *res)
{
if (index >= nr_rintc)
return -1;
res->start = rintc_acpi_data[index]->imsic_addr;
res->end = res->start + rintc_acpi_data[index]->imsic_size - 1;
res->flags = IORESOURCE_MEM;
return 0;
}
static int __init riscv_intc_acpi_init(union acpi_subtable_headers *header,
const unsigned long end)
{
......@@ -258,6 +337,15 @@ static int __init riscv_intc_acpi_init(union acpi_subtable_headers *header,
int rc;
rintc = (struct acpi_madt_rintc *)header;
rintc_acpi_data[nr_rintc] = kzalloc(sizeof(*rintc_acpi_data[0]), GFP_KERNEL);
if (!rintc_acpi_data[nr_rintc])
return -ENOMEM;
rintc_acpi_data[nr_rintc]->ext_intc_id = rintc->ext_intc_id;
rintc_acpi_data[nr_rintc]->hart_id = rintc->hart_id;
rintc_acpi_data[nr_rintc]->imsic_addr = rintc->imsic_addr;
rintc_acpi_data[nr_rintc]->imsic_size = rintc->imsic_size;
nr_rintc++;
/*
* The ACPI MADT will have one INTC for each CPU (or HART)
......@@ -277,6 +365,8 @@ static int __init riscv_intc_acpi_init(union acpi_subtable_headers *header,
rc = riscv_intc_init_common(fn, &riscv_intc_chip);
if (rc)
irq_domain_free_fwnode(fn);
else
acpi_set_irq_model(ACPI_IRQ_MODEL_RINTC, riscv_acpi_get_gsi_domain_id);
return rc;
}
......
......@@ -4,6 +4,7 @@
* Copyright (C) 2018 Christoph Hellwig
*/
#define pr_fmt(fmt) "riscv-plic: " fmt
#include <linux/acpi.h>
#include <linux/cpu.h>
#include <linux/interrupt.h>
#include <linux/io.h>
......@@ -71,6 +72,8 @@ struct plic_priv {
unsigned long plic_quirks;
unsigned int nr_irqs;
unsigned long *prio_save;
u32 gsi_base;
int acpi_plic_id;
};
struct plic_handler {
......@@ -325,6 +328,10 @@ static int plic_irq_domain_translate(struct irq_domain *d,
{
struct plic_priv *priv = d->host_data;
/* For DT, gsi_base is always zero. */
if (fwspec->param[0] >= priv->gsi_base)
fwspec->param[0] = fwspec->param[0] - priv->gsi_base;
if (test_bit(PLIC_QUIRK_EDGE_INTERRUPT, &priv->plic_quirks))
return irq_domain_translate_twocell(d, fwspec, hwirq, type);
......@@ -426,17 +433,36 @@ static const struct of_device_id plic_match[] = {
{}
};
#ifdef CONFIG_ACPI
static const struct acpi_device_id plic_acpi_match[] = {
{ "RSCV0001", 0 },
{}
};
MODULE_DEVICE_TABLE(acpi, plic_acpi_match);
#endif
static int plic_parse_nr_irqs_and_contexts(struct fwnode_handle *fwnode,
u32 *nr_irqs, u32 *nr_contexts)
u32 *nr_irqs, u32 *nr_contexts,
u32 *gsi_base, u32 *id)
{
int rc;
/*
* Currently, only OF fwnode is supported so extend this
* function for ACPI support.
*/
if (!is_of_node(fwnode))
return -EINVAL;
if (!is_of_node(fwnode)) {
rc = riscv_acpi_get_gsi_info(fwnode, gsi_base, id, nr_irqs, NULL);
if (rc) {
pr_err("%pfwP: failed to find GSI mapping\n", fwnode);
return rc;
}
*nr_contexts = acpi_rintc_get_plic_nr_contexts(*id);
if (WARN_ON(!*nr_contexts)) {
pr_err("%pfwP: no PLIC context available\n", fwnode);
return -EINVAL;
}
return 0;
}
rc = of_property_read_u32(to_of_node(fwnode), "riscv,ndev", nr_irqs);
if (rc) {
......@@ -450,22 +476,28 @@ static int plic_parse_nr_irqs_and_contexts(struct fwnode_handle *fwnode,
return -EINVAL;
}
*gsi_base = 0;
*id = 0;
return 0;
}
static int plic_parse_context_parent(struct fwnode_handle *fwnode, u32 context,
u32 *parent_hwirq, int *parent_cpu)
u32 *parent_hwirq, int *parent_cpu, u32 id)
{
struct of_phandle_args parent;
unsigned long hartid;
int rc;
/*
* Currently, only OF fwnode is supported so extend this
* function for ACPI support.
*/
if (!is_of_node(fwnode))
return -EINVAL;
if (!is_of_node(fwnode)) {
hartid = acpi_rintc_ext_parent_to_hartid(id, context);
if (hartid == INVALID_HARTID)
return -EINVAL;
*parent_cpu = riscv_hartid_to_cpuid(hartid);
*parent_hwirq = RV_IRQ_EXT;
return 0;
}
rc = of_irq_parse_one(to_of_node(fwnode), context, &parent);
if (rc)
......@@ -489,6 +521,8 @@ static int plic_probe(struct fwnode_handle *fwnode)
struct plic_priv *priv;
irq_hw_number_t hwirq;
void __iomem *regs;
int id, context_id;
u32 gsi_base;
if (is_of_node(fwnode)) {
const struct of_device_id *id;
......@@ -501,10 +535,12 @@ static int plic_probe(struct fwnode_handle *fwnode)
if (!regs)
return -ENOMEM;
} else {
return -ENODEV;
regs = devm_platform_ioremap_resource(to_platform_device(fwnode->dev), 0);
if (IS_ERR(regs))
return PTR_ERR(regs);
}
error = plic_parse_nr_irqs_and_contexts(fwnode, &nr_irqs, &nr_contexts);
error = plic_parse_nr_irqs_and_contexts(fwnode, &nr_irqs, &nr_contexts, &gsi_base, &id);
if (error)
goto fail_free_regs;
......@@ -518,6 +554,8 @@ static int plic_probe(struct fwnode_handle *fwnode)
priv->plic_quirks = plic_quirks;
priv->nr_irqs = nr_irqs;
priv->regs = regs;
priv->gsi_base = gsi_base;
priv->acpi_plic_id = id;
priv->prio_save = bitmap_zalloc(nr_irqs, GFP_KERNEL);
if (!priv->prio_save) {
......@@ -526,12 +564,23 @@ static int plic_probe(struct fwnode_handle *fwnode)
}
for (i = 0; i < nr_contexts; i++) {
error = plic_parse_context_parent(fwnode, i, &parent_hwirq, &cpu);
error = plic_parse_context_parent(fwnode, i, &parent_hwirq, &cpu,
priv->acpi_plic_id);
if (error) {
pr_warn("%pfwP: hwirq for context%d not found\n", fwnode, i);
continue;
}
if (is_of_node(fwnode)) {
context_id = i;
} else {
context_id = acpi_rintc_get_plic_context(priv->acpi_plic_id, i);
if (context_id == INVALID_CONTEXT) {
pr_warn("%pfwP: invalid context id for context%d\n", fwnode, i);
continue;
}
}
/*
* Skip contexts other than external interrupts for our
* privilege level.
......@@ -569,10 +618,10 @@ static int plic_probe(struct fwnode_handle *fwnode)
cpumask_set_cpu(cpu, &priv->lmask);
handler->present = true;
handler->hart_base = priv->regs + CONTEXT_BASE +
i * CONTEXT_SIZE;
context_id * CONTEXT_SIZE;
raw_spin_lock_init(&handler->enable_lock);
handler->enable_base = priv->regs + CONTEXT_ENABLE_BASE +
i * CONTEXT_ENABLE_SIZE;
context_id * CONTEXT_ENABLE_SIZE;
handler->priv = priv;
handler->enable_save = kcalloc(DIV_ROUND_UP(nr_irqs, 32),
......@@ -588,8 +637,8 @@ static int plic_probe(struct fwnode_handle *fwnode)
nr_handlers++;
}
priv->irqdomain = irq_domain_add_linear(to_of_node(fwnode), nr_irqs + 1,
&plic_irqdomain_ops, priv);
priv->irqdomain = irq_domain_create_linear(fwnode, nr_irqs + 1,
&plic_irqdomain_ops, priv);
if (WARN_ON(!priv->irqdomain))
goto fail_cleanup_contexts;
......@@ -626,13 +675,18 @@ static int plic_probe(struct fwnode_handle *fwnode)
}
}
#ifdef CONFIG_ACPI
if (!acpi_disabled)
acpi_dev_clear_dependencies(ACPI_COMPANION(fwnode->dev));
#endif
pr_info("%pfwP: mapped %d interrupts with %d handlers for %d contexts.\n",
fwnode, nr_irqs, nr_handlers, nr_contexts);
return 0;
fail_cleanup_contexts:
for (i = 0; i < nr_contexts; i++) {
if (plic_parse_context_parent(fwnode, i, &parent_hwirq, &cpu))
if (plic_parse_context_parent(fwnode, i, &parent_hwirq, &cpu, priv->acpi_plic_id))
continue;
if (parent_hwirq != RV_IRQ_EXT || cpu < 0)
continue;
......@@ -663,6 +717,7 @@ static struct platform_driver plic_driver = {
.name = "riscv-plic",
.of_match_table = plic_match,
.suppress_bind_attrs = true,
.acpi_match_table = ACPI_PTR(plic_acpi_match),
},
.probe = plic_platform_probe,
};
......
......@@ -15,6 +15,7 @@
#include <linux/pci_hotplug.h>
#include <linux/module.h>
#include <linux/pci-acpi.h>
#include <linux/pci-ecam.h>
#include <linux/pm_runtime.h>
#include <linux/pm_qos.h>
#include <linux/rwsem.h>
......@@ -1541,3 +1542,184 @@ static int __init acpi_pci_init(void)
return 0;
}
arch_initcall(acpi_pci_init);
#if defined(CONFIG_ARM64) || defined(CONFIG_RISCV)
/*
* Try to assign the IRQ number when probing a new device
*/
int pcibios_alloc_irq(struct pci_dev *dev)
{
if (!acpi_disabled)
acpi_pci_irq_enable(dev);
return 0;
}
struct acpi_pci_generic_root_info {
struct acpi_pci_root_info common;
struct pci_config_window *cfg; /* config space mapping */
};
int acpi_pci_bus_find_domain_nr(struct pci_bus *bus)
{
struct pci_config_window *cfg = bus->sysdata;
struct acpi_device *adev = to_acpi_device(cfg->parent);
struct acpi_pci_root *root = acpi_driver_data(adev);
return root->segment;
}
int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
{
struct pci_config_window *cfg;
struct acpi_device *adev;
struct device *bus_dev;
if (acpi_disabled)
return 0;
cfg = bridge->bus->sysdata;
/*
* On Hyper-V there is no corresponding ACPI device for a root bridge,
* therefore ->parent is set as NULL by the driver. And set 'adev' as
* NULL in this case because there is no proper ACPI device.
*/
if (!cfg->parent)
adev = NULL;
else
adev = to_acpi_device(cfg->parent);
bus_dev = &bridge->bus->dev;
ACPI_COMPANION_SET(&bridge->dev, adev);
set_dev_node(bus_dev, acpi_get_node(acpi_device_handle(adev)));
return 0;
}
static int pci_acpi_root_prepare_resources(struct acpi_pci_root_info *ci)
{
struct resource_entry *entry, *tmp;
int status;
status = acpi_pci_probe_root_resources(ci);
resource_list_for_each_entry_safe(entry, tmp, &ci->resources) {
if (!(entry->res->flags & IORESOURCE_WINDOW))
resource_list_destroy_entry(entry);
}
return status;
}
/*
* Lookup the bus range for the domain in MCFG, and set up config space
* mapping.
*/
static struct pci_config_window *
pci_acpi_setup_ecam_mapping(struct acpi_pci_root *root)
{
struct device *dev = &root->device->dev;
struct resource *bus_res = &root->secondary;
u16 seg = root->segment;
const struct pci_ecam_ops *ecam_ops;
struct resource cfgres;
struct acpi_device *adev;
struct pci_config_window *cfg;
int ret;
ret = pci_mcfg_lookup(root, &cfgres, &ecam_ops);
if (ret) {
dev_err(dev, "%04x:%pR ECAM region not found\n", seg, bus_res);
return NULL;
}
adev = acpi_resource_consumer(&cfgres);
if (adev)
dev_info(dev, "ECAM area %pR reserved by %s\n", &cfgres,
dev_name(&adev->dev));
else
dev_warn(dev, FW_BUG "ECAM area %pR not reserved in ACPI namespace\n",
&cfgres);
cfg = pci_ecam_create(dev, &cfgres, bus_res, ecam_ops);
if (IS_ERR(cfg)) {
dev_err(dev, "%04x:%pR error %ld mapping ECAM\n", seg, bus_res,
PTR_ERR(cfg));
return NULL;
}
return cfg;
}
/* release_info: free resources allocated by init_info */
static void pci_acpi_generic_release_info(struct acpi_pci_root_info *ci)
{
struct acpi_pci_generic_root_info *ri;
ri = container_of(ci, struct acpi_pci_generic_root_info, common);
pci_ecam_free(ri->cfg);
kfree(ci->ops);
kfree(ri);
}
/* Interface called from ACPI code to setup PCI host controller */
struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
{
struct acpi_pci_generic_root_info *ri;
struct pci_bus *bus, *child;
struct acpi_pci_root_ops *root_ops;
struct pci_host_bridge *host;
ri = kzalloc(sizeof(*ri), GFP_KERNEL);
if (!ri)
return NULL;
root_ops = kzalloc(sizeof(*root_ops), GFP_KERNEL);
if (!root_ops) {
kfree(ri);
return NULL;
}
ri->cfg = pci_acpi_setup_ecam_mapping(root);
if (!ri->cfg) {
kfree(ri);
kfree(root_ops);
return NULL;
}
root_ops->release_info = pci_acpi_generic_release_info;
root_ops->prepare_resources = pci_acpi_root_prepare_resources;
root_ops->pci_ops = (struct pci_ops *)&ri->cfg->ops->pci_ops;
bus = acpi_pci_root_create(root, root_ops, &ri->common, ri->cfg);
if (!bus)
return NULL;
/* If we must preserve the resource configuration, claim now */
host = pci_find_host_bridge(bus);
if (host->preserve_config)
pci_bus_claim_resources(bus);
/*
* Assign whatever was left unassigned. If we didn't claim above,
* this will reassign everything.
*/
pci_assign_unassigned_root_bus_resources(bus);
list_for_each_entry(child, &bus->children, node)
pcie_bus_configure_settings(child);
return bus;
}
void pcibios_add_bus(struct pci_bus *bus)
{
acpi_pci_add_bus(bus);
}
void pcibios_remove_bus(struct pci_bus *bus)
{
acpi_pci_remove_bus(bus);
}
#endif
......@@ -67,7 +67,6 @@
* General Purpose Events (GPEs)
* Global Lock
* ACPI PM timer
* FACS table (Waking vectors and Global Lock)
*/
#ifndef ACPI_REDUCED_HARDWARE
#define ACPI_REDUCED_HARDWARE FALSE
......
......@@ -193,6 +193,7 @@
*/
#ifndef ACPI_NO_ERROR_MESSAGES
#define AE_INFO _acpi_module_name, __LINE__
#define ACPI_ONCE(_fn, _plist) { static char _done; if (!_done) { _done = 1; _fn _plist; } }
/*
* Error reporting. Callers module and line number are inserted by AE_INFO,
......@@ -201,8 +202,10 @@
*/
#define ACPI_INFO(plist) acpi_info plist
#define ACPI_WARNING(plist) acpi_warning plist
#define ACPI_WARNING_ONCE(plist) ACPI_ONCE(acpi_warning, plist)
#define ACPI_EXCEPTION(plist) acpi_exception plist
#define ACPI_ERROR(plist) acpi_error plist
#define ACPI_ERROR_ONCE(plist) ACPI_ONCE(acpi_error, plist)
#define ACPI_BIOS_WARNING(plist) acpi_bios_warning plist
#define ACPI_BIOS_EXCEPTION(plist) acpi_bios_exception plist
#define ACPI_BIOS_ERROR(plist) acpi_bios_error plist
......@@ -214,8 +217,10 @@
#define ACPI_INFO(plist)
#define ACPI_WARNING(plist)
#define ACPI_WARNING_ONCE(plist)
#define ACPI_EXCEPTION(plist)
#define ACPI_ERROR(plist)
#define ACPI_ERROR_ONCE(plist)
#define ACPI_BIOS_WARNING(plist)
#define ACPI_BIOS_EXCEPTION(plist)
#define ACPI_BIOS_ERROR(plist)
......
......@@ -228,10 +228,12 @@ struct acpi_device_dir {
/* Plug and Play */
#define MAX_ACPI_DEVICE_NAME_LEN 40
#define MAX_ACPI_CLASS_NAME_LEN 20
typedef char acpi_bus_id[8];
typedef u64 acpi_bus_address;
typedef char acpi_device_name[40];
typedef char acpi_device_class[20];
typedef char acpi_device_name[MAX_ACPI_DEVICE_NAME_LEN];
typedef char acpi_device_class[MAX_ACPI_CLASS_NAME_LEN];
struct acpi_hardware_id {
struct list_head list;
......@@ -255,7 +257,6 @@ struct acpi_device_pnp {
struct list_head ids; /* _HID and _CIDs */
acpi_device_name device_name; /* Driver-determined */
acpi_device_class device_class; /* " */
union acpi_object *str_obj; /* unicode string for _STR method */
};
#define acpi_device_bid(d) ((d)->pnp.bus_id)
......@@ -993,6 +994,8 @@ static inline void acpi_put_acpi_dev(struct acpi_device *adev)
int acpi_wait_for_acpi_ipmi(void);
int acpi_scan_add_dep(acpi_handle handle, struct acpi_handle_list *dep_devices);
u32 arch_acpi_add_auto_dep(acpi_handle handle);
#else /* CONFIG_ACPI */
static inline int register_acpi_bus_type(void *bus) { return 0; }
......
......@@ -12,7 +12,7 @@
/* Current ACPICA subsystem version in YYYYMMDD format */
#define ACPI_CA_VERSION 0x20240322
#define ACPI_CA_VERSION 0x20240827
#include <acpi/acconfig.h>
#include <acpi/actypes.h>
......@@ -878,10 +878,10 @@ ACPI_EXTERNAL_RETURN_STATUS(acpi_status
acpi_leave_sleep_state_prep(u8 sleep_state))
ACPI_EXTERNAL_RETURN_STATUS(acpi_status acpi_leave_sleep_state(u8 sleep_state))
ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
acpi_set_firmware_waking_vector
(acpi_physical_address physical_address,
acpi_physical_address physical_address64))
ACPI_EXTERNAL_RETURN_STATUS(acpi_status
acpi_set_firmware_waking_vector
(acpi_physical_address physical_address,
acpi_physical_address physical_address64))
/*
* ACPI Timer interfaces
*/
......
......@@ -567,6 +567,10 @@ struct acpi_cedt_cxims {
u64 xormap_list[];
};
struct acpi_cedt_cxims_target_element {
u64 xormap;
};
/* 3: CXL RCEC Downstream Port Association Structure */
struct acpi_cedt_rdpas {
......@@ -751,6 +755,7 @@ struct acpi_dbg2_device {
#define ACPI_DBG2_16550_WITH_GAS 0x0012
#define ACPI_DBG2_SDM845_7_372MHZ 0x0013
#define ACPI_DBG2_INTEL_LPSS 0x0014
#define ACPI_DBG2_RISCV_SBI_CON 0x0015
#define ACPI_DBG2_1394_STANDARD 0x0000
......@@ -1791,7 +1796,7 @@ struct acpi_hmat_cache {
u32 reserved1;
u64 cache_size;
u32 cache_attributes;
u16 reserved2;
u16 address_mode;
u16 number_of_SMBIOShandles;
};
......@@ -1803,6 +1808,9 @@ struct acpi_hmat_cache {
#define ACPI_HMAT_WRITE_POLICY (0x0000F000)
#define ACPI_HMAT_CACHE_LINE_SIZE (0xFFFF0000)
#define ACPI_HMAT_CACHE_MODE_UNKNOWN (0)
#define ACPI_HMAT_CACHE_MODE_EXTENDED_LINEAR (1)
/* Values for cache associativity flag */
#define ACPI_HMAT_CA_NONE (0)
......
......@@ -1607,7 +1607,7 @@ struct acpi_mpam_msc_node {
u32 max_nrdy_usec;
u64 hardware_id_linked_device;
u32 instance_id_linked_device;
u32 num_resouce_nodes;
u32 num_resource_nodes;
};
struct acpi_table_mpam {
......
......@@ -92,10 +92,10 @@ struct acpi_table_slit {
/*******************************************************************************
*
* SPCR - Serial Port Console Redirection table
* Version 2
* Version 4
*
* Conforms to "Serial Port Console Redirection Table",
* Version 1.03, August 10, 2015
* Version 1.10, Jan 5, 2023
*
******************************************************************************/
......@@ -112,7 +112,7 @@ struct acpi_table_spcr {
u8 stop_bits;
u8 flow_control;
u8 terminal_type;
u8 reserved1;
u8 language;
u16 pci_device_id;
u16 pci_vendor_id;
u8 pci_bus;
......@@ -120,7 +120,11 @@ struct acpi_table_spcr {
u8 pci_function;
u32 pci_flags;
u8 pci_segment;
u32 reserved2;
u32 uart_clk_freq;
u32 precise_baudrate;
u16 name_space_string_length;
u16 name_space_string_offset;
char name_space_string[];
};
/* Masks for pci_flags field above */
......
......@@ -1311,6 +1311,7 @@ typedef enum {
#define ACPI_OSI_WIN_10_19H1 0x14
#define ACPI_OSI_WIN_10_20H1 0x15
#define ACPI_OSI_WIN_11 0x16
#define ACPI_OSI_WIN_11_22H2 0x17
/* Definitions of getopt */
......
......@@ -64,6 +64,8 @@ struct cpc_desc {
int cpu_id;
int write_cmd_status;
int write_cmd_id;
/* Lock used for RMW operations in cpc_write() */
spinlock_t rmw_lock;
struct cpc_register_resource cpc_regs[MAX_CPC_REG_ENT];
struct acpi_psd_package domain_info;
struct kobject kobj;
......
......@@ -252,6 +252,12 @@
#define ACPI_RELEASE_GLOBAL_LOCK(Glptr, pending) pending = 0
#endif
/* NULL/invalid value to use for destroyed or not-yet-created semaphores. */
#ifndef ACPI_SEMAPHORE_NULL
#define ACPI_SEMAPHORE_NULL NULL
#endif
/* Flush CPU cache - used when going to sleep. Wbinvd or similar. */
#ifndef ACPI_FLUSH_CPU_CACHE
......
......@@ -107,6 +107,7 @@ enum acpi_irq_model_id {
ACPI_IRQ_MODEL_PLATFORM,
ACPI_IRQ_MODEL_GIC,
ACPI_IRQ_MODEL_LPIC,
ACPI_IRQ_MODEL_RINTC,
ACPI_IRQ_MODEL_COUNT
};
......@@ -1343,6 +1344,8 @@ struct acpi_probe_entry {
kernel_ulong_t driver_data;
};
void arch_sort_irqchip_probe(struct acpi_probe_entry *ap_head, int nr);
#define ACPI_DECLARE_PROBE_ENTRY(table, name, table_id, subtable, \
valid, data, fn) \
static const struct acpi_probe_entry __acpi_probe_##name \
......@@ -1529,6 +1532,12 @@ void acpi_arm_init(void);
static inline void acpi_arm_init(void) { }
#endif
#ifdef CONFIG_RISCV
void acpi_riscv_init(void);
#else
static inline void acpi_riscv_init(void) { }
#endif
#ifdef CONFIG_ACPI_PCC
void acpi_init_pcc(void);
#else
......
......@@ -8,6 +8,8 @@
#include <linux/types.h>
#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/fwnode.h>
#include <asm/csr.h>
#define IMSIC_MMIO_PAGE_SHIFT 12
......@@ -84,4 +86,11 @@ static inline const struct imsic_global_config *imsic_get_global_config(void)
#endif
#ifdef CONFIG_ACPI
int imsic_platform_acpi_probe(struct fwnode_handle *fwnode);
struct fwnode_handle *imsic_acpi_get_fwnode(struct device *dev);
#else
static inline struct fwnode_handle *imsic_acpi_get_fwnode(struct device *dev) { return NULL; }
#endif
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment