aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMete Durlu <[email protected]>2024-07-04 14:10:10 +0200
committerVasily Gorbik <[email protected]>2024-07-10 19:50:45 +0200
commitb7a5e5dfbd68050e8582e901f397dc75451bb877 (patch)
tree4e2af8541be86e19fb929bf83186de2588976691
parent6fdf72c9a9f614115ac7f2889c1018bbff1af9b3 (diff)
s390/sthyi: Use cached data when diag is busy
When sthyi is being emulated, data from diag204 is used. If diag204 returns busy, previously cached sthyi info block is returned to the caller and cache expiry is set to expired. Acked-by: Heiko Carstens <[email protected]> Reviewed-by: Tobias Huschle <[email protected]> Signed-off-by: Tobias Huschle <[email protected]> Signed-off-by: Mete Durlu <[email protected]> Signed-off-by: Vasily Gorbik <[email protected]>
-rw-r--r--arch/s390/kernel/sthyi.c55
1 files changed, 38 insertions, 17 deletions
diff --git a/arch/s390/kernel/sthyi.c b/arch/s390/kernel/sthyi.c
index 9f9bac01f5f2..1cf2ad04f8e9 100644
--- a/arch/s390/kernel/sthyi.c
+++ b/arch/s390/kernel/sthyi.c
@@ -300,7 +300,7 @@ static struct diag204_x_part_block *lpar_cpu_inf(struct lpar_cpu_inf *part_inf,
return (struct diag204_x_part_block *)&block->cpus[i];
}
-static void *diag204_get_data(void)
+static void *diag204_get_data(bool diag204_allow_busy)
{
unsigned long subcode;
void *diag204_buf;
@@ -320,6 +320,8 @@ static void *diag204_get_data(void)
return ERR_PTR(-ENOMEM);
subcode = DIAG204_SUBC_STIB7;
subcode |= DIAG204_INFO_EXT;
+ if (diag204_has_bif() && diag204_allow_busy)
+ subcode |= DIAG204_BIF_BIT;
rc = diag204(subcode, pages, diag204_buf);
if (rc < 0) {
vfree(diag204_buf);
@@ -328,22 +330,27 @@ static void *diag204_get_data(void)
return diag204_buf;
}
-static void fill_diag(struct sthyi_sctns *sctns)
+static bool is_diag204_cached(struct sthyi_sctns *sctns)
+{
+ /*
+ * Check if validity bits are set when diag204 data
+ * is gathered.
+ */
+ if (sctns->par.infpval1)
+ return true;
+ return false;
+}
+
+static void fill_diag(struct sthyi_sctns *sctns, void *diag204_buf)
{
int i;
bool this_lpar;
- void *diag204_buf;
void *diag224_buf = NULL;
struct diag204_x_info_blk_hdr *ti_hdr;
struct diag204_x_part_block *part_block;
struct diag204_x_phys_block *phys_block;
struct lpar_cpu_inf lpar_inf = {};
- /* Errors are handled through the validity bits in the response. */
- diag204_buf = diag204_get_data();
- if (IS_ERR(diag204_buf))
- return;
-
diag224_buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
if (!diag224_buf || diag224(diag224_buf))
goto out;
@@ -408,7 +415,6 @@ static void fill_diag(struct sthyi_sctns *sctns)
out:
free_page((unsigned long)diag224_buf);
- vfree(diag204_buf);
}
static int sthyi(u64 vaddr, u64 *rc)
@@ -430,19 +436,31 @@ static int sthyi(u64 vaddr, u64 *rc)
static int fill_dst(void *dst, u64 *rc)
{
+ void *diag204_buf;
+
struct sthyi_sctns *sctns = (struct sthyi_sctns *)dst;
/*
* If the facility is on, we don't want to emulate the instruction.
* We ask the hypervisor to provide the data.
*/
- if (test_facility(74))
+ if (test_facility(74)) {
+ memset(dst, 0, PAGE_SIZE);
return sthyi((u64)dst, rc);
-
+ }
+ /*
+ * When emulating, if diag204 returns BUSY don't reset dst buffer
+ * and use cached data.
+ */
+ *rc = 0;
+ diag204_buf = diag204_get_data(is_diag204_cached(sctns));
+ if (IS_ERR(diag204_buf))
+ return PTR_ERR(diag204_buf);
+ memset(dst, 0, PAGE_SIZE);
fill_hdr(sctns);
fill_stsi(sctns);
- fill_diag(sctns);
- *rc = 0;
+ fill_diag(sctns, diag204_buf);
+ vfree(diag204_buf);
return 0;
}
@@ -461,11 +479,14 @@ static int sthyi_update_cache(u64 *rc)
{
int r;
- memset(sthyi_cache.info, 0, PAGE_SIZE);
r = fill_dst(sthyi_cache.info, rc);
- if (r)
- return r;
- sthyi_cache.end = jiffies + CACHE_VALID_JIFFIES;
+ if (r == 0) {
+ sthyi_cache.end = jiffies + CACHE_VALID_JIFFIES;
+ } else if (r == -EBUSY) {
+ /* mark as expired and return 0 to keep using cached data */
+ sthyi_cache.end = jiffies - 1;
+ r = 0;
+ }
return r;
}