Subject: [PATCH 2/7] Add various hugetlb page table fix

From: [email-masked] (bill4carson)
Date: Tue, 07 Feb 2012 09:42:01 +0800

On 2012?02?07? 00:26, Catalin Marinas wrote:
> On Wed, Feb 01, 2012 at 03:10:21AM +0000, bill4carson wrote:
>> Why L_PTE_HUGEPAGE is needed?
>>
>> hugetlb subsystem will call pte_page to derive the corresponding page
>> struct from a given pte, and pte_pfn is used first to convert pte into
>> a page frame number.
>
> Are you sure the pte_pfn() conversion is right? Does it need to be
> different from the 4K pfn?

Hello, Catalin

Let me take a few words to make this clear for us.

pte_page is defined as following to derive page struct from a given pte.
This macro is used both in generic mm as well as hugetlb sub-system, so
we need do the switch in pte_pfn to mark huge page based linux pte out
of normal page based linux pte, that's what L_PTE_HUGEPAGE for.

#define pte_page(pte)		pfn_to_page(pte_pfn(pte))

So L_PTE_HUGEPAGE is *NOT* set in normal page based linux pte,
linux pte bits[31:12] is the page frame number;
otherwise, we got a huge page based linux pte, and linux pte
bits[31:20] is page frame number for SECTION mapping, and bits[31:24]
is page frame number for SUPER-SECTION mapping.

I think this the full story of following code:

#ifdef CONFIG_ARM_HUGETLB_SUPPORT

#ifdef CONFIG_HUGEPAGE_SIZE_2MB
#define hugepte_pfn(pte)    ((pte_val(pte) & SECTION_MASK) >> PAGE_SHIFT)
#endif
#ifdef CONFIG_HUGEPAGE_SIZE_16MB
#define hugepte_pfn(pte)    ((pte_val(pte) & SUPERSECTION_MASK) >> 
PAGE_SHIFT)
#endif
#define pte_is_huge(pte)	(pte_val(pte) & L_PTE_HUGEPAGE)
#define pte_pfn(pte)	    (pte_is_huge(pte) ? \
				hugepte_pfn(pte) : ((pte_val(pte) & PHYS_MASK) >> PAGE_SHIFT))
#else
#define pte_pfn(pte)		((pte_val(pte) & PHYS_MASK) >> PAGE_SHIFT)
#endif /*!CONFIG_ARM_HUGETLB_SUPPORT*/

#define pte_page(pte)		pfn_to_page(pte_pfn(pte))

> I haven't seen any other architecture doing
> shifts other than PAGE_SHIFT even for huge pages.
>

#define L_PTE_HUGEPAGE	(_AT(pteval_t, 1) << 11) /* mark hugepage */
#define L_PTE_HPAGE_2M  (_AT(pteval_t, 1) << 12) /* only when HUGEPAGE 
set */
#define L_PTE_HPAGE_16M (_AT(pteval_t, 1) << 13) /* only when HUGEPAGE 
set */

See linux pte BIT12 is used to denote 2MB huge page, BIT13 is used for
16MB page, that's why PAGE_SHIFT is not enough for do the shifting.

I hope I understand your question and give the right answer :)

-- 
I am a slow learner
but I will keep trying to fight for my dreams!

--bill