Skip to content

Commit

Permalink
Merge branches 'acpi-pmic', 'acpi-apei' and 'acpi-x86'
Browse files Browse the repository at this point in the history
* acpi-pmic:
  ACPI / PMIC: Add TI PMIC TPS68470 operation region driver

* acpi-apei:
  APEI / ERST: use 64-bit timestamps
  ACPI / APEI: Remove arch_apei_flush_tlb_one()
  arm64: mm: Remove arch_apei_flush_tlb_one()
  ACPI / APEI: Remove ghes_ioremap_area
  ACPI / APEI: Replace ioremap_page_range() with fixmap
  ACPI / APEI: remove the unused dead-code for SEA/NMI notification type
  ACPI / APEI: adjust a local variable type in ghes_ioremap_pfn_irq()

* acpi-x86:
  ACPI / x86: Extend KIOX000A quirk to cover all affected BIOS versions
  • Loading branch information
Rafael J. Wysocki committed Nov 13, 2017
4 parents 60764eb + e13452a + c0041d4 + 1c3b44c commit 85595ad
Show file tree
Hide file tree
Showing 12 changed files with 530 additions and 115 deletions.
12 changes: 0 additions & 12 deletions arch/arm64/include/asm/acpi.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,18 +126,6 @@ static inline const char *acpi_get_enable_method(int cpu)
*/
#define acpi_disable_cmcff 1
pgprot_t arch_apei_get_mem_attribute(phys_addr_t addr);

/*
* Despite its name, this function must still broadcast the TLB
* invalidation in order to ensure other CPUs don't end up with junk
* entries as a result of speculation. Unusually, its also called in
* IRQ context (ghes_iounmap_irq) so if we ever need to use IPIs for
* TLB broadcasting, then we're in trouble here.
*/
static inline void arch_apei_flush_tlb_one(unsigned long addr)
{
flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
}
#endif /* CONFIG_ACPI_APEI */

#ifdef CONFIG_ACPI_NUMA
Expand Down
7 changes: 7 additions & 0 deletions arch/arm64/include/asm/fixmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@ enum fixed_addresses {

FIX_EARLYCON_MEM_BASE,
FIX_TEXT_POKE0,

#ifdef CONFIG_ACPI_APEI_GHES
/* Used for GHES mapping from assorted contexts */
FIX_APEI_GHES_IRQ,
FIX_APEI_GHES_NMI,
#endif /* CONFIG_ACPI_APEI_GHES */

__end_of_permanent_fixed_addresses,

/*
Expand Down
4 changes: 4 additions & 0 deletions arch/arm64/mm/mmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -778,6 +778,10 @@ void __init early_fixmap_init(void)
}
}

/*
* Unusually, this is also called in IRQ context (ghes_iounmap_irq) so if we
* ever need to use IPIs for TLB broadcasting, then we're in trouble here.
*/
void __set_fixmap(enum fixed_addresses idx,
phys_addr_t phys, pgprot_t flags)
{
Expand Down
6 changes: 6 additions & 0 deletions arch/x86/include/asm/fixmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,12 @@ enum fixed_addresses {
FIX_GDT_REMAP_BEGIN,
FIX_GDT_REMAP_END = FIX_GDT_REMAP_BEGIN + NR_CPUS - 1,

#ifdef CONFIG_ACPI_APEI_GHES
/* Used for GHES mapping from assorted contexts */
FIX_APEI_GHES_IRQ,
FIX_APEI_GHES_NMI,
#endif

__end_of_permanent_fixed_addresses,

/*
Expand Down
5 changes: 0 additions & 5 deletions arch/x86/kernel/acpi/apei.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,3 @@ void arch_apei_report_mem_error(int sev, struct cper_sec_mem_err *mem_err)
apei_mce_report_mem_error(sev, mem_err);
#endif
}

void arch_apei_flush_tlb_one(unsigned long addr)
{
__flush_tlb_one(addr);
}
16 changes: 16 additions & 0 deletions drivers/acpi/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -536,4 +536,20 @@ if ARM64
source "drivers/acpi/arm64/Kconfig"
endif

config TPS68470_PMIC_OPREGION
bool "ACPI operation region support for TPS68470 PMIC"
depends on MFD_TPS68470
help
This config adds ACPI operation region support for TI TPS68470 PMIC.
TPS68470 device is an advanced power management unit that powers
a Compact Camera Module (CCM), generates clocks for image sensors,
drives a dual LED for flash and incorporates two LED drivers for
general purpose indicators.
This driver enables ACPI operation region support control voltage
regulators and clocks.

This option is a bool as it provides an ACPI operation
region, which must be available before any of the devices
using this, are probed.

endif # ACPI
2 changes: 2 additions & 0 deletions drivers/acpi/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ obj-$(CONFIG_CHT_WC_PMIC_OPREGION) += pmic/intel_pmic_chtwc.o

obj-$(CONFIG_ACPI_CONFIGFS) += acpi_configfs.o

obj-$(CONFIG_TPS68470_PMIC_OPREGION) += pmic/tps68470_pmic.o

video-objs += acpi_video.o video_detect.o
obj-y += dptf/

Expand Down
2 changes: 1 addition & 1 deletion drivers/acpi/apei/erst.c
Original file line number Diff line number Diff line change
Expand Up @@ -1061,7 +1061,7 @@ static int erst_writer(struct pstore_record *record)
rcd->hdr.error_severity = CPER_SEV_FATAL;
/* timestamp valid. platform_id, partition_id are invalid */
rcd->hdr.validation_bits = CPER_VALID_TIMESTAMP;
rcd->hdr.timestamp = get_seconds();
rcd->hdr.timestamp = ktime_get_real_seconds();
rcd->hdr.record_length = sizeof(*rcd) + record->size;
rcd->hdr.creator_id = CPER_CREATOR_PSTORE;
rcd->hdr.notification_type = CPER_NOTIFY_MCE;
Expand Down
117 changes: 22 additions & 95 deletions drivers/acpi/apei/ghes.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
#include <acpi/actbl1.h>
#include <acpi/ghes.h>
#include <acpi/apei.h>
#include <asm/fixmap.h>
#include <asm/tlbflush.h>
#include <ras/ras_event.h>

Expand Down Expand Up @@ -112,22 +113,10 @@ static DEFINE_MUTEX(ghes_list_mutex);
* Because the memory area used to transfer hardware error information
* from BIOS to Linux can be determined only in NMI, IRQ or timer
* handler, but general ioremap can not be used in atomic context, so
* a special version of atomic ioremap is implemented for that.
*/

/*
* Two virtual pages are used, one for IRQ/PROCESS context, the other for
* NMI context (optionally).
*/
#define GHES_IOREMAP_PAGES 2
#define GHES_IOREMAP_IRQ_PAGE(base) (base)
#define GHES_IOREMAP_NMI_PAGE(base) ((base) + PAGE_SIZE)

/* virtual memory area for atomic ioremap */
static struct vm_struct *ghes_ioremap_area;
/*
* These 2 spinlock is used to prevent atomic ioremap virtual memory
* area from being mapped simultaneously.
* the fixmap is used instead.
*
* These 2 spinlocks are used to prevent the fixmap entries from being used
* simultaneously.
*/
static DEFINE_RAW_SPINLOCK(ghes_ioremap_lock_nmi);
static DEFINE_SPINLOCK(ghes_ioremap_lock_irq);
Expand All @@ -140,71 +129,38 @@ static atomic_t ghes_estatus_cache_alloced;

static int ghes_panic_timeout __read_mostly = 30;

static int ghes_ioremap_init(void)
{
ghes_ioremap_area = __get_vm_area(PAGE_SIZE * GHES_IOREMAP_PAGES,
VM_IOREMAP, VMALLOC_START, VMALLOC_END);
if (!ghes_ioremap_area) {
pr_err(GHES_PFX "Failed to allocate virtual memory area for atomic ioremap.\n");
return -ENOMEM;
}

return 0;
}

static void ghes_ioremap_exit(void)
{
free_vm_area(ghes_ioremap_area);
}

static void __iomem *ghes_ioremap_pfn_nmi(u64 pfn)
{
unsigned long vaddr;
phys_addr_t paddr;
pgprot_t prot;

vaddr = (unsigned long)GHES_IOREMAP_NMI_PAGE(ghes_ioremap_area->addr);

paddr = pfn << PAGE_SHIFT;
prot = arch_apei_get_mem_attribute(paddr);
ioremap_page_range(vaddr, vaddr + PAGE_SIZE, paddr, prot);
__set_fixmap(FIX_APEI_GHES_NMI, paddr, prot);

return (void __iomem *)vaddr;
return (void __iomem *) fix_to_virt(FIX_APEI_GHES_NMI);
}

static void __iomem *ghes_ioremap_pfn_irq(u64 pfn)
{
unsigned long vaddr, paddr;
phys_addr_t paddr;
pgprot_t prot;

vaddr = (unsigned long)GHES_IOREMAP_IRQ_PAGE(ghes_ioremap_area->addr);

paddr = pfn << PAGE_SHIFT;
prot = arch_apei_get_mem_attribute(paddr);
__set_fixmap(FIX_APEI_GHES_IRQ, paddr, prot);

ioremap_page_range(vaddr, vaddr + PAGE_SIZE, paddr, prot);

return (void __iomem *)vaddr;
return (void __iomem *) fix_to_virt(FIX_APEI_GHES_IRQ);
}

static void ghes_iounmap_nmi(void __iomem *vaddr_ptr)
static void ghes_iounmap_nmi(void)
{
unsigned long vaddr = (unsigned long __force)vaddr_ptr;
void *base = ghes_ioremap_area->addr;

BUG_ON(vaddr != (unsigned long)GHES_IOREMAP_NMI_PAGE(base));
unmap_kernel_range_noflush(vaddr, PAGE_SIZE);
arch_apei_flush_tlb_one(vaddr);
clear_fixmap(FIX_APEI_GHES_NMI);
}

static void ghes_iounmap_irq(void __iomem *vaddr_ptr)
static void ghes_iounmap_irq(void)
{
unsigned long vaddr = (unsigned long __force)vaddr_ptr;
void *base = ghes_ioremap_area->addr;

BUG_ON(vaddr != (unsigned long)GHES_IOREMAP_IRQ_PAGE(base));
unmap_kernel_range_noflush(vaddr, PAGE_SIZE);
arch_apei_flush_tlb_one(vaddr);
clear_fixmap(FIX_APEI_GHES_IRQ);
}

static int ghes_estatus_pool_init(void)
Expand Down Expand Up @@ -360,10 +316,10 @@ static void ghes_copy_tofrom_phys(void *buffer, u64 paddr, u32 len,
paddr += trunk;
buffer += trunk;
if (in_nmi) {
ghes_iounmap_nmi(vaddr);
ghes_iounmap_nmi();
raw_spin_unlock(&ghes_ioremap_lock_nmi);
} else {
ghes_iounmap_irq(vaddr);
ghes_iounmap_irq();
spin_unlock_irqrestore(&ghes_ioremap_lock_irq, flags);
}
}
Expand Down Expand Up @@ -851,17 +807,8 @@ static void ghes_sea_remove(struct ghes *ghes)
synchronize_rcu();
}
#else /* CONFIG_ACPI_APEI_SEA */
static inline void ghes_sea_add(struct ghes *ghes)
{
pr_err(GHES_PFX "ID: %d, trying to add SEA notification which is not supported\n",
ghes->generic->header.source_id);
}

static inline void ghes_sea_remove(struct ghes *ghes)
{
pr_err(GHES_PFX "ID: %d, trying to remove SEA notification which is not supported\n",
ghes->generic->header.source_id);
}
static inline void ghes_sea_add(struct ghes *ghes) { }
static inline void ghes_sea_remove(struct ghes *ghes) { }
#endif /* CONFIG_ACPI_APEI_SEA */

#ifdef CONFIG_HAVE_ACPI_APEI_NMI
Expand Down Expand Up @@ -1063,23 +1010,9 @@ static void ghes_nmi_init_cxt(void)
init_irq_work(&ghes_proc_irq_work, ghes_proc_in_irq);
}
#else /* CONFIG_HAVE_ACPI_APEI_NMI */
static inline void ghes_nmi_add(struct ghes *ghes)
{
pr_err(GHES_PFX "ID: %d, trying to add NMI notification which is not supported!\n",
ghes->generic->header.source_id);
BUG();
}

static inline void ghes_nmi_remove(struct ghes *ghes)
{
pr_err(GHES_PFX "ID: %d, trying to remove NMI notification which is not supported!\n",
ghes->generic->header.source_id);
BUG();
}

static inline void ghes_nmi_init_cxt(void)
{
}
static inline void ghes_nmi_add(struct ghes *ghes) { }
static inline void ghes_nmi_remove(struct ghes *ghes) { }
static inline void ghes_nmi_init_cxt(void) { }
#endif /* CONFIG_HAVE_ACPI_APEI_NMI */

static int ghes_probe(struct platform_device *ghes_dev)
Expand Down Expand Up @@ -1285,13 +1218,9 @@ static int __init ghes_init(void)

ghes_nmi_init_cxt();

rc = ghes_ioremap_init();
if (rc)
goto err;

rc = ghes_estatus_pool_init();
if (rc)
goto err_ioremap_exit;
goto err;

rc = ghes_estatus_pool_expand(GHES_ESTATUS_CACHE_AVG_SIZE *
GHES_ESTATUS_CACHE_ALLOCED_MAX);
Expand All @@ -1315,8 +1244,6 @@ static int __init ghes_init(void)
return 0;
err_pool_exit:
ghes_estatus_pool_exit();
err_ioremap_exit:
ghes_ioremap_exit();
err:
return rc;
}
Expand Down
Loading

0 comments on commit 85595ad

Please sign in to comment.