Commit ab0a97cf authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
parents 91403d50 20c8c4da
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -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 *);
+17 −6
Original line number Diff line number Diff line
@@ -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;
}
+24 −2
Original line number Diff line number Diff line
@@ -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;
	}
+18 −2
Original line number Diff line number Diff line
@@ -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;
		}

+4 −0
Original line number Diff line number Diff line
@@ -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 */