aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYinghai Lu <yinghai@kernel.org>2012-09-17 22:25:34 -0700
committerYinghai Lu <yinghai@kernel.org>2012-09-17 22:25:34 -0700
commitd798967c7aeed6707d70125a6f80c2c82f77a66b (patch)
tree86b9ea7c11716e90c52d1d8ffaa4168bcefec575
parentd5266a6df5ef874c81be39e694627755e5769fde (diff)
downloadlinux-yinghai-d798967c7aeed6707d70125a6f80c2c82f77a66b.tar.gz
PCI: Don't allocate small resource in big empty space.
Use allocate_resource_fit to allocate one fit resource only Signed-off-by: Yinghai Lu <yinghai@kernel.org>
-rw-r--r--drivers/pci/bus.c22
-rw-r--r--drivers/pci/setup-bus.c12
-rw-r--r--drivers/pci/setup-res.c28
-rw-r--r--include/linux/pci.h10
4 files changed, 54 insertions, 18 deletions
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index 264c4522b75b1..197b5d968ae24 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -122,14 +122,14 @@ void __init pci_alloc_high_get_opt(char *str)
* for a specific device resource.
*/
int
-pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
+pci_bus_alloc_resource_fit(struct pci_bus *bus, struct resource *res,
resource_size_t size, resource_size_t align,
resource_size_t min, unsigned int type_mask,
resource_size_t (*alignf)(void *,
const struct resource *,
resource_size_t,
resource_size_t),
- void *alignf_data)
+ void *alignf_data, bool fit)
{
int i, ret = -ENOMEM;
struct resource *r;
@@ -177,10 +177,10 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
again:
/* Ok, try it out.. */
- ret = allocate_resource(r, res, size,
+ ret = allocate_resource_fit(r, res, size,
max(start, r->start ? : min),
end, align,
- alignf, alignf_data);
+ alignf, alignf_data, fit);
if (ret == 0)
return 0;
@@ -196,6 +196,20 @@ again:
void __weak pcibios_resource_survey_bus(struct pci_bus *bus) { }
+int
+pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
+ resource_size_t size, resource_size_t align,
+ resource_size_t min, unsigned int type_mask,
+ resource_size_t (*alignf)(void *,
+ const struct resource *,
+ resource_size_t,
+ resource_size_t),
+ void *alignf_data)
+{
+ return pci_bus_alloc_resource_fit(bus, res, size, align, min, type_mask,
+ alignf, alignf_data, false);
+}
+
/**
* pci_bus_add_device - add a single device
* @dev: device to add
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index e779bdeef4732..67c2d40b48178 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -273,7 +273,7 @@ out:
* requests that could not satisfied to the failed_list.
*/
static void assign_requested_resources_sorted(struct list_head *head,
- struct list_head *fail_head)
+ struct list_head *fail_head, bool fit)
{
struct resource *res;
struct pci_dev_resource *dev_res;
@@ -283,7 +283,7 @@ static void assign_requested_resources_sorted(struct list_head *head,
res = dev_res->res;
idx = pci_dev_resource_idx(dev_res->dev, res);
if (resource_size(res) &&
- pci_assign_resource(dev_res->dev, idx)) {
+ pci_assign_resource_fit(dev_res->dev, idx, fit)) {
if (fail_head) {
/*
* if the failed res is for ROM BAR, and it will
@@ -318,6 +318,7 @@ static void __assign_resources_sorted(struct list_head *head,
LIST_HEAD(local_fail_head);
struct pci_dev_resource *save_res;
struct pci_dev_resource *dev_res;
+ bool fit = true;
/* Check if optional add_size is there */
if (!realloc_head || list_empty(realloc_head))
@@ -337,7 +338,7 @@ static void __assign_resources_sorted(struct list_head *head,
dev_res->res);
/* Try updated head list with add_size added */
- assign_requested_resources_sorted(head, &local_fail_head);
+ assign_requested_resources_sorted(head, &local_fail_head, fit);
/* all assigned with add_size ? */
if (list_empty(&local_fail_head)) {
@@ -364,9 +365,12 @@ static void __assign_resources_sorted(struct list_head *head,
}
free_list(&save_head);
+ /* will need to expand later, so not use fit */
+ fit = false;
+
requested_and_reassign:
/* Satisfy the must-have resource requests */
- assign_requested_resources_sorted(head, fail_head);
+ assign_requested_resources_sorted(head, fail_head, fit);
/* Try to satisfy any additional optional resource
requests */
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
index 6a85dcf8522b9..1a004ef51c8c7 100644
--- a/drivers/pci/setup-res.c
+++ b/drivers/pci/setup-res.c
@@ -210,7 +210,8 @@ static int pci_revert_fw_address(struct resource *res, struct pci_dev *dev,
}
static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev,
- int resno, resource_size_t size, resource_size_t align)
+ int resno, resource_size_t size, resource_size_t align,
+ bool fit)
{
struct resource *res = pci_dev_resource_n(dev, resno);
resource_size_t min;
@@ -219,9 +220,9 @@ static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev,
min = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM;
/* First, try exact prefetching match.. */
- ret = pci_bus_alloc_resource(bus, res, size, align, min,
+ ret = pci_bus_alloc_resource_fit(bus, res, size, align, min,
IORESOURCE_PREFETCH,
- pcibios_align_resource, dev);
+ pcibios_align_resource, dev, fit);
if (ret < 0 && (res->flags & IORESOURCE_PREFETCH)) {
/*
@@ -230,14 +231,15 @@ static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev,
* But a prefetching area can handle a non-prefetching
* window (it will just not perform as well).
*/
- ret = pci_bus_alloc_resource(bus, res, size, align, min, 0,
- pcibios_align_resource, dev);
+ ret = pci_bus_alloc_resource_fit(bus, res, size, align, min, 0,
+ pcibios_align_resource, dev, fit);
}
return ret;
}
static int _pci_assign_resource(struct pci_dev *dev, int resno,
- resource_size_t size, resource_size_t min_align)
+ resource_size_t size, resource_size_t min_align,
+ bool fit)
{
struct resource *res = pci_dev_resource_n(dev, resno);
struct pci_bus *bus;
@@ -245,7 +247,8 @@ static int _pci_assign_resource(struct pci_dev *dev, int resno,
char *type;
bus = dev->bus;
- while ((ret = __pci_assign_resource(bus, dev, resno, size, min_align))) {
+ while ((ret = __pci_assign_resource(bus, dev, resno, size,
+ min_align, fit))) {
if (!bus->parent || !bus->self->transparent)
break;
bus = bus->parent;
@@ -269,7 +272,7 @@ static int _pci_assign_resource(struct pci_dev *dev, int resno,
return ret;
}
-int pci_assign_resource(struct pci_dev *dev, int resno)
+int pci_assign_resource_fit(struct pci_dev *dev, int resno, bool fit)
{
struct resource *res = pci_dev_resource_n(dev, resno);
resource_size_t align, size;
@@ -285,7 +288,7 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
bus = dev->bus;
size = resource_size(res);
- ret = _pci_assign_resource(dev, resno, size, align);
+ ret = _pci_assign_resource(dev, resno, size, align, fit);
/*
* If we failed to assign anything, let's try the address
@@ -319,7 +322,7 @@ int pci_reassign_resource(struct pci_dev *dev, int resno, resource_size_t addsiz
/* already aligned with min_align */
new_size = resource_size(res) + addsize;
- ret = _pci_assign_resource(dev, resno, new_size, min_align);
+ ret = _pci_assign_resource(dev, resno, new_size, min_align, false);
if (!ret) {
res->flags &= ~IORESOURCE_STARTALIGN;
dev_info(&dev->dev, "BAR %d: reassigned %pR\n", resno, res);
@@ -329,6 +332,11 @@ int pci_reassign_resource(struct pci_dev *dev, int resno, resource_size_t addsiz
return ret;
}
+int pci_assign_resource(struct pci_dev *dev, int resno)
+{
+ return pci_assign_resource_fit(dev, resno, false);
+}
+
int pci_enable_resources(struct pci_dev *dev, int mask)
{
u16 cmd, old_cmd;
diff --git a/include/linux/pci.h b/include/linux/pci.h
index f3181a2bd0fc2..4e52a45579a1c 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -984,6 +984,7 @@ int __pci_reset_function_locked(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_assign_resource_fit(struct pci_dev *dev, int i, bool fit);
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);
@@ -1101,6 +1102,15 @@ int __must_check pci_bus_alloc_resource(struct pci_bus *bus,
resource_size_t,
resource_size_t),
void *alignf_data);
+int __must_check pci_bus_alloc_resource_fit(struct pci_bus *bus,
+ struct resource *res, resource_size_t size,
+ resource_size_t align, resource_size_t min,
+ unsigned int type_mask,
+ resource_size_t (*alignf)(void *,
+ const struct resource *,
+ resource_size_t,
+ resource_size_t),
+ void *alignf_data, bool fit);
void pci_enable_bridges(struct pci_bus *bus);
/* Proper probing supporting hot-pluggable devices */