From c793504de3de484076e1eb96d5187af55f47945c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 2 Feb 2015 10:42:47 +0800 Subject: ACPI: Remove redundant check in function acpi_dev_resource_address_space() The ACPI type is checked in acpi_resource_to_address64() anyway. Signed-off-by: Thomas Gleixner Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/resource.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index d0a4d90c6bcc..1c616a56e007 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -189,15 +189,6 @@ bool acpi_dev_resource_address_space(struct acpi_resource *ares, u64 len; u8 io_decode; - switch (ares->type) { - case ACPI_RESOURCE_TYPE_ADDRESS16: - case ACPI_RESOURCE_TYPE_ADDRESS32: - case ACPI_RESOURCE_TYPE_ADDRESS64: - break; - default: - return false; - } - status = acpi_resource_to_address64(ares, &addr); if (ACPI_FAILURE(status)) return false; -- cgit v1.2.1 From c420dbd13ef7f399a865498496ac9ce2755b8007 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 2 Feb 2015 10:42:48 +0800 Subject: ACPI: Implement proper length checks for mem resources Check whether the resulting length is the same as the given length. Check for start <= end as well. We need to hand in the resource for this, so we can apply the flags directly. [Jiang] Remove enforcement that resource starting address must be non-zero. Signed-off-by: Thomas Gleixner Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/resource.c | 62 ++++++++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 27 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 1c616a56e007..3e7d9f6eb875 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -34,21 +34,37 @@ #define valid_IRQ(i) (true) #endif -static unsigned long acpi_dev_memresource_flags(u64 len, u8 write_protect, - bool window) +static bool acpi_dev_resource_len_valid(u64 start, u64 end, u64 len, bool io) { - unsigned long flags = IORESOURCE_MEM; + u64 reslen = end - start + 1; - if (len == 0) - flags |= IORESOURCE_DISABLED; + /* + * CHECKME: len might be required to check versus a minimum + * length as well. 1 for io is fine, but for memory it does + * not make any sense at all. + */ + if (len && reslen && reslen == len && start <= end) + return true; + + pr_info("ACPI: invalid or unassigned resource %s [%016llx - %016llx] length [%016llx]\n", + io ? "io" : "mem", start, end, len); + + return false; +} + +static void acpi_dev_memresource_flags(struct resource *res, u64 len, + u8 write_protect, bool window) +{ + res->flags = IORESOURCE_MEM; + + if (!acpi_dev_resource_len_valid(res->start, res->end, len, false)) + res->flags |= IORESOURCE_DISABLED; if (write_protect == ACPI_READ_WRITE_MEMORY) - flags |= IORESOURCE_MEM_WRITEABLE; + res->flags |= IORESOURCE_MEM_WRITEABLE; if (window) - flags |= IORESOURCE_WINDOW; - - return flags; + res->flags |= IORESOURCE_WINDOW; } static void acpi_dev_get_memresource(struct resource *res, u64 start, u64 len, @@ -56,7 +72,7 @@ static void acpi_dev_get_memresource(struct resource *res, u64 start, u64 len, { res->start = start; res->end = start + len - 1; - res->flags = acpi_dev_memresource_flags(len, write_protect, false); + acpi_dev_memresource_flags(res, len, write_protect, false); } /** @@ -77,24 +93,18 @@ bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res) switch (ares->type) { case ACPI_RESOURCE_TYPE_MEMORY24: memory24 = &ares->data.memory24; - if (!memory24->minimum && !memory24->address_length) - return false; acpi_dev_get_memresource(res, memory24->minimum, memory24->address_length, memory24->write_protect); break; case ACPI_RESOURCE_TYPE_MEMORY32: memory32 = &ares->data.memory32; - if (!memory32->minimum && !memory32->address_length) - return false; acpi_dev_get_memresource(res, memory32->minimum, memory32->address_length, memory32->write_protect); break; case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: fixed_memory32 = &ares->data.fixed_memory32; - if (!fixed_memory32->address && !fixed_memory32->address_length) - return false; acpi_dev_get_memresource(res, fixed_memory32->address, fixed_memory32->address_length, fixed_memory32->write_protect); @@ -102,7 +112,8 @@ bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res) default: return false; } - return true; + + return !(res->flags & IORESOURCE_DISABLED); } EXPORT_SYMBOL_GPL(acpi_dev_resource_memory); @@ -186,7 +197,6 @@ bool acpi_dev_resource_address_space(struct acpi_resource *ares, acpi_status status; struct acpi_resource_address64 addr; bool window; - u64 len; u8 io_decode; status = acpi_resource_to_address64(ares, &addr); @@ -199,10 +209,9 @@ bool acpi_dev_resource_address_space(struct acpi_resource *ares, switch(addr.resource_type) { case ACPI_MEMORY_RANGE: - len = addr.address.maximum - addr.address.minimum + 1; - res->flags = acpi_dev_memresource_flags(len, - addr.info.mem.write_protect, - window); + acpi_dev_memresource_flags(res, addr.address.address_length, + addr.info.mem.write_protect, + window); break; case ACPI_IO_RANGE: io_decode = addr.address.granularity == 0xfff ? @@ -236,7 +245,6 @@ bool acpi_dev_resource_ext_address_space(struct acpi_resource *ares, { struct acpi_resource_extended_address64 *ext_addr; bool window; - u64 len; u8 io_decode; if (ares->type != ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64) @@ -250,10 +258,10 @@ bool acpi_dev_resource_ext_address_space(struct acpi_resource *ares, switch(ext_addr->resource_type) { case ACPI_MEMORY_RANGE: - len = ext_addr->address.maximum - ext_addr->address.minimum + 1; - res->flags = acpi_dev_memresource_flags(len, - ext_addr->info.mem.write_protect, - window); + acpi_dev_memresource_flags(res, + ext_addr->address.address_length, + ext_addr->info.mem.write_protect, + window); break; case ACPI_IO_RANGE: io_decode = ext_addr->address.granularity == 0xfff ? -- cgit v1.2.1 From 1d0420f1cfc4763a8c5bfc617e0a40f710c2f74d Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 2 Feb 2015 10:42:49 +0800 Subject: ACPI: Use the length check for io resources as well Also apply length check to IO resources. [Jiang] Remove enforcement that resource starting address must be non-zero. Signed-off-by: Thomas Gleixner Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/resource.c | 44 +++++++++++++++++++------------------------- 1 file changed, 19 insertions(+), 25 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 3e7d9f6eb875..16d291c60277 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -117,31 +117,30 @@ bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res) } EXPORT_SYMBOL_GPL(acpi_dev_resource_memory); -static unsigned int acpi_dev_ioresource_flags(u64 start, u64 end, u8 io_decode, - bool window) +static void acpi_dev_ioresource_flags(struct resource *res, u64 len, + u8 io_decode, bool window) { - int flags = IORESOURCE_IO; + res->flags = IORESOURCE_IO; - if (io_decode == ACPI_DECODE_16) - flags |= IORESOURCE_IO_16BIT_ADDR; + if (!acpi_dev_resource_len_valid(res->start, res->end, len, true)) + res->flags |= IORESOURCE_DISABLED; - if (start > end || end >= 0x10003) - flags |= IORESOURCE_DISABLED; + if (res->end >= 0x10003) + res->flags |= IORESOURCE_DISABLED; - if (window) - flags |= IORESOURCE_WINDOW; + if (io_decode == ACPI_DECODE_16) + res->flags |= IORESOURCE_IO_16BIT_ADDR; - return flags; + if (window) + res->flags |= IORESOURCE_WINDOW; } static void acpi_dev_get_ioresource(struct resource *res, u64 start, u64 len, u8 io_decode) { - u64 end = start + len - 1; - res->start = start; - res->end = end; - res->flags = acpi_dev_ioresource_flags(start, end, io_decode, false); + res->end = start + len - 1; + acpi_dev_ioresource_flags(res, len, io_decode, false); } /** @@ -161,16 +160,12 @@ bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res) switch (ares->type) { case ACPI_RESOURCE_TYPE_IO: io = &ares->data.io; - if (!io->minimum && !io->address_length) - return false; acpi_dev_get_ioresource(res, io->minimum, io->address_length, io->io_decode); break; case ACPI_RESOURCE_TYPE_FIXED_IO: fixed_io = &ares->data.fixed_io; - if (!fixed_io->address && !fixed_io->address_length) - return false; acpi_dev_get_ioresource(res, fixed_io->address, fixed_io->address_length, ACPI_DECODE_10); @@ -178,7 +173,8 @@ bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res) default: return false; } - return true; + + return !(res->flags & IORESOURCE_DISABLED); } EXPORT_SYMBOL_GPL(acpi_dev_resource_io); @@ -216,9 +212,8 @@ bool acpi_dev_resource_address_space(struct acpi_resource *ares, case ACPI_IO_RANGE: io_decode = addr.address.granularity == 0xfff ? ACPI_DECODE_10 : ACPI_DECODE_16; - res->flags = acpi_dev_ioresource_flags(addr.address.minimum, - addr.address.maximum, - io_decode, window); + acpi_dev_ioresource_flags(res, addr.address.address_length, + io_decode, window); break; case ACPI_BUS_NUMBER_RANGE: res->flags = IORESOURCE_BUS; @@ -266,9 +261,8 @@ bool acpi_dev_resource_ext_address_space(struct acpi_resource *ares, case ACPI_IO_RANGE: io_decode = ext_addr->address.granularity == 0xfff ? ACPI_DECODE_10 : ACPI_DECODE_16; - res->flags = acpi_dev_ioresource_flags(ext_addr->address.minimum, - ext_addr->address.maximum, - io_decode, window); + acpi_dev_ioresource_flags(res, ext_addr->address.address_length, + io_decode, window); break; case ACPI_BUS_NUMBER_RANGE: res->flags = IORESOURCE_BUS; -- cgit v1.2.1 From e814f6deee6188265b5af9f1190e5734f116860e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 2 Feb 2015 10:42:50 +0800 Subject: ACPI: Let the parser return false for disabled resources If the parser disables a resource during parsing, let it return false, so the calling code does not need to implement further checks. Signed-off-by: Thomas Gleixner Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/resource.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 16d291c60277..cdb1a3c4a0b9 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -219,10 +219,10 @@ bool acpi_dev_resource_address_space(struct acpi_resource *ares, res->flags = IORESOURCE_BUS; break; default: - res->flags = 0; + return false; } - return true; + return !(res->flags & IORESOURCE_DISABLED); } EXPORT_SYMBOL_GPL(acpi_dev_resource_address_space); @@ -268,10 +268,10 @@ bool acpi_dev_resource_ext_address_space(struct acpi_resource *ares, res->flags = IORESOURCE_BUS; break; default: - res->flags = 0; + return false; } - return true; + return !(res->flags & IORESOURCE_DISABLED); } EXPORT_SYMBOL_GPL(acpi_dev_resource_ext_address_space); -- cgit v1.2.1 From eb76d55e66a9bed2359cc5a0f08168b287c4dea8 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 2 Feb 2015 10:42:51 +0800 Subject: ACPI: Unify the parsing of address_space and ext_address_space With the unions in place which let us identify the substructs we can use a single parser for address_space and ext_address_space. Signed-off-by: Thomas Gleixner Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/resource.c | 90 +++++++++++++++++++------------------------------ 1 file changed, 34 insertions(+), 56 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index cdb1a3c4a0b9..99903d196024 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -178,6 +178,35 @@ bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res) } EXPORT_SYMBOL_GPL(acpi_dev_resource_io); +static bool acpi_decode_space(struct resource *res, + struct acpi_resource_address *addr, + struct acpi_address64_attribute *attr) +{ + u8 iodec = attr->granularity == 0xfff ? ACPI_DECODE_10 : ACPI_DECODE_16; + bool window = addr->producer_consumer == ACPI_PRODUCER; + bool wp = addr->info.mem.write_protect; + u64 len = attr->address_length; + + res->start = attr->minimum; + res->end = attr->maximum; + + switch (addr->resource_type) { + case ACPI_MEMORY_RANGE: + acpi_dev_memresource_flags(res, len, wp, window); + break; + case ACPI_IO_RANGE: + acpi_dev_ioresource_flags(res, len, iodec, window); + break; + case ACPI_BUS_NUMBER_RANGE: + res->flags = IORESOURCE_BUS; + break; + default: + return false; + } + + return !(res->flags & IORESOURCE_DISABLED); +} + /** * acpi_dev_resource_address_space - Extract ACPI address space information. * @ares: Input ACPI resource object. @@ -190,39 +219,13 @@ EXPORT_SYMBOL_GPL(acpi_dev_resource_io); bool acpi_dev_resource_address_space(struct acpi_resource *ares, struct resource *res) { - acpi_status status; struct acpi_resource_address64 addr; - bool window; - u8 io_decode; - - status = acpi_resource_to_address64(ares, &addr); - if (ACPI_FAILURE(status)) - return false; - res->start = addr.address.minimum; - res->end = addr.address.maximum; - window = addr.producer_consumer == ACPI_PRODUCER; - - switch(addr.resource_type) { - case ACPI_MEMORY_RANGE: - acpi_dev_memresource_flags(res, addr.address.address_length, - addr.info.mem.write_protect, - window); - break; - case ACPI_IO_RANGE: - io_decode = addr.address.granularity == 0xfff ? - ACPI_DECODE_10 : ACPI_DECODE_16; - acpi_dev_ioresource_flags(res, addr.address.address_length, - io_decode, window); - break; - case ACPI_BUS_NUMBER_RANGE: - res->flags = IORESOURCE_BUS; - break; - default: + if (ACPI_FAILURE(acpi_resource_to_address64(ares, &addr))) return false; - } - return !(res->flags & IORESOURCE_DISABLED); + return acpi_decode_space(res, (struct acpi_resource_address *)&addr, + &addr.address); } EXPORT_SYMBOL_GPL(acpi_dev_resource_address_space); @@ -239,39 +242,14 @@ bool acpi_dev_resource_ext_address_space(struct acpi_resource *ares, struct resource *res) { struct acpi_resource_extended_address64 *ext_addr; - bool window; - u8 io_decode; if (ares->type != ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64) return false; ext_addr = &ares->data.ext_address64; - res->start = ext_addr->address.minimum; - res->end = ext_addr->address.maximum; - window = ext_addr->producer_consumer == ACPI_PRODUCER; - - switch(ext_addr->resource_type) { - case ACPI_MEMORY_RANGE: - acpi_dev_memresource_flags(res, - ext_addr->address.address_length, - ext_addr->info.mem.write_protect, - window); - break; - case ACPI_IO_RANGE: - io_decode = ext_addr->address.granularity == 0xfff ? - ACPI_DECODE_10 : ACPI_DECODE_16; - acpi_dev_ioresource_flags(res, ext_addr->address.address_length, - io_decode, window); - break; - case ACPI_BUS_NUMBER_RANGE: - res->flags = IORESOURCE_BUS; - break; - default: - return false; - } - - return !(res->flags & IORESOURCE_DISABLED); + return acpi_decode_space(res, (struct acpi_resource_address *)ext_addr, + &ext_addr->address); } EXPORT_SYMBOL_GPL(acpi_dev_resource_ext_address_space); -- cgit v1.2.1 From 72e26b0d487fc494f40aa61e10a0757791e62e36 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 2 Feb 2015 10:42:52 +0800 Subject: ACPI: Move the window flag logic to the combined parser Normal memory and io resources have window always set to false. Move the flag logic to the unified address space parser. Signed-off-by: Thomas Gleixner Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/resource.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 99903d196024..15d17937c431 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -53,7 +53,7 @@ static bool acpi_dev_resource_len_valid(u64 start, u64 end, u64 len, bool io) } static void acpi_dev_memresource_flags(struct resource *res, u64 len, - u8 write_protect, bool window) + u8 write_protect) { res->flags = IORESOURCE_MEM; @@ -62,9 +62,6 @@ static void acpi_dev_memresource_flags(struct resource *res, u64 len, if (write_protect == ACPI_READ_WRITE_MEMORY) res->flags |= IORESOURCE_MEM_WRITEABLE; - - if (window) - res->flags |= IORESOURCE_WINDOW; } static void acpi_dev_get_memresource(struct resource *res, u64 start, u64 len, @@ -72,7 +69,7 @@ static void acpi_dev_get_memresource(struct resource *res, u64 start, u64 len, { res->start = start; res->end = start + len - 1; - acpi_dev_memresource_flags(res, len, write_protect, false); + acpi_dev_memresource_flags(res, len, write_protect); } /** @@ -118,7 +115,7 @@ bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res) EXPORT_SYMBOL_GPL(acpi_dev_resource_memory); static void acpi_dev_ioresource_flags(struct resource *res, u64 len, - u8 io_decode, bool window) + u8 io_decode) { res->flags = IORESOURCE_IO; @@ -130,9 +127,6 @@ static void acpi_dev_ioresource_flags(struct resource *res, u64 len, if (io_decode == ACPI_DECODE_16) res->flags |= IORESOURCE_IO_16BIT_ADDR; - - if (window) - res->flags |= IORESOURCE_WINDOW; } static void acpi_dev_get_ioresource(struct resource *res, u64 start, u64 len, @@ -140,7 +134,7 @@ static void acpi_dev_get_ioresource(struct resource *res, u64 start, u64 len, { res->start = start; res->end = start + len - 1; - acpi_dev_ioresource_flags(res, len, io_decode, false); + acpi_dev_ioresource_flags(res, len, io_decode); } /** @@ -183,7 +177,6 @@ static bool acpi_decode_space(struct resource *res, struct acpi_address64_attribute *attr) { u8 iodec = attr->granularity == 0xfff ? ACPI_DECODE_10 : ACPI_DECODE_16; - bool window = addr->producer_consumer == ACPI_PRODUCER; bool wp = addr->info.mem.write_protect; u64 len = attr->address_length; @@ -192,10 +185,10 @@ static bool acpi_decode_space(struct resource *res, switch (addr->resource_type) { case ACPI_MEMORY_RANGE: - acpi_dev_memresource_flags(res, len, wp, window); + acpi_dev_memresource_flags(res, len, wp); break; case ACPI_IO_RANGE: - acpi_dev_ioresource_flags(res, len, iodec, window); + acpi_dev_ioresource_flags(res, len, iodec); break; case ACPI_BUS_NUMBER_RANGE: res->flags = IORESOURCE_BUS; @@ -204,6 +197,9 @@ static bool acpi_decode_space(struct resource *res, return false; } + if (addr->producer_consumer == ACPI_PRODUCER) + res->flags |= IORESOURCE_WINDOW; + return !(res->flags & IORESOURCE_DISABLED); } -- cgit v1.2.1 From fcb29bbcd5404494eb46ad24908a4843b5a32060 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 2 Feb 2015 10:42:53 +0800 Subject: ACPI: Add prefetch decoding to the address space parser Add support of PREFETCH attributre to ACPI address space and extended address space parser. Signed-off-by: Thomas Gleixner Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/resource.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/acpi') diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 15d17937c431..7ce00a63f695 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -200,6 +200,9 @@ static bool acpi_decode_space(struct resource *res, if (addr->producer_consumer == ACPI_PRODUCER) res->flags |= IORESOURCE_WINDOW; + if (addr->info.mem.caching == ACPI_PREFETCHABLE_MEMORY) + res->flags |= IORESOURCE_PREFETCH; + return !(res->flags & IORESOURCE_DISABLED); } -- cgit v1.2.1 From 8515f9368161730655b64ddaf8b11a3d20049610 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 2 Feb 2015 10:42:54 +0800 Subject: ACPI: Fix a bug in parsing ACPI Memory24 resource According to ACPI spec 5, section 6.4.3.1 "24-Bit Memory Range Descriptor", minimum, maximum and address_length field in struct acpi_resource_memory24 is in granularity of 256-bytes. So shift 8-bit left to get correct address. Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/resource.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 7ce00a63f695..5544c6d26f32 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -90,8 +90,8 @@ bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res) switch (ares->type) { case ACPI_RESOURCE_TYPE_MEMORY24: memory24 = &ares->data.memory24; - acpi_dev_get_memresource(res, memory24->minimum, - memory24->address_length, + acpi_dev_get_memresource(res, memory24->minimum << 8, + memory24->address_length << 8, memory24->write_protect); break; case ACPI_RESOURCE_TYPE_MEMORY32: -- cgit v1.2.1 From 581c19f3a72ae9ff7f24f2a6c2e67f269ed4392a Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 2 Feb 2015 10:42:55 +0800 Subject: ACPI: Normalize return value of resource parser functions Normalize return value of resource parse functions as: 1) return "true" if resource is assigned. 2) return "false" and IORESOURCE_DISABLED setting in res->flags if resource is unassigned. 3) return "false" and zeroing res->flags if it's not an valid or expected resource. Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/resource.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'drivers/acpi') diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 5544c6d26f32..32561290a4a0 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -80,6 +80,11 @@ static void acpi_dev_get_memresource(struct resource *res, u64 start, u64 len, * Check if the given ACPI resource object represents a memory resource and * if that's the case, use the information in it to populate the generic * resource object pointed to by @res. + * + * Return: + * 1) false with res->flags setting to zero: not the expected resource type + * 2) false with IORESOURCE_DISABLED in res->flags: valid unassigned resource + * 3) true: valid assigned resource */ bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res) { @@ -107,6 +112,7 @@ bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res) fixed_memory32->write_protect); break; default: + res->flags = 0; return false; } @@ -145,6 +151,11 @@ static void acpi_dev_get_ioresource(struct resource *res, u64 start, u64 len, * Check if the given ACPI resource object represents an I/O resource and * if that's the case, use the information in it to populate the generic * resource object pointed to by @res. + * + * Return: + * 1) false with res->flags setting to zero: not the expected resource type + * 2) false with IORESOURCE_DISABLED in res->flags: valid unassigned resource + * 3) true: valid assigned resource */ bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res) { @@ -165,6 +176,7 @@ bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res) ACPI_DECODE_10); break; default: + res->flags = 0; return false; } @@ -214,12 +226,18 @@ static bool acpi_decode_space(struct resource *res, * Check if the given ACPI resource object represents an address space resource * and if that's the case, use the information in it to populate the generic * resource object pointed to by @res. + * + * Return: + * 1) false with res->flags setting to zero: not the expected resource type + * 2) false with IORESOURCE_DISABLED in res->flags: valid unassigned resource + * 3) true: valid assigned resource */ bool acpi_dev_resource_address_space(struct acpi_resource *ares, struct resource *res) { struct acpi_resource_address64 addr; + res->flags = 0; if (ACPI_FAILURE(acpi_resource_to_address64(ares, &addr))) return false; @@ -236,12 +254,18 @@ EXPORT_SYMBOL_GPL(acpi_dev_resource_address_space); * Check if the given ACPI resource object represents an extended address space * resource and if that's the case, use the information in it to populate the * generic resource object pointed to by @res. + * + * Return: + * 1) false with res->flags setting to zero: not the expected resource type + * 2) false with IORESOURCE_DISABLED in res->flags: valid unassigned resource + * 3) true: valid assigned resource */ bool acpi_dev_resource_ext_address_space(struct acpi_resource *ares, struct resource *res) { struct acpi_resource_extended_address64 *ext_addr; + res->flags = 0; if (ares->type != ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64) return false; @@ -339,6 +363,11 @@ static void acpi_dev_get_irqresource(struct resource *res, u32 gsi, * represented by the resource and populate the generic resource object pointed * to by @res accordingly. If the registration of the GSI is not successful, * IORESOURCE_DISABLED will be set it that object's flags. + * + * Return: + * 1) false with res->flags setting to zero: not the expected resource type + * 2) false with IORESOURCE_DISABLED in res->flags: valid unassigned resource + * 3) true: valid assigned resource */ bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index, struct resource *res) @@ -372,6 +401,7 @@ bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index, ext_irq->sharable, false); break; default: + res->flags = 0; return false; } -- cgit v1.2.1 From c78b688561e684098a11012ca21a6d578f9dfb67 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 2 Feb 2015 10:42:56 +0800 Subject: ACPI: Set flag IORESOURCE_UNSET for unassigned resources Also set flag IORESOURCE_UNSET for unassigned resource in addition to IORESOURCE_DISABLED to mark resource as unassigned. Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/resource.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 32561290a4a0..5bf73a9f26d9 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -58,7 +58,7 @@ static void acpi_dev_memresource_flags(struct resource *res, u64 len, res->flags = IORESOURCE_MEM; if (!acpi_dev_resource_len_valid(res->start, res->end, len, false)) - res->flags |= IORESOURCE_DISABLED; + res->flags |= IORESOURCE_DISABLED | IORESOURCE_UNSET; if (write_protect == ACPI_READ_WRITE_MEMORY) res->flags |= IORESOURCE_MEM_WRITEABLE; @@ -126,10 +126,10 @@ static void acpi_dev_ioresource_flags(struct resource *res, u64 len, res->flags = IORESOURCE_IO; if (!acpi_dev_resource_len_valid(res->start, res->end, len, true)) - res->flags |= IORESOURCE_DISABLED; + res->flags |= IORESOURCE_DISABLED | IORESOURCE_UNSET; if (res->end >= 0x10003) - res->flags |= IORESOURCE_DISABLED; + res->flags |= IORESOURCE_DISABLED | IORESOURCE_UNSET; if (io_decode == ACPI_DECODE_16) res->flags |= IORESOURCE_IO_16BIT_ADDR; @@ -304,7 +304,7 @@ static void acpi_dev_irqresource_disabled(struct resource *res, u32 gsi) { res->start = gsi; res->end = gsi; - res->flags = IORESOURCE_IRQ | IORESOURCE_DISABLED; + res->flags = IORESOURCE_IRQ | IORESOURCE_DISABLED | IORESOURCE_UNSET; } static void acpi_dev_get_irqresource(struct resource *res, u32 gsi, -- cgit v1.2.1 From a274019fc332d7b4dcb85735978c2018522be312 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 2 Feb 2015 10:42:57 +0800 Subject: ACPI: Enforce stricter checks for address space descriptors Enforce stricter checks for address space descriptors according to ACPI spec. Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/resource.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/acpi') diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 5bf73a9f26d9..57891a621b96 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -192,6 +192,15 @@ static bool acpi_decode_space(struct resource *res, bool wp = addr->info.mem.write_protect; u64 len = attr->address_length; + /* + * Filter out invalid descriptor according to ACPI Spec 5.0, section + * 6.4.3.5 Address Space Resource Descriptors. + */ + if ((addr->min_address_fixed != addr->max_address_fixed && len) || + (addr->min_address_fixed && addr->max_address_fixed && !len)) + pr_debug("ACPI: Invalid address space min_addr_fix %d, max_addr_fix %d, len %llx\n", + addr->min_address_fixed, addr->max_address_fixed, len); + res->start = attr->minimum; res->end = attr->maximum; -- cgit v1.2.1 From a49170b552423a3e85fc4f0d778c707402ee4863 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 2 Feb 2015 10:42:58 +0800 Subject: ACPI: Return translation offset when parsing ACPI address space resources Change function acpi_dev_resource_address_space() and acpi_dev_resource_ext_address_space() to return address space translation offset. It's based on a patch from Yinghai Lu . Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/resource.c | 58 +++++++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 26 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 57891a621b96..c902c8eece81 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -184,13 +184,14 @@ bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res) } EXPORT_SYMBOL_GPL(acpi_dev_resource_io); -static bool acpi_decode_space(struct resource *res, +static bool acpi_decode_space(struct resource_win *win, struct acpi_resource_address *addr, struct acpi_address64_attribute *attr) { u8 iodec = attr->granularity == 0xfff ? ACPI_DECODE_10 : ACPI_DECODE_16; bool wp = addr->info.mem.write_protect; u64 len = attr->address_length; + struct resource *res = &win->res; /* * Filter out invalid descriptor according to ACPI Spec 5.0, section @@ -218,6 +219,8 @@ static bool acpi_decode_space(struct resource *res, return false; } + win->offset = attr->translation_offset; + if (addr->producer_consumer == ACPI_PRODUCER) res->flags |= IORESOURCE_WINDOW; @@ -230,27 +233,28 @@ static bool acpi_decode_space(struct resource *res, /** * acpi_dev_resource_address_space - Extract ACPI address space information. * @ares: Input ACPI resource object. - * @res: Output generic resource object. + * @win: Output generic resource object. * * Check if the given ACPI resource object represents an address space resource * and if that's the case, use the information in it to populate the generic - * resource object pointed to by @res. + * resource object pointed to by @win. * * Return: - * 1) false with res->flags setting to zero: not the expected resource type - * 2) false with IORESOURCE_DISABLED in res->flags: valid unassigned resource + * 1) false with win->res.flags setting to zero: not the expected resource type + * 2) false with IORESOURCE_DISABLED in win->res.flags: valid unassigned + * resource * 3) true: valid assigned resource */ bool acpi_dev_resource_address_space(struct acpi_resource *ares, - struct resource *res) + struct resource_win *win) { struct acpi_resource_address64 addr; - res->flags = 0; + win->res.flags = 0; if (ACPI_FAILURE(acpi_resource_to_address64(ares, &addr))) return false; - return acpi_decode_space(res, (struct acpi_resource_address *)&addr, + return acpi_decode_space(win, (struct acpi_resource_address *)&addr, &addr.address); } EXPORT_SYMBOL_GPL(acpi_dev_resource_address_space); @@ -258,29 +262,30 @@ EXPORT_SYMBOL_GPL(acpi_dev_resource_address_space); /** * acpi_dev_resource_ext_address_space - Extract ACPI address space information. * @ares: Input ACPI resource object. - * @res: Output generic resource object. + * @win: Output generic resource object. * * Check if the given ACPI resource object represents an extended address space * resource and if that's the case, use the information in it to populate the - * generic resource object pointed to by @res. + * generic resource object pointed to by @win. * * Return: - * 1) false with res->flags setting to zero: not the expected resource type - * 2) false with IORESOURCE_DISABLED in res->flags: valid unassigned resource + * 1) false with win->res.flags setting to zero: not the expected resource type + * 2) false with IORESOURCE_DISABLED in win->res.flags: valid unassigned + * resource * 3) true: valid assigned resource */ bool acpi_dev_resource_ext_address_space(struct acpi_resource *ares, - struct resource *res) + struct resource_win *win) { struct acpi_resource_extended_address64 *ext_addr; - res->flags = 0; + win->res.flags = 0; if (ares->type != ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64) return false; ext_addr = &ares->data.ext_address64; - return acpi_decode_space(res, (struct acpi_resource_address *)ext_addr, + return acpi_decode_space(win, (struct acpi_resource_address *)ext_addr, &ext_addr->address); } EXPORT_SYMBOL_GPL(acpi_dev_resource_ext_address_space); @@ -441,7 +446,7 @@ struct res_proc_context { int error; }; -static acpi_status acpi_dev_new_resource_entry(struct resource *r, +static acpi_status acpi_dev_new_resource_entry(struct resource_win *win, struct res_proc_context *c) { struct resource_list_entry *rentry; @@ -451,7 +456,7 @@ static acpi_status acpi_dev_new_resource_entry(struct resource *r, c->error = -ENOMEM; return AE_NO_MEMORY; } - rentry->res = *r; + rentry->res = win->res; list_add_tail(&rentry->node, c->list); c->count++; return AE_OK; @@ -461,7 +466,8 @@ static acpi_status acpi_dev_process_resource(struct acpi_resource *ares, void *context) { struct res_proc_context *c = context; - struct resource r; + struct resource_win win; + struct resource *res = &win.res; int i; if (c->preproc) { @@ -476,18 +482,18 @@ static acpi_status acpi_dev_process_resource(struct acpi_resource *ares, } } - memset(&r, 0, sizeof(r)); + memset(&win, 0, sizeof(win)); - if (acpi_dev_resource_memory(ares, &r) - || acpi_dev_resource_io(ares, &r) - || acpi_dev_resource_address_space(ares, &r) - || acpi_dev_resource_ext_address_space(ares, &r)) - return acpi_dev_new_resource_entry(&r, c); + if (acpi_dev_resource_memory(ares, res) + || acpi_dev_resource_io(ares, res) + || acpi_dev_resource_address_space(ares, &win) + || acpi_dev_resource_ext_address_space(ares, &win)) + return acpi_dev_new_resource_entry(&win, c); - for (i = 0; acpi_dev_resource_interrupt(ares, i, &r); i++) { + for (i = 0; acpi_dev_resource_interrupt(ares, i, res); i++) { acpi_status status; - status = acpi_dev_new_resource_entry(&r, c); + status = acpi_dev_new_resource_entry(&win, c); if (ACPI_FAILURE(status)) return status; } -- cgit v1.2.1 From 2ea3d266bab3b497238113b20136f7c3f69ad9c0 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 2 Feb 2015 10:42:59 +0800 Subject: ACPI: Translate resource into master side address for bridge window resources Add translation_offset into the result address for bridge window resources to form the master side address. Currently acpi_dev_resource_{ext_}address_space() are only used for devices instead of bridges, so it won't break current users. Later it will be used to support PCI host bridge drivers. Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/resource.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers/acpi') diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index c902c8eece81..4dc8cfb2e94e 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -205,6 +205,21 @@ static bool acpi_decode_space(struct resource_win *win, res->start = attr->minimum; res->end = attr->maximum; + /* + * For bridges that translate addresses across the bridge, + * translation_offset is the offset that must be added to the + * address on the secondary side to obtain the address on the + * primary side. Non-bridge devices must list 0 for all Address + * Translation offset bits. + */ + if (addr->producer_consumer == ACPI_PRODUCER) { + res->start += attr->translation_offset; + res->end += attr->translation_offset; + } else if (attr->translation_offset) { + pr_debug("ACPI: translation_offset(%lld) is invalid for non-bridge device.\n", + attr->translation_offset); + } + switch (addr->resource_type) { case ACPI_MEMORY_RANGE: acpi_dev_memresource_flags(res, len, wp); -- cgit v1.2.1 From 93286f4798590e711aa395503401f8632fb74f9a Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 2 Feb 2015 10:43:00 +0800 Subject: ACPI: Add field offset to struct resource_list_entry Add field offset to struct resource_list_entry to host address space translation offset so it could be used to represent bridge resources. Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/resource.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/acpi') diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 4dc8cfb2e94e..1c3abae6f2fa 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -472,6 +472,7 @@ static acpi_status acpi_dev_new_resource_entry(struct resource_win *win, return AE_NO_MEMORY; } rentry->res = win->res; + rentry->offset = win->offset; list_add_tail(&rentry->node, c->list); c->count++; return AE_OK; -- cgit v1.2.1 From 62d1141ff34e35de496ba06491c8e854b23b3f3e Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 2 Feb 2015 10:43:01 +0800 Subject: ACPI: Introduce helper function acpi_dev_filter_resource_type() Introduce helper function acpi_dev_filter_resource_type(), which may be used by acpi_dev_get_resources() to filer out resource based on resource type. Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/resource.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) (limited to 'drivers/acpi') diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 1c3abae6f2fa..3ea0d17eb951 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -569,3 +569,58 @@ int acpi_dev_get_resources(struct acpi_device *adev, struct list_head *list, return c.count; } EXPORT_SYMBOL_GPL(acpi_dev_get_resources); + +/** + * acpi_dev_filter_resource_type - Filter ACPI resource according to resource + * types + * @ares: Input ACPI resource object. + * @types: Valid resource types of IORESOURCE_XXX + * + * This is a hepler function to support acpi_dev_get_resources(), which filters + * ACPI resource objects according to resource types. + */ +int acpi_dev_filter_resource_type(struct acpi_resource *ares, + unsigned long types) +{ + unsigned long type = 0; + + switch (ares->type) { + case ACPI_RESOURCE_TYPE_MEMORY24: + case ACPI_RESOURCE_TYPE_MEMORY32: + case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: + type = IORESOURCE_MEM; + break; + case ACPI_RESOURCE_TYPE_IO: + case ACPI_RESOURCE_TYPE_FIXED_IO: + type = IORESOURCE_IO; + break; + case ACPI_RESOURCE_TYPE_IRQ: + case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: + type = IORESOURCE_IRQ; + break; + case ACPI_RESOURCE_TYPE_DMA: + case ACPI_RESOURCE_TYPE_FIXED_DMA: + type = IORESOURCE_DMA; + break; + case ACPI_RESOURCE_TYPE_GENERIC_REGISTER: + type = IORESOURCE_REG; + break; + case ACPI_RESOURCE_TYPE_ADDRESS16: + case ACPI_RESOURCE_TYPE_ADDRESS32: + case ACPI_RESOURCE_TYPE_ADDRESS64: + case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: + if (ares->data.address.resource_type == ACPI_MEMORY_RANGE) + type = IORESOURCE_MEM; + else if (ares->data.address.resource_type == ACPI_IO_RANGE) + type = IORESOURCE_IO; + else if (ares->data.address.resource_type == + ACPI_BUS_NUMBER_RANGE) + type = IORESOURCE_BUS; + break; + default: + break; + } + + return (type & types) ? 0 : 1; +} +EXPORT_SYMBOL_GPL(acpi_dev_filter_resource_type); -- cgit v1.2.1 From 90e97820619dc912b52cc9d103272819d8b51259 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 5 Feb 2015 13:44:43 +0800 Subject: resources: Move struct resource_list_entry from ACPI into resource core Currently ACPI, PCI and pnp all implement the same resource list management with different data structure. We need to transfer from one data structure into another when passing resources from one subsystem into another subsystem. So move struct resource_list_entry from ACPI into resource core and rename it as resource_entry, then it could be reused by different subystems and avoid the data structure conversion. Introduce dedicated header file resource_ext.h instead of embedding it into ioport.h to avoid header file inclusion order issues. Signed-off-by: Jiang Liu Acked-by: Vinod Koul Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_lpss.c | 8 ++++---- drivers/acpi/acpi_platform.c | 4 ++-- drivers/acpi/resource.c | 17 ++++++----------- 3 files changed, 12 insertions(+), 17 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index 4f3febf8a589..dfd1b8095dad 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -313,7 +313,7 @@ static int acpi_lpss_create_device(struct acpi_device *adev, { struct lpss_device_desc *dev_desc; struct lpss_private_data *pdata; - struct resource_list_entry *rentry; + struct resource_entry *rentry; struct list_head resource_list; struct platform_device *pdev; int ret; @@ -333,12 +333,12 @@ static int acpi_lpss_create_device(struct acpi_device *adev, goto err_out; list_for_each_entry(rentry, &resource_list, node) - if (resource_type(&rentry->res) == IORESOURCE_MEM) { + if (resource_type(rentry->res) == IORESOURCE_MEM) { if (dev_desc->prv_size_override) pdata->mmio_size = dev_desc->prv_size_override; else - pdata->mmio_size = resource_size(&rentry->res); - pdata->mmio_base = ioremap(rentry->res.start, + pdata->mmio_size = resource_size(rentry->res); + pdata->mmio_base = ioremap(rentry->res->start, pdata->mmio_size); break; } diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c index 6ba8beb6b9d2..1284138e42ab 100644 --- a/drivers/acpi/acpi_platform.c +++ b/drivers/acpi/acpi_platform.c @@ -45,7 +45,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev) struct platform_device *pdev = NULL; struct acpi_device *acpi_parent; struct platform_device_info pdevinfo; - struct resource_list_entry *rentry; + struct resource_entry *rentry; struct list_head resource_list; struct resource *resources = NULL; int count; @@ -71,7 +71,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev) } count = 0; list_for_each_entry(rentry, &resource_list, node) - resources[count++] = rentry->res; + resources[count++] = *rentry->res; acpi_dev_free_resource_list(&resource_list); } diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 3ea0d17eb951..4752b9939987 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -444,12 +444,7 @@ EXPORT_SYMBOL_GPL(acpi_dev_resource_interrupt); */ void acpi_dev_free_resource_list(struct list_head *list) { - struct resource_list_entry *rentry, *re; - - list_for_each_entry_safe(rentry, re, list, node) { - list_del(&rentry->node); - kfree(rentry); - } + resource_list_free(list); } EXPORT_SYMBOL_GPL(acpi_dev_free_resource_list); @@ -464,16 +459,16 @@ struct res_proc_context { static acpi_status acpi_dev_new_resource_entry(struct resource_win *win, struct res_proc_context *c) { - struct resource_list_entry *rentry; + struct resource_entry *rentry; - rentry = kmalloc(sizeof(*rentry), GFP_KERNEL); + rentry = resource_list_create_entry(NULL, 0); if (!rentry) { c->error = -ENOMEM; return AE_NO_MEMORY; } - rentry->res = win->res; + *rentry->res = win->res; rentry->offset = win->offset; - list_add_tail(&rentry->node, c->list); + resource_list_add_tail(rentry, c->list); c->count++; return AE_OK; } @@ -534,7 +529,7 @@ static acpi_status acpi_dev_process_resource(struct acpi_resource *ares, * returned as the final error code. * * The resultant struct resource objects are put on the list pointed to by - * @list, that must be empty initially, as members of struct resource_list_entry + * @list, that must be empty initially, as members of struct resource_entry * objects. Callers of this routine should use %acpi_dev_free_resource_list() to * free that list. * -- cgit v1.2.1 From b4b55cda587442477a3a9f0669e26bba4b7800c0 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 5 Feb 2015 13:44:47 +0800 Subject: x86/PCI: Refine the way to release PCI IRQ resources Some PCI device drivers assume that pci_dev->irq won't change after calling pci_disable_device() and pci_enable_device() during suspend and resume. Commit c03b3b0738a5 ("x86, irq, mpparse: Release IOAPIC pin when PCI device is disabled") frees PCI IRQ resources when pci_disable_device() is called and reallocate IRQ resources when pci_enable_device() is called again. This breaks above assumption. So commit 3eec595235c1 ("x86, irq, PCI: Keep IRQ assignment for PCI devices during suspend/hibernation") and 9eabc99a635a ("x86, irq, PCI: Keep IRQ assignment for runtime power management") fix the issue by avoiding freeing/reallocating IRQ resources during PCI device suspend/resume. They achieve this by checking dev.power.is_prepared and dev.power.runtime_status. PM maintainer, Rafael, then pointed out that it's really an ugly fix which leaking PM internal state information to IRQ subsystem. Recently David Vrabel also reports an regression in pciback driver caused by commit cffe0a2b5a34 ("x86, irq: Keep balance of IOAPIC pin reference count"). Please refer to: http://lkml.org/lkml/2015/1/14/546 So this patch refine the way to release PCI IRQ resources. Instead of releasing PCI IRQ resources in pci_disable_device()/ pcibios_disable_device(), we now release it at driver unbinding notification BUS_NOTIFY_UNBOUND_DRIVER. In other word, we only release PCI IRQ resources when there's no driver bound to the PCI device, and it keeps the assumption that pci_dev->irq won't through multiple invocation of pci_enable_device()/pci_disable_device(). Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/pci_irq.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index b1def411c0b8..e7f718d6918a 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -485,14 +485,6 @@ void acpi_pci_irq_disable(struct pci_dev *dev) if (!pin || !dev->irq_managed || dev->irq <= 0) return; - /* Keep IOAPIC pin configuration when suspending */ - if (dev->dev.power.is_prepared) - return; -#ifdef CONFIG_PM - if (dev->dev.power.runtime_status == RPM_SUSPENDING) - return; -#endif - entry = acpi_pci_irq_lookup(dev, pin); if (!entry) return; @@ -513,5 +505,6 @@ void acpi_pci_irq_disable(struct pci_dev *dev) if (gsi >= 0) { acpi_unregister_gsi(gsi); dev->irq_managed = 0; + dev->irq = 0; } } -- cgit v1.2.1 From ecf5636dcd59cd5508641f995cc4c2bafedbb995 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Thu, 5 Feb 2015 13:44:48 +0800 Subject: ACPI: Add interfaces to parse IOAPIC ID for IOAPIC hotplug We need to parse APIC ID for IOAPIC registration for IOAPIC hotplug. ACPI _MAT method and MADT table are used to figure out IOAPIC ID, just like parsing CPU APIC ID for CPU hotplug. [ tglx: Fixed docbook comment ] Signed-off-by: Yinghai Lu Signed-off-by: Jiang Liu Cc: Konrad Rzeszutek Wilk Cc: Tony Luck Cc: Joerg Roedel Cc: Greg Kroah-Hartman Cc: Benjamin Herrenschmidt Cc: Rafael J. Wysocki Cc: Bjorn Helgaas Cc: Randy Dunlap Cc: Borislav Petkov Cc: Len Brown Link: http://lkml.kernel.org/r/1414387308-27148-8-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner Signed-off-by: Rafael J. Wysocki --- drivers/acpi/processor_core.c | 123 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 114 insertions(+), 9 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 02e48394276c..7962651cdbd4 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -4,6 +4,10 @@ * * Alex Chiang * - Unified x86/ia64 implementations + * + * I/O APIC hotplug support + * Yinghai Lu + * Jiang Liu */ #include #include @@ -12,6 +16,21 @@ #define _COMPONENT ACPI_PROCESSOR_COMPONENT ACPI_MODULE_NAME("processor_core"); +static struct acpi_table_madt *get_madt_table(void) +{ + static struct acpi_table_madt *madt; + static int read_madt; + + if (!read_madt) { + if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0, + (struct acpi_table_header **)&madt))) + madt = NULL; + read_madt++; + } + + return madt; +} + static int map_lapic_id(struct acpi_subtable_header *entry, u32 acpi_id, int *apic_id) { @@ -67,17 +86,10 @@ static int map_lsapic_id(struct acpi_subtable_header *entry, static int map_madt_entry(int type, u32 acpi_id) { unsigned long madt_end, entry; - static struct acpi_table_madt *madt; - static int read_madt; int phys_id = -1; /* CPU hardware ID */ + struct acpi_table_madt *madt; - if (!read_madt) { - if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0, - (struct acpi_table_header **)&madt))) - madt = NULL; - read_madt++; - } - + madt = get_madt_table(); if (!madt) return phys_id; @@ -203,3 +215,96 @@ int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id) return acpi_map_cpuid(phys_id, acpi_id); } EXPORT_SYMBOL_GPL(acpi_get_cpuid); + +#ifdef CONFIG_ACPI_HOTPLUG_IOAPIC +static int get_ioapic_id(struct acpi_subtable_header *entry, u32 gsi_base, + u64 *phys_addr, int *ioapic_id) +{ + struct acpi_madt_io_apic *ioapic = (struct acpi_madt_io_apic *)entry; + + if (ioapic->global_irq_base != gsi_base) + return 0; + + *phys_addr = ioapic->address; + *ioapic_id = ioapic->id; + return 1; +} + +static int parse_madt_ioapic_entry(u32 gsi_base, u64 *phys_addr) +{ + struct acpi_subtable_header *hdr; + unsigned long madt_end, entry; + struct acpi_table_madt *madt; + int apic_id = -1; + + madt = get_madt_table(); + if (!madt) + return apic_id; + + entry = (unsigned long)madt; + madt_end = entry + madt->header.length; + + /* Parse all entries looking for a match. */ + entry += sizeof(struct acpi_table_madt); + while (entry + sizeof(struct acpi_subtable_header) < madt_end) { + hdr = (struct acpi_subtable_header *)entry; + if (hdr->type == ACPI_MADT_TYPE_IO_APIC && + get_ioapic_id(hdr, gsi_base, phys_addr, &apic_id)) + break; + else + entry += hdr->length; + } + + return apic_id; +} + +static int parse_mat_ioapic_entry(acpi_handle handle, u32 gsi_base, + u64 *phys_addr) +{ + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + struct acpi_subtable_header *header; + union acpi_object *obj; + int apic_id = -1; + + if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer))) + goto exit; + + if (!buffer.length || !buffer.pointer) + goto exit; + + obj = buffer.pointer; + if (obj->type != ACPI_TYPE_BUFFER || + obj->buffer.length < sizeof(struct acpi_subtable_header)) + goto exit; + + header = (struct acpi_subtable_header *)obj->buffer.pointer; + if (header->type == ACPI_MADT_TYPE_IO_APIC) + get_ioapic_id(header, gsi_base, phys_addr, &apic_id); + +exit: + kfree(buffer.pointer); + return apic_id; +} + +/** + * acpi_get_ioapic_id - Get IOAPIC ID and physical address matching @gsi_base + * @handle: ACPI object for IOAPIC device + * @gsi_base: GSI base to match with + * @phys_addr: Pointer to store physical address of matching IOAPIC record + * + * Walk resources returned by ACPI_MAT method, then ACPI MADT table, to search + * for an ACPI IOAPIC record matching @gsi_base. + * Return IOAPIC id and store physical address in @phys_addr if found a match, + * otherwise return <0. + */ +int acpi_get_ioapic_id(acpi_handle handle, u32 gsi_base, u64 *phys_addr) +{ + int apic_id; + + apic_id = parse_mat_ioapic_entry(handle, gsi_base, phys_addr); + if (apic_id == -1) + apic_id = parse_madt_ioapic_entry(gsi_base, phys_addr); + + return apic_id; +} +#endif /* CONFIG_ACPI_HOTPLUG_IOAPIC */ -- cgit v1.2.1 From c183619b63ec934110e3a173a34b414e26869f96 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 5 Feb 2015 13:44:49 +0800 Subject: x86/irq, ACPI: Implement ACPI driver to support IOAPIC hotplug Enable support of IOAPIC hotplug by: 1) reintroducing ACPI based IOAPIC driver 2) enhance pci_root driver to hook hotplug events The ACPI IOAPIC driver is always enabled if all of ACPI, PCI and IOAPIC are enabled. Signed-off-by: Jiang Liu Cc: Konrad Rzeszutek Wilk Cc: Tony Luck Cc: Joerg Roedel Cc: Greg Kroah-Hartman Cc: Benjamin Herrenschmidt Cc: Rafael J. Wysocki Cc: Bjorn Helgaas Cc: Randy Dunlap Cc: Yinghai Lu Cc: Borislav Petkov Cc: Len Brown Link: http://lkml.kernel.org/r/1414387308-27148-19-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner Signed-off-by: Rafael J. Wysocki --- drivers/acpi/Kconfig | 6 ++ drivers/acpi/Makefile | 1 + drivers/acpi/internal.h | 7 ++ drivers/acpi/ioapic.c | 229 ++++++++++++++++++++++++++++++++++++++++++++++++ drivers/acpi/pci_root.c | 3 + 5 files changed, 246 insertions(+) create mode 100644 drivers/acpi/ioapic.c (limited to 'drivers/acpi') diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 8951cefb0a96..e6c3ddd92665 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -315,6 +315,12 @@ config ACPI_HOTPLUG_MEMORY To compile this driver as a module, choose M here: the module will be called acpi_memhotplug. +config ACPI_HOTPLUG_IOAPIC + bool + depends on PCI + depends on X86_IO_APIC + default y + config ACPI_SBS tristate "Smart Battery System" depends on X86 diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index f74317cc1ca9..e59494c90402 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -70,6 +70,7 @@ obj-$(CONFIG_ACPI_PROCESSOR) += processor.o obj-y += container.o obj-$(CONFIG_ACPI_THERMAL) += thermal.o obj-y += acpi_memhotplug.o +obj-$(CONFIG_ACPI_HOTPLUG_IOAPIC) += ioapic.o obj-$(CONFIG_ACPI_BATTERY) += battery.o obj-$(CONFIG_ACPI_SBS) += sbshc.o obj-$(CONFIG_ACPI_SBS) += sbs.o diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 163e82f536fa..caca2805536d 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -35,6 +35,13 @@ void acpi_int340x_thermal_init(void); int acpi_sysfs_init(void); void acpi_container_init(void); void acpi_memory_hotplug_init(void); +#ifdef CONFIG_ACPI_HOTPLUG_IOAPIC +int acpi_ioapic_add(struct acpi_pci_root *root); +int acpi_ioapic_remove(struct acpi_pci_root *root); +#else +static inline int acpi_ioapic_add(struct acpi_pci_root *root) { return 0; } +static inline int acpi_ioapic_remove(struct acpi_pci_root *root) { return 0; } +#endif #ifdef CONFIG_ACPI_DOCK void register_dock_dependent_device(struct acpi_device *adev, acpi_handle dshandle); diff --git a/drivers/acpi/ioapic.c b/drivers/acpi/ioapic.c new file mode 100644 index 000000000000..ccdc8db16bb8 --- /dev/null +++ b/drivers/acpi/ioapic.c @@ -0,0 +1,229 @@ +/* + * IOAPIC/IOxAPIC/IOSAPIC driver + * + * Copyright (C) 2009 Fujitsu Limited. + * (c) Copyright 2009 Hewlett-Packard Development Company, L.P. + * + * Copyright (C) 2014 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Based on original drivers/pci/ioapic.c + * Yinghai Lu + * Jiang Liu + */ + +/* + * This driver manages I/O APICs added by hotplug after boot. + * We try to claim all I/O APIC devices, but those present at boot were + * registered when we parsed the ACPI MADT. + */ + +#define pr_fmt(fmt) "ACPI : IOAPIC: " fmt + +#include +#include +#include +#include + +struct acpi_pci_ioapic { + acpi_handle root_handle; + acpi_handle handle; + u32 gsi_base; + struct resource res; + struct pci_dev *pdev; + struct list_head list; +}; + +static LIST_HEAD(ioapic_list); +static DEFINE_MUTEX(ioapic_list_lock); + +static acpi_status setup_res(struct acpi_resource *acpi_res, void *data) +{ + struct resource *res = data; + struct resource_win win; + + res->flags = 0; + if (acpi_dev_filter_resource_type(acpi_res, IORESOURCE_MEM) == 0) + return AE_OK; + + if (!acpi_dev_resource_memory(acpi_res, res)) { + if (acpi_dev_resource_address_space(acpi_res, &win) || + acpi_dev_resource_ext_address_space(acpi_res, &win)) + *res = win.res; + } + if ((res->flags & IORESOURCE_PREFETCH) || + (res->flags & IORESOURCE_DISABLED)) + res->flags = 0; + + return AE_CTRL_TERMINATE; +} + +static bool acpi_is_ioapic(acpi_handle handle, char **type) +{ + acpi_status status; + struct acpi_device_info *info; + char *hid = NULL; + bool match = false; + + if (!acpi_has_method(handle, "_GSB")) + return false; + + status = acpi_get_object_info(handle, &info); + if (ACPI_SUCCESS(status)) { + if (info->valid & ACPI_VALID_HID) + hid = info->hardware_id.string; + if (hid) { + if (strcmp(hid, "ACPI0009") == 0) { + *type = "IOxAPIC"; + match = true; + } else if (strcmp(hid, "ACPI000A") == 0) { + *type = "IOAPIC"; + match = true; + } + } + kfree(info); + } + + return match; +} + +static acpi_status handle_ioapic_add(acpi_handle handle, u32 lvl, + void *context, void **rv) +{ + acpi_status status; + unsigned long long gsi_base; + struct acpi_pci_ioapic *ioapic; + struct pci_dev *dev = NULL; + struct resource *res = NULL; + char *type = NULL; + + if (!acpi_is_ioapic(handle, &type)) + return AE_OK; + + mutex_lock(&ioapic_list_lock); + list_for_each_entry(ioapic, &ioapic_list, list) + if (ioapic->handle == handle) { + mutex_unlock(&ioapic_list_lock); + return AE_OK; + } + + status = acpi_evaluate_integer(handle, "_GSB", NULL, &gsi_base); + if (ACPI_FAILURE(status)) { + acpi_handle_warn(handle, "failed to evaluate _GSB method\n"); + goto exit; + } + + ioapic = kzalloc(sizeof(*ioapic), GFP_KERNEL); + if (!ioapic) { + pr_err("cannot allocate memory for new IOAPIC\n"); + goto exit; + } else { + ioapic->root_handle = (acpi_handle)context; + ioapic->handle = handle; + ioapic->gsi_base = (u32)gsi_base; + INIT_LIST_HEAD(&ioapic->list); + } + + if (acpi_ioapic_registered(handle, (u32)gsi_base)) + goto done; + + dev = acpi_get_pci_dev(handle); + if (dev && pci_resource_len(dev, 0)) { + if (pci_enable_device(dev) < 0) + goto exit_put; + pci_set_master(dev); + if (pci_request_region(dev, 0, type)) + goto exit_disable; + res = &dev->resource[0]; + ioapic->pdev = dev; + } else { + pci_dev_put(dev); + dev = NULL; + + res = &ioapic->res; + acpi_walk_resources(handle, METHOD_NAME__CRS, setup_res, res); + if (res->flags == 0) { + acpi_handle_warn(handle, "failed to get resource\n"); + goto exit_free; + } else if (request_resource(&iomem_resource, res)) { + acpi_handle_warn(handle, "failed to insert resource\n"); + goto exit_free; + } + } + + if (acpi_register_ioapic(handle, res->start, (u32)gsi_base)) { + acpi_handle_warn(handle, "failed to register IOAPIC\n"); + goto exit_release; + } +done: + list_add(&ioapic->list, &ioapic_list); + mutex_unlock(&ioapic_list_lock); + + if (dev) + dev_info(&dev->dev, "%s at %pR, GSI %u\n", + type, res, (u32)gsi_base); + else + acpi_handle_info(handle, "%s at %pR, GSI %u\n", + type, res, (u32)gsi_base); + + return AE_OK; + +exit_release: + if (dev) + pci_release_region(dev, 0); + else + release_resource(res); +exit_disable: + if (dev) + pci_disable_device(dev); +exit_put: + pci_dev_put(dev); +exit_free: + kfree(ioapic); +exit: + mutex_unlock(&ioapic_list_lock); + *(acpi_status *)rv = AE_ERROR; + return AE_OK; +} + +int acpi_ioapic_add(struct acpi_pci_root *root) +{ + acpi_status status, retval = AE_OK; + + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, root->device->handle, + UINT_MAX, handle_ioapic_add, NULL, + root->device->handle, (void **)&retval); + + return ACPI_SUCCESS(status) && ACPI_SUCCESS(retval) ? 0 : -ENODEV; +} + +int acpi_ioapic_remove(struct acpi_pci_root *root) +{ + int retval = 0; + struct acpi_pci_ioapic *ioapic, *tmp; + + mutex_lock(&ioapic_list_lock); + list_for_each_entry_safe(ioapic, tmp, &ioapic_list, list) { + if (root->device->handle != ioapic->root_handle) + continue; + + if (acpi_unregister_ioapic(ioapic->handle, ioapic->gsi_base)) + retval = -EBUSY; + + if (ioapic->pdev) { + pci_release_region(ioapic->pdev, 0); + pci_disable_device(ioapic->pdev); + pci_dev_put(ioapic->pdev); + } else if (ioapic->res.flags && ioapic->res.parent) { + release_resource(&ioapic->res); + } + list_del(&ioapic->list); + kfree(ioapic); + } + mutex_unlock(&ioapic_list_lock); + + return retval; +} diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index e53e0f659204..68a5f712cd19 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -621,6 +621,7 @@ static int acpi_pci_root_add(struct acpi_device *device, if (hotadd) { pcibios_resource_survey_bus(root->bus); pci_assign_unassigned_root_bus_resources(root->bus); + acpi_ioapic_add(root); } pci_lock_rescan_remove(); @@ -644,6 +645,8 @@ static void acpi_pci_root_remove(struct acpi_device *device) pci_stop_root_bus(root->bus); + WARN_ON(acpi_ioapic_remove(root)); + device_set_run_wake(root->bus->bridge, false); pci_acpi_remove_bus_pm_notifier(device); -- cgit v1.2.1