@@ -300,7 +300,7 @@ static struct diag204_x_part_block *lpar_cpu_inf(struct lpar_cpu_inf *part_inf,
300
300
return (struct diag204_x_part_block * )& block -> cpus [i ];
301
301
}
302
302
303
- static void * diag204_get_data (void )
303
+ static void * diag204_get_data (bool diag204_allow_busy )
304
304
{
305
305
unsigned long subcode ;
306
306
void * diag204_buf ;
@@ -320,6 +320,8 @@ static void *diag204_get_data(void)
320
320
return ERR_PTR (- ENOMEM );
321
321
subcode = DIAG204_SUBC_STIB7 ;
322
322
subcode |= DIAG204_INFO_EXT ;
323
+ if (diag204_has_bif () && diag204_allow_busy )
324
+ subcode |= DIAG204_BIF_BIT ;
323
325
rc = diag204 (subcode , pages , diag204_buf );
324
326
if (rc < 0 ) {
325
327
vfree (diag204_buf );
@@ -328,22 +330,27 @@ static void *diag204_get_data(void)
328
330
return diag204_buf ;
329
331
}
330
332
331
- static void fill_diag (struct sthyi_sctns * sctns )
333
+ static bool is_diag204_cached (struct sthyi_sctns * sctns )
334
+ {
335
+ /*
336
+ * Check if validity bits are set when diag204 data
337
+ * is gathered.
338
+ */
339
+ if (sctns -> par .infpval1 )
340
+ return true;
341
+ return false;
342
+ }
343
+
344
+ static void fill_diag (struct sthyi_sctns * sctns , void * diag204_buf )
332
345
{
333
346
int i ;
334
347
bool this_lpar ;
335
- void * diag204_buf ;
336
348
void * diag224_buf = NULL ;
337
349
struct diag204_x_info_blk_hdr * ti_hdr ;
338
350
struct diag204_x_part_block * part_block ;
339
351
struct diag204_x_phys_block * phys_block ;
340
352
struct lpar_cpu_inf lpar_inf = {};
341
353
342
- /* Errors are handled through the validity bits in the response. */
343
- diag204_buf = diag204_get_data ();
344
- if (IS_ERR (diag204_buf ))
345
- return ;
346
-
347
354
diag224_buf = (void * )__get_free_page (GFP_KERNEL | GFP_DMA );
348
355
if (!diag224_buf || diag224 (diag224_buf ))
349
356
goto out ;
@@ -408,7 +415,6 @@ static void fill_diag(struct sthyi_sctns *sctns)
408
415
409
416
out :
410
417
free_page ((unsigned long )diag224_buf );
411
- vfree (diag204_buf );
412
418
}
413
419
414
420
static int sthyi (u64 vaddr , u64 * rc )
@@ -430,19 +436,31 @@ static int sthyi(u64 vaddr, u64 *rc)
430
436
431
437
static int fill_dst (void * dst , u64 * rc )
432
438
{
439
+ void * diag204_buf ;
440
+
433
441
struct sthyi_sctns * sctns = (struct sthyi_sctns * )dst ;
434
442
435
443
/*
436
444
* If the facility is on, we don't want to emulate the instruction.
437
445
* We ask the hypervisor to provide the data.
438
446
*/
439
- if (test_facility (74 ))
447
+ if (test_facility (74 )) {
448
+ memset (dst , 0 , PAGE_SIZE );
440
449
return sthyi ((u64 )dst , rc );
441
-
450
+ }
451
+ /*
452
+ * When emulating, if diag204 returns BUSY don't reset dst buffer
453
+ * and use cached data.
454
+ */
455
+ * rc = 0 ;
456
+ diag204_buf = diag204_get_data (is_diag204_cached (sctns ));
457
+ if (IS_ERR (diag204_buf ))
458
+ return PTR_ERR (diag204_buf );
459
+ memset (dst , 0 , PAGE_SIZE );
442
460
fill_hdr (sctns );
443
461
fill_stsi (sctns );
444
- fill_diag (sctns );
445
- * rc = 0 ;
462
+ fill_diag (sctns , diag204_buf );
463
+ vfree ( diag204_buf ) ;
446
464
return 0 ;
447
465
}
448
466
@@ -461,11 +479,14 @@ static int sthyi_update_cache(u64 *rc)
461
479
{
462
480
int r ;
463
481
464
- memset (sthyi_cache .info , 0 , PAGE_SIZE );
465
482
r = fill_dst (sthyi_cache .info , rc );
466
- if (r )
467
- return r ;
468
- sthyi_cache .end = jiffies + CACHE_VALID_JIFFIES ;
483
+ if (r == 0 ) {
484
+ sthyi_cache .end = jiffies + CACHE_VALID_JIFFIES ;
485
+ } else if (r == - EBUSY ) {
486
+ /* mark as expired and return 0 to keep using cached data */
487
+ sthyi_cache .end = jiffies - 1 ;
488
+ r = 0 ;
489
+ }
469
490
return r ;
470
491
}
471
492
0 commit comments