Commit 0c3bef61 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6:
  PCI: OF: Don't crash when bridge parent is NULL.
  PCI: export pcie_bus_configure_settings symbol
  PCI: code and comments cleanup
  PCI: make cardbus-bridge resources optional
  PCI: make SRIOV resources optional
  PCI : ability to relocate assigned pci-resources
  PCI: honor child buses add_size in hot plug configuration
  PCI: Set PCI-E Max Payload Size on fabric
parents 01b88335 69566dd8
......@@ -360,6 +360,15 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root)
}
}
/* After the PCI-E bus has been walked and all devices discovered,
* configure any settings of the fabric that might be necessary.
*/
if (bus) {
struct pci_bus *child;
list_for_each_entry(child, &bus->children, node)
pcie_bus_configure_settings(child, child->self->pcie_mpss);
}
if (!bus)
kfree(sd);
......
......@@ -158,47 +158,6 @@ static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp)
*/
}
/* Program PCIE MaxPayload setting on device: ensure parent maxpayload <= device */
static int pci_set_payload(struct pci_dev *dev)
{
int pos, ppos;
u16 pctl, psz;
u16 dctl, dsz, dcap, dmax;
struct pci_dev *parent;
parent = dev->bus->self;
pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
if (!pos)
return 0;
/* Read Device MaxPayload capability and setting */
pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &dctl);
pci_read_config_word(dev, pos + PCI_EXP_DEVCAP, &dcap);
dsz = (dctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5;
dmax = (dcap & PCI_EXP_DEVCAP_PAYLOAD);
/* Read Parent MaxPayload setting */
ppos = pci_find_capability(parent, PCI_CAP_ID_EXP);
if (!ppos)
return 0;
pci_read_config_word(parent, ppos + PCI_EXP_DEVCTL, &pctl);
psz = (pctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5;
/* If parent payload > device max payload -> error
* If parent payload > device payload -> set speed
* If parent payload <= device payload -> do nothing
*/
if (psz > dmax)
return -1;
else if (psz > dsz) {
dev_info(&dev->dev, "Setting MaxPayload to %d\n", 128 << psz);
pci_write_config_word(dev, pos + PCI_EXP_DEVCTL,
(dctl & ~PCI_EXP_DEVCTL_PAYLOAD) +
(psz << 5));
}
return 0;
}
void pci_configure_slot(struct pci_dev *dev)
{
struct pci_dev *cdev;
......@@ -210,9 +169,7 @@ void pci_configure_slot(struct pci_dev *dev)
(dev->class >> 8) == PCI_CLASS_BRIDGE_PCI)))
return;
ret = pci_set_payload(dev);
if (ret)
dev_warn(&dev->dev, "could not set device max payload\n");
pcie_bus_configure_settings(dev->bus, dev->bus->self->pcie_mpss);
memset(&hpp, 0, sizeof(hpp));
ret = pci_get_hp_params(dev, &hpp);
......
......@@ -55,7 +55,7 @@ struct device_node * __weak pcibios_get_phb_of_node(struct pci_bus *bus)
*/
if (bus->bridge->of_node)
return of_node_get(bus->bridge->of_node);
if (bus->bridge->parent->of_node)
if (bus->bridge->parent && bus->bridge->parent->of_node)
return of_node_get(bus->bridge->parent->of_node);
return NULL;
}
......@@ -77,6 +77,8 @@ unsigned long pci_cardbus_mem_size = DEFAULT_CARDBUS_MEM_SIZE;
unsigned long pci_hotplug_io_size = DEFAULT_HOTPLUG_IO_SIZE;
unsigned long pci_hotplug_mem_size = DEFAULT_HOTPLUG_MEM_SIZE;
enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_PERFORMANCE;
/*
* The default CLS is used if arch didn't set CLS explicitly and not
* all pci devices agree on the same value. Arch can override either
......@@ -3222,6 +3224,67 @@ int pcie_set_readrq(struct pci_dev *dev, int rq)
}
EXPORT_SYMBOL(pcie_set_readrq);
/**
* pcie_get_mps - get PCI Express maximum payload size
* @dev: PCI device to query
*
* Returns maximum payload size in bytes
* or appropriate error value.
*/
int pcie_get_mps(struct pci_dev *dev)
{
int ret, cap;
u16 ctl;
cap = pci_pcie_cap(dev);
if (!cap)
return -EINVAL;
ret = pci_read_config_word(dev, cap + PCI_EXP_DEVCTL, &ctl);
if (!ret)
ret = 128 << ((ctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5);
return ret;
}
/**
* pcie_set_mps - set PCI Express maximum payload size
* @dev: PCI device to query
* @rq: maximum payload size in bytes
* valid values are 128, 256, 512, 1024, 2048, 4096
*
* If possible sets maximum payload size
*/
int pcie_set_mps(struct pci_dev *dev, int mps)
{
int cap, err = -EINVAL;
u16 ctl, v;
if (mps < 128 || mps > 4096 || !is_power_of_2(mps))
goto out;
v = ffs(mps) - 8;
if (v > dev->pcie_mpss)
goto out;
v <<= 5;
cap = pci_pcie_cap(dev);
if (!cap)
goto out;
err = pci_read_config_word(dev, cap + PCI_EXP_DEVCTL, &ctl);
if (err)
goto out;
if ((ctl & PCI_EXP_DEVCTL_PAYLOAD) != v) {
ctl &= ~PCI_EXP_DEVCTL_PAYLOAD;
ctl |= v;
err = pci_write_config_word(dev, cap + PCI_EXP_DEVCTL, ctl);
}
out:
return err;
}
/**
* pci_select_bars - Make BAR mask from the type of resource
* @dev: the PCI device for which BAR mask is made
......@@ -3505,6 +3568,10 @@ static int __init pci_setup(char *str)
pci_hotplug_io_size = memparse(str + 9, &str);
} else if (!strncmp(str, "hpmemsize=", 10)) {
pci_hotplug_mem_size = memparse(str + 10, &str);
} else if (!strncmp(str, "pcie_bus_safe", 13)) {
pcie_bus_config = PCIE_BUS_SAFE;
} else if (!strncmp(str, "pcie_bus_perf", 13)) {
pcie_bus_config = PCIE_BUS_PERFORMANCE;
} else {
printk(KERN_ERR "PCI: Unknown option `%s'\n",
str);
......
......@@ -283,6 +283,8 @@ static inline int pci_iov_bus_range(struct pci_bus *bus)
#endif /* CONFIG_PCI_IOV */
extern unsigned long pci_cardbus_resource_alignment(struct resource *);
static inline resource_size_t pci_resource_alignment(struct pci_dev *dev,
struct resource *res)
{
......@@ -292,6 +294,8 @@ static inline resource_size_t pci_resource_alignment(struct pci_dev *dev,
if (resno >= PCI_IOV_RESOURCES && resno <= PCI_IOV_RESOURCE_END)
return pci_sriov_resource_alignment(dev, resno);
#endif
if (dev->class >> 8 == PCI_CLASS_BRIDGE_CARDBUS)
return pci_cardbus_resource_alignment(res);
return resource_alignment(res);
}
......
......@@ -856,6 +856,8 @@ void set_pcie_port_type(struct pci_dev *pdev)
pdev->pcie_cap = pos;
pci_read_config_word(pdev, pos + PCI_EXP_FLAGS, &reg16);
pdev->pcie_type = (reg16 & PCI_EXP_FLAGS_TYPE) >> 4;
pci_read_config_word(pdev, pos + PCI_EXP_DEVCAP, &reg16);
pdev->pcie_mpss = reg16 & PCI_EXP_DEVCAP_PAYLOAD;
}
void set_pcie_hotplug_bridge(struct pci_dev *pdev)
......@@ -1326,6 +1328,150 @@ int pci_scan_slot(struct pci_bus *bus, int devfn)
return nr;
}
static int pcie_find_smpss(struct pci_dev *dev, void *data)
{
u8 *smpss = data;
if (!pci_is_pcie(dev))
return 0;
/* For PCIE hotplug enabled slots not connected directly to a
* PCI-E root port, there can be problems when hotplugging
* devices. This is due to the possibility of hotplugging a
* device into the fabric with a smaller MPS that the devices
* currently running have configured. Modifying the MPS on the
* running devices could cause a fatal bus error due to an
* incoming frame being larger than the newly configured MPS.
* To work around this, the MPS for the entire fabric must be
* set to the minimum size. Any devices hotplugged into this
* fabric will have the minimum MPS set. If the PCI hotplug
* slot is directly connected to the root port and there are not
* other devices on the fabric (which seems to be the most
* common case), then this is not an issue and MPS discovery
* will occur as normal.
*/
if (dev->is_hotplug_bridge && (!list_is_singular(&dev->bus->devices) ||
dev->bus->self->pcie_type != PCI_EXP_TYPE_ROOT_PORT))
*smpss = 0;
if (*smpss > dev->pcie_mpss)
*smpss = dev->pcie_mpss;
return 0;
}
static void pcie_write_mps(struct pci_dev *dev, int mps)
{
int rc, dev_mpss;
dev_mpss = 128 << dev->pcie_mpss;
if (pcie_bus_config == PCIE_BUS_PERFORMANCE) {
if (dev->bus->self) {
dev_dbg(&dev->bus->dev, "Bus MPSS %d\n",
128 << dev->bus->self->pcie_mpss);
/* For "MPS Force Max", the assumption is made that
* downstream communication will never be larger than
* the MRRS. So, the MPS only needs to be configured
* for the upstream communication. This being the case,
* walk from the top down and set the MPS of the child
* to that of the parent bus.
*/
mps = 128 << dev->bus->self->pcie_mpss;
if (mps > dev_mpss)
dev_warn(&dev->dev, "MPS configured higher than"
" maximum supported by the device. If"
" a bus issue occurs, try running with"
" pci=pcie_bus_safe.\n");
}
dev->pcie_mpss = ffs(mps) - 8;
}
rc = pcie_set_mps(dev, mps);
if (rc)
dev_err(&dev->dev, "Failed attempting to set the MPS\n");
}
static void pcie_write_mrrs(struct pci_dev *dev, int mps)
{
int rc, mrrs;
if (pcie_bus_config == PCIE_BUS_PERFORMANCE) {
int dev_mpss = 128 << dev->pcie_mpss;
/* For Max performance, the MRRS must be set to the largest
* supported value. However, it cannot be configured larger
* than the MPS the device or the bus can support. This assumes
* that the largest MRRS available on the device cannot be
* smaller than the device MPSS.
*/
mrrs = mps < dev_mpss ? mps : dev_mpss;
} else
/* In the "safe" case, configure the MRRS for fairness on the
* bus by making all devices have the same size
*/
mrrs = mps;
/* MRRS is a R/W register. Invalid values can be written, but a
* subsiquent read will verify if the value is acceptable or not.
* If the MRRS value provided is not acceptable (e.g., too large),
* shrink the value until it is acceptable to the HW.
*/
while (mrrs != pcie_get_readrq(dev) && mrrs >= 128) {
rc = pcie_set_readrq(dev, mrrs);
if (rc)
dev_err(&dev->dev, "Failed attempting to set the MRRS\n");
mrrs /= 2;
}
}
static int pcie_bus_configure_set(struct pci_dev *dev, void *data)
{
int mps = 128 << *(u8 *)data;
if (!pci_is_pcie(dev))
return 0;
dev_info(&dev->dev, "Dev MPS %d MPSS %d MRRS %d\n",
pcie_get_mps(dev), 128<<dev->pcie_mpss, pcie_get_readrq(dev));
pcie_write_mps(dev, mps);
pcie_write_mrrs(dev, mps);
dev_info(&dev->dev, "Dev MPS %d MPSS %d MRRS %d\n",
pcie_get_mps(dev), 128<<dev->pcie_mpss, pcie_get_readrq(dev));
return 0;
}
/* pcie_bus_configure_mps requires that pci_walk_bus work in a top-down,
* parents then children fashion. If this changes, then this code will not
* work as designed.
*/
void pcie_bus_configure_settings(struct pci_bus *bus, u8 mpss)
{
u8 smpss = mpss;
if (!bus->self)
return;
if (!pci_is_pcie(bus->self))
return;
if (pcie_bus_config == PCIE_BUS_SAFE) {
pcie_find_smpss(bus->self, &smpss);
pci_walk_bus(bus, pcie_find_smpss, &smpss);
}
pcie_bus_configure_set(bus->self, &smpss);
pci_walk_bus(bus, pcie_bus_configure_set, &smpss);
}
EXPORT_SYMBOL_GPL(pcie_bus_configure_settings);
unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus)
{
unsigned int devfn, pass, max = bus->secondary;
......
This diff is collapsed.
......@@ -128,16 +128,16 @@ void pci_disable_bridge_window(struct pci_dev *dev)
}
#endif /* CONFIG_PCI_QUIRKS */
static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev,
int resno)
int resno, resource_size_t size, resource_size_t align)
{
struct resource *res = dev->resource + resno;
resource_size_t size, min, align;
resource_size_t min;
int ret;
size = resource_size(res);
min = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM;
align = pci_resource_alignment(dev, res);
/* First, try exact prefetching match.. */
ret = pci_bus_alloc_resource(bus, res, size, align, min,
......@@ -154,56 +154,101 @@ static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev,
ret = pci_bus_alloc_resource(bus, res, size, align, min, 0,
pcibios_align_resource, dev);
}
return ret;
}
if (ret < 0 && dev->fw_addr[resno]) {
struct resource *root, *conflict;
resource_size_t start, end;
static int pci_revert_fw_address(struct resource *res, struct pci_dev *dev,
int resno, resource_size_t size)
{
struct resource *root, *conflict;
resource_size_t start, end;
int ret = 0;
/*
* If we failed to assign anything, let's try the address
* where firmware left it. That at least has a chance of
* working, which is better than just leaving it disabled.
*/
if (res->flags & IORESOURCE_IO)
root = &ioport_resource;
else
root = &iomem_resource;
start = res->start;
end = res->end;
res->start = dev->fw_addr[resno];
res->end = res->start + size - 1;
dev_info(&dev->dev, "BAR %d: trying firmware assignment %pR\n",
resno, res);
conflict = request_resource_conflict(root, res);
if (conflict) {
dev_info(&dev->dev,
"BAR %d: %pR conflicts with %s %pR\n", resno,
res, conflict->name, conflict);
res->start = start;
res->end = end;
ret = 1;
}
return ret;
}
static int _pci_assign_resource(struct pci_dev *dev, int resno, int size, resource_size_t min_align)
{
struct resource *res = dev->resource + resno;
struct pci_bus *bus;
int ret;
char *type;
if (res->flags & IORESOURCE_IO)
root = &ioport_resource;
bus = dev->bus;
while ((ret = __pci_assign_resource(bus, dev, resno, size, min_align))) {
if (!bus->parent || !bus->self->transparent)
break;
bus = bus->parent;
}
if (ret) {
if (res->flags & IORESOURCE_MEM)
if (res->flags & IORESOURCE_PREFETCH)
type = "mem pref";
else
type = "mem";
else if (res->flags & IORESOURCE_IO)
type = "io";
else
root = &iomem_resource;
start = res->start;
end = res->end;
res->start = dev->fw_addr[resno];
res->end = res->start + size - 1;
dev_info(&dev->dev, "BAR %d: trying firmware assignment %pR\n",
resno, res);
conflict = request_resource_conflict(root, res);
if (conflict) {
dev_info(&dev->dev,
"BAR %d: %pR conflicts with %s %pR\n", resno,
res, conflict->name, conflict);
res->start = start;
res->end = end;
} else
ret = 0;
type = "unknown";
dev_info(&dev->dev,
"BAR %d: can't assign %s (size %#llx)\n",
resno, type, (unsigned long long) resource_size(res));
}
return ret;
}
int pci_reassign_resource(struct pci_dev *dev, int resno, resource_size_t addsize,
resource_size_t min_align)
{
struct resource *res = dev->resource + resno;
resource_size_t new_size;
int ret;
if (!res->parent) {
dev_info(&dev->dev, "BAR %d: can't reassign an unassigned resouce %pR "
"\n", resno, res);
return -EINVAL;
}
new_size = resource_size(res) + addsize + min_align;
ret = _pci_assign_resource(dev, resno, new_size, min_align);
if (!ret) {
res->flags &= ~IORESOURCE_STARTALIGN;
dev_info(&dev->dev, "BAR %d: assigned %pR\n", resno, res);
if (resno < PCI_BRIDGE_RESOURCES)
pci_update_resource(dev, resno);
}
return ret;
}
int pci_assign_resource(struct pci_dev *dev, int resno)
{
struct resource *res = dev->resource + resno;
resource_size_t align;
resource_size_t align, size;
struct pci_bus *bus;
int ret;
char *type;
align = pci_resource_alignment(dev, res);
if (!align) {
......@@ -213,34 +258,27 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
}
bus = dev->bus;
while ((ret = __pci_assign_resource(bus, dev, resno))) {
if (bus->parent && bus->self->transparent)
bus = bus->parent;
else
bus = NULL;
if (bus)
continue;
break;
}
size = resource_size(res);
ret = _pci_assign_resource(dev, resno, size, align);
if (ret) {
if (res->flags & IORESOURCE_MEM)
if (res->flags & IORESOURCE_PREFETCH)
type = "mem pref";
else
type = "mem";
else if (res->flags & IORESOURCE_IO)
type = "io";
else
type = "unknown";
dev_info(&dev->dev,
"BAR %d: can't assign %s (size %#llx)\n",
resno, type, (unsigned long long) resource_size(res));
}
/*
* If we failed to assign anything, let's try the address
* where firmware left it. That at least has a chance of
* working, which is better than just leaving it disabled.
*/
if (ret < 0 && dev->fw_addr[resno])
ret = pci_revert_fw_address(res, dev, resno, size);
if (!ret) {
res->flags &= ~IORESOURCE_STARTALIGN;
dev_info(&dev->dev, "BAR %d: assigned %pR\n", resno, res);
if (resno < PCI_BRIDGE_RESOURCES)
pci_update_resource(dev, resno);
}
return ret;
}
/* Sort resources by alignment */
void pdev_sort_resources(struct pci_dev *dev, struct resource_list *head)
{
......
......@@ -251,7 +251,8 @@ struct pci_dev {
u8 revision; /* PCI revision, low byte of class word */
u8 hdr_type; /* PCI header type (`multi' flag masked out) */
u8 pcie_cap; /* PCI-E capability offset */
u8 pcie_type; /* PCI-E device/port type */
u8 pcie_type:4; /* PCI-E device/port type */
u8 pcie_mpss:3; /* PCI-E Max Payload Size Supported */
u8 rom_base_reg; /* which config register controls the ROM */
u8 pin; /* which interrupt pin this device uses */
......@@ -617,6 +618,16 @@ struct pci_driver {
/* these external functions are only available when PCI support is enabled */
#ifdef CONFIG_PCI
extern void pcie_bus_configure_settings(struct pci_bus *bus, u8 smpss);
enum pcie_bus_config_types {
PCIE_BUS_PERFORMANCE,
PCIE_BUS_SAFE,
PCIE_BUS_PEER2PEER,
};
extern enum pcie_bus_config_types pcie_bus_config;
extern struct bus_type pci_bus_type;
/* Do NOT directly access these two variables, unless you are arch specific pci
......@@ -796,10 +807,13 @@ int pcix_get_mmrbc(struct pci_dev *dev);
int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc);
int pcie_get_readrq(struct pci_dev *dev);
int pcie_set_readrq(struct pci_dev *dev, int rq);
int pcie_get_mps(struct pci_dev *dev);
int pcie_set_mps(struct pci_dev *dev, int mps);
int __pci_reset_function(struct pci_dev *dev);
int pci_reset_function(struct pci_dev *dev);
void pci_update_resource(struct pci_dev *dev, int resno);
int __must_check pci_assign_resource(struct pci_dev *dev, int i);
int __must_check pci_reassign_resource(struct pci_dev *dev, int i, resource_size_t add_size, resource_size_t align);
int pci_select_bars(struct pci_dev *dev, unsigned long flags);
/* ROM control related routines */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment