/*1* linux/arch/m68k/mm/memory.c2*3* Copyright (C) 1995 Hamish Macdonald4*/56#include <linux/module.h>7#include <linux/mm.h>8#include <linux/kernel.h>9#include <linux/string.h>10#include <linux/types.h>11#include <linux/init.h>12#include <linux/pagemap.h>13#include <linux/gfp.h>1415#include <asm/setup.h>16#include <asm/segment.h>17#include <asm/page.h>18#include <asm/pgalloc.h>19#include <asm/system.h>20#include <asm/traps.h>21#include <asm/machdep.h>222324/* ++andreas: {get,free}_pointer_table rewritten to use unused fields from25struct page instead of separately kmalloced struct. Stolen from26arch/sparc/mm/srmmu.c ... */2728typedef struct list_head ptable_desc;29static LIST_HEAD(ptable_list);3031#define PD_PTABLE(page) ((ptable_desc *)&(virt_to_page(page)->lru))32#define PD_PAGE(ptable) (list_entry(ptable, struct page, lru))33#define PD_MARKBITS(dp) (*(unsigned char *)&PD_PAGE(dp)->index)3435#define PTABLE_SIZE (PTRS_PER_PMD * sizeof(pmd_t))3637void __init init_pointer_table(unsigned long ptable)38{39ptable_desc *dp;40unsigned long page = ptable & PAGE_MASK;41unsigned char mask = 1 << ((ptable - page)/PTABLE_SIZE);4243dp = PD_PTABLE(page);44if (!(PD_MARKBITS(dp) & mask)) {45PD_MARKBITS(dp) = 0xff;46list_add(dp, &ptable_list);47}4849PD_MARKBITS(dp) &= ~mask;50#ifdef DEBUG51printk("init_pointer_table: %lx, %x\n", ptable, PD_MARKBITS(dp));52#endif5354/* unreserve the page so it's possible to free that page */55PD_PAGE(dp)->flags &= ~(1 << PG_reserved);56init_page_count(PD_PAGE(dp));5758return;59}6061pmd_t *get_pointer_table (void)62{63ptable_desc *dp = ptable_list.next;64unsigned char mask = PD_MARKBITS (dp);65unsigned char tmp;66unsigned int off;6768/*69* For a pointer table for a user process address space, a70* table is taken from a page allocated for the purpose. Each71* page can hold 8 pointer tables. The page is remapped in72* virtual address space to be noncacheable.73*/74if (mask == 0) {75void *page;76ptable_desc *new;7778if (!(page = (void *)get_zeroed_page(GFP_KERNEL)))79return NULL;8081flush_tlb_kernel_page(page);82nocache_page(page);8384new = PD_PTABLE(page);85PD_MARKBITS(new) = 0xfe;86list_add_tail(new, dp);8788return (pmd_t *)page;89}9091for (tmp = 1, off = 0; (mask & tmp) == 0; tmp <<= 1, off += PTABLE_SIZE)92;93PD_MARKBITS(dp) = mask & ~tmp;94if (!PD_MARKBITS(dp)) {95/* move to end of list */96list_move_tail(dp, &ptable_list);97}98return (pmd_t *) (page_address(PD_PAGE(dp)) + off);99}100101int free_pointer_table (pmd_t *ptable)102{103ptable_desc *dp;104unsigned long page = (unsigned long)ptable & PAGE_MASK;105unsigned char mask = 1 << (((unsigned long)ptable - page)/PTABLE_SIZE);106107dp = PD_PTABLE(page);108if (PD_MARKBITS (dp) & mask)109panic ("table already free!");110111PD_MARKBITS (dp) |= mask;112113if (PD_MARKBITS(dp) == 0xff) {114/* all tables in page are free, free page */115list_del(dp);116cache_page((void *)page);117free_page (page);118return 1;119} else if (ptable_list.next != dp) {120/*121* move this descriptor to the front of the list, since122* it has one or more free tables.123*/124list_move(dp, &ptable_list);125}126return 0;127}128129/* invalidate page in both caches */130static inline void clear040(unsigned long paddr)131{132asm volatile (133"nop\n\t"134".chip 68040\n\t"135"cinvp %%bc,(%0)\n\t"136".chip 68k"137: : "a" (paddr));138}139140/* invalidate page in i-cache */141static inline void cleari040(unsigned long paddr)142{143asm volatile (144"nop\n\t"145".chip 68040\n\t"146"cinvp %%ic,(%0)\n\t"147".chip 68k"148: : "a" (paddr));149}150151/* push page in both caches */152/* RZ: cpush %bc DOES invalidate %ic, regardless of DPI */153static inline void push040(unsigned long paddr)154{155asm volatile (156"nop\n\t"157".chip 68040\n\t"158"cpushp %%bc,(%0)\n\t"159".chip 68k"160: : "a" (paddr));161}162163/* push and invalidate page in both caches, must disable ints164* to avoid invalidating valid data */165static inline void pushcl040(unsigned long paddr)166{167unsigned long flags;168169local_irq_save(flags);170push040(paddr);171if (CPU_IS_060)172clear040(paddr);173local_irq_restore(flags);174}175176/*177* 040: Hit every page containing an address in the range paddr..paddr+len-1.178* (Low order bits of the ea of a CINVP/CPUSHP are "don't care"s).179* Hit every page until there is a page or less to go. Hit the next page,180* and the one after that if the range hits it.181*/182/* ++roman: A little bit more care is required here: The CINVP instruction183* invalidates cache entries WITHOUT WRITING DIRTY DATA BACK! So the beginning184* and the end of the region must be treated differently if they are not185* exactly at the beginning or end of a page boundary. Else, maybe too much186* data becomes invalidated and thus lost forever. CPUSHP does what we need:187* it invalidates the page after pushing dirty data to memory. (Thanks to Jes188* for discovering the problem!)189*/190/* ... but on the '060, CPUSH doesn't invalidate (for us, since we have set191* the DPI bit in the CACR; would it cause problems with temporarily changing192* this?). So we have to push first and then additionally to invalidate.193*/194195196/*197* cache_clear() semantics: Clear any cache entries for the area in question,198* without writing back dirty entries first. This is useful if the data will199* be overwritten anyway, e.g. by DMA to memory. The range is defined by a200* _physical_ address.201*/202203void cache_clear (unsigned long paddr, int len)204{205if (CPU_IS_040_OR_060) {206int tmp;207208/*209* We need special treatment for the first page, in case it210* is not page-aligned. Page align the addresses to work211* around bug I17 in the 68060.212*/213if ((tmp = -paddr & (PAGE_SIZE - 1))) {214pushcl040(paddr & PAGE_MASK);215if ((len -= tmp) <= 0)216return;217paddr += tmp;218}219tmp = PAGE_SIZE;220paddr &= PAGE_MASK;221while ((len -= tmp) >= 0) {222clear040(paddr);223paddr += tmp;224}225if ((len += tmp))226/* a page boundary gets crossed at the end */227pushcl040(paddr);228}229else /* 68030 or 68020 */230asm volatile ("movec %/cacr,%/d0\n\t"231"oriw %0,%/d0\n\t"232"movec %/d0,%/cacr"233: : "i" (FLUSH_I_AND_D)234: "d0");235#ifdef CONFIG_M68K_L2_CACHE236if(mach_l2_flush)237mach_l2_flush(0);238#endif239}240EXPORT_SYMBOL(cache_clear);241242243/*244* cache_push() semantics: Write back any dirty cache data in the given area,245* and invalidate the range in the instruction cache. It needs not (but may)246* invalidate those entries also in the data cache. The range is defined by a247* _physical_ address.248*/249250void cache_push (unsigned long paddr, int len)251{252if (CPU_IS_040_OR_060) {253int tmp = PAGE_SIZE;254255/*256* on 68040 or 68060, push cache lines for pages in the range;257* on the '040 this also invalidates the pushed lines, but not on258* the '060!259*/260len += paddr & (PAGE_SIZE - 1);261262/*263* Work around bug I17 in the 68060 affecting some instruction264* lines not being invalidated properly.265*/266paddr &= PAGE_MASK;267268do {269push040(paddr);270paddr += tmp;271} while ((len -= tmp) > 0);272}273/*274* 68030/68020 have no writeback cache. On the other hand,275* cache_push is actually a superset of cache_clear (the lines276* get written back and invalidated), so we should make sure277* to perform the corresponding actions. After all, this is getting278* called in places where we've just loaded code, or whatever, so279* flushing the icache is appropriate; flushing the dcache shouldn't280* be required.281*/282else /* 68030 or 68020 */283asm volatile ("movec %/cacr,%/d0\n\t"284"oriw %0,%/d0\n\t"285"movec %/d0,%/cacr"286: : "i" (FLUSH_I)287: "d0");288#ifdef CONFIG_M68K_L2_CACHE289if(mach_l2_flush)290mach_l2_flush(1);291#endif292}293EXPORT_SYMBOL(cache_push);294295296297