1*b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * linux/arch/m68k/mm/memory.c
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * Copyright (C) 1995 Hamish Macdonald
61da177e4SLinus Torvalds */
71da177e4SLinus Torvalds
82e811488SAl Viro #include <linux/module.h>
91da177e4SLinus Torvalds #include <linux/mm.h>
101da177e4SLinus Torvalds #include <linux/kernel.h>
111da177e4SLinus Torvalds #include <linux/string.h>
121da177e4SLinus Torvalds #include <linux/types.h>
131da177e4SLinus Torvalds #include <linux/init.h>
141da177e4SLinus Torvalds #include <linux/pagemap.h>
155a0e3ad6STejun Heo #include <linux/gfp.h>
161da177e4SLinus Torvalds
171da177e4SLinus Torvalds #include <asm/setup.h>
181da177e4SLinus Torvalds #include <asm/page.h>
191da177e4SLinus Torvalds #include <asm/traps.h>
201da177e4SLinus Torvalds #include <asm/machdep.h>
211da177e4SLinus Torvalds
221da177e4SLinus Torvalds
231da177e4SLinus Torvalds /* invalidate page in both caches */
clear040(unsigned long paddr)241da177e4SLinus Torvalds static inline void clear040(unsigned long paddr)
251da177e4SLinus Torvalds {
261da177e4SLinus Torvalds asm volatile (
271da177e4SLinus Torvalds "nop\n\t"
281da177e4SLinus Torvalds ".chip 68040\n\t"
291da177e4SLinus Torvalds "cinvp %%bc,(%0)\n\t"
301da177e4SLinus Torvalds ".chip 68k"
311da177e4SLinus Torvalds : : "a" (paddr));
321da177e4SLinus Torvalds }
331da177e4SLinus Torvalds
341da177e4SLinus Torvalds /* invalidate page in i-cache */
cleari040(unsigned long paddr)351da177e4SLinus Torvalds static inline void cleari040(unsigned long paddr)
361da177e4SLinus Torvalds {
371da177e4SLinus Torvalds asm volatile (
381da177e4SLinus Torvalds "nop\n\t"
391da177e4SLinus Torvalds ".chip 68040\n\t"
401da177e4SLinus Torvalds "cinvp %%ic,(%0)\n\t"
411da177e4SLinus Torvalds ".chip 68k"
421da177e4SLinus Torvalds : : "a" (paddr));
431da177e4SLinus Torvalds }
441da177e4SLinus Torvalds
451da177e4SLinus Torvalds /* push page in both caches */
461da177e4SLinus Torvalds /* RZ: cpush %bc DOES invalidate %ic, regardless of DPI */
push040(unsigned long paddr)471da177e4SLinus Torvalds static inline void push040(unsigned long paddr)
481da177e4SLinus Torvalds {
491da177e4SLinus Torvalds asm volatile (
501da177e4SLinus Torvalds "nop\n\t"
511da177e4SLinus Torvalds ".chip 68040\n\t"
521da177e4SLinus Torvalds "cpushp %%bc,(%0)\n\t"
531da177e4SLinus Torvalds ".chip 68k"
541da177e4SLinus Torvalds : : "a" (paddr));
551da177e4SLinus Torvalds }
561da177e4SLinus Torvalds
571da177e4SLinus Torvalds /* push and invalidate page in both caches, must disable ints
581da177e4SLinus Torvalds * to avoid invalidating valid data */
pushcl040(unsigned long paddr)591da177e4SLinus Torvalds static inline void pushcl040(unsigned long paddr)
601da177e4SLinus Torvalds {
611da177e4SLinus Torvalds unsigned long flags;
621da177e4SLinus Torvalds
631da177e4SLinus Torvalds local_irq_save(flags);
641da177e4SLinus Torvalds push040(paddr);
651da177e4SLinus Torvalds if (CPU_IS_060)
661da177e4SLinus Torvalds clear040(paddr);
671da177e4SLinus Torvalds local_irq_restore(flags);
681da177e4SLinus Torvalds }
691da177e4SLinus Torvalds
701da177e4SLinus Torvalds /*
711da177e4SLinus Torvalds * 040: Hit every page containing an address in the range paddr..paddr+len-1.
721da177e4SLinus Torvalds * (Low order bits of the ea of a CINVP/CPUSHP are "don't care"s).
731da177e4SLinus Torvalds * Hit every page until there is a page or less to go. Hit the next page,
741da177e4SLinus Torvalds * and the one after that if the range hits it.
751da177e4SLinus Torvalds */
761da177e4SLinus Torvalds /* ++roman: A little bit more care is required here: The CINVP instruction
771da177e4SLinus Torvalds * invalidates cache entries WITHOUT WRITING DIRTY DATA BACK! So the beginning
781da177e4SLinus Torvalds * and the end of the region must be treated differently if they are not
791da177e4SLinus Torvalds * exactly at the beginning or end of a page boundary. Else, maybe too much
801da177e4SLinus Torvalds * data becomes invalidated and thus lost forever. CPUSHP does what we need:
811da177e4SLinus Torvalds * it invalidates the page after pushing dirty data to memory. (Thanks to Jes
821da177e4SLinus Torvalds * for discovering the problem!)
831da177e4SLinus Torvalds */
841da177e4SLinus Torvalds /* ... but on the '060, CPUSH doesn't invalidate (for us, since we have set
851da177e4SLinus Torvalds * the DPI bit in the CACR; would it cause problems with temporarily changing
861da177e4SLinus Torvalds * this?). So we have to push first and then additionally to invalidate.
871da177e4SLinus Torvalds */
881da177e4SLinus Torvalds
891da177e4SLinus Torvalds
901da177e4SLinus Torvalds /*
911da177e4SLinus Torvalds * cache_clear() semantics: Clear any cache entries for the area in question,
921da177e4SLinus Torvalds * without writing back dirty entries first. This is useful if the data will
931da177e4SLinus Torvalds * be overwritten anyway, e.g. by DMA to memory. The range is defined by a
941da177e4SLinus Torvalds * _physical_ address.
951da177e4SLinus Torvalds */
961da177e4SLinus Torvalds
cache_clear(unsigned long paddr,int len)971da177e4SLinus Torvalds void cache_clear (unsigned long paddr, int len)
981da177e4SLinus Torvalds {
9960610192SGreg Ungerer if (CPU_IS_COLDFIRE) {
100f3ff6432SGreg Ungerer clear_cf_bcache(0, DCACHE_MAX_ADDR);
10160610192SGreg Ungerer } else if (CPU_IS_040_OR_060) {
1021da177e4SLinus Torvalds int tmp;
1031da177e4SLinus Torvalds
1041da177e4SLinus Torvalds /*
1051da177e4SLinus Torvalds * We need special treatment for the first page, in case it
1061da177e4SLinus Torvalds * is not page-aligned. Page align the addresses to work
1071da177e4SLinus Torvalds * around bug I17 in the 68060.
1081da177e4SLinus Torvalds */
1091da177e4SLinus Torvalds if ((tmp = -paddr & (PAGE_SIZE - 1))) {
1101da177e4SLinus Torvalds pushcl040(paddr & PAGE_MASK);
1111da177e4SLinus Torvalds if ((len -= tmp) <= 0)
1121da177e4SLinus Torvalds return;
1131da177e4SLinus Torvalds paddr += tmp;
1141da177e4SLinus Torvalds }
1151da177e4SLinus Torvalds tmp = PAGE_SIZE;
1161da177e4SLinus Torvalds paddr &= PAGE_MASK;
1171da177e4SLinus Torvalds while ((len -= tmp) >= 0) {
1181da177e4SLinus Torvalds clear040(paddr);
1191da177e4SLinus Torvalds paddr += tmp;
1201da177e4SLinus Torvalds }
1211da177e4SLinus Torvalds if ((len += tmp))
1221da177e4SLinus Torvalds /* a page boundary gets crossed at the end */
1231da177e4SLinus Torvalds pushcl040(paddr);
1241da177e4SLinus Torvalds }
1251da177e4SLinus Torvalds else /* 68030 or 68020 */
1261da177e4SLinus Torvalds asm volatile ("movec %/cacr,%/d0\n\t"
1271da177e4SLinus Torvalds "oriw %0,%/d0\n\t"
1281da177e4SLinus Torvalds "movec %/d0,%/cacr"
1291da177e4SLinus Torvalds : : "i" (FLUSH_I_AND_D)
1301da177e4SLinus Torvalds : "d0");
1311da177e4SLinus Torvalds #ifdef CONFIG_M68K_L2_CACHE
1321da177e4SLinus Torvalds if(mach_l2_flush)
1331da177e4SLinus Torvalds mach_l2_flush(0);
1341da177e4SLinus Torvalds #endif
1351da177e4SLinus Torvalds }
136bf8af91bSGeert Uytterhoeven EXPORT_SYMBOL(cache_clear);
1371da177e4SLinus Torvalds
1381da177e4SLinus Torvalds
1391da177e4SLinus Torvalds /*
1401da177e4SLinus Torvalds * cache_push() semantics: Write back any dirty cache data in the given area,
1411da177e4SLinus Torvalds * and invalidate the range in the instruction cache. It needs not (but may)
1421da177e4SLinus Torvalds * invalidate those entries also in the data cache. The range is defined by a
1431da177e4SLinus Torvalds * _physical_ address.
1441da177e4SLinus Torvalds */
1451da177e4SLinus Torvalds
cache_push(unsigned long paddr,int len)1461da177e4SLinus Torvalds void cache_push (unsigned long paddr, int len)
1471da177e4SLinus Torvalds {
14860610192SGreg Ungerer if (CPU_IS_COLDFIRE) {
14960610192SGreg Ungerer flush_cf_bcache(0, DCACHE_MAX_ADDR);
15060610192SGreg Ungerer } else if (CPU_IS_040_OR_060) {
1511da177e4SLinus Torvalds int tmp = PAGE_SIZE;
1521da177e4SLinus Torvalds
1531da177e4SLinus Torvalds /*
1541da177e4SLinus Torvalds * on 68040 or 68060, push cache lines for pages in the range;
1551da177e4SLinus Torvalds * on the '040 this also invalidates the pushed lines, but not on
1561da177e4SLinus Torvalds * the '060!
1571da177e4SLinus Torvalds */
1581da177e4SLinus Torvalds len += paddr & (PAGE_SIZE - 1);
1591da177e4SLinus Torvalds
1601da177e4SLinus Torvalds /*
1611da177e4SLinus Torvalds * Work around bug I17 in the 68060 affecting some instruction
1621da177e4SLinus Torvalds * lines not being invalidated properly.
1631da177e4SLinus Torvalds */
1641da177e4SLinus Torvalds paddr &= PAGE_MASK;
1651da177e4SLinus Torvalds
1661da177e4SLinus Torvalds do {
1671da177e4SLinus Torvalds push040(paddr);
1681da177e4SLinus Torvalds paddr += tmp;
1691da177e4SLinus Torvalds } while ((len -= tmp) > 0);
1701da177e4SLinus Torvalds }
1711da177e4SLinus Torvalds /*
1721da177e4SLinus Torvalds * 68030/68020 have no writeback cache. On the other hand,
1731da177e4SLinus Torvalds * cache_push is actually a superset of cache_clear (the lines
1741da177e4SLinus Torvalds * get written back and invalidated), so we should make sure
1751da177e4SLinus Torvalds * to perform the corresponding actions. After all, this is getting
1761da177e4SLinus Torvalds * called in places where we've just loaded code, or whatever, so
1771da177e4SLinus Torvalds * flushing the icache is appropriate; flushing the dcache shouldn't
1781da177e4SLinus Torvalds * be required.
1791da177e4SLinus Torvalds */
1801da177e4SLinus Torvalds else /* 68030 or 68020 */
1811da177e4SLinus Torvalds asm volatile ("movec %/cacr,%/d0\n\t"
1821da177e4SLinus Torvalds "oriw %0,%/d0\n\t"
1831da177e4SLinus Torvalds "movec %/d0,%/cacr"
1841da177e4SLinus Torvalds : : "i" (FLUSH_I)
1851da177e4SLinus Torvalds : "d0");
1861da177e4SLinus Torvalds #ifdef CONFIG_M68K_L2_CACHE
1871da177e4SLinus Torvalds if(mach_l2_flush)
1881da177e4SLinus Torvalds mach_l2_flush(1);
1891da177e4SLinus Torvalds #endif
1901da177e4SLinus Torvalds }
191bf8af91bSGeert Uytterhoeven EXPORT_SYMBOL(cache_push);
1921da177e4SLinus Torvalds
193