@@ -111,6 +111,51 @@ static pud_t level3_user_vsyscall[PTRS_PER_PUD] __page_aligned_bss;
111111 */
112112static DEFINE_SPINLOCK (xen_reservation_lock );
113113
114+ /* Protected by xen_reservation_lock. */
115+ #define MIN_CONTIG_ORDER 9 /* 2MB */
116+ static unsigned int discontig_frames_order = MIN_CONTIG_ORDER ;
117+ static unsigned long discontig_frames_early [1UL << MIN_CONTIG_ORDER ] __initdata ;
118+ static unsigned long * discontig_frames __refdata = discontig_frames_early ;
119+ static bool discontig_frames_dyn ;
120+
121+ static int alloc_discontig_frames (unsigned int order )
122+ {
123+ unsigned long * new_array , * old_array ;
124+ unsigned int old_order ;
125+ unsigned long flags ;
126+
127+ BUG_ON (order < MIN_CONTIG_ORDER );
128+ BUILD_BUG_ON (sizeof (discontig_frames_early ) != PAGE_SIZE );
129+
130+ new_array = (unsigned long * )__get_free_pages (GFP_KERNEL ,
131+ order - MIN_CONTIG_ORDER );
132+ if (!new_array )
133+ return - ENOMEM ;
134+
135+ spin_lock_irqsave (& xen_reservation_lock , flags );
136+
137+ old_order = discontig_frames_order ;
138+
139+ if (order > discontig_frames_order || !discontig_frames_dyn ) {
140+ if (!discontig_frames_dyn )
141+ old_array = NULL ;
142+ else
143+ old_array = discontig_frames ;
144+
145+ discontig_frames = new_array ;
146+ discontig_frames_order = order ;
147+ discontig_frames_dyn = true;
148+ } else {
149+ old_array = new_array ;
150+ }
151+
152+ spin_unlock_irqrestore (& xen_reservation_lock , flags );
153+
154+ free_pages ((unsigned long )old_array , old_order - MIN_CONTIG_ORDER );
155+
156+ return 0 ;
157+ }
158+
114159/*
115160 * Note about cr3 (pagetable base) values:
116161 *
@@ -814,6 +859,9 @@ static void __init xen_after_bootmem(void)
814859 SetPagePinned (virt_to_page (level3_user_vsyscall ));
815860#endif
816861 xen_pgd_walk (& init_mm , xen_mark_pinned , FIXADDR_TOP );
862+
863+ if (alloc_discontig_frames (MIN_CONTIG_ORDER ))
864+ BUG ();
817865}
818866
819867static void xen_unpin_page (struct mm_struct * mm , struct page * page ,
@@ -2203,10 +2251,6 @@ void __init xen_init_mmu_ops(void)
22032251 memset (dummy_mapping , 0xff , PAGE_SIZE );
22042252}
22052253
2206- /* Protected by xen_reservation_lock. */
2207- #define MAX_CONTIG_ORDER 9 /* 2MB */
2208- static unsigned long discontig_frames [1 <<MAX_CONTIG_ORDER ];
2209-
22102254#define VOID_PTE (mfn_pte(0, __pgprot(0)))
22112255static void xen_zap_pfn_range (unsigned long vaddr , unsigned int order ,
22122256 unsigned long * in_frames ,
@@ -2323,18 +2367,25 @@ int xen_create_contiguous_region(phys_addr_t pstart, unsigned int order,
23232367 unsigned int address_bits ,
23242368 dma_addr_t * dma_handle )
23252369{
2326- unsigned long * in_frames = discontig_frames , out_frame ;
2370+ unsigned long * in_frames , out_frame ;
23272371 unsigned long flags ;
23282372 int success ;
23292373 unsigned long vstart = (unsigned long )phys_to_virt (pstart );
23302374
2331- if (unlikely (order > MAX_CONTIG_ORDER ))
2332- return - ENOMEM ;
2375+ if (unlikely (order > discontig_frames_order )) {
2376+ if (!discontig_frames_dyn )
2377+ return - ENOMEM ;
2378+
2379+ if (alloc_discontig_frames (order ))
2380+ return - ENOMEM ;
2381+ }
23332382
23342383 memset ((void * ) vstart , 0 , PAGE_SIZE << order );
23352384
23362385 spin_lock_irqsave (& xen_reservation_lock , flags );
23372386
2387+ in_frames = discontig_frames ;
2388+
23382389 /* 1. Zap current PTEs, remembering MFNs. */
23392390 xen_zap_pfn_range (vstart , order , in_frames , NULL );
23402391
@@ -2358,19 +2409,21 @@ int xen_create_contiguous_region(phys_addr_t pstart, unsigned int order,
23582409
23592410void xen_destroy_contiguous_region (phys_addr_t pstart , unsigned int order )
23602411{
2361- unsigned long * out_frames = discontig_frames , in_frame ;
2412+ unsigned long * out_frames , in_frame ;
23622413 unsigned long flags ;
23632414 int success ;
23642415 unsigned long vstart ;
23652416
2366- if (unlikely (order > MAX_CONTIG_ORDER ))
2417+ if (unlikely (order > discontig_frames_order ))
23672418 return ;
23682419
23692420 vstart = (unsigned long )phys_to_virt (pstart );
23702421 memset ((void * ) vstart , 0 , PAGE_SIZE << order );
23712422
23722423 spin_lock_irqsave (& xen_reservation_lock , flags );
23732424
2425+ out_frames = discontig_frames ;
2426+
23742427 /* 1. Find start MFN of contiguous extent. */
23752428 in_frame = virt_to_mfn ((void * )vstart );
23762429
0 commit comments