On Wed, Oct 25, 2023 at 9:35 PM Björn Töpel <bjorn@xxxxxxxxxx> wrote: > > Hi! > > Anup Patel <apatel@xxxxxxxxxxxxxxxx> writes: > > > On Tue, Oct 24, 2023 at 6:35 PM Björn Töpel <bjorn@xxxxxxxxxx> wrote: > >> > >> Hi Anup! > >> > >> Wow, I'm really happy to see that you're moving towards the 1-1 model! > >> > >> Anup Patel <apatel@xxxxxxxxxxxxxxxx> writes: > >> > >> > The RISC-V advanced interrupt architecture (AIA) specification > >> > defines a new MSI controller called incoming message signalled > >> > interrupt controller (IMSIC) which manages MSI on per-HART (or > >> > per-CPU) basis. It also supports IPIs as software injected MSIs. > >> > (For more details refer https://github.com/riscv/riscv-aia) > >> > > >> > Let us add an early irqchip driver for RISC-V IMSIC which sets > >> > up the IMSIC state and provide IPIs. > >> > >> It would help (reviewers, and future bugfixers) if you add (here or in > >> the cover) what design decisions you've taken instead of just saying > >> that you're now supporting IMSIC. > > > > I agree with the suggestion but this kind of information should be > > in the source itself rather than commit description. > > I think the high-level flow, and why you made certain design decisions > should be in the commit message. > > The "how" in the code, the "why" in the commit message. Regardless -- it > would make it easier for reviewers to get into your code faster. > > [...] > > >> > + > >> > + writel(IMSIC_IPI_ID, local->msi_va); > >> > >> Do you need the barriers here? If so, please document. If not, use the > >> _releaxed() version. > > > > We can't assume that _relaxed version of MMIO operations > > will work for RISC-V implementation so we conservatively > > use regular MMIO operations without _releaxed(). > > You'll need to expand on your thinking here, Anup. We can't just > sprinkle fences everywhere because of "we can't assume it'll work". Do > you need proper barriers for IPIs or not? For IPIs, we use generic IPI-mux which has its own barriers. We certainly need matching read and write barrier for the data being passed for synchronization. > > [...] > > >> > + mvec = lpriv->ids_move[i]; > >> > + lpriv->ids_move[i] = NULL; > >> > + if (mvec) { > >> > + if (__imsic_id_read_clear_pending(i)) { > >> > + mlocal = per_cpu_ptr(imsic->global.local, > >> > + mvec->cpu); > >> > + writel(mvec->local_id, mlocal->msi_va); > >> > >> Again, do you need all the barriers? If yes, document. No, then relax > >> the call. > > > > Same comment as above. > > Dito for me! ;-) > > >> > + } > >> > + > >> > + lpriv->vectors[i].hwirq = UINT_MAX; > >> > + lpriv->vectors[i].order = UINT_MAX; > >> > + clear_bit(i, lpriv->ids_used_bitmap); > >> > + } > >> > + > >> > + } > >> > + raw_spin_unlock_irqrestore(&lpriv->ids_lock, flags); > >> > +} > >> > + > >> > +void imsic_local_delivery(bool enable) > >> > +{ > >> > + if (enable) { > >> > + imsic_csr_write(IMSIC_EITHRESHOLD, IMSIC_ENABLE_EITHRESHOLD); > >> > + imsic_csr_write(IMSIC_EIDELIVERY, IMSIC_ENABLE_EIDELIVERY); > >> > + } else { > >> > + imsic_csr_write(IMSIC_EIDELIVERY, IMSIC_DISABLE_EIDELIVERY); > >> > + imsic_csr_write(IMSIC_EITHRESHOLD, IMSIC_DISABLE_EITHRESHOLD); > >> > + } > >> > >> My regular "early exit" nit. I guess I really dislike indentation. ;-) > > > > -ENOPARSE > > if (...) { > a(); > b(); > c(); > } else { > d(); > e(); > } > > vs > > if (...) { > a(); > b(); > c(); > return; > } > > d(); > e(); > > [...] > > >> > +void imsic_vector_mask(struct imsic_vector *vec) > >> > +{ > >> > + struct imsic_local_priv *lpriv; > >> > + unsigned long flags; > >> > + > >> > + lpriv = per_cpu_ptr(imsic->lpriv, vec->cpu); > >> > + if (WARN_ON(&lpriv->vectors[vec->local_id] != vec)) > >> > + return; > >> > + > >> > + raw_spin_lock_irqsave(&lpriv->ids_lock, flags); > >> > + bitmap_clear(lpriv->ids_enabled_bitmap, vec->local_id, 1); > >> > + raw_spin_unlock_irqrestore(&lpriv->ids_lock, flags); > >> > + > >> > + imsic_remote_sync(vec->cpu); > >> > >> x86 seems to set a timer instead, for the remote cpu cleanup, which can > >> be much cheaper, and less in instrusive. Is that applicable here? > > > > The issue with that approach is deciding the right duration > > of timer interrupt. There might be platforms who need > > immediate mask/unmask response. We can certainely > > keep improving/tuning this over-time. > > Any concrete examples where this is an actual problem? Do you have a concrete timer duration with proper justification ? > > [...] > > >> > +void imsic_vector_move(struct imsic_vector *old_vec, > >> > + struct imsic_vector *new_vec) > >> > +{ > >> > + struct imsic_local_priv *old_lpriv, *new_lpriv; > >> > + struct imsic_vector *ovec, *nvec; > >> > + unsigned long flags, flags1; > >> > + unsigned int i; > >> > + > >> > + if (WARN_ON(old_vec->cpu == new_vec->cpu || > >> > + old_vec->order != new_vec->order || > >> > + (old_vec->local_id & IMSIC_VECTOR_MASK(old_vec)) || > >> > + (new_vec->local_id & IMSIC_VECTOR_MASK(new_vec)))) > >> > + return; > >> > + > >> > + old_lpriv = per_cpu_ptr(imsic->lpriv, old_vec->cpu); > >> > + if (WARN_ON(&old_lpriv->vectors[old_vec->local_id] != old_vec)) > >> > + return; > >> > + > >> > + new_lpriv = per_cpu_ptr(imsic->lpriv, new_vec->cpu); > >> > + if (WARN_ON(&new_lpriv->vectors[new_vec->local_id] != new_vec)) > >> > + return; > >> > + > >> > + raw_spin_lock_irqsave(&old_lpriv->ids_lock, flags); > >> > + raw_spin_lock_irqsave(&new_lpriv->ids_lock, flags1); > >> > + > >> > + /* Move the state of each vector entry */ > >> > + for (i = 0; i < BIT(old_vec->order); i++) { > >> > + ovec = old_vec + i; > >> > + nvec = new_vec + i; > >> > + > >> > + /* Unmask the new vector entry */ > >> > + if (test_bit(ovec->local_id, old_lpriv->ids_enabled_bitmap)) > >> > + bitmap_set(new_lpriv->ids_enabled_bitmap, > >> > + nvec->local_id, 1); > >> > + > >> > + /* Mask the old vector entry */ > >> > + bitmap_clear(old_lpriv->ids_enabled_bitmap, ovec->local_id, 1); > >> > + > >> > + /* > >> > + * Move and re-trigger the new vector entry based on the > >> > + * pending state of the old vector entry because we might > >> > + * get a device interrupt on the old vector entry while > >> > + * device was being moved to the new vector entry. > >> > + */ > >> > + old_lpriv->ids_move[ovec->local_id] = nvec; > >> > + } > >> > >> Hmm, nested spinlocks, and reimplementing what the irq matrix allocator > >> does. > >> > >> Convince me why irq matrix is not a good fit to track the interrupts IDs > >> *and* get handling/tracking for managed/unmanaged interrupts. You said > >> that it was the power-of-two blocks for MSI, but can't that be enfored > >> on matrix alloc? Where are you doing the special handling of MSI? > >> > >> The reason I'm asking is because I'm pretty certain that x86 has proper > >> MSI support (Thomas Gleixner can answer for sure! ;-)) > >> > >> IMSIC smells a lot like the the LAPIC. The implementation could probably > >> be *very* close to what arch/x86/kernel/apic/vector.c does. > >> > >> Am I completly off here? > >> > > > > The x86 APIC driver only supports MSI-X due to which the IRQ matrix > > allocator only supports ID/Vector allocation suitable for MSI-X whereas > > the ARM GICv3 driver supports both legacy MSI and MSI-X. In absence > > of legacy MSI support, Linux x86 will fallback to INTx for PCI devices > > with legacy MSI support but for RISC-V platforms we can't assume that > > INTx is available because we might be dealing with an IMSIC-only > > platform. > > You're mixing up MSI and *multi-MSI* (multiple MSI vectors). So now you are doubting my understanding of MSI ? > > x86 support MSI-X, MSI, and multi-MSI with IOMMU. > > Gleixner has a some insights on why one probably should *not* jump > through hoops to support multi-MSI: > https://lore.kernel.org/all/877d7yhve7.ffs@tglx/ This is a fair justification to drop why x86 does not support the legacy-MSI or "multi-MSI". > > Will we really see HW requiring multi-MSI support on RISC-V systems > without IOMMU? To me this sounds like a theoretical exercise. > > > Refer, x86_vector_msi_parent_ops in arch/x86/kernel/apic/msi.c and > > X86_VECTOR_MSI_FLAGS_SUPPORTED in arch/x86/include/asm/msi.h > > > > Refer, its_pci_msi_domain_info in drivers/irqchip/irq-gic-v3-its-pci-msi.c > > > > The changes which I think are need in the IRQ matrix allocator before > > integrating it in the IMSIC driver are the following: > > 1) IRQ matrix allocator assumed NR_VECTORS to be a fixed define > > which the arch code provides but in RISC-V world the number of > > IDs are discovered from DT or ACPI. > > Ok, let's try to be bit more explicit. Have you had a look at > kernel/irq/matrix.c? Why do you doubt it ? > > You need to define the IRQ_MATRIX_BITS (which x86 sets to NR_VECTORS). > This is the size of the bitmap. For IMSIC this would be 2047. Wow, let's just create large bitmaps even when underlying HW has fewer per-CPU IDs !!! > > The matrix allocator is an excellent fit, modulo multi-MSI. It's battle > proven code. > > > 2) IRQ matrix allocator needs to be support allocator multiple vectors > > in power-of-2 which will allow IMSIC driver to support both legacy > > MSI and MSI-X. This will involve changing the way best CPU is > > found, the way bitmap APIs are used and adding some new APIs > > for allocate vectors in power-of-2 > > ...and all the other things multi-MSI requires. > > > Based on above, I suggest we keep the integration of IRQ matrix > > allocator in the IMSIC driver as a separate series which will allow > > us to unblock other series (such as AIA ACPI support, power > > managment related changes in AIA drivers, etc). > > I suggest removing the multi-MSI support, and use the matrix allocator. > We have something that looks like what x86 has (IMSIC). We have a > battle-proven implementation, and helper function. In my view it would > be just weird not to piggy-back on that work, and benefit from years of > bugfixes/things we haven't thought of. > > Finally; I don't see that you're handling managed interrupt in the > series (Oh, the matrix allocator has support for that! ;-)). We don't need managed interrupts like x86 does. We are using IPI-mux to create multiple virtual IPIs on-top-of single ID and we use some of these virtual IPIs for internal managment. > > I realize it's some changes, but the interrupt handling is a central > piece. > > If you agree with my input, LMK if you're time/work-constrained, and I > can take a stab at integrating it in the series. > > > Björn Regards, Anup