Path: blob/master/arch/powerpc/platforms/iseries/htab.c
10820 views
/*1* iSeries hashtable management.2* Derived from pSeries_htab.c3*4* SMP scalability work:5* Copyright (C) 2001 Anton Blanchard <[email protected]>, IBM6*7* This program is free software; you can redistribute it and/or8* modify it under the terms of the GNU General Public License9* as published by the Free Software Foundation; either version10* 2 of the License, or (at your option) any later version.11*/12#include <asm/machdep.h>13#include <asm/pgtable.h>14#include <asm/mmu.h>15#include <asm/mmu_context.h>16#include <asm/abs_addr.h>17#include <linux/spinlock.h>1819#include "call_hpt.h"2021static spinlock_t iSeries_hlocks[64] __cacheline_aligned_in_smp;2223/*24* Very primitive algorithm for picking up a lock25*/26static inline void iSeries_hlock(unsigned long slot)27{28if (slot & 0x8)29slot = ~slot;30spin_lock(&iSeries_hlocks[(slot >> 4) & 0x3f]);31}3233static inline void iSeries_hunlock(unsigned long slot)34{35if (slot & 0x8)36slot = ~slot;37spin_unlock(&iSeries_hlocks[(slot >> 4) & 0x3f]);38}3940static long iSeries_hpte_insert(unsigned long hpte_group, unsigned long va,41unsigned long pa, unsigned long rflags,42unsigned long vflags, int psize, int ssize)43{44long slot;45struct hash_pte lhpte;46int secondary = 0;4748BUG_ON(psize != MMU_PAGE_4K);4950/*51* The hypervisor tries both primary and secondary.52* If we are being called to insert in the secondary,53* it means we have already tried both primary and secondary,54* so we return failure immediately.55*/56if (vflags & HPTE_V_SECONDARY)57return -1;5859iSeries_hlock(hpte_group);6061slot = HvCallHpt_findValid(&lhpte, va >> HW_PAGE_SHIFT);62if (unlikely(lhpte.v & HPTE_V_VALID)) {63if (vflags & HPTE_V_BOLTED) {64HvCallHpt_setSwBits(slot, 0x10, 0);65HvCallHpt_setPp(slot, PP_RWXX);66iSeries_hunlock(hpte_group);67if (slot < 0)68return 0x8 | (slot & 7);69else70return slot & 7;71}72BUG();73}7475if (slot == -1) { /* No available entry found in either group */76iSeries_hunlock(hpte_group);77return -1;78}7980if (slot < 0) { /* MSB set means secondary group */81vflags |= HPTE_V_SECONDARY;82secondary = 1;83slot &= 0x7fffffffffffffff;84}858687lhpte.v = hpte_encode_v(va, MMU_PAGE_4K, MMU_SEGSIZE_256M) |88vflags | HPTE_V_VALID;89lhpte.r = hpte_encode_r(phys_to_abs(pa), MMU_PAGE_4K) | rflags;9091/* Now fill in the actual HPTE */92HvCallHpt_addValidate(slot, secondary, &lhpte);9394iSeries_hunlock(hpte_group);9596return (secondary << 3) | (slot & 7);97}9899static unsigned long iSeries_hpte_getword0(unsigned long slot)100{101struct hash_pte hpte;102103HvCallHpt_get(&hpte, slot);104return hpte.v;105}106107static long iSeries_hpte_remove(unsigned long hpte_group)108{109unsigned long slot_offset;110int i;111unsigned long hpte_v;112113/* Pick a random slot to start at */114slot_offset = mftb() & 0x7;115116iSeries_hlock(hpte_group);117118for (i = 0; i < HPTES_PER_GROUP; i++) {119hpte_v = iSeries_hpte_getword0(hpte_group + slot_offset);120121if (! (hpte_v & HPTE_V_BOLTED)) {122HvCallHpt_invalidateSetSwBitsGet(hpte_group +123slot_offset, 0, 0);124iSeries_hunlock(hpte_group);125return i;126}127128slot_offset++;129slot_offset &= 0x7;130}131132iSeries_hunlock(hpte_group);133134return -1;135}136137/*138* The HyperVisor expects the "flags" argument in this form:139* bits 0..59 : reserved140* bit 60 : N141* bits 61..63 : PP2,PP1,PP0142*/143static long iSeries_hpte_updatepp(unsigned long slot, unsigned long newpp,144unsigned long va, int psize, int ssize, int local)145{146struct hash_pte hpte;147unsigned long want_v;148149iSeries_hlock(slot);150151HvCallHpt_get(&hpte, slot);152want_v = hpte_encode_v(va, MMU_PAGE_4K, MMU_SEGSIZE_256M);153154if (HPTE_V_COMPARE(hpte.v, want_v) && (hpte.v & HPTE_V_VALID)) {155/*156* Hypervisor expects bits as NPPP, which is157* different from how they are mapped in our PP.158*/159HvCallHpt_setPp(slot, (newpp & 0x3) | ((newpp & 0x4) << 1));160iSeries_hunlock(slot);161return 0;162}163iSeries_hunlock(slot);164165return -1;166}167168/*169* Functions used to find the PTE for a particular virtual address.170* Only used during boot when bolting pages.171*172* Input : vpn : virtual page number173* Output: PTE index within the page table of the entry174* -1 on failure175*/176static long iSeries_hpte_find(unsigned long vpn)177{178struct hash_pte hpte;179long slot;180181/*182* The HvCallHpt_findValid interface is as follows:183* 0xffffffffffffffff : No entry found.184* 0x00000000xxxxxxxx : Entry found in primary group, slot x185* 0x80000000xxxxxxxx : Entry found in secondary group, slot x186*/187slot = HvCallHpt_findValid(&hpte, vpn);188if (hpte.v & HPTE_V_VALID) {189if (slot < 0) {190slot &= 0x7fffffffffffffff;191slot = -slot;192}193} else194slot = -1;195return slot;196}197198/*199* Update the page protection bits. Intended to be used to create200* guard pages for kernel data structures on pages which are bolted201* in the HPT. Assumes pages being operated on will not be stolen.202* Does not work on large pages.203*204* No need to lock here because we should be the only user.205*/206static void iSeries_hpte_updateboltedpp(unsigned long newpp, unsigned long ea,207int psize, int ssize)208{209unsigned long vsid,va,vpn;210long slot;211212BUG_ON(psize != MMU_PAGE_4K);213214vsid = get_kernel_vsid(ea, MMU_SEGSIZE_256M);215va = (vsid << 28) | (ea & 0x0fffffff);216vpn = va >> HW_PAGE_SHIFT;217slot = iSeries_hpte_find(vpn);218if (slot == -1)219panic("updateboltedpp: Could not find page to bolt\n");220HvCallHpt_setPp(slot, newpp);221}222223static void iSeries_hpte_invalidate(unsigned long slot, unsigned long va,224int psize, int ssize, int local)225{226unsigned long hpte_v;227unsigned long avpn = va >> 23;228unsigned long flags;229230local_irq_save(flags);231232iSeries_hlock(slot);233234hpte_v = iSeries_hpte_getword0(slot);235236if ((HPTE_V_AVPN_VAL(hpte_v) == avpn) && (hpte_v & HPTE_V_VALID))237HvCallHpt_invalidateSetSwBitsGet(slot, 0, 0);238239iSeries_hunlock(slot);240241local_irq_restore(flags);242}243244void __init hpte_init_iSeries(void)245{246int i;247248for (i = 0; i < ARRAY_SIZE(iSeries_hlocks); i++)249spin_lock_init(&iSeries_hlocks[i]);250251ppc_md.hpte_invalidate = iSeries_hpte_invalidate;252ppc_md.hpte_updatepp = iSeries_hpte_updatepp;253ppc_md.hpte_updateboltedpp = iSeries_hpte_updateboltedpp;254ppc_md.hpte_insert = iSeries_hpte_insert;255ppc_md.hpte_remove = iSeries_hpte_remove;256}257258259