Skip to content

Commit 4f89fa2

Browse files
James Morserafaeljw
authored andcommitted
ACPI / APEI: Replace ioremap_page_range() with fixmap
Replace ghes_io{re,un}map_pfn_{nmi,irq}()s use of ioremap_page_range() with __set_fixmap() as ioremap_page_range() may sleep to allocate a new level of page-table, even if its passed an existing final-address to use in the mapping. The GHES driver can only be enabled for architectures that select HAVE_ACPI_APEI: Add fixmap entries to both x86 and arm64. clear_fixmap() does the TLB invalidation in __set_fixmap() for arm64 and __set_pte_vaddr() for x86. In each case its the same as the respective arch_apei_flush_tlb_one(). Reported-by: Fengguang Wu <[email protected]> Suggested-by: Linus Torvalds <[email protected]> Signed-off-by: James Morse <[email protected]> Reviewed-by: Borislav Petkov <[email protected]> Tested-by: Tyler Baicar <[email protected]> Tested-by: Toshi Kani <[email protected]> [ For the arm64 bits: ] Acked-by: Will Deacon <[email protected]> [ For the x86 bits: ] Acked-by: Ingo Molnar <[email protected]> Signed-off-by: Rafael J. Wysocki <[email protected]> Cc: All applicable <[email protected]>
1 parent c49870e commit 4f89fa2

File tree

3 files changed

+27
-30
lines changed

3 files changed

+27
-30
lines changed

arch/arm64/include/asm/fixmap.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,13 @@ enum fixed_addresses {
5151

5252
FIX_EARLYCON_MEM_BASE,
5353
FIX_TEXT_POKE0,
54+
55+
#ifdef CONFIG_ACPI_APEI_GHES
56+
/* Used for GHES mapping from assorted contexts */
57+
FIX_APEI_GHES_IRQ,
58+
FIX_APEI_GHES_NMI,
59+
#endif /* CONFIG_ACPI_APEI_GHES */
60+
5461
__end_of_permanent_fixed_addresses,
5562

5663
/*

arch/x86/include/asm/fixmap.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,12 @@ enum fixed_addresses {
104104
FIX_GDT_REMAP_BEGIN,
105105
FIX_GDT_REMAP_END = FIX_GDT_REMAP_BEGIN + NR_CPUS - 1,
106106

107+
#ifdef CONFIG_ACPI_APEI_GHES
108+
/* Used for GHES mapping from assorted contexts */
109+
FIX_APEI_GHES_IRQ,
110+
FIX_APEI_GHES_NMI,
111+
#endif
112+
107113
__end_of_permanent_fixed_addresses,
108114

109115
/*

drivers/acpi/apei/ghes.c

Lines changed: 14 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
#include <acpi/actbl1.h>
5252
#include <acpi/ghes.h>
5353
#include <acpi/apei.h>
54+
#include <asm/fixmap.h>
5455
#include <asm/tlbflush.h>
5556
#include <ras/ras_event.h>
5657

@@ -112,7 +113,7 @@ static DEFINE_MUTEX(ghes_list_mutex);
112113
* Because the memory area used to transfer hardware error information
113114
* from BIOS to Linux can be determined only in NMI, IRQ or timer
114115
* handler, but general ioremap can not be used in atomic context, so
115-
* a special version of atomic ioremap is implemented for that.
116+
* the fixmap is used instead.
116117
*/
117118

118119
/*
@@ -126,8 +127,8 @@ static DEFINE_MUTEX(ghes_list_mutex);
126127
/* virtual memory area for atomic ioremap */
127128
static struct vm_struct *ghes_ioremap_area;
128129
/*
129-
* These 2 spinlock is used to prevent atomic ioremap virtual memory
130-
* area from being mapped simultaneously.
130+
* These 2 spinlocks are used to prevent the fixmap entries from being used
131+
* simultaneously.
131132
*/
132133
static DEFINE_RAW_SPINLOCK(ghes_ioremap_lock_nmi);
133134
static DEFINE_SPINLOCK(ghes_ioremap_lock_irq);
@@ -159,53 +160,36 @@ static void ghes_ioremap_exit(void)
159160

160161
static void __iomem *ghes_ioremap_pfn_nmi(u64 pfn)
161162
{
162-
unsigned long vaddr;
163163
phys_addr_t paddr;
164164
pgprot_t prot;
165165

166-
vaddr = (unsigned long)GHES_IOREMAP_NMI_PAGE(ghes_ioremap_area->addr);
167-
168166
paddr = pfn << PAGE_SHIFT;
169167
prot = arch_apei_get_mem_attribute(paddr);
170-
ioremap_page_range(vaddr, vaddr + PAGE_SIZE, paddr, prot);
168+
__set_fixmap(FIX_APEI_GHES_NMI, paddr, prot);
171169

172-
return (void __iomem *)vaddr;
170+
return (void __iomem *) fix_to_virt(FIX_APEI_GHES_NMI);
173171
}
174172

175173
static void __iomem *ghes_ioremap_pfn_irq(u64 pfn)
176174
{
177-
unsigned long vaddr;
178175
phys_addr_t paddr;
179176
pgprot_t prot;
180177

181-
vaddr = (unsigned long)GHES_IOREMAP_IRQ_PAGE(ghes_ioremap_area->addr);
182-
183178
paddr = pfn << PAGE_SHIFT;
184179
prot = arch_apei_get_mem_attribute(paddr);
180+
__set_fixmap(FIX_APEI_GHES_IRQ, paddr, prot);
185181

186-
ioremap_page_range(vaddr, vaddr + PAGE_SIZE, paddr, prot);
187-
188-
return (void __iomem *)vaddr;
182+
return (void __iomem *) fix_to_virt(FIX_APEI_GHES_IRQ);
189183
}
190184

191-
static void ghes_iounmap_nmi(void __iomem *vaddr_ptr)
185+
static void ghes_iounmap_nmi(void)
192186
{
193-
unsigned long vaddr = (unsigned long __force)vaddr_ptr;
194-
void *base = ghes_ioremap_area->addr;
195-
196-
BUG_ON(vaddr != (unsigned long)GHES_IOREMAP_NMI_PAGE(base));
197-
unmap_kernel_range_noflush(vaddr, PAGE_SIZE);
198-
arch_apei_flush_tlb_one(vaddr);
187+
clear_fixmap(FIX_APEI_GHES_NMI);
199188
}
200189

201-
static void ghes_iounmap_irq(void __iomem *vaddr_ptr)
190+
static void ghes_iounmap_irq(void)
202191
{
203-
unsigned long vaddr = (unsigned long __force)vaddr_ptr;
204-
void *base = ghes_ioremap_area->addr;
205-
206-
BUG_ON(vaddr != (unsigned long)GHES_IOREMAP_IRQ_PAGE(base));
207-
unmap_kernel_range_noflush(vaddr, PAGE_SIZE);
208-
arch_apei_flush_tlb_one(vaddr);
192+
clear_fixmap(FIX_APEI_GHES_IRQ);
209193
}
210194

211195
static int ghes_estatus_pool_init(void)
@@ -361,10 +345,10 @@ static void ghes_copy_tofrom_phys(void *buffer, u64 paddr, u32 len,
361345
paddr += trunk;
362346
buffer += trunk;
363347
if (in_nmi) {
364-
ghes_iounmap_nmi(vaddr);
348+
ghes_iounmap_nmi();
365349
raw_spin_unlock(&ghes_ioremap_lock_nmi);
366350
} else {
367-
ghes_iounmap_irq(vaddr);
351+
ghes_iounmap_irq();
368352
spin_unlock_irqrestore(&ghes_ioremap_lock_irq, flags);
369353
}
370354
}

0 commit comments

Comments
 (0)