0cf72f7f14
The hypervisor returns migration failure if all VAS windows are not
closed. During pre-migration stage, vas_migration_handler() sets
migration_in_progress flag and closes all windows from the list.
The allocate VAS window routine checks the migration flag, setup
the window and then add it to the list. So there is possibility of
the migration handler missing the window that is still in the
process of setup.
t1: Allocate and open VAS t2: Migration event
window
lock vas_pseries_mutex
If migration_in_progress set
unlock vas_pseries_mutex
return
open window HCALL
unlock vas_pseries_mutex
Modify window HCALL lock vas_pseries_mutex
setup window migration_in_progress=true
Closes all windows from the list
// May miss windows that are
// not in the list
unlock vas_pseries_mutex
lock vas_pseries_mutex return
if nr_closed_windows == 0
// No DLPAR CPU or migration
add window to the list
// Window will be added to the
// list after the setup is completed
unlock vas_pseries_mutex
return
unlock vas_pseries_mutex
Close VAS window
// due to DLPAR CPU or migration
return -EBUSY
This patch resolves the issue with the following steps:
- Set the migration_in_progress flag without holding mutex.
- Introduce nr_open_wins_progress counter in VAS capabilities
struct
- This counter tracks the number of open windows are still in
progress
- The allocate setup window thread closes windows if the migration
is set and decrements nr_open_window_progress counter
- The migration handler waits for no in-progress open windows.
The code flow with the fix is as follows:
t1: Allocate and open VAS t2: Migration event
window
lock vas_pseries_mutex
If migration_in_progress set
unlock vas_pseries_mutex
return
open window HCALL
nr_open_wins_progress++
// Window opened, but not
// added to the list yet
unlock vas_pseries_mutex
Modify window HCALL migration_in_progress=true
setup window lock vas_pseries_mutex
Closes all windows from the list
While nr_open_wins_progress {
unlock vas_pseries_mutex
lock vas_pseries_mutex sleep
if nr_closed_windows == 0 // Wait if any open window in
or migration is not started // progress. The open window
// No DLPAR CPU or migration // thread closes the window without
add window to the list // adding to the list and return if
nr_open_wins_progress-- // the migration is in progress.
unlock vas_pseries_mutex
return
Close VAS window
nr_open_wins_progress--
unlock vas_pseries_mutex
return -EBUSY lock vas_pseries_mutex
}
unlock vas_pseries_mutex
return
Fixes: 37e6764895
("powerpc/pseries/vas: Add VAS migration handler")
Signed-off-by: Haren Myneni <haren@linux.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/20231125235104.3405008-1-haren@linux.ibm.com
158 lines
4.2 KiB
C
158 lines
4.2 KiB
C
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
/*
|
|
* Copyright 2020-21 IBM Corp.
|
|
*/
|
|
|
|
#ifndef _VAS_H
|
|
#define _VAS_H
|
|
#include <asm/vas.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/stringify.h>
|
|
|
|
/*
|
|
* VAS window modify flags
|
|
*/
|
|
#define VAS_MOD_WIN_CLOSE PPC_BIT(0)
|
|
#define VAS_MOD_WIN_JOBS_KILL PPC_BIT(1)
|
|
#define VAS_MOD_WIN_DR PPC_BIT(3)
|
|
#define VAS_MOD_WIN_PR PPC_BIT(4)
|
|
#define VAS_MOD_WIN_SF PPC_BIT(5)
|
|
#define VAS_MOD_WIN_TA PPC_BIT(6)
|
|
#define VAS_MOD_WIN_FLAGS (VAS_MOD_WIN_JOBS_KILL | VAS_MOD_WIN_DR | \
|
|
VAS_MOD_WIN_PR | VAS_MOD_WIN_SF)
|
|
|
|
#define VAS_WIN_ACTIVE 0x0
|
|
#define VAS_WIN_CLOSED 0x1
|
|
#define VAS_WIN_INACTIVE 0x2 /* Inactive due to HW failure */
|
|
/* Process of being modified, deallocated, or quiesced */
|
|
#define VAS_WIN_MOD_IN_PROCESS 0x3
|
|
|
|
#define VAS_COPY_PASTE_USER_MODE 0x00000001
|
|
#define VAS_COP_OP_USER_MODE 0x00000010
|
|
|
|
#define VAS_GZIP_QOS_CAPABILITIES 0x56516F73477A6970
|
|
#define VAS_GZIP_DEFAULT_CAPABILITIES 0x56446566477A6970
|
|
|
|
enum vas_migrate_action {
|
|
VAS_SUSPEND,
|
|
VAS_RESUME,
|
|
};
|
|
|
|
/*
|
|
* Co-processor feature - GZIP QoS windows or GZIP default windows
|
|
*/
|
|
enum vas_cop_feat_type {
|
|
VAS_GZIP_QOS_FEAT_TYPE,
|
|
VAS_GZIP_DEF_FEAT_TYPE,
|
|
VAS_MAX_FEAT_TYPE,
|
|
};
|
|
|
|
/*
|
|
* Use to get feature specific capabilities from the
|
|
* hypervisor.
|
|
*/
|
|
struct hv_vas_cop_feat_caps {
|
|
__be64 descriptor;
|
|
u8 win_type; /* Default or QoS type */
|
|
u8 user_mode;
|
|
__be16 max_lpar_creds;
|
|
__be16 max_win_creds;
|
|
union {
|
|
__be16 reserved;
|
|
__be16 def_lpar_creds; /* Used for default capabilities */
|
|
};
|
|
__be16 target_lpar_creds;
|
|
} __packed __aligned(0x1000);
|
|
|
|
/*
|
|
* Feature specific (QoS or default) capabilities.
|
|
*/
|
|
struct vas_cop_feat_caps {
|
|
u64 descriptor;
|
|
u8 win_type; /* Default or QoS type */
|
|
u8 user_mode; /* User mode copy/paste or COP HCALL */
|
|
u16 max_lpar_creds; /* Max credits available in LPAR */
|
|
/* Max credits can be assigned per window */
|
|
u16 max_win_creds;
|
|
union {
|
|
u16 reserved; /* Used for QoS credit type */
|
|
u16 def_lpar_creds; /* Used for default credit type */
|
|
};
|
|
/* Total LPAR available credits. Can be different from max LPAR */
|
|
/* credits due to DLPAR operation */
|
|
atomic_t nr_total_credits; /* Total credits assigned to LPAR */
|
|
atomic_t nr_used_credits; /* Used credits so far */
|
|
};
|
|
|
|
/*
|
|
* Feature (QoS or Default) specific to store capabilities and
|
|
* the list of open windows.
|
|
*/
|
|
struct vas_caps {
|
|
struct vas_cop_feat_caps caps;
|
|
struct list_head list; /* List of open windows */
|
|
int nr_open_wins_progress; /* Number of open windows in */
|
|
/* progress. Used in migration */
|
|
int nr_close_wins; /* closed windows in the hypervisor for DLPAR */
|
|
int nr_open_windows; /* Number of successful open windows */
|
|
u8 feat; /* Feature type */
|
|
};
|
|
|
|
/*
|
|
* To get window information from the hypervisor.
|
|
*/
|
|
struct hv_vas_win_lpar {
|
|
__be16 version;
|
|
u8 win_type;
|
|
u8 status;
|
|
__be16 credits; /* No of credits assigned to this window */
|
|
__be16 reserved;
|
|
__be32 pid; /* LPAR Process ID */
|
|
__be32 tid; /* LPAR Thread ID */
|
|
__be64 win_addr; /* Paste address */
|
|
__be32 interrupt; /* Interrupt when NX request completes */
|
|
__be32 fault; /* Interrupt when NX sees fault */
|
|
/* Associativity Domain Identifiers as returned in */
|
|
/* H_HOME_NODE_ASSOCIATIVITY */
|
|
__be64 domain[6];
|
|
__be64 win_util; /* Number of bytes processed */
|
|
} __packed __aligned(0x1000);
|
|
|
|
struct pseries_vas_window {
|
|
struct vas_window vas_win;
|
|
u64 win_addr; /* Physical paste address */
|
|
u8 win_type; /* QoS or Default window */
|
|
u32 complete_irq; /* Completion interrupt */
|
|
u32 fault_irq; /* Fault interrupt */
|
|
u64 domain[6]; /* Associativity domain Ids */
|
|
/* this window is allocated */
|
|
u64 util;
|
|
u32 pid; /* PID associated with this window */
|
|
|
|
/* List of windows opened which is used for LPM */
|
|
struct list_head win_list;
|
|
u64 flags;
|
|
char *name;
|
|
int fault_virq;
|
|
atomic_t pending_faults; /* Number of pending faults */
|
|
};
|
|
|
|
int sysfs_add_vas_caps(struct vas_cop_feat_caps *caps);
|
|
int vas_reconfig_capabilties(u8 type, int new_nr_creds);
|
|
int __init sysfs_pseries_vas_init(struct vas_all_caps *vas_caps);
|
|
|
|
#ifdef CONFIG_PPC_VAS
|
|
int vas_migration_handler(int action);
|
|
int pseries_vas_dlpar_cpu(void);
|
|
#else
|
|
static inline int vas_migration_handler(int action)
|
|
{
|
|
return 0;
|
|
}
|
|
static inline int pseries_vas_dlpar_cpu(void)
|
|
{
|
|
return 0;
|
|
}
|
|
#endif
|
|
#endif /* _VAS_H */
|