45
45
#include "plpar_wrappers.h"
46
46
#include "pseries.h"
47
47
48
+ /* Flag bits for H_BULK_REMOVE */
49
+ #define HBR_REQUEST 0x4000000000000000UL
50
+ #define HBR_RESPONSE 0x8000000000000000UL
51
+ #define HBR_END 0xc000000000000000UL
52
+ #define HBR_AVPN 0x0200000000000000UL
53
+ #define HBR_ANDCOND 0x0100000000000000UL
54
+
48
55
49
56
/* in hvCall.S */
50
57
EXPORT_SYMBOL (plpar_hcall );
@@ -347,6 +354,113 @@ static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long vpn,
347
354
BUG_ON (lpar_rc != H_SUCCESS );
348
355
}
349
356
357
+ /*
358
+ * Limit iterations holding pSeries_lpar_tlbie_lock to 3. We also need
359
+ * to make sure that we avoid bouncing the hypervisor tlbie lock.
360
+ */
361
+ #define PPC64_HUGE_HPTE_BATCH 12
362
+
363
+ static void __pSeries_lpar_hugepage_invalidate (unsigned long * slot ,
364
+ unsigned long * vpn , int count ,
365
+ int psize , int ssize )
366
+ {
367
+ unsigned long param [8 ];
368
+ int i = 0 , pix = 0 , rc ;
369
+ unsigned long flags = 0 ;
370
+ int lock_tlbie = !mmu_has_feature (MMU_FTR_LOCKLESS_TLBIE );
371
+
372
+ if (lock_tlbie )
373
+ spin_lock_irqsave (& pSeries_lpar_tlbie_lock , flags );
374
+
375
+ for (i = 0 ; i < count ; i ++ ) {
376
+
377
+ if (!firmware_has_feature (FW_FEATURE_BULK_REMOVE )) {
378
+ pSeries_lpar_hpte_invalidate (slot [i ], vpn [i ], psize , 0 ,
379
+ ssize , 0 );
380
+ } else {
381
+ param [pix ] = HBR_REQUEST | HBR_AVPN | slot [i ];
382
+ param [pix + 1 ] = hpte_encode_avpn (vpn [i ], psize , ssize );
383
+ pix += 2 ;
384
+ if (pix == 8 ) {
385
+ rc = plpar_hcall9 (H_BULK_REMOVE , param ,
386
+ param [0 ], param [1 ], param [2 ],
387
+ param [3 ], param [4 ], param [5 ],
388
+ param [6 ], param [7 ]);
389
+ BUG_ON (rc != H_SUCCESS );
390
+ pix = 0 ;
391
+ }
392
+ }
393
+ }
394
+ if (pix ) {
395
+ param [pix ] = HBR_END ;
396
+ rc = plpar_hcall9 (H_BULK_REMOVE , param , param [0 ], param [1 ],
397
+ param [2 ], param [3 ], param [4 ], param [5 ],
398
+ param [6 ], param [7 ]);
399
+ BUG_ON (rc != H_SUCCESS );
400
+ }
401
+
402
+ if (lock_tlbie )
403
+ spin_unlock_irqrestore (& pSeries_lpar_tlbie_lock , flags );
404
+ }
405
+
406
+ static void pSeries_lpar_hugepage_invalidate (struct mm_struct * mm ,
407
+ unsigned char * hpte_slot_array ,
408
+ unsigned long addr , int psize )
409
+ {
410
+ int ssize = 0 , i , index = 0 ;
411
+ unsigned long s_addr = addr ;
412
+ unsigned int max_hpte_count , valid ;
413
+ unsigned long vpn_array [PPC64_HUGE_HPTE_BATCH ];
414
+ unsigned long slot_array [PPC64_HUGE_HPTE_BATCH ];
415
+ unsigned long shift , hidx , vpn = 0 , vsid , hash , slot ;
416
+
417
+ shift = mmu_psize_defs [psize ].shift ;
418
+ max_hpte_count = 1U << (PMD_SHIFT - shift );
419
+
420
+ for (i = 0 ; i < max_hpte_count ; i ++ ) {
421
+ valid = hpte_valid (hpte_slot_array , i );
422
+ if (!valid )
423
+ continue ;
424
+ hidx = hpte_hash_index (hpte_slot_array , i );
425
+
426
+ /* get the vpn */
427
+ addr = s_addr + (i * (1ul << shift ));
428
+ if (!is_kernel_addr (addr )) {
429
+ ssize = user_segment_size (addr );
430
+ vsid = get_vsid (mm -> context .id , addr , ssize );
431
+ WARN_ON (vsid == 0 );
432
+ } else {
433
+ vsid = get_kernel_vsid (addr , mmu_kernel_ssize );
434
+ ssize = mmu_kernel_ssize ;
435
+ }
436
+
437
+ vpn = hpt_vpn (addr , vsid , ssize );
438
+ hash = hpt_hash (vpn , shift , ssize );
439
+ if (hidx & _PTEIDX_SECONDARY )
440
+ hash = ~hash ;
441
+
442
+ slot = (hash & htab_hash_mask ) * HPTES_PER_GROUP ;
443
+ slot += hidx & _PTEIDX_GROUP_IX ;
444
+
445
+ slot_array [index ] = slot ;
446
+ vpn_array [index ] = vpn ;
447
+ if (index == PPC64_HUGE_HPTE_BATCH - 1 ) {
448
+ /*
449
+ * Now do a bluk invalidate
450
+ */
451
+ __pSeries_lpar_hugepage_invalidate (slot_array ,
452
+ vpn_array ,
453
+ PPC64_HUGE_HPTE_BATCH ,
454
+ psize , ssize );
455
+ index = 0 ;
456
+ } else
457
+ index ++ ;
458
+ }
459
+ if (index )
460
+ __pSeries_lpar_hugepage_invalidate (slot_array , vpn_array ,
461
+ index , psize , ssize );
462
+ }
463
+
350
464
static void pSeries_lpar_hpte_removebolted (unsigned long ea ,
351
465
int psize , int ssize )
352
466
{
@@ -364,13 +478,6 @@ static void pSeries_lpar_hpte_removebolted(unsigned long ea,
364
478
pSeries_lpar_hpte_invalidate (slot , vpn , psize , 0 , ssize , 0 );
365
479
}
366
480
367
- /* Flag bits for H_BULK_REMOVE */
368
- #define HBR_REQUEST 0x4000000000000000UL
369
- #define HBR_RESPONSE 0x8000000000000000UL
370
- #define HBR_END 0xc000000000000000UL
371
- #define HBR_AVPN 0x0200000000000000UL
372
- #define HBR_ANDCOND 0x0100000000000000UL
373
-
374
481
/*
375
482
* Take a spinlock around flushes to avoid bouncing the hypervisor tlbie
376
483
* lock.
@@ -459,6 +566,7 @@ void __init hpte_init_lpar(void)
459
566
ppc_md .hpte_removebolted = pSeries_lpar_hpte_removebolted ;
460
567
ppc_md .flush_hash_range = pSeries_lpar_flush_hash_range ;
461
568
ppc_md .hpte_clear_all = pSeries_lpar_hptab_clear ;
569
+ ppc_md .hugepage_invalidate = pSeries_lpar_hugepage_invalidate ;
462
570
}
463
571
464
572
#ifdef CONFIG_PPC_SMLPAR
0 commit comments