Add generic primitives for clear_user_pages_incoherent() and clear_page_make_coherent(). To ensure that callers don't mix accesses to different types of address_spaces, annotate clear_user_pages_incoherent() as taking an __incoherent pointer as argument. Also add clear_user_highpages_incoherent() which either calls clear_user_pages_incoherent() or falls back to clear_user_highpages() Signed-off-by: Ankur Arora <ankur.a.arora@xxxxxxxxxx> --- Notes: clear_user_highpages_incoherent() operates on an __incoherent region and expects the caller to call clear_page_make_coherent(). It should, however be taking an __incoherent * as argument -- this it does not do because I couldn't see a clean way of doing that with highmem. Suggestions? include/asm-generic/clear_page.h | 21 +++++++++++++++++++++ include/linux/highmem.h | 23 +++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/include/asm-generic/clear_page.h b/include/asm-generic/clear_page.h index f827d661519c..0ebff70a60a9 100644 --- a/include/asm-generic/clear_page.h +++ b/include/asm-generic/clear_page.h @@ -16,6 +16,9 @@ #if defined(CONFIG_HIGHMEM) && defined(__HAVE_ARCH_CLEAR_USER_PAGES) #error CONFIG_HIGHMEM is incompatible with __HAVE_ARCH_CLEAR_USER_PAGES #endif +#if defined(CONFIG_HIGHMEM) && defined(__HAVE_ARCH_CLEAR_USER_PAGES_INCOHERENT) +#error CONFIG_HIGHMEM is incompatible with __HAVE_ARCH_CLEAR_USER_PAGES_INCOHERENT +#endif #ifndef __HAVE_ARCH_CLEAR_USER_PAGES @@ -41,4 +44,22 @@ static inline void clear_user_pages(void *page, unsigned long vaddr, #define ARCH_MAX_CLEAR_PAGES (1 << ARCH_MAX_CLEAR_PAGES_ORDER) +#ifndef __HAVE_ARCH_CLEAR_USER_PAGES_INCOHERENT +#ifndef __ASSEMBLY__ +/* + * Fallback path (via clear_user_pages()) if the architecture does not + * support incoherent clearing. + */ +static inline void clear_user_pages_incoherent(__incoherent void *page, + unsigned long vaddr, + struct page *pg, + unsigned int npages) +{ + clear_user_pages((__force void *)page, vaddr, pg, npages); +} + +static inline void clear_page_make_coherent(void) { } +#endif /* __ASSEMBLY__ */ +#endif /* __HAVE_ARCH_CLEAR_USER_PAGES_INCOHERENT */ + #endif /* __ASM_GENERIC_CLEAR_PAGE_H */ diff --git a/include/linux/highmem.h b/include/linux/highmem.h index 08781d7693e7..90179f623c3b 100644 --- a/include/linux/highmem.h +++ b/include/linux/highmem.h @@ -231,6 +231,29 @@ static inline void clear_user_highpages(struct page *page, unsigned long vaddr, } #endif /* __HAVE_ARCH_CLEAR_USER_PAGES */ +#ifdef __HAVE_ARCH_CLEAR_USER_PAGES_INCOHERENT +static inline void clear_user_highpages_incoherent(struct page *page, + unsigned long vaddr, + unsigned int npages) +{ + __incoherent void *addr = (__incoherent void *) page_address(page); + + clear_user_pages_incoherent(addr, vaddr, page, npages); +} +#else +static inline void clear_user_highpages_incoherent(struct page *page, + unsigned long vaddr, + unsigned int npages) +{ + /* + * We fallback to clear_user_highpages() for the CONFIG_HIGHMEM + * configs. + * For !CONFIG_HIGHMEM, this will get translated to clear_user_pages(). + */ + clear_user_highpages(page, vaddr, npages); +} +#endif /* __HAVE_ARCH_CLEAR_USER_PAGES_INCOHERENT */ + #ifndef __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE_MOVABLE /** * alloc_zeroed_user_highpage_movable - Allocate a zeroed HIGHMEM page for a VMA that the caller knows can move -- 2.31.1