@@ -300,7 +300,7 @@ static struct diag204_x_part_block *lpar_cpu_inf(struct lpar_cpu_inf *part_inf,
300300 return (struct diag204_x_part_block * )& block -> cpus [i ];
301301}
302302
303- static void * diag204_get_data (void )
303+ static void * diag204_get_data (bool diag204_allow_busy )
304304{
305305 unsigned long subcode ;
306306 void * diag204_buf ;
@@ -320,6 +320,8 @@ static void *diag204_get_data(void)
320320 return ERR_PTR (- ENOMEM );
321321 subcode = DIAG204_SUBC_STIB7 ;
322322 subcode |= DIAG204_INFO_EXT ;
323+ if (diag204_has_bif () && diag204_allow_busy )
324+ subcode |= DIAG204_BIF_BIT ;
323325 rc = diag204 (subcode , pages , diag204_buf );
324326 if (rc < 0 ) {
325327 vfree (diag204_buf );
@@ -328,22 +330,27 @@ static void *diag204_get_data(void)
328330 return diag204_buf ;
329331}
330332
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 )
332345{
333346 int i ;
334347 bool this_lpar ;
335- void * diag204_buf ;
336348 void * diag224_buf = NULL ;
337349 struct diag204_x_info_blk_hdr * ti_hdr ;
338350 struct diag204_x_part_block * part_block ;
339351 struct diag204_x_phys_block * phys_block ;
340352 struct lpar_cpu_inf lpar_inf = {};
341353
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-
347354 diag224_buf = (void * )__get_free_page (GFP_KERNEL | GFP_DMA );
348355 if (!diag224_buf || diag224 (diag224_buf ))
349356 goto out ;
@@ -408,7 +415,6 @@ static void fill_diag(struct sthyi_sctns *sctns)
408415
409416out :
410417 free_page ((unsigned long )diag224_buf );
411- vfree (diag204_buf );
412418}
413419
414420static int sthyi (u64 vaddr , u64 * rc )
@@ -430,19 +436,31 @@ static int sthyi(u64 vaddr, u64 *rc)
430436
431437static int fill_dst (void * dst , u64 * rc )
432438{
439+ void * diag204_buf ;
440+
433441 struct sthyi_sctns * sctns = (struct sthyi_sctns * )dst ;
434442
435443 /*
436444 * If the facility is on, we don't want to emulate the instruction.
437445 * We ask the hypervisor to provide the data.
438446 */
439- if (test_facility (74 ))
447+ if (test_facility (74 )) {
448+ memset (dst , 0 , PAGE_SIZE );
440449 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 );
442460 fill_hdr (sctns );
443461 fill_stsi (sctns );
444- fill_diag (sctns );
445- * rc = 0 ;
462+ fill_diag (sctns , diag204_buf );
463+ vfree ( diag204_buf ) ;
446464 return 0 ;
447465}
448466
@@ -461,11 +479,14 @@ static int sthyi_update_cache(u64 *rc)
461479{
462480 int r ;
463481
464- memset (sthyi_cache .info , 0 , PAGE_SIZE );
465482 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+ }
469490 return r ;
470491}
471492
0 commit comments