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) ...@@ -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) if (!bus)
kfree(sd); kfree(sd);
......
...@@ -158,47 +158,6 @@ static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp) ...@@ -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) void pci_configure_slot(struct pci_dev *dev)
{ {
struct pci_dev *cdev; struct pci_dev *cdev;
...@@ -210,9 +169,7 @@ void pci_configure_slot(struct pci_dev *dev) ...@@ -210,9 +169,7 @@ void pci_configure_slot(struct pci_dev *dev)
(dev->class >> 8) == PCI_CLASS_BRIDGE_PCI))) (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI)))
return; return;
ret = pci_set_payload(dev); pcie_bus_configure_settings(dev->bus, dev->bus->self->pcie_mpss);
if (ret)
dev_warn(&dev->dev, "could not set device max payload\n");
memset(&hpp, 0, sizeof(hpp)); memset(&hpp, 0, sizeof(hpp));
ret = pci_get_hp_params(dev, &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) ...@@ -55,7 +55,7 @@ struct device_node * __weak pcibios_get_phb_of_node(struct pci_bus *bus)
*/ */
if (bus->bridge->of_node) if (bus->bridge->of_node)
return of_node_get(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 of_node_get(bus->bridge->parent->of_node);
return NULL; return NULL;
} }
...@@ -77,6 +77,8 @@ unsigned long pci_cardbus_mem_size = DEFAULT_CARDBUS_MEM_SIZE; ...@@ -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_io_size = DEFAULT_HOTPLUG_IO_SIZE;
unsigned long pci_hotplug_mem_size = DEFAULT_HOTPLUG_MEM_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 * 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 * 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) ...@@ -3222,6 +3224,67 @@ int pcie_set_readrq(struct pci_dev *dev, int rq)
} }
EXPORT_SYMBOL(pcie_set_readrq); 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 * pci_select_bars - Make BAR mask from the type of resource
* @dev: the PCI device for which BAR mask is made * @dev: the PCI device for which BAR mask is made
...@@ -3505,6 +3568,10 @@ static int __init pci_setup(char *str) ...@@ -3505,6 +3568,10 @@ static int __init pci_setup(char *str)
pci_hotplug_io_size = memparse(str + 9, &str); pci_hotplug_io_size = memparse(str + 9, &str);
} else if (!strncmp(str, "hpmemsize=", 10)) { } else if (!strncmp(str, "hpmemsize=", 10)) {
pci_hotplug_mem_size = memparse(str + 10, &str); 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 { } else {
printk(KERN_ERR "PCI: Unknown option `%s'\n", printk(KERN_ERR "PCI: Unknown option `%s'\n",
str); str);
......
...@@ -283,6 +283,8 @@ static inline int pci_iov_bus_range(struct pci_bus *bus) ...@@ -283,6 +283,8 @@ static inline int pci_iov_bus_range(struct pci_bus *bus)
#endif /* CONFIG_PCI_IOV */ #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, static inline resource_size_t pci_resource_alignment(struct pci_dev *dev,
struct resource *res) struct resource *res)
{ {
...@@ -292,6 +294,8 @@ static inline resource_size_t pci_resource_alignment(struct pci_dev *dev, ...@@ -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) if (resno >= PCI_IOV_RESOURCES && resno <= PCI_IOV_RESOURCE_END)
return pci_sriov_resource_alignment(dev, resno); return pci_sriov_resource_alignment(dev, resno);
#endif #endif
if (dev->class >> 8 == PCI_CLASS_BRIDGE_CARDBUS)
return pci_cardbus_resource_alignment(res);
return resource_alignment(res); return resource_alignment(res);
} }
......
...@@ -856,6 +856,8 @@ void set_pcie_port_type(struct pci_dev *pdev) ...@@ -856,6 +856,8 @@ void set_pcie_port_type(struct pci_dev *pdev)
pdev->pcie_cap = pos; pdev->pcie_cap = pos;
pci_read_config_word(pdev, pos + PCI_EXP_FLAGS, &reg16); pci_read_config_word(pdev, pos + PCI_EXP_FLAGS, &reg16);
pdev->pcie_type = (reg16 & PCI_EXP_FLAGS_TYPE) >> 4; 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) void set_pcie_hotplug_bridge(struct pci_dev *pdev)
...@@ -1326,6 +1328,150 @@ int pci_scan_slot(struct pci_bus *bus, int devfn) ...@@ -1326,6 +1328,150 @@ int pci_scan_slot(struct pci_bus *bus, int devfn)
return nr; 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 __devinit pci_scan_child_bus(struct pci_bus *bus)
{ {
unsigned int devfn, pass, max = bus->secondary; unsigned int devfn, pass, max = bus->secondary;
......
...@@ -34,6 +34,7 @@ struct resource_list_x { ...@@ -34,6 +34,7 @@ struct resource_list_x {
resource_size_t start; resource_size_t start;
resource_size_t end; resource_size_t end;
resource_size_t add_size; resource_size_t add_size;
resource_size_t min_align;
unsigned long flags; unsigned long flags;
}; };
...@@ -65,7 +66,7 @@ void pci_realloc(void) ...@@ -65,7 +66,7 @@ void pci_realloc(void)
*/ */
static void add_to_list(struct resource_list_x *head, static void add_to_list(struct resource_list_x *head,
struct pci_dev *dev, struct resource *res, struct pci_dev *dev, struct resource *res,
resource_size_t add_size) resource_size_t add_size, resource_size_t min_align)
{ {
struct resource_list_x *list = head; struct resource_list_x *list = head;
struct resource_list_x *ln = list->next; struct resource_list_x *ln = list->next;
...@@ -84,13 +85,16 @@ static void add_to_list(struct resource_list_x *head, ...@@ -84,13 +85,16 @@ static void add_to_list(struct resource_list_x *head,
tmp->end = res->end; tmp->end = res->end;
tmp->flags = res->flags; tmp->flags = res->flags;
tmp->add_size = add_size; tmp->add_size = add_size;
tmp->min_align = min_align;
list->next = tmp; list->next = tmp;
} }
static void add_to_failed_list(struct resource_list_x *head, static void add_to_failed_list(struct resource_list_x *head,
struct pci_dev *dev, struct resource *res) struct pci_dev *dev, struct resource *res)
{ {
add_to_list(head, dev, res, 0); add_to_list(head, dev, res,
0 /* dont care */,
0 /* dont care */);
} }
static void __dev_sort_resources(struct pci_dev *dev, static void __dev_sort_resources(struct pci_dev *dev,
...@@ -121,18 +125,18 @@ static inline void reset_resource(struct resource *res) ...@@ -121,18 +125,18 @@ static inline void reset_resource(struct resource *res)
} }
/** /**
* adjust_resources_sorted() - satisfy any additional resource requests * reassign_resources_sorted() - satisfy any additional resource requests
* *
* @add_head : head of the list tracking requests requiring additional * @realloc_head : head of the list tracking requests requiring additional
* resources * resources
* @head : head of the list tracking requests with allocated * @head : head of the list tracking requests with allocated
* resources * resources
* *
* Walk through each element of the add_head and try to procure * Walk through each element of the realloc_head and try to procure
* additional resources for the element, provided the element * additional resources for the element, provided the element
* is in the head list. * is in the head list.
*/ */
static void adjust_resources_sorted(struct resource_list_x *add_head, static void reassign_resources_sorted(struct resource_list_x *realloc_head,
struct resource_list *head) struct resource_list *head)
{ {
struct resource *res; struct resource *res;
...@@ -141,8 +145,8 @@ static void adjust_resources_sorted(struct resource_list_x *add_head, ...@@ -141,8 +145,8 @@ static void adjust_resources_sorted(struct resource_list_x *add_head,
resource_size_t add_size; resource_size_t add_size;
int idx; int idx;
prev = add_head; prev = realloc_head;
for (list = add_head->next; list;) { for (list = realloc_head->next; list;) {
res = list->res; res = list->res;
/* skip resource that has been reset */ /* skip resource that has been reset */
if (!res->flags) if (!res->flags)
...@@ -159,13 +163,17 @@ static void adjust_resources_sorted(struct resource_list_x *add_head, ...@@ -159,13 +163,17 @@ static void adjust_resources_sorted(struct resource_list_x *add_head,
idx = res - &list->dev->resource[0]; idx = res - &list->dev->resource[0];
add_size=list->add_size; add_size=list->add_size;
if (!resource_size(res) && add_size) { if (!resource_size(res)) {
res->end = res->start + add_size - 1; res->start = list->start;
if(pci_assign_resource(list->dev, idx)) res->end = res->start + add_size - 1;
if(pci_assign_resource(list->dev, idx))
reset_resource(res); reset_resource(res);
} else if (add_size) { } else {
adjust_resource(res, res->start, resource_size_t align = list->min_align;
resource_size(res) + add_size); res->flags |= list->flags & (IORESOURCE_STARTALIGN|IORESOURCE_SIZEALIGN);
if (pci_reassign_resource(list->dev, idx, add_size, align))
dev_printk(KERN_DEBUG, &list->dev->dev, "failed to add optional resources res=%pR\n",
res);
} }
out: out:
tmp = list; tmp = list;
...@@ -210,16 +218,16 @@ static void assign_requested_resources_sorted(struct resource_list *head, ...@@ -210,16 +218,16 @@ static void assign_requested_resources_sorted(struct resource_list *head,
} }
static void __assign_resources_sorted(struct resource_list *head, static void __assign_resources_sorted(struct resource_list *head,
struct resource_list_x *add_head, struct resource_list_x *realloc_head,
struct resource_list_x *fail_head) struct resource_list_x *fail_head)
{ {
/* Satisfy the must-have resource requests */ /* Satisfy the must-have resource requests */
assign_requested_resources_sorted(head, fail_head); assign_requested_resources_sorted(head, fail_head);
/* Try to satisfy any additional nice-to-have resource /* Try to satisfy any additional optional resource
requests */ requests */
if (add_head) if (realloc_head)
adjust_resources_sorted(add_head, head); reassign_resources_sorted(realloc_head, head);
free_list(resource_list, head); free_list(resource_list, head);
} }
...@@ -235,7 +243,7 @@ static void pdev_assign_resources_sorted(struct pci_dev *dev, ...@@ -235,7 +243,7 @@ static void pdev_assign_resources_sorted(struct pci_dev *dev,
} }
static void pbus_assign_resources_sorted(const struct pci_bus *bus, static void pbus_assign_resources_sorted(const struct pci_bus *bus,
struct resource_list_x *add_head, struct resource_list_x *realloc_head,
struct resource_list_x *fail_head) struct resource_list_x *fail_head)
{ {
struct pci_dev *dev; struct pci_dev *dev;
...@@ -245,7 +253,7 @@ static void pbus_assign_resources_sorted(const struct pci_bus *bus, ...@@ -245,7 +253,7 @@ static void pbus_assign_resources_sorted(const struct pci_bus *bus,
list_for_each_entry(dev, &bus->devices, bus_list) list_for_each_entry(dev, &bus->devices, bus_list)
__dev_sort_resources(dev, &head); __dev_sort_resources(dev, &head);
__assign_resources_sorted(&head, add_head, fail_head); __assign_resources_sorted(&head, realloc_head, fail_head);
} }
void pci_setup_cardbus(struct pci_bus *bus) void pci_setup_cardbus(struct pci_bus *bus)
...@@ -540,13 +548,27 @@ static resource_size_t calculate_memsize(resource_size_t size, ...@@ -540,13 +548,27 @@ static resource_size_t calculate_memsize(resource_size_t size,
return size; return size;
} }
static resource_size_t get_res_add_size(struct resource_list_x *realloc_head,
struct resource *res)
{
struct resource_list_x *list;
/* check if it is in realloc_head list */
for (list = realloc_head->next; list && list->res != res;
list = list->next);
if (list)
return list->add_size;
return 0;
}
/** /**
* pbus_size_io() - size the io window of a given bus * pbus_size_io() - size the io window of a given bus
* *
* @bus : the bus * @bus : the bus
* @min_size : the minimum io window that must to be allocated * @min_size : the minimum io window that must to be allocated
* @add_size : additional optional io window * @add_size : additional optional io window
* @add_head : track the additional io window on this list * @realloc_head : track the additional io window on this list
* *
* Sizing the IO windows of the PCI-PCI bridge is trivial, * Sizing the IO windows of the PCI-PCI bridge is trivial,
* since these windows have 4K granularity and the IO ranges * since these windows have 4K granularity and the IO ranges
...@@ -554,11 +576,12 @@ static resource_size_t calculate_memsize(resource_size_t size, ...@@ -554,11 +576,12 @@ static resource_size_t calculate_memsize(resource_size_t size,
* We must be careful with the ISA aliasing though. * We must be careful with the ISA aliasing though.
*/ */
static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size, static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
resource_size_t add_size, struct resource_list_x *add_head) resource_size_t add_size, struct resource_list_x *realloc_head)
{ {
struct pci_dev *dev; struct pci_dev *dev;
struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO); struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO);
unsigned long size = 0, size0 = 0, size1 = 0; unsigned long size = 0, size0 = 0, size1 = 0;
resource_size_t children_add_size = 0;
if (!b_res) if (!b_res)
return; return;
...@@ -579,11 +602,16 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size, ...@@ -579,11 +602,16 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
size += r_size; size += r_size;
else else
size1 += r_size; size1 += r_size;
if (realloc_head)
children_add_size += get_res_add_size(realloc_head, r);
} }
} }
size0 = calculate_iosize(size, min_size, size1, size0 = calculate_iosize(size, min_size, size1,
resource_size(b_res), 4096); resource_size(b_res), 4096);
size1 = (!add_head || (add_head && !add_size)) ? size0 : if (children_add_size > add_size)
add_size = children_add_size;
size1 = (!realloc_head || (realloc_head && !add_size)) ? size0 :
calculate_iosize(size, min_size+add_size, size1, calculate_iosize(size, min_size+add_size, size1,
resource_size(b_res), 4096); resource_size(b_res), 4096);
if (!size0 && !size1) { if (!size0 && !size1) {
...@@ -598,8 +626,8 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size, ...@@ -598,8 +626,8 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
b_res->start = 4096; b_res->start = 4096;
b_res->end = b_res->start + size0 - 1; b_res->end = b_res->start + size0 - 1;
b_res->flags |= IORESOURCE_STARTALIGN; b_res->flags |= IORESOURCE_STARTALIGN;
if (size1 > size0 && add_head) if (size1 > size0 && realloc_head)
add_to_list(add_head, bus->self, b_res, size1-size0); add_to_list(realloc_head, bus->self, b_res, size1-size0, 4096);
} }
/** /**
...@@ -608,7 +636,7 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size, ...@@ -608,7 +636,7 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
* @bus : the bus * @bus : the bus
* @min_size : the minimum memory window that must to be allocated * @min_size : the minimum memory window that must to be allocated
* @add_size : additional optional memory window * @add_size : additional optional memory window
* @add_head : track the additional memory window on this list * @realloc_head : track the additional memory window on this list
* *
* Calculate the size of the bus and minimal alignment which * Calculate the size of the bus and minimal alignment which
* guarantees that all child resources fit in this size. * guarantees that all child resources fit in this size.
...@@ -616,7 +644,7 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size, ...@@ -616,7 +644,7 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
unsigned long type, resource_size_t min_size, unsigned long type, resource_size_t min_size,
resource_size_t add_size, resource_size_t add_size,
struct resource_list_x *add_head) struct resource_list_x *realloc_head)
{ {
struct pci_dev *dev; struct pci_dev *dev;
resource_size_t min_align, align, size, size0, size1; resource_size_t min_align, align, size, size0, size1;
...@@ -624,6 +652,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, ...@@ -624,6 +652,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
int order, max_order; int order, max_order;
struct resource *b_res = find_free_bus_resource(bus, type); struct resource *b_res = find_free_bus_resource(bus, type);
unsigned int mem64_mask = 0; unsigned int mem64_mask = 0;
resource_size_t children_add_size = 0;
if (!b_res) if (!b_res)
return 0; return 0;
...@@ -645,6 +674,16 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, ...@@ -645,6 +674,16 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
if (r->parent || (r->flags & mask) != type) if (r->parent || (r->flags & mask) != type)
continue; continue;
r_size = resource_size(r); r_size = resource_size(r);
#ifdef CONFIG_PCI_IOV
/* put SRIOV requested res to the optional list */
if (realloc_head && i >= PCI_IOV_RESOURCES &&
i <= PCI_IOV_RESOURCE_END) {
r->end = r->start - 1;
add_to_list(realloc_head, dev, r, r_size, 0/* dont' care */);
children_add_size += r_size;
continue;
}
#endif
/* For bridges size != alignment */ /* For bridges size != alignment */
align = pci_resource_alignment(dev, r); align = pci_resource_alignment(dev, r);
order = __ffs(align) - 20; order = __ffs(align) - 20;
...@@ -665,6 +704,9 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, ...@@ -665,6 +704,9 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
if (order > max_order) if (order > max_order)
max_order = order; max_order = order;
mem64_mask &= r->flags & IORESOURCE_MEM_64; mem64_mask &= r->flags & IORESOURCE_MEM_64;
if (realloc_head)
children_add_size += get_res_add_size(realloc_head, r);
} }
} }
align = 0; align = 0;
...@@ -681,7 +723,9 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, ...@@ -681,7 +723,9 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
align += aligns[order]; align += aligns[order];
} }
size0 = calculate_memsize(size, min_size, 0, resource_size(b_res), min_align); size0 = calculate_memsize(size, min_size, 0, resource_size(b_res), min_align);
size1 = (!add_head || (add_head && !add_size)) ? size0 : if (children_add_size > add_size)
add_size = children_add_size;
size1 = (!realloc_head || (realloc_head && !add_size)) ? size0 :
calculate_memsize(size, min_size+add_size, 0, calculate_memsize(size, min_size+add_size, 0,
resource_size(b_res), min_align); resource_size(b_res), min_align);
if (!size0 && !size1) { if (!size0 && !size1) {
...@@ -695,12 +739,22 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, ...@@ -695,12 +739,22 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
b_res->start = min_align; b_res->start = min_align;
b_res->end = size0 + min_align - 1; b_res->end = size0 + min_align - 1;
b_res->flags |= IORESOURCE_STARTALIGN | mem64_mask; b_res->flags |= IORESOURCE_STARTALIGN | mem64_mask;
if (size1 > size0 && add_head) if (size1 > size0 && realloc_head)
add_to_list(add_head, bus->self, b_res, size1-size0); add_to_list(realloc_head, bus->self, b_res, size1-size0, min_align);
return 1; return 1;
} }
static void pci_bus_size_cardbus(struct pci_bus *bus) unsigned long pci_cardbus_resource_alignment(struct resource *res)
{
if (res->flags & IORESOURCE_IO)
return pci_cardbus_io_size;
if (res->flags & IORESOURCE_MEM)
return pci_cardbus_mem_size;
return 0;
}
static void pci_bus_size_cardbus(struct pci_bus *bus,
struct resource_list_x *realloc_head)
{ {
struct pci_dev *bridge = bus->self; struct pci_dev *bridge = bus->self;
struct resource *b_res = &bridge->resource[PCI_BRIDGE_RESOURCES]; struct resource *b_res = &bridge->resource[PCI_BRIDGE_RESOURCES];
...@@ -711,12 +765,14 @@ static void pci_bus_size_cardbus(struct pci_bus *bus) ...@@ -711,12 +765,14 @@ static void pci_bus_size_cardbus(struct pci_bus *bus)
* a fixed amount of bus space for CardBus bridges. * a fixed amount of bus space for CardBus bridges.
*/ */
b_res[0].start = 0; b_res[0].start = 0;
b_res[0].end = pci_cardbus_io_size - 1;
b_res[0].flags |= IORESOURCE_IO | IORESOURCE_SIZEALIGN; b_res[0].flags |= IORESOURCE_IO | IORESOURCE_SIZEALIGN;
if (realloc_head)
add_to_list(realloc_head, bridge, b_res, pci_cardbus_io_size, 0 /* dont care */);
b_res[1].start = 0; b_res[1].start = 0;
b_res[1].end = pci_cardbus_io_size - 1;
b_res[1].flags |= IORESOURCE_IO | IORESOURCE_SIZEALIGN; b_res[1].flags |= IORESOURCE_IO | IORESOURCE_SIZEALIGN;
if (realloc_head)
add_to_list(realloc_head, bridge, b_res+1, pci_cardbus_io_size, 0 /* dont care */);
/* /*
* Check whether prefetchable memory is supported * Check whether prefetchable memory is supported
...@@ -736,21 +792,31 @@ static void pci_bus_size_cardbus(struct pci_bus *bus) ...@@ -736,21 +792,31 @@ static void pci_bus_size_cardbus(struct pci_bus *bus)
*/ */
if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0) { if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0) {
b_res[2].start = 0; b_res[2].start = 0;
b_res[2].end = pci_cardbus_mem_size - 1;
b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_SIZEALIGN; b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_SIZEALIGN;
if (realloc_head)
add_to_list(realloc_head, bridge, b_res+2, pci_cardbus_mem_size, 0 /* dont care */);
b_res[3].start = 0; b_res[3].start = 0;
b_res[3].end = pci_cardbus_mem_size - 1;
b_res[3].flags |= IORESOURCE_MEM | IORESOURCE_SIZEALIGN; b_res[3].flags |= IORESOURCE_MEM | IORESOURCE_SIZEALIGN;
if (realloc_head)
add_to_list(realloc_head, bridge, b_res+3, pci_cardbus_mem_size, 0 /* dont care */);
} else { } else {
b_res[3].start = 0; b_res[3].start = 0;
b_res[3].end = pci_cardbus_mem_size * 2 - 1;
b_res[3].flags |= IORESOURCE_MEM | IORESOURCE_SIZEALIGN; b_res[3].flags |= IORESOURCE_MEM | IORESOURCE_SIZEALIGN;
if (realloc_head)
add_to_list(realloc_head, bridge, b_res+3, pci_cardbus_mem_size * 2, 0 /* dont care */);
} }
/* set the size of the resource to zero, so that the resource does not
* get assigned during required-resource allocation cycle but gets assigned
* during the optional-resource allocation cycle.
*/
b_res[0].start = b_res[1].start = b_res[2].start = b_res[3].start = 1;
b_res[0].end = b_res[1].end = b_res[2].end = b_res[3].end = 0;
} }
void __ref __pci_bus_size_bridges(struct pci_bus *bus, void __ref __pci_bus_size_bridges(struct pci_bus *bus,
struct resource_list_x *add_head) struct resource_list_x *realloc_head)
{ {
struct pci_dev *dev; struct pci_dev *dev;
unsigned long mask, prefmask; unsigned long mask, prefmask;
...@@ -763,12 +829,12 @@ void __ref __pci_bus_size_bridges(struct pci_bus *bus, ...@@ -763,12 +829,12 @@ void __ref __pci_bus_size_bridges(struct pci_bus *bus,
switch (dev->class >> 8) { switch (dev->class >> 8) {
case PCI_CLASS_BRIDGE_CARDBUS: case PCI_CLASS_BRIDGE_CARDBUS:
pci_bus_size_cardbus(b); pci_bus_size_cardbus(b, realloc_head);
break; break;
case PCI_CLASS_BRIDGE_PCI: case PCI_CLASS_BRIDGE_PCI:
default: default:
__pci_bus_size_bridges(b, add_head); __pci_bus_size_bridges(b, realloc_head);
break; break;
} }
} }
...@@ -792,7 +858,7 @@ void __ref __pci_bus_size_bridges(struct pci_bus *bus, ...@@ -792,7 +858,7 @@ void __ref __pci_bus_size_bridges(struct pci_bus *bus,
* Follow thru * Follow thru
*/ */
default: default:
pbus_size_io(bus, 0, additional_io_size, add_head); pbus_size_io(bus, 0, additional_io_size, realloc_head);
/* If the bridge supports prefetchable range, size it /* If the bridge supports prefetchable range, size it
separately. If it doesn't, or its prefetchable window separately. If it doesn't, or its prefetchable window
has already been allocated by arch code, try has already been allocated by arch code, try
...@@ -800,11 +866,11 @@ void __ref __pci_bus_size_bridges(struct pci_bus *bus, ...@@ -800,11 +866,11 @@ void __ref __pci_bus_size_bridges(struct pci_bus *bus,
resources. */ resources. */
mask = IORESOURCE_MEM; mask = IORESOURCE_MEM;
prefmask = IORESOURCE_MEM | IORESOURCE_PREFETCH; prefmask = IORESOURCE_MEM | IORESOURCE_PREFETCH;
if (pbus_size_mem(bus, prefmask, prefmask, 0, additional_mem_size, add_head)) if (pbus_size_mem(bus, prefmask, prefmask, 0, additional_mem_size, realloc_head))
mask = prefmask; /* Success, size non-prefetch only. */ mask = prefmask; /* Success, size non-prefetch only. */
else else
additional_mem_size += additional_mem_size; additional_mem_size += additional_mem_size;
pbus_size_mem(bus, mask, IORESOURCE_MEM, 0, additional_mem_size, add_head); pbus_size_mem(bus, mask, IORESOURCE_MEM, 0, additional_mem_size, realloc_head);
break; break;
} }
} }
...@@ -816,20 +882,20 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus) ...@@ -816,20 +882,20 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus)
EXPORT_SYMBOL(pci_bus_size_bridges); EXPORT_SYMBOL(pci_bus_size_bridges);
static void __ref __pci_bus_assign_resources(const struct pci_bus *bus, static void __ref __pci_bus_assign_resources(const struct pci_bus *bus,
struct resource_list_x *add_head, struct resource_list_x *realloc_head,
struct resource_list_x *fail_head) struct resource_list_x *fail_head)
{ {
struct pci_bus *b; struct pci_bus *b;
struct pci_dev *dev; struct pci_dev *dev;
pbus_assign_resources_sorted(bus, add_head, fail_head); pbus_assign_resources_sorted(bus, realloc_head, fail_head);
list_for_each_entry(dev, &bus->devices, bus_list) { list_for_each_entry(dev, &bus->devices, bus_list) {
b = dev->subordinate; b = dev->subordinate;
if (!b) if (!b)
continue; continue;
__pci_bus_assign_resources(b, add_head, fail_head); __pci_bus_assign_resources(b, realloc_head, fail_head);
switch (dev->class >> 8) { switch (dev->class >> 8) {
case PCI_CLASS_BRIDGE_PCI: case PCI_CLASS_BRIDGE_PCI:
...@@ -1039,7 +1105,7 @@ void __init ...@@ -1039,7 +1105,7 @@ void __init
pci_assign_unassigned_resources(void) pci_assign_unassigned_resources(void)
{ {
struct pci_bus *bus; struct pci_bus *bus;
struct resource_list_x add_list; /* list of resources that struct resource_list_x realloc_list; /* list of resources that
want additional resources */ want additional resources */
int tried_times = 0; int tried_times = 0;
enum release_type rel_type = leaf_only; enum release_type rel_type = leaf_only;
...@@ -1052,7 +1118,7 @@ pci_assign_unassigned_resources(void) ...@@ -1052,7 +1118,7 @@ pci_assign_unassigned_resources(void)
head.next = NULL; head.next = NULL;
add_list.next = NULL; realloc_list.next = NULL;
pci_try_num = max_depth + 1; pci_try_num = max_depth + 1;
printk(KERN_DEBUG "PCI: max bus depth: %d pci_try_num: %d\n", printk(KERN_DEBUG "PCI: max bus depth: %d pci_try_num: %d\n",
...@@ -1062,12 +1128,12 @@ pci_assign_unassigned_resources(void) ...@@ -1062,12 +1128,12 @@ pci_assign_unassigned_resources(void)
/* Depth first, calculate sizes and alignments of all /* Depth first, calculate sizes and alignments of all
subordinate buses. */ subordinate buses. */
list_for_each_entry(bus, &pci_root_buses, node) list_for_each_entry(bus, &pci_root_buses, node)
__pci_bus_size_bridges(bus, &add_list); __pci_bus_size_bridges(bus, &realloc_list);
/* Depth last, allocate resources and update the hardware. */ /* Depth last, allocate resources and update the hardware. */
list_for_each_entry(bus, &pci_root_buses, node) list_for_each_entry(bus, &pci_root_buses, node)
__pci_bus_assign_resources(bus, &add_list, &head); __pci_bus_assign_resources(bus, &realloc_list, &head);
BUG_ON(add_list.next); BUG_ON(realloc_list.next);
tried_times++; tried_times++;
/* any device complain? */ /* any device complain? */
......
...@@ -128,16 +128,16 @@ void pci_disable_bridge_window(struct pci_dev *dev) ...@@ -128,16 +128,16 @@ void pci_disable_bridge_window(struct pci_dev *dev)
} }
#endif /* CONFIG_PCI_QUIRKS */ #endif /* CONFIG_PCI_QUIRKS */
static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev, 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; struct resource *res = dev->resource + resno;
resource_size_t size, min, align; resource_size_t min;
int ret; int ret;
size = resource_size(res);
min = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM; min = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM;
align = pci_resource_alignment(dev, res);
/* First, try exact prefetching match.. */ /* First, try exact prefetching match.. */
ret = pci_bus_alloc_resource(bus, res, size, align, min, 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, ...@@ -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, ret = pci_bus_alloc_resource(bus, res, size, align, min, 0,
pcibios_align_resource, dev); pcibios_align_resource, dev);
} }
return ret;
}
if (ret < 0 && dev->fw_addr[resno]) { static int pci_revert_fw_address(struct resource *res, struct pci_dev *dev,
struct resource *root, *conflict; int resno, resource_size_t size)
resource_size_t start, end; {
struct resource *root, *conflict;
resource_size_t start, end;
int ret = 0;
/* if (res->flags & IORESOURCE_IO)
* If we failed to assign anything, let's try the address root = &ioport_resource;
* where firmware left it. That at least has a chance of else
* working, which is better than just leaving it disabled. 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) bus = dev->bus;
root = &ioport_resource; 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 else
root = &iomem_resource; type = "unknown";
dev_info(&dev->dev,
start = res->start; "BAR %d: can't assign %s (size %#llx)\n",
end = res->end; resno, type, (unsigned long long) resource_size(res));
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;
} }
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) { if (!ret) {
res->flags &= ~IORESOURCE_STARTALIGN; res->flags &= ~IORESOURCE_STARTALIGN;
dev_info(&dev->dev, "BAR %d: assigned %pR\n", resno, res); dev_info(&dev->dev, "BAR %d: assigned %pR\n", resno, res);
if (resno < PCI_BRIDGE_RESOURCES) if (resno < PCI_BRIDGE_RESOURCES)
pci_update_resource(dev, resno); pci_update_resource(dev, resno);
} }
return ret; return ret;
} }
int pci_assign_resource(struct pci_dev *dev, int resno) int pci_assign_resource(struct pci_dev *dev, int resno)
{ {
struct resource *res = dev->resource + resno; struct resource *res = dev->resource + resno;
resource_size_t align; resource_size_t align, size;
struct pci_bus *bus; struct pci_bus *bus;
int ret; int ret;
char *type;
align = pci_resource_alignment(dev, res); align = pci_resource_alignment(dev, res);
if (!align) { if (!align) {
...@@ -213,34 +258,27 @@ int pci_assign_resource(struct pci_dev *dev, int resno) ...@@ -213,34 +258,27 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
} }
bus = dev->bus; bus = dev->bus;
while ((ret = __pci_assign_resource(bus, dev, resno))) { size = resource_size(res);
if (bus->parent && bus->self->transparent) ret = _pci_assign_resource(dev, resno, size, align);
bus = bus->parent;
else
bus = NULL;
if (bus)
continue;
break;
}
if (ret) { /*
if (res->flags & IORESOURCE_MEM) * If we failed to assign anything, let's try the address
if (res->flags & IORESOURCE_PREFETCH) * where firmware left it. That at least has a chance of
type = "mem pref"; * working, which is better than just leaving it disabled.
else */
type = "mem"; if (ret < 0 && dev->fw_addr[resno])
else if (res->flags & IORESOURCE_IO) ret = pci_revert_fw_address(res, dev, resno, size);
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 (!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; return ret;
} }
/* Sort resources by alignment */ /* Sort resources by alignment */
void pdev_sort_resources(struct pci_dev *dev, struct resource_list *head) void pdev_sort_resources(struct pci_dev *dev, struct resource_list *head)
{ {
......
...@@ -251,7 +251,8 @@ struct pci_dev { ...@@ -251,7 +251,8 @@ struct pci_dev {
u8 revision; /* PCI revision, low byte of class word */ u8 revision; /* PCI revision, low byte of class word */
u8 hdr_type; /* PCI header type (`multi' flag masked out) */ u8 hdr_type; /* PCI header type (`multi' flag masked out) */
u8 pcie_cap; /* PCI-E capability offset */ 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 rom_base_reg; /* which config register controls the ROM */
u8 pin; /* which interrupt pin this device uses */ u8 pin; /* which interrupt pin this device uses */
...@@ -617,6 +618,16 @@ struct pci_driver { ...@@ -617,6 +618,16 @@ struct pci_driver {
/* these external functions are only available when PCI support is enabled */ /* these external functions are only available when PCI support is enabled */
#ifdef CONFIG_PCI #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; extern struct bus_type pci_bus_type;
/* Do NOT directly access these two variables, unless you are arch specific pci /* 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); ...@@ -796,10 +807,13 @@ int pcix_get_mmrbc(struct pci_dev *dev);
int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc); int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc);
int pcie_get_readrq(struct pci_dev *dev); int pcie_get_readrq(struct pci_dev *dev);
int pcie_set_readrq(struct pci_dev *dev, int rq); 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);
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); 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_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); int pci_select_bars(struct pci_dev *dev, unsigned long flags);
/* ROM control related routines */ /* 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