Path: blob/master/arch/mn10300/mm/cache-inv-by-reg.S
10817 views
/* MN10300 CPU cache invalidation routines, using automatic purge registers1*2* Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.3* Written by David Howells ([email protected])4*5* This program is free software; you can redistribute it and/or6* modify it under the terms of the GNU General Public Licence7* as published by the Free Software Foundation; either version8* 2 of the Licence, or (at your option) any later version.9*/10#include <linux/sys.h>11#include <linux/linkage.h>12#include <asm/smp.h>13#include <asm/page.h>14#include <asm/cache.h>15#include <asm/irqflags.h>16#include <asm/cacheflush.h>17#include "cache.inc"1819#define mn10300_local_dcache_inv_range_intr_interval \20+((1 << MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL) - 1)2122#if mn10300_local_dcache_inv_range_intr_interval > 0xff23#error MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL must be 8 or less24#endif2526.am33_22728#ifndef CONFIG_SMP29.globl mn10300_icache_inv30.globl mn10300_icache_inv_page31.globl mn10300_icache_inv_range32.globl mn10300_icache_inv_range233.globl mn10300_dcache_inv34.globl mn10300_dcache_inv_page35.globl mn10300_dcache_inv_range36.globl mn10300_dcache_inv_range23738mn10300_icache_inv = mn10300_local_icache_inv39mn10300_icache_inv_page = mn10300_local_icache_inv_page40mn10300_icache_inv_range = mn10300_local_icache_inv_range41mn10300_icache_inv_range2 = mn10300_local_icache_inv_range242mn10300_dcache_inv = mn10300_local_dcache_inv43mn10300_dcache_inv_page = mn10300_local_dcache_inv_page44mn10300_dcache_inv_range = mn10300_local_dcache_inv_range45mn10300_dcache_inv_range2 = mn10300_local_dcache_inv_range24647#endif /* !CONFIG_SMP */4849###############################################################################50#51# void mn10300_local_icache_inv(void)52# Invalidate the entire icache53#54###############################################################################55ALIGN56.globl mn10300_local_icache_inv57.type mn10300_local_icache_inv,@function58mn10300_local_icache_inv:59mov CHCTR,a06061movhu (a0),d062btst CHCTR_ICEN,d063beq mn10300_local_icache_inv_end6465invalidate_icache 16667mn10300_local_icache_inv_end:68ret [],069.size mn10300_local_icache_inv,.-mn10300_local_icache_inv7071###############################################################################72#73# void mn10300_local_dcache_inv(void)74# Invalidate the entire dcache75#76###############################################################################77ALIGN78.globl mn10300_local_dcache_inv79.type mn10300_local_dcache_inv,@function80mn10300_local_dcache_inv:81mov CHCTR,a08283movhu (a0),d084btst CHCTR_DCEN,d085beq mn10300_local_dcache_inv_end8687invalidate_dcache 18889mn10300_local_dcache_inv_end:90ret [],091.size mn10300_local_dcache_inv,.-mn10300_local_dcache_inv9293###############################################################################94#95# void mn10300_local_dcache_inv_range(unsigned long start, unsigned long end)96# void mn10300_local_dcache_inv_range2(unsigned long start, unsigned long size)97# void mn10300_local_dcache_inv_page(unsigned long start)98# Invalidate a range of addresses on a page in the dcache99#100###############################################################################101ALIGN102.globl mn10300_local_dcache_inv_page103.globl mn10300_local_dcache_inv_range104.globl mn10300_local_dcache_inv_range2105.type mn10300_local_dcache_inv_page,@function106.type mn10300_local_dcache_inv_range,@function107.type mn10300_local_dcache_inv_range2,@function108mn10300_local_dcache_inv_page:109and ~(PAGE_SIZE-1),d0110mov PAGE_SIZE,d1111mn10300_local_dcache_inv_range2:112add d0,d1113mn10300_local_dcache_inv_range:114# If we are in writeback mode we check the start and end alignments,115# and if they're not cacheline-aligned, we must flush any bits outside116# the range that share cachelines with stuff inside the range117#ifdef CONFIG_MN10300_CACHE_WBACK118btst ~L1_CACHE_TAG_MASK,d0119bne 1f120btst ~L1_CACHE_TAG_MASK,d1121beq 2f1221:123bra mn10300_local_dcache_flush_inv_range1242:125#endif /* CONFIG_MN10300_CACHE_WBACK */126127movm [d2,d3,a2],(sp)128129mov CHCTR,a0130movhu (a0),d2131btst CHCTR_DCEN,d2132beq mn10300_local_dcache_inv_range_end133134# round the addresses out to be full cachelines, unless we're in135# writeback mode, in which case we would be in flush and invalidate by136# now137#ifndef CONFIG_MN10300_CACHE_WBACK138and L1_CACHE_TAG_MASK,d0 # round start addr down139140mov L1_CACHE_BYTES-1,d2141add d2,d1142and L1_CACHE_TAG_MASK,d1 # round end addr up143#endif /* !CONFIG_MN10300_CACHE_WBACK */144145sub d0,d1,d2 # calculate the total size146mov d0,a2 # A2 = start address147mov d1,a1 # A1 = end address148149LOCAL_CLI_SAVE(d3)150151mov DCPGCR,a0 # make sure the purger isn't busy152setlb153mov (a0),d0154btst DCPGCR_DCPGBSY,d0155lne156157# skip initial address alignment calculation if address is zero158mov d2,d1159cmp 0,a2160beq 1f161162dcivloop:163/* calculate alignsize164*165* alignsize = L1_CACHE_BYTES;166* while (! start & alignsize) {167* alignsize <<=1;168* }169* d1 = alignsize;170*/171mov L1_CACHE_BYTES,d1172lsr 1,d1173setlb174add d1,d1175mov d1,d0176and a2,d0177leq1781791:180/* calculate invsize181*182* if (totalsize > alignsize) {183* invsize = alignsize;184* } else {185* invsize = totalsize;186* tmp = 0x80000000;187* while (! invsize & tmp) {188* tmp >>= 1;189* }190* invsize = tmp;191* }192* d1 = invsize193*/194cmp d2,d1195bns 2f196mov d2,d1197198mov 0x80000000,d0 # start from 31bit=1199setlb200lsr 1,d0201mov d0,e0202and d1,e0203leq204mov d0,d12052062:207/* set mask208*209* mask = ~(invsize-1);210* DCPGMR = mask;211*/212mov d1,d0213add -1,d0214not d0215mov d0,(DCPGMR)216217# invalidate area218mov a2,d0219or DCPGCR_DCI,d0220mov d0,(a0) # DCPGCR = (mask & start) | DCPGCR_DCI221222setlb # wait for the purge to complete223mov (a0),d0224btst DCPGCR_DCPGBSY,d0225lne226227sub d1,d2 # decrease size remaining228add d1,a2 # increase next start address229230/* check invalidating of end address231*232* a2 = a2 + invsize233* if (a2 < end) {234* goto dcivloop;235* } */236cmp a1,a2237bns dcivloop238239LOCAL_IRQ_RESTORE(d3)240241mn10300_local_dcache_inv_range_end:242ret [d2,d3,a2],12243.size mn10300_local_dcache_inv_page,.-mn10300_local_dcache_inv_page244.size mn10300_local_dcache_inv_range,.-mn10300_local_dcache_inv_range245.size mn10300_local_dcache_inv_range2,.-mn10300_local_dcache_inv_range2246247###############################################################################248#249# void mn10300_local_icache_inv_page(unsigned long start)250# void mn10300_local_icache_inv_range2(unsigned long start, unsigned long size)251# void mn10300_local_icache_inv_range(unsigned long start, unsigned long end)252# Invalidate a range of addresses on a page in the icache253#254###############################################################################255ALIGN256.globl mn10300_local_icache_inv_page257.globl mn10300_local_icache_inv_range258.globl mn10300_local_icache_inv_range2259.type mn10300_local_icache_inv_page,@function260.type mn10300_local_icache_inv_range,@function261.type mn10300_local_icache_inv_range2,@function262mn10300_local_icache_inv_page:263and ~(PAGE_SIZE-1),d0264mov PAGE_SIZE,d1265mn10300_local_icache_inv_range2:266add d0,d1267mn10300_local_icache_inv_range:268movm [d2,d3,a2],(sp)269270mov CHCTR,a0271movhu (a0),d2272btst CHCTR_ICEN,d2273beq mn10300_local_icache_inv_range_reg_end274275/* calculate alignsize276*277* alignsize = L1_CACHE_BYTES;278* for (i = (end - start - 1) / L1_CACHE_BYTES ; i > 0; i >>= 1) {279* alignsize <<= 1;280* }281* d2 = alignsize;282*/283mov L1_CACHE_BYTES,d2284sub d0,d1,d3285add -1,d3286lsr L1_CACHE_SHIFT,d3287beq 2f2881:289add d2,d2290lsr 1,d3291bne 1b2922:293294/* a1 = end */295mov d1,a1296297LOCAL_CLI_SAVE(d3)298299mov ICIVCR,a0300/* wait for busy bit of area invalidation */301setlb302mov (a0),d1303btst ICIVCR_ICIVBSY,d1304lne305306/* set mask307*308* mask = ~(alignsize-1);309* ICIVMR = mask;310*/311mov d2,d1312add -1,d1313not d1314mov d1,(ICIVMR)315/* a2 = mask & start */316and d1,d0,a2317318icivloop:319/* area invalidate320*321* ICIVCR = (mask & start) | ICIVCR_ICI322*/323mov a2,d0324or ICIVCR_ICI,d0325mov d0,(a0)326327/* wait for busy bit of area invalidation */328setlb329mov (a0),d1330btst ICIVCR_ICIVBSY,d1331lne332333/* check invalidating of end address334*335* a2 = a2 + alignsize336* if (a2 < end) {337* goto icivloop;338* } */339add d2,a2340cmp a1,a2341bns icivloop342343LOCAL_IRQ_RESTORE(d3)344345mn10300_local_icache_inv_range_reg_end:346ret [d2,d3,a2],12347.size mn10300_local_icache_inv_page,.-mn10300_local_icache_inv_page348.size mn10300_local_icache_inv_range,.-mn10300_local_icache_inv_range349.size mn10300_local_icache_inv_range2,.-mn10300_local_icache_inv_range2350351352