Skip to content

Commit 42dac16

Browse files
deecegregkh
authored andcommitted
powerpc: Convert flush_icache_range & friends to C
[ Upstream commit 23eb7f5 ] Similar to commit 22e9c88 ("powerpc/64: reuse PPC32 static inline flush_dcache_range()") this patch converts the following ASM symbols to C: flush_icache_range() __flush_dcache_icache() __flush_dcache_icache_phys() This was done as we discovered a long-standing bug where the length of the range was truncated due to using a 32 bit shift instead of a 64 bit one. By converting these functions to C, it becomes easier to maintain. flush_dcache_icache_phys() retains a critical assembler section as we must ensure there are no memory accesses while the data MMU is disabled (authored by Christophe Leroy). Since this has no external callers, it has also been made static, allowing the compiler to inline it within flush_dcache_icache_page(). Signed-off-by: Alastair D'Silva <[email protected]> Signed-off-by: Christophe Leroy <[email protected]> Signed-off-by: Michael Ellerman <[email protected]> [mpe: Minor fixups, don't export __flush_dcache_icache()] Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Sasha Levin <[email protected]>
1 parent ec21f6d commit 42dac16

File tree

5 files changed

+170
-252
lines changed

5 files changed

+170
-252
lines changed

arch/powerpc/include/asm/cache.h

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -96,22 +96,7 @@ static inline u32 l1_icache_bytes(void)
9696
}
9797

9898
#endif
99-
#endif /* ! __ASSEMBLY__ */
100-
101-
#if defined(__ASSEMBLY__)
102-
/*
103-
* For a snooping icache, we still need a dummy icbi to purge all the
104-
* prefetched instructions from the ifetch buffers. We also need a sync
105-
* before the icbi to order the the actual stores to memory that might
106-
* have modified instructions with the icbi.
107-
*/
108-
#define PURGE_PREFETCHED_INS \
109-
sync; \
110-
icbi 0,r3; \
111-
sync; \
112-
isync
11399

114-
#else
115100
#define __read_mostly __attribute__((__section__(".data..read_mostly")))
116101

117102
#ifdef CONFIG_PPC_BOOK3S_32
@@ -145,6 +130,17 @@ static inline void dcbst(void *addr)
145130
{
146131
__asm__ __volatile__ ("dcbst 0, %0" : : "r"(addr) : "memory");
147132
}
133+
134+
static inline void icbi(void *addr)
135+
{
136+
asm volatile ("icbi 0, %0" : : "r"(addr) : "memory");
137+
}
138+
139+
static inline void iccci(void *addr)
140+
{
141+
asm volatile ("iccci 0, %0" : : "r"(addr) : "memory");
142+
}
143+
148144
#endif /* !__ASSEMBLY__ */
149145
#endif /* __KERNEL__ */
150146
#endif /* _ASM_POWERPC_CACHE_H */

arch/powerpc/include/asm/cacheflush.h

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -42,24 +42,20 @@ extern void flush_dcache_page(struct page *page);
4242
#define flush_dcache_mmap_lock(mapping) do { } while (0)
4343
#define flush_dcache_mmap_unlock(mapping) do { } while (0)
4444

45-
extern void flush_icache_range(unsigned long, unsigned long);
45+
void flush_icache_range(unsigned long start, unsigned long stop);
4646
extern void flush_icache_user_range(struct vm_area_struct *vma,
4747
struct page *page, unsigned long addr,
4848
int len);
49-
extern void __flush_dcache_icache(void *page_va);
5049
extern void flush_dcache_icache_page(struct page *page);
51-
#if defined(CONFIG_PPC32) && !defined(CONFIG_BOOKE)
52-
extern void __flush_dcache_icache_phys(unsigned long physaddr);
53-
#else
54-
static inline void __flush_dcache_icache_phys(unsigned long physaddr)
55-
{
56-
BUG();
57-
}
58-
#endif
59-
60-
/*
61-
* Write any modified data cache blocks out to memory and invalidate them.
62-
* Does not invalidate the corresponding instruction cache blocks.
50+
void __flush_dcache_icache(void *page);
51+
52+
/**
53+
* flush_dcache_range(): Write any modified data cache blocks out to memory and
54+
* invalidate them. Does not invalidate the corresponding instruction cache
55+
* blocks.
56+
*
57+
* @start: the start address
58+
* @stop: the stop address (exclusive)
6359
*/
6460
static inline void flush_dcache_range(unsigned long start, unsigned long stop)
6561
{

arch/powerpc/kernel/misc_32.S

Lines changed: 0 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -316,126 +316,6 @@ _GLOBAL(flush_instruction_cache)
316316
EXPORT_SYMBOL(flush_instruction_cache)
317317
#endif /* CONFIG_PPC_8xx */
318318

319-
/*
320-
* Write any modified data cache blocks out to memory
321-
* and invalidate the corresponding instruction cache blocks.
322-
* This is a no-op on the 601.
323-
*
324-
* flush_icache_range(unsigned long start, unsigned long stop)
325-
*/
326-
_GLOBAL(flush_icache_range)
327-
#if defined(CONFIG_PPC_BOOK3S_601) || defined(CONFIG_E200)
328-
PURGE_PREFETCHED_INS
329-
blr /* for 601 and e200, do nothing */
330-
#else
331-
rlwinm r3,r3,0,0,31 - L1_CACHE_SHIFT
332-
subf r4,r3,r4
333-
addi r4,r4,L1_CACHE_BYTES - 1
334-
srwi. r4,r4,L1_CACHE_SHIFT
335-
beqlr
336-
mtctr r4
337-
mr r6,r3
338-
1: dcbst 0,r3
339-
addi r3,r3,L1_CACHE_BYTES
340-
bdnz 1b
341-
sync /* wait for dcbst's to get to ram */
342-
#ifndef CONFIG_44x
343-
mtctr r4
344-
2: icbi 0,r6
345-
addi r6,r6,L1_CACHE_BYTES
346-
bdnz 2b
347-
#else
348-
/* Flash invalidate on 44x because we are passed kmapped addresses and
349-
this doesn't work for userspace pages due to the virtually tagged
350-
icache. Sigh. */
351-
iccci 0, r0
352-
#endif
353-
sync /* additional sync needed on g4 */
354-
isync
355-
blr
356-
#endif
357-
_ASM_NOKPROBE_SYMBOL(flush_icache_range)
358-
EXPORT_SYMBOL(flush_icache_range)
359-
360-
/*
361-
* Flush a particular page from the data cache to RAM.
362-
* Note: this is necessary because the instruction cache does *not*
363-
* snoop from the data cache.
364-
* This is a no-op on the 601 and e200 which have a unified cache.
365-
*
366-
* void __flush_dcache_icache(void *page)
367-
*/
368-
_GLOBAL(__flush_dcache_icache)
369-
#if defined(CONFIG_PPC_BOOK3S_601) || defined(CONFIG_E200)
370-
PURGE_PREFETCHED_INS
371-
blr
372-
#else
373-
rlwinm r3,r3,0,0,31-PAGE_SHIFT /* Get page base address */
374-
li r4,PAGE_SIZE/L1_CACHE_BYTES /* Number of lines in a page */
375-
mtctr r4
376-
mr r6,r3
377-
0: dcbst 0,r3 /* Write line to ram */
378-
addi r3,r3,L1_CACHE_BYTES
379-
bdnz 0b
380-
sync
381-
#ifdef CONFIG_44x
382-
/* We don't flush the icache on 44x. Those have a virtual icache
383-
* and we don't have access to the virtual address here (it's
384-
* not the page vaddr but where it's mapped in user space). The
385-
* flushing of the icache on these is handled elsewhere, when
386-
* a change in the address space occurs, before returning to
387-
* user space
388-
*/
389-
BEGIN_MMU_FTR_SECTION
390-
blr
391-
END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_44x)
392-
#endif /* CONFIG_44x */
393-
mtctr r4
394-
1: icbi 0,r6
395-
addi r6,r6,L1_CACHE_BYTES
396-
bdnz 1b
397-
sync
398-
isync
399-
blr
400-
#endif
401-
402-
#ifndef CONFIG_BOOKE
403-
/*
404-
* Flush a particular page from the data cache to RAM, identified
405-
* by its physical address. We turn off the MMU so we can just use
406-
* the physical address (this may be a highmem page without a kernel
407-
* mapping).
408-
*
409-
* void __flush_dcache_icache_phys(unsigned long physaddr)
410-
*/
411-
_GLOBAL(__flush_dcache_icache_phys)
412-
#if defined(CONFIG_PPC_BOOK3S_601) || defined(CONFIG_E200)
413-
PURGE_PREFETCHED_INS
414-
blr /* for 601 and e200, do nothing */
415-
#else
416-
mfmsr r10
417-
rlwinm r0,r10,0,28,26 /* clear DR */
418-
mtmsr r0
419-
isync
420-
rlwinm r3,r3,0,0,31-PAGE_SHIFT /* Get page base address */
421-
li r4,PAGE_SIZE/L1_CACHE_BYTES /* Number of lines in a page */
422-
mtctr r4
423-
mr r6,r3
424-
0: dcbst 0,r3 /* Write line to ram */
425-
addi r3,r3,L1_CACHE_BYTES
426-
bdnz 0b
427-
sync
428-
mtctr r4
429-
1: icbi 0,r6
430-
addi r6,r6,L1_CACHE_BYTES
431-
bdnz 1b
432-
sync
433-
mtmsr r10 /* restore DR */
434-
isync
435-
blr
436-
#endif
437-
#endif /* CONFIG_BOOKE */
438-
439319
/*
440320
* Copy a whole page. We use the dcbz instruction on the destination
441321
* to reduce memory traffic (it eliminates the unnecessary reads of

arch/powerpc/kernel/misc_64.S

Lines changed: 0 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -49,108 +49,6 @@ _GLOBAL(call_do_irq)
4949
mtlr r0
5050
blr
5151

52-
.section ".toc","aw"
53-
PPC64_CACHES:
54-
.tc ppc64_caches[TC],ppc64_caches
55-
.section ".text"
56-
57-
/*
58-
* Write any modified data cache blocks out to memory
59-
* and invalidate the corresponding instruction cache blocks.
60-
*
61-
* flush_icache_range(unsigned long start, unsigned long stop)
62-
*
63-
* flush all bytes from start through stop-1 inclusive
64-
*/
65-
66-
_GLOBAL_TOC(flush_icache_range)
67-
BEGIN_FTR_SECTION
68-
PURGE_PREFETCHED_INS
69-
blr
70-
END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
71-
/*
72-
* Flush the data cache to memory
73-
*
74-
* Different systems have different cache line sizes
75-
* and in some cases i-cache and d-cache line sizes differ from
76-
* each other.
77-
*/
78-
ld r10,PPC64_CACHES@toc(r2)
79-
lwz r7,DCACHEL1BLOCKSIZE(r10)/* Get cache block size */
80-
addi r5,r7,-1
81-
andc r6,r3,r5 /* round low to line bdy */
82-
subf r8,r6,r4 /* compute length */
83-
add r8,r8,r5 /* ensure we get enough */
84-
lwz r9,DCACHEL1LOGBLOCKSIZE(r10) /* Get log-2 of cache block size */
85-
srd. r8,r8,r9 /* compute line count */
86-
beqlr /* nothing to do? */
87-
mtctr r8
88-
1: dcbst 0,r6
89-
add r6,r6,r7
90-
bdnz 1b
91-
sync
92-
93-
/* Now invalidate the instruction cache */
94-
95-
lwz r7,ICACHEL1BLOCKSIZE(r10) /* Get Icache block size */
96-
addi r5,r7,-1
97-
andc r6,r3,r5 /* round low to line bdy */
98-
subf r8,r6,r4 /* compute length */
99-
add r8,r8,r5
100-
lwz r9,ICACHEL1LOGBLOCKSIZE(r10) /* Get log-2 of Icache block size */
101-
srd. r8,r8,r9 /* compute line count */
102-
beqlr /* nothing to do? */
103-
mtctr r8
104-
2: icbi 0,r6
105-
add r6,r6,r7
106-
bdnz 2b
107-
isync
108-
blr
109-
_ASM_NOKPROBE_SYMBOL(flush_icache_range)
110-
EXPORT_SYMBOL(flush_icache_range)
111-
112-
/*
113-
* Flush a particular page from the data cache to RAM.
114-
* Note: this is necessary because the instruction cache does *not*
115-
* snoop from the data cache.
116-
*
117-
* void __flush_dcache_icache(void *page)
118-
*/
119-
_GLOBAL(__flush_dcache_icache)
120-
/*
121-
* Flush the data cache to memory
122-
*
123-
* Different systems have different cache line sizes
124-
*/
125-
126-
BEGIN_FTR_SECTION
127-
PURGE_PREFETCHED_INS
128-
blr
129-
END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
130-
131-
/* Flush the dcache */
132-
ld r7,PPC64_CACHES@toc(r2)
133-
clrrdi r3,r3,PAGE_SHIFT /* Page align */
134-
lwz r4,DCACHEL1BLOCKSPERPAGE(r7) /* Get # dcache blocks per page */
135-
lwz r5,DCACHEL1BLOCKSIZE(r7) /* Get dcache block size */
136-
mr r6,r3
137-
mtctr r4
138-
0: dcbst 0,r6
139-
add r6,r6,r5
140-
bdnz 0b
141-
sync
142-
143-
/* Now invalidate the icache */
144-
145-
lwz r4,ICACHEL1BLOCKSPERPAGE(r7) /* Get # icache blocks per page */
146-
lwz r5,ICACHEL1BLOCKSIZE(r7) /* Get icache block size */
147-
mtctr r4
148-
1: icbi 0,r3
149-
add r3,r3,r5
150-
bdnz 1b
151-
isync
152-
blr
153-
15452
_GLOBAL(__bswapdi2)
15553
EXPORT_SYMBOL(__bswapdi2)
15654
srdi r8,r3,32

0 commit comments

Comments
 (0)