From: Cédric Le Goater <clg@kaod.org> Date: 2021-07-01 13:29:35
Hello,
This series adds support for MSI IRQ domains on top of the XICS (P8)
and XIVE (P9/P10) IRQ domains for the PowerNV (baremetal) and pSeries
(VM) platforms. It should simplify and improve IRQ affinity of PCI
MSIs under these PowerPC platforms, specially for drivers distributing
multiple RX/TX queues on the different CPUs of the system.
Data locality can still be improved with an interrupt controller node
per chip but this requires FW changes. It could be done under OPAL.
The patchset has a large impact but it is well contained under the MSI
support. Initial tests were done on the P8, P9 and P10 PowerNV and
pSeries platforms, under the KVM and PowerVM hypervisor. PCI passthrough
was tested on P8/KVM, P9/KVM and P9/pVM with both interrupt modes.
P8 passthrough has some optimization to EOI MSIs when under real mode :
e3c13e56a471 ("KVM: PPC: Book3S HV: Handle passthrough interrupts in guest")
5d375199ea96 ("KVM: PPC: Book3S HV: Set server for passed-through interrupts")
They give us a ~10% bandwidth improvement on some 100G adapters
(Thanks Alexey), so it's good to keep but they require access to the
low level IRQ domain of the machine. It should be possible to rework
the code and use the MSI IRQ domains instead but for now, it's simpler
to keep the bypass. That can come later.
The P8/CAPI driver is also impacted. Tests were done on a Firestone
system with a memory AFU.
Thanks,
C.
Changes since v2 :
- Included some CONFIG_IRQ_DOMAIN_HIERARCHY ifdefs
- Microwatt fixes for ICS native
- Removed irqd_is_started() check when setting the affinity
Cédric Le Goater (32):
powerpc/pseries/pci: Introduce __find_pe_total_msi()
powerpc/pseries/pci: Introduce rtas_prepare_msi_irqs()
powerpc/xive: Add support for IRQ domain hierarchy
powerpc/xive: Ease debugging of xive_irq_set_affinity()
powerpc/pseries/pci: Add MSI domains
powerpc/xive: Drop unmask of MSIs at startup
powerpc/xive: Remove irqd_is_started() check when setting the affinity
powerpc/pseries/pci: Add a domain_free_irqs() handler
powerpc/pseries/pci: Add a msi_free() handler to clear XIVE data
powerpc/pseries/pci: Add support of MSI domains to PHB hotplug
powerpc/powernv/pci: Introduce __pnv_pci_ioda_msi_setup()
powerpc/powernv/pci: Add MSI domains
KVM: PPC: Book3S HV: Use the new IRQ chip to detect passthrough
interrupts
KVM: PPC: Book3S HV: XIVE: Change interface of passthrough interrupt
routines
KVM: PPC: Book3S HV: XIVE: Fix mapping of passthrough interrupts
powerpc/xics: Remove ICS list
powerpc/xics: Rename the map handler in a check handler
powerpc/xics: Give a name to the default XICS IRQ domain
powerpc/xics: Add debug logging to the set_irq_affinity handlers
powerpc/xics: Add support for IRQ domain hierarchy
powerpc/powernv/pci: Customize the MSI EOI handler to support PHB3
powerpc/pci: Drop XIVE restriction on MSI domains
powerpc/xics: Drop unmask of MSIs at startup
powerpc/pseries/pci: Drop unused MSI code
powerpc/powernv/pci: Drop unused MSI code
powerpc/powernv/pci: Adapt is_pnv_opal_msi() to detect passthrough
interrupt
powerpc/xics: Fix IRQ migration
powerpc/powernv/pci: Set the IRQ chip data for P8/CXL devices
powerpc/powernv/pci: Rework pnv_opal_pci_msi_eoi()
KVM: PPC: Book3S HV: XICS: Fix mapping of passthrough interrupts
powerpc/xive: Use XIVE domain under xmon and debugfs
genirq: Improve "hwirq" output in /proc and /sys/
arch/powerpc/include/asm/kvm_ppc.h | 4 +-
arch/powerpc/include/asm/pci-bridge.h | 5 +
arch/powerpc/include/asm/pnv-pci.h | 2 +-
arch/powerpc/include/asm/xics.h | 3 +-
arch/powerpc/include/asm/xive.h | 1 +
arch/powerpc/platforms/powernv/pci.h | 6 -
arch/powerpc/platforms/pseries/pseries.h | 2 +
arch/powerpc/kernel/pci-common.c | 6 +
arch/powerpc/kvm/book3s_hv.c | 18 +-
arch/powerpc/kvm/book3s_hv_rm_xics.c | 8 +-
arch/powerpc/kvm/book3s_xive.c | 18 +-
arch/powerpc/platforms/powernv/pci-ioda.c | 256 ++++++++++++++++--
arch/powerpc/platforms/powernv/pci.c | 67 -----
arch/powerpc/platforms/pseries/msi.c | 296 ++++++++++++++++-----
arch/powerpc/platforms/pseries/pci_dlpar.c | 4 +
arch/powerpc/platforms/pseries/setup.c | 2 +
arch/powerpc/sysdev/xics/ics-native.c | 13 +-
arch/powerpc/sysdev/xics/ics-opal.c | 40 +--
arch/powerpc/sysdev/xics/ics-rtas.c | 40 +--
arch/powerpc/sysdev/xics/xics-common.c | 129 ++++++---
arch/powerpc/sysdev/xive/common.c | 98 +++++--
kernel/irq/irqdesc.c | 2 +-
kernel/irq/irqdomain.c | 1 +
kernel/irq/proc.c | 2 +-
24 files changed, 710 insertions(+), 313 deletions(-)
--
2.31.1
From: Cédric Le Goater <clg@kaod.org> Date: 2021-07-01 13:28:40
In the early days of XIVE support, commit cffb717ceb8e ("powerpc/xive:
Ensure active irqd when setting affinity") tried to fix an issue
related to interrupt migration. If the root cause was related to CPU
unplug, it should have been fixed and there is no reason to keep the
irqd_is_started() check. This test is also breaking affinity setting
of MSIs which can set before starting the associated IRQ.
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
arch/powerpc/sysdev/xive/common.c | 4 ----
1 file changed, 4 deletions(-)
@@ -719,10 +719,6 @@ static int xive_irq_set_affinity(struct irq_data *d,if(cpumask_any_and(cpumask,cpu_online_mask)>=nr_cpu_ids)return-EINVAL;-/* Don't do anything if the interrupt isn't started */-if(!irqd_is_started(d))-returnIRQ_SET_MASK_OK;-/**Ifexistingtargetisalreadyinthenewmask,andis*onlinethendonothing.
From: Cédric Le Goater <clg@kaod.org> Date: 2021-07-01 13:28:58
pr_debug() is easier to activate and it helps to know how the kernel
configures the HW when tweaking the IRQ subsystem.
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
arch/powerpc/sysdev/xive/common.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
From: Cédric Le Goater <clg@kaod.org> Date: 2021-07-01 13:29:17
Two IRQ domains are added on top of default machine IRQ domain.
First, the top level "pSeries-PCI-MSI" domain deals with the MSI
specificities. In this domain, the HW IRQ numbers are generated by the
PCI MSI layer, they compose a unique ID for an MSI source with the PCI
device identifier and the MSI vector number.
These numbers can be quite large on a pSeries machine running under
the IBM Hypervisor and /sys/kernel/irq/ and /proc/interrupts will
require small fixes to show them correctly.
Second domain is the in-the-middle "pSeries-MSI" domain which acts as
a proxy between the PCI MSI subsystem and the machine IRQ subsystem.
It usually allocate the MSI vector numbers but, on pSeries machines,
this is done by the RTAS FW and RTAS returns IRQ numbers in the IRQ
number space of the machine. This is why the in-the-middle "pSeries-MSI"
domain has the same HW IRQ numbers as its parent domain.
Only the XIVE (P9/P10) parent domain is supported for now. We still
need to add support for IRQ domain hierarchy under XICS.
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
arch/powerpc/include/asm/pci-bridge.h | 5 +
arch/powerpc/platforms/pseries/pseries.h | 1 +
arch/powerpc/kernel/pci-common.c | 6 +
arch/powerpc/platforms/pseries/msi.c | 185 +++++++++++++++++++++++
arch/powerpc/platforms/pseries/setup.c | 2 +
5 files changed, 199 insertions(+)
@@ -126,6 +126,11 @@ struct pci_controller {#endif /* CONFIG_PPC64 */void*private_data;++/* IRQ domain hierarchy */+structirq_domain*dev_domain;+structirq_domain*msi_domain;+structfwnode_handle*fwnode;};/* These are used for config access before all the PCI probing
From: Cédric Le Goater <clg@kaod.org> Date: 2021-07-01 13:29:52
The RTAS firmware can not disable one MSI at a time. It's all or
nothing. We need a custom free IRQ handler for that.
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
arch/powerpc/platforms/pseries/msi.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
From: Cédric Le Goater <clg@kaod.org> Date: 2021-07-01 13:30:15
It will help to size the PCI MSI domain.
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
arch/powerpc/platforms/pseries/msi.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
From: Cédric Le Goater <clg@kaod.org> Date: 2021-07-01 13:30:34
It will be used as a 'compose_msg' handler of the MSI domain introduced
later.
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
arch/powerpc/platforms/powernv/pci-ioda.c | 28 +++++++++++++++++++----
1 file changed, 23 insertions(+), 5 deletions(-)
@@ -2016,15 +2016,17 @@ bool is_pnv_opal_msi(struct irq_chip *chip)}EXPORT_SYMBOL_GPL(is_pnv_opal_msi);-staticintpnv_pci_ioda_msi_setup(structpnv_phb*phb,structpci_dev*dev,-unsignedinthwirq,unsignedintvirq,-unsignedintis_64,structmsi_msg*msg)+staticint__pnv_pci_ioda_msi_setup(structpnv_phb*phb,structpci_dev*dev,+unsignedintxive_num,+unsignedintis_64,structmsi_msg*msg){structpnv_ioda_pe*pe=pnv_ioda_get_pe(dev);-unsignedintxive_num=hwirq-phb->msi_base;__be32data;intrc;+dev_dbg(&dev->dev,"%s: setup %s-bit MSI for vector #%d\n",__func__,+is_64?"64":"32",xive_num);+/* No PE assigned ? bail out ... no MSI for you ! */if(pe==NULL)return-ENXIO;
@@ -2072,12 +2074,28 @@ static int pnv_pci_ioda_msi_setup(struct pnv_phb *phb, struct pci_dev *dev,}msg->data=be32_to_cpu(data);+return0;+}++staticintpnv_pci_ioda_msi_setup(structpnv_phb*phb,structpci_dev*dev,+unsignedinthwirq,unsignedintvirq,+unsignedintis_64,structmsi_msg*msg)+{+structpnv_ioda_pe*pe=pnv_ioda_get_pe(dev);+unsignedintxive_num=hwirq-phb->msi_base;+intrc;++rc=__pnv_pci_ioda_msi_setup(phb,dev,xive_num,is_64,msg);+if(rc)+returnrc;++/* P8 only */pnv_set_msi_irq_chip(phb,virq);pr_devel("%s: %s-bit MSI on hwirq %x (xive #%d),"" address=%x_%08x data=%x PE# %x\n",pci_name(dev),is_64?"64":"32",hwirq,xive_num,-msg->address_hi,msg->address_lo,data,pe->pe_number);+msg->address_hi,msg->address_lo,msg->data,pe->pe_number);return0;}
From: Cédric Le Goater <clg@kaod.org> Date: 2021-07-01 13:30:52
This is very similar to the MSI domains of the pSeries platform. The
MSI allocator is directly handled under the Linux PHB in the
in-the-middle "PNV-MSI" domain.
Only the XIVE (P9/P10) parent domain is supported for now. Support for
XICS will come later.
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
arch/powerpc/platforms/powernv/pci-ioda.c | 188 ++++++++++++++++++++++
1 file changed, 188 insertions(+)
From: Cédric Le Goater <clg@kaod.org> Date: 2021-07-01 13:31:11
Passthrough PCI MSI interrupts are detected in KVM with a check on a
specific EOI handler (P8) or on XIVE (P9). We can now check the
PCI-MSI IRQ chip which is cleaner.
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
arch/powerpc/kvm/book3s_hv.c | 2 +-
arch/powerpc/platforms/powernv/pci-ioda.c | 4 +++-
2 files changed, 4 insertions(+), 2 deletions(-)
@@ -5260,7 +5260,7 @@ static int kvmppc_set_passthru_irq(struct kvm *kvm, int host_irq, int guest_gsi)*whatourreal-modeEOIcodedoes,oraXIVEinterrupt*/chip=irq_data_get_irq_chip(&desc->irq_data);-if(!chip||!(is_pnv_opal_msi(chip)||is_xive_irq(chip))){+if(!chip||!is_pnv_opal_msi(chip)){pr_warn("kvmppc_set_passthru_irq_hv: Could not assign IRQ map for (%d,%d)\n",host_irq,guest_gsi);mutex_unlock(&kvm->lock);
From: Cédric Le Goater <clg@kaod.org> Date: 2021-07-01 13:31:29
This splits the routine setting the MSIs in two parts: allocation of
MSIs for the PCI device at the FW level (RTAS) and the actual mapping
and activation of the IRQs.
rtas_prepare_msi_irqs() will serve as a handler for the PCI MSI domain.
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
arch/powerpc/platforms/pseries/msi.c | 23 +++++++++++++++++++----
1 file changed, 19 insertions(+), 4 deletions(-)
@@ -456,6 +455,22 @@ static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec_in, int type)returnrc;}+return0;+}++staticintrtas_setup_msi_irqs(structpci_dev*pdev,intnvec_in,inttype)+{+structpci_dn*pdn;+inthwirq,virq,i;+intrc;+structmsi_desc*entry;+structmsi_msgmsg;++rc=rtas_prepare_msi_irqs(pdev,nvec_in,type,NULL);+if(rc)+returnrc;++pdn=pci_get_pdn(pdev);i=0;for_each_pci_msi_entry(entry,pdev){hwirq=rtas_query_irq_number(pdn,i++);
From: Cédric Le Goater <clg@kaod.org> Date: 2021-07-01 13:31:46
We always had only one ICS per machine. Simplify the XICS driver by
removing the ICS list.
The ICS stored in the chip data of the XICS domain becomes useless and
we don't need it anymore to migrate away IRQs from a CPU. This will be
removed in a subsequent patch.
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
arch/powerpc/sysdev/xics/xics-common.c | 45 +++++++++++---------------
1 file changed, 19 insertions(+), 26 deletions(-)
@@ -198,7 +197,6 @@ void xics_migrate_irqs_away(void)structirq_chip*chip;longserver;unsignedlongflags;-structics*ics;/* We can't set affinity on ISA interrupts */if(virq<NUM_ISA_INTERRUPTS)
@@ -219,13 +217,10 @@ void xics_migrate_irqs_away(void)raw_spin_lock_irqsave(&desc->lock,flags);/* Locate interrupt server */-server=-1;-ics=irq_desc_get_chip_data(desc);-if(ics)-server=ics->get_server(ics,irq);+server=xics_ics->get_server(xics_ics,irq);if(server<0){-printk(KERN_ERR"%s: Can't find server for irq %d\n",-__func__,irq);+pr_err("%s: Can't find server for irq %d/%x\n",+__func__,virq,irq);gotounlock;}
@@ -307,13 +302,9 @@ int xics_get_irq_server(unsigned int virq, const struct cpumask *cpumask,staticintxics_host_match(structirq_domain*h,structdevice_node*node,enumirq_domain_bus_tokenbus_token){-structics*ics;--list_for_each_entry(ics,&ics_list,link)-if(ics->host_match(ics,node))-return1;--return0;+if(WARN_ON(!xics_ics))+return0;+returnxics_ics->host_match(xics_ics,node)?1:0;}/* Dummies */
@@ -348,12 +337,14 @@ static int xics_host_map(struct irq_domain *h, unsigned int virq,return0;}+if(WARN_ON(!xics_ics))+return-EINVAL;+/* Let the ICS setup the chip data */-list_for_each_entry(ics,&ics_list,link)-if(ics->map(ics,virq)==0)-return0;+if(xics_ics->map(xics_ics,virq))+return-EINVAL;-return-EINVAL;+return0;}staticintxics_host_xlate(structirq_domain*h,structdevice_node*ct,
@@ -427,7 +418,9 @@ static void __init xics_init_host(void)void__initxics_register_ics(structics*ics){-list_add(&ics->link,&ics_list);+if(WARN_ONCE(xics_ics,"XICS: Source Controller is already defined !"))+return;+xics_ics=ics;}staticvoid__initxics_get_server_size(void)
From: Cédric Le Goater <clg@kaod.org> Date: 2021-07-01 13:32:23
PHB3s need an extra OPAL call to EOI the interrupt. The call takes an
OPAL HW IRQ number but it is translated into a vector number in OPAL.
Here, we directly use the vector number of the in-the-middle "PNV-MSI"
domain instead of grabbing the OPAL HW IRQ number in the XICS parent
domain.
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
arch/powerpc/platforms/powernv/pci-ioda.c | 23 ++++++++++++++++++++++-
1 file changed, 22 insertions(+), 1 deletion(-)
From: Cédric Le Goater <clg@kaod.org> Date: 2021-07-01 13:32:40
That was a workaround in the XIVE domain because of the lack of MSI
domain. This is now handled.
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
arch/powerpc/sysdev/xive/common.c | 10 ----------
1 file changed, 10 deletions(-)
From: Cédric Le Goater <clg@kaod.org> Date: 2021-07-01 13:32:58
Simply allocate or release the MSI domains when a PHB is inserted in
or removed from the machine.
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
arch/powerpc/platforms/pseries/pseries.h | 1 +
arch/powerpc/platforms/pseries/msi.c | 10 ++++++++++
arch/powerpc/platforms/pseries/pci_dlpar.c | 4 ++++
3 files changed, 15 insertions(+)
@@ -33,6 +33,8 @@ struct pci_controller *init_phb_dynamic(struct device_node *dn)pci_devs_phb_init_dynamic(phb);+pseries_msi_allocate_domains(phb);+/* Create EEH devices for the PHB */eeh_phb_pe_create(phb);
@@ -74,6 +76,8 @@ int remove_phb_dynamic(struct pci_controller *phb)}}+pseries_msi_free_domains(phb);+/* Remove the PCI bus and unregister the bridge device from sysfs */phb->bus=NULL;pci_remove_bus(b);
From: Cédric Le Goater <clg@kaod.org> Date: 2021-07-01 13:33:16
MSIs should be fully managed by the PCI and IRQ subsystems now.
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
arch/powerpc/platforms/pseries/msi.c | 87 ----------------------------
1 file changed, 87 deletions(-)
@@ -111,21 +111,6 @@ static int rtas_query_irq_number(struct pci_dn *pdn, int offset)returnrtas_ret[0];}-staticvoidrtas_teardown_msi_irqs(structpci_dev*pdev)-{-structmsi_desc*entry;--for_each_pci_msi_entry(entry,pdev){-if(!entry->irq)-continue;--irq_set_msi_desc(entry->irq,NULL);-irq_dispose_mapping(entry->irq);-}--rtas_disable_msi(pdev);-}-staticintcheck_req(structpci_dev*pdev,intnvec,char*prop_name){structdevice_node*dn;
@@ -459,66 +444,6 @@ static int rtas_prepare_msi_irqs(struct pci_dev *pdev, int nvec_in, int type,return0;}-staticintrtas_setup_msi_irqs(structpci_dev*pdev,intnvec_in,inttype)-{-structpci_dn*pdn;-inthwirq,virq,i;-intrc;-structmsi_desc*entry;-structmsi_msgmsg;--rc=rtas_prepare_msi_irqs(pdev,nvec_in,type,NULL);-if(rc)-returnrc;--pdn=pci_get_pdn(pdev);-i=0;-for_each_pci_msi_entry(entry,pdev){-hwirq=rtas_query_irq_number(pdn,i++);-if(hwirq<0){-pr_debug("rtas_msi: error (%d) getting hwirq\n",rc);-returnhwirq;-}--/*-*DependingonthenumberofonlineCPUsintheoriginal-*kernel,itislikelyforCPU#0tobeofflineinakdump-*kernel.TheassociatedIRQsintheaffinitymappings-*providedbyirq_create_affinity_masks()arethusnot-*startedbyirq_startup(),asper-designformanagedIRQs.-*Thiscanbeaproblemwithmulti-queueblockdevicesdriven-*byblk-mq:suchanon-startedIRQisverylikelypaired-*withthesinglequeueenforcedbyblk-mqduringkdump(see-*blk_mq_alloc_tag_set()).Thiscausesthedevicetoremain-*silentandlikelyhangstheguestatsomepoint.-*-*Wedon'treallycareforfine-grainedaffinitywhendoing-*kdumpactually:simplyignorethepre-computedaffinity-*masksinthiscaseandletthedefaultmaskwithallCPUs-*beusedwhencreatingtheIRQmappings.-*/-if(is_kdump_kernel())-virq=irq_create_mapping(NULL,hwirq);-else-virq=irq_create_mapping_affinity(NULL,hwirq,-entry->affinity);--if(!virq){-pr_debug("rtas_msi: Failed mapping hwirq %d\n",hwirq);-return-ENOSPC;-}--dev_dbg(&pdev->dev,"rtas_msi: allocated virq %d\n",virq);-irq_set_msi_desc(virq,entry);--/* Read config space back so we can restore after reset */-__pci_read_msi_msg(entry,&msg);-entry->msg=msg;-}--return0;-}-staticintpseries_msi_ops_prepare(structirq_domain*domain,structdevice*dev,intnvec,msi_alloc_info_t*arg){
From: Cédric Le Goater <clg@kaod.org> Date: 2021-07-01 13:33:34
This adds handlers to allocate/free IRQs in a domain hierarchy. We
could try to use xive_irq_domain_map() in xive_irq_domain_alloc() but
we rely on xive_irq_alloc_data() to set the IRQ handler data and
duplicating the code is simpler.
xive_irq_free_data() needs to be called when IRQ are freed to clear
the MMIO mappings and free the XIVE handler data, xive_irq_data
structure. This is going to be a problem with MSI domains which we
will address later.
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
arch/powerpc/sysdev/xive/common.c | 64 +++++++++++++++++++++++++++++++
1 file changed, 64 insertions(+)
From: Cédric Le Goater <clg@kaod.org> Date: 2021-07-01 13:33:52
That was a workaround in the XICS domain because of the lack of MSI
domain. This is now handled.
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
arch/powerpc/sysdev/xics/ics-opal.c | 11 -----------
arch/powerpc/sysdev/xics/ics-rtas.c | 9 ---------
2 files changed, 20 deletions(-)
From: Cédric Le Goater <clg@kaod.org> Date: 2021-07-01 13:34:10
The pnv_ioda2_msi_eoi() chip handler is not used anymore for MSIs.
Simply use the check on the PSI-MSI chip.
Cc: Alexey Kardashevskiy <redacted>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
arch/powerpc/platforms/powernv/pci-ioda.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
From: Cédric Le Goater <clg@kaod.org> Date: 2021-07-01 13:34:28
The routine kvmppc_set_passthru_irq() calls kvmppc_xive_set_mapped()
and kvmppc_xive_clr_mapped() with an IRQ descriptor. Use directly the
host IRQ number to remove a useless conversion.
Add some debug.
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
arch/powerpc/include/asm/kvm_ppc.h | 4 ++--
arch/powerpc/kvm/book3s_hv.c | 4 ++--
arch/powerpc/kvm/book3s_xive.c | 17 ++++++++---------
3 files changed, 12 insertions(+), 13 deletions(-)
@@ -5303,7 +5303,7 @@ static int kvmppc_set_passthru_irq(struct kvm *kvm, int host_irq, int guest_gsi)pimap->n_mapped++;if(xics_on_xive())-rc=kvmppc_xive_set_mapped(kvm,guest_gsi,desc);+rc=kvmppc_xive_set_mapped(kvm,guest_gsi,host_irq);elsekvmppc_xics_set_mapped(kvm,guest_gsi,desc->irq_data.hwirq);if(rc)
@@ -5344,7 +5344,7 @@ static int kvmppc_clr_passthru_irq(struct kvm *kvm, int host_irq, int guest_gsi)}if(xics_on_xive())-rc=kvmppc_xive_clr_mapped(kvm,guest_gsi,pimap->mapped[i].desc);+rc=kvmppc_xive_clr_mapped(kvm,guest_gsi,host_irq);elsekvmppc_xics_clr_mapped(kvm,guest_gsi,pimap->mapped[i].r_hwirq);
@@ -958,7 +958,7 @@ int kvmppc_xive_set_mapped(struct kvm *kvm, unsigned long guest_irq,*/rc=irq_set_vcpu_affinity(host_irq,state);if(rc){-pr_err("Failed to set VCPU affinity for irq %d\n",host_irq);+pr_err("Failed to set VCPU affinity for host IRQ %ld\n",host_irq);returnrc;}
@@ -1018,12 +1018,11 @@ int kvmppc_xive_set_mapped(struct kvm *kvm, unsigned long guest_irq,EXPORT_SYMBOL_GPL(kvmppc_xive_set_mapped);intkvmppc_xive_clr_mapped(structkvm*kvm,unsignedlongguest_irq,-structirq_desc*host_desc)+unsignedlonghost_irq){structkvmppc_xive*xive=kvm->arch.xive;structkvmppc_xive_src_block*sb;structkvmppc_xive_irq_state*state;-unsignedinthost_irq=irq_desc_get_irq(host_desc);u16idx;u8prio;intrc;
@@ -1031,7 +1030,7 @@ int kvmppc_xive_clr_mapped(struct kvm *kvm, unsigned long guest_irq,if(!xive)return-ENODEV;-pr_devel("clr_mapped girq 0x%lx...\n",guest_irq);+pr_debug("%s: GIRQ 0x%lx host IRQ %ld\n",__func__,guest_irq,host_irq);sb=kvmppc_xive_find_source(xive,guest_irq,&idx);if(!sb)
@@ -1058,7 +1057,7 @@ int kvmppc_xive_clr_mapped(struct kvm *kvm, unsigned long guest_irq,/* Release the passed-through interrupt to the host */rc=irq_set_vcpu_affinity(host_irq,NULL);if(rc){-pr_err("Failed to clr VCPU affinity for irq %d\n",host_irq);+pr_err("Failed to clr VCPU affinity for host IRQ %ld\n",host_irq);returnrc;}
From: Cédric Le Goater <clg@kaod.org> Date: 2021-07-01 13:34:46
desc->irq_data points to the top level IRQ data descriptor which is
not necessarily in the XICS IRQ domain. MSIs are in another domain for
instance. Fix that by looking for a mapping on the low level XICS IRQ
domain.
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
arch/powerpc/sysdev/xics/xics-common.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
@@ -183,6 +183,8 @@ void xics_migrate_irqs_away(void)unsignedintirq,virq;structirq_desc*desc;+pr_debug("%s: CPU %u\n",__func__,cpu);+/* If we used to be the default server, move to the new "boot_cpuid" */if(hw_cpu==xics_default_server)xics_update_irq_servers();
@@ -197,6 +199,7 @@ void xics_migrate_irqs_away(void)structirq_chip*chip;longserver;unsignedlongflags;+structirq_data*irqd;/* We can't set affinity on ISA interrupts */if(virq<NUM_ISA_INTERRUPTS)
@@ -204,9 +207,11 @@ void xics_migrate_irqs_away(void)/* We only need to migrate enabled IRQS */if(!desc->action)continue;-if(desc->irq_data.domain!=xics_host)+/* We need a mapping in the XICS IRQ domain */+irqd=irq_domain_get_irq_data(xics_host,virq);+if(!irqd)continue;-irq=desc->irq_data.hwirq;+irq=irqd_to_hwirq(irqd);/* We need to get IPIs still. */if(irq==XICS_IPI||irq==XICS_IRQ_SPURIOUS)continue;
From: Cédric Le Goater <clg@kaod.org> Date: 2021-07-01 13:35:13
The MSI domain clears the IRQ with msi_domain_free(), which calls
irq_domain_free_irqs_top(), which clears the handler data. This is a
problem for the XIVE controller since we need to unmap MMIO pages and
free a specific XIVE structure.
The 'msi_free()' handler is called before irq_domain_free_irqs_top()
when the handler data is still available. Use that to clear the XIVE
controller data.
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
arch/powerpc/include/asm/xive.h | 1 +
arch/powerpc/platforms/pseries/msi.c | 16 +++++++++++++++-
arch/powerpc/sysdev/xive/common.c | 5 ++++-
3 files changed, 20 insertions(+), 2 deletions(-)
@@ -160,73 +160,6 @@ int pnv_pci_set_power_state(uint64_t id, uint8_t state, struct opal_msg *msg)}EXPORT_SYMBOL_GPL(pnv_pci_set_power_state);-intpnv_setup_msi_irqs(structpci_dev*pdev,intnvec,inttype)-{-structpnv_phb*phb=pci_bus_to_pnvhb(pdev->bus);-structmsi_desc*entry;-structmsi_msgmsg;-inthwirq;-unsignedintvirq;-intrc;--if(WARN_ON(!phb)||!phb->msi_bmp.bitmap)-return-ENODEV;--if(pdev->no_64bit_msi&&!phb->msi32_support)-return-ENODEV;--for_each_pci_msi_entry(entry,pdev){-if(!entry->msi_attrib.is_64&&!phb->msi32_support){-pr_warn("%s: Supports only 64-bit MSIs\n",-pci_name(pdev));-return-ENXIO;-}-hwirq=msi_bitmap_alloc_hwirqs(&phb->msi_bmp,1);-if(hwirq<0){-pr_warn("%s: Failed to find a free MSI\n",-pci_name(pdev));-return-ENOSPC;-}-virq=irq_create_mapping(NULL,phb->msi_base+hwirq);-if(!virq){-pr_warn("%s: Failed to map MSI to linux irq\n",-pci_name(pdev));-msi_bitmap_free_hwirqs(&phb->msi_bmp,hwirq,1);-return-ENOMEM;-}-rc=phb->msi_setup(phb,pdev,phb->msi_base+hwirq,-virq,entry->msi_attrib.is_64,&msg);-if(rc){-pr_warn("%s: Failed to setup MSI\n",pci_name(pdev));-irq_dispose_mapping(virq);-msi_bitmap_free_hwirqs(&phb->msi_bmp,hwirq,1);-returnrc;-}-irq_set_msi_desc(virq,entry);-pci_write_msi_msg(virq,&msg);-}-return0;-}--voidpnv_teardown_msi_irqs(structpci_dev*pdev)-{-structpnv_phb*phb=pci_bus_to_pnvhb(pdev->bus);-structmsi_desc*entry;-irq_hw_number_thwirq;--if(WARN_ON(!phb))-return;--for_each_pci_msi_entry(entry,pdev){-if(!entry->irq)-continue;-hwirq=virq_to_hw(entry->irq);-irq_set_msi_desc(entry->irq,NULL);-irq_dispose_mapping(entry->irq);-msi_bitmap_free_hwirqs(&phb->msi_bmp,hwirq-phb->msi_base,1);-}-}-/* Nicely print the contents of the PE State Tables (PEST). */staticvoidpnv_pci_dump_pest(__be64pestA[],__be64pestB[],intpest_size){
From: Cédric Le Goater <clg@kaod.org> Date: 2021-07-01 13:35:49
pnv_opal_pci_msi_eoi() is called from KVM to EOI passthrough interrupts
when in real mode. Adding MSI domain broke the hack using the
'ioda.irq_chip' field to deduce the owning PHB. Fix that by using the
IRQ chip data in the MSI domain.
The 'ioda.irq_chip' field is now unused and could be removed from the
pnv_phb struct.
Cc: Alexey Kardashevskiy <redacted>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
arch/powerpc/include/asm/pnv-pci.h | 2 +-
arch/powerpc/kvm/book3s_hv_rm_xics.c | 8 ++++----
arch/powerpc/platforms/powernv/pci-ioda.c | 17 +++++++++++++----
3 files changed, 18 insertions(+), 9 deletions(-)
From: Cédric Le Goater <clg@kaod.org> Date: 2021-07-01 13:36:07
It really helps to know how the HW is configured when tweaking the IRQ
subsystem.
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
arch/powerpc/sysdev/xics/ics-opal.c | 2 +-
arch/powerpc/sysdev/xics/ics-rtas.c | 3 +++
2 files changed, 4 insertions(+), 1 deletion(-)
From: Cédric Le Goater <clg@kaod.org> Date: 2021-07-01 13:36:24
XICS doesn't have any state associated with the IRQ. The support is
straightforward and simpler than for XIVE.
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
arch/powerpc/sysdev/xics/xics-common.c | 41 ++++++++++++++++++++++++++
1 file changed, 41 insertions(+)
From: Cédric Le Goater <clg@kaod.org> Date: 2021-07-01 13:36:42
This moves the IRQ initialization done under the different ICS backends
in the common part of XICS. The 'map' handler becomes a simple 'check'
on the HW IRQ at the FW level.
As we don't need an ICS anymore in xics_migrate_irqs_away(), the XICS
domain does not set a chip data for the IRQ.
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
arch/powerpc/include/asm/xics.h | 3 ++-
arch/powerpc/sysdev/xics/ics-native.c | 13 +++++-------
arch/powerpc/sysdev/xics/ics-opal.c | 27 +++++++++----------------
arch/powerpc/sysdev/xics/ics-rtas.c | 28 +++++++++-----------------
arch/powerpc/sysdev/xics/xics-common.c | 15 ++++++++------
5 files changed, 36 insertions(+), 50 deletions(-)
@@ -89,10 +89,11 @@ static inline int ics_opal_init(void) { return -ENODEV; }/* ICS instance, hooked up to chip_data of an irq */structics{structlist_headlink;-int(*map)(structics*ics,unsignedintvirq);+int(*check)(structics*ics,unsignedinthwirq);void(*mask_unknown)(structics*ics,unsignedlongvec);long(*get_server)(structics*ics,unsignedlongvec);int(*host_match)(structics*ics,structdevice_node*node);+structirq_chip*chip;chardata[];};
@@ -157,26 +157,13 @@ static struct irq_chip ics_opal_irq_chip = {.irq_retrigger=xics_retrigger,};-staticintics_opal_map(structics*ics,unsignedintvirq);-staticvoidics_opal_mask_unknown(structics*ics,unsignedlongvec);-staticlongics_opal_get_server(structics*ics,unsignedlongvec);-staticintics_opal_host_match(structics*ics,structdevice_node*node){return1;}-/* Only one global & state struct ics */-staticstructicsics_hal={-.map=ics_opal_map,-.mask_unknown=ics_opal_mask_unknown,-.get_server=ics_opal_get_server,-.host_match=ics_opal_host_match,-};--staticintics_opal_map(structics*ics,unsignedintvirq)+staticintics_opal_check(structics*ics,unsignedinthw_irq){-unsignedinthw_irq=(unsignedint)virq_to_hw(virq);int64_trc;__be16server;int8_tpriority;
@@ -189,9 +176,6 @@ static int ics_opal_map(struct ics *ics, unsigned int virq)if(rc!=OPAL_SUCCESS)return-ENXIO;-irq_set_chip_and_handler(virq,&ics_opal_irq_chip,handle_fasteoi_irq);-irq_set_chip_data(virq,&ics_hal);-return0;}
@@ -222,6 +206,15 @@ static long ics_opal_get_server(struct ics *ics, unsigned long vec)returnics_opal_unmangle_server(be16_to_cpu(server));}+/* Only one global & state struct ics */+staticstructicsics_hal={+.check=ics_opal_check,+.mask_unknown=ics_opal_mask_unknown,+.get_server=ics_opal_get_server,+.host_match=ics_opal_host_match,+.chip=&ics_opal_irq_chip,+};+int__initics_opal_init(void){if(!firmware_has_feature(FW_FEATURE_OPAL))
@@ -24,19 +24,6 @@ static int ibm_set_xive;staticintibm_int_on;staticintibm_int_off;-staticintics_rtas_map(structics*ics,unsignedintvirq);-staticvoidics_rtas_mask_unknown(structics*ics,unsignedlongvec);-staticlongics_rtas_get_server(structics*ics,unsignedlongvec);-staticintics_rtas_host_match(structics*ics,structdevice_node*node);--/* Only one global & state struct ics */-staticstructicsics_rtas={-.map=ics_rtas_map,-.mask_unknown=ics_rtas_mask_unknown,-.get_server=ics_rtas_get_server,-.host_match=ics_rtas_host_match,-};-staticvoidics_rtas_unmask_irq(structirq_data*d){unsignedinthw_irq=(unsignedint)irqd_to_hwirq(d);
@@ -183,9 +169,6 @@ static int ics_rtas_map(struct ics *ics, unsigned int virq)if(rc)return-ENXIO;-irq_set_chip_and_handler(virq,&ics_rtas_irq_chip,handle_fasteoi_irq);-irq_set_chip_data(virq,&ics_rtas);-return0;}
@@ -213,6 +196,15 @@ static int ics_rtas_host_match(struct ics *ics, struct device_node *node)return!of_device_is_compatible(node,"chrp,iic");}+/* Only one global & state struct ics */+staticstructicsics_rtas={+.check=ics_rtas_check,+.mask_unknown=ics_rtas_mask_unknown,+.get_server=ics_rtas_get_server,+.host_match=ics_rtas_host_match,+.chip=&ics_rtas_irq_chip,+};+__initintics_rtas_init(void){ibm_get_xive=rtas_token("ibm,get-xive");
@@ -331,7 +331,7 @@ static int xics_host_map(struct irq_domain *h, unsigned int virq,irq_clear_status_flags(virq,IRQ_LEVEL);/* Don't call into ICS for IPIs */-if(hw==XICS_IPI){+if(hwirq==XICS_IPI){irq_set_chip_and_handler(virq,&xics_ipi_chip,handle_percpu_irq);return0;
@@ -340,10 +340,13 @@ static int xics_host_map(struct irq_domain *h, unsigned int virq,if(WARN_ON(!xics_ics))return-EINVAL;-/* Let the ICS setup the chip data */-if(xics_ics->map(xics_ics,virq))+if(xics_ics->check(xics_ics,hwirq))return-EINVAL;+/* No chip data for the XICS domain */+irq_domain_set_info(domain,virq,hwirq,xics_ics->chip,+NULL,handle_fasteoi_irq,NULL,NULL);+return0;}
From: Cédric Le Goater <clg@kaod.org> Date: 2021-07-01 13:37:24
PCI MSI interrupt numbers are now mapped in a PCI-MSI domain but the
underlying calls handling the passthrough of the interrupt in the
guest need a number in the XIVE IRQ domain.
Use the IRQ data mapped in the XIVE IRQ domain and not the one in the
PCI-MSI domain.
Cc: Thomas Gleixner <redacted>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
arch/powerpc/kvm/book3s_xive.c | 3 ++-
kernel/irq/irqdomain.c | 1 +
2 files changed, 3 insertions(+), 1 deletion(-)
From: Cédric Le Goater <clg@kaod.org> Date: 2021-07-01 13:37:42
The HW IRQ numbers generated by the PCI MSI layer can be quite large
on a pSeries machine when running under the IBM Hypervisor and they
appear as negative. Use '%lu' instead to show them correctly.
Cc: Thomas Gleixner <redacted>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
kernel/irq/irqdesc.c | 2 +-
kernel/irq/proc.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
From: Cédric Le Goater <clg@kaod.org> Date: 2021-07-01 13:38:00
Before MSI domains, the default IRQ chip of PHB3 MSIs was patched by
pnv_set_msi_irq_chip() with the custom EOI handler pnv_ioda2_msi_eoi()
and the owning PHB was deduced from the 'ioda.irq_chip' field. This
path has been deprecated by the MSI domains but it is still in use by
the P8 CAPI 'cxl' driver.
Rewriting this driver to support MSI would be a waste of time.
Nevertheless, we can still remove the IRQ chip patch and set the IRQ
chip data instead. This is cleaner.
Cc: Frederic Barrat <redacted>
Cc: Christophe Lombard <redacted>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
arch/powerpc/platforms/powernv/pci-ioda.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
From: Cédric Le Goater <clg@kaod.org> Date: 2021-07-01 13:38:18
The default domain of the PCI/MSIs is not the XIVE domain anymore. To
list the IRQ mappings under XMON and debugfs, query the IRQ data from
the low level XIVE domain.
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
arch/powerpc/sysdev/xive/common.c | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
From: Cédric Le Goater <clg@kaod.org> Date: 2021-07-01 13:38:36
PCI MSIs now live in an MSI domain but the underlying calls, which
will EOI the interrupt in real mode, need an HW IRQ number mapped in
the XICS IRQ domain. Grab it there.
Cc: Alexey Kardashevskiy <redacted>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
arch/powerpc/kvm/book3s_hv.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
@@ -5233,6 +5233,7 @@ static int kvmppc_set_passthru_irq(struct kvm *kvm, int host_irq, int guest_gsi)structkvmppc_passthru_irqmap*pimap;structirq_chip*chip;inti,rc=0;+structirq_data*host_data;if(!kvm_irq_bypass)return1;
@@ -5297,7 +5298,14 @@ static int kvmppc_set_passthru_irq(struct kvm *kvm, int host_irq, int guest_gsi)*theKVMrealmodehandler.*/smp_wmb();-irq_map->r_hwirq=desc->irq_data.hwirq;++/*+*The'host_irq'numberismappedinthePCI-MSIdomainbut+*theunderlyingcalls,whichwillEOItheinterruptinreal+*mode,needanHWIRQnumbermappedintheXICSIRQdomain.+*/+host_data=irq_domain_get_irq_data(irq_get_default_host(),host_irq);+irq_map->r_hwirq=(unsignedint)irqd_to_hwirq(host_data);if(i==pimap->n_mapped)pimap->n_mapped++;
@@ -5305,7 +5313,7 @@ static int kvmppc_set_passthru_irq(struct kvm *kvm, int host_irq, int guest_gsi)if(xics_on_xive())rc=kvmppc_xive_set_mapped(kvm,guest_gsi,host_irq);else-kvmppc_xics_set_mapped(kvm,guest_gsi,desc->irq_data.hwirq);+kvmppc_xics_set_mapped(kvm,guest_gsi,irq_map->r_hwirq);if(rc)irq_map->r_hwirq=0;
From: Cédric Le Goater <clg@kaod.org> Date: 2021-07-01 13:38:55
The PowerNV and pSeries platforms now have support for both the XICS
and XIVE IRQ domains.
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
arch/powerpc/platforms/powernv/pci-ioda.c | 4 +---
arch/powerpc/platforms/pseries/msi.c | 4 ----
2 files changed, 1 insertion(+), 7 deletions(-)
@@ -720,10 +720,6 @@ int pseries_msi_allocate_domains(struct pci_controller *phb){intcount;-/* Only supported by the XIVE driver */-if(!xive_enabled())-return-ENODEV;-if(!__find_pe_total_msi(phb->dn,&count)){pr_err("PCI: failed to find MSIs for bridge %pOF (domain %d)\n",phb->dn,phb->global_number);
From: Michael Ellerman <hidden> Date: 2021-08-18 13:50:18
On Thu, 1 Jul 2021 15:27:18 +0200, Cédric Le Goater wrote:
This series adds support for MSI IRQ domains on top of the XICS (P8)
and XIVE (P9/P10) IRQ domains for the PowerNV (baremetal) and pSeries
(VM) platforms. It should simplify and improve IRQ affinity of PCI
MSIs under these PowerPC platforms, specially for drivers distributing
multiple RX/TX queues on the different CPUs of the system.
Data locality can still be improved with an interrupt controller node
per chip but this requires FW changes. It could be done under OPAL.
[...]