X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fppc64%2Fkernel%2FiSeries_htab.c;h=b1177b476cbdb8607fab84b324e36389f798963d;hb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;hp=05e41ee263c2d9e0fd87dcbc48286d6c384f026b;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/arch/ppc64/kernel/iSeries_htab.c b/arch/ppc64/kernel/iSeries_htab.c index 05e41ee26..b1177b476 100644 --- a/arch/ppc64/kernel/iSeries_htab.c +++ b/arch/ppc64/kernel/iSeries_htab.c @@ -16,17 +16,26 @@ #include #include #include - -#if 0 #include -#include -#include -#include -#include -#include -#include -#endif +static spinlock_t iSeries_hlocks[64] __cacheline_aligned_in_smp = { [0 ... 63] = SPIN_LOCK_UNLOCKED}; + +/* + * Very primitive algorithm for picking up a lock + */ +static inline void iSeries_hlock(unsigned long slot) +{ + if (slot & 0x8) + slot = ~slot; + spin_lock(&iSeries_hlocks[(slot >> 4) & 0x3f]); +} + +static inline void iSeries_hunlock(unsigned long slot) +{ + if (slot & 0x8) + slot = ~slot; + spin_unlock(&iSeries_hlocks[(slot >> 4) & 0x3f]); +} static long iSeries_hpte_insert(unsigned long hpte_group, unsigned long va, unsigned long prpn, int secondary, @@ -44,12 +53,15 @@ static long iSeries_hpte_insert(unsigned long hpte_group, unsigned long va, if (secondary) return -1; + iSeries_hlock(hpte_group); + slot = HvCallHpt_findValid(&lhpte, va >> PAGE_SHIFT); - if (lhpte.dw0.dw0.v) - panic("select_hpte_slot found entry already valid\n"); + BUG_ON(lhpte.dw0.dw0.v); - if (slot == -1) /* No available entry found in either group */ + if (slot == -1) { /* No available entry found in either group */ + iSeries_hunlock(hpte_group); return -1; + } if (slot < 0) { /* MSB set means secondary group */ secondary = 1; @@ -69,6 +81,8 @@ static long iSeries_hpte_insert(unsigned long hpte_group, unsigned long va, /* Now fill in the actual HPTE */ HvCallHpt_addValidate(slot, secondary, &lhpte); + iSeries_hunlock(hpte_group); + return (secondary << 3) | (slot & 7); } @@ -92,6 +106,8 @@ static long iSeries_hpte_remove(unsigned long hpte_group) /* Pick a random slot to start at */ slot_offset = mftb() & 0x7; + iSeries_hlock(hpte_group); + for (i = 0; i < HPTES_PER_GROUP; i++) { lhpte.dw0.dword0 = iSeries_hpte_getword0(hpte_group + slot_offset); @@ -99,6 +115,7 @@ static long iSeries_hpte_remove(unsigned long hpte_group) if (!lhpte.dw0.dw0.bolted) { HvCallHpt_invalidateSetSwBitsGet(hpte_group + slot_offset, 0, 0); + iSeries_hunlock(hpte_group); return i; } @@ -106,6 +123,8 @@ static long iSeries_hpte_remove(unsigned long hpte_group) slot_offset &= 0x7; } + iSeries_hunlock(hpte_group); + return -1; } @@ -121,11 +140,16 @@ static long iSeries_hpte_updatepp(unsigned long slot, unsigned long newpp, HPTE hpte; unsigned long avpn = va >> 23; + iSeries_hlock(slot); + HvCallHpt_get(&hpte, slot); if ((hpte.dw0.dw0.avpn == avpn) && (hpte.dw0.dw0.v)) { HvCallHpt_setPp(slot, (newpp & 0x3) | ((newpp & 0x4) << 1)); + iSeries_hunlock(slot); return 0; } + iSeries_hunlock(slot); + return -1; } @@ -186,11 +210,20 @@ static void iSeries_hpte_invalidate(unsigned long slot, unsigned long va, { HPTE lhpte; unsigned long avpn = va >> 23; + unsigned long flags; + + local_irq_save(flags); + + iSeries_hlock(slot); lhpte.dw0.dword0 = iSeries_hpte_getword0(slot); if ((lhpte.dw0.dw0.avpn == avpn) && lhpte.dw0.dw0.v) HvCallHpt_invalidateSetSwBitsGet(slot, 0, 0); + + iSeries_hunlock(slot); + + local_irq_restore(flags); } void hpte_init_iSeries(void) @@ -200,4 +233,6 @@ void hpte_init_iSeries(void) ppc_md.hpte_updateboltedpp = iSeries_hpte_updateboltedpp; ppc_md.hpte_insert = iSeries_hpte_insert; ppc_md.hpte_remove = iSeries_hpte_remove; + + htab_finish_init(); }