mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 12:28:41 +08:00
PCI updates for v3.14:
MSI - Fix AHCI single-MSI fallback (Alexander Gordeev) - Fix populate_msi_sysfs() error paths (Greg Kroah-Hartman) - Fix htmldocs problem (Masanari Iida) - Add pci_enable_msi_exact() and pci_enable_msix_exact() (Alexander Gordeev) - Update documentation (Alexander Gordeev) Miscellaneous - mvebu: expose device ID & revision via lspci (Andrew Lunn) - Enable INTx if the BIOS left them disabled (Bjorn Helgaas) -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABAgAGBQJTBkj5AAoJEFmIoMA60/r8aiAQAIWQnZ7UhXBqMAXDR8nJuTbk b2l4EpNtrGPKy27ZogwDV7ACE7BcBc8vQWhsuMbaxyYTUh4Amr19CysjyBqmoLe9 4eMuGlItkXCbtEw8wquiSz8rtUHH90yTwXk3XMQ0SkscMuAp+QSUb48a3uBSPMX/ gf29IeV8CJjqfLnvtCYkp9jgVuph9vpw+g+DTaLPGA23KS8QJKvmJ95R15fhfcGZ B4fbJG8TT8LLLD4LDeZOSqbz2n4rE8Xaif1locLAkQtPhiSe65vZYP5IFwlH/t4T Rzqtkuy2pbybfMk2JVDXzXQgIbCH0h3fEYRZM7ydhU3dndb1E8oUAYf1CbG1GoLv 36feVn7YWs3VQhs+IpoqJivtgmQKOmFgtGByPOgP47SWXssmyBz2DZCap6WPVGGb KCJNshSGtpNA3ge34jj8Y5wKN2Y+jGoBvLPObJd80Rwwmx00Nn33jn4dYX9JkPlB kq4I9+y8CmMuADB+St3kHklAw0qFeK7pj2iMRnpfdEbau4el16ch8S9rEBltOj/2 wMejSViUH1RsdpJMMHads3pR+oAjFxxc8x1fnp4roIr2SkvZhCmcZwM6GJJhMJpi RM/B4RnK4dMuE6vGX5jsDQFy7xKoE6Wfop/cXK6HbifX+kiZo90PD8vbNthFJ/Wy 2B0AN2cvL5dCKvoX2gqJ =CTv7 -----END PGP SIGNATURE----- Merge tag 'pci-v3.14-fixes-1' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci Pull PCI updates from Bjorn Helgaas: "The most interesting thing here is the change to enable INTx (by clearing PCI_COMMAND_INTX_DISABLE) if the BIOS left INTx disabled. Apparently the Baytrail BIOS does this, which means EHCI doesn't work. Also, fix an AHCI MSI regression and other issues with the recent MSI changes. This also adds pci_enable_msi_exact() and pci_enable_msix_exact(), which aren't regression fixes, but will keep us from touching drivers twice (once to stop using the deprecated pci_enable_msi(), etc., and again to use the *_exact() variants). There's also a minor MVEBU fix. Summary: MSI: - Fix AHCI single-MSI fallback (Alexander Gordeev) - Fix populate_msi_sysfs() error paths (Greg Kroah-Hartman) - Fix htmldocs problem (Masanari Iida) - Add pci_enable_msi_exact() and pci_enable_msix_exact() (Alexander Gordeev) - Update documentation (Alexander Gordeev) Miscellaneous: - mvebu: expose device ID & revision via lspci (Andrew Lunn) - Enable INTx if the BIOS left them disabled (Bjorn Helgaas)" * tag 'pci-v3.14-fixes-1' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci: ahci: Fix broken fallback to single MSI mode PCI: Enable INTx if BIOS left them disabled PCI/MSI: Add pci_enable_msi_exact() and pci_enable_msix_exact() PCI/MSI: Fix cut-and-paste errors in documentation PCI/MSI: Add pci_enable_msi() documentation back PCI/MSI: Fix pci_msix_vec_count() htmldocs failure PCI/MSI: Fix leak of msi_attrs PCI/MSI: Check kmalloc() return value, fix leak of name PCI: mvebu: Use Device ID and revision from underlying endpoint
This commit is contained in:
commit
d158fc7f36
@ -82,7 +82,19 @@ 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_range
|
||||
4.2.1 pci_enable_msi
|
||||
|
||||
int pci_enable_msi(struct pci_dev *dev)
|
||||
|
||||
A successful call allocates ONE interrupt to the device, regardless
|
||||
of how many MSIs the device supports. The device is switched from
|
||||
pin-based interrupt mode to MSI mode. The dev->irq number is changed
|
||||
to a new number which represents the message signaled interrupt;
|
||||
consequently, this function should be called before the driver calls
|
||||
request_irq(), because an MSI is delivered via a vector that is
|
||||
different from the vector of a pin-based interrupt.
|
||||
|
||||
4.2.2 pci_enable_msi_range
|
||||
|
||||
int pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec)
|
||||
|
||||
@ -147,6 +159,11 @@ static int foo_driver_enable_msi(struct pci_dev *pdev, int nvec)
|
||||
return pci_enable_msi_range(pdev, nvec, nvec);
|
||||
}
|
||||
|
||||
Note, unlike pci_enable_msi_exact() function, which could be also used to
|
||||
enable a particular number of MSI-X interrupts, pci_enable_msi_range()
|
||||
returns either a negative errno or 'nvec' (not negative errno or 0 - as
|
||||
pci_enable_msi_exact() does).
|
||||
|
||||
4.2.1.3 Single MSI mode
|
||||
|
||||
The most notorious example of the request type described above is
|
||||
@ -158,7 +175,27 @@ static int foo_driver_enable_single_msi(struct pci_dev *pdev)
|
||||
return pci_enable_msi_range(pdev, 1, 1);
|
||||
}
|
||||
|
||||
4.2.2 pci_disable_msi
|
||||
Note, unlike pci_enable_msi() function, which could be also used to
|
||||
enable the single MSI mode, pci_enable_msi_range() returns either a
|
||||
negative errno or 1 (not negative errno or 0 - as pci_enable_msi()
|
||||
does).
|
||||
|
||||
4.2.3 pci_enable_msi_exact
|
||||
|
||||
int pci_enable_msi_exact(struct pci_dev *dev, int nvec)
|
||||
|
||||
This variation on pci_enable_msi_range() call allows a device driver to
|
||||
request exactly 'nvec' MSIs.
|
||||
|
||||
If this function returns a negative number, it indicates an error and
|
||||
the driver should not attempt to request any more MSI interrupts for
|
||||
this device.
|
||||
|
||||
By contrast with pci_enable_msi_range() function, pci_enable_msi_exact()
|
||||
returns zero in case of success, which indicates MSI interrupts have been
|
||||
successfully allocated.
|
||||
|
||||
4.2.4 pci_disable_msi
|
||||
|
||||
void pci_disable_msi(struct pci_dev *dev)
|
||||
|
||||
@ -172,7 +209,7 @@ on any interrupt for which it previously called request_irq().
|
||||
Failure to do so results in a BUG_ON(), leaving the device with
|
||||
MSI enabled and thus leaking its vector.
|
||||
|
||||
4.2.3 pci_msi_vec_count
|
||||
4.2.4 pci_msi_vec_count
|
||||
|
||||
int pci_msi_vec_count(struct pci_dev *dev)
|
||||
|
||||
@ -257,8 +294,8 @@ possible, likely up to the limit returned by pci_msix_vec_count() function:
|
||||
|
||||
static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec)
|
||||
{
|
||||
return pci_enable_msi_range(adapter->pdev, adapter->msix_entries,
|
||||
1, nvec);
|
||||
return pci_enable_msix_range(adapter->pdev, adapter->msix_entries,
|
||||
1, nvec);
|
||||
}
|
||||
|
||||
Note the value of 'minvec' parameter is 1. As 'minvec' is inclusive,
|
||||
@ -269,8 +306,8 @@ In this case the function could look like this:
|
||||
|
||||
static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec)
|
||||
{
|
||||
return pci_enable_msi_range(adapter->pdev, adapter->msix_entries,
|
||||
FOO_DRIVER_MINIMUM_NVEC, nvec);
|
||||
return pci_enable_msix_range(adapter->pdev, adapter->msix_entries,
|
||||
FOO_DRIVER_MINIMUM_NVEC, nvec);
|
||||
}
|
||||
|
||||
4.3.1.2 Exact number of MSI-X interrupts
|
||||
@ -282,10 +319,15 @@ parameters:
|
||||
|
||||
static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec)
|
||||
{
|
||||
return pci_enable_msi_range(adapter->pdev, adapter->msix_entries,
|
||||
nvec, nvec);
|
||||
return pci_enable_msix_range(adapter->pdev, adapter->msix_entries,
|
||||
nvec, nvec);
|
||||
}
|
||||
|
||||
Note, unlike pci_enable_msix_exact() function, which could be also used to
|
||||
enable a particular number of MSI-X interrupts, pci_enable_msix_range()
|
||||
returns either a negative errno or 'nvec' (not negative errno or 0 - as
|
||||
pci_enable_msix_exact() does).
|
||||
|
||||
4.3.1.3 Specific requirements to the number of MSI-X interrupts
|
||||
|
||||
As noted above, there could be devices that can not operate with just any
|
||||
@ -332,7 +374,64 @@ Note how pci_enable_msix_range() return value is analized for a fallback -
|
||||
any error code other than -ENOSPC indicates a fatal error and should not
|
||||
be retried.
|
||||
|
||||
4.3.2 pci_disable_msix
|
||||
4.3.2 pci_enable_msix_exact
|
||||
|
||||
int pci_enable_msix_exact(struct pci_dev *dev,
|
||||
struct msix_entry *entries, int nvec)
|
||||
|
||||
This variation on pci_enable_msix_range() call allows a device driver to
|
||||
request exactly 'nvec' MSI-Xs.
|
||||
|
||||
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.
|
||||
|
||||
By contrast with pci_enable_msix_range() function, pci_enable_msix_exact()
|
||||
returns zero in case of success, which indicates MSI-X interrupts have been
|
||||
successfully allocated.
|
||||
|
||||
Another version of a routine that enables MSI-X mode for a device with
|
||||
specific requirements described in chapter 4.3.1.3 might look like this:
|
||||
|
||||
/*
|
||||
* Assume 'minvec' and 'maxvec' are non-zero
|
||||
*/
|
||||
static int foo_driver_enable_msix(struct foo_adapter *adapter,
|
||||
int minvec, int maxvec)
|
||||
{
|
||||
int rc;
|
||||
|
||||
minvec = roundup_pow_of_two(minvec);
|
||||
maxvec = rounddown_pow_of_two(maxvec);
|
||||
|
||||
if (minvec > maxvec)
|
||||
return -ERANGE;
|
||||
|
||||
retry:
|
||||
rc = pci_enable_msix_exact(adapter->pdev,
|
||||
adapter->msix_entries, maxvec);
|
||||
|
||||
/*
|
||||
* -ENOSPC is the only error code allowed to be analyzed
|
||||
*/
|
||||
if (rc == -ENOSPC) {
|
||||
if (maxvec == 1)
|
||||
return -ENOSPC;
|
||||
|
||||
maxvec /= 2;
|
||||
|
||||
if (minvec > maxvec)
|
||||
return -ENOSPC;
|
||||
|
||||
goto retry;
|
||||
} else if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
return maxvec;
|
||||
}
|
||||
|
||||
4.3.3 pci_disable_msix
|
||||
|
||||
void pci_disable_msix(struct pci_dev *dev)
|
||||
|
||||
|
@ -1184,8 +1184,10 @@ static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports,
|
||||
|
||||
nvec = rc;
|
||||
rc = pci_enable_msi_block(pdev, nvec);
|
||||
if (rc)
|
||||
if (rc < 0)
|
||||
goto intx;
|
||||
else if (rc > 0)
|
||||
goto single_msi;
|
||||
|
||||
return nvec;
|
||||
|
||||
|
@ -60,14 +60,6 @@
|
||||
#define PCIE_DEBUG_CTRL 0x1a60
|
||||
#define PCIE_DEBUG_SOFT_RESET BIT(20)
|
||||
|
||||
/*
|
||||
* This product ID is registered by Marvell, and used when the Marvell
|
||||
* SoC is not the root complex, but an endpoint on the PCIe bus. It is
|
||||
* therefore safe to re-use this PCI ID for our emulated PCI-to-PCI
|
||||
* bridge.
|
||||
*/
|
||||
#define MARVELL_EMULATED_PCI_PCI_BRIDGE_ID 0x7846
|
||||
|
||||
/* PCI configuration space of a PCI-to-PCI bridge */
|
||||
struct mvebu_sw_pci_bridge {
|
||||
u16 vendor;
|
||||
@ -388,7 +380,8 @@ static void mvebu_sw_pci_bridge_init(struct mvebu_pcie_port *port)
|
||||
|
||||
bridge->class = PCI_CLASS_BRIDGE_PCI;
|
||||
bridge->vendor = PCI_VENDOR_ID_MARVELL;
|
||||
bridge->device = MARVELL_EMULATED_PCI_PCI_BRIDGE_ID;
|
||||
bridge->device = mvebu_readl(port, PCIE_DEV_ID_OFF) >> 16;
|
||||
bridge->revision = mvebu_readl(port, PCIE_DEV_REV_OFF) & 0xff;
|
||||
bridge->header_type = PCI_HEADER_TYPE_BRIDGE;
|
||||
bridge->cache_line_size = 0x10;
|
||||
|
||||
|
@ -545,9 +545,15 @@ static int populate_msi_sysfs(struct pci_dev *pdev)
|
||||
return -ENOMEM;
|
||||
list_for_each_entry(entry, &pdev->msi_list, list) {
|
||||
char *name = kmalloc(20, GFP_KERNEL);
|
||||
msi_dev_attr = kzalloc(sizeof(*msi_dev_attr), GFP_KERNEL);
|
||||
if (!msi_dev_attr)
|
||||
if (!name)
|
||||
goto error_attrs;
|
||||
|
||||
msi_dev_attr = kzalloc(sizeof(*msi_dev_attr), GFP_KERNEL);
|
||||
if (!msi_dev_attr) {
|
||||
kfree(name);
|
||||
goto error_attrs;
|
||||
}
|
||||
|
||||
sprintf(name, "%d", entry->irq);
|
||||
sysfs_attr_init(&msi_dev_attr->attr);
|
||||
msi_dev_attr->attr.name = name;
|
||||
@ -589,6 +595,7 @@ error_attrs:
|
||||
++count;
|
||||
msi_attr = msi_attrs[count];
|
||||
}
|
||||
kfree(msi_attrs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -959,7 +966,6 @@ EXPORT_SYMBOL(pci_disable_msi);
|
||||
/**
|
||||
* pci_msix_vec_count - return the number of device's MSI-X table entries
|
||||
* @dev: pointer to the pci_dev data structure of MSI-X device function
|
||||
|
||||
* This function returns the number of device's MSI-X table entries and
|
||||
* therefore the number of MSI-X vectors device is capable of sending.
|
||||
* It returns a negative errno if the device is not capable of sending MSI-X
|
||||
|
@ -1181,6 +1181,8 @@ EXPORT_SYMBOL_GPL(pci_load_and_free_saved_state);
|
||||
static int do_pci_enable_device(struct pci_dev *dev, int bars)
|
||||
{
|
||||
int err;
|
||||
u16 cmd;
|
||||
u8 pin;
|
||||
|
||||
err = pci_set_power_state(dev, PCI_D0);
|
||||
if (err < 0 && err != -EIO)
|
||||
@ -1190,6 +1192,14 @@ static int do_pci_enable_device(struct pci_dev *dev, int bars)
|
||||
return err;
|
||||
pci_fixup_device(pci_fixup_enable, dev);
|
||||
|
||||
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
|
||||
if (pin) {
|
||||
pci_read_config_word(dev, PCI_COMMAND, &cmd);
|
||||
if (cmd & PCI_COMMAND_INTX_DISABLE)
|
||||
pci_write_config_word(dev, PCI_COMMAND,
|
||||
cmd & ~PCI_COMMAND_INTX_DISABLE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1169,8 +1169,23 @@ void msi_remove_pci_irq_vectors(struct pci_dev *dev);
|
||||
void pci_restore_msi_state(struct pci_dev *dev);
|
||||
int pci_msi_enabled(void);
|
||||
int pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec);
|
||||
static inline int pci_enable_msi_exact(struct pci_dev *dev, int nvec)
|
||||
{
|
||||
int rc = pci_enable_msi_range(dev, nvec, nvec);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
return 0;
|
||||
}
|
||||
int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries,
|
||||
int minvec, int maxvec);
|
||||
static inline int pci_enable_msix_exact(struct pci_dev *dev,
|
||||
struct msix_entry *entries, int nvec)
|
||||
{
|
||||
int rc = pci_enable_msix_range(dev, entries, nvec, nvec);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static inline int pci_msi_vec_count(struct pci_dev *dev) { return -ENOSYS; }
|
||||
static inline int pci_enable_msi_block(struct pci_dev *dev, int nvec)
|
||||
@ -1189,9 +1204,14 @@ static inline int pci_msi_enabled(void) { return 0; }
|
||||
static inline int pci_enable_msi_range(struct pci_dev *dev, int minvec,
|
||||
int maxvec)
|
||||
{ return -ENOSYS; }
|
||||
static inline int pci_enable_msi_exact(struct pci_dev *dev, int nvec)
|
||||
{ return -ENOSYS; }
|
||||
static inline int pci_enable_msix_range(struct pci_dev *dev,
|
||||
struct msix_entry *entries, int minvec, int maxvec)
|
||||
{ return -ENOSYS; }
|
||||
static inline int pci_enable_msix_exact(struct pci_dev *dev,
|
||||
struct msix_entry *entries, int nvec)
|
||||
{ return -ENOSYS; }
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PCIEPORTBUS
|
||||
|
Loading…
Reference in New Issue
Block a user