Re: [PATCH] Rewrite MSI-HOWTO

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



> 		The MSI Driver Guide HOWTO
> 	Tom L Nguyen tom.l.nguyen@xxxxxxxxx
> 			10/03/2003
> 	Revised Feb 12, 2004 by Martine Silbermann
> 		email: Martine.Silbermann@xxxxxx
> 	Revised Jun 25, 2004 by Tom L Nguyen
> 	Revised Jul  9, 2008 by Matthew Wilcox <willy@xxxxxxxxxxxxxxx>
> 		Copyright 2003, 2008 Intel Corporation
> 
> 1. About this guide
> 
> This guide describes the basics of Message Signaled Interrupts (MSIs),

good (Signaled).  Please be consistent with that spelling...

> the advantages of using MSI over traditional interrupt mechanisms, how
> to change your driver to use MSI or MSI-X and some basic diagnostics to
> try if a device doesn't support MSIs.
> 
> 
> 2. What are MSIs?
> 
> A Message Signalled Interrupt is a write from the device to a special

vs. that one.  Just spell it however the PCI SIG spells it, please.


> address which causes an interrupt to be received by the CPU.
> 
> The MSI capability was first specified in PCI 2.2 and was later enhanced
> in PCI 3.0 to allow each interrupt to be masked individually.  The MSI-X
> capability was also introduced with PCI 3.0.  It supports more interrupts
> per device than MSI and allows interrupts to be independently configured.
> 
> Devices may support both MSI and MSI-X, but only one can be enabled at
> a time.
> 
> 
> 3. Why use MSIs?
> 
...

> 
> 4. How to use MSIs
> 
> PCI devices are initialised to use pin-based interrupts.  The device
> driver has to set up the device to use MSI or MSI-X.  Not all machines
> support MSIs correctly, and for those machines, the APIs described below
> will simply fail and the device will continue to use pin-based interrupts.
> 
> 4.1 Include kernel support for MSIs
> 
> To support MSI or MSI-X, the kernel must be built with the CONFIG_PCI_MSI
> option enabled.  This option is only available on some architectures,
> and it may depend on some other options also being set.  For example,
> on x86, you must also enable X86_UP_APIC or SMP in order to see the
> CONFIG_PCI_MSI option.

in 2.6.27-rc8, it needs both X86_LOCAL_APIC and X86_IO_APIC, but SMP will do that.

> 4.2 Using MSI
> 
> Most of the hard work is done for the driver in the PCI layer.  It simply
> has to request that the PCI layer set up the MSI capability for this
> device.
> 
> 4.2.1 pci_enable_msi
> 
...
> 
> 4.2.2 pci_disable_msi
> 
> void pci_disable_msi(struct pci_dev *dev)
> 
> This function should be used to undo the effect of pci_enable_msi().
> Calling it restores dev->irq to the pin-based interrupt number and frees
> the previously allocated message signaled interrupt(s).  The interrupt
> may subsequently be assigned to another device, so drivers should not
> cache the value of pdev->irq.

s/pdev/dev/

> 
> A device driver must always call free_irq() on the interrupt(s)
> for which it has called request_irq() before calling this function.
> Failure to do so will result in a BUG_ON(), the device will be left with

s/,/;/ to kill run-on sentences.

> MSI enabled and will leak its vector.
> 
> 4.3 Using MSI-X
> 
> The MSI-X capability is much more flexible than the MSI capability.
> It supports up to 2048 interrupts, each of which can be separately
> assigned.  To support this flexibility, drivers must use an array of
> `struct msix_entry':
> 
> struct msix_entry {
> 	u16 	vector; /* kernel uses to write alloc vector */
> 	u16	entry; /* driver uses to specify entry */
> };
> 
> This allows for the device to use these interrupts in a sparse fashion;
> for example it could use interrupts 3 and 1027 and allocate only a
> two-element array.  The driver is expected to fill in the 'entry' value
> in each element of the array to indicate which entries it wants the kernel
> to assign interrupts for.  It is invalid to fill in two entries with the
> same number.

so in this example, the driver would set msix[0].entry = 3 and
msix[1].entry = 1-27  (??)
and then continue with (below...):

> 
> 4.3.1 pci_enable_msix
> 
> int pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries, int nvec)
> 
> Calling this function asks the PCI subsystem to allocate 'nvec' MSIs.
> The 'entries' argument is a pointer to an array of msix_entry structs
> which should be at least 'nvec' entries in size.  On success, the
> function will return 0 and the device will have been switched into
> MSI-X interrupt mode.  The 'vector' elements in each entry will have
> been filled in with the interrupt number.  The driver should then call
> request_irq() for each 'vector' that it decides to use.
> 
> If this function returns a negative number, it indicates an error and
> the driver should not attempt to allocate any more MSI-X interrupts for
> this device.  If it returns a positive number, it indicates the maximum
> number of interrupt vectors that could have been allocated.
> 
> This function, in contrast with pci_enable_msi(), does not adjust
> pdev->irq.  The device will not generate interrupts for this interrupt

s/pdev/dev/  /* or change the parameter name */


> number once MSI-X is enabled.  The device driver is responsible for
> keeping track of the interrupts assigned to the MSI-X vectors so it can
> free them again later.
> 
> Device drivers should normally call this function once per device
> during the initialization phase.

or initialisation ?  (was "initialised" above)

> 
> 4.3.2 pci_disable_msix
> 
> void pci_disable_msix(struct pci_dev *dev)
> 
> This API should be used to undo the effect of pci_enable_msix().  It frees
> the previously allocated message signaled interrupts.  The interrupts may

Good here ;)

> subsequently be assigned to another device, so drivers should not cache
> the value of the 'vector' elements over a call to pci_disable_msix().
> 
> A device driver must always call free_irq() on the interrupt(s)
> for which it has called request_irq() before calling this function.
> Failure to do so will result in a BUG_ON(), the device will be left with

s/,/;/ to avoid run-on sentences.

> MSI enabled and will leak its vector.
> 
> 4.3.3 The MSI-X Table
> 
> The MSI-X capability specifies a BAR and offset within that BAR for the
> MSI-X Table.  This address is mapped by the PCI subsystem, and should not
> be accessed directly by the device driver.  If the driver wishes to
> mask or unmask an interrupt, it should call disable_irq() / enable_irq().
> 
> 4.4 Handling devices implementing both MSI and MSI-X capabilities
> 
...
> 
> 4.5 Considerations when using MSIs
> 
> 4.5.1 Choosing between MSI-X and MSI
> 
> If your device supports both MSI-X and MSI capabilities, you should use
> the MSI-X facilities in preference to the MSI facilities.  As mentioned
> above, MSI-X supports any number of interrupts between 1 and 2048.
> In constrast, MSI is restricted to a maximum of 32 interrupts (and
> must be a power of two).  In addition, the MSI interrupt vectors must
> be allocated consecutively, so the system may not be able to allocate
> as many vectors for MSI as it could for MSI-X.  On some platforms, MSI
> interrupts must all be targetted at the same set of CPUs whereas MSI-X
> interrupts can all be targetted at different CPUs.

Yes, I would spell it "targeted", but you are writing it, so it's OK.

> 
> 4.5.2 Spinlocks
> 
...
> 
> 4.6 How to tell whether MSI/MSI-X is enabled on a device
> 
> Using lspci -v (as root) will show some devices with "Message Signalled

Is that how 'lspci' spells it?  Ugh, it is.  oh well.

> Interrupts" and others with "MSI-X".  Each of these capabilities have an
> 'Enable' flag which will be followed with either "+" (enabled) or "-"
> (disabled).
> 
> 
> 5. MSI quirks
> 
> Several PCI chipsets or devices are known not to support MSIs.
> The PCI stack provides three ways to disable MSIs:
> 
> 1. globally
> 2. on all devices behind a specific bridge
> 3. on a single device
> 
> 5.1. Disabling MSIs globally
> 
...
> 
> 5.2. Disabling MSIs below a bridge
> 
> Some PCI bridges are not able to route MSIs between busses properly.
> In this case, MSIs must be disabled on all devices behind the bridge.
> 
> Some bridges allow you to enable MSIs by changing some bits in their
> PCI configuration space (especially the Hypertransport chipsets such
> as the nVidia nForce and Serverworks HT2000).  As with host chipsets,
> Linux mostly knows about them and automatically enables MSIs if it can.
> If you have a bridge which Linux doesn't yet know about, you can enable
> MSIs in configuration space using whatever method you know works, then
> enable MSIs on that bridge by doing:
> 
>        echo 1 > /sys/bus/pci/devices/$bridge/msi_bus
> 
> where $bridge is the PCI address of the bridge you've enabled (eg

preferred:  e.g.

> 0000:00:0e.0).
> 
> To disable MSIs, echo 0 instead of 1.  Changing this value should be
> done with caution as it can break interrupt handling for all devices
> below this bridge.
> 
> Again, please notify linux-pci@xxxxxxxxxxxxxxx of any bridges that need
> special handling.
> 
> 5.3. Disabling MSIs on a single device
> 
> Some devices are known to have faulty MSI implementations.  Usually this
> is handled in the individual device driver but occasionally it's necessary
> to handle this with a quirk.  Some drivers have an option to disable MSIs;
> this is deprecated.
> 
> 5.4. Finding why MSIs are disabled on a device
> 
...


---
~Randy
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [DMA Engine]     [Linux Coverity]     [Linux USB]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Greybus]

  Powered by Linux