Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 93842
b: refs/heads/master
c: 5b7baf0
h: refs/heads/master
v: v3
  • Loading branch information
Christian Borntraeger authored and Avi Kivity committed Apr 27, 2008
1 parent b8544e1 commit a228c55
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 7 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 402b08622d9ac6e32e25289573272e0f21bb58a7
refs/heads/master: 5b7baf05783b1ac97a510243d7e82293416a7cf6
92 changes: 89 additions & 3 deletions trunk/include/asm-s390/pgtable.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
*/
#ifndef __ASSEMBLY__
#include <linux/mm_types.h>
#include <asm/bitops.h>
#include <asm/bug.h>
#include <asm/processor.h>

Expand Down Expand Up @@ -258,6 +259,13 @@ extern char empty_zero_page[PAGE_SIZE];
* swap pte is 1011 and 0001, 0011, 0101, 0111 are invalid.
*/

/* Page status table bits for virtualization */
#define RCP_PCL_BIT 55
#define RCP_HR_BIT 54
#define RCP_HC_BIT 53
#define RCP_GR_BIT 50
#define RCP_GC_BIT 49

#ifndef __s390x__

/* Bits in the segment table address-space-control-element */
Expand Down Expand Up @@ -513,6 +521,48 @@ static inline int pte_file(pte_t pte)
#define __HAVE_ARCH_PTE_SAME
#define pte_same(a,b) (pte_val(a) == pte_val(b))

static inline void rcp_lock(pte_t *ptep)
{
#ifdef CONFIG_PGSTE
unsigned long *pgste = (unsigned long *) (ptep + PTRS_PER_PTE);
preempt_disable();
while (test_and_set_bit(RCP_PCL_BIT, pgste))
;
#endif
}

static inline void rcp_unlock(pte_t *ptep)
{
#ifdef CONFIG_PGSTE
unsigned long *pgste = (unsigned long *) (ptep + PTRS_PER_PTE);
clear_bit(RCP_PCL_BIT, pgste);
preempt_enable();
#endif
}

/* forward declaration for SetPageUptodate in page-flags.h*/
static inline void page_clear_dirty(struct page *page);
#include <linux/page-flags.h>

static inline void ptep_rcp_copy(pte_t *ptep)
{
#ifdef CONFIG_PGSTE
struct page *page = virt_to_page(pte_val(*ptep));
unsigned int skey;
unsigned long *pgste = (unsigned long *) (ptep + PTRS_PER_PTE);

skey = page_get_storage_key(page_to_phys(page));
if (skey & _PAGE_CHANGED)
set_bit(RCP_GC_BIT, pgste);
if (skey & _PAGE_REFERENCED)
set_bit(RCP_GR_BIT, pgste);
if (test_and_clear_bit(RCP_HC_BIT, pgste))
SetPageDirty(page);
if (test_and_clear_bit(RCP_HR_BIT, pgste))
SetPageReferenced(page);
#endif
}

/*
* query functions pte_write/pte_dirty/pte_young only work if
* pte_present() is true. Undefined behaviour if not..
Expand Down Expand Up @@ -599,6 +649,8 @@ static inline void pmd_clear(pmd_t *pmd)

static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
{
if (mm->context.pgstes)
ptep_rcp_copy(ptep);
pte_val(*ptep) = _PAGE_TYPE_EMPTY;
if (mm->context.noexec)
pte_val(ptep[PTRS_PER_PTE]) = _PAGE_TYPE_EMPTY;
Expand Down Expand Up @@ -667,14 +719,38 @@ static inline pte_t pte_mkyoung(pte_t pte)
static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
unsigned long addr, pte_t *ptep)
{
#ifdef CONFIG_PGSTE
unsigned long physpage;
int young;
unsigned long *pgste;

if (!vma->vm_mm->context.pgstes)
return 0;
physpage = pte_val(*ptep) & PAGE_MASK;
pgste = (unsigned long *) (ptep + PTRS_PER_PTE);

young = ((page_get_storage_key(physpage) & _PAGE_REFERENCED) != 0);
rcp_lock(ptep);
if (young)
set_bit(RCP_GR_BIT, pgste);
young |= test_and_clear_bit(RCP_HR_BIT, pgste);
rcp_unlock(ptep);
return young;
#endif
return 0;
}

#define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
unsigned long address, pte_t *ptep)
{
/* No need to flush TLB; bits are in storage key */
/* No need to flush TLB
* On s390 reference bits are in storage key and never in TLB
* With virtualization we handle the reference bit, without we
* we can simply return */
#ifdef CONFIG_PGSTE
return ptep_test_and_clear_young(vma, address, ptep);
#endif
return 0;
}

Expand All @@ -693,15 +769,25 @@ static inline void __ptep_ipte(unsigned long address, pte_t *ptep)
: "=m" (*ptep) : "m" (*ptep),
"a" (pto), "a" (address));
}
pte_val(*ptep) = _PAGE_TYPE_EMPTY;
}

static inline void ptep_invalidate(struct mm_struct *mm,
unsigned long address, pte_t *ptep)
{
if (mm->context.pgstes) {
rcp_lock(ptep);
__ptep_ipte(address, ptep);
ptep_rcp_copy(ptep);
pte_val(*ptep) = _PAGE_TYPE_EMPTY;
rcp_unlock(ptep);
return;
}
__ptep_ipte(address, ptep);
if (mm->context.noexec)
pte_val(*ptep) = _PAGE_TYPE_EMPTY;
if (mm->context.noexec) {
__ptep_ipte(address, ptep + PTRS_PER_PTE);
pte_val(*(ptep + PTRS_PER_PTE)) = _PAGE_TYPE_EMPTY;
}
}

/*
Expand Down
7 changes: 4 additions & 3 deletions trunk/mm/rmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -413,9 +413,6 @@ int page_referenced(struct page *page, int is_locked,
{
int referenced = 0;

if (page_test_and_clear_young(page))
referenced++;

if (TestClearPageReferenced(page))
referenced++;

Expand All @@ -433,6 +430,10 @@ int page_referenced(struct page *page, int is_locked,
unlock_page(page);
}
}

if (page_test_and_clear_young(page))
referenced++;

return referenced;
}

Expand Down

0 comments on commit a228c55

Please sign in to comment.