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:
@ -30,6 +30,16 @@ void *pci_traverse_device_nodes(struct device_node *start,
|
|||||||
void *data);
|
void *data);
|
||||||
extern void pci_devs_phb_init_dynamic(struct pci_controller *phb);
|
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 */
|
/* From rtas_pci.h */
|
||||||
extern void init_pci_config_tokens (void);
|
extern void init_pci_config_tokens (void);
|
||||||
extern unsigned long get_phb_buid (struct device_node *);
|
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;
|
struct pci_controller *hose;
|
||||||
|
|
||||||
if (!dev_is_pci(dev))
|
if (!dev_is_pci(dev))
|
||||||
return ERR_PTR(-EPERM);
|
return ERR_PTR(-ENODEV);
|
||||||
|
|
||||||
pdev = to_pci_dev(dev);
|
pdev = to_pci_dev(dev);
|
||||||
hose = pdev->bus->sysdata;
|
hose = pdev->bus->sysdata;
|
||||||
@ -1409,6 +1409,21 @@ static const struct attribute_group *spapr_tce_iommu_groups[] = {
|
|||||||
NULL,
|
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
|
* This registers IOMMU devices of PHBs. This needs to happen
|
||||||
* after core_initcall(iommu_init) + postcore_initcall(pci_driver_init) and
|
* 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;
|
struct pci_controller *hose;
|
||||||
|
|
||||||
list_for_each_entry(hose, &hose_list, list_node) {
|
list_for_each_entry(hose, &hose_list, list_node) {
|
||||||
iommu_device_sysfs_add(&hose->iommu, hose->parent,
|
ppc_iommu_register_device(hose);
|
||||||
spapr_tce_iommu_groups, "iommu-phb%04x",
|
|
||||||
hose->global_number);
|
|
||||||
iommu_device_register(&hose->iommu, &spapr_tce_iommu_ops,
|
|
||||||
hose->parent);
|
|
||||||
}
|
}
|
||||||
return 0;
|
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 */
|
/* Dummy value used in computing PCR value below */
|
||||||
#define PCR_ARCH_31 (PCR_ARCH_300 << 1)
|
#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)
|
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;
|
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;
|
break;
|
||||||
case PVR_ARCH_300:
|
case PVR_ARCH_300:
|
||||||
guest_pcr_bit = PCR_ARCH_300;
|
guest_pcr_bit = PCR_ARCH_300;
|
||||||
cap = H_GUEST_CAP_POWER9;
|
|
||||||
break;
|
break;
|
||||||
case PVR_ARCH_31:
|
case PVR_ARCH_31:
|
||||||
guest_pcr_bit = PCR_ARCH_31;
|
guest_pcr_bit = PCR_ARCH_31;
|
||||||
cap = H_GUEST_CAP_POWER10;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@ -440,6 +456,12 @@ static int kvmppc_set_arch_compat(struct kvm_vcpu *vcpu, u32 arch_compat)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (kvmhv_on_pseries() && kvmhv_is_nestedv2()) {
|
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))
|
if (!(cap & nested_capabilities))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -138,6 +138,7 @@ static int gs_msg_ops_vcpu_fill_info(struct kvmppc_gs_buff *gsb,
|
|||||||
vector128 v;
|
vector128 v;
|
||||||
int rc, i;
|
int rc, i;
|
||||||
u16 iden;
|
u16 iden;
|
||||||
|
u32 arch_compat = 0;
|
||||||
|
|
||||||
vcpu = gsm->data;
|
vcpu = gsm->data;
|
||||||
|
|
||||||
@ -347,8 +348,23 @@ static int gs_msg_ops_vcpu_fill_info(struct kvmppc_gs_buff *gsb,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case KVMPPC_GSID_LOGICAL_PVR:
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,6 +35,8 @@ struct pci_controller *init_phb_dynamic(struct device_node *dn)
|
|||||||
|
|
||||||
pseries_msi_allocate_domains(phb);
|
pseries_msi_allocate_domains(phb);
|
||||||
|
|
||||||
|
ppc_iommu_register_device(phb);
|
||||||
|
|
||||||
/* Create EEH devices for the PHB */
|
/* Create EEH devices for the PHB */
|
||||||
eeh_phb_pe_create(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);
|
pseries_msi_free_domains(phb);
|
||||||
|
|
||||||
/* Keep a reference so phb isn't freed yet */
|
/* Keep a reference so phb isn't freed yet */
|
||||||
|
Reference in New Issue
Block a user