irqchip/gic-v4: GICv4.1 architecture support
Subsystems (6)
Marc Zyngier
maintainerv2 cover irqchip/gic-v4: GICv4.1 architecture support
This rather long series expands the existing GICv4 support to deal with the new GICv4.1 architecture, which comes with a set of major improvements compared to v4.0:
- One architectural doorbell per vcpu, instead of one doorbell per VLPI
- Doorbell entirely managed by the HW, with an "at most once" delivery guarantee per non-residency phase and only when requested by the hypervisor
- A shared memory scheme between ITSs and redistributors, allowing for an optimised residency sequence (the use of VMOVP becomes less frequent)
- Support for direct virtual SGI delivery (the injection path still involves the hypervisor), at the cost of losing the active state on SGIs. It shouldn't be a big deal, but some guest operating systems might notice (Linux definitely won't care)
On the other hand, public documentation is not available yet, so that's a bit annoying...
The series is roughly organised in 5 parts:
(1) A bunch of reworks to make the checking of some features more straightforward,
(2) VPE table allocation, new flavours of VMAPP/VMOVP commands
(3) v4.1 doorbell management
(4) Virtual SGI support
(5) Plumbing of virtual SGIs in KVM
Notes:
- This series has uncovered a behaviour that looks like a HW bug on the Cavium ThunderX (aka TX1) platform (see patch #10). I'd very much welcome some clarification from the Marvell/Cavium folks on Cc, as well as an official erratum number if this happens to be an actual bug
- I plan to take the first seven patches into 5.5 in order to reduce the size of the backlog:
* patch #1 and #3 are good performance optimisations
* patches #4 through to #7 are nice cleanups
Do shout if you see any issue with this.
* From v1:
- A bunch of minor reworks after Zenghui Yu's review
- A workaround for what looks like a new and unexpected TX1 bug
- A subtle reorder of the series so that some patches can go in early
Marc Zyngier (36):
KVM: arm64: vgic-v4: Move the GICv4 residency flow to be driven by
vcpu_load/put
irqchip/gic-v3-its: Factor out wait_for_syncr primitive irqchip/gic-v3-its: Allow LPI invalidation via the DirectLPI interface irqchip/gic-v3-its: Make is_v4 use a TYPER copy irqchip/gic-v3-its: Kill its->ite_size and use TYPER copy instead irqchip/gic-v3-its: Kill its->device_ids and use TYPER copy instead irqchip/gic-v3-its: Add get_vlpi_map() helper irqchip/gic-v3: Detect GICv4.1 supporting RVPEID irqchip/gic-v3: Add GICv4.1 VPEID size discovery irqchip/gic-v3: Workaround Cavium TX1 erratum when reading GICD_TYPER2 irqchip/gic-v4.1: VPE table (aka GICR_VPROPBASER) allocation irqchip/gic-v4.1: Implement the v4.1 flavour of VMAPP irqchip/gic-v4.1: Don't use the VPE proxy if RVPEID is set irqchip/gic-v4.1: Implement the v4.1 flavour of VMOVP irqchip/gic-v4.1: Plumb skeletal VPE irqchip irqchip/gic-v4.1: Add mask/unmask doorbell callbacks irqchip/gic-v4.1: Add VPE residency callback irqchip/gic-v4.1: Add VPE eviction callback irqchip/gic-v4.1: Add VPE INVALL callback irqchip/gic-v4.1: Suppress per-VLPI doorbell irqchip/gic-v4.1: Allow direct invalidation of VLPIs irqchip/gic-v4.1: Advertise support v4.1 to KVM irqchip/gic-v4.1: Map the ITS SGIR register page irqchip/gic-v4.1: Plumb skeletal VSGI irqchip irqchip/gic-v4.1: Add initial SGI configuration irqchip/gic-v4.1: Plumb mask/unmask SGI callbacks irqchip/gic-v4.1: Plumb get/set_irqchip_state SGI callbacks irqchip/gic-v4.1: Plumb set_vcpu_affinity SGI callbacks irqchip/gic-v4.1: Move doorbell management to the GICv4 abstraction
layer
irqchip/gic-v4.1: Add VSGI allocation/teardown irqchip/gic-v4.1: Add VSGI property setup irqchip/gic-v4.1: Eagerly vmap vPEs
KVM: arm64: GICv4.1: Let doorbells be auto-enabled
KVM: arm64: GICv4.1: Add direct injection capability to SGI registers
KVM: arm64: GICv4.1: Configure SGIs as HW interrupts
KVM: arm64: GICv4.1: Expose HW-based SGIs in debugfs
arch/arm/include/asm/arch_gicv3.h | 2 + arch/arm64/include/asm/arch_gicv3.h | 1 + drivers/irqchip/irq-gic-v3-its.c | 1102 +++++++++++++++++++++--- drivers/irqchip/irq-gic-v3.c | 46 +- drivers/irqchip/irq-gic-v4.c | 143 ++- include/kvm/arm_vgic.h | 5 +- include/linux/irqchip/arm-gic-common.h | 2 + include/linux/irqchip/arm-gic-v3.h | 75 +- include/linux/irqchip/arm-gic-v4.h | 45 +- virt/kvm/arm/arm.c | 12 +- virt/kvm/arm/vgic/vgic-debug.c | 14 +- virt/kvm/arm/vgic/vgic-mmio-v3.c | 15 +- virt/kvm/arm/vgic/vgic-mmio.c | 88 +- virt/kvm/arm/vgic/vgic-v3.c | 5 + virt/kvm/arm/vgic/vgic-v4.c | 106 ++- virt/kvm/arm/vgic/vgic.c | 4 - virt/kvm/arm/vgic/vgic.h | 2 - 17 files changed, 1492 insertions(+), 175 deletions(-)
Signature · 6 lines
2.20.1 _______________________________________________ kvmarm mailing list [email protected] https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
Marc Zyngier
maintainerPATCH v2 1/36 KVM: arm64: vgic-v4: Move the GICv4 residency flow to be driven by vcpu_load/put
When the VHE code was reworked, a lot of the vgic stuff was moved around, but the GICv4 residency code did stay untouched, meaning that we come in and out of residency on each flush/sync, which is obviously suboptimal.
To address this, let's move things around a bit:
- Residency entry (flush) moves to vcpu_load
- Residency exit (sync) moves to vcpu_put
- On blocking (entry to WFI), we "put"
- On unblocking (exit from WFI, we "load"
Because these can nest (load/block/put/load/unblock/put, for example), we now have per-VPE tracking of the residency state.
Additionally, vgic_v4_put gains a "need doorbell" parameter, which only gets set to true when blocking because of a WFI. This allows a finer control of the doorbell, which now also gets disabled as soon as it gets signaled.
--- drivers/irqchip/irq-gic-v4.c | 7 +++- include/kvm/arm_vgic.h | 4 +-- include/linux/irqchip/arm-gic-v4.h | 2 ++ virt/kvm/arm/arm.c | 12 ++++--- virt/kvm/arm/vgic/vgic-v3.c | 4 +++ virt/kvm/arm/vgic/vgic-v4.c | 55 ++++++++++++++---------------- virt/kvm/arm/vgic/vgic.c | 4 --- virt/kvm/arm/vgic/vgic.h | 2 -- 8 files changed, 48 insertions(+), 42 deletions(-)
drivers/irqchip/irq-gic-v4.c +6 -1
@@ -141,12 +141,17 @@ static int its_send_vpe_cmd(struct its_vpe *vpe, struct its_cmd_info *info)int its_schedule_vpe (struct its_vpe *vpe,bool on) {struct its_cmd_info info; +int ret;WARN_ON (preemptible ()); info.cmd_type = on ?SCHEDULE_VPE :DESCHEDULE_VPE ; -return its_send_vpe_cmd (vpe, &info); + ret =its_send_vpe_cmd (vpe, &info); +if (!ret) + vpe->resident = on; + +return ret; }int its_invall_vpe (struct its_vpe *vpe)
include/kvm/arm_vgic.h +2 -2
@@ -396,7 +396,7 @@ int kvm_vgic_v4_set_forwarding(struct kvm *kvm, int irq,int kvm_vgic_v4_unset_forwarding (struct kvm *kvm,int irq,struct kvm_kernel_irq_routing_entry *irq_entry); -void kvm_vgic_v4_enable_doorbell (struct kvm_vcpu *vcpu); -void kvm_vgic_v4_disable_doorbell (struct kvm_vcpu *vcpu); +int vgic_v4_load (struct kvm_vcpu *vcpu); +int vgic_v4_put (struct kvm_vcpu *vcpu,bool need_db);#endif /* __KVM_ARM_VGIC_H */
include/linux/irqchip/arm-gic-v4.h +2 -0
@@ -35,6 +35,8 @@ struct its_vpe {/* Doorbell interrupt */ int irq;irq_hw_number_t vpe_db_lpi; +/* VPE resident */ +bool resident;/* VPE proxy mapping */ int vpe_proxy_event;/*
virt/kvm/arm/arm.c +8 -4
@@ -322,20 +322,24 @@ void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu)/* * If we're about to block (most likely because we've just hit a * WFI), we need to sync back the state of the GIC CPU interface -* so that we have the lastest PMR and group enables. This ensures +* so that we have the latest PMR and group enables. This ensures * that kvm_arch_vcpu_runnable has up-to-date data to decide * whether we have pending interrupts. +* +* For the same reason, we want to tell GICv4 that we need +* doorbells to be signalled, should an interrupt become pending. */ preempt_disable ();kvm_vgic_vmcr_sync (vcpu); +vgic_v4_put (vcpu, true);preempt_enable (); - -kvm_vgic_v4_enable_doorbell (vcpu); }void kvm_arch_vcpu_unblocking (struct kvm_vcpu *vcpu) { -kvm_vgic_v4_disable_doorbell (vcpu); +preempt_disable (); +vgic_v4_load (vcpu); +preempt_enable (); }int kvm_arch_vcpu_init (struct kvm_vcpu *vcpu)
virt/kvm/arm/vgic/vgic-v3.c +4 -0
@@ -664,6 +664,8 @@ void vgic_v3_load(struct kvm_vcpu *vcpu)if (has_vhe ())__vgic_v3_activate_traps (vcpu); + +WARN_ON (vgic_v4_load (vcpu)); }void vgic_v3_vmcr_sync (struct kvm_vcpu *vcpu)
@@ -676,6 +678,8 @@ void vgic_v3_vmcr_sync(struct kvm_vcpu *vcpu)void vgic_v3_put (struct kvm_vcpu *vcpu) { +WARN_ON (vgic_v4_put (vcpu, false)); +vgic_v3_vmcr_sync (vcpu);kvm_call_hyp (__vgic_v3_save_aprs, vcpu);
virt/kvm/arm/vgic/vgic-v4.c +26 -29
93 lines not on this page · raw message
virt/kvm/arm/vgic/vgic.c +0 -4
@@ -857,8 +857,6 @@ void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu) {struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; -WARN_ON (vgic_v4_sync_hwstate (vcpu)); -/* An empty ap_list_head implies used_lrs == 0 */ if (list_empty (&vcpu->arch.vgic_cpu.ap_list_head))return ;
@@ -882,8 +880,6 @@ static inline void vgic_restore_state(struct kvm_vcpu *vcpu)/* Flush our emulation state into the GIC hardware before entering the guest. */ void kvm_vgic_flush_hwstate (struct kvm_vcpu *vcpu) { -WARN_ON (vgic_v4_flush_hwstate (vcpu)); -/* * If there are no virtual interrupts active or pending for this * VCPU, then there is no work to do and we can bail out without
virt/kvm/arm/vgic/vgic.h +0 -2
@@ -316,7 +316,5 @@ void vgic_its_invalidate_cache(struct kvm *kvm);bool vgic_supports_direct_msis (struct kvm *kvm);int vgic_v4_init (struct kvm *kvm);void vgic_v4_teardown (struct kvm *kvm); -int vgic_v4_sync_hwstate (struct kvm_vcpu *vcpu); -int vgic_v4_flush_hwstate (struct kvm_vcpu *vcpu);#endif
Signature · 6 lines
2.20.1 _______________________________________________ kvmarm mailing list [email protected] https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
Marc Zyngier
maintainerPATCH v2 2/36 irqchip/gic-v3-its: Factor out wait_for_syncr primitive
In reply to Marc ZyngierWaiting for a redistributor to have performed an operation is a common thing to do, and the idiom is already spread around. As we're going to make even more use of this, let's have a primitive that does just that.
--- drivers/irqchip/irq-gic-v3-its.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-)
drivers/irqchip/irq-gic-v3-its.c +9 -6
@@ -1075,6 +1075,12 @@ static void lpi_write_config(struct irq_data *d, u8 clr, u8 set)dsb (ishst); } +static void wait_for_syncr (void __iomem *rdbase) +{ +while (gic_read_lpir (rdbase +GICR_SYNCR ) &1 ) +cpu_relax (); +} +static void lpi_update_config (struct irq_data *d,u8 clr,u8 set) {struct its_device *its_dev =irq_data_get_irq_chip_data (d);
@@ -2757,8 +2763,7 @@ static void its_vpe_db_proxy_move(struct its_vpe *vpe, int from, int to) rdbase =per_cpu_ptr (gic_rdists->rdist, from)->rd_base;gic_write_lpir (vpe->vpe_db_lpi, rdbase +GICR_CLRLPIR ); -while (gic_read_lpir (rdbase +GICR_SYNCR ) &1 ) -cpu_relax (); +wait_for_syncr (rdbase);return ; }
@@ -2914,8 +2919,7 @@ static void its_vpe_send_inv(struct irq_data *d) rdbase =per_cpu_ptr (gic_rdists->rdist, vpe->col_idx)->rd_base;gic_write_lpir (vpe->vpe_db_lpi, rdbase +GICR_INVLPIR ); -while (gic_read_lpir (rdbase +GICR_SYNCR ) &1 ) -cpu_relax (); +wait_for_syncr (rdbase); }else {its_vpe_send_cmd (vpe, its_send_inv); }
@@ -2957,8 +2961,7 @@ static int its_vpe_set_irqchip_state(struct irq_data *d,gic_write_lpir (vpe->vpe_db_lpi, rdbase +GICR_SETLPIR ); }else {gic_write_lpir (vpe->vpe_db_lpi, rdbase +GICR_CLRLPIR ); -while (gic_read_lpir (rdbase +GICR_SYNCR ) &1 ) -cpu_relax (); +wait_for_syncr (rdbase); } }else {if (state)
Signature · 6 lines
2.20.1 _______________________________________________ kvmarm mailing list [email protected] https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
Re: [PATCH v2 02/36] irqchip/gic-v3-its: Factor out wait_for_syncr primitive
Quoted 6 lines · Marc Zyngier
Waiting for a redistributor to have performed an operation is a common thing to do, and the idiom is already spread around. As we're going to make even more use of this, let's have a primitive that does just that.
Signed-off-by Marc Zyngier <[email protected]>
[tip: irq/core] irqchip/gic-v3-its: Factor out wait_for_syncr primitive
In reply to Marc ZyngierThe following commit has been merged into the irq/core branch of tip:
The following commit has been merged into the irq/core branch of tip:
Commit-ID: 2f4f064b31315c7c8986522cf38ef6d11fb77986 Gitweb: https://git.kernel.org/tip/2f4f064b31315c7c8986522cf38ef6d11fb77986 Author: Marc Zyngier <[email protected]> AuthorDate: Fri, 08 Nov 2019 16:57:56 Committer: Marc Zyngier <[email protected]> CommitterDate: Sun, 10 Nov 2019 18:47:50
irqchip/gic-v3-its: Factor out wait_for_syncr primitive
Waiting for a redistributor to have performed an operation is a common thing to do, and the idiom is already spread around. As we're going to make even more use of this, let's have a primitive that does just that.
--- drivers/irqchip/irq-gic-v3-its.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-)
drivers/irqchip/irq-gic-v3-its.c +9 -6
@@ -1093,6 +1093,12 @@ static void lpi_write_config(struct irq_data *d, u8 clr, u8 set)dsb (ishst); } +static void wait_for_syncr (void __iomem *rdbase) +{ +while (gic_read_lpir (rdbase +GICR_SYNCR ) &1 ) +cpu_relax (); +} +static void lpi_update_config (struct irq_data *d,u8 clr,u8 set) {struct its_device *its_dev =irq_data_get_irq_chip_data (d);
@@ -2775,8 +2781,7 @@ static void its_vpe_db_proxy_move(struct its_vpe *vpe, int from, int to) rdbase =per_cpu_ptr (gic_rdists->rdist, from)->rd_base;gic_write_lpir (vpe->vpe_db_lpi, rdbase +GICR_CLRLPIR ); -while (gic_read_lpir (rdbase +GICR_SYNCR ) &1 ) -cpu_relax (); +wait_for_syncr (rdbase);return ; }
@@ -2932,8 +2937,7 @@ static void its_vpe_send_inv(struct irq_data *d) rdbase =per_cpu_ptr (gic_rdists->rdist, vpe->col_idx)->rd_base;gic_write_lpir (vpe->vpe_db_lpi, rdbase +GICR_INVLPIR ); -while (gic_read_lpir (rdbase +GICR_SYNCR ) &1 ) -cpu_relax (); +wait_for_syncr (rdbase); }else {its_vpe_send_cmd (vpe, its_send_inv); }
@@ -2975,8 +2979,7 @@ static int its_vpe_set_irqchip_state(struct irq_data *d,gic_write_lpir (vpe->vpe_db_lpi, rdbase +GICR_SETLPIR ); }else {gic_write_lpir (vpe->vpe_db_lpi, rdbase +GICR_CLRLPIR ); -while (gic_read_lpir (rdbase +GICR_SYNCR ) &1 ) -cpu_relax (); +wait_for_syncr (rdbase); } }else {if (state)
Marc Zyngier
maintainerPATCH v2 3/36 irqchip/gic-v3-its: Allow LPI invalidation via the DirectLPI interface
In reply to Marc ZyngierWe currently don't make much use of the DirectLPI feature, and it would be beneficial to do this more, if only because it becomes a mandatory feature for GICv4.1.
--- drivers/irqchip/irq-gic-v3-its.c | 40 +++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 8 deletions(-)
drivers/irqchip/irq-gic-v3-its.c +32 -8
@@ -175,6 +175,12 @@ static DEFINE_IDA(its_vpeid_ida);#define gic_data_rdist_rd_base () (gic_data_rdist()->rd_base)#define gic_data_rdist_vlpi_base () (gic_data_rdist_rd_base() + SZ_128K) +static inline u32 its_get_event_id (struct irq_data *d) +{ +struct its_device *its_dev =irq_data_get_irq_chip_data (d); +return d->hwirq - its_dev->event_map.lpi_base; +} +static struct its_collection *dev_event_to_col (struct its_device *its_dev,u32 event) {
@@ -183,6 +189,13 @@ static struct its_collection *dev_event_to_col(struct its_device *its_dev,return its->collections + its_dev->event_map.col_map[event]; } +static struct its_collection *irq_to_col (struct irq_data *d) +{ +struct its_device *its_dev =irq_data_get_irq_chip_data (d); + +return dev_event_to_col (its_dev,its_get_event_id (d)); +} +static struct its_collection *valid_col (struct its_collection *col) {if (WARN_ON_ONCE (col->target_address &GENMASK_ULL (15 ,0 )))
@@ -1031,12 +1044,6 @@ static void its_send_vinvall(struct its_node *its, struct its_vpe *vpe)* irqchip functions - assumes MSI, mostly. */ -static inline u32 its_get_event_id (struct irq_data *d) -{ -struct its_device *its_dev =irq_data_get_irq_chip_data (d); -return d->hwirq - its_dev->event_map.lpi_base; -} -static void lpi_write_config (struct irq_data *d,u8 clr,u8 set) {irq_hw_number_t hwirq;
@@ -1081,12 +1088,28 @@ static void wait_for_syncr(void __iomem *rdbase)cpu_relax (); } +static void direct_lpi_inv (struct irq_data *d) +{ +struct its_collection *col; +void __iomem *rdbase; + +/* Target the redistributor this LPI is currently routed to */ + col =irq_to_col (d); + rdbase =per_cpu_ptr (gic_rdists->rdist, col->col_id)->rd_base; +gic_write_lpir (d->hwirq, rdbase +GICR_INVLPIR ); + +wait_for_syncr (rdbase); +} +static void lpi_update_config (struct irq_data *d,u8 clr,u8 set) {struct its_device *its_dev =irq_data_get_irq_chip_data (d);lpi_write_config (d, clr, set); -its_send_inv (its_dev,its_get_event_id (d)); +if (gic_rdists->has_direct_lpi && !irqd_is_forwarded_to_vcpu (d)) +direct_lpi_inv (d); +else +its_send_inv (its_dev,its_get_event_id (d)); }static void its_vlpi_set_doorbell (struct irq_data *d,bool enable)
@@ -2917,8 +2940,9 @@ static void its_vpe_send_inv(struct irq_data *d)if (gic_rdists->has_direct_lpi) {void __iomem *rdbase; +/* Target the redistributor this VPE is currently known on */ rdbase =per_cpu_ptr (gic_rdists->rdist, vpe->col_idx)->rd_base; -gic_write_lpir (vpe->vpe_db_lpi, rdbase +GICR_INVLPIR ); +gic_write_lpir (d->parent_data->hwirq, rdbase +GICR_INVLPIR );wait_for_syncr (rdbase); }else {its_vpe_send_cmd (vpe, its_send_inv);
Signature · 6 lines
2.20.1 _______________________________________________ kvmarm mailing list [email protected] https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
Re: [PATCH v2 03/36] irqchip/gic-v3-its: Allow LPI invalidation via the DirectLPI interface
Hi Marc,
Quoted 5 lines · Marc Zyngier
We currently don't make much use of the DirectLPI feature, and it would be beneficial to do this more, if only because it becomes a mandatory feature for GICv4.1.
Signed-off-by Marc Zyngier <[email protected]>
I have no objection to this patch, which says:
But this patch really drives me to look through all callsites of dev_event_to_col(), the abstraction which can be used _only_ with physical LPI mappings.
I find that when building the INV command, we use dev_event_to_col() to find the "sync_obj" and then pass it to the following SYNC command. But the "INV+SYNC" will be performed both on physical LPI and *VLPI* (lpi_update_config/its_send_inv).
So I have two questions about the way we sending INV on VLPI:
1) Which "sync" command should be followed? SYNC or VSYNC? (we currently use SYNC, while the spec says, SYNC "ensures all outstanding ITS operations associated with *physical* interrupts for the Redistributor are globally observed ...")
2) The "sync_obj" we are currently using seems to be wrong.
Thanks,
Zenghui
Marc Zyngier
maintainerRe: [PATCH v2 03/36] irqchip/gic-v3-its: Allow LPI invalidation via the DirectLPI interface
Quoted 25 lines · Zenghui Yu
Hi Marc,
Quoted 5 lines · Marc Zyngier
We currently don't make much use of the DirectLPI feature, and it would be beneficial to do this more, if only because it becomes a mandatory feature for GICv4.1.
Signed-off-by Marc Zyngier <[email protected]>I have no objection to this patch, which says:
Reviewed-by Zenghui Yu <[email protected]>But this patch really drives me to look through all callsites of
dev_event_to_col(), the abstraction which can be used _only_ with physical LPI mappings.I find that when building the INV command, we use
dev_event_to_col()to find the "sync_obj" and then pass it to the following SYNC command. But the "INV+SYNC" will be performed both on physical LPI and *VLPI* (lpi_update_config/its_send_inv).
So I have two questions about the way we sending INV on VLPI:
Quoted 6 lines
1) Which "sync" command should be followed? SYNC or VSYNC? (we currently use SYNC, while the spec says, SYNC "ensures all outstanding ITS operations associated with *physical* interrupts for the Redistributor are globally observed ...")
2) The "
sync_obj" we are currently using seems to be wrong.
I think you're right on both counts (where were you when I wrote the initial GICv4 support? ;-). I think the confusion stems from the fact that there is no 'VINV' command, and we simply overlooked the sync object issue. It is quite likely that existing implementations don't care much about the difference (otherwise we'd have seen the problem before), but it doesn't hurt to do the right thing.
I have the following patch as part of a set of fixes that I'm about to post (once I get a chance to test them), let me know what you think.
M.
drivers/irqchip/irq-gic-v3-its.c +35 -1
@@ -702,6 +702,24 @@ static struct its_vpe *its_build_vmovp_cmd(struct its_node *its,return valid_vpe (its, desc->its_vmovp_cmd.vpe); } +static struct its_vpe *its_build_vinv_cmd (struct its_node *its, +struct its_cmd_block *cmd, +struct its_cmd_desc *desc) +{ +struct its_vlpi_map *map; + + map =dev_event_to_vlpi_map (desc->its_inv_cmd.dev, + desc->its_inv_cmd.event_id); + +its_encode_cmd (cmd,GITS_CMD_INV ); +its_encode_devid (cmd, desc->its_inv_cmd.dev->device_id); +its_encode_event_id (cmd, desc->its_inv_cmd.event_id); + +its_fixup_cmd (cmd); + +return valid_vpe (its, map->vpe); +} +static u64 its_cmd_ptr_to_offset (struct its_node *its,struct its_cmd_block *ptr) {
@@ -1068,6 +1086,20 @@ static void its_send_vinvall(struct its_node *its, struct its_vpe *vpe)its_send_single_vcommand (its, its_build_vinvall_cmd, &desc); } +static void its_send_vinv (struct its_device *dev,u32 event_id) +{ +struct its_cmd_desc desc; + +/* +* There is no real VINV command. This is just a normal INV, +* with a VSYNC instead of a SYNC. +*/ + desc.its_inv_cmd.dev = dev; + desc.its_inv_cmd.event_id = event_id; + +its_send_single_vcommand (dev->its, its_build_vinv_cmd, &desc); +} +/* * irqchip functions - assumes MSI, mostly. */
@@ -1142,8 +1174,10 @@ static void lpi_update_config(struct irq_data *d, u8 clr, u8 set)lpi_write_config (d, clr, set);if (gic_rdists->has_direct_lpi && !irqd_is_forwarded_to_vcpu (d))direct_lpi_inv (d); -else +else if (!irqd_is_forwarded_to_vcpu (d))its_send_inv (its_dev,its_get_event_id (d)); +else +its_send_vinv (its_dev,its_get_event_id (d)); }static void its_vlpi_set_doorbell (struct irq_data *d,bool enable)
Signature · 1 line
Jazz is not dead, it just smells funny.
Zenghui Yu
reviewerRe: [PATCH v2 03/36] irqchip/gic-v3-its: Allow LPI invalidation via the DirectLPI interface
Hi Marc,
Quoted 18 lines · Marc Zyngier
Quoted 16 lines · Zenghui Yu
But this patch really drives me to look through all callsites of
dev_event_to_col(), the abstraction which can be used _only_ with physical LPI mappings.I find that when building the INV command, we use
dev_event_to_col()to find the "sync_obj" and then pass it to the following SYNC command. But the "INV+SYNC" will be performed both on physical LPI and *VLPI* (lpi_update_config/its_send_inv).
So I have two questions about the way we sending INV on VLPI:1) Which "sync" command should be followed? SYNC or VSYNC? (we currently use SYNC, while the spec says, SYNC "ensures all outstanding ITS operations associated with *physical* interrupts for the Redistributor are globally observed ...")
Quoted 4 lines
Quoted 1 line
2) The "
sync_obj" we are currently using seems to be wrong.I think you're right on both counts (where were you when I wrote the initial GICv4 support? ;-). I think the confusion stems from the fact
(I'm a bit late here :-).
Quoted 16 lines
that there is no 'VINV' command, and we simply overlooked the sync object issue. It is quite likely that existing implementations don't care much about the difference (otherwise we'd have seen the problem before), but it doesn't hurt to do the right thing.
I have the following patch as part of a set of fixes that I'm about to post (once I get a chance to test them), let me know what you think.
M.drivers/irqchip/irq-gic-v3-its.c +0
-0@@ -702,6 +702,24 @@ static struct its_vpe *its_build_vmovp_cmd(struct its_node *its,return valid_vpe (its, desc->its_vmovp_cmd.vpe);
drivers/irqchip/irq-gic-v3-its.c static struct its_vpe *its_build_vmovp_cmd(struct its_node *its, · line 712
Quoted 10 lines
drivers/irqchip/irq-gic-v3-its.c +8
-0} +static struct its_vpe *its_build_vinv_cmd (struct its_node *its, +struct its_cmd_block *cmd, +struct its_cmd_desc *desc) +{ +struct its_vlpi_map *map; + + map =dev_event_to_vlpi_map (desc->its_inv_cmd.dev, + desc->its_inv_cmd.event_id);
Indeed! I think we need this kind of abstraction for VLPI.
Quoted 35 lines
drivers/irqchip/irq-gic-v3-its.c +24
-0+ +its_encode_cmd (cmd,GITS_CMD_INV ); +its_encode_devid (cmd, desc->its_inv_cmd.dev->device_id); +its_encode_event_id (cmd, desc->its_inv_cmd.event_id); + +its_fixup_cmd (cmd); + +return valid_vpe (its, map->vpe); +} +static u64 its_cmd_ptr_to_offset (struct its_node *its,struct its_cmd_block *ptr) {@@ -1068,6 +1086,20 @@ static void its_send_vinvall(struct its_node *its, struct its_vpe *vpe)its_send_single_vcommand (its, its_build_vinvall_cmd, &desc); } +static void its_send_vinv (struct its_device *dev,u32 event_id) +{ +struct its_cmd_desc desc; + +/* +* There is no real VINV command. This is just a normal INV, +* with a VSYNC instead of a SYNC. +*/ + desc.its_inv_cmd.dev = dev; + desc.its_inv_cmd.event_id = event_id; + +its_send_single_vcommand (dev->its, its_build_vinv_cmd, &desc); +} +/* * irqchip functions - assumes MSI, mostly. */
drivers/irqchip/irq-gic-v3-its.c static void lpi_update_config(struct irq_data *d, u8 clr, u8 set) · line 1180
Quoted 8 lines
drivers/irqchip/irq-gic-v3-its.c +3
-1@@ -1142,8 +1174,10 @@ static void lpi_update_config(struct irq_data *d, u8 clr, u8 set)lpi_write_config (d, clr, set);if (gic_rdists->has_direct_lpi && !irqd_is_forwarded_to_vcpu (d))direct_lpi_inv (d); -else +else if (!irqd_is_forwarded_to_vcpu (d))its_send_inv (its_dev,its_get_event_id (d)); +else +its_send_vinv (its_dev,its_get_event_id (d));
Yeah, this is exactly what I was having in the mind when reporting this problem - "maybe we should have a SW emulated VINV+VSYNC for VLPI". So I think this patch has done the right thing.
And what about the INT and CLEAR? In response to guest's INT/CLEAR commands, hypervisor (I mean KVM) will bother the ITS driver to send INT/CLEAR for VLPIs. They're both followed by SYNC and might need the same fixes?
Thanks,
Zenghui
Quoted 4 lines
drivers/irqchip/irq-gic-v3-its.c +0
-0}static void its_vlpi_set_doorbell (struct irq_data *d,bool enable)
Marc Zyngier
maintainerRe: [PATCH v2 03/36] irqchip/gic-v3-its: Allow LPI invalidation via the DirectLPI interface
Quoted 45 lines · Zenghui Yu
Hi Marc,
Quoted 13 lines · Marc Zyngier
Quoted 11 lines · Zenghui Yu
But this patch really drives me to look through all callsites of
dev_event_to_col(), the abstraction which can be used _only_ with physical LPI mappings.I find that when building the INV command, we use
dev_event_to_col()to find the "sync_obj" and then pass it to the following SYNC command. But the "INV+SYNC" will be performed both on physical LPI and *VLPI* (lpi_update_config/its_send_inv).
So I have two questions about the way we sending INV on VLPI:Quoted 8 lines
Quoted 6 lines
1) Which "sync" command should be followed? SYNC or VSYNC? (we currently use SYNC, while the spec says, SYNC "ensures all outstanding ITS operations associated with *physical* interrupts for the Redistributor are globally observed ...")
2) The "
sync_obj" we are currently using seems to be wrong.I think you're right on both counts (where were you when I wrote the initial GICv4 support? ;-). I think the confusion stems from the fact
(I'm a bit late here :-).
Quoted 18 lines
that there is no 'VINV' command, and we simply overlooked the sync object issue. It is quite likely that existing implementations don't care much about the difference (otherwise we'd have seen the problem before), but it doesn't hurt to do the right thing.
I have the following patch as part of a set of fixes that I'm about to post (once I get a chance to test them), let me know what you think.M.drivers/irqchip/irq-gic-v3-its.c +1
-0@@ -702,6 +702,24 @@ static struct its_vpe *its_build_vmovp_cmd(struct its_node *its, return valid_vpe(its, desc->its_vmovp_cmd.vpe); } +static struct its_vpe *its_build_vinv_cmd(struct its_node *its, + struct its_cmd_block *cmd,
Quoted 8 lines
drivers/irqchip/irq-gic-v3-its.c static struct its_vpe *its_build_vmovp_cmd(struct its_node *its, · line 712
Quoted 6 lines
drivers/irqchip/irq-gic-v3-its.c +6
-0+ struct its_cmd_desc *desc) +{ +struct its_vlpi_map *map; + + map =dev_event_to_vlpi_map (desc->its_inv_cmd.dev, + desc->its_inv_cmd.event_id);Indeed! I think we need this kind of abstraction for VLPI.
Yeah, I finally realised we'd needed something like that, and made it part of the get_vlpi_map() patch.
Quoted 50 lines
Quoted 36 lines
drivers/irqchip/irq-gic-v3-its.c +23
-0+ +its_encode_cmd (cmd,GITS_CMD_INV ); +its_encode_devid (cmd, desc->its_inv_cmd.dev->device_id); +its_encode_event_id (cmd, desc->its_inv_cmd.event_id); + +its_fixup_cmd (cmd); + +return valid_vpe (its, map->vpe); +} +static u64 its_cmd_ptr_to_offset (struct its_node *its,struct its_cmd_block *ptr) {@@ -1068,6 +1086,20 @@ static void its_send_vinvall(struct its_node *its, struct its_vpe *vpe)its_send_single_vcommand (its, its_build_vinvall_cmd, &desc); } +static void its_send_vinv(struct its_device *dev, u32 event_id) +{ +struct its_cmd_desc desc; + +/* +* There is no real VINV command. This is just a normal INV, +* with a VSYNC instead of a SYNC. +*/ + desc.its_inv_cmd.dev = dev; + desc.its_inv_cmd.event_id = event_id; + +its_send_single_vcommand (dev->its, its_build_vinv_cmd, &desc); +} +/* * irqchip functions - assumes MSI, mostly. */ drivers/irqchip/irq-gic-v3-its.c static void lpi_update_config(struct irq_data · line 1181
Quoted 9 lines
drivers/irqchip/irq-gic-v3-its.c +3
-1@@ -1142,8 +1174,10 @@ static void lpi_update_config(struct irq_data *d, u8 clr, u8 set)lpi_write_config (d, clr, set);if (gic_rdists->has_direct_lpi && !irqd_is_forwarded_to_vcpu (d))direct_lpi_inv (d); -else +else if (!irqd_is_forwarded_to_vcpu (d))its_send_inv (its_dev,its_get_event_id (d)); +else +its_send_vinv (its_dev,its_get_event_id (d));Yeah, this is exactly what I was having in the mind when reporting this problem - "maybe we should have a SW emulated VINV+VSYNC for VLPI". So I think this patch has done the right thing.
Quoted 4 lines
And what about the INT and CLEAR? In response to guest's INT/CLEAR commands, hypervisor (I mean KVM) will bother the ITS driver to send INT/CLEAR for VLPIs. They're both followed by SYNC and might need the same fixes?
Yup. Please see this series[1], which has grown quite a few fixups, including some pretty old ones (I've just pushed an update, and should post it shortly).
Thanks,
M.
[1] https://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git/log/?h=irq/gic-5.5-wip
Signature · 1 line
Jazz is not dead. It just smells funny...
[tip: irq/core] irqchip/gic-v3-its: Allow LPI invalidation via the DirectLPI interface
In reply to Marc ZyngierThe following commit has been merged into the irq/core branch of tip:
The following commit has been merged into the irq/core branch of tip:
Commit-ID: 425c09be0f091a3b5940261d9a5d8467d62987e7 Gitweb: https://git.kernel.org/tip/425c09be0f091a3b5940261d9a5d8467d62987e7 Author: Marc Zyngier <[email protected]> AuthorDate: Fri, 08 Nov 2019 16:57:57 Committer: Marc Zyngier <[email protected]> CommitterDate: Sun, 10 Nov 2019 18:47:51
irqchip/gic-v3-its: Allow LPI invalidation via the DirectLPI interface
We currently don't make much use of the DirectLPI feature, and it would be beneficial to do this more, if only because it becomes a mandatory feature for GICv4.1.
--- drivers/irqchip/irq-gic-v3-its.c | 40 ++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 8 deletions(-)
drivers/irqchip/irq-gic-v3-its.c +32 -8
@@ -191,6 +191,12 @@ static u16 get_its_list(struct its_vm *vm)return (u16 )its_list; } +static inline u32 its_get_event_id (struct irq_data *d) +{ +struct its_device *its_dev =irq_data_get_irq_chip_data (d); +return d->hwirq - its_dev->event_map.lpi_base; +} +static struct its_collection *dev_event_to_col (struct its_device *its_dev,u32 event) {
@@ -199,6 +205,13 @@ static struct its_collection *dev_event_to_col(struct its_device *its_dev,return its->collections + its_dev->event_map.col_map[event]; } +static struct its_collection *irq_to_col (struct irq_data *d) +{ +struct its_device *its_dev =irq_data_get_irq_chip_data (d); + +return dev_event_to_col (its_dev,its_get_event_id (d)); +} +static struct its_collection *valid_col (struct its_collection *col) {if (WARN_ON_ONCE (col->target_address &GENMASK_ULL (15 ,0 )))
@@ -1049,12 +1062,6 @@ static void its_send_vinvall(struct its_node *its, struct its_vpe *vpe)* irqchip functions - assumes MSI, mostly. */ -static inline u32 its_get_event_id (struct irq_data *d) -{ -struct its_device *its_dev =irq_data_get_irq_chip_data (d); -return d->hwirq - its_dev->event_map.lpi_base; -} -static void lpi_write_config (struct irq_data *d,u8 clr,u8 set) {irq_hw_number_t hwirq;
@@ -1099,12 +1106,28 @@ static void wait_for_syncr(void __iomem *rdbase)cpu_relax (); } +static void direct_lpi_inv (struct irq_data *d) +{ +struct its_collection *col; +void __iomem *rdbase; + +/* Target the redistributor this LPI is currently routed to */ + col =irq_to_col (d); + rdbase =per_cpu_ptr (gic_rdists->rdist, col->col_id)->rd_base; +gic_write_lpir (d->hwirq, rdbase +GICR_INVLPIR ); + +wait_for_syncr (rdbase); +} +static void lpi_update_config (struct irq_data *d,u8 clr,u8 set) {struct its_device *its_dev =irq_data_get_irq_chip_data (d);lpi_write_config (d, clr, set); -its_send_inv (its_dev,its_get_event_id (d)); +if (gic_rdists->has_direct_lpi && !irqd_is_forwarded_to_vcpu (d)) +direct_lpi_inv (d); +else +its_send_inv (its_dev,its_get_event_id (d)); }static void its_vlpi_set_doorbell (struct irq_data *d,bool enable)
@@ -2935,8 +2958,9 @@ static void its_vpe_send_inv(struct irq_data *d)if (gic_rdists->has_direct_lpi) {void __iomem *rdbase; +/* Target the redistributor this VPE is currently known on */ rdbase =per_cpu_ptr (gic_rdists->rdist, vpe->col_idx)->rd_base; -gic_write_lpir (vpe->vpe_db_lpi, rdbase +GICR_INVLPIR ); +gic_write_lpir (d->parent_data->hwirq, rdbase +GICR_INVLPIR );wait_for_syncr (rdbase); }else {its_vpe_send_cmd (vpe, its_send_inv);
Marc Zyngier
maintainerPATCH v2 4/36 irqchip/gic-v3-its: Make is_v4 use a TYPER copy
In reply to Marc ZyngierInstead of caching the GICv4 compatibility in a discrete way, cache the TYPER register instead, which can then be used to implement the same functionnality. This will get used more extensively in subsequent patches.
--- drivers/irqchip/irq-gic-v3-its.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-)
drivers/irqchip/irq-gic-v3-its.c +13 -11
@@ -102,6 +102,7 @@ struct its_node {struct its_collection *collections;struct fwnode_handle *fwnode_handle;u64 (*get_msi_base)(struct its_device *its_dev); +u64 typer;u64 cbaser_save;u32 ctlr_save;struct list_head its_device_list;
@@ -112,10 +113,11 @@ struct its_node {int numa_node;unsigned int msi_domain_flags;u32 pre_its_base;/* for Socionext Synquacer */ -bool is_v4;int vlpi_redist_offset; }; +#define is_v4 (its) (!!((its)->typer & GITS_TYPER_VLPIS)) +#define ITS_ITT_ALIGN SZ_256/* The maximum number of VPEID bits supported by VLPI commands */
@@ -1019,7 +1021,7 @@ static void its_send_vmovp(struct its_vpe *vpe)/* Emit VMOVPs */ list_for_each_entry (its, &its_nodes, entry) { -if (!its->is_v4) +if (!is_v4 (its))continue ;if (!vpe->its_vm->vlpi_count[its->list_nr])
@@ -1430,7 +1432,7 @@ static int its_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu_info)struct its_cmd_info *info = vcpu_info;/* Need a v4 ITS */ -if (!its_dev->its->is_v4) +if (!is_v4 (its_dev->its))return -EINVAL ;/* Unmap request? */
@@ -2394,7 +2396,7 @@ static bool its_alloc_vpe_table(u32 vpe_id)list_for_each_entry (its, &its_nodes, entry) {struct its_baser *baser; -if (!its->is_v4) +if (!is_v4 (its))continue ; baser =its_get_baser (its,GITS_BASER_TYPE_VCPU );
@@ -2882,7 +2884,7 @@ static void its_vpe_invall(struct its_vpe *vpe)struct its_node *its;list_for_each_entry (its, &its_nodes, entry) { -if (!its->is_v4) +if (!is_v4 (its))continue ;if (its_list_map && !vpe->its_vm->vlpi_count[its->list_nr])
@@ -3150,7 +3152,7 @@ static int its_vpe_irq_domain_activate(struct irq_domain *domain, vpe->col_idx =cpumask_first (cpu_online_mask);list_for_each_entry (its, &its_nodes, entry) { -if (!its->is_v4) +if (!is_v4 (its))continue ;its_send_vmapp (its, vpe, true);
@@ -3176,7 +3178,7 @@ static void its_vpe_irq_domain_deactivate(struct irq_domain *domain,return ;list_for_each_entry (its, &its_nodes, entry) { -if (!its->is_v4) +if (!is_v4 (its))continue ;its_send_vmapp (its, vpe, false);
@@ -3614,12 +3616,12 @@ static int __init its_probe_one(struct resource *res,INIT_LIST_HEAD (&its->entry);INIT_LIST_HEAD (&its->its_device_list); typer =gic_read_typer (its_base +GITS_TYPER ); + its->typer = typer; its->base = its_base; its->phys_base = res->start; its->ite_size =GITS_TYPER_ITT_ENTRY_SIZE (typer); its->device_ids =GITS_TYPER_DEVBITS (typer); - its->is_v4 = !!(typer &GITS_TYPER_VLPIS ); -if (its->is_v4) { +if (is_v4 (its)) {if (!(typer &GITS_TYPER_VMOVP )) { err =its_compute_its_list_map (res, its_base);if (err <0 )
@@ -3686,7 +3688,7 @@ static int __init its_probe_one(struct resource *res,gits_write_cwriter (0 , its->base +GITS_CWRITER ); ctlr =readl_relaxed (its->base +GITS_CTLR ); ctlr |=GITS_CTLR_ENABLE ; -if (its->is_v4) +if (is_v4 (its)) ctlr |= GITS_CTLR_ImDe;writel_relaxed (ctlr, its->base +GITS_CTLR );
@@ -4011,7 +4013,7 @@ int __init its_init(struct fwnode_handle *handle, struct rdists *rdists,return err;list_for_each_entry (its, &its_nodes, entry) - has_v4 |= its->is_v4; + has_v4 |=is_v4 (its);if (has_v4 & rdists->has_vlpis) { if (its_init_vpe_domain() ||
Signature · 1 line
2.20.1
Re: [PATCH v2 04/36] irqchip/gic-v3-its: Make is_v4 use a TYPER copy
Hi Marc,
Quoted 5 lines · Marc Zyngier
Instead of caching the GICv4 compatibility in a discrete way, cache the TYPER register instead, which can then be used to implement the same functionnality. This will get used more extensively in subsequent patches.
Signed-off-by Marc Zyngier <[email protected]>
nit: You may need to rebase some patches on top of mainline when you finally decide to take them in, i.e., as we currently have get_its_list(), which will use the legacy its->is_v4.
Besides,
Marc Zyngier
maintainerRe: [PATCH v2 04/36] irqchip/gic-v3-its: Make is_v4 use a TYPER copy
Quoted 8 lines · Zenghui Yu
Hi Marc,
Quoted 4 lines · Marc Zyngier
Instead of caching the GICv4 compatibility in a discrete way, cache the TYPER register instead, which can then be used to implement the same functionnality. This will get used more extensively in subsequent patches.
Quoted 5 lines
Quoted 1 line
Signed-off-by Marc Zyngier <[email protected]>nit: You may need to rebase some patches on top of mainline when you finally decide to take them in, i.e., as we currently have
get_its_list(), which will use the legacyits->is_v4.
Yeah, I was planning on rebasing the whole irqchip-next branch on top of -rc5 to avoid this kind of problems.
Quoted 1 line
Reviewed-by Zenghui Yu <[email protected]>
Thanks for that.
M.
Signature · 5 lines
Jazz is not dead, it just smells funny. _______________________________________________ kvmarm mailing list [email protected] https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
[tip: irq/core] irqchip/gic-v3-its: Make is_v4 use a TYPER copy
In reply to Marc ZyngierThe following commit has been merged into the irq/core branch of tip:
The following commit has been merged into the irq/core branch of tip:
Commit-ID: 0dd57fed6b46659b2db1156cb9100fbcfef6fe5d Gitweb: https://git.kernel.org/tip/0dd57fed6b46659b2db1156cb9100fbcfef6fe5d Author: Marc Zyngier <[email protected]> AuthorDate: Fri, 08 Nov 2019 16:57:58 Committer: Marc Zyngier <[email protected]> CommitterDate: Sun, 10 Nov 2019 18:47:51
irqchip/gic-v3-its: Make is_v4 use a TYPER copy
Instead of caching the GICv4 compatibility in a discrete way, cache the TYPER register instead, which can then be used to implement the same functionnality. This will get used more extensively in subsequent patches.
--- drivers/irqchip/irq-gic-v3-its.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-)
drivers/irqchip/irq-gic-v3-its.c +14 -12
@@ -102,6 +102,7 @@ struct its_node {struct its_collection *collections;struct fwnode_handle *fwnode_handle;u64 (*get_msi_base)(struct its_device *its_dev); +u64 typer;u64 cbaser_save;u32 ctlr_save;struct list_head its_device_list;
@@ -112,10 +113,11 @@ struct its_node {int numa_node;unsigned int msi_domain_flags;u32 pre_its_base;/* for Socionext Synquacer */ -bool is_v4;int vlpi_redist_offset; }; +#define is_v4 (its) (!!((its)->typer & GITS_TYPER_VLPIS)) +#define ITS_ITT_ALIGN SZ_256/* The maximum number of VPEID bits supported by VLPI commands */
@@ -181,7 +183,7 @@ static u16 get_its_list(struct its_vm *vm)unsigned long its_list =0 ;list_for_each_entry (its, &its_nodes, entry) { -if (!its->is_v4) +if (!is_v4 (its))continue ;if (vm->vlpi_count[its->list_nr])
@@ -1037,7 +1039,7 @@ static void its_send_vmovp(struct its_vpe *vpe)/* Emit VMOVPs */ list_for_each_entry (its, &its_nodes, entry) { -if (!its->is_v4) +if (!is_v4 (its))continue ;if (!vpe->its_vm->vlpi_count[its->list_nr])
@@ -1448,7 +1450,7 @@ static int its_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu_info)struct its_cmd_info *info = vcpu_info;/* Need a v4 ITS */ -if (!its_dev->its->is_v4) +if (!is_v4 (its_dev->its))return -EINVAL ;/* Unmap request? */
@@ -2412,7 +2414,7 @@ static bool its_alloc_vpe_table(u32 vpe_id)list_for_each_entry (its, &its_nodes, entry) {struct its_baser *baser; -if (!its->is_v4) +if (!is_v4 (its))continue ; baser =its_get_baser (its,GITS_BASER_TYPE_VCPU );
@@ -2900,7 +2902,7 @@ static void its_vpe_invall(struct its_vpe *vpe)struct its_node *its;list_for_each_entry (its, &its_nodes, entry) { -if (!its->is_v4) +if (!is_v4 (its))continue ;if (its_list_map && !vpe->its_vm->vlpi_count[its->list_nr])
@@ -3168,7 +3170,7 @@ static int its_vpe_irq_domain_activate(struct irq_domain *domain, vpe->col_idx =cpumask_first (cpu_online_mask);list_for_each_entry (its, &its_nodes, entry) { -if (!its->is_v4) +if (!is_v4 (its))continue ;its_send_vmapp (its, vpe, true);
@@ -3194,7 +3196,7 @@ static void its_vpe_irq_domain_deactivate(struct irq_domain *domain,return ;list_for_each_entry (its, &its_nodes, entry) { -if (!its->is_v4) +if (!is_v4 (its))continue ;its_send_vmapp (its, vpe, false);
@@ -3632,12 +3634,12 @@ static int __init its_probe_one(struct resource *res,INIT_LIST_HEAD (&its->entry);INIT_LIST_HEAD (&its->its_device_list); typer =gic_read_typer (its_base +GITS_TYPER ); + its->typer = typer; its->base = its_base; its->phys_base = res->start; its->ite_size =GITS_TYPER_ITT_ENTRY_SIZE (typer); its->device_ids =GITS_TYPER_DEVBITS (typer); - its->is_v4 = !!(typer &GITS_TYPER_VLPIS ); -if (its->is_v4) { +if (is_v4 (its)) {if (!(typer &GITS_TYPER_VMOVP )) { err =its_compute_its_list_map (res, its_base);if (err <0 )
@@ -3704,7 +3706,7 @@ static int __init its_probe_one(struct resource *res,gits_write_cwriter (0 , its->base +GITS_CWRITER ); ctlr =readl_relaxed (its->base +GITS_CTLR ); ctlr |=GITS_CTLR_ENABLE ; -if (its->is_v4) +if (is_v4 (its)) ctlr |= GITS_CTLR_ImDe;writel_relaxed (ctlr, its->base +GITS_CTLR );
@@ -4029,7 +4031,7 @@ int __init its_init(struct fwnode_handle *handle, struct rdists *rdists,return err;list_for_each_entry (its, &its_nodes, entry) - has_v4 |= its->is_v4; + has_v4 |=is_v4 (its);if (has_v4 & rdists->has_vlpis) { if (its_init_vpe_domain() ||
Marc Zyngier
maintainerPATCH v2 5/36 irqchip/gic-v3-its: Kill its->ite_size and use TYPER copy instead
In reply to Marc ZyngierNow that we have a copy of TYPER in the ITS structure, rely on this to provide the same service as its->ite_size, which gets axed. Errata workarounds are now updating the cached fields instead of requiring a separate field in the ITS structure.
--- drivers/irqchip/irq-gic-v3-its.c | 8 ++++---- include/linux/irqchip/arm-gic-v3.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-)
drivers/irqchip/irq-gic-v3-its.c +4 -4
@@ -6,6 +6,7 @@#include <linux/acpi.h> #include <linux/acpi_iort.h> +#include <linux/bitfield.h> #include <linux/bitmap.h> #include <linux/cpu.h> #include <linux/crash_dump.h>
@@ -108,7 +109,6 @@ struct its_node {struct list_head its_device_list;u64 flags;unsigned long list_nr; -u32 ite_size;u32 device_ids;int numa_node;unsigned int msi_domain_flags;
@@ -2435,7 +2435,7 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,* sized as a power of two (and you need at least one bit...). */ nr_ites =max (2 , nvecs); - sz = nr_ites * its->ite_size; + sz = nr_ites * (FIELD_GET (GITS_TYPER_ITT_ENTRY_SIZE , its->typer) +1 ); sz =max (sz,ITS_ITT_ALIGN ) +ITS_ITT_ALIGN -1 ; itt =kzalloc_node (sz,GFP_KERNEL , its->numa_node);if (alloc_lpis) {
@@ -3250,7 +3250,8 @@ static bool __maybe_unused its_enable_quirk_qdf2400_e0065(void *data)struct its_node *its = data;/* On QDF2400, the size of the ITE is 16Bytes */ - its->ite_size =16 ; + its->typer &= ~GITS_TYPER_ITT_ENTRY_SIZE ; + its->typer |=FIELD_PREP (GITS_TYPER_ITT_ENTRY_SIZE ,16 -1 );return true; }
@@ -3619,7 +3620,6 @@ static int __init its_probe_one(struct resource *res, its->typer = typer; its->base = its_base; its->phys_base = res->start; - its->ite_size =GITS_TYPER_ITT_ENTRY_SIZE (typer); its->device_ids =GITS_TYPER_DEVBITS (typer);if (is_v4 (its)) {if (!(typer &GITS_TYPER_VMOVP )) {
include/linux/irqchip/arm-gic-v3.h +1 -1
@@ -334,7 +334,7 @@#define GITS_TYPER_PLPIS (1UL << 0)#define GITS_TYPER_VLPIS (1UL << 1)#define GITS_TYPER_ITT_ENTRY_SIZE_SHIFT 4 -#define GITS_TYPER_ITT_ENTRY_SIZE (r) ((((r) >> GITS_TYPER_ITT_ENTRY_SIZE_SHIFT) & 0xf) + 1) +#define GITS_TYPER_ITT_ENTRY_SIZE GENMASK_ULL(7, 4)#define GITS_TYPER_IDBITS_SHIFT 8#define GITS_TYPER_DEVBITS_SHIFT 13#define GITS_TYPER_DEVBITS (r) ((((r) >> GITS_TYPER_DEVBITS_SHIFT) & 0x1f) + 1)
Signature · 1 line
2.20.1
Re: [PATCH v2 05/36] irqchip/gic-v3-its: Kill its->ite_size and use TYPER copy instead
Quoted 6 lines · Marc Zyngier
Now that we have a copy of TYPER in the ITS structure, rely on this to provide the same service as
its->ite_size, which gets axed. Errata workarounds are now updating the cached fields instead of requiring a separate field in the ITS structure.Signed-off-by Marc Zyngier <[email protected]>
[tip: irq/core] irqchip/gic-v3-its: Kill its->ite_size and use TYPER copy instead
In reply to Marc ZyngierThe following commit has been merged into the irq/core branch of tip:
The following commit has been merged into the irq/core branch of tip:
Commit-ID: ffedbf0cba153c91a0da5d1280a5e639664c5ab3 Gitweb: https://git.kernel.org/tip/ffedbf0cba153c91a0da5d1280a5e639664c5ab3 Author: Marc Zyngier <[email protected]> AuthorDate: Fri, 08 Nov 2019 16:57:59 Committer: Marc Zyngier <[email protected]> CommitterDate: Sun, 10 Nov 2019 18:47:52
irqchip/gic-v3-its: Kill its->ite_size and use TYPER copy instead
Now that we have a copy of TYPER in the ITS structure, rely on this to provide the same service as its->ite_size, which gets axed. Errata workarounds are now updating the cached fields instead of requiring a separate field in the ITS structure.
--- drivers/irqchip/irq-gic-v3-its.c | 8 ++++---- include/linux/irqchip/arm-gic-v3.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-)
drivers/irqchip/irq-gic-v3-its.c +4 -4
@@ -6,6 +6,7 @@#include <linux/acpi.h> #include <linux/acpi_iort.h> +#include <linux/bitfield.h> #include <linux/bitmap.h> #include <linux/cpu.h> #include <linux/crash_dump.h>
@@ -108,7 +109,6 @@ struct its_node {struct list_head its_device_list;u64 flags;unsigned long list_nr; -u32 ite_size;u32 device_ids;int numa_node;unsigned int msi_domain_flags;
@@ -2453,7 +2453,7 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,* sized as a power of two (and you need at least one bit...). */ nr_ites =max (2 , nvecs); - sz = nr_ites * its->ite_size; + sz = nr_ites * (FIELD_GET (GITS_TYPER_ITT_ENTRY_SIZE , its->typer) +1 ); sz =max (sz,ITS_ITT_ALIGN ) +ITS_ITT_ALIGN -1 ; itt =kzalloc_node (sz,GFP_KERNEL , its->numa_node);if (alloc_lpis) {
@@ -3268,7 +3268,8 @@ static bool __maybe_unused its_enable_quirk_qdf2400_e0065(void *data)struct its_node *its = data;/* On QDF2400, the size of the ITE is 16Bytes */ - its->ite_size =16 ; + its->typer &= ~GITS_TYPER_ITT_ENTRY_SIZE ; + its->typer |=FIELD_PREP (GITS_TYPER_ITT_ENTRY_SIZE ,16 -1 );return true; }
@@ -3637,7 +3638,6 @@ static int __init its_probe_one(struct resource *res, its->typer = typer; its->base = its_base; its->phys_base = res->start; - its->ite_size =GITS_TYPER_ITT_ENTRY_SIZE (typer); its->device_ids =GITS_TYPER_DEVBITS (typer);if (is_v4 (its)) {if (!(typer &GITS_TYPER_VMOVP )) {
include/linux/irqchip/arm-gic-v3.h +1 -1
@@ -334,7 +334,7 @@#define GITS_TYPER_PLPIS (1UL << 0)#define GITS_TYPER_VLPIS (1UL << 1)#define GITS_TYPER_ITT_ENTRY_SIZE_SHIFT 4 -#define GITS_TYPER_ITT_ENTRY_SIZE (r) ((((r) >> GITS_TYPER_ITT_ENTRY_SIZE_SHIFT) & 0xf) + 1) +#define GITS_TYPER_ITT_ENTRY_SIZE GENMASK_ULL(7, 4)#define GITS_TYPER_IDBITS_SHIFT 8#define GITS_TYPER_DEVBITS_SHIFT 13#define GITS_TYPER_DEVBITS (r) ((((r) >> GITS_TYPER_DEVBITS_SHIFT) & 0x1f) + 1)
Marc Zyngier
maintainerPATCH v2 6/36 irqchip/gic-v3-its: Kill its->device_ids and use TYPER copy instead
In reply to Marc ZyngierNow that we have a copy of TYPER in the ITS structure, rely on this to provide the same service as its->device_ids, which gets axed. Errata workarounds are now updating the cached fields instead of requiring a separate field in the ITS structure.
--- drivers/irqchip/irq-gic-v3-its.c | 24 +++++++++++++----------- include/linux/irqchip/arm-gic-v3.h | 2 +- 2 files changed, 14 insertions(+), 12 deletions(-)
drivers/irqchip/irq-gic-v3-its.c +13 -11
@@ -109,7 +109,6 @@ struct its_node {struct list_head its_device_list;u64 flags;unsigned long list_nr; -u32 device_ids;int numa_node;unsigned int msi_domain_flags;u32 pre_its_base;/* for Socionext Synquacer */
@@ -117,6 +116,7 @@ struct its_node { };#define is_v4 (its) (!!((its)->typer & GITS_TYPER_VLPIS)) +#define device_ids (its) (FIELD_GET(GITS_TYPER_DEVBITS, (its)->typer) + 1)#define ITS_ITT_ALIGN SZ_256
@@ -1938,9 +1938,9 @@ static bool its_parse_indirect_baser(struct its_node *its,if (new_order >=MAX_ORDER ) { new_order =MAX_ORDER -1 ; ids =ilog2 (PAGE_ORDER_TO_SIZE (new_order) / (int )esz); -pr_warn ("ITS@%pa: %s Table too large, reduce ids %u->%u\n" , +pr_warn ("ITS@%pa: %s Table too large, reduce ids %llu->%u\n" , &its->phys_base, its_base_type_string[type], - its->device_ids, ids); +device_ids (its), ids); } *order = new_order;
@@ -1986,7 +1986,7 @@ static int its_alloc_tables(struct its_node *its)case GITS_BASER_TYPE_DEVICE : indirect =its_parse_indirect_baser (its, baser, psz, &order, - its->device_ids); +device_ids (its));break ;case GITS_BASER_TYPE_VCPU :
@@ -2377,7 +2377,7 @@ static bool its_alloc_device_table(struct its_node *its, u32 dev_id)/* Don't allow device id that exceeds ITS hardware limit */ if (!baser) -return (ilog2 (dev_id) < its->device_ids); +return (ilog2 (dev_id) <device_ids (its));return its_alloc_table_entry (its, baser, dev_id); }
@@ -3229,8 +3229,9 @@ static bool __maybe_unused its_enable_quirk_cavium_22375(void *data) {struct its_node *its = data; -/* erratum 22375: only alloc 8MB table size */ - its->device_ids =0x14 ;/* 20 bits, 8MB */ +/* erratum 22375: only alloc 8MB table size (20 bits) */ + its->typer &= ~GITS_TYPER_DEVBITS ; + its->typer |=FIELD_PREP (GITS_TYPER_DEVBITS ,20 -1 ); its->flags |=ITS_FLAGS_WORKAROUND_CAVIUM_22375 ;return true;
@@ -3285,8 +3286,10 @@ static bool __maybe_unused its_enable_quirk_socionext_synquacer(void *data) its->get_msi_base = its_irq_get_msi_base_pre_its; ids =ilog2 (pre_its_window[1 ]) -2 ; -if (its->device_ids > ids) - its->device_ids = ids; +if (device_ids (its) > ids) { + its->typer &= ~GITS_TYPER_DEVBITS ; + its->typer |=FIELD_PREP (GITS_TYPER_DEVBITS , ids -1 ); + }/* the pre-ITS breaks isolation, so disable MSI remapping */ its->msi_domain_flags &= ~IRQ_DOMAIN_FLAG_MSI_REMAP ;
@@ -3519,7 +3522,7 @@ static int its_init_vpe_domain(void) }/* Use the last possible DevID */ - devid =GENMASK (its->device_ids -1 ,0 ); + devid =GENMASK (device_ids (its) -1 ,0 ); vpe_proxy.dev =its_create_device (its, devid, entries, false);if (!vpe_proxy.dev) {kfree (vpe_proxy.vpes);
@@ -3620,7 +3623,6 @@ static int __init its_probe_one(struct resource *res, its->typer = typer; its->base = its_base; its->phys_base = res->start; - its->device_ids =GITS_TYPER_DEVBITS (typer);if (is_v4 (its)) {if (!(typer &GITS_TYPER_VMOVP )) { err =its_compute_its_list_map (res, its_base);
include/linux/irqchip/arm-gic-v3.h +1 -1
@@ -337,7 +337,7 @@#define GITS_TYPER_ITT_ENTRY_SIZE GENMASK_ULL(7, 4)#define GITS_TYPER_IDBITS_SHIFT 8#define GITS_TYPER_DEVBITS_SHIFT 13 -#define GITS_TYPER_DEVBITS (r) ((((r) >> GITS_TYPER_DEVBITS_SHIFT) & 0x1f) + 1) +#define GITS_TYPER_DEVBITS GENMASK_ULL(17, 13)#define GITS_TYPER_PTA (1UL << 19)#define GITS_TYPER_HCC_SHIFT 24#define GITS_TYPER_HCC (r) (((r) >> GITS_TYPER_HCC_SHIFT) & 0xff)
Signature · 6 lines
2.20.1 _______________________________________________ kvmarm mailing list [email protected] https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
Re: [PATCH v2 06/36] irqchip/gic-v3-its: Kill its->device_ids and use TYPER copy instead
Hi Marc,
Quoted 6 lines · Marc Zyngier
Now that we have a copy of TYPER in the ITS structure, rely on this to provide the same service as
its->device_ids, which gets axed. Errata workarounds are now updating the cached fields instead of requiring a separate field in the ITS structure.Signed-off-by Marc Zyngier <[email protected]>
Quoted 26 lines
--- drivers/irqchip/irq-gic-v3-its.c | 24 +++++++++++++----------- include/linux/irqchip/arm-gic-v3.h | 2 +- 2 files changed, 14 insertions(+), 12 deletions(-)drivers/irqchip/irq-gic-v3-its.c +1
-1@@ -109,7 +109,6 @@ struct its_node {struct list_head its_device_list;u64 flags;unsigned long list_nr; -u32 device_ids;int numa_node;unsigned int msi_domain_flags;u32 pre_its_base;/* for Socionext Synquacer */ @@ -117,6 +116,7 @@ struct its_node { };#define is_v4 (its) (!!((its)->typer & GITS_TYPER_VLPIS)) +#define device_ids (its) (FIELD_GET(GITS_TYPER_DEVBITS, (its)->typer) + 1)#define ITS_ITT_ALIGN SZ_256
drivers/irqchip/irq-gic-v3-its.c static bool its_parse_indirect_baser(struct its_node *its, · line 1943
Quoted 8 lines
drivers/irqchip/irq-gic-v3-its.c +2
-2@@ -1938,9 +1938,9 @@ static bool its_parse_indirect_baser(struct its_node *its,if (new_order >=MAX_ORDER ) { new_order =MAX_ORDER -1 ; ids =ilog2 (PAGE_ORDER_TO_SIZE (new_order) / (int )esz); -pr_warn ("ITS@%pa: %s Table too large, reduce ids %u->%u\n" , +pr_warn ("ITS@%pa: %s Table too large, reduce ids %llu->%u\n" , &its->phys_base, its_base_type_string[type], - its->device_ids, ids); +device_ids (its), ids);
But this pr_warn() looks a bit odd. The table type is chosen from its_base_type_string[], but ids is always Devbits (+1)?
Thanks,
Zenghui
_______________________________________________
kvmarm mailing list
[email protected]
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
Marc Zyngier
maintainerRe: [PATCH v2 06/36] irqchip/gic-v3-its: Kill its->device_ids and use TYPER copy instead
Hi Zenghui,
Quoted 4 lines · Zenghui Yu
Hi Marc,
On 2019/10/27 22:42, Marc Zyngier wrote:
Quoted 8 lines
Quoted 6 lines
Now that we have a copy of TYPER in the ITS structure, rely on this to provide the same service as
its->device_ids, which gets axed. Errata workarounds are now updating the cached fields instead of requiring a separate field in the ITS structure.Signed-off-by Marc Zyngier <[email protected]>Reviewed-by Zenghui Yu <[email protected]>
Thanks for that.
Quoted 29 lines
Quoted 29 lines
--- drivers/irqchip/irq-gic-v3-its.c | 24 +++++++++++++----------- include/linux/irqchip/arm-gic-v3.h | 2 +- 2 files changed, 14 insertions(+), 12 deletions(-)drivers/irqchip/irq-gic-v3-its.c +1
-1@@ -109,7 +109,6 @@ struct its_node {struct list_head its_device_list;u64 flags;unsigned long list_nr; -u32 device_ids;int numa_node;unsigned int msi_domain_flags;u32 pre_its_base;/* for Socionext Synquacer */ @@ -117,6 +116,7 @@ struct its_node { };#define is_v4 (its) (!!((its)->typer & GITS_TYPER_VLPIS)) +#define device_ids (its) (FIELD_GET(GITS_TYPER_DEVBITS, (its)->typer) + 1)#define ITS_ITT_ALIGN SZ_256 @@ -1938,9 +1938,9 @@ static bool its_parse_indirect_baser(struct its_node *its,if (new_order >= MAX_ORDER) { new_order = MAX_ORDER - 1; ids = ilog2(PAGE_ORDER_TO_SIZE(new_order) / (int)esz);
Quoted 8 lines
drivers/irqchip/irq-gic-v3-its.c static bool its_parse_indirect_baser(struct its_node *its, · line 1943
Quoted 5 lines
drivers/irqchip/irq-gic-v3-its.c +2
-2-pr_warn ("ITS@%pa: %s Table too large, reduce ids %u->%u\n" , +pr_warn ("ITS@%pa: %s Table too large, reduce ids %llu->%u\n" , &its->phys_base, its_base_type_string[type], - its->device_ids, ids); +device_ids (its), ids);But this
pr_warn()looks a bit odd. The table type is chosen from its_base_type_string[], but ids is always Devbits (+1)?
This is a bit of a shortcut, I agree. But the device table practically is the only one where we can run out of space if the ITS doesn't support two level tables. All the other tables are very small, being limited by the number of CPUs (collections) or a small ID space (vPEs).
So while this is a bit ugly, I don't thing it is not too concerning.
Thanks,
M.
Signature · 5 lines
Jazz is not dead, it just smells funny. _______________________________________________ kvmarm mailing list [email protected] https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
Zenghui Yu
reviewerRe: [PATCH v2 06/36] irqchip/gic-v3-its: Kill its->device_ids and use TYPER copy instead
Quoted 57 lines · Marc Zyngier
Hi Zenghui,
Quoted 4 lines · Zenghui Yu
Hi Marc,
On 2019/10/27 22:42, Marc Zyngier wrote:
Quoted 8 lines
Quoted 6 lines
Now that we have a copy of TYPER in the ITS structure, rely on this to provide the same service as
its->device_ids, which gets axed. Errata workarounds are now updating the cached fields instead of requiring a separate field in the ITS structure.Signed-off-by Marc Zyngier <[email protected]>Reviewed-by Zenghui Yu <[email protected]>Thanks for that.
Quoted 29 lines
Quoted 29 lines
--- drivers/irqchip/irq-gic-v3-its.c | 24 +++++++++++++----------- include/linux/irqchip/arm-gic-v3.h | 2 +- 2 files changed, 14 insertions(+), 12 deletions(-)drivers/irqchip/irq-gic-v3-its.c +1
-1@@ -109,7 +109,6 @@ struct its_node {struct list_head its_device_list;u64 flags;unsigned long list_nr; -u32 device_ids;int numa_node;unsigned int msi_domain_flags;u32 pre_its_base;/* for Socionext Synquacer */ @@ -117,6 +116,7 @@ struct its_node { };#define is_v4 (its) (!!((its)->typer & GITS_TYPER_VLPIS)) +#define device_ids (its) (FIELD_GET(GITS_TYPER_DEVBITS, (its)->typer) + 1)#define ITS_ITT_ALIGN SZ_256 @@ -1938,9 +1938,9 @@ static bool its_parse_indirect_baser(struct its_node *its,if (new_order >= MAX_ORDER) { new_order = MAX_ORDER - 1; ids = ilog2(PAGE_ORDER_TO_SIZE(new_order) / (int)esz);Quoted 8 lines
drivers/irqchip/irq-gic-v3-its.c static bool its_parse_indirect_baser(struct its_node *its, · line 1943
Quoted 5 lines
drivers/irqchip/irq-gic-v3-its.c +2
-2-pr_warn ("ITS@%pa: %s Table too large, reduce ids %u->%u\n" , +pr_warn ("ITS@%pa: %s Table too large, reduce ids %llu->%u\n" , &its->phys_base, its_base_type_string[type], - its->device_ids, ids); +device_ids (its), ids);But this
pr_warn()looks a bit odd. The table type is chosen from its_base_type_string[], but ids is always Devbits (+1)?
Quoted 5 lines
This is a bit of a shortcut, I agree. But the device table practically is the only one where we can run out of space if the ITS doesn't support two level tables. All the other tables are very small, being limited by the number of CPUs (collections) or a small ID space (vPEs).
Make sense. Thanks for the clarification.
Zenghui
Quoted 7 lines
So while this is a bit ugly, I don't thing it is not too concerning.
Thanks,
M.
[tip: irq/core] irqchip/gic-v3-its: Kill its->device_ids and use TYPER copy instead
In reply to Marc ZyngierThe following commit has been merged into the irq/core branch of tip:
The following commit has been merged into the irq/core branch of tip:
Commit-ID: 576a83429757999f220f36f206044af2b9026672 Gitweb: https://git.kernel.org/tip/576a83429757999f220f36f206044af2b9026672 Author: Marc Zyngier <[email protected]> AuthorDate: Fri, 08 Nov 2019 16:58:00 Committer: Marc Zyngier <[email protected]> CommitterDate: Sun, 10 Nov 2019 18:47:52
irqchip/gic-v3-its: Kill its->device_ids and use TYPER copy instead
Now that we have a copy of TYPER in the ITS structure, rely on this to provide the same service as its->device_ids, which gets axed. Errata workarounds are now updating the cached fields instead of requiring a separate field in the ITS structure.
--- drivers/irqchip/irq-gic-v3-its.c | 24 +++++++++++++----------- include/linux/irqchip/arm-gic-v3.h | 2 +- 2 files changed, 14 insertions(+), 12 deletions(-)
drivers/irqchip/irq-gic-v3-its.c +13 -11
@@ -109,7 +109,6 @@ struct its_node {struct list_head its_device_list;u64 flags;unsigned long list_nr; -u32 device_ids;int numa_node;unsigned int msi_domain_flags;u32 pre_its_base;/* for Socionext Synquacer */
@@ -117,6 +116,7 @@ struct its_node { };#define is_v4 (its) (!!((its)->typer & GITS_TYPER_VLPIS)) +#define device_ids (its) (FIELD_GET(GITS_TYPER_DEVBITS, (its)->typer) + 1)#define ITS_ITT_ALIGN SZ_256
@@ -1956,9 +1956,9 @@ static bool its_parse_indirect_baser(struct its_node *its,if (new_order >=MAX_ORDER ) { new_order =MAX_ORDER -1 ; ids =ilog2 (PAGE_ORDER_TO_SIZE (new_order) / (int )esz); -pr_warn ("ITS@%pa: %s Table too large, reduce ids %u->%u\n" , +pr_warn ("ITS@%pa: %s Table too large, reduce ids %llu->%u\n" , &its->phys_base, its_base_type_string[type], - its->device_ids, ids); +device_ids (its), ids); } *order = new_order;
@@ -2004,7 +2004,7 @@ static int its_alloc_tables(struct its_node *its)case GITS_BASER_TYPE_DEVICE : indirect =its_parse_indirect_baser (its, baser, psz, &order, - its->device_ids); +device_ids (its));break ;case GITS_BASER_TYPE_VCPU :
@@ -2395,7 +2395,7 @@ static bool its_alloc_device_table(struct its_node *its, u32 dev_id)/* Don't allow device id that exceeds ITS hardware limit */ if (!baser) -return (ilog2 (dev_id) < its->device_ids); +return (ilog2 (dev_id) <device_ids (its));return its_alloc_table_entry (its, baser, dev_id); }
@@ -3247,8 +3247,9 @@ static bool __maybe_unused its_enable_quirk_cavium_22375(void *data) {struct its_node *its = data; -/* erratum 22375: only alloc 8MB table size */ - its->device_ids =0x14 ;/* 20 bits, 8MB */ +/* erratum 22375: only alloc 8MB table size (20 bits) */ + its->typer &= ~GITS_TYPER_DEVBITS ; + its->typer |=FIELD_PREP (GITS_TYPER_DEVBITS ,20 -1 ); its->flags |=ITS_FLAGS_WORKAROUND_CAVIUM_22375 ;return true;
@@ -3303,8 +3304,10 @@ static bool __maybe_unused its_enable_quirk_socionext_synquacer(void *data) its->get_msi_base = its_irq_get_msi_base_pre_its; ids =ilog2 (pre_its_window[1 ]) -2 ; -if (its->device_ids > ids) - its->device_ids = ids; +if (device_ids (its) > ids) { + its->typer &= ~GITS_TYPER_DEVBITS ; + its->typer |=FIELD_PREP (GITS_TYPER_DEVBITS , ids -1 ); + }/* the pre-ITS breaks isolation, so disable MSI remapping */ its->msi_domain_flags &= ~IRQ_DOMAIN_FLAG_MSI_REMAP ;
@@ -3537,7 +3540,7 @@ static int its_init_vpe_domain(void) }/* Use the last possible DevID */ - devid =GENMASK (its->device_ids -1 ,0 ); + devid =GENMASK (device_ids (its) -1 ,0 ); vpe_proxy.dev =its_create_device (its, devid, entries, false);if (!vpe_proxy.dev) {kfree (vpe_proxy.vpes);
@@ -3638,7 +3641,6 @@ static int __init its_probe_one(struct resource *res, its->typer = typer; its->base = its_base; its->phys_base = res->start; - its->device_ids =GITS_TYPER_DEVBITS (typer);if (is_v4 (its)) {if (!(typer &GITS_TYPER_VMOVP )) { err =its_compute_its_list_map (res, its_base);
include/linux/irqchip/arm-gic-v3.h +1 -1
@@ -337,7 +337,7 @@#define GITS_TYPER_ITT_ENTRY_SIZE GENMASK_ULL(7, 4)#define GITS_TYPER_IDBITS_SHIFT 8#define GITS_TYPER_DEVBITS_SHIFT 13 -#define GITS_TYPER_DEVBITS (r) ((((r) >> GITS_TYPER_DEVBITS_SHIFT) & 0x1f) + 1) +#define GITS_TYPER_DEVBITS GENMASK_ULL(17, 13)#define GITS_TYPER_PTA (1UL << 19)#define GITS_TYPER_HCC_SHIFT 24#define GITS_TYPER_HCC (r) (((r) >> GITS_TYPER_HCC_SHIFT) & 0xff)
Marc Zyngier
maintainerPATCH v2 7/36 irqchip/gic-v3-its: Add get_vlpi_map() helper
In reply to Marc ZyngierObtaining the mapping information for a VLPI is something quite common, and the GICv4.1 code is going to make even more use of it. Expose it as a separate helper.
--- drivers/irqchip/irq-gic-v3-its.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-)
drivers/irqchip/irq-gic-v3-its.c +16 -11
@@ -1045,20 +1045,26 @@ static void its_send_vinvall(struct its_node *its, struct its_vpe *vpe)/* * irqchip functions - assumes MSI, mostly. */ +static struct its_vlpi_map *get_vlpi_map (struct irq_data *d) +{ +struct its_device *its_dev =irq_data_get_irq_chip_data (d); +u32 event =its_get_event_id (d); + +if (!irqd_is_forwarded_to_vcpu (d)) +return NULL ; + +return &its_dev->event_map.vlpi_maps[event]; +}static void lpi_write_config (struct irq_data *d,u8 clr,u8 set) { +struct its_vlpi_map *map =get_vlpi_map (d);irq_hw_number_t hwirq;void *va;u8 *cfg; -if (irqd_is_forwarded_to_vcpu (d)) { -struct its_device *its_dev =irq_data_get_irq_chip_data (d); -u32 event =its_get_event_id (d); -struct its_vlpi_map *map; - - va =page_address (its_dev->event_map.vm->vprop_page); - map = &its_dev->event_map.vlpi_maps[event]; +if (map) { + va =page_address (map->vm->vprop_page); hwirq = map->vintid;/* Remember the updated property */
@@ -1351,19 +1357,18 @@ static int its_vlpi_map(struct irq_data *d, struct its_cmd_info *info)static int its_vlpi_get (struct irq_data *d,struct its_cmd_info *info) {struct its_device *its_dev =irq_data_get_irq_chip_data (d); -u32 event =its_get_event_id (d); +struct its_vlpi_map *map =get_vlpi_map (d);int ret =0 ;mutex_lock (&its_dev->event_map.vlpi_lock); -if (!its_dev->event_map.vm || - !its_dev->event_map.vlpi_maps[event].vm) { +if (!its_dev->event_map.vm || !map->vm) { ret = -EINVAL ; goto out; }/* Copy our mapping information to the incoming request */ - *info->map = its_dev->event_map.vlpi_maps[event]; + *info->map = *map; out:mutex_unlock (&its_dev->event_map.vlpi_lock);
Signature · 6 lines
2.20.1 _______________________________________________ kvmarm mailing list [email protected] https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
Re: [PATCH v2 07/36] irqchip/gic-v3-its: Add get_vlpi_map() helper
Quoted 5 lines · Marc Zyngier
Obtaining the mapping information for a VLPI is something quite common, and the GICv4.1 code is going to make even more use of it. Expose it as a separate helper.
Signed-off-by Marc Zyngier <[email protected]>
[tip: irq/core] irqchip/gic-v3-its: Add its_vlpi_map helpers
In reply to Marc ZyngierThe following commit has been merged into the irq/core branch of tip:
The following commit has been merged into the irq/core branch of tip:
Commit-ID: c1d4d5cd203cc8ec83d67d4e2af51f1a9f01ba34 Gitweb: https://git.kernel.org/tip/c1d4d5cd203cc8ec83d67d4e2af51f1a9f01ba34 Author: Marc Zyngier <[email protected]> AuthorDate: Fri, 08 Nov 2019 16:58:01 Committer: Marc Zyngier <[email protected]> CommitterDate: Sun, 10 Nov 2019 18:47:52
irqchip/gic-v3-its: Add its_vlpi_map helpers
Obtaining the mapping information for a VLPI is something quite common, and the GICv4.1 code is going to make even more use of it. Expose it as a separate set of helpers.
--- drivers/irqchip/irq-gic-v3-its.c | 47 +++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 15 deletions(-)
drivers/irqchip/irq-gic-v3-its.c +32 -15
@@ -207,6 +207,15 @@ static struct its_collection *dev_event_to_col(struct its_device *its_dev,return its->collections + its_dev->event_map.col_map[event]; } +static struct its_vlpi_map *dev_event_to_vlpi_map (struct its_device *its_dev, +u32 event) +{ +if (WARN_ON_ONCE (event >= its_dev->event_map.nr_lpis)) +return NULL ; + +return &its_dev->event_map.vlpi_maps[event]; +} +static struct its_collection *irq_to_col (struct irq_data *d) {struct its_device *its_dev =irq_data_get_irq_chip_data (d);
@@ -971,7 +980,7 @@ static void its_send_invall(struct its_node *its, struct its_collection *col)static void its_send_vmapti (struct its_device *dev,u32 id) { -struct its_vlpi_map *map = &dev->event_map.vlpi_maps[id]; +struct its_vlpi_map *map =dev_event_to_vlpi_map (dev, id);struct its_cmd_desc desc; desc.its_vmapti_cmd.vpe = map->vpe;
@@ -985,7 +994,7 @@ static void its_send_vmapti(struct its_device *dev, u32 id)static void its_send_vmovi (struct its_device *dev,u32 id) { -struct its_vlpi_map *map = &dev->event_map.vlpi_maps[id]; +struct its_vlpi_map *map =dev_event_to_vlpi_map (dev, id);struct its_cmd_desc desc; desc.its_vmovi_cmd.vpe = map->vpe;
@@ -1063,20 +1072,26 @@ static void its_send_vinvall(struct its_node *its, struct its_vpe *vpe)/* * irqchip functions - assumes MSI, mostly. */ +static struct its_vlpi_map *get_vlpi_map (struct irq_data *d) +{ +struct its_device *its_dev =irq_data_get_irq_chip_data (d); +u32 event =its_get_event_id (d); + +if (!irqd_is_forwarded_to_vcpu (d)) +return NULL ; + +return dev_event_to_vlpi_map (its_dev, event); +}static void lpi_write_config (struct irq_data *d,u8 clr,u8 set) { +struct its_vlpi_map *map =get_vlpi_map (d);irq_hw_number_t hwirq;void *va;u8 *cfg; -if (irqd_is_forwarded_to_vcpu (d)) { -struct its_device *its_dev =irq_data_get_irq_chip_data (d); -u32 event =its_get_event_id (d); -struct its_vlpi_map *map; - - va =page_address (its_dev->event_map.vm->vprop_page); - map = &its_dev->event_map.vlpi_maps[event]; +if (map) { + va =page_address (map->vm->vprop_page); hwirq = map->vintid;/* Remember the updated property */
@@ -1136,11 +1151,14 @@ static void its_vlpi_set_doorbell(struct irq_data *d, bool enable) {struct its_device *its_dev =irq_data_get_irq_chip_data (d);u32 event =its_get_event_id (d); +struct its_vlpi_map *map; -if (its_dev->event_map.vlpi_maps[event].db_enabled == enable) + map =dev_event_to_vlpi_map (its_dev, event); + +if (map->db_enabled == enable)return ; - its_dev->event_map.vlpi_maps[event].db_enabled = enable; + map->db_enabled = enable;/* * More fun with the architecture:
@@ -1369,19 +1387,18 @@ out:static int its_vlpi_get (struct irq_data *d,struct its_cmd_info *info) {struct its_device *its_dev =irq_data_get_irq_chip_data (d); -u32 event =its_get_event_id (d); +struct its_vlpi_map *map =get_vlpi_map (d);int ret =0 ;mutex_lock (&its_dev->event_map.vlpi_lock); -if (!its_dev->event_map.vm || - !its_dev->event_map.vlpi_maps[event].vm) { +if (!its_dev->event_map.vm || !map->vm) { ret = -EINVAL ; goto out; }/* Copy our mapping information to the incoming request */ - *info->map = its_dev->event_map.vlpi_maps[event]; + *info->map = *map; out:mutex_unlock (&its_dev->event_map.vlpi_lock);
Marc Zyngier
maintainerPATCH v2 8/36 irqchip/gic-v3: Detect GICv4.1 supporting RVPEID
In reply to Marc ZyngierGICv4.1 supports the RVPEID ("Residency per vPE ID"), which allows for a much efficient way of making virtual CPUs resident (to allow direct injection of interrupts).
The functionnality needs to be discovered on each and every redistributor in the system, and disabled if the settings are inconsistent.
--- drivers/irqchip/irq-gic-v3.c | 21 ++++++++++++++++++--- include/linux/irqchip/arm-gic-v3.h | 2 ++ 2 files changed, 20 insertions(+), 3 deletions(-)
drivers/irqchip/irq-gic-v3.c +18 -3
@@ -849,8 +849,21 @@ static int __gic_update_rdist_properties(struct redist_region *region, void __iomem *ptr) {u64 typer =gic_read_typer (ptr +GICR_TYPER ); + gic_data.rdists.has_vlpis &= !!(typer &GICR_TYPER_VLPIS ); - gic_data.rdists.has_direct_lpi &= !!(typer & GICR_TYPER_DirectLPIS); + +/* RVPEID implies some form of DirectLPI, no matter what the doc says... :-/ */ + gic_data.rdists.has_rvpeid &= !!(typer &GICR_TYPER_RVPEID ); + gic_data.rdists.has_direct_lpi &= (!!(typer & GICR_TYPER_DirectLPIS) | + gic_data.rdists.has_rvpeid); + +/* Detect non-sensical configurations */ +if (WARN_ON_ONCE (gic_data.rdists.has_rvpeid && !gic_data.rdists.has_vlpis)) { + gic_data.rdists.has_direct_lpi = false; + gic_data.rdists.has_vlpis = false; + gic_data.rdists.has_rvpeid = false; + } + gic_data.ppi_nr =min (GICR_TYPER_NR_PPIS (typer), gic_data.ppi_nr);return 1 ;
@@ -863,9 +876,10 @@ static void gic_update_rdist_properties(void)if (WARN_ON (gic_data.ppi_nr ==UINT_MAX )) gic_data.ppi_nr =0 ;pr_info ("%d PPIs implemented\n" , gic_data.ppi_nr); -pr_info ("%sVLPI support, %sdirect LPI support\n" , +pr_info ("%sVLPI support, %sdirect LPI support, %sRVPEID support\n" , !gic_data.rdists.has_vlpis ?"no " :"" , - !gic_data.rdists.has_direct_lpi ?"no " :"" ); + !gic_data.rdists.has_direct_lpi ?"no " :"" , + !gic_data.rdists.has_rvpeid ?"no " :"" ); }/* Check whether it's single security state view */
@@ -1546,6 +1560,7 @@ static int __init gic_init_bases(void __iomem *dist_base, &gic_data);irq_domain_update_bus_token (gic_data.domain,DOMAIN_BUS_WIRED ); gic_data.rdists.rdist =alloc_percpu (typeof (*gic_data.rdists.rdist)); + gic_data.rdists.has_rvpeid = true; gic_data.rdists.has_vlpis = true; gic_data.rdists.has_direct_lpi = true;
include/linux/irqchip/arm-gic-v3.h +2 -0
@@ -234,6 +234,7 @@#define GICR_TYPER_VLPIS (1U << 1)#define GICR_TYPER_DirectLPIS (1U << 3)#define GICR_TYPER_LAST (1U << 4) +#define GICR_TYPER_RVPEID (1U << 7)#define GIC_V3_REDIST_SIZE 0x20000
@@ -613,6 +614,7 @@ struct rdists {u64 flags;u32 gicd_typer;bool has_vlpis; +bool has_rvpeid;bool has_direct_lpi; };
Signature · 6 lines
2.20.1 _______________________________________________ kvmarm mailing list [email protected] https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
Re: [PATCH v2 08/36] irqchip/gic-v3: Detect GICv4.1 supporting RVPEID
Hi Marc,
Quoted 8 lines · Marc Zyngier
GICv4.1 supports the RVPEID ("Residency per vPE ID"), which allows for a much efficient way of making virtual CPUs resident (to allow direct injection of interrupts).
The functionnality needs to be discovered on each and every redistributor in the system, and disabled if the settings are inconsistent.
Signed-off-by Marc Zyngier <[email protected]>
Marc Zyngier
maintainerPATCH v2 9/36 irqchip/gic-v3: Add GICv4.1 VPEID size discovery
In reply to Marc ZyngierWhile GICv4.0 mandates 16 bit worth of VPEIDs, GICv4.1 allows smaller implementations to be built. Add the required glue to dynamically compute the limit.
--- drivers/irqchip/irq-gic-v3-its.c | 11 ++++++++++- drivers/irqchip/irq-gic-v3.c | 3 +++ include/linux/irqchip/arm-gic-v3.h | 5 +++++ 3 files changed, 18 insertions(+), 1 deletion(-)
drivers/irqchip/irq-gic-v3-its.c +10 -1
@@ -121,7 +121,16 @@ struct its_node {#define ITS_ITT_ALIGN SZ_256/* The maximum number of VPEID bits supported by VLPI commands */ -#define ITS_MAX_VPEID_BITS (16) +#define ITS_MAX_VPEID_BITS \ + ({ \ + int nvpeid = 16; \ + if (gic_rdists->has_rvpeid && \ + gic_rdists->gicd_typer2 & GICD_TYPER2_VIL) \ + nvpeid = 1 + (gic_rdists->gicd_typer2 & \ + GICD_TYPER2_VID); \ + \ + nvpeid; \ + })#define ITS_MAX_VPEID (1 << (ITS_MAX_VPEID_BITS))/* Convert page order to size in bytes */
drivers/irqchip/irq-gic-v3.c +3 -0
@@ -1556,6 +1556,9 @@ static int __init gic_init_bases(void __iomem *dist_base,pr_info ("%d SPIs implemented\n" ,GIC_LINE_NR -32 );pr_info ("%d Extended SPIs implemented\n" ,GIC_ESPI_NR ); + + gic_data.rdists.gicd_typer2 =readl_relaxed (gic_data.dist_base +GICD_TYPER2 ); + gic_data.domain =irq_domain_create_tree (handle, &gic_irq_domain_ops, &gic_data);irq_domain_update_bus_token (gic_data.domain,DOMAIN_BUS_WIRED );
include/linux/irqchip/arm-gic-v3.h +5 -0
@@ -13,6 +13,7 @@#define GICD_CTLR 0x0000#define GICD_TYPER 0x0004#define GICD_IIDR 0x0008 +#define GICD_TYPER2 0x000C#define GICD_STATUSR 0x0010#define GICD_SETSPI_NSR 0x0040#define GICD_CLRSPI_NSR 0x0048
@@ -89,6 +90,9 @@#define GICD_TYPER_ESPIS (typer) \ (((typer) & GICD_TYPER_ESPI) ? GICD_TYPER_SPIS((typer) >> 27) : 0) +#define GICD_TYPER2_VIL (1U << 7) +#define GICD_TYPER2_VID GENMASK(4, 0) +#define GICD_IROUTER_SPI_MODE_ONE (0U << 31)#define GICD_IROUTER_SPI_MODE_ANY (1U << 31)
@@ -613,6 +617,7 @@ struct rdists {void *prop_table_va;u64 flags;u32 gicd_typer; +u32 gicd_typer2;bool has_vlpis;bool has_rvpeid;bool has_direct_lpi;
Signature · 1 line
2.20.1
Re: [PATCH v2 09/36] irqchip/gic-v3: Add GICv4.1 VPEID size discovery
Hi Marc,
Quoted 17 lines · Marc Zyngier
While GICv4.0 mandates 16 bit worth of VPEIDs, GICv4.1 allows smaller implementations to be built. Add the required glue to dynamically compute the limit.
Signed-off-by Marc Zyngier <[email protected]>--- drivers/irqchip/irq-gic-v3-its.c | 11 ++++++++++- drivers/irqchip/irq-gic-v3.c | 3 +++ include/linux/irqchip/arm-gic-v3.h | 5 +++++ 3 files changed, 18 insertions(+), 1 deletion(-)drivers/irqchip/irq-gic-v3-its.c +0
-0@@ -121,7 +121,16 @@ struct its_node {#define ITS_ITT_ALIGN SZ_256
drivers/irqchip/irq-gic-v3-its.c struct its_node { · line 130
Quoted 10 lines
drivers/irqchip/irq-gic-v3-its.c +7
-1/* The maximum number of VPEID bits supported by VLPI commands */ -#define ITS_MAX_VPEID_BITS (16) +#define ITS_MAX_VPEID_BITS \ + ({ \ + int nvpeid = 16; \ + if (gic_rdists->has_rvpeid && \ + gic_rdists->gicd_typer2 & GICD_TYPER2_VIL) \ + nvpeid = 1 + (gic_rdists->gicd_typer2 & \ + GICD_TYPER2_VID); \
Does it make sense to let nvpeid not more than 16 here? As the spec says "Values above 0x0F are RESERVED". But I don't know why should we have this restriction ;-)
Either way,
Thanks
Quoted 51 lines
drivers/irqchip/irq-gic-v3-its.c +3
-0+ \ + nvpeid; \ + })#define ITS_MAX_VPEID (1 << (ITS_MAX_VPEID_BITS))/* Convert page order to size in bytes */ drivers/irqchip/irq-gic-v3.c +3
-0@@ -1556,6 +1556,9 @@ static int __init gic_init_bases(void __iomem *dist_base,pr_info ("%d SPIs implemented\n" ,GIC_LINE_NR -32 );pr_info ("%d Extended SPIs implemented\n" ,GIC_ESPI_NR ); + + gic_data.rdists.gicd_typer2 =readl_relaxed (gic_data.dist_base +GICD_TYPER2 ); + gic_data.domain =irq_domain_create_tree (handle, &gic_irq_domain_ops, &gic_data);irq_domain_update_bus_token (gic_data.domain,DOMAIN_BUS_WIRED );include/linux/irqchip/arm-gic-v3.h +5
-0@@ -13,6 +13,7 @@#define GICD_CTLR 0x0000#define GICD_TYPER 0x0004#define GICD_IIDR 0x0008 +#define GICD_TYPER2 0x000C#define GICD_STATUSR 0x0010#define GICD_SETSPI_NSR 0x0040#define GICD_CLRSPI_NSR 0x0048@@ -89,6 +90,9 @@#define GICD_TYPER_ESPIS (typer) \ (((typer) & GICD_TYPER_ESPI) ? GICD_TYPER_SPIS((typer) >> 27) : 0) +#define GICD_TYPER2_VIL (1U << 7) +#define GICD_TYPER2_VID GENMASK(4, 0) +#define GICD_IROUTER_SPI_MODE_ONE (0U << 31)#define GICD_IROUTER_SPI_MODE_ANY (1U << 31)@@ -613,6 +617,7 @@ struct rdists {void *prop_table_va;u64 flags;u32 gicd_typer; +u32 gicd_typer2;bool has_vlpis;bool has_rvpeid;bool has_direct_lpi;
Marc Zyngier
maintainerRe: [PATCH v2 09/36] irqchip/gic-v3: Add GICv4.1 VPEID size discovery
Quoted 27 lines · Zenghui Yu
Hi Marc,
Quoted 23 lines · Marc Zyngier
While GICv4.0 mandates 16 bit worth of VPEIDs, GICv4.1 allows smaller implementations to be built. Add the required glue to dynamically compute the limit.
Signed-off-by Marc Zyngier <[email protected]>--- drivers/irqchip/irq-gic-v3-its.c | 11 ++++++++++- drivers/irqchip/irq-gic-v3.c | 3 +++ include/linux/irqchip/arm-gic-v3.h | 5 +++++ 3 files changed, 18 insertions(+), 1 deletion(-)drivers/irqchip/irq-gic-v3-its.c +3
-1@@ -121,7 +121,16 @@ struct its_node {#define ITS_ITT_ALIGN SZ_256/* The maximum number of VPEID bits supported by VLPI commands */ -#define ITS_MAX_VPEID_BITS (16) +#define ITS_MAX_VPEID_BITS \ + ({ \ + int nvpeid = 16; \
Quoted 8 lines
drivers/irqchip/irq-gic-v3-its.c struct its_node { · line 130
Quoted 4 lines
drivers/irqchip/irq-gic-v3-its.c +4
-0+if (gic_rdists->has_rvpeid && \ + gic_rdists->gicd_typer2 &GICD_TYPER2_VIL ) \ + nvpeid =1 + (gic_rdists->gicd_typer2 & \ +GICD_TYPER2_VID ); \Does it make sense to let nvpeid not more than 16 here? As the spec says "Values above
0x0Fare RESERVED". But I don't know why should we have this restriction ;-)
This is something that Andrew raised in the previous version. My take on this is that properly implemented HW should give us something that matches the spec (in the 0-15 range), and I don't think that guarding against that is useful at this stage.
My understanding is that once the architecture allows using the 16-31 range, we'll either use it directly because it is just a natural extension to the existing range, or they mean something different altogether and we'll get a new discovery bit somewhere.
Quoted 3 lines
Either way,
Reviewed-by Zenghui Yu <[email protected]>
Thanks,
M.
Signature · 1 line
Jazz is not dead, it just smells funny.
Marc Zyngier
maintainerPATCH v2 10/36 irqchip/gic-v3: Workaround Cavium TX1 erratum when reading GICD_TYPER2
In reply to Marc ZyngierDespite the architecture spec being extremely clear about the fact that reserved registers in the GIC distributor memory map are RES0 (and thus are not allowed to generate an exception), the Cavium ThunderX (aka TX1) SoC explodes as such:
[ 0.000000] GICv3: GIC: Using split EOI/Deactivate mode [ 0.000000] GICv3: 128 SPIs implemented [ 0.000000] GICv3: 0 Extended SPIs implemented [ 0.000000] Internal error: synchronous external abort: 96000210 [#1] SMP [ 0.000000] Modules linked in: [ 0.000000] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 5.4.0-rc4-00035-g3cf6a3d5725f #7956 [ 0.000000] Hardware name: cavium,thunder-88xx (DT) [ 0.000000] pstate: 60000085 (nZCv daIf -PAN -UAO) [ 0.000000] pc : __raw_readl+0x0/0x8 [ 0.000000] lr : gic_init_bases+0x110/0x560 [ 0.000000] sp : ffff800011243d90 [ 0.000000] x29: ffff800011243d90 x28: 0000000000000000 [ 0.000000] x27: 0000000000000018 x26: 0000000000000002 [ 0.000000] x25: ffff8000116f0000 x24: ffff000fbe6a2c80 [ 0.000000] x23: 0000000000000000 x22: ffff010fdc322b68 [ 0.000000] x21: ffff800010a7a208 x20: 00000000009b0404 [ 0.000000] x19: ffff80001124dad0 x18: 0000000000000010 [ 0.000000] x17: 000000004d8d492b x16: 00000000f67eb9af [ 0.000000] x15: ffffffffffffffff x14: ffff800011249908 [ 0.000000] x13: ffff800091243ae7 x12: ffff800011243af4 [ 0.000000] x11: ffff80001126e000 x10: ffff800011243a70 [ 0.000000] x9 : 00000000ffffffd0 x8 : ffff80001069c828 [ 0.000000] x7 : 0000000000000059 x6 : ffff8000113fb4d1 [ 0.000000] x5 : 0000000000000001 x4 : 0000000000000000 [ 0.000000] x3 : 0000000000000000 x2 : 0000000000000000 [ 0.000000] x1 : 0000000000000000 x0 : ffff8000116f000c [ 0.000000] Call trace: [ 0.000000] __raw_readl+0x0/0x8 [ 0.000000] gic_of_init+0x188/0x224 [ 0.000000] of_irq_init+0x200/0x3cc [ 0.000000] irqchip_init+0x1c/0x40 [ 0.000000] init_IRQ+0x160/0x1d0 [ 0.000000] start_kernel+0x2ec/0x4b8 [ 0.000000] Code: a8c47bfd d65f03c0 d538d080 d65f03c0 (b9400000)
when reading the GICv4.1 GICD_TYPER2 register, which is unexpected...
Work around it by adding a new quirk flagging all the A1 revisions of the distributor, but it remains unknown whether this could affect other revisions of this SoC (or even other SoCs from the same silicon vendor).
--- drivers/irqchip/irq-gic-v3.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-)
drivers/irqchip/irq-gic-v3.c +22 -1
@@ -34,6 +34,7 @@#define GICD_INT_NMI_PRI (GICD_INT_DEF_PRI & ~0x80)#define FLAGS_WORKAROUND_GICR_WAKER_MSM8996 (1ULL << 0) +#define FLAGS_WORKAROUND_GICD_TYPER2_TX1 (1ULL << 1)struct redist_region {void __iomem *redist_base;
@@ -1455,6 +1456,15 @@ static bool gic_enable_quirk_msm8996(void *data)return true; } +static bool gic_enable_quirk_tx1 (void *data) +{ +struct gic_chip_data *d = data; + + d->flags |=FLAGS_WORKAROUND_GICD_TYPER2_TX1 ; + +return true; +} +static bool gic_enable_quirk_hip06_07 (void *data) {struct gic_chip_data *d = data;
@@ -1493,6 +1503,12 @@ static const struct gic_quirk gic_quirks[] = { .mask = 0xffffffff, .init = gic_enable_quirk_hip06_07, }, + { + .desc = "GICv3: Cavium TX1 GICD_TYPER2 erratum", + .iidr = 0xa100034c, + .mask = 0xfff00fff, + .init = gic_enable_quirk_tx1, + }, { } };
@@ -1557,7 +1573,12 @@ static int __init gic_init_bases(void __iomem *dist_base,pr_info ("%d SPIs implemented\n" ,GIC_LINE_NR -32 );pr_info ("%d Extended SPIs implemented\n" ,GIC_ESPI_NR ); - gic_data.rdists.gicd_typer2 =readl_relaxed (gic_data.dist_base +GICD_TYPER2 ); +/* +* ThunderX1 explodes on reading GICD_TYPER2, in total violation +* of the spec (which says that reserved addresses are RES0). +*/ +if (!(gic_data.flags &FLAGS_WORKAROUND_GICD_TYPER2_TX1 )) + gic_data.rdists.gicd_typer2 =readl_relaxed (gic_data.dist_base +GICD_TYPER2 ); gic_data.domain =irq_domain_create_tree (handle, &gic_irq_domain_ops, &gic_data);
Signature · 1 line
2.20.1
[tip: irq/urgent] irqchip/gic-v3: Workaround Cavium erratum 38539 when reading GICD_TYPER2
The following commit has been merged into the irq/urgent branch of tip:
The following commit has been merged into the irq/urgent branch of tip:
Commit-ID: d01fd161e85904064290435f67f4ed59af5daf74 Gitweb: https://git.kernel.org/tip/d01fd161e85904064290435f67f4ed59af5daf74 Author: Marc Zyngier <[email protected]> AuthorDate: Wed, 11 Mar 2020 11:56:49 Committer: Marc Zyngier <[email protected]> CommitterDate: Sat, 14 Mar 2020 10:15:19
irqchip/gic-v3: Workaround Cavium erratum 38539 when reading GICD_TYPER2
Despite the architecture spec requiring that reserved registers in the GIC distributor memory map are RES0 (and thus are not allowed to generate an exception), the Cavium ThunderX (aka TX1) SoC explodes as such:
[ 0.000000] GICv3: GIC: Using split EOI/Deactivate mode [ 0.000000] GICv3: 128 SPIs implemented [ 0.000000] GICv3: 0 Extended SPIs implemented [ 0.000000] Internal error: synchronous external abort: 96000210 [#1] SMP [ 0.000000] Modules linked in: [ 0.000000] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 5.4.0-rc4-00035-g3cf6a3d5725f #7956 [ 0.000000] Hardware name: cavium,thunder-88xx (DT) [ 0.000000] pstate: 60000085 (nZCv daIf -PAN -UAO) [ 0.000000] pc : __raw_readl+0x0/0x8 [ 0.000000] lr : gic_init_bases+0x110/0x560 [ 0.000000] sp : ffff800011243d90 [ 0.000000] x29: ffff800011243d90 x28: 0000000000000000 [ 0.000000] x27: 0000000000000018 x26: 0000000000000002 [ 0.000000] x25: ffff8000116f0000 x24: ffff000fbe6a2c80 [ 0.000000] x23: 0000000000000000 x22: ffff010fdc322b68 [ 0.000000] x21: ffff800010a7a208 x20: 00000000009b0404 [ 0.000000] x19: ffff80001124dad0 x18: 0000000000000010 [ 0.000000] x17: 000000004d8d492b x16: 00000000f67eb9af [ 0.000000] x15: ffffffffffffffff x14: ffff800011249908 [ 0.000000] x13: ffff800091243ae7 x12: ffff800011243af4 [ 0.000000] x11: ffff80001126e000 x10: ffff800011243a70 [ 0.000000] x9 : 00000000ffffffd0 x8 : ffff80001069c828 [ 0.000000] x7 : 0000000000000059 x6 : ffff8000113fb4d1 [ 0.000000] x5 : 0000000000000001 x4 : 0000000000000000 [ 0.000000] x3 : 0000000000000000 x2 : 0000000000000000 [ 0.000000] x1 : 0000000000000000 x0 : ffff8000116f000c [ 0.000000] Call trace: [ 0.000000] __raw_readl+0x0/0x8 [ 0.000000] gic_of_init+0x188/0x224 [ 0.000000] of_irq_init+0x200/0x3cc [ 0.000000] irqchip_init+0x1c/0x40 [ 0.000000] init_IRQ+0x160/0x1d0 [ 0.000000] start_kernel+0x2ec/0x4b8 [ 0.000000] Code: a8c47bfd d65f03c0 d538d080 d65f03c0 (b9400000)
when reading the GICv4.1 GICD_TYPER2 register, which is unexpected...
Work around it by adding a new quirk for the following variants:
ThunderX: CN88xx
OCTEON TX: CN83xx, CN81xx
OCTEON TX2: CN93xx, CN96xx, CN98xx, CNF95xx*
and use this flag to avoid accessing GICD_TYPER2. Note that all reserved registers (including redistributors and ITS) are impacted by this erratum, but that only GICD_TYPER2 has to be worked around so far.
--- Documentation/arm64/silicon-errata.rst | 2 ++- drivers/irqchip/irq-gic-v3.c | 30 ++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-)
Documentation/arm64/silicon-errata.rst +2 -0
@@ -108,6 +108,8 @@ stable kernels. +----------------+-----------------+-----------------+-----------------------------+ | Cavium | ThunderX GICv3 | #23154 | CAVIUM_ERRATUM_23154 | +----------------+-----------------+-----------------+-----------------------------+ +| Cavium | ThunderX GICv3 | #38539 | N/A | ++----------------+-----------------+-----------------+-----------------------------+ | Cavium | ThunderX Core | #27456 | CAVIUM_ERRATUM_27456 | +----------------+-----------------+-----------------+-----------------------------+ | Cavium | ThunderX Core | #30115 | CAVIUM_ERRATUM_30115 |
drivers/irqchip/irq-gic-v3.c +29 -1
@@ -34,6 +34,7 @@#define GICD_INT_NMI_PRI (GICD_INT_DEF_PRI & ~0x80)#define FLAGS_WORKAROUND_GICR_WAKER_MSM8996 (1ULL << 0) +#define FLAGS_WORKAROUND_CAVIUM_ERRATUM_38539 (1ULL << 1)struct redist_region {void __iomem *redist_base;
@@ -1464,6 +1465,15 @@ static bool gic_enable_quirk_msm8996(void *data)return true; } +static bool gic_enable_quirk_cavium_38539 (void *data) +{ +struct gic_chip_data *d = data; + + d->flags |=FLAGS_WORKAROUND_CAVIUM_ERRATUM_38539 ; + +return true; +} +static bool gic_enable_quirk_hip06_07 (void *data) {struct gic_chip_data *d = data;
@@ -1503,6 +1513,19 @@ static const struct gic_quirk gic_quirks[] = { .init = gic_enable_quirk_hip06_07, }, { +/* +* Reserved register accesses generate a Synchronous +* External Abort. This erratum applies to: +* - ThunderX: CN88xx +* - OCTEON TX: CN83xx, CN81xx +* - OCTEON TX2: CN93xx, CN96xx, CN98xx, CNF95xx* +*/ + .desc = "GICv3: Cavium erratum 38539", + .iidr = 0xa000034c, + .mask = 0xe8f00fff, + .init = gic_enable_quirk_cavium_38539, + }, + { } };
@@ -1577,7 +1600,12 @@ static int __init gic_init_bases(void __iomem *dist_base,pr_info ("%d SPIs implemented\n" ,GIC_LINE_NR -32 );pr_info ("%d Extended SPIs implemented\n" ,GIC_ESPI_NR ); - gic_data.rdists.gicd_typer2 =readl_relaxed (gic_data.dist_base +GICD_TYPER2 ); +/* +* ThunderX1 explodes on reading GICD_TYPER2, in violation of the +* architecture spec (which says that reserved registers are RES0). +*/ +if (!(gic_data.flags &FLAGS_WORKAROUND_CAVIUM_ERRATUM_38539 )) + gic_data.rdists.gicd_typer2 =readl_relaxed (gic_data.dist_base +GICD_TYPER2 ); gic_data.domain =irq_domain_create_tree (handle, &gic_irq_domain_ops, &gic_data);
Marc Zyngier
maintainerPATCH v2 11/36 irqchip/gic-v4.1: VPE table (aka GICR_VPROPBASER) allocation
In reply to Marc ZyngierGICv4.1 defines a new VPE table that is potentially shared between both the ITSs and the redistributors, following complicated affinity rules.
To make things more confusing, the programming of this table at the redistributor level is reusing the GICv4.0 GICR_VPROPBASER register for something completely different.
The code flow is somewhat complexified by the need to respect the affinities required by the HW, meaning that tables can either be inherited from a previously discovered ITS or redistributor.
--- arch/arm/include/asm/arch_gicv3.h | 2 + arch/arm64/include/asm/arch_gicv3.h | 1 + drivers/irqchip/irq-gic-v3-its.c | 305 +++++++++++++++++++++++++++- include/linux/irqchip/arm-gic-v3.h | 33 ++- 4 files changed, 334 insertions(+), 7 deletions(-)
arch/arm/include/asm/arch_gicv3.h +2 -0
@@ -10,6 +10,7 @@#ifndef __ASSEMBLY__#include <linux/io.h> +#include <linux/io-64-nonatomic-lo-hi.h> #include <asm/barrier.h> #include <asm/cacheflush.h> #include <asm/cp15.h>
@@ -327,6 +328,7 @@ static inline u64 __gic_readq_nonatomic(const volatile void __iomem *addr)/* * GITS_VPROPBASER - hi and lo bits may be accessed independently. */ +#define gits_read_vpropbaser (c) __gic_readq_nonatomic(c)#define gits_write_vpropbaser (v, c) __gic_writeq_nonatomic(v, c)/*
arch/arm64/include/asm/arch_gicv3.h +1 -0
@@ -141,6 +141,7 @@ static inline u32 gic_read_rpr(void)#define gicr_read_pendbaser (c) readq_relaxed(c)#define gits_write_vpropbaser (v, c) writeq_relaxed(v, c) +#define gits_read_vpropbaser (c) readq_relaxed(c)#define gits_write_vpendbaser (v, c) writeq_relaxed(v, c)#define gits_read_vpendbaser (c) readq_relaxed(c)
drivers/irqchip/irq-gic-v3-its.c +302 -3
371 lines not on this page · raw message
include/linux/irqchip/arm-gic-v3.h +29 -4
@@ -102,6 +102,11 @@#define GIC_V3_DIST_SIZE 0x10000 +#define GIC_PAGE_SIZE_4K 0ULL +#define GIC_PAGE_SIZE_16K 1ULL +#define GIC_PAGE_SIZE_64K 2ULL +#define GIC_PAGE_SIZE_MASK 3ULL +/* * Re-Distributor registers, offsets from RD_base */
@@ -239,6 +244,8 @@#define GICR_TYPER_DirectLPIS (1U << 3)#define GICR_TYPER_LAST (1U << 4)#define GICR_TYPER_RVPEID (1U << 7) +#define GICR_TYPER_COMMON_LPI_AFF GENMASK_ULL(25, 24) +#define GICR_TYPER_AFFINITY GENMASK_ULL(63, 32)#define GIC_V3_REDIST_SIZE 0x20000
@@ -277,6 +284,18 @@#define GICR_VPROPBASER_RaWaWt GIC_BASER_CACHEABILITY(GICR_VPROPBASER, INNER, RaWaWt)#define GICR_VPROPBASER_RaWaWb GIC_BASER_CACHEABILITY(GICR_VPROPBASER, INNER, RaWaWb) +/* +* GICv4.1 VPROPBASER reinvention. A subtle mix between the old +* VPROPBASER and ITS_BASER. Just not quite any of the two. +*/ +#define GICR_VPROPBASER_4_1_VALID (1ULL << 63) +#define GICR_VPROPBASER_4_1_ENTRY_SIZE GENMASK_ULL(61, 59) +#define GICR_VPROPBASER_4_1_INDIRECT (1ULL << 55) +#define GICR_VPROPBASER_4_1_PAGE_SIZE GENMASK_ULL(54, 53) +#define GICR_VPROPBASER_4_1_Z (1ULL << 52) +#define GICR_VPROPBASER_4_1_ADDR GENMASK_ULL(51, 12) +#define GICR_VPROPBASER_4_1_SIZE GENMASK_ULL(6, 0) +#define GICR_VPENDBASER 0x0078#define GICR_VPENDBASER_SHAREABILITY_SHIFT (10)
@@ -314,6 +333,7 @@#define GITS_CTLR 0x0000#define GITS_IIDR 0x0004#define GITS_TYPER 0x0008 +#define GITS_MPIDR 0x0018#define GITS_CBASER 0x0080#define GITS_CWRITER 0x0088#define GITS_CREADR 0x0090
@@ -347,6 +367,8 @@#define GITS_TYPER_HCC_SHIFT 24#define GITS_TYPER_HCC (r) (((r) >> GITS_TYPER_HCC_SHIFT) & 0xff)#define GITS_TYPER_VMOVP (1ULL << 37) +#define GITS_TYPER_VMAPP (1ULL << 40) +#define GITS_TYPER_SVPET GENMASK_ULL(42, 41)#define GITS_IIDR_REV_SHIFT 12#define GITS_IIDR_REV_MASK (0xf << GITS_IIDR_REV_SHIFT)
@@ -417,10 +439,11 @@#define GITS_BASER_InnerShareable \ GIC_BASER_SHAREABILITY(GITS_BASER, InnerShareable)#define GITS_BASER_PAGE_SIZE_SHIFT (8) -#define GITS_BASER_PAGE_SIZE_4K (0ULL << GITS_BASER_PAGE_SIZE_SHIFT) -#define GITS_BASER_PAGE_SIZE_16K (1ULL << GITS_BASER_PAGE_SIZE_SHIFT) -#define GITS_BASER_PAGE_SIZE_64K (2ULL << GITS_BASER_PAGE_SIZE_SHIFT) -#define GITS_BASER_PAGE_SIZE_MASK (3ULL << GITS_BASER_PAGE_SIZE_SHIFT) +#define __GITS_BASER_PSZ (sz) (GIC_PAGE_SIZE_ ## sz << GITS_BASER_PAGE_SIZE_SHIFT) +#define GITS_BASER_PAGE_SIZE_4K __GITS_BASER_PSZ(4K) +#define GITS_BASER_PAGE_SIZE_16K __GITS_BASER_PSZ(16K) +#define GITS_BASER_PAGE_SIZE_64K __GITS_BASER_PSZ(64K) +#define GITS_BASER_PAGE_SIZE_MASK __GITS_BASER_PSZ(MASK)#define GITS_BASER_PAGES_MAX 256#define GITS_BASER_PAGES_SHIFT (0)#define GITS_BASER_NR_PAGES (r) (((r) & 0xff) + 1)
@@ -610,8 +633,10 @@ struct rdists {struct {void __iomem *rd_base;struct page *pend_page; +struct page *vpe_l1_page;phys_addr_t phys_base;bool lpi_enabled; +cpumask_t *vpe_table_mask; }__percpu *rdist;phys_addr_t prop_table_pa;void *prop_table_va;
Signature · 1 line
2.20.1
Zenghui Yu
reviewerRe: [PATCH v2 11/36] irqchip/gic-v4.1: VPE table (aka GICR_VPROPBASER) allocation
Hi Marc,
[ +Wudi and Nianyao. As they spotted the following issue but
I forgot to send it out. ]
Quoted 18 lines · Marc Zyngier
GICv4.1 defines a new VPE table that is potentially shared between both the ITSs and the redistributors, following complicated affinity rules.
To make things more confusing, the programming of this table at the redistributor level is reusing the GICv4.0
GICR_VPROPBASERregister for something completely different.The code flow is somewhat complexified by the need to respect the affinities required by the HW, meaning that tables can either be inherited from a previously discovered ITS or redistributor.
Signed-off-by Marc Zyngier <[email protected]>---[...]
drivers/irqchip/irq-gic-v3-its.c +0
-0
[...]
Quoted 28 lines
drivers/irqchip/irq-gic-v3-its.c +24
-0@@ -2025,6 +2098,214 @@ static int its_alloc_tables(struct its_node *its)return 0 ; } +static u64 inherit_vpe_l1_table_from_its (void ) +{ +struct its_node *its; +u64 val; +u32 aff; + + val =gic_read_typer (gic_data_rdist_rd_base () +GICR_TYPER ); + aff =compute_common_aff (val); + +list_for_each_entry (its, &its_nodes, entry) { +u64 baser; + +if (!is_v4_1 (its)) +continue ; + +if (!FIELD_GET (GITS_TYPER_SVPET , its->typer)) +continue ; + +if (aff !=compute_its_aff (its)) +continue ; + +/* GICv4.1 guarantees that the vPE table is GITS_BASER2 */ + baser = its->tables[2 ].val; +if (!(baser &GITS_BASER_VALID ))
drivers/irqchip/irq-gic-v3-its.c static int its_alloc_tables(struct its_node *its) · line 2134
Quoted 10 lines
drivers/irqchip/irq-gic-v3-its.c +10
-0+continue ; + +/* We have a winner! */ + val =GICR_VPROPBASER_4_1_VALID ; +if (baser &GITS_BASER_INDIRECT ) + val |=GICR_VPROPBASER_4_1_INDIRECT ; + val |=FIELD_PREP (GICR_VPROPBASER_4_1_PAGE_SIZE , +FIELD_GET (GITS_BASER_PAGE_SIZE_MASK , baser)); + val |=FIELD_PREP (GICR_VPROPBASER_4_1_ADDR , +GITS_BASER_ADDR_48_to_52 (baser) >>12 );
We've used GITS_BASER_ADDR_48_to_52() only in the KVM code where the pagesize of ITS table is fixed to 64K.
It may not work when the pagesize is 4K or 16K?
Thanks,
Zenghui
Quoted 11 lines
drivers/irqchip/irq-gic-v3-its.c +11
-0+ val |=FIELD_PREP (GICR_VPROPBASER_SHAREABILITY_MASK , +FIELD_GET (GITS_BASER_SHAREABILITY_MASK , baser)); + val |=FIELD_PREP (GICR_VPROPBASER_INNER_CACHEABILITY_MASK , +FIELD_GET (GITS_BASER_INNER_CACHEABILITY_MASK , baser)); + val |=FIELD_PREP (GICR_VPROPBASER_4_1_SIZE ,GITS_BASER_NR_PAGES (baser) -1 ); + +return val; + } + +return 0 ; +}
Marc Zyngier
maintainerRe: [PATCH v2 11/36] irqchip/gic-v4.1: VPE table (aka GICR_VPROPBASER) allocation
Hi Zenghui,
Quoted 56 lines · Zenghui Yu
Hi Marc,
[ +Wudi and Nianyao. As they spotted the following issue but
I forgot to send it out. ]Quoted 15 lines · Marc Zyngier
GICv4.1 defines a new VPE table that is potentially shared between both the ITSs and the redistributors, following complicated affinity rules.
To make things more confusing, the programming of this table at the redistributor level is reusing the GICv4.0GICR_VPROPBASERregister for something completely different.
The code flow is somewhat complexified by the need to respect the affinities required by the HW, meaning that tables can either be inherited from a previously discovered ITS or redistributor.Signed-off-by Marc Zyngier <[email protected]>---[...]
drivers/irqchip/irq-gic-v3-its.c +0
-0[...]
Quoted 34 lines
drivers/irqchip/irq-gic-v3-its.c +29
-0@@ -2025,6 +2098,214 @@ static int its_alloc_tables(struct its_node *its)return 0 ; } +static u64 inherit_vpe_l1_table_from_its(void) +{ +struct its_node *its; +u64 val; +u32 aff; + + val =gic_read_typer (gic_data_rdist_rd_base () +GICR_TYPER ); + aff =compute_common_aff (val); + +list_for_each_entry (its, &its_nodes, entry) { +u64 baser; + +if (!is_v4_1 (its)) +continue ; + +if (!FIELD_GET (GITS_TYPER_SVPET , its->typer)) +continue ; + +if (aff !=compute_its_aff (its)) +continue ; + +/* GICv4.1 guarantees that the vPE table is GITS_BASER2 */ + baser = its->tables[2 ].val; +if (!(baser &GITS_BASER_VALID )) +continue ; + +/* We have a winner! */ + val =GICR_VPROPBASER_4_1_VALID ; +if (baser &GITS_BASER_INDIRECT ) + val |=GICR_VPROPBASER_4_1_INDIRECT ;
Quoted 8 lines
drivers/irqchip/irq-gic-v3-its.c static int its_alloc_tables(struct its_node · line 2134
Quoted 4 lines
drivers/irqchip/irq-gic-v3-its.c +4
-0+ val |=FIELD_PREP (GICR_VPROPBASER_4_1_PAGE_SIZE , +FIELD_GET (GITS_BASER_PAGE_SIZE_MASK , baser)); + val |=FIELD_PREP (GICR_VPROPBASER_4_1_ADDR , +GITS_BASER_ADDR_48_to_52 (baser) >>12 );We've used
GITS_BASER_ADDR_48_to_52()only in the KVM code where the pagesize of ITS table is fixed to 64K.
It may not work when the pagesize is 4K or 16K?
You're absolutely right, we shouldn't mess with the 52bit macros when PZ isn't set to 64k. I'm adding the following fix to this patch:
drivers/irqchip/irq-gic-v3-its.c +10 -3
@@ -2433,7 +2433,7 @@ static u64 inherit_vpe_l1_table_from_its(void) aff =compute_common_aff (val);list_for_each_entry (its, &its_nodes, entry) { -u64 baser; +u64 baser, addr;if (!is_v4_1 (its))continue ;
@@ -2455,8 +2455,15 @@ static u64 inherit_vpe_l1_table_from_its(void) val |=GICR_VPROPBASER_4_1_INDIRECT ; val |=FIELD_PREP (GICR_VPROPBASER_4_1_PAGE_SIZE ,FIELD_GET (GITS_BASER_PAGE_SIZE_MASK , baser)); - val |=FIELD_PREP (GICR_VPROPBASER_4_1_ADDR , -GITS_BASER_ADDR_48_to_52 (baser) >>12 ); +switch (FIELD_GET (GITS_BASER_PAGE_SIZE_MASK , baser)) { +case GIC_PAGE_SIZE_64K : + addr =GITS_BASER_ADDR_48_to_52 (baser); +break ; +default : + addr = baser &GENMASK_ULL (47 ,12 ); +break ; + } + val |=FIELD_PREP (GICR_VPROPBASER_4_1_ADDR , addr >>12 ); val |=FIELD_PREP (GICR_VPROPBASER_SHAREABILITY_MASK ,FIELD_GET (GITS_BASER_SHAREABILITY_MASK , baser)); val |= FIELD_PREP(GICR_VPROPBASER_INNER_CACHEABILITY_MASK,
Thanks again,
M.
Signature · 1 line
Jazz is not dead. It just smells funny...
Marc Zyngier
maintainerPATCH v2 12/36 irqchip/gic-v4.1: Implement the v4.1 flavour of VMAPP
In reply to Marc ZyngierThe ITS VMAPP command gains some new fields with GICv4.1:
- a default doorbell, which allows a single doorbell to be used for all the VLPIs routed to a given VPE
- a pointer to the configuration table (instead of having it in a register that gets context switched)
- a flag indicating whether this is the first map or the last unmap for this particulat VPE
- a flag indicating whether the pending table is known to be zeroed, or not
Plumb in the new fields in the VMAPP builder, and add the map/unmap refcounting so that the ITS can do the right thing.
--- drivers/irqchip/irq-gic-v3-its.c | 60 +++++++++++++++++++++++++++--- include/linux/irqchip/arm-gic-v4.h | 18 +++++++-- 2 files changed, 69 insertions(+), 9 deletions(-)
drivers/irqchip/irq-gic-v3-its.c +55 -5
@@ -422,6 +422,27 @@ static void its_encode_vpt_size(struct its_cmd_block *cmd, u8 vpt_size)its_mask_encode (&cmd->raw_cmd[3 ], vpt_size,4 ,0 ); } +static void its_encode_vconf_addr (struct its_cmd_block *cmd,u64 vconf_pa) +{ +its_mask_encode (&cmd->raw_cmd[0 ], vconf_pa >>16 ,51 ,16 ); +} + +static void its_encode_alloc (struct its_cmd_block *cmd,bool alloc) +{ +its_mask_encode (&cmd->raw_cmd[0 ], alloc,8 ,8 ); +} + +static void its_encode_ptz (struct its_cmd_block *cmd,bool ptz) +{ +its_mask_encode (&cmd->raw_cmd[0 ], ptz,9 ,9 ); +} + +static void its_encode_vmapp_default_db (struct its_cmd_block *cmd, +u32 vpe_db_lpi) +{ +its_mask_encode (&cmd->raw_cmd[1 ], vpe_db_lpi,31 ,0 ); +} +static inline void its_fixup_cmd (struct its_cmd_block *cmd) {/* Let's fixup BE commands */
@@ -605,19 +626,45 @@ static struct its_vpe *its_build_vmapp_cmd(struct its_node *its,struct its_cmd_block *cmd, struct its_cmd_desc *desc) { - unsigned long vpt_addr; + unsigned long vpt_addr, vconf_addr;u64 target; - - vpt_addr =virt_to_phys (page_address (desc->its_vmapp_cmd.vpe->vpt_page)); - target = desc->its_vmapp_cmd.col->target_address + its->vlpi_redist_offset; +bool alloc;its_encode_cmd (cmd,GITS_CMD_VMAPP );its_encode_vpeid (cmd, desc->its_vmapp_cmd.vpe->vpe_id);its_encode_valid (cmd, desc->its_vmapp_cmd.valid); + +if (!desc->its_vmapp_cmd.valid) { +if (is_v4_1 (its)) { + alloc = !atomic_dec_return (&desc->its_vmapp_cmd.vpe->vmapp_count); +its_encode_alloc (cmd, alloc); + } + + goto out; + } + + vpt_addr =virt_to_phys (page_address (desc->its_vmapp_cmd.vpe->vpt_page)); + target = desc->its_vmapp_cmd.col->target_address + its->vlpi_redist_offset; +its_encode_target (cmd, target);its_encode_vpt_addr (cmd, vpt_addr);its_encode_vpt_size (cmd,LPI_NRBITS -1 ); +if (!is_v4_1 (its)) + goto out; + + vconf_addr =virt_to_phys (page_address (desc->its_vmapp_cmd.vpe->its_vm->vprop_page)); + + alloc =atomic_inc_and_test (&desc->its_vmapp_cmd.vpe->vmapp_count); + +its_encode_alloc (cmd, alloc); + +/* We can only signal PTZ when alloc==1. Why do we have two bits? */ +its_encode_ptz (cmd, alloc); +its_encode_vconf_addr (cmd, vconf_addr); +its_encode_vmapp_default_db (cmd, desc->its_vmapp_cmd.vpe->vpe_db_lpi); + +out:its_fixup_cmd (cmd);return valid_vpe (its, desc->its_vmapp_cmd.vpe);
@@ -3349,7 +3396,10 @@ static int its_vpe_init(struct its_vpe *vpe) vpe->vpe_id = vpe_id; vpe->vpt_page = vpt_page; - vpe->vpe_proxy_event =-1 ; +if (gic_rdists->has_rvpeid) +atomic_set (&vpe->vmapp_count,0 ); +else + vpe->vpe_proxy_event =-1 ;return 0 ; }
include/linux/irqchip/arm-gic-v4.h +14 -4
@@ -37,8 +37,20 @@ struct its_vpe {irq_hw_number_t vpe_db_lpi;/* VPE resident */ bool resident; -/* VPE proxy mapping */ -int vpe_proxy_event; +union { +/* GICv4.0 implementations */ +struct { +/* VPE proxy mapping */ +int vpe_proxy_event; +/* Implementation Defined Area Invalid */ +bool idai; + }; +/* GICv4.1 implementations */ +struct { +atomic_t vmapp_count; + }; + }; +/* * This collection ID is used to indirect the target * redistributor for this VPE. The ID itself isn't involved in
@@ -47,8 +59,6 @@ struct its_vpe {u16 col_idx;/* Unique (system-wide) VPE identifier */ u16 vpe_id; -/* Implementation Defined Area Invalid */ -bool idai;/* Pending VLPIs on schedule out? */ bool pending_last; };
Signature · 1 line
2.20.1
Re: [PATCH v2 12/36] irqchip/gic-v4.1: Implement the v4.1 flavour of VMAPP
Hi Marc,
Quoted 7 lines · Marc Zyngier
The ITS VMAPP command gains some new fields with GICv4.1:
- a default doorbell, which allows a single doorbell to be used for all the VLPIs routed to a given VPE
- a pointer to the configuration table (instead of having it in a register that gets context switched)
- a flag indicating whether this is the first map or the last unmap for this particulat VPE
particular
Quoted 6 lines
- a flag indicating whether the pending table is known to be zeroed, or not
Plumb in the new fields in the VMAPP builder, and add the map/unmap refcounting so that the ITS can do the right thing.
Signed-off-by Marc Zyngier <[email protected]>
Quoted 50 lines
--- drivers/irqchip/irq-gic-v3-its.c | 60 +++++++++++++++++++++++++++--- include/linux/irqchip/arm-gic-v4.h | 18 +++++++-- 2 files changed, 69 insertions(+), 9 deletions(-)drivers/irqchip/irq-gic-v3-its.c +23
-4@@ -422,6 +422,27 @@ static void its_encode_vpt_size(struct its_cmd_block *cmd, u8 vpt_size)its_mask_encode (&cmd->raw_cmd[3 ], vpt_size,4 ,0 ); } +static void its_encode_vconf_addr (struct its_cmd_block *cmd,u64 vconf_pa) +{ +its_mask_encode (&cmd->raw_cmd[0 ], vconf_pa >>16 ,51 ,16 ); +} + +static void its_encode_alloc (struct its_cmd_block *cmd,bool alloc) +{ +its_mask_encode (&cmd->raw_cmd[0 ], alloc,8 ,8 ); +} + +static void its_encode_ptz (struct its_cmd_block *cmd,bool ptz) +{ +its_mask_encode (&cmd->raw_cmd[0 ], ptz,9 ,9 ); +} + +static void its_encode_vmapp_default_db (struct its_cmd_block *cmd, +u32 vpe_db_lpi) +{ +its_mask_encode (&cmd->raw_cmd[1 ], vpe_db_lpi,31 ,0 ); +} +static inline void its_fixup_cmd (struct its_cmd_block *cmd) {/* Let's fixup BE commands */ @@ -605,19 +626,45 @@ static struct its_vpe *its_build_vmapp_cmd(struct its_node *its,struct its_cmd_block *cmd, struct its_cmd_desc *desc) { - unsigned long vpt_addr; + unsigned long vpt_addr, vconf_addr;u64 target; - - vpt_addr =virt_to_phys (page_address (desc->its_vmapp_cmd.vpe->vpt_page)); - target = desc->its_vmapp_cmd.col->target_address + its->vlpi_redist_offset; +bool alloc;its_encode_cmd (cmd,GITS_CMD_VMAPP );
drivers/irqchip/irq-gic-v3-its.c static struct its_vpe *its_build_vmapp_cmd(struct its_node *its, · line 643
Quoted 10 lines
drivers/irqchip/irq-gic-v3-its.c +8
-0its_encode_vpeid (cmd, desc->its_vmapp_cmd.vpe->vpe_id);its_encode_valid (cmd, desc->its_vmapp_cmd.valid); + +if (!desc->its_vmapp_cmd.valid) { +if (is_v4_1 (its)) { + alloc = !atomic_dec_return (&desc->its_vmapp_cmd.vpe->vmapp_count); +its_encode_alloc (cmd, alloc); + } + + goto out;
(note to myself, the reason for "goto out" here is that in GICv4.1, the remaining field are RES0 when V==0.)
Thanks,
Zenghui
Quoted 76 lines
drivers/irqchip/irq-gic-v3-its.c +24
-1+ } + + vpt_addr =virt_to_phys (page_address (desc->its_vmapp_cmd.vpe->vpt_page)); + target = desc->its_vmapp_cmd.col->target_address + its->vlpi_redist_offset; +its_encode_target (cmd, target);its_encode_vpt_addr (cmd, vpt_addr);its_encode_vpt_size (cmd,LPI_NRBITS -1 ); +if (!is_v4_1 (its)) + goto out; + + vconf_addr =virt_to_phys (page_address (desc->its_vmapp_cmd.vpe->its_vm->vprop_page)); + + alloc =atomic_inc_and_test (&desc->its_vmapp_cmd.vpe->vmapp_count); + +its_encode_alloc (cmd, alloc); + +/* We can only signal PTZ when alloc==1. Why do we have two bits? */ +its_encode_ptz (cmd, alloc); +its_encode_vconf_addr (cmd, vconf_addr); +its_encode_vmapp_default_db (cmd, desc->its_vmapp_cmd.vpe->vpe_db_lpi); + +out:its_fixup_cmd (cmd);return valid_vpe (its, desc->its_vmapp_cmd.vpe);@@ -3349,7 +3396,10 @@ static int its_vpe_init(struct its_vpe *vpe) vpe->vpe_id = vpe_id; vpe->vpt_page = vpt_page; - vpe->vpe_proxy_event =-1 ; +if (gic_rdists->has_rvpeid) +atomic_set (&vpe->vmapp_count,0 ); +else + vpe->vpe_proxy_event =-1 ;return 0 ; }include/linux/irqchip/arm-gic-v4.h +14
-4@@ -37,8 +37,20 @@ struct its_vpe {irq_hw_number_t vpe_db_lpi;/* VPE resident */ bool resident; -/* VPE proxy mapping */ -int vpe_proxy_event; +union { +/* GICv4.0 implementations */ +struct { +/* VPE proxy mapping */ +int vpe_proxy_event; +/* Implementation Defined Area Invalid */ +bool idai; + }; +/* GICv4.1 implementations */ +struct { +atomic_t vmapp_count; + }; + }; +/* * This collection ID is used to indirect the target * redistributor for this VPE. The ID itself isn't involved in @@ -47,8 +59,6 @@ struct its_vpe {u16 col_idx;/* Unique (system-wide) VPE identifier */ u16 vpe_id; -/* Implementation Defined Area Invalid */ -bool idai;/* Pending VLPIs on schedule out? */ bool pending_last; };
Zenghui Yu
reviewerRe: [PATCH v2 12/36] irqchip/gic-v4.1: Implement the v4.1 flavour of VMAPP
In reply to Marc ZyngierHi Marc,
Quoted 13 lines · Marc Zyngier
The ITS VMAPP command gains some new fields with GICv4.1:
- a default doorbell, which allows a single doorbell to be used for all the VLPIs routed to a given VPE
- a pointer to the configuration table (instead of having it in a register that gets context switched)
- a flag indicating whether this is the first map or the last unmap for this particulat VPE
- a flag indicating whether the pending table is known to be zeroed, or notPlumb in the new fields in the VMAPP builder, and add the map/unmap refcounting so that the ITS can do the right thing.
Signed-off-by Marc Zyngier <[email protected]>
[...]
Quoted 28 lines
drivers/irqchip/irq-gic-v3-its.c +15
-4@@ -605,19 +626,45 @@ static struct its_vpe *its_build_vmapp_cmd(struct its_node *its,struct its_cmd_block *cmd, struct its_cmd_desc *desc) { - unsigned long vpt_addr; + unsigned long vpt_addr, vconf_addr;u64 target; - - vpt_addr =virt_to_phys (page_address (desc->its_vmapp_cmd.vpe->vpt_page)); - target = desc->its_vmapp_cmd.col->target_address + its->vlpi_redist_offset; +bool alloc;its_encode_cmd (cmd,GITS_CMD_VMAPP );its_encode_vpeid (cmd, desc->its_vmapp_cmd.vpe->vpe_id);its_encode_valid (cmd, desc->its_vmapp_cmd.valid); + +if (!desc->its_vmapp_cmd.valid) { +if (is_v4_1 (its)) { + alloc = !atomic_dec_return (&desc->its_vmapp_cmd.vpe->vmapp_count); +its_encode_alloc (cmd, alloc); + } + + goto out; + } + + vpt_addr =virt_to_phys (page_address (desc->its_vmapp_cmd.vpe->vpt_page)); + target = desc->its_vmapp_cmd.col->target_address + its->vlpi_redist_offset; +
drivers/irqchip/irq-gic-v3-its.c static struct its_vpe *its_build_vmapp_cmd(struct its_node *its, · line 658
Quoted 10 lines
drivers/irqchip/irq-gic-v3-its.c +6
-0its_encode_target (cmd, target);its_encode_vpt_addr (cmd, vpt_addr);its_encode_vpt_size (cmd,LPI_NRBITS -1 ); +if (!is_v4_1 (its)) + goto out; + + vconf_addr =virt_to_phys (page_address (desc->its_vmapp_cmd.vpe->its_vm->vprop_page)); + + alloc =atomic_inc_and_test (&desc->its_vmapp_cmd.vpe->vmapp_count);
As the comment block on top of atomic_inc_and_test(atomic *v) says,
* Atomically increments @v by 1
* and returns true if the result is zero, or false for all
* other cases.
*/
We will always get the 'alloc' as false here, even if this is the first mapping of this vPE. This is not as expected, I think.
And on the other hand, I wonder what is the reason for 'vmapp_count' to be atomic_t?
Thanks,
Zenghui
Quoted 61 lines
drivers/irqchip/irq-gic-v3-its.c +13
-1+ +its_encode_alloc (cmd, alloc); + +/* We can only signal PTZ when alloc==1. Why do we have two bits? */ +its_encode_ptz (cmd, alloc); +its_encode_vconf_addr (cmd, vconf_addr); +its_encode_vmapp_default_db (cmd, desc->its_vmapp_cmd.vpe->vpe_db_lpi); + +out:its_fixup_cmd (cmd);return valid_vpe (its, desc->its_vmapp_cmd.vpe);@@ -3349,7 +3396,10 @@ static int its_vpe_init(struct its_vpe *vpe) vpe->vpe_id = vpe_id; vpe->vpt_page = vpt_page; - vpe->vpe_proxy_event =-1 ; +if (gic_rdists->has_rvpeid) +atomic_set (&vpe->vmapp_count,0 ); +else + vpe->vpe_proxy_event =-1 ;return 0 ; }include/linux/irqchip/arm-gic-v4.h +14
-4@@ -37,8 +37,20 @@ struct its_vpe {irq_hw_number_t vpe_db_lpi;/* VPE resident */ bool resident; -/* VPE proxy mapping */ -int vpe_proxy_event; +union { +/* GICv4.0 implementations */ +struct { +/* VPE proxy mapping */ +int vpe_proxy_event; +/* Implementation Defined Area Invalid */ +bool idai; + }; +/* GICv4.1 implementations */ +struct { +atomic_t vmapp_count; + }; + }; +/* * This collection ID is used to indirect the target * redistributor for this VPE. The ID itself isn't involved in @@ -47,8 +59,6 @@ struct its_vpe {u16 col_idx;/* Unique (system-wide) VPE identifier */ u16 vpe_id; -/* Implementation Defined Area Invalid */ -bool idai;/* Pending VLPIs on schedule out? */ bool pending_last; };
Marc Zyngier
maintainerRe: [PATCH v2 12/36] irqchip/gic-v4.1: Implement the v4.1 flavour of VMAPP
Hi Zenghui,
Quoted 68 lines · Zenghui Yu
Hi Marc,
Quoted 14 lines · Marc Zyngier
The ITS VMAPP command gains some new fields with GICv4.1:
- a default doorbell, which allows a single doorbell to be used for all the VLPIs routed to a given VPE
- a pointer to the configuration table (instead of having it in a register
that gets context switched)
- a flag indicating whether this is the first map or the last unmap for
this particulat VPE
- a flag indicating whether the pending table is known to be zeroed, or not
Plumb in the new fields in the VMAPP builder, and add the map/unmap refcounting so that the ITS can do the right thing.Signed-off-by Marc Zyngier <[email protected]>[...]
Quoted 44 lines
drivers/irqchip/irq-gic-v3-its.c +18
-4@@ -605,19 +626,45 @@ static struct its_vpe *its_build_vmapp_cmd(struct its_node *its, struct its_cmd_block *cmd, struct its_cmd_desc *desc) { -unsigned long vpt_addr; +unsigned long vpt_addr, vconf_addr;u64 target; - - vpt_addr =virt_to_phys (page_address (desc->its_vmapp_cmd.vpe->vpt_page)); - target = desc->its_vmapp_cmd.col->target_address + its->vlpi_redist_offset; +bool alloc;its_encode_cmd (cmd,GITS_CMD_VMAPP );its_encode_vpeid (cmd, desc->its_vmapp_cmd.vpe->vpe_id);its_encode_valid (cmd, desc->its_vmapp_cmd.valid); + +if (!desc->its_vmapp_cmd.valid) { +if (is_v4_1 (its)) { + alloc = !atomic_dec_return (&desc->its_vmapp_cmd.vpe->vmapp_count); +its_encode_alloc (cmd, alloc); + } + + goto out; + } + + vpt_addr =virt_to_phys (page_address (desc->its_vmapp_cmd.vpe->vpt_page)); + target = desc->its_vmapp_cmd.col->target_address + its->vlpi_redist_offset; +its_encode_target (cmd, target);its_encode_vpt_addr (cmd, vpt_addr);its_encode_vpt_size (cmd,LPI_NRBITS -1 ); + if (!is_v4_1(its)) + goto out; + + vconf_addr =virt_to_phys(page_address(desc->its_vmapp_cmd.vpe->its_vm->vprop_page));
(quoted diff) +2
-0+ + alloc =Quoted 1 line
atomic_inc_and_test(&desc->its_vmapp_cmd.vpe->vmapp_count);As the comment block on top of
atomic_inc_and_test(atomic *v)says,
Quoted 7 lines
* Atomically increments @v by 1
* and returns true if the result is zero, or false for all
* other cases.
*/We will always get the 'alloc' as false here, even if this is the first mapping of this vPE. This is not as expected, I think.
As usual, a very good observation!
Indeed, I cocked up the logic here, as we need to test the value before the increment (and not after). What we want is probably something like:
alloc = !atomic_fetch_inc(&desc->its_vmapp_cmd.vpe->vmapp_count);
Quoted 2 lines
And on the other hand, I wonder what is the reason for '
vmapp_count' to beatomic_t?
The rational is that we could end-up with multiple VMAPP commands emitted in parallel, for example. That's probably not strictly necessary right now, but I'm trying to be cautious.
Thanks,
M.
Signature · 1 line
Jazz is not dead. It just smells funny...
Marc Zyngier
maintainerPATCH v2 13/36 irqchip/gic-v4.1: Don't use the VPE proxy if RVPEID is set
In reply to Marc ZyngierThe infamous VPE proxy device isn't used with GICv4.1 because:
- we can invalidate any LPI from the DirectLPI MMIO interface
- the ITS and redistributors understand the life cycle of the doorbell, so we don't need to enable/disable it all the time
So let's escape early from the proxy related functions.
--- drivers/irqchip/irq-gic-v3-its.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-)
drivers/irqchip/irq-gic-v3-its.c +22 -1
@@ -3069,7 +3069,7 @@ static const struct irq_domain_ops its_domain_ops = {/* * This is insane. * -* If a GICv4 doesn't implement Direct LPIs (which is extremely +* If a GICv4.0 doesn't implement Direct LPIs (which is extremely * likely), the only way to perform an invalidate is to use a fake * device to issue an INV command, implying that the LPI has first * been mapped to some event on that device. Since this is not exactly
@@ -3077,9 +3077,18 @@ static const struct irq_domain_ops its_domain_ops = {* only issue an UNMAP if we're short on available slots. * * Broken by design(tm). +* +* GICv4.1 actually mandates that we're able to invalidate by writing to a +* MMIO register. It doesn't implement the whole of DirectLPI, but that's +* good enough. And most of the time, we don't even have to invalidate +* anything, so that's actually pretty good! */ static void its_vpe_db_proxy_unmap_locked (struct its_vpe *vpe) { +/* GICv4.1 doesn't use a proxy, so nothing to do here */ +if (gic_rdists->has_rvpeid) +return ; +/* Already unmapped? */ if (vpe->vpe_proxy_event ==-1 )return ;
@@ -3102,6 +3111,10 @@ static void its_vpe_db_proxy_unmap_locked(struct its_vpe *vpe)static void its_vpe_db_proxy_unmap (struct its_vpe *vpe) { +/* GICv4.1 doesn't use a proxy, so nothing to do here */ +if (gic_rdists->has_rvpeid) +return ; +if (!gic_rdists->has_direct_lpi) {unsigned long flags;
@@ -3113,6 +3126,10 @@ static void its_vpe_db_proxy_unmap(struct its_vpe *vpe)static void its_vpe_db_proxy_map_locked (struct its_vpe *vpe) { +/* GICv4.1 doesn't use a proxy, so nothing to do here */ +if (gic_rdists->has_rvpeid) +return ; +/* Already mapped? */ if (vpe->vpe_proxy_event !=-1 )return ;
@@ -3135,6 +3152,10 @@ static void its_vpe_db_proxy_move(struct its_vpe *vpe, int from, int to)unsigned long flags;struct its_collection *target_col; +/* GICv4.1 doesn't use a proxy, so nothing to do here */ +if (gic_rdists->has_rvpeid) +return ; +if (gic_rdists->has_direct_lpi) {void __iomem *rdbase;
Signature · 6 lines
2.20.1 _______________________________________________ kvmarm mailing list [email protected] https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
Re: [PATCH v2 13/36] irqchip/gic-v4.1: Don't use the VPE proxy if RVPEID is set
Hi Marc,
Quoted 9 lines · Marc Zyngier
The infamous VPE proxy device isn't used with GICv4.1 because:
- we can invalidate any LPI from the DirectLPI MMIO interface
- the ITS and redistributors understand the life cycle of the doorbell, so we don't need to enable/disable it all the timeSo let's escape early from the proxy related functions.
Signed-off-by Marc Zyngier <[email protected]>
Quoted 18 lines
--- drivers/irqchip/irq-gic-v3-its.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-)drivers/irqchip/irq-gic-v3-its.c +1
-1@@ -3069,7 +3069,7 @@ static const struct irq_domain_ops its_domain_ops = {/* * This is insane. * -* If a GICv4 doesn't implement Direct LPIs (which is extremely +* If a GICv4.0 doesn't implement Direct LPIs (which is extremely * likely), the only way to perform an invalidate is to use a fake * device to issue an INV command, implying that the LPI has first * been mapped to some event on that device. Since this is not exactly
drivers/irqchip/irq-gic-v3-its.c static const struct irq_domain_ops its_domain_ops = { · line 3084
Quoted 8 lines
drivers/irqchip/irq-gic-v3-its.c +5
-0@@ -3077,9 +3077,18 @@ static const struct irq_domain_ops its_domain_ops = {* only issue an UNMAP if we're short on available slots. * * Broken by design(tm). +* +* GICv4.1 actually mandates that we're able to invalidate by writing to a +* MMIO register. It doesn't implement the whole of DirectLPI, but that's +* good enough. And most of the time, we don't even have to invalidate +* anything, so that's actually pretty good!
I can't understand the meaning of this last sentence. May I ask for an explanation? :)
Thanks,
Zenghui
Quoted 44 lines
drivers/irqchip/irq-gic-v3-its.c +16
-0*/ static void its_vpe_db_proxy_unmap_locked (struct its_vpe *vpe) { +/* GICv4.1 doesn't use a proxy, so nothing to do here */ +if (gic_rdists->has_rvpeid) +return ; +/* Already unmapped? */ if (vpe->vpe_proxy_event ==-1 )return ;@@ -3102,6 +3111,10 @@ static void its_vpe_db_proxy_unmap_locked(struct its_vpe *vpe)static void its_vpe_db_proxy_unmap (struct its_vpe *vpe) { +/* GICv4.1 doesn't use a proxy, so nothing to do here */ +if (gic_rdists->has_rvpeid) +return ; +if (!gic_rdists->has_direct_lpi) {unsigned long flags;@@ -3113,6 +3126,10 @@ static void its_vpe_db_proxy_unmap(struct its_vpe *vpe)static void its_vpe_db_proxy_map_locked (struct its_vpe *vpe) { +/* GICv4.1 doesn't use a proxy, so nothing to do here */ +if (gic_rdists->has_rvpeid) +return ; +/* Already mapped? */ if (vpe->vpe_proxy_event !=-1 )return ;@@ -3135,6 +3152,10 @@ static void its_vpe_db_proxy_move(struct its_vpe *vpe, int from, int to)unsigned long flags;struct its_collection *target_col; +/* GICv4.1 doesn't use a proxy, so nothing to do here */ +if (gic_rdists->has_rvpeid) +return ; +if (gic_rdists->has_direct_lpi) {void __iomem *rdbase;
Marc Zyngier
maintainerRe: [PATCH v2 13/36] irqchip/gic-v4.1: Don't use the VPE proxy if RVPEID is set
Quoted 39 lines · Zenghui Yu
Hi Marc,
Quoted 7 lines · Marc Zyngier
The infamous VPE proxy device isn't used with GICv4.1 because:
- we can invalidate any LPI from the DirectLPI MMIO interface
- the ITS and redistributors understand the life cycle of the doorbell, so we don't need to enable/disable it all the time
So let's escape early from the proxy related functions.Signed-off-by Marc Zyngier <[email protected]>Reviewed-by Zenghui Yu <[email protected]>Quoted 26 lines
--- drivers/irqchip/irq-gic-v3-its.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-)drivers/irqchip/irq-gic-v3-its.c +1
-1@@ -3069,7 +3069,7 @@ static const struct irq_domain_ops its_domain_ops = {/* * This is insane. * -* If a GICv4 doesn't implement Direct LPIs (which is extremely +* If a GICv4.0 doesn't implement Direct LPIs (which is extremely * likely), the only way to perform an invalidate is to use a fake * device to issue an INV command, implying that the LPI has first * been mapped to some event on that device. Since this is not
exactlydrivers/irqchip/irq-gic-v3-its.c +2
-0@@ -3077,9 +3077,18 @@ static const struct irq_domain_ops its_domain_ops = { * only issue an UNMAP if we're short on available slots. * * Broken by design(tm). + * + * GICv4.1 actually mandates that we're able to invalidate bywriting to a
Quoted 8 lines
Quoted 5 lines
+ * MMIO register. It doesn't implement the whole of DirectLPI, but that's
+ * good enough. And most of the time, we don't even have to invalidate
+ * anything, so that's actually pretty good!I can't understand the meaning of this last sentence. May I ask for an explanation? :)
Yeah, reading this now, it feels pretty clumsy, and only remotely connected to the patch.
What I'm trying to say here is that, although GICv4.1 doesn't have the full spectrum of v4.0 DirectLPI (it only allows a subset of it), this subset is more then enough for us. Here's the rational:
When a vPE exits from the hypervisor, we know whether we need to request a doorbell or not (depending on whether we're blocking on WFI or not). On GICv4.0, this translates into enabling the doorbell interrupt, which generates an invalidation (costly). And whenever we've taken a doorbell, or are scheduled again, we need to turn the doorbell off (invalidation again).
With v4.1, we can just say *at exit time* whether we want doorbells to be subsequently generated (see its_vpe_4_1_deschedule() and the req_db parameter in the info structure). This is part of making the vPE non-resident, so we have 0 overhead at this stage.
I'll try and update the comment here.
Thanks,
M.
Signature · 5 lines
Jazz is not dead. It just smells funny... _______________________________________________ kvmarm mailing list [email protected] https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
Zenghui Yu
reviewerRe: [PATCH v2 13/36] irqchip/gic-v4.1: Don't use the VPE proxy if RVPEID is set
Hi Marc,
Quoted 61 lines · Marc Zyngier
Quoted 37 lines · Zenghui Yu
Hi Marc,
Quoted 7 lines · Marc Zyngier
The infamous VPE proxy device isn't used with GICv4.1 because:
- we can invalidate any LPI from the DirectLPI MMIO interface
- the ITS and redistributors understand the life cycle of the doorbell, so we don't need to enable/disable it all the time
So let's escape early from the proxy related functions.Signed-off-by Marc Zyngier <[email protected]>Reviewed-by Zenghui Yu <[email protected]>Quoted 24 lines
---
drivers/irqchip/irq-gic-v3-its.c| 23 ++++++++++++++++++++++-1 file changed, 22 insertions(+), 1 deletion(-)drivers/irqchip/irq-gic-v3-its.c +1
-1@@ -3069,7 +3069,7 @@ static const struct irq_domain_ops its_domain_ops = { /** This is insane. * -* If a GICv4 doesn't implement Direct LPIs (which is extremely +* If a GICv4.0 doesn't implement Direct LPIs (which is extremely * likely), the only way to perform an invalidate is to use a fake * device to issue an INV command, implying that the LPI has first * been mapped to some event on that device. Since this is not exactly
drivers/irqchip/irq-gic-v3-its.c +2
-0@@ -3077,9 +3077,18 @@ static const struct irq_domain_ops its_domain_ops = { * only issue an UNMAP if we're short on available slots. * * Broken by design(tm). + * + * GICv4.1 actually mandates that we're able to invalidate byQuoted 8 lines
Quoted 5 lines
writing to a
+ * MMIO register. It doesn't implement the whole of DirectLPI, but that's
+ * good enough. And most of the time, we don't even have to invalidate
+ * anything, so that's actually pretty good!I can't understand the meaning of this last sentence. May I ask for an explanation? :)
Yeah, reading this now, it feels pretty clumsy, and only remotely connected to the patch.
What I'm trying to say here is that, although GICv4.1 doesn't have the full spectrum of v4.0 DirectLPI (it only allows a subset of it), this subset is more then enough for us. Here's the rational:
When a vPE exits from the hypervisor, we know whether we need to request a doorbell or not (depending on whether we're blocking on WFI or not). On GICv4.0, this translates into enabling the doorbell interrupt, which generates an invalidation (costly). And whenever we've taken a doorbell, or are scheduled again, we need to turn the doorbell off (invalidation again).
Quoted 4 lines
With v4.1, we can just say *at exit time* whether we want doorbells to be subsequently generated (see
its_vpe_4_1_deschedule()and thereq_dbparameter in the info structure). This is part of making the vPE non-resident, so we have 0 overhead at this stage.
Great, and get it. Thanks for this clear explanation!
Zenghui
Marc Zyngier
maintainerPATCH v2 14/36 irqchip/gic-v4.1: Implement the v4.1 flavour of VMOVP
In reply to Marc ZyngierWith GICv4.1, VMOVP is extended to allow a default doorbell to be specified, as well as a validity bit for this doorbell. As an added bonus, VMOPVP isn't required anymore of moving a VPE between redistributors that share the same affinity.
Let's add this support to the VMOVP builder, and make sure we don't issuer the command if we don't really need to.
--- drivers/irqchip/irq-gic-v3-its.c | 40 ++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 7 deletions(-)
drivers/irqchip/irq-gic-v3-its.c +33 -7
@@ -443,6 +443,17 @@ static void its_encode_vmapp_default_db(struct its_cmd_block *cmd,its_mask_encode (&cmd->raw_cmd[1 ], vpe_db_lpi,31 ,0 ); } +static void its_encode_vmovp_default_db (struct its_cmd_block *cmd, +u32 vpe_db_lpi) +{ +its_mask_encode (&cmd->raw_cmd[3 ], vpe_db_lpi,31 ,0 ); +} + +static void its_encode_db (struct its_cmd_block *cmd,bool db) +{ +its_mask_encode (&cmd->raw_cmd[2 ], db,63 ,63 ); +} +static inline void its_fixup_cmd (struct its_cmd_block *cmd) {/* Let's fixup BE commands */
@@ -729,6 +740,11 @@ static struct its_vpe *its_build_vmovp_cmd(struct its_node *its,its_encode_vpeid (cmd, desc->its_vmovp_cmd.vpe->vpe_id);its_encode_target (cmd, target); +if (is_v4_1 (its)) { +its_encode_db (cmd, true); +its_encode_vmovp_default_db (cmd, desc->its_vmovp_cmd.vpe->vpe_db_lpi); + } +its_fixup_cmd (cmd);return valid_vpe (its, desc->its_vmovp_cmd.vpe);
@@ -3182,7 +3198,7 @@ static int its_vpe_set_affinity(struct irq_data *d, bool force) {struct its_vpe *vpe =irq_data_get_irq_chip_data (d); -int cpu =cpumask_first (mask_val); +int from, cpu =cpumask_first (mask_val);/* * Changing affinity is mega expensive, so let's be as lazy as
@@ -3190,14 +3206,24 @@ static int its_vpe_set_affinity(struct irq_data *d,* into the proxy device, we need to move the doorbell * interrupt to its new location. */ -if (vpe->col_idx != cpu) { -int from = vpe->col_idx; +if (vpe->col_idx == cpu) + goto out; - vpe->col_idx = cpu; -its_send_vmovp (vpe); -its_vpe_db_proxy_move (vpe, from, cpu); - } + from = vpe->col_idx; + vpe->col_idx = cpu; + +/* +* GICv4.1 allows us to skip VMOVP if moving to a cpu whose RD +* is sharing its VPE table with the current one. +*/ +if (gic_data_rdist_cpu (cpu)->vpe_table_mask && +cpumask_test_cpu (from,gic_data_rdist_cpu (cpu)->vpe_table_mask)) + goto out; +its_send_vmovp (vpe); +its_vpe_db_proxy_move (vpe, from, cpu); + +out:irq_data_update_effective_affinity (d,cpumask_of (cpu));return IRQ_SET_MASK_OK_DONE ;
Signature · 1 line
2.20.1
Re: [PATCH v2 14/36] irqchip/gic-v4.1: Implement the v4.1 flavour of VMOVP
Hi Marc,
Quoted 3 lines · Marc Zyngier
With GICv4.1, VMOVP is extended to allow a default doorbell to be specified, as well as a validity bit for this doorbell. As an added bonus, VMOPVP isn't required anymore of moving a VPE between
^^^^^^
VMOVP
Quoted 4 lines
redistributors that share the same affinity.
Let's add this support to the VMOVP builder, and make sure we don't issuer the command if we don't really need to.
issue
Quoted 2 lines
Signed-off-by Marc Zyngier <[email protected]>
Marc Zyngier
maintainerPATCH v2 15/36 irqchip/gic-v4.1: Plumb skeletal VPE irqchip
In reply to Marc ZyngierJust like for GICv4.0, each VPE has its own doorbell interrupt, and thus an irqchip that manages them. Since the doorbell management is quite different on GICv4.1, let's introduce an almost empty irqchip the will get populated over the next new patches.
--- drivers/irqchip/irq-gic-v3-its.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-)
drivers/irqchip/irq-gic-v3-its.c +31 -1
@@ -3408,6 +3408,32 @@ static struct irq_chip its_vpe_irq_chip = { .irq_set_vcpu_affinity = its_vpe_set_vcpu_affinity, }; +static int its_vpe_4_1_set_vcpu_affinity (struct irq_data *d,void *vcpu_info) +{ +struct its_cmd_info *info = vcpu_info; + +switch (info->cmd_type) { +case SCHEDULE_VPE : +return 0 ; + +case DESCHEDULE_VPE : +return 0 ; + +case INVALL_VPE : +return 0 ; + +default : +return -EINVAL ; + } +} + +static struct irq_chip its_vpe_4_1_irq_chip = { + .name ="GICv4.1-vpe" , + .irq_eoi = irq_chip_eoi_parent, + .irq_set_affinity = its_vpe_set_affinity, + .irq_set_vcpu_affinity = its_vpe_4_1_set_vcpu_affinity, +}; +static int its_vpe_id_alloc (void ) {return ida_simple_get (&its_vpeid_ida,0 ,ITS_MAX_VPEID ,GFP_KERNEL );
@@ -3488,6 +3514,7 @@ static void its_vpe_irq_domain_free(struct irq_domain *domain,static int its_vpe_irq_domain_alloc (struct irq_domain *domain,unsigned int virq,unsigned int nr_irqs,void *args) { +struct irq_chip *irqchip = &its_vpe_irq_chip;struct its_vm *vm = args;unsigned long *bitmap;struct page *vprop_page;
@@ -3515,6 +3542,9 @@ static int its_vpe_irq_domain_alloc(struct irq_domain *domain, unsigned int virq vm->nr_db_lpis = nr_ids; vm->vprop_page = vprop_page; +if (gic_rdists->has_rvpeid) + irqchip = &its_vpe_4_1_irq_chip; +for (i =0 ; i < nr_irqs; i++) { vm->vpes[i]->vpe_db_lpi = base + i; err =its_vpe_init (vm->vpes[i]);
@@ -3525,7 +3555,7 @@ static int its_vpe_irq_domain_alloc(struct irq_domain *domain, unsigned int virqif (err)break ;irq_domain_set_hwirq_and_chip (domain, virq + i, i, - &its_vpe_irq_chip, vm->vpes[i]); + irqchip, vm->vpes[i]);set_bit (i, bitmap); }
Signature · 1 line
2.20.1
Re: [PATCH v2 15/36] irqchip/gic-v4.1: Plumb skeletal VPE irqchip
Hi Marc,
Quoted 6 lines · Marc Zyngier
Just like for GICv4.0, each VPE has its own doorbell interrupt, and thus an irqchip that manages them. Since the doorbell management is quite different on GICv4.1, let's introduce an almost empty irqchip the will get populated over the next new patches.
Signed-off-by Marc Zyngier <[email protected]>
Marc Zyngier
maintainerPATCH v2 16/36 irqchip/gic-v4.1: Add mask/unmask doorbell callbacks
In reply to Marc Zyngiermasking/unmasking doorbells on GICv4.1 relies on a new INVDB command, which broadcasts the invalidation to all RDs.
Implement the new command as well as the masking callbacks, and plug the whole thing into the v4.1 VPE irqchip.
--- drivers/irqchip/irq-gic-v3-its.c | 60 ++++++++++++++++++++++++++++++ include/linux/irqchip/arm-gic-v3.h | 3 +- 2 files changed, 62 insertions(+), 1 deletion(-)
drivers/irqchip/irq-gic-v3-its.c +60 -0
@@ -309,6 +309,10 @@ struct its_cmd_desc {u16 seq_num;u16 its_list; } its_vmovp_cmd; + +struct { +struct its_vpe *vpe; + } its_invdb_cmd; }; };
@@ -750,6 +754,21 @@ static struct its_vpe *its_build_vmovp_cmd(struct its_node *its,return valid_vpe (its, desc->its_vmovp_cmd.vpe); } +static struct its_vpe *its_build_invdb_cmd (struct its_node *its, +struct its_cmd_block *cmd, +struct its_cmd_desc *desc) +{ +if (WARN_ON (!is_v4_1 (its))) +return NULL ; + +its_encode_cmd (cmd,GITS_CMD_INVDB ); +its_encode_vpeid (cmd, desc->its_invdb_cmd.vpe->vpe_id); + +its_fixup_cmd (cmd); + +return valid_vpe (its, desc->its_invdb_cmd.vpe); +} +static u64 its_cmd_ptr_to_offset (struct its_node *its,struct its_cmd_block *ptr) {
@@ -1117,6 +1136,14 @@ static void its_send_vinvall(struct its_node *its, struct its_vpe *vpe)its_send_single_vcommand (its, its_build_vinvall_cmd, &desc); } +static void its_send_invdb (struct its_node *its,struct its_vpe *vpe) +{ +struct its_cmd_desc desc; + + desc.its_invdb_cmd.vpe = vpe; +its_send_single_vcommand (its, its_build_invdb_cmd, &desc); +} +/* * irqchip functions - assumes MSI, mostly. */
@@ -3408,6 +3435,37 @@ static struct irq_chip its_vpe_irq_chip = { .irq_set_vcpu_affinity = its_vpe_set_vcpu_affinity, }; +static void its_vpe_4_1_send_inv (struct irq_data *d) +{ +struct its_vpe *vpe =irq_data_get_irq_chip_data (d); +struct its_node *its; + +/* +* GICv4.1 wants doorbells to be invalidated using the +* INVDB command in order to be broadcast to all RDs. Send +* it to the first valid ITS, and let the HW do its magic. +*/ +list_for_each_entry (its, &its_nodes, entry) { +if (!is_v4_1 (its)) +continue ; + +its_send_invdb (its, vpe); +break ; + } +} + +static void its_vpe_4_1_mask_irq (struct irq_data *d) +{ +lpi_write_config (d->parent_data,LPI_PROP_ENABLED ,0 ); +its_vpe_4_1_send_inv (d); +} + +static void its_vpe_4_1_unmask_irq (struct irq_data *d) +{ +lpi_write_config (d->parent_data,0 ,LPI_PROP_ENABLED ); +its_vpe_4_1_send_inv (d); +} +static int its_vpe_4_1_set_vcpu_affinity (struct irq_data *d,void *vcpu_info) {struct its_cmd_info *info = vcpu_info;
@@ -3429,6 +3487,8 @@ static int its_vpe_4_1_set_vcpu_affinity(struct irq_data *d, void *vcpu_info)static struct irq_chip its_vpe_4_1_irq_chip = { .name ="GICv4.1-vpe" , + .irq_mask = its_vpe_4_1_mask_irq, + .irq_unmask = its_vpe_4_1_unmask_irq, .irq_eoi = irq_chip_eoi_parent, .irq_set_affinity = its_vpe_set_affinity, .irq_set_vcpu_affinity = its_vpe_4_1_set_vcpu_affinity,
include/linux/irqchip/arm-gic-v3.h +2 -1
@@ -484,8 +484,9 @@#define GITS_CMD_VMAPTI GITS_CMD_GICv4(GITS_CMD_MAPTI)#define GITS_CMD_VMOVI GITS_CMD_GICv4(GITS_CMD_MOVI)#define GITS_CMD_VSYNC GITS_CMD_GICv4(GITS_CMD_SYNC) -/* VMOVP is the odd one, as it doesn't have a physical counterpart */ +/* VMOVP and INVDB are the odd ones, as they dont have a physical counterpart */ #define GITS_CMD_VMOVP GITS_CMD_GICv4(2) +#define GITS_CMD_INVDB GITS_CMD_GICv4(0xe)/* * ITS error numbers
Signature · 1 line
2.20.1
Re: [PATCH v2 16/36] irqchip/gic-v4.1: Add mask/unmask doorbell callbacks
Hi Marc,
Quoted 7 lines · Marc Zyngier
masking/unmasking doorbells on GICv4.1 relies on a new INVDB command, which broadcasts the invalidation to all RDs.
Implement the new command as well as the masking callbacks, and plug the whole thing into the v4.1 VPE irqchip.
Signed-off-by Marc Zyngier <[email protected]>
Quoted 68 lines
--- drivers/irqchip/irq-gic-v3-its.c | 60 ++++++++++++++++++++++++++++++ include/linux/irqchip/arm-gic-v3.h | 3 +- 2 files changed, 62 insertions(+), 1 deletion(-)drivers/irqchip/irq-gic-v3-its.c +34
-0@@ -309,6 +309,10 @@ struct its_cmd_desc {u16 seq_num;u16 its_list; } its_vmovp_cmd; + +struct { +struct its_vpe *vpe; + } its_invdb_cmd; }; };@@ -750,6 +754,21 @@ static struct its_vpe *its_build_vmovp_cmd(struct its_node *its,return valid_vpe (its, desc->its_vmovp_cmd.vpe); } +static struct its_vpe *its_build_invdb_cmd (struct its_node *its, +struct its_cmd_block *cmd, +struct its_cmd_desc *desc) +{ +if (WARN_ON (!is_v4_1 (its))) +return NULL ; + +its_encode_cmd (cmd,GITS_CMD_INVDB ); +its_encode_vpeid (cmd, desc->its_invdb_cmd.vpe->vpe_id); + +its_fixup_cmd (cmd); + +return valid_vpe (its, desc->its_invdb_cmd.vpe); +} +static u64 its_cmd_ptr_to_offset (struct its_node *its,struct its_cmd_block *ptr) {@@ -1117,6 +1136,14 @@ static void its_send_vinvall(struct its_node *its, struct its_vpe *vpe)its_send_single_vcommand (its, its_build_vinvall_cmd, &desc); } +static void its_send_invdb (struct its_node *its,struct its_vpe *vpe) +{ +struct its_cmd_desc desc; + + desc.its_invdb_cmd.vpe = vpe; +its_send_single_vcommand (its, its_build_invdb_cmd, &desc); +} +/* * irqchip functions - assumes MSI, mostly. */ @@ -3408,6 +3435,37 @@ static struct irq_chip its_vpe_irq_chip = { .irq_set_vcpu_affinity = its_vpe_set_vcpu_affinity, }; +static void its_vpe_4_1_send_inv (struct irq_data *d) +{ +struct its_vpe *vpe =irq_data_get_irq_chip_data (d); +struct its_node *its; + +/* +* GICv4.1 wants doorbells to be invalidated using the
drivers/irqchip/irq-gic-v3-its.c static struct irq_chip its_vpe_irq_chip = { · line 3454
Quoted 10 lines
drivers/irqchip/irq-gic-v3-its.c +10
-0+* INVDB command in order to be broadcast to all RDs. Send +* it to the first valid ITS, and let the HW do its magic. +*/ +list_for_each_entry (its, &its_nodes, entry) { +if (!is_v4_1 (its)) +continue ; + +its_send_invdb (its, vpe); +break ; + }
Maybe use find_4_1_its() helper instead?
Thanks,
Zenghui
Quoted 42 lines
drivers/irqchip/irq-gic-v3-its.c +16
-0+} + +static void its_vpe_4_1_mask_irq (struct irq_data *d) +{ +lpi_write_config (d->parent_data,LPI_PROP_ENABLED ,0 ); +its_vpe_4_1_send_inv (d); +} + +static void its_vpe_4_1_unmask_irq (struct irq_data *d) +{ +lpi_write_config (d->parent_data,0 ,LPI_PROP_ENABLED ); +its_vpe_4_1_send_inv (d); +} +static int its_vpe_4_1_set_vcpu_affinity (struct irq_data *d,void *vcpu_info) {struct its_cmd_info *info = vcpu_info;@@ -3429,6 +3487,8 @@ static int its_vpe_4_1_set_vcpu_affinity(struct irq_data *d, void *vcpu_info)static struct irq_chip its_vpe_4_1_irq_chip = { .name ="GICv4.1-vpe" , + .irq_mask = its_vpe_4_1_mask_irq, + .irq_unmask = its_vpe_4_1_unmask_irq, .irq_eoi = irq_chip_eoi_parent, .irq_set_affinity = its_vpe_set_affinity, .irq_set_vcpu_affinity = its_vpe_4_1_set_vcpu_affinity,include/linux/irqchip/arm-gic-v3.h +2
-1@@ -484,8 +484,9 @@#define GITS_CMD_VMAPTI GITS_CMD_GICv4(GITS_CMD_MAPTI)#define GITS_CMD_VMOVI GITS_CMD_GICv4(GITS_CMD_MOVI)#define GITS_CMD_VSYNC GITS_CMD_GICv4(GITS_CMD_SYNC) -/* VMOVP is the odd one, as it doesn't have a physical counterpart */ +/* VMOVP and INVDB are the odd ones, as they dont have a physical counterpart */ #define GITS_CMD_VMOVP GITS_CMD_GICv4(2) +#define GITS_CMD_INVDB GITS_CMD_GICv4(0xe)/* * ITS error numbers
Marc Zyngier
maintainerRe: [PATCH v2 16/36] irqchip/gic-v4.1: Add mask/unmask doorbell callbacks
Quoted 82 lines · Zenghui Yu
Hi Marc,
Quoted 5 lines · Marc Zyngier
masking/unmasking doorbells on GICv4.1 relies on a new INVDB command, which broadcasts the invalidation to all RDs.
Implement the new command as well as the masking callbacks, and plug the whole thing into the v4.1 VPE irqchip.Signed-off-by Marc Zyngier <[email protected]>Reviewed-by Zenghui Yu <[email protected]>Quoted 71 lines
--- drivers/irqchip/irq-gic-v3-its.c | 60 ++++++++++++++++++++++++++++++ include/linux/irqchip/arm-gic-v3.h | 3 +- 2 files changed, 62 insertions(+), 1 deletion(-)drivers/irqchip/irq-gic-v3-its.c +4
-0@@ -309,6 +309,10 @@ struct its_cmd_desc {u16 seq_num;u16 its_list; } its_vmovp_cmd; + +struct { +struct its_vpe *vpe; + } its_invdb_cmd; }; }; @@ -750,6 +754,21 @@ static struct its_vpe*its_build_vmovp_cmd(struct
its_node*its,
returnvalid_vpe(its, desc->its_vmovp_cmd.vpe);
}
+static structits_vpe*its_build_invdb_cmd(structits_node*its,drivers/irqchip/irq-gic-v3-its.c +31
-0+ struct its_cmd_block *cmd, + struct its_cmd_desc *desc) +{ +if (WARN_ON (!is_v4_1 (its))) +return NULL ; + +its_encode_cmd (cmd,GITS_CMD_INVDB ); +its_encode_vpeid (cmd, desc->its_invdb_cmd.vpe->vpe_id); + +its_fixup_cmd (cmd); + +return valid_vpe (its, desc->its_invdb_cmd.vpe); +} +static u64 its_cmd_ptr_to_offset (struct its_node *its,struct its_cmd_block *ptr) {@@ -1117,6 +1136,14 @@ static void its_send_vinvall(struct its_node *its, struct its_vpe *vpe)its_send_single_vcommand (its, its_build_vinvall_cmd, &desc); } +static void its_send_invdb(struct its_node *its, struct its_vpe *vpe) +{ +struct its_cmd_desc desc; + + desc.its_invdb_cmd.vpe = vpe; +its_send_single_vcommand (its, its_build_invdb_cmd, &desc); +} +/* * irqchip functions - assumes MSI, mostly. */ @@ -3408,6 +3435,37 @@ static struct irq_chip its_vpe_irq_chip = { .irq_set_vcpu_affinity = its_vpe_set_vcpu_affinity, }; +static void its_vpe_4_1_send_inv(struct irq_data *d) +{ +struct its_vpe *vpe =irq_data_get_irq_chip_data (d); +struct its_node *its; + +/* +* GICv4.1 wants doorbells to be invalidated using the +* INVDB command in order to be broadcast to all RDs. Send +* it to the first valid ITS, and let the HW do its magic. +*/ +list_for_each_entry (its, &its_nodes, entry) {
Quoted 8 lines
drivers/irqchip/irq-gic-v3-its.c static struct irq_chip its_vpe_irq_chip = { · line 3454
Quoted 6 lines
drivers/irqchip/irq-gic-v3-its.c +6
-0+if (!is_v4_1 (its)) +continue ; + +its_send_invdb (its, vpe); +break ; + }Maybe use
find_4_1_its()helper instead?
Yes, good point. I've moved it up in the series, and it is now added to this patch.
Thanks,
M.
Signature · 1 line
Jazz is not dead. It just smells funny...
Marc Zyngier
maintainerPATCH v2 17/36 irqchip/gic-v4.1: Add VPE residency callback
In reply to Marc ZyngierMaking a VPE resident on GICv4.1 is pretty simple, as it is just a single write to the local redistributor. We just need extra information about which groups to enable, which the KVM code will have to provide.
--- drivers/irqchip/irq-gic-v3-its.c | 17 +++++++++++++++++ include/linux/irqchip/arm-gic-v3.h | 9 +++++++++ include/linux/irqchip/arm-gic-v4.h | 5 +++++ 3 files changed, 31 insertions(+)
drivers/irqchip/irq-gic-v3-its.c +17 -0
@@ -3466,12 +3466,29 @@ static void its_vpe_4_1_unmask_irq(struct irq_data *d)its_vpe_4_1_send_inv (d); } +static void its_vpe_4_1_schedule (struct its_vpe *vpe, +struct its_cmd_info *info) +{ +void __iomem *vlpi_base =gic_data_rdist_vlpi_base (); +u64 val =0 ; + +/* Schedule the VPE */ + val |= GICR_VPENDBASER_Valid; + val |= info->g0en ?GICR_VPENDBASER_4_1_VGRP0EN :0 ; + val |= info->g1en ?GICR_VPENDBASER_4_1_VGRP1EN :0 ; + val |=FIELD_PREP (GICR_VPENDBASER_4_1_VPEID , vpe->vpe_id); + +gits_write_vpendbaser (val, vlpi_base +GICR_VPENDBASER ); +} +static int its_vpe_4_1_set_vcpu_affinity (struct irq_data *d,void *vcpu_info) { +struct its_vpe *vpe =irq_data_get_irq_chip_data (d);struct its_cmd_info *info = vcpu_info;switch (info->cmd_type) {case SCHEDULE_VPE : +its_vpe_4_1_schedule (vpe, info);return 0 ;case DESCHEDULE_VPE :
include/linux/irqchip/arm-gic-v3.h +9 -0
@@ -327,6 +327,15 @@#define GICR_VPENDBASER_IDAI (1ULL << 62)#define GICR_VPENDBASER_Valid (1ULL << 63) +/* +* GICv4.1 VPENDBASER, used for VPE residency. On top of these fields, +* also use the above Valid, PendingLast and Dirty. +*/ +#define GICR_VPENDBASER_4_1_DB (1ULL << 62) +#define GICR_VPENDBASER_4_1_VGRP0EN (1ULL << 59) +#define GICR_VPENDBASER_4_1_VGRP1EN (1ULL << 58) +#define GICR_VPENDBASER_4_1_VPEID GENMASK_ULL(15, 0) +/* * ITS registers, offsets from ITS_base */
include/linux/irqchip/arm-gic-v4.h +5 -0
@@ -98,6 +98,11 @@ struct its_cmd_info {union {struct its_vlpi_map *map;u8 config; +bool req_db; +struct { +bool g0en; +bool g1en; + }; }; };
Signature · 1 line
2.20.1
Re: [PATCH v2 17/36] irqchip/gic-v4.1: Add VPE residency callback
Hi Marc,
Quoted 5 lines · Marc Zyngier
Making a VPE resident on GICv4.1 is pretty simple, as it is just a single write to the local redistributor. We just need extra information about which groups to enable, which the KVM code will have to provide.
Signed-off-by Marc Zyngier <[email protected]>
Marc Zyngier
maintainerPATCH v2 18/36 irqchip/gic-v4.1: Add VPE eviction callback
In reply to Marc ZyngierWhen descheduling a VPE, special care must be taken to tell the GIC about whether we want to receive a doorbell or not. This is a major improvement on GICv4.0, where the doorbell had to be separately enabled/disabled.
--- drivers/irqchip/irq-gic-v3-its.c | 53 +++++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 11 deletions(-)
drivers/irqchip/irq-gic-v3-its.c +42 -11
@@ -2487,7 +2487,7 @@ static int __init allocate_lpi_tables(void)return 0 ; } -static u64 its_clear_vpend_valid (void __iomem *vlpi_base) +static u64 its_clear_vpend_valid (void __iomem *vlpi_base,u64 clr,u64 set) {u32 count =1000000 ;/* 1s! */ bool clean;
@@ -2495,6 +2495,8 @@ static u64 its_clear_vpend_valid(void __iomem *vlpi_base) val =gits_read_vpendbaser (vlpi_base +GICR_VPENDBASER ); val &= ~GICR_VPENDBASER_Valid; + val &= ~clr; + val |= set;gits_write_vpendbaser (val, vlpi_base +GICR_VPENDBASER ); do {
@@ -2507,6 +2509,11 @@ static u64 its_clear_vpend_valid(void __iomem *vlpi_base) } }while (!clean && count); +if (unlikely (val & GICR_VPENDBASER_Dirty)) { +pr_err_ratelimited ("ITS virtual pending table not cleaning\n" ); + val |= GICR_VPENDBASER_PendingLast; + } +return val; }
@@ -2615,7 +2622,7 @@ static void its_cpu_init_lpis(void)* ancient programming gets left in and has possibility of * corrupting memory. */ - val =its_clear_vpend_valid (vlpi_base); + val =its_clear_vpend_valid (vlpi_base,0 ,0 );WARN_ON (val & GICR_VPENDBASER_Dirty); }
@@ -3293,16 +3300,10 @@ static void its_vpe_deschedule(struct its_vpe *vpe)void __iomem *vlpi_base =gic_data_rdist_vlpi_base ();u64 val; - val =its_clear_vpend_valid (vlpi_base); + val =its_clear_vpend_valid (vlpi_base,0 ,0 ); -if (unlikely (val & GICR_VPENDBASER_Dirty)) { -pr_err_ratelimited ("ITS virtual pending table not cleaning\n" ); - vpe->idai = false; - vpe->pending_last = true; - }else { - vpe->idai = !!(val &GICR_VPENDBASER_IDAI ); - vpe->pending_last = !!(val & GICR_VPENDBASER_PendingLast); - } + vpe->idai = !!(val &GICR_VPENDBASER_IDAI ); + vpe->pending_last = !!(val & GICR_VPENDBASER_PendingLast); }static void its_vpe_invall (struct its_vpe *vpe)
@@ -3481,6 +3482,35 @@ static void its_vpe_4_1_schedule(struct its_vpe *vpe,gits_write_vpendbaser (val, vlpi_base +GICR_VPENDBASER ); } +static void its_vpe_4_1_deschedule (struct its_vpe *vpe, +struct its_cmd_info *info) +{ +void __iomem *vlpi_base =gic_data_rdist_vlpi_base (); +u64 val; + +if (info->req_db) { +/* +* vPE is going to block: make the vPE non-resident with +* PendingLast clear and DB set. The GIC guarantees that if +* we read-back PendingLast clear, then a doorbell will be +* delivered when an interrupt comes. +*/ + val =its_clear_vpend_valid (vlpi_base, + GICR_VPENDBASER_PendingLast, +GICR_VPENDBASER_4_1_DB ); + vpe->pending_last = !!(val & GICR_VPENDBASER_PendingLast); + }else { +/* +* We're not blocking, so just make the vPE non-resident +* with PendingLast set, indicating that we'll be back. +*/ + val =its_clear_vpend_valid (vlpi_base, +0 , + GICR_VPENDBASER_PendingLast); + vpe->pending_last = true; + } +} +static int its_vpe_4_1_set_vcpu_affinity (struct irq_data *d,void *vcpu_info) {struct its_vpe *vpe =irq_data_get_irq_chip_data (d);
@@ -3492,6 +3522,7 @@ static int its_vpe_4_1_set_vcpu_affinity(struct irq_data *d, void *vcpu_info)return 0 ;case DESCHEDULE_VPE : +its_vpe_4_1_deschedule (vpe, info);return 0 ;case INVALL_VPE :
Signature · 1 line
2.20.1
Re: [PATCH v2 18/36] irqchip/gic-v4.1: Add VPE eviction callback
Hi Marc,
Quoted 6 lines · Marc Zyngier
When descheduling a VPE, special care must be taken to tell the GIC about whether we want to receive a doorbell or not. This is a major improvement on GICv4.0, where the doorbell had to be separately enabled/disabled.
Signed-off-by Marc Zyngier <[email protected]>
Marc Zyngier
maintainerPATCH v2 19/36 irqchip/gic-v4.1: Add VPE INVALL callback
In reply to Marc ZyngierGICv4.1 redistributors have a VPE-aware INVALL register. Progress! We can now emulate a guest-requested INVALL without emiting a VINVALL command.
--- drivers/irqchip/irq-gic-v3-its.c | 14 ++++++++++++++ include/linux/irqchip/arm-gic-v3.h | 3 +++ 2 files changed, 17 insertions(+)
drivers/irqchip/irq-gic-v3-its.c +14 -0
@@ -3511,6 +3511,19 @@ static void its_vpe_4_1_deschedule(struct its_vpe *vpe, } } +static void its_vpe_4_1_invall (struct its_vpe *vpe) +{ +void __iomem *rdbase; +u64 val; + + val =GICR_INVLPIR_V ; + val |=FIELD_PREP (GICR_INVLPIR_VPEID , vpe->vpe_id); + +/* Target the redistributor this vPE is currently known on */ + rdbase =per_cpu_ptr (gic_rdists->rdist, vpe->col_idx)->rd_base; +gic_write_lpir (val, rdbase +GICR_INVALLR ); +} +static int its_vpe_4_1_set_vcpu_affinity (struct irq_data *d,void *vcpu_info) {struct its_vpe *vpe =irq_data_get_irq_chip_data (d);
@@ -3526,6 +3539,7 @@ static int its_vpe_4_1_set_vcpu_affinity(struct irq_data *d, void *vcpu_info)return 0 ;case INVALL_VPE : +its_vpe_4_1_invall (vpe);return 0 ;default :
include/linux/irqchip/arm-gic-v3.h +3 -0
@@ -247,6 +247,9 @@#define GICR_TYPER_COMMON_LPI_AFF GENMASK_ULL(25, 24)#define GICR_TYPER_AFFINITY GENMASK_ULL(63, 32) +#define GICR_INVLPIR_VPEID GENMASK_ULL(47, 32) +#define GICR_INVLPIR_V GENMASK_ULL(63, 63) +#define GIC_V3_REDIST_SIZE 0x20000#define LPI_PROP_GROUP1 (1 << 1)
Signature · 1 line
2.20.1
Re: [PATCH v2 19/36] irqchip/gic-v4.1: Add VPE INVALL callback
Hi Marc,
Quoted 5 lines · Marc Zyngier
GICv4.1 redistributors have a VPE-aware INVALL register. Progress! We can now emulate a guest-requested INVALL without emiting a VINVALL command.
Signed-off-by Marc Zyngier <[email protected]>
Quoted 10 lines
--- drivers/irqchip/irq-gic-v3-its.c | 14 ++++++++++++++ include/linux/irqchip/arm-gic-v3.h | 3 +++ 2 files changed, 17 insertions(+)drivers/irqchip/irq-gic-v3-its.c +0
-0
drivers/irqchip/irq-gic-v3-its.c static void its_vpe_4_1_deschedule(struct its_vpe *vpe, · line 3520
Quoted 10 lines
drivers/irqchip/irq-gic-v3-its.c +7
-0@@ -3511,6 +3511,19 @@ static void its_vpe_4_1_deschedule(struct its_vpe *vpe, } } +static void its_vpe_4_1_invall (struct its_vpe *vpe) +{ +void __iomem *rdbase; +u64 val; + + val =GICR_INVLPIR_V ; + val |=FIELD_PREP (GICR_INVLPIR_VPEID , vpe->vpe_id);
Can we use GICR_INVALL_V/VPEID instead, and ...
Quoted 22 lines
drivers/irqchip/irq-gic-v3-its.c +7
-0+ +/* Target the redistributor this vPE is currently known on */ + rdbase =per_cpu_ptr (gic_rdists->rdist, vpe->col_idx)->rd_base; +gic_write_lpir (val, rdbase +GICR_INVALLR ); +} +static int its_vpe_4_1_set_vcpu_affinity (struct irq_data *d,void *vcpu_info) {struct its_vpe *vpe =irq_data_get_irq_chip_data (d);@@ -3526,6 +3539,7 @@ static int its_vpe_4_1_set_vcpu_affinity(struct irq_data *d, void *vcpu_info)return 0 ;case INVALL_VPE : +its_vpe_4_1_invall (vpe);return 0 ;default :include/linux/irqchip/arm-gic-v3.h +0
-0
include/linux/irqchip/arm-gic-v3.h line 252
Quoted 6 lines
include/linux/irqchip/arm-gic-v3.h +3
-0@@ -247,6 +247,9 @@#define GICR_TYPER_COMMON_LPI_AFF GENMASK_ULL(25, 24)#define GICR_TYPER_AFFINITY GENMASK_ULL(63, 32) +#define GICR_INVLPIR_VPEID GENMASK_ULL(47, 32) +#define GICR_INVLPIR_V GENMASK_ULL(63, 63) +
... define them here:
#define GICR_INVALL_VPEID GICR_INVLPIR_VPEID
#define GICR_INVALL_V GICR_INVLPIR_V
Thanks,
Zenghui
Quoted 4 lines
include/linux/irqchip/arm-gic-v3.h +0
-0#define GIC_V3_REDIST_SIZE 0x20000#define LPI_PROP_GROUP1 (1 << 1)
Marc Zyngier
maintainerRe: [PATCH v2 19/36] irqchip/gic-v4.1: Add VPE INVALL callback
[Old email, doing some v3 cleanup]
Quoted 64 lines · Zenghui Yu
Hi Marc,
Quoted 4 lines · Marc Zyngier
GICv4.1 redistributors have a VPE-aware INVALL register. Progress! We can now emulate a guest-requested INVALL without emiting a VINVALL command.
Signed-off-by Marc Zyngier <[email protected]>Reviewed-by Zenghui Yu <[email protected]>Quoted 9 lines
--- drivers/irqchip/irq-gic-v3-its.c | 14 ++++++++++++++ include/linux/irqchip/arm-gic-v3.h | 3 +++ 2 files changed, 17 insertions(+)drivers/irqchip/irq-gic-v3-its.c +0
-0drivers/irqchip/irq-gic-v3-its.c static void its_vpe_4_1_deschedule(struct · line 3520
Quoted 10 lines
drivers/irqchip/irq-gic-v3-its.c +6
-0@@ -3511,6 +3511,19 @@ static void its_vpe_4_1_deschedule(struct its_vpe *vpe, } } +static void its_vpe_4_1_invall(struct its_vpe *vpe) +{ +void __iomem *rdbase; +u64 val; + + val =GICR_INVLPIR_V ; + val |=FIELD_PREP (GICR_INVLPIR_VPEID , vpe->vpe_id);Can we use GICR_INVALL_V/VPEID instead, and ...
Quoted 24 lines
drivers/irqchip/irq-gic-v3-its.c +7
-0+ +/* Target the redistributor this vPE is currently known on */ + rdbase =per_cpu_ptr (gic_rdists->rdist, vpe->col_idx)->rd_base; +gic_write_lpir (val, rdbase +GICR_INVALLR ); +} +static int its_vpe_4_1_set_vcpu_affinity (struct irq_data *d,void *vcpu_info) {struct its_vpe *vpe =irq_data_get_irq_chip_data (d);@@ -3526,6 +3539,7 @@ static int its_vpe_4_1_set_vcpu_affinity(struct irq_data *d, void *vcpu_info) return 0;case INVALL_VPE : +its_vpe_4_1_invall (vpe);return 0 ;default:
include/linux/irqchip/arm-gic-v3.h +0
-0include/linux/irqchip/arm-gic-v3.h line 251
Quoted 5 lines
include/linux/irqchip/arm-gic-v3.h +2
-0@@ -247,6 +247,9 @@#define GICR_TYPER_COMMON_LPI_AFF GENMASK_ULL(25, 24)#define GICR_TYPER_AFFINITY GENMASK_ULL(63, 32) +#define GICR_INVLPIR_VPEID GENMASK_ULL(47, 32) +#define GICR_INVLPIR_V GENMASK_ULL(63, 63) +... define them here:
Quoted 2 lines
#define
GICR_INVALL_VPEIDGICR_INVLPIR_VPEID
#defineGICR_INVALL_VGICR_INVLPIR_V
Yes, that's a sensible things to do. I'll squash that in my rebased series.
Thanks,
M.
Signature · 1 line
Jazz is not dead. It just smells funny...
Marc Zyngier
maintainerPATCH v2 20/36 irqchip/gic-v4.1: Suppress per-VLPI doorbell
In reply to Marc ZyngierSince GICv4.1 gives us a per-VPE doorbell, avoid programming anything else on VMOVI/VMAPI/VMAPTI and on any other action that would have otherwise resulted in a per-VLPI doorbell to be programmed.
--- drivers/irqchip/irq-gic-v3-its.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
drivers/irqchip/irq-gic-v3-its.c +9 -2
@@ -691,7 +691,7 @@ static struct its_vpe *its_build_vmapti_cmd(struct its_node *its, {u32 db; -if (desc->its_vmapti_cmd.db_enabled) +if (!is_v4_1 (its) && desc->its_vmapti_cmd.db_enabled) db = desc->its_vmapti_cmd.vpe->vpe_db_lpi;else db =1023 ;
@@ -714,7 +714,7 @@ static struct its_vpe *its_build_vmovi_cmd(struct its_node *its, {u32 db; -if (desc->its_vmovi_cmd.db_enabled) +if (!is_v4_1 (its) && desc->its_vmovi_cmd.db_enabled) db = desc->its_vmovi_cmd.vpe->vpe_db_lpi;else db =1023 ;
@@ -1227,6 +1227,13 @@ static void its_vlpi_set_doorbell(struct irq_data *d, bool enable)struct its_device *its_dev =irq_data_get_irq_chip_data (d);u32 event =its_get_event_id (d); +/* +* GICv4.1 does away with the per-LPI nonsense, nothing to do +* here. +*/ +if (is_v4_1 (its_dev->its)) +return ; +if (its_dev->event_map.vlpi_maps[event].db_enabled == enable)return ;
Signature · 1 line
2.20.1
Re: [PATCH v2 20/36] irqchip/gic-v4.1: Suppress per-VLPI doorbell
Hi Marc,
Quoted 5 lines · Marc Zyngier
Since GICv4.1 gives us a per-VPE doorbell, avoid programming anything else on VMOVI/VMAPI/VMAPTI and on any other action that would have otherwise resulted in a per-VLPI doorbell to be programmed.
Signed-off-by Marc Zyngier <[email protected]>
Marc Zyngier
maintainerPATCH v2 21/36 irqchip/gic-v4.1: Allow direct invalidation of VLPIs
In reply to Marc ZyngierJust like for INVALL, GICv4.1 has grown a VPE-aware INVLPI register. Let's plumb it in and make use of the DirectLPI code in that case.
--- drivers/irqchip/irq-gic-v3-its.c | 53 ++++++++++++++++++++---------- include/linux/irqchip/arm-gic-v3.h | 1 + 2 files changed, 36 insertions(+), 18 deletions(-)
drivers/irqchip/irq-gic-v3-its.c +35 -18
@@ -203,11 +203,26 @@ static struct its_collection *dev_event_to_col(struct its_device *its_dev,return its->collections + its_dev->event_map.col_map[event]; } -static struct its_collection *irq_to_col (struct irq_data *d) +static struct its_vlpi_map *get_vlpi_map (struct irq_data *d) {struct its_device *its_dev =irq_data_get_irq_chip_data (d); +u32 event =its_get_event_id (d); + +if (!irqd_is_forwarded_to_vcpu (d)) +return NULL ; -return dev_event_to_col (its_dev,its_get_event_id (d)); +return &its_dev->event_map.vlpi_maps[event]; +} + +static int irq_to_cpuid (struct irq_data *d) +{ +struct its_device *its_dev =irq_data_get_irq_chip_data (d); +struct its_vlpi_map *map =get_vlpi_map (d); + +if (map) +return map->vpe->col_idx; + +return its_dev->event_map.col_map[its_get_event_id (d)]; }static struct its_collection *valid_col (struct its_collection *col)
@@ -1147,17 +1162,6 @@ static void its_send_invdb(struct its_node *its, struct its_vpe *vpe)/* * irqchip functions - assumes MSI, mostly. */ -static struct its_vlpi_map *get_vlpi_map (struct irq_data *d) -{ -struct its_device *its_dev =irq_data_get_irq_chip_data (d); -u32 event =its_get_event_id (d); - -if (!irqd_is_forwarded_to_vcpu (d)) -return NULL ; - -return &its_dev->event_map.vlpi_maps[event]; -} -static void lpi_write_config (struct irq_data *d,u8 clr,u8 set) {struct its_vlpi_map *map =get_vlpi_map (d);
@@ -1200,13 +1204,25 @@ static void wait_for_syncr(void __iomem *rdbase)static void direct_lpi_inv (struct irq_data *d) { -struct its_collection *col; +struct its_vlpi_map *map =get_vlpi_map (d);void __iomem *rdbase; +u64 val; + +if (map) { +struct its_device *its_dev =irq_data_get_irq_chip_data (d); + +WARN_ON (!is_v4_1 (its_dev->its)); + + val =GICR_INVLPIR_V ; + val |=FIELD_PREP (GICR_INVLPIR_VPEID , map->vpe->vpe_id); + val |=FIELD_PREP (GICR_INVLPIR_INTID , map->vintid); + }else { + val = d->hwirq; + }/* Target the redistributor this LPI is currently routed to */ - col =irq_to_col (d); - rdbase =per_cpu_ptr (gic_rdists->rdist, col->col_id)->rd_base; -gic_write_lpir (d->hwirq, rdbase +GICR_INVLPIR ); + rdbase =per_cpu_ptr (gic_rdists->rdist,irq_to_cpuid (d))->rd_base; +gic_write_lpir (val, rdbase +GICR_INVLPIR );wait_for_syncr (rdbase); }
@@ -1216,7 +1232,8 @@ static void lpi_update_config(struct irq_data *d, u8 clr, u8 set)struct its_device *its_dev =irq_data_get_irq_chip_data (d);lpi_write_config (d, clr, set); -if (gic_rdists->has_direct_lpi && !irqd_is_forwarded_to_vcpu (d)) +if (gic_rdists->has_direct_lpi && + (is_v4_1 (its_dev->its) || !irqd_is_forwarded_to_vcpu (d)))direct_lpi_inv (d);else its_send_inv (its_dev,its_get_event_id (d));
include/linux/irqchip/arm-gic-v3.h +1 -0
@@ -247,6 +247,7 @@#define GICR_TYPER_COMMON_LPI_AFF GENMASK_ULL(25, 24)#define GICR_TYPER_AFFINITY GENMASK_ULL(63, 32) +#define GICR_INVLPIR_INTID GENMASK_ULL(31, 0)#define GICR_INVLPIR_VPEID GENMASK_ULL(47, 32)#define GICR_INVLPIR_V GENMASK_ULL(63, 63)
Signature · 1 line
2.20.1
Re: [PATCH v2 21/36] irqchip/gic-v4.1: Allow direct invalidation of VLPIs
Hi Marc,
Quoted 4 lines · Marc Zyngier
Just like for INVALL, GICv4.1 has grown a VPE-aware INVLPI register. Let's plumb it in and make use of the DirectLPI code in that case.
Signed-off-by Marc Zyngier <[email protected]>
Marc Zyngier
maintainerPATCH v2 22/36 irqchip/gic-v4.1: Advertise support v4.1 to KVM
In reply to Marc ZyngierTell KVM that we support v4.1. Nothing uses this information so far.
--- drivers/irqchip/irq-gic-v3-its.c | 9 ++++++++- drivers/irqchip/irq-gic-v3.c | 1 + include/linux/irqchip/arm-gic-common.h | 2 ++ 3 files changed, 11 insertions(+), 1 deletion(-)
drivers/irqchip/irq-gic-v3-its.c +8 -1
@@ -4580,6 +4580,7 @@ int __init its_init(struct fwnode_handle *handle, struct rdists *rdists,struct device_node *of_node;struct its_node *its;bool has_v4 = false; +bool has_v4_1 = false;int err; gic_rdists = rdists;
@@ -4600,8 +4601,14 @@ int __init its_init(struct fwnode_handle *handle, struct rdists *rdists,if (err)return err; -list_for_each_entry (its, &its_nodes, entry) +list_for_each_entry (its, &its_nodes, entry) { has_v4 |=is_v4 (its); + has_v4_1 |=is_v4_1 (its); + } + +/* Don't bother with inconsistent systems */ +if (WARN_ON (!has_v4_1 && rdists->has_rvpeid)) + rdists->has_rvpeid = false;if (has_v4 & rdists->has_vlpis) { if (its_init_vpe_domain() ||
drivers/irqchip/irq-gic-v3.c +1 -0
@@ -1758,6 +1758,7 @@ static void __init gic_of_setup_kvm_info(struct device_node *node) gic_v3_kvm_info.vcpu = r; gic_v3_kvm_info.has_v4 = gic_data.rdists.has_vlpis; + gic_v3_kvm_info.has_v4_1 = gic_data.rdists.has_rvpeid;gic_set_kvm_info (&gic_v3_kvm_info); }
include/linux/irqchip/arm-gic-common.h +2 -0
@@ -32,6 +32,8 @@ struct gic_kvm_info {struct resource vctrl;/* vlpi support */ bool has_v4; +/* rvpeid support */ +bool has_v4_1; };const struct gic_kvm_info *gic_get_kvm_info (void );
Signature · 1 line
2.20.1
Zenghui Yu
reviewerRe: [PATCH v2 22/36] irqchip/gic-v4.1: Advertise support v4.1 to KVM
Hi Marc,
Quoted 42 lines · Marc Zyngier
Tell KVM that we support v4.1. Nothing uses this information so far.
Signed-off-by Marc Zyngier <[email protected]>--- drivers/irqchip/irq-gic-v3-its.c | 9 ++++++++- drivers/irqchip/irq-gic-v3.c | 1 + include/linux/irqchip/arm-gic-common.h | 2 ++ 3 files changed, 11 insertions(+), 1 deletion(-)drivers/irqchip/irq-gic-v3-its.c +8
-1@@ -4580,6 +4580,7 @@ int __init its_init(struct fwnode_handle *handle, struct rdists *rdists,struct device_node *of_node;struct its_node *its;bool has_v4 = false; +bool has_v4_1 = false;int err; gic_rdists = rdists;@@ -4600,8 +4601,14 @@ int __init its_init(struct fwnode_handle *handle, struct rdists *rdists,if (err)return err; -list_for_each_entry (its, &its_nodes, entry) +list_for_each_entry (its, &its_nodes, entry) { has_v4 |=is_v4 (its); + has_v4_1 |=is_v4_1 (its); + } + +/* Don't bother with inconsistent systems */ +if (WARN_ON (!has_v4_1 && rdists->has_rvpeid)) + rdists->has_rvpeid = false;if (has_v4 & rdists->has_vlpis) { if (its_init_vpe_domain() ||drivers/irqchip/irq-gic-v3.c +0
-0
drivers/irqchip/irq-gic-v3.c static void __init gic_of_setup_kvm_info(struct device_node *node) · line 1761
Quoted 4 lines
drivers/irqchip/irq-gic-v3.c +1
-0@@ -1758,6 +1758,7 @@ static void __init gic_of_setup_kvm_info(struct device_node *node) gic_v3_kvm_info.vcpu = r; gic_v3_kvm_info.has_v4 = gic_data.rdists.has_vlpis; + gic_v3_kvm_info.has_v4_1 = gic_data.rdists.has_rvpeid;
Also set gic_v3_kvm_info.has_v4_1 in gic_acpi_setup_kvm_info().
Thanks,
Zenghui
Quoted 17 lines
drivers/irqchip/irq-gic-v3.c +0
-0gic_set_kvm_info (&gic_v3_kvm_info); }include/linux/irqchip/arm-gic-common.h +2
-0@@ -32,6 +32,8 @@ struct gic_kvm_info {struct resource vctrl;/* vlpi support */ bool has_v4; +/* rvpeid support */ +bool has_v4_1; };const struct gic_kvm_info *gic_get_kvm_info (void );
Marc Zyngier
maintainerRe: [PATCH v2 22/36] irqchip/gic-v4.1: Advertise support v4.1 to KVM
Quoted 47 lines · Zenghui Yu
Hi Marc,
Quoted 44 lines · Marc Zyngier
Tell KVM that we support v4.1. Nothing uses this information so far.
Signed-off-by Marc Zyngier <[email protected]>--- drivers/irqchip/irq-gic-v3-its.c | 9 ++++++++- drivers/irqchip/irq-gic-v3.c | 1 + include/linux/irqchip/arm-gic-common.h | 2 ++ 3 files changed, 11 insertions(+), 1 deletion(-)drivers/irqchip/irq-gic-v3-its.c +1
-0@@ -4580,6 +4580,7 @@ int __init its_init(struct fwnode_handle *handle, struct rdists *rdists, struct device_node *of_node;struct its_node *its;bool has_v4 = false; +bool has_v4_1 = false;int err;gic_rdists = rdists;drivers/irqchip/irq-gic-v3-its.c +7
-0@@ -4600,8 +4601,14 @@ int __init its_init(struct fwnode_handle *handle, struct rdists *rdists, if (err) return err; - list_for_each_entry(its, &its_nodes, entry) +list_for_each_entry (its, &its_nodes, entry) { has_v4 |=is_v4 (its); + has_v4_1 |=is_v4_1 (its); + } + +/* Don't bother with inconsistent systems */ +if (WARN_ON (!has_v4_1 && rdists->has_rvpeid)) + rdists->has_rvpeid = false;if (has_v4 & rdists->has_vlpis) { if (its_init_vpe_domain() ||drivers/irqchip/irq-gic-v3.c +0
-0@@ -1758,6 +1758,7 @@ static void __init gic_of_setup_kvm_info(struct device_node *node) gic_v3_kvm_info.vcpu = r;
Quoted 4 lines
drivers/irqchip/irq-gic-v3.c static void __init gic_of_setup_kvm_info(struct device_node *node) · line 1761
Quoted 2 lines
drivers/irqchip/irq-gic-v3.c +1
-0gic_v3_kvm_info.has_v4 = gic_data.rdists.has_vlpis; + gic_v3_kvm_info.has_v4_1 = gic_data.rdists.has_rvpeid;Also set gic_v3_kvm_info.has_v4_1 in
gic_acpi_setup_kvm_info().
Indeed. Now fixed.
Thanks,
M.
Signature · 1 line
Jazz is not dead. It just smells funny...
Marc Zyngier
maintainerPATCH v2 23/36 irqchip/gic-v4.1: Map the ITS SGIR register page
In reply to Marc ZyngierOne of the new features of GICv4.1 is to allow virtual SGIs to be directly signaled to a VPE. For that, the ITS has grown a new 64kB page containing only a single register that is used to signal a SGI to a given VPE.
Add a second mapping covering this new 64kB range, and take this opportunity to limit the original mapping to 64kB, which is enough to cover the span of the ITS registers.
--- drivers/irqchip/irq-gic-v3-its.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-)
drivers/irqchip/irq-gic-v3-its.c +13 -2
@@ -97,6 +97,7 @@ struct its_node {struct mutex dev_alloc_lock;struct list_head entry;void __iomem *base; +void __iomem *sgir_base;phys_addr_t phys_base;struct its_cmd_block *cmd_base;struct its_cmd_block *cmd_write;
@@ -4166,7 +4167,7 @@ static int __init its_probe_one(struct resource *res,struct page *page;int err; - its_base =ioremap (res->start,resource_size (res)); + its_base =ioremap (res->start,SZ_64K );if (!its_base) {pr_warn ("ITS@%pa: Unable to map ITS registers\n" , &res->start);return -ENOMEM ;
@@ -4217,6 +4218,13 @@ static int __init its_probe_one(struct resource *res,if (is_v4_1 (its)) {u32 svpet =FIELD_GET (GITS_TYPER_SVPET , typer); + + its->sgir_base =ioremap (res->start +SZ_128K ,SZ_64K ); +if (!its->sgir_base) { + err = -ENOMEM ; + goto out_free_its; + } + its->mpidr =readl_relaxed (its_base +GITS_MPIDR ); pr_info("ITS@%pa: Using GICv4.1 mode %08x %08x\n",
@@ -4230,7 +4238,7 @@ static int __init its_probe_one(struct resource *res, get_order(ITS_CMD_QUEUE_SZ));if (!page) { err = -ENOMEM ; - goto out_free_its; + goto out_unmap_sgir; } its->cmd_base = (void *)page_address (page); its->cmd_write = its->cmd_base;
@@ -4297,6 +4305,9 @@ static int __init its_probe_one(struct resource *res,its_free_tables (its); out_free_cmd:free_pages ((unsigned long )its->cmd_base,get_order (ITS_CMD_QUEUE_SZ )); +out_unmap_sgir: +if (its->sgir_base) +iounmap (its->sgir_base); out_free_its:kfree (its); out_unmap:
Signature · 1 line
2.20.1
Marc Zyngier
maintainerPATCH v2 24/36 irqchip/gic-v4.1: Plumb skeletal VSGI irqchip
In reply to Marc ZyngierSince GICv4.1 has the capability to inject 16 SGIs into each VPE, and that I'm keen not to invent too many specific interfaces to manupulate these interrupts, let's pretend that each of these SGIs is an actual Linux interrupt.
For that matter, let's introduce a minimal irqchip and irqdomain setup that will get fleshed up in the following patches.
--- drivers/irqchip/irq-gic-v3-its.c | 68 +++++++++++++++++++++++++++++- drivers/irqchip/irq-gic-v4.c | 8 +++- include/linux/irqchip/arm-gic-v4.h | 9 +++- 3 files changed, 81 insertions(+), 4 deletions(-)
drivers/irqchip/irq-gic-v3-its.c +67 -1
@@ -3581,6 +3581,67 @@ static struct irq_chip its_vpe_4_1_irq_chip = { .irq_set_vcpu_affinity = its_vpe_4_1_set_vcpu_affinity, }; +static int its_sgi_set_affinity (struct irq_data *d, +const struct cpumask *mask_val, +bool force) +{ +return -EINVAL ; +} + +static struct irq_chip its_sgi_irq_chip = { + .name ="GICv4.1-sgi" , + .irq_set_affinity = its_sgi_set_affinity, +}; + +static int its_sgi_irq_domain_alloc (struct irq_domain *domain, +unsigned int virq,unsigned int nr_irqs, +void *args) +{ +struct its_vpe *vpe = args; +int i; + +/* Yes, we do want 16 SGIs */ +WARN_ON (nr_irqs !=16 ); + +for (i =0 ; i <16 ; i++) { + vpe->sgi_config[i].priority =0 ; + vpe->sgi_config[i].enabled = false; + vpe->sgi_config[i].group = false; + +irq_domain_set_hwirq_and_chip (domain, virq + i, i, + &its_sgi_irq_chip, vpe); +irq_set_status_flags (virq + i,IRQ_DISABLE_UNLAZY ); + } + +return 0 ; +} + +static void its_sgi_irq_domain_free (struct irq_domain *domain, +unsigned int virq, +unsigned int nr_irqs) +{ +/* Nothing to do */ +} + +static int its_sgi_irq_domain_activate (struct irq_domain *domain, +struct irq_data *d,bool reserve) +{ +return 0 ; +} + +static void its_sgi_irq_domain_deactivate (struct irq_domain *domain, +struct irq_data *d) +{ +/* Nothing to do */ +} + +static struct irq_domain_ops its_sgi_domain_ops = { + .alloc = its_sgi_irq_domain_alloc, + .free = its_sgi_irq_domain_free, + .activate = its_sgi_irq_domain_activate, + .deactivate = its_sgi_irq_domain_deactivate, +}; +static int its_vpe_id_alloc (void ) {return ida_simple_get (&its_vpeid_ida,0 ,ITS_MAX_VPEID ,GFP_KERNEL );
@@ -4622,8 +4683,13 @@ int __init its_init(struct fwnode_handle *handle, struct rdists *rdists, rdists->has_rvpeid = false;if (has_v4 & rdists->has_vlpis) { +struct irq_domain_ops *sgi_ops =NULL ; + +if (has_v4_1) + sgi_ops = &its_sgi_domain_ops; +if (its_init_vpe_domain () || -its_init_v4 (parent_domain, &its_vpe_domain_ops)) { +its_init_v4 (parent_domain, &its_vpe_domain_ops, sgi_ops)) { rdists->has_vlpis = false;pr_err ("ITS: Disabling GICv4 support\n" ); }
drivers/irqchip/irq-gic-v4.c +6 -2
@@ -85,6 +85,7 @@static struct irq_domain *gic_domain;static const struct irq_domain_ops *vpe_domain_ops; +static const struct irq_domain_ops *sgi_domain_ops;int its_alloc_vcpu_irqs (struct its_vm *vm) {
@@ -216,12 +217,15 @@ int its_prop_update_vlpi(int irq, u8 config, bool inv)return irq_set_vcpu_affinity (irq, &info); } -int its_init_v4 (struct irq_domain *domain,const struct irq_domain_ops *ops) +int its_init_v4 (struct irq_domain *domain, +const struct irq_domain_ops *vpe_ops, +const struct irq_domain_ops *sgi_ops) {if (domain) {pr_info ("ITS: Enabling GICv4 support\n" ); gic_domain = domain; - vpe_domain_ops = ops; + vpe_domain_ops = vpe_ops; + sgi_domain_ops = sgi_ops;return 0 ; }
include/linux/irqchip/arm-gic-v4.h +8 -1
@@ -47,6 +47,11 @@ struct its_vpe { };/* GICv4.1 implementations */ struct { +struct { +u8 priority; +bool enabled; +bool group; + } sgi_config[16 ];atomic_t vmapp_count; }; };
@@ -116,6 +121,8 @@ int its_unmap_vlpi(int irq);int its_prop_update_vlpi (int irq,u8 config,bool inv);struct irq_domain_ops ; -int its_init_v4 (struct irq_domain *domain,const struct irq_domain_ops *ops); +int its_init_v4 (struct irq_domain *domain, +const struct irq_domain_ops *vpe_ops, +const struct irq_domain_ops *sgi_ops);#endif
Signature · 1 line
2.20.1
Marc Zyngier
maintainerPATCH v2 25/36 irqchip/gic-v4.1: Add initial SGI configuration
In reply to Marc ZyngierThe GICv4.1 ITS has yet another new command (VSGI) which allows a VPE-targeted SGI to be configured (or have its pending state cleared). Add support for this command and plumb it into the activate irqdomain callback so that it is ready to be used.
--- drivers/irqchip/irq-gic-v3-its.c | 88 ++++++++++++++++++++++++++++++ include/linux/irqchip/arm-gic-v3.h | 3 +- 2 files changed, 90 insertions(+), 1 deletion(-)
drivers/irqchip/irq-gic-v3-its.c +88 -0
@@ -329,6 +329,15 @@ struct its_cmd_desc {struct {struct its_vpe *vpe; } its_invdb_cmd; + +struct { +struct its_vpe *vpe; +u8 sgi; +u8 priority; +bool enable; +bool group; +bool clear; + } its_vsgi_cmd; }; };
@@ -474,6 +483,31 @@ static void its_encode_db(struct its_cmd_block *cmd, bool db)its_mask_encode (&cmd->raw_cmd[2 ], db,63 ,63 ); } +static void its_encode_sgi_intid (struct its_cmd_block *cmd,u8 sgi) +{ +its_mask_encode (&cmd->raw_cmd[0 ], sgi,35 ,32 ); +} + +static void its_encode_sgi_priority (struct its_cmd_block *cmd,u8 prio) +{ +its_mask_encode (&cmd->raw_cmd[0 ], prio >>4 ,23 ,20 ); +} + +static void its_encode_sgi_group (struct its_cmd_block *cmd,bool grp) +{ +its_mask_encode (&cmd->raw_cmd[0 ], grp,10 ,10 ); +} + +static void its_encode_sgi_clear (struct its_cmd_block *cmd,bool clr) +{ +its_mask_encode (&cmd->raw_cmd[0 ], clr,9 ,9 ); +} + +static void its_encode_sgi_enable (struct its_cmd_block *cmd,bool en) +{ +its_mask_encode (&cmd->raw_cmd[0 ], en,8 ,8 ); +} +static inline void its_fixup_cmd (struct its_cmd_block *cmd) {/* Let's fixup BE commands */
@@ -785,6 +819,26 @@ static struct its_vpe *its_build_invdb_cmd(struct its_node *its,return valid_vpe (its, desc->its_invdb_cmd.vpe); } +static struct its_vpe *its_build_vsgi_cmd (struct its_node *its, +struct its_cmd_block *cmd, +struct its_cmd_desc *desc) +{ +if (WARN_ON (!is_v4_1 (its))) +return NULL ; + +its_encode_cmd (cmd,GITS_CMD_VSGI ); +its_encode_vpeid (cmd, desc->its_vsgi_cmd.vpe->vpe_id); +its_encode_sgi_intid (cmd, desc->its_vsgi_cmd.sgi); +its_encode_sgi_priority (cmd, desc->its_vsgi_cmd.priority); +its_encode_sgi_group (cmd, desc->its_vsgi_cmd.group); +its_encode_sgi_clear (cmd, desc->its_vsgi_cmd.clear); +its_encode_sgi_enable (cmd, desc->its_vsgi_cmd.enable); + +its_fixup_cmd (cmd); + +return valid_vpe (its, desc->its_vsgi_cmd.vpe); +} +static u64 its_cmd_ptr_to_offset (struct its_node *its,struct its_cmd_block *ptr) {
@@ -3581,6 +3635,38 @@ static struct irq_chip its_vpe_4_1_irq_chip = { .irq_set_vcpu_affinity = its_vpe_4_1_set_vcpu_affinity, }; +static struct its_node *find_4_1_its (void ) +{ +static struct its_node *its =NULL ; + +if (!its) { +list_for_each_entry (its, &its_nodes, entry) { +if (is_v4_1 (its)) +return its; + } + +/* Oops? */ + its =NULL ; + } + +return its; +} + +static void its_configure_sgi (struct irq_data *d,bool clear) +{ +struct its_vpe *vpe =irq_data_get_irq_chip_data (d); +struct its_cmd_desc desc; + + desc.its_vsgi_cmd.vpe = vpe; + desc.its_vsgi_cmd.sgi = d->hwirq; + desc.its_vsgi_cmd.priority = vpe->sgi_config[d->hwirq].priority; + desc.its_vsgi_cmd.enable = vpe->sgi_config[d->hwirq].enabled; + desc.its_vsgi_cmd.group = vpe->sgi_config[d->hwirq].group; + desc.its_vsgi_cmd.clear = clear; + +its_send_single_vcommand (find_4_1_its (), its_build_vsgi_cmd, &desc); +} +static int its_sgi_set_affinity (struct irq_data *d,const struct cpumask *mask_val,bool force)
@@ -3626,6 +3712,8 @@ static void its_sgi_irq_domain_free(struct irq_domain *domain,static int its_sgi_irq_domain_activate (struct irq_domain *domain,struct irq_data *d,bool reserve) { +/* Write out the initial SGI configuration */ +its_configure_sgi (d, false);return 0 ; }
include/linux/irqchip/arm-gic-v3.h +2 -1
@@ -497,8 +497,9 @@#define GITS_CMD_VMAPTI GITS_CMD_GICv4(GITS_CMD_MAPTI)#define GITS_CMD_VMOVI GITS_CMD_GICv4(GITS_CMD_MOVI)#define GITS_CMD_VSYNC GITS_CMD_GICv4(GITS_CMD_SYNC) -/* VMOVP and INVDB are the odd ones, as they dont have a physical counterpart */ +/* VMOVP, VSGI and INVDB are the odd ones, as they dont have a physical counterpart */ #define GITS_CMD_VMOVP GITS_CMD_GICv4(2) +#define GITS_CMD_VSGI GITS_CMD_GICv4(3)#define GITS_CMD_INVDB GITS_CMD_GICv4(0xe)/*
Signature · 1 line
2.20.1
Marc Zyngier
maintainerPATCH v2 26/36 irqchip/gic-v4.1: Plumb mask/unmask SGI callbacks
In reply to Marc ZyngierImplement mask/unmask for virtual SGIs by calling into the configuration helper.
--- drivers/irqchip/irq-gic-v3-its.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+)
drivers/irqchip/irq-gic-v3-its.c +18 -0
@@ -3667,6 +3667,22 @@ static void its_configure_sgi(struct irq_data *d, bool clear)its_send_single_vcommand (find_4_1_its (), its_build_vsgi_cmd, &desc); } +static void its_sgi_mask_irq (struct irq_data *d) +{ +struct its_vpe *vpe =irq_data_get_irq_chip_data (d); + + vpe->sgi_config[d->hwirq].enabled = false; +its_configure_sgi (d, false); +} + +static void its_sgi_unmask_irq (struct irq_data *d) +{ +struct its_vpe *vpe =irq_data_get_irq_chip_data (d); + + vpe->sgi_config[d->hwirq].enabled = true; +its_configure_sgi (d, false); +} +static int its_sgi_set_affinity (struct irq_data *d,const struct cpumask *mask_val,bool force)
@@ -3676,6 +3692,8 @@ static int its_sgi_set_affinity(struct irq_data *d,static struct irq_chip its_sgi_irq_chip = { .name ="GICv4.1-sgi" , + .irq_mask = its_sgi_mask_irq, + .irq_unmask = its_sgi_unmask_irq, .irq_set_affinity = its_sgi_set_affinity, };
Signature · 1 line
2.20.1
Marc Zyngier
maintainerPATCH v2 27/36 irqchip/gic-v4.1: Plumb get/set_irqchip_state SGI callbacks
In reply to Marc ZyngierTo implement the get/set_irqchip_state callbacks (limited to the PENDING state), we have to use a particular set of hacks:
- Reading the pending state is done by using a pair of new redistributor registers (GICR_VSGIR, GICR_VSGIPENDR), which allow the 16 interrupts state to be retrieved.
- Setting the pending state is done by generating it as we'd otherwise do for a guest (writing to GITS_SGIR)
- Clearing the pending state is done by emiting a VSGI command with the "clear" bit set.
--- drivers/irqchip/irq-gic-v3-its.c | 56 ++++++++++++++++++++++++++++++ include/linux/irqchip/arm-gic-v3.h | 14 ++++++++ 2 files changed, 70 insertions(+)
drivers/irqchip/irq-gic-v3-its.c +56 -0
@@ -3690,11 +3690,67 @@ static int its_sgi_set_affinity(struct irq_data *d,return -EINVAL ; } +static int its_sgi_set_irqchip_state (struct irq_data *d, +enum irqchip_irq_state which, +bool state) +{ +if (which !=IRQCHIP_STATE_PENDING ) +return -EINVAL ; + +if (state) { +struct its_vpe *vpe =irq_data_get_irq_chip_data (d); +struct its_node *its =find_4_1_its (); +u64 val; + + val =FIELD_PREP (GITS_SGIR_VPEID , vpe->vpe_id); + val |=FIELD_PREP (GITS_SGIR_VINTID , d->hwirq); +writeq_relaxed (val, its->sgir_base +GITS_SGIR -SZ_128K ); + }else { +its_configure_sgi (d, true); + } + +return 0 ; +} + +static int its_sgi_get_irqchip_state (struct irq_data *d, +enum irqchip_irq_state which,bool *val) +{ +struct its_vpe *vpe =irq_data_get_irq_chip_data (d); +void __iomem *base =gic_data_rdist_cpu (vpe->col_idx)->rd_base +SZ_128K ; +u32 count =1000000 ;/* 1s! */ +u32 status; + +if (which !=IRQCHIP_STATE_PENDING ) +return -EINVAL ; + +writel_relaxed (vpe->vpe_id, base +GICR_VSGIR ); +do { + status =readl_relaxed (base +GICR_VSGIPENDR ); +if (!(status &GICR_VSGIPENDR_BUSY )) + goto out; + + count--; +if (!count) { +pr_err_ratelimited ("Unable to get SGI status\n" ); + goto out; + } +cpu_relax (); +udelay (1 ); + }while (count); + +out: + *val = !!(status & (1 << d->hwirq)); + +return 0 ; +} +static struct irq_chip its_sgi_irq_chip = { .name ="GICv4.1-sgi" , .irq_mask = its_sgi_mask_irq, .irq_unmask = its_sgi_unmask_irq, .irq_set_affinity = its_sgi_set_affinity, + .irq_set_irqchip_state = its_sgi_set_irqchip_state, + .irq_get_irqchip_state = its_sgi_get_irqchip_state, }; static int its_sgi_irq_domain_alloc(struct irq_domain *domain,
include/linux/irqchip/arm-gic-v3.h +14 -0
@@ -340,6 +340,15 @@#define GICR_VPENDBASER_4_1_VGRP1EN (1ULL << 58)#define GICR_VPENDBASER_4_1_VPEID GENMASK_ULL(15, 0) +#define GICR_VSGIR 0x0080 + +#define GICR_VSGIR_VPEID GENMASK(15, 0) + +#define GICR_VSGIPENDR 0x0088 + +#define GICR_VSGIPENDR_BUSY (1U << 31) +#define GICR_VSGIPENDR_PENDING GENMASK(15, 0) +/* * ITS registers, offsets from ITS_base */
@@ -363,6 +372,11 @@#define GITS_TRANSLATER 0x10040 +#define GITS_SGIR 0x20020 + +#define GITS_SGIR_VPEID GENMASK_ULL(47, 32) +#define GITS_SGIR_VINTID GENMASK_ULL(7, 0) +#define GITS_CTLR_ENABLE (1U << 0)#define GITS_CTLR_ImDe (1U << 1)#define GITS_CTLR_ITS_NUMBER_SHIFT 4
Signature · 1 line
2.20.1
Marc Zyngier
maintainerPATCH v2 28/36 irqchip/gic-v4.1: Plumb set_vcpu_affinity SGI callbacks
In reply to Marc ZyngierAs for VLPIs, there is a number of configuration bits that cannot be directly communicated through the normal irqchip API, and we have to use our good old friend set_vcpu_affinity.
This is used to configure group and priority for a given vSGI.
--- drivers/irqchip/irq-gic-v3-its.c | 18 ++++++++++++++++++ include/linux/irqchip/arm-gic-v4.h | 5 +++++ 2 files changed, 23 insertions(+)
drivers/irqchip/irq-gic-v3-its.c +18 -0
@@ -3744,6 +3744,23 @@ static int its_sgi_get_irqchip_state(struct irq_data *d,return 0 ; } +static int its_sgi_set_vcpu_affinity (struct irq_data *d,void *vcpu_info) +{ +struct its_vpe *vpe =irq_data_get_irq_chip_data (d); +struct its_cmd_info *info = vcpu_info; + +switch (info->cmd_type) { +case PROP_UPDATE_SGI : + vpe->sgi_config[d->hwirq].priority = info->priority; + vpe->sgi_config[d->hwirq].group = info->group; +its_configure_sgi (d, false); +return 0 ; + +default : +return -EINVAL ; + } +} +static struct irq_chip its_sgi_irq_chip = { .name ="GICv4.1-sgi" , .irq_mask = its_sgi_mask_irq,
@@ -3751,6 +3768,7 @@ static struct irq_chip its_sgi_irq_chip = { .irq_set_affinity = its_sgi_set_affinity, .irq_set_irqchip_state = its_sgi_set_irqchip_state, .irq_get_irqchip_state = its_sgi_get_irqchip_state, + .irq_set_vcpu_affinity = its_sgi_set_vcpu_affinity, }; static int its_sgi_irq_domain_alloc(struct irq_domain *domain,
include/linux/irqchip/arm-gic-v4.h +5 -0
@@ -96,6 +96,7 @@ enum its_vcpu_info_cmd_type {SCHEDULE_VPE ,DESCHEDULE_VPE ,INVALL_VPE , + PROP_UPDATE_SGI, }; struct its_cmd_info {
@@ -108,6 +109,10 @@ struct its_cmd_info {bool g0en;bool g1en; }; +struct { +u8 priority; +bool group; + }; }; };
Signature · 1 line
2.20.1
Marc Zyngier
maintainerPATCH v2 29/36 irqchip/gic-v4.1: Move doorbell management to the GICv4 abstraction layer
In reply to Marc ZyngierIn order to hide some of the differences between v4.0 and v4.1, move the doorbell management out of the KVM code, and into the GICv4-specific layer. This allows the calling code to ask for the doorbell when blocking, and otherwise to leave the doorbell permanently disabled.
This matches the v4.1 code perfectly, and only results in a minor refactoring of the v4.0 code.
--- drivers/irqchip/irq-gic-v4.c | 49 +++++++++++++++++++++++++++--- include/kvm/arm_vgic.h | 1 + include/linux/irqchip/arm-gic-v4.h | 3 +- virt/kvm/arm/vgic/vgic-v3.c | 1 + virt/kvm/arm/vgic/vgic-v4.c | 34 +++++++++------------ 5 files changed, 63 insertions(+), 25 deletions(-)
drivers/irqchip/irq-gic-v4.c +45 -4
@@ -87,6 +87,11 @@ static struct irq_domain *gic_domain;static const struct irq_domain_ops *vpe_domain_ops;static const struct irq_domain_ops *sgi_domain_ops; +static bool has_v4_1 (void ) +{ +return !!sgi_domain_ops; +} +int its_alloc_vcpu_irqs (struct its_vm *vm) {int vpe_base_irq, i;
@@ -139,18 +144,54 @@ static int its_send_vpe_cmd(struct its_vpe *vpe, struct its_cmd_info *info)return irq_set_vcpu_affinity (vpe->irq, info); } -int its_schedule_vpe (struct its_vpe *vpe,bool on) +int its_make_vpe_non_resident (struct its_vpe *vpe,bool db) { -struct its_cmd_info info; +struct irq_desc *desc =irq_to_desc (vpe->irq); +struct its_cmd_info info = { };int ret;WARN_ON (preemptible ()); - info.cmd_type = on ?SCHEDULE_VPE :DESCHEDULE_VPE ; + info.cmd_type =DESCHEDULE_VPE ; +if (has_v4_1 ()) { +/* GICv4.1 can directly deal with doorbells */ + info.req_db = db; + }else { +/* Undo the nested disable_irq() calls... */ +while (db &&irqd_irq_disabled (&desc->irq_data)) +enable_irq (vpe->irq); + } + + ret =its_send_vpe_cmd (vpe, &info); +if (!ret) + vpe->resident = false; + +return ret; +} + +int its_make_vpe_resident (struct its_vpe *vpe) +{ +struct its_cmd_info info = { }; +int ret; + +WARN_ON (preemptible ()); + + info.cmd_type =SCHEDULE_VPE ; +if (has_v4_1 ()) { +/* +* FIXME: This needs to come from the distributor, and +* not be blindly set out of thin air... +*/ + info.g0en = true; + info.g1en = true; + }else { +/* Disabled the doorbell, as we're about to enter the guest */ +disable_irq_nosync (vpe->irq); + } ret =its_send_vpe_cmd (vpe, &info);if (!ret) - vpe->resident = on; + vpe->resident = true;return ret; }
include/kvm/arm_vgic.h +1 -0
@@ -70,6 +70,7 @@ struct vgic_global {/* Hardware has GICv4? */ bool has_gicv4; +bool has_gicv4_1;/* GIC system register CPU interface */ struct static_key_false gicv3_cpuif;
include/linux/irqchip/arm-gic-v4.h +2 -1
@@ -118,7 +118,8 @@ struct its_cmd_info {int its_alloc_vcpu_irqs (struct its_vm *vm);void its_free_vcpu_irqs (struct its_vm *vm); -int its_schedule_vpe (struct its_vpe *vpe,bool on); +int its_make_vpe_resident (struct its_vpe *vpe); +int its_make_vpe_non_resident (struct its_vpe *vpe,bool db);int its_invall_vpe (struct its_vpe *vpe);int its_map_vlpi (int irq,struct its_vlpi_map *map);int its_get_vlpi (int irq,struct its_vlpi_map *map);
virt/kvm/arm/vgic/vgic-v3.c +1 -0
@@ -595,6 +595,7 @@ int vgic_v3_probe(const struct gic_kvm_info *info)/* GICv4 support? */ if (info->has_v4) { kvm_vgic_global_state.has_gicv4 = gicv4_enable; + kvm_vgic_global_state.has_gicv4_1 = info->has_v4_1;kvm_info ("GICv4 support %sabled\n" , gicv4_enable ?"en" :"dis" ); }
virt/kvm/arm/vgic/vgic-v4.c +14 -20
@@ -67,10 +67,10 @@* it. And if we've migrated our vcpu from one CPU to another, we must * tell the ITS (so that the messages reach the right redistributor). * This is done in two steps: first issue a irq_set_affinity() on the -* irq corresponding to the vcpu, then call its_schedule_vpe(). You -* must be in a non-preemptible context. On exit, another call to -* its_schedule_vpe() tells the redistributor that we're done with the -* vcpu. +* irq corresponding to the vcpu, then call its_make_vpe_resident(). +* You must be in a non-preemptible context. On exit, a call to +* its_make_vpe_non_resident() tells the redistributor that we're done +* with the vcpu. * * Finally, the doorbell handling: Each vcpu is allocated an interrupt * which will fire each time a VLPI is made pending whilst the vcpu is
@@ -86,7 +86,8 @@ static irqreturn_t vgic_v4_doorbell_handler(int irq, void *info)struct kvm_vcpu *vcpu = info;/* We got the message, no need to fire again */ -if (!irqd_irq_disabled (&irq_to_desc (irq)->irq_data)) +if (!kvm_vgic_global_state.has_gicv4_1 && + !irqd_irq_disabled (&irq_to_desc (irq)->irq_data))disable_irq_nosync (irq); vcpu->arch.vgic_cpu.vgic_v3.its_vpe.pending_last = true;
@@ -199,19 +200,11 @@ void vgic_v4_teardown(struct kvm *kvm)int vgic_v4_put (struct kvm_vcpu *vcpu,bool need_db) {struct its_vpe *vpe = &vcpu->arch.vgic_cpu.vgic_v3.its_vpe; -struct irq_desc *desc =irq_to_desc (vpe->irq);if (!vgic_supports_direct_msis (vcpu->kvm) || !vpe->resident)return 0 ; -/* -* If blocking, a doorbell is required. Undo the nested -* disable_irq() calls... -*/ -while (need_db &&irqd_irq_disabled (&desc->irq_data)) -enable_irq (vpe->irq); - -return its_schedule_vpe (vpe, false); +return its_make_vpe_non_resident (vpe, need_db); }int vgic_v4_load (struct kvm_vcpu *vcpu)
@@ -232,18 +225,19 @@ int vgic_v4_load(struct kvm_vcpu *vcpu)if (err)return err; -/* Disabled the doorbell, as we're about to enter the guest */ -disable_irq_nosync (vpe->irq); - - err =its_schedule_vpe (vpe, true); + err =its_make_vpe_resident (vpe);if (err)return err;/* * Now that the VPE is resident, let's get rid of a potential -* doorbell interrupt that would still be pending. +* doorbell interrupt that would still be pending. This is a +* GICv4.0 only "feature"... */ -return irq_set_irqchip_state (vpe->irq,IRQCHIP_STATE_PENDING , false); +if (!kvm_vgic_global_state.has_gicv4_1) + err =irq_set_irqchip_state (vpe->irq,IRQCHIP_STATE_PENDING , false); + +return err; } static struct vgic_its *vgic_get_its(struct kvm *kvm,
Signature · 1 line
2.20.1
Marc Zyngier
maintainerPATCH v2 30/36 irqchip/gic-v4.1: Add VSGI allocation/teardown
In reply to Marc ZyngierAllocate per-VPE SGIs when initializing the GIC-specific part of the VPE data structure.
--- drivers/irqchip/irq-gic-v4.c | 68 +++++++++++++++++++++++++++++- include/linux/irqchip/arm-gic-v4.h | 2 + 2 files changed, 69 insertions(+), 1 deletion(-)
drivers/irqchip/irq-gic-v4.c +67 -1
@@ -92,6 +92,47 @@ static bool has_v4_1(void)return !!sgi_domain_ops; } +static int its_alloc_vcpu_sgis (struct its_vpe *vpe,int idx) +{ +char *name; +int sgi_base; + +if (!has_v4_1 ()) +return 0 ; + + name =kasprintf (GFP_KERNEL ,"GICv4-sgi-%d" ,task_pid_nr (current)); +if (!name) + goto err; + + vpe->fwnode =irq_domain_alloc_named_id_fwnode (name, idx); +if (!vpe->fwnode) + goto err; + +kfree (name); + name =NULL ; + + vpe->sgi_domain =irq_domain_create_linear (vpe->fwnode,16 , + sgi_domain_ops, vpe); +if (!vpe->sgi_domain) + goto err; + + sgi_base =__irq_domain_alloc_irqs (vpe->sgi_domain,-1 ,16 , +NUMA_NO_NODE , vpe, + false,NULL ); +if (sgi_base <=0 ) + goto err; + +return 0 ; + +err: +if (vpe->sgi_domain) +irq_domain_remove (vpe->sgi_domain); +if (vpe->fwnode) +irq_domain_free_fwnode (vpe->fwnode); +kfree (name); +return -ENOMEM ; +} +int its_alloc_vcpu_irqs (struct its_vm *vm) {int vpe_base_irq, i;
@@ -118,8 +159,13 @@ int its_alloc_vcpu_irqs(struct its_vm *vm)if (vpe_base_irq <=0 ) goto err; -for (i =0 ; i < vm->nr_vpes; i++) +for (i =0 ; i < vm->nr_vpes; i++) { +int ret; vm->vpes[i]->irq = vpe_base_irq + i; + ret =its_alloc_vcpu_sgis (vm->vpes[i], i); +if (ret) + goto err; + }return 0 ;
@@ -132,8 +178,28 @@ int its_alloc_vcpu_irqs(struct its_vm *vm)return -ENOMEM ; } +static void its_free_sgi_irqs (struct its_vm *vm) +{ +int i; + +if (!has_v4_1 ()) +return ; + +for (i =0 ; i < vm->nr_vpes; i++) { +unsigned int irq =irq_find_mapping (vm->vpes[i]->sgi_domain,0 ); + +if (WARN_ON (!irq)) +continue ; + +irq_domain_free_irqs (irq,16 ); +irq_domain_remove (vm->vpes[i]->sgi_domain); +irq_domain_free_fwnode (vm->vpes[i]->fwnode); + } +} +void its_free_vcpu_irqs (struct its_vm *vm) { +its_free_sgi_irqs (vm);irq_domain_free_irqs (vm->vpes[0 ]->irq, vm->nr_vpes);irq_domain_remove (vm->domain);irq_domain_free_fwnode (vm->fwnode);
include/linux/irqchip/arm-gic-v4.h +2 -0
@@ -47,6 +47,8 @@ struct its_vpe { };/* GICv4.1 implementations */ struct { +struct fwnode_handle *fwnode; +struct irq_domain *sgi_domain;struct {u8 priority;bool enabled;
Signature · 1 line
2.20.1
Marc Zyngier
maintainerPATCH v2 31/36 irqchip/gic-v4.1: Add VSGI property setup
In reply to Marc ZyngierAdd the SGI configuration entry point for KVM to use.
--- drivers/irqchip/irq-gic-v4.c | 13 +++++++++++++ include/linux/irqchip/arm-gic-v4.h | 1 + 2 files changed, 14 insertions(+)
drivers/irqchip/irq-gic-v4.c +13 -0
@@ -324,6 +324,19 @@ int its_prop_update_vlpi(int irq, u8 config, bool inv)return irq_set_vcpu_affinity (irq, &info); } +int its_prop_update_vsgi (int irq,u8 priority,bool group) +{ +struct its_cmd_info info = { + .cmd_type =PROP_UPDATE_SGI , + { + .priority = priority, + .group = group, + }, + }; + +return irq_set_vcpu_affinity (irq, &info); +} +int its_init_v4 (struct irq_domain *domain,const struct irq_domain_ops *vpe_ops,const struct irq_domain_ops *sgi_ops)
include/linux/irqchip/arm-gic-v4.h +1 -0
@@ -127,6 +127,7 @@ int its_map_vlpi(int irq, struct its_vlpi_map *map);int its_get_vlpi (int irq,struct its_vlpi_map *map);int its_unmap_vlpi (int irq);int its_prop_update_vlpi (int irq,u8 config,bool inv); +int its_prop_update_vsgi (int irq,u8 priority,bool group);struct irq_domain_ops ; int its_init_v4(struct irq_domain *domain,
Signature · 1 line
2.20.1
Marc Zyngier
maintainerPATCH v2 32/36 irqchip/gic-v4.1: Eagerly vmap vPEs
In reply to Marc ZyngierNow that we have HW-accelerated SGIs being delivered to VPEs, it becomes required to map the VPEs on all ITSs instead of relying on the lazy approach that we would use when using the ITS-list mechanism.
--- drivers/irqchip/irq-gic-v3-its.c | 39 +++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 8 deletions(-)
drivers/irqchip/irq-gic-v3-its.c +31 -8
@@ -1419,12 +1419,31 @@ static int its_irq_set_irqchip_state(struct irq_data *d,return 0 ; } +/* +* Two favourable cases: +* +* (a) Either we have a GICv4.1, and all vPEs have to be mapped at all times +* for vSGI delivery +* +* (b) Or the ITSs do not use a list map, meaning that VMOVP is cheap enough +* and we're better off mapping all VPEs always +* +* If neither (a) nor (b) is true, then we map vPEs on demand. +* +*/ +static bool gic_requires_eager_mapping (void ) +{ +if (!its_list_map || gic_rdists->has_rvpeid) +return true; + +return false; +} +static void its_map_vm (struct its_node *its,struct its_vm *vm) {unsigned long flags; -/* Not using the ITS list? Everything is always mapped. */ -if (!its_list_map) +if (gic_requires_eager_mapping ())return ;raw_spin_lock_irqsave (&vmovp_lock, flags);
@@ -1458,7 +1477,7 @@ static void its_unmap_vm(struct its_node *its, struct its_vm *vm)unsigned long flags;/* Not using the ITS list? Everything is always mapped. */ -if (!its_list_map) +if (gic_requires_eager_mapping ())return ;raw_spin_lock_irqsave (&vmovp_lock, flags);
@@ -3964,8 +3983,12 @@ static int its_vpe_irq_domain_activate(struct irq_domain *domain,struct its_vpe *vpe =irq_data_get_irq_chip_data (d);struct its_node *its; -/* If we use the list map, we issue VMAPP on demand... */ -if (its_list_map) +/* +* If we use the list map, we issue VMAPP on demand... Unless +* we're on a GICv4.1 and we eagerly map the VPE on all ITSs +* so that VSGIs can work. +*/ +if (!gic_requires_eager_mapping ())return 0 ;/* Map the VPE to the first possible CPU */
@@ -3991,10 +4014,10 @@ static void its_vpe_irq_domain_deactivate(struct irq_domain *domain,struct its_node *its;/* -* If we use the list map, we unmap the VPE once no VLPIs are -* associated with the VM. +* If we use the list map on GICv4.0, we unmap the VPE once no +* VLPIs are associated with the VM. */ -if (its_list_map) +if (!gic_requires_eager_mapping ())return ;list_for_each_entry (its, &its_nodes, entry) {
Signature · 1 line
2.20.1
Marc Zyngier
maintainerPATCH v2 33/36 KVM: arm64: GICv4.1: Let doorbells be auto-enabled
In reply to Marc ZyngierAs GICv4.1 understands the life cycle of doorbells (instead of just randomly firing them at the most inconvenient time), just enable them at irq_request time, and be done with it.
--- virt/kvm/arm/vgic/vgic-v4.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
virt/kvm/arm/vgic/vgic-v4.c +8 -1
@@ -141,6 +141,7 @@ int vgic_v4_init(struct kvm *kvm)kvm_for_each_vcpu (i, vcpu, kvm) {int irq = dist->its_vm.vpes[i]->irq; +unsigned long irq_flags =DB_IRQ_FLAGS ;/* * Don't automatically enable the doorbell, as we're
@@ -148,8 +149,14 @@ int vgic_v4_init(struct kvm *kvm)* blocked. Also disable the lazy disabling, as the * doorbell could kick us out of the guest too * early... +* +* On GICv4.1, the doorbell is managed in HW and must +* be left enabled. */ -irq_set_status_flags (irq,DB_IRQ_FLAGS ); +if (kvm_vgic_global_state.has_gicv4_1) + irq_flags &= ~IRQ_NOAUTOEN ; +irq_set_status_flags (irq, irq_flags); + ret =request_irq (irq, vgic_v4_doorbell_handler,0 ,"vcpu" , vcpu);if (ret) {
Signature · 1 line
2.20.1
Marc Zyngier
maintainerPATCH v2 34/36 KVM: arm64: GICv4.1: Add direct injection capability to SGI registers
In reply to Marc ZyngierMost of the GICv3 emulation code that deals with SGIs now has to be aware of the v4.1 capabilities in order to benefit from it.
Add such support, keyed on the interrupt having the hw flag set and being a SGI.
--- virt/kvm/arm/vgic/vgic-mmio-v3.c | 15 +++++- virt/kvm/arm/vgic/vgic-mmio.c | 88 ++++++++++++++++++++++++++++++-- 2 files changed, 96 insertions(+), 7 deletions(-)
virt/kvm/arm/vgic/vgic-mmio-v3.c +13 -2
@@ -6,6 +6,7 @@#include <linux/irqchip/arm-gic-v3.h> #include <linux/kvm.h> #include <linux/kvm_host.h> +#include <linux/interrupt.h> #include <kvm/iodev.h> #include <kvm/arm_vgic.h>
@@ -939,8 +940,18 @@ void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg, bool allow_group1)* generate interrupts of either group. */ if (!irq->group || allow_group1) { - irq->pending_latch = true; -vgic_queue_irq_unlock (vcpu->kvm, irq, flags); +if (!irq->hw) { + irq->pending_latch = true; +vgic_queue_irq_unlock (vcpu->kvm, irq, flags); + }else { +/* HW SGI? Ask the GIC to inject it */ +int err; + err =irq_set_irqchip_state (irq->host_irq, +IRQCHIP_STATE_PENDING , + true); +WARN_RATELIMIT (err,"IRQ %d" , irq->host_irq); +raw_spin_unlock_irqrestore (&irq->irq_lock, flags); + } }else {raw_spin_unlock_irqrestore (&irq->irq_lock, flags); }
virt/kvm/arm/vgic/vgic-mmio.c +83 -5
151 lines not on this page · raw message
Signature · 1 line
2.20.1
Marc Zyngier
maintainerPATCH v2 35/36 KVM: arm64: GICv4.1: Configure SGIs as HW interrupts
In reply to Marc ZyngierTo enable HW delivery of SGIs, set their hw flag to true, link them to the corresponding Linux interrupt, which is then activated.
This configures the SGIs at the ITS level, and put the show on the road!
--- virt/kvm/arm/vgic/vgic-v4.c | 42 +++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+)
virt/kvm/arm/vgic/vgic-v4.c +42 -0
@@ -97,6 +97,46 @@ static irqreturn_t vgic_v4_doorbell_handler(int irq, void *info)return IRQ_HANDLED ; } +static void vgic_v4_sync_sgi_config (struct its_vpe *vpe,struct vgic_irq *irq) +{ + vpe->sgi_config[irq->intid].enabled = irq->enabled; + vpe->sgi_config[irq->intid].group = irq->group; + vpe->sgi_config[irq->intid].priority = irq->priority; +} + +static void vgic_v4_init_vsgis (struct kvm_vcpu *vcpu) +{ +struct its_vpe *vpe = &vcpu->arch.vgic_cpu.vgic_v3.its_vpe; +int i; + +if (!kvm_vgic_global_state.has_gicv4_1) +return ; + +/* +* With GICv4.1, every virtual SGI can be directly injected. So +* let's pretend that they are HW interrupts, tied to a host +* IRQ. The SGI code will do its magic. +*/ +for (i =0 ; i <VGIC_NR_SGIS ; i++) { +struct vgic_irq *irq =vgic_get_irq (vcpu->kvm, vcpu, i); +struct irq_desc *desc; +int ret; + + irq->hw = true; + irq->host_irq =irq_find_mapping (vpe->sgi_domain, i); +vgic_v4_sync_sgi_config (vpe, irq); +/* +* SGIs are initialised as disabled. Enable them if +* required by the rest of the VGIC init code. +*/ + desc =irq_to_desc (irq->host_irq); + ret =irq_domain_activate_irq (irq_desc_get_irq_data (desc), + false); +WARN_ON (ret); +vgic_put_irq (vcpu->kvm, irq); + } +} +/** * vgic_v4_init - Initialize the GICv4 data structures * @kvm: Pointer to the VM being initialized
@@ -168,6 +208,8 @@ int vgic_v4_init(struct kvm *kvm) dist->its_vm.nr_vpes = i;break ; } + +vgic_v4_init_vsgis (vcpu); }if (ret)
Signature · 1 line
2.20.1
Marc Zyngier
maintainerPATCH v2 36/36 KVM: arm64: GICv4.1: Expose HW-based SGIs in debugfs
In reply to Marc ZyngierThe vgic-state debugfs file could do with showing the pending state of the HW-backed SGIs. Plug it into the low-level code.
--- virt/kvm/arm/vgic/vgic-debug.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-)
virt/kvm/arm/vgic/vgic-debug.c +13 -1
@@ -178,6 +178,8 @@ static void print_irq_state(struct seq_file *s, struct vgic_irq *irq, struct kvm_vcpu *vcpu) {char *type; +bool pending; +if (irq->intid <VGIC_NR_SGIS ) type ="SGI" ;else if (irq->intid <VGIC_NR_PRIVATE_IRQS )
@@ -190,6 +192,16 @@ static void print_irq_state(struct seq_file *s, struct vgic_irq *irq,if (irq->intid ==0 || irq->intid ==VGIC_NR_PRIVATE_IRQS )print_header (s, irq, vcpu); + pending = irq->pending_latch; +if (irq->hw &&vgic_irq_is_sgi (irq->intid)) { +int err; + + err =irq_get_irqchip_state (irq->host_irq, +IRQCHIP_STATE_PENDING , + &pending); +WARN_ON_ONCE (err); + } +seq_printf (s," %s %4d " " %2d " "%d%d%d%d%d%d%d "
@@ -201,7 +213,7 @@ static void print_irq_state(struct seq_file *s, struct vgic_irq *irq,"\n" , type, irq->intid, (irq->target_vcpu) ? irq->target_vcpu->vcpu_id :-1 , - irq->pending_latch, + pending, irq->line_level, irq->active, irq->enabled,
Signature · 1 line
2.20.1