Multiple MSI on SMP, misrouting or misunderstanding?

John Baldwin jhb at freebsd.org
Mon Jun 8 15:33:59 UTC 2009


On Monday 08 June 2009 5:15:24 am Alexander Motin wrote:
> Hi.
> 
> While experimenting with using multiple MSIs support on AHCI controller 
> I have got the problem. When system boots as UP - everything is fine, 
> driver allocates all available 16 MSIs and works. But when system booted 
> as SMP, interrupts begin to behave strange: I didn't receive expected 
> AHCI IRQs, but instead receive IRQ1 interrupts of atkbd0, while I have 
> no PS/2 keyboard/mouse attached.
> 
> As I have found, problem appears due to IRQ rebalancing between CPUs. As 
> I have got, MSI requires that all vectors from the same group to be 
> allocated sequentially, but IRQ rebalancing breaks correct order, that 
> happed during initial allocation.
> 
> I was quite surprised by this issue. If multiple MSI vectors of the same 
> device have to be allocated sequentially and bound to the same CPU, then 
> they will be unable to give any SMP scalability benefits. Am I right, or 
> there is some special technique expected to be used to somehow 
> distribute grouped MSI vectors between CPUs which we don't have?
> 
> I have made small patch that denies rebalancing for grouped MSIs, to 
> make them work at least somehow. It works fine for me, but I am not sure 
> that it is the best solution.

It is a limitation of MSI.  With MSI, you have a single address register for 
the entire group of messages (the individual messages are just distinguished 
by toggling the lower N bits in the message data register).  On x86 the 
address register includes the APIC ID.  That means that all of the messages 
get sent to the same CPU.  With MSI-X, there is a table with separate address 
and data registers for each message.  This allows a driver to distribute 
interrupts across CPUs.  I had old patches prior to the per-CPU IDT stuff to 
handle this quirk of MSI groups.  The approach I used there was that I would 
only allow reassigning of the entire group by assigning to the first 
interrupt in the group.  With per-CPU IDTs that gets trickier though as you 
need to allocate a whole block of aligned, consecutive IDT vectors in the new 
CPU.

-- 
John Baldwin


More information about the freebsd-current mailing list