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: 37e6764895ef ("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 */
|