mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-01 10:45:49 +00:00
powerpc fixes for 6.8 #4
- Fix a crash when hot adding a PCI device to an LPAR since recent changes. - Fix nested KVM level-2 guest reboot failure due to empty 'arch_compat'. Thanks to: Amit Machhiwal, Aneesh Kumar K.V (IBM), Brian King, Gaurav Batra, Vaibhav Jain. -----BEGIN PGP SIGNATURE----- iQJHBAABCAAxFiEEJFGtCPCthwEv2Y/bUevqPMjhpYAFAmXaf8kTHG1wZUBlbGxl cm1hbi5pZC5hdQAKCRBR6+o8yOGlgJUyEACK+gmbPJxVwRnt60e7l8SJrjaXE9ZH llI2ffSM63KOL0qeJlWj8EfNcmU3ihCnMpVS4VHAIvEvCq8KBdcHh7EfLmIjMSl2 oHfcb+dpdnWpQUkI2jci6ptxv8Al7hmd5kP6X5TGn0XJaXWatW4tj7QDP574DCZY UfbHGvGnCVmlcxm3xhn7JzJT4Lgj9ehxgZEMHB68qfwU2rJgUXNITBzOsGwfq4c0 wiIdzVGMuJQdaFLt0JLNP2KY8kpVsAeKRYgSsLrkDkp+tKOIPvgeBmC221pOb1Y4 iZbpXR3h06WfFBnA2PJpdfuacN55/gF0U5BnyOj5tB7CTx65oTyX/BJLIocKWAlF hRRPVEYqBH0mZCHXn03+J/A2/iut1XxDlVMpEhjjZjb57CTYCApSpHer6shPw6PV QqG+iAr7lBCZ70qS2m2+mjPhgDf5TNlxlsip7S3xJJpJvScN/JyPDupDF7tQYuHD GjIOm8gSHL0i3F4L3NAZ9FtPRwxXcv85sWCTbE7jsfVOT/kkDGTwhx/vdPIR0la8 agDv/Q0FyyFHWd5IS4oqXFop6P3boulHexdIec/MIhBrPSZ6oG0ySzj3rqdI7VYh 7BYj/cHerKONR/BU6S3vKddh9RDD9Fe5ghEAgng2DxG+Za/m/M2v/76123/ZeZuw qQ8aiIvYOJ4DGA== =+tcX -----END PGP SIGNATURE----- Merge tag 'powerpc-6.8-4' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux Pull powerpc fixes from Michael Ellerman: - Fix a crash when hot adding a PCI device to an LPAR since recent changes - Fix nested KVM level-2 guest reboot failure due to empty 'arch_compat' Thanks to Amit Machhiwal, Aneesh Kumar K.V (IBM), Brian King, Gaurav Batra, and Vaibhav Jain. * tag 'powerpc-6.8-4' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux: KVM: PPC: Book3S HV: Fix L2 guest reboot failure due to empty 'arch_compat' powerpc/pseries/iommu: DLPAR add doesn't completely initialize pci_controller
This commit is contained in:
commit
ab0a97cffa
@ -30,6 +30,16 @@ void *pci_traverse_device_nodes(struct device_node *start,
|
||||
void *data);
|
||||
extern void pci_devs_phb_init_dynamic(struct pci_controller *phb);
|
||||
|
||||
#if defined(CONFIG_IOMMU_API) && (defined(CONFIG_PPC_PSERIES) || \
|
||||
defined(CONFIG_PPC_POWERNV))
|
||||
extern void ppc_iommu_register_device(struct pci_controller *phb);
|
||||
extern void ppc_iommu_unregister_device(struct pci_controller *phb);
|
||||
#else
|
||||
static inline void ppc_iommu_register_device(struct pci_controller *phb) { }
|
||||
static inline void ppc_iommu_unregister_device(struct pci_controller *phb) { }
|
||||
#endif
|
||||
|
||||
|
||||
/* From rtas_pci.h */
|
||||
extern void init_pci_config_tokens (void);
|
||||
extern unsigned long get_phb_buid (struct device_node *);
|
||||
|
@ -1360,7 +1360,7 @@ static struct iommu_device *spapr_tce_iommu_probe_device(struct device *dev)
|
||||
struct pci_controller *hose;
|
||||
|
||||
if (!dev_is_pci(dev))
|
||||
return ERR_PTR(-EPERM);
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
pdev = to_pci_dev(dev);
|
||||
hose = pdev->bus->sysdata;
|
||||
@ -1409,6 +1409,21 @@ static const struct attribute_group *spapr_tce_iommu_groups[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
void ppc_iommu_register_device(struct pci_controller *phb)
|
||||
{
|
||||
iommu_device_sysfs_add(&phb->iommu, phb->parent,
|
||||
spapr_tce_iommu_groups, "iommu-phb%04x",
|
||||
phb->global_number);
|
||||
iommu_device_register(&phb->iommu, &spapr_tce_iommu_ops,
|
||||
phb->parent);
|
||||
}
|
||||
|
||||
void ppc_iommu_unregister_device(struct pci_controller *phb)
|
||||
{
|
||||
iommu_device_unregister(&phb->iommu);
|
||||
iommu_device_sysfs_remove(&phb->iommu);
|
||||
}
|
||||
|
||||
/*
|
||||
* This registers IOMMU devices of PHBs. This needs to happen
|
||||
* after core_initcall(iommu_init) + postcore_initcall(pci_driver_init) and
|
||||
@ -1419,11 +1434,7 @@ static int __init spapr_tce_setup_phb_iommus_initcall(void)
|
||||
struct pci_controller *hose;
|
||||
|
||||
list_for_each_entry(hose, &hose_list, list_node) {
|
||||
iommu_device_sysfs_add(&hose->iommu, hose->parent,
|
||||
spapr_tce_iommu_groups, "iommu-phb%04x",
|
||||
hose->global_number);
|
||||
iommu_device_register(&hose->iommu, &spapr_tce_iommu_ops,
|
||||
hose->parent);
|
||||
ppc_iommu_register_device(hose);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -391,6 +391,24 @@ static void kvmppc_set_pvr_hv(struct kvm_vcpu *vcpu, u32 pvr)
|
||||
/* Dummy value used in computing PCR value below */
|
||||
#define PCR_ARCH_31 (PCR_ARCH_300 << 1)
|
||||
|
||||
static inline unsigned long map_pcr_to_cap(unsigned long pcr)
|
||||
{
|
||||
unsigned long cap = 0;
|
||||
|
||||
switch (pcr) {
|
||||
case PCR_ARCH_300:
|
||||
cap = H_GUEST_CAP_POWER9;
|
||||
break;
|
||||
case PCR_ARCH_31:
|
||||
cap = H_GUEST_CAP_POWER10;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return cap;
|
||||
}
|
||||
|
||||
static int kvmppc_set_arch_compat(struct kvm_vcpu *vcpu, u32 arch_compat)
|
||||
{
|
||||
unsigned long host_pcr_bit = 0, guest_pcr_bit = 0, cap = 0;
|
||||
@ -424,11 +442,9 @@ static int kvmppc_set_arch_compat(struct kvm_vcpu *vcpu, u32 arch_compat)
|
||||
break;
|
||||
case PVR_ARCH_300:
|
||||
guest_pcr_bit = PCR_ARCH_300;
|
||||
cap = H_GUEST_CAP_POWER9;
|
||||
break;
|
||||
case PVR_ARCH_31:
|
||||
guest_pcr_bit = PCR_ARCH_31;
|
||||
cap = H_GUEST_CAP_POWER10;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
@ -440,6 +456,12 @@ static int kvmppc_set_arch_compat(struct kvm_vcpu *vcpu, u32 arch_compat)
|
||||
return -EINVAL;
|
||||
|
||||
if (kvmhv_on_pseries() && kvmhv_is_nestedv2()) {
|
||||
/*
|
||||
* 'arch_compat == 0' would mean the guest should default to
|
||||
* L1's compatibility. In this case, the guest would pick
|
||||
* host's PCR and evaluate the corresponding capabilities.
|
||||
*/
|
||||
cap = map_pcr_to_cap(guest_pcr_bit);
|
||||
if (!(cap & nested_capabilities))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -138,6 +138,7 @@ static int gs_msg_ops_vcpu_fill_info(struct kvmppc_gs_buff *gsb,
|
||||
vector128 v;
|
||||
int rc, i;
|
||||
u16 iden;
|
||||
u32 arch_compat = 0;
|
||||
|
||||
vcpu = gsm->data;
|
||||
|
||||
@ -347,8 +348,23 @@ static int gs_msg_ops_vcpu_fill_info(struct kvmppc_gs_buff *gsb,
|
||||
break;
|
||||
}
|
||||
case KVMPPC_GSID_LOGICAL_PVR:
|
||||
rc = kvmppc_gse_put_u32(gsb, iden,
|
||||
vcpu->arch.vcore->arch_compat);
|
||||
/*
|
||||
* Though 'arch_compat == 0' would mean the default
|
||||
* compatibility, arch_compat, being a Guest Wide
|
||||
* Element, cannot be filled with a value of 0 in GSB
|
||||
* as this would result into a kernel trap.
|
||||
* Hence, when `arch_compat == 0`, arch_compat should
|
||||
* default to L1's PVR.
|
||||
*/
|
||||
if (!vcpu->arch.vcore->arch_compat) {
|
||||
if (cpu_has_feature(CPU_FTR_ARCH_31))
|
||||
arch_compat = PVR_ARCH_31;
|
||||
else if (cpu_has_feature(CPU_FTR_ARCH_300))
|
||||
arch_compat = PVR_ARCH_300;
|
||||
} else {
|
||||
arch_compat = vcpu->arch.vcore->arch_compat;
|
||||
}
|
||||
rc = kvmppc_gse_put_u32(gsb, iden, arch_compat);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -35,6 +35,8 @@ struct pci_controller *init_phb_dynamic(struct device_node *dn)
|
||||
|
||||
pseries_msi_allocate_domains(phb);
|
||||
|
||||
ppc_iommu_register_device(phb);
|
||||
|
||||
/* Create EEH devices for the PHB */
|
||||
eeh_phb_pe_create(phb);
|
||||
|
||||
@ -76,6 +78,8 @@ int remove_phb_dynamic(struct pci_controller *phb)
|
||||
}
|
||||
}
|
||||
|
||||
ppc_iommu_unregister_device(phb);
|
||||
|
||||
pseries_msi_free_domains(phb);
|
||||
|
||||
/* Keep a reference so phb isn't freed yet */
|
||||
|
Loading…
Reference in New Issue
Block a user