diff options
author | Yinghai Lu <yinghai@kernel.org> | 2012-09-17 22:25:34 -0700 |
---|---|---|
committer | Yinghai Lu <yinghai@kernel.org> | 2012-09-17 22:25:34 -0700 |
commit | d798967c7aeed6707d70125a6f80c2c82f77a66b (patch) | |
tree | 86b9ea7c11716e90c52d1d8ffaa4168bcefec575 | |
parent | d5266a6df5ef874c81be39e694627755e5769fde (diff) | |
download | linux-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.c | 22 | ||||
-rw-r--r-- | drivers/pci/setup-bus.c | 12 | ||||
-rw-r--r-- | drivers/pci/setup-res.c | 28 | ||||
-rw-r--r-- | include/linux/pci.h | 10 |
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 */ |