PCI: add PCI-X/PCI-Express read control interfaces
This patch introduces an interface to read and write PCI-X / PCI-Express maximum read byte count values from PCI config space. There is a second function that returns the maximum _designed_ read byte count, which marks the maximum value for a device, since some drivers try to set MMRBC to the highest allowed value and rely on such a function. Based on patch set by Stephen Hemminger <shemminger@linux-foundation.org> Cc: Stephen Hemminger <shemminger@linux-foundation.org> Signed-off-by: Peter Oruba <peter.oruba@amd.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
parent
e4585da22a
commit
d556ad4bbe
3 changed files with 182 additions and 1 deletions
|
@ -1374,6 +1374,166 @@ pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask)
|
|||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* pcix_get_max_mmrbc - get PCI-X maximum designed memory read byte count
|
||||
* @dev: PCI device to query
|
||||
*
|
||||
* Returns mmrbc: maximum designed memory read count in bytes
|
||||
* or appropriate error value.
|
||||
*/
|
||||
int pcix_get_max_mmrbc(struct pci_dev *dev)
|
||||
{
|
||||
int ret, err, cap;
|
||||
u32 stat;
|
||||
|
||||
cap = pci_find_capability(dev, PCI_CAP_ID_PCIX);
|
||||
if (!cap)
|
||||
return -EINVAL;
|
||||
|
||||
err = pci_read_config_dword(dev, cap + PCI_X_STATUS, &stat);
|
||||
if (err)
|
||||
return -EINVAL;
|
||||
|
||||
ret = (stat & PCI_X_STATUS_MAX_READ) >> 12;
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(pcix_get_max_mmrbc);
|
||||
|
||||
/**
|
||||
* pcix_get_mmrbc - get PCI-X maximum memory read byte count
|
||||
* @dev: PCI device to query
|
||||
*
|
||||
* Returns mmrbc: maximum memory read count in bytes
|
||||
* or appropriate error value.
|
||||
*/
|
||||
int pcix_get_mmrbc(struct pci_dev *dev)
|
||||
{
|
||||
int ret, cap;
|
||||
u32 cmd;
|
||||
|
||||
cap = pci_find_capability(dev, PCI_CAP_ID_PCIX);
|
||||
if (!cap)
|
||||
return -EINVAL;
|
||||
|
||||
ret = pci_read_config_dword(dev, cap + PCI_X_CMD, &cmd);
|
||||
if (!ret)
|
||||
ret = 512 << ((cmd & PCI_X_CMD_MAX_READ) >> 2);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(pcix_get_mmrbc);
|
||||
|
||||
/**
|
||||
* pcix_set_mmrbc - set PCI-X maximum memory read byte count
|
||||
* @dev: PCI device to query
|
||||
* @mmrbc: maximum memory read count in bytes
|
||||
* valid values are 512, 1024, 2048, 4096
|
||||
*
|
||||
* If possible sets maximum memory read byte count, some bridges have erratas
|
||||
* that prevent this.
|
||||
*/
|
||||
int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc)
|
||||
{
|
||||
int cap, err = -EINVAL;
|
||||
u32 stat, cmd, v, o;
|
||||
|
||||
if (mmrbc < 512 || mmrbc > 4096 || (mmrbc & (mmrbc-1)))
|
||||
goto out;
|
||||
|
||||
v = ffs(mmrbc) - 10;
|
||||
|
||||
cap = pci_find_capability(dev, PCI_CAP_ID_PCIX);
|
||||
if (!cap)
|
||||
goto out;
|
||||
|
||||
err = pci_read_config_dword(dev, cap + PCI_X_STATUS, &stat);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (v > (stat & PCI_X_STATUS_MAX_READ) >> 21)
|
||||
return -E2BIG;
|
||||
|
||||
err = pci_read_config_dword(dev, cap + PCI_X_CMD, &cmd);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
o = (cmd & PCI_X_CMD_MAX_READ) >> 2;
|
||||
if (o != v) {
|
||||
if (v > o && dev->bus &&
|
||||
(dev->bus->bus_flags & PCI_BUS_FLAGS_NO_MMRBC))
|
||||
return -EIO;
|
||||
|
||||
cmd &= ~PCI_X_CMD_MAX_READ;
|
||||
cmd |= v << 2;
|
||||
err = pci_write_config_dword(dev, cap + PCI_X_CMD, cmd);
|
||||
}
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(pcix_set_mmrbc);
|
||||
|
||||
/**
|
||||
* pcie_get_readrq - get PCI Express read request size
|
||||
* @dev: PCI device to query
|
||||
*
|
||||
* Returns maximum memory read request in bytes
|
||||
* or appropriate error value.
|
||||
*/
|
||||
int pcie_get_readrq(struct pci_dev *dev)
|
||||
{
|
||||
int ret, cap;
|
||||
u16 ctl;
|
||||
|
||||
cap = pci_find_capability(dev, PCI_CAP_ID_EXP);
|
||||
if (!cap)
|
||||
return -EINVAL;
|
||||
|
||||
ret = pci_read_config_word(dev, cap + PCI_EXP_DEVCTL, &ctl);
|
||||
if (!ret)
|
||||
ret = 128 << ((ctl & PCI_EXP_DEVCTL_READRQ) >> 12);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(pcie_get_readrq);
|
||||
|
||||
/**
|
||||
* pcie_set_readrq - set PCI Express maximum memory read request
|
||||
* @dev: PCI device to query
|
||||
* @count: maximum memory read count in bytes
|
||||
* valid values are 128, 256, 512, 1024, 2048, 4096
|
||||
*
|
||||
* If possible sets maximum read byte count
|
||||
*/
|
||||
int pcie_set_readrq(struct pci_dev *dev, int rq)
|
||||
{
|
||||
int cap, err = -EINVAL;
|
||||
u16 ctl, v;
|
||||
|
||||
if (rq < 128 || rq > 4096 || (rq & (rq-1)))
|
||||
goto out;
|
||||
|
||||
v = (ffs(rq) - 8) << 12;
|
||||
|
||||
cap = pci_find_capability(dev, PCI_CAP_ID_EXP);
|
||||
if (!cap)
|
||||
goto out;
|
||||
|
||||
err = pci_read_config_word(dev, cap + PCI_EXP_DEVCTL, &ctl);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if ((ctl & PCI_EXP_DEVCTL_READRQ) != v) {
|
||||
ctl &= ~PCI_EXP_DEVCTL_READRQ;
|
||||
ctl |= v;
|
||||
err = pci_write_config_dword(dev, cap + PCI_EXP_DEVCTL, ctl);
|
||||
}
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(pcie_set_readrq);
|
||||
|
||||
/**
|
||||
* pci_select_bars - Make BAR mask from the type of resource
|
||||
* @dev: the PCI device for which BAR mask is made
|
||||
|
|
|
@ -627,6 +627,22 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_
|
|||
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_amd_8131_ioapic);
|
||||
#endif /* CONFIG_X86_IO_APIC */
|
||||
|
||||
/*
|
||||
* Some settings of MMRBC can lead to data corruption so block changes.
|
||||
* See AMD 8131 HyperTransport PCI-X Tunnel Revision Guide
|
||||
*/
|
||||
static void __init quirk_amd_8131_mmrbc(struct pci_dev *dev)
|
||||
{
|
||||
unsigned char revid;
|
||||
|
||||
pci_read_config_byte(dev, PCI_REVISION_ID, &revid);
|
||||
if (dev->subordinate && revid <= 0x12) {
|
||||
printk(KERN_INFO "AMD8131 rev %x detected, disabling PCI-X MMRBC\n",
|
||||
revid);
|
||||
dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MMRBC;
|
||||
}
|
||||
}
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_amd_8131_mmrbc);
|
||||
|
||||
/*
|
||||
* FIXME: it is questionable that quirk_via_acpi
|
||||
|
|
|
@ -111,7 +111,8 @@ enum pcie_reset_state {
|
|||
|
||||
typedef unsigned short __bitwise pci_bus_flags_t;
|
||||
enum pci_bus_flags {
|
||||
PCI_BUS_FLAGS_NO_MSI = (__force pci_bus_flags_t) 1,
|
||||
PCI_BUS_FLAGS_NO_MSI = (__force pci_bus_flags_t) 1,
|
||||
PCI_BUS_FLAGS_NO_MMRBC = (__force pci_bus_flags_t) 2,
|
||||
};
|
||||
|
||||
struct pci_cap_saved_state {
|
||||
|
@ -549,6 +550,10 @@ void pci_intx(struct pci_dev *dev, int enable);
|
|||
void pci_msi_off(struct pci_dev *dev);
|
||||
int pci_set_dma_mask(struct pci_dev *dev, u64 mask);
|
||||
int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask);
|
||||
int pcix_get_max_mmrbc(struct pci_dev *dev);
|
||||
int pcix_get_mmrbc(struct pci_dev *dev);
|
||||
int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc);
|
||||
int pcie_set_readrq(struct pci_dev *dev, int rq);
|
||||
void pci_update_resource(struct pci_dev *dev, struct resource *res, int resno);
|
||||
int __must_check pci_assign_resource(struct pci_dev *dev, int i);
|
||||
int __must_check pci_assign_resource_fixed(struct pci_dev *dev, int i);
|
||||
|
|
Loading…
Reference in a new issue