From 93c9a7f8793175fdad5c472af5af07f994116a04 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Tue, 19 Jun 2018 16:52:42 -0500 Subject: PCI: Clean up resource allocation in devm_of_pci_get_host_bridge_resources() Instead of first allocating and then freeing memory for struct resource in case we cannot parse a PCI resource from the device tree, work against a local struct and kmemdup() it when we decide to go with it. Suggested-by: Andy Shevchenko Signed-off-by: Jan Kiszka Signed-off-by: Bjorn Helgaas Reviewed-by: Vladimir Zapolskiy --- drivers/pci/of.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/of.c b/drivers/pci/of.c index d088c9147f10..f8686c48e255 100644 --- a/drivers/pci/of.c +++ b/drivers/pci/of.c @@ -266,7 +266,7 @@ int devm_of_pci_get_host_bridge_resources(struct device *dev, struct list_head *resources, resource_size_t *io_base) { struct device_node *dev_node = dev->of_node; - struct resource *res; + struct resource *res, tmp_res; struct resource *bus_range; struct of_pci_range range; struct of_pci_range_parser parser; @@ -320,18 +320,16 @@ int devm_of_pci_get_host_bridge_resources(struct device *dev, if (range.cpu_addr == OF_BAD_ADDR || range.size == 0) continue; - res = devm_kzalloc(dev, sizeof(struct resource), GFP_KERNEL); + err = of_pci_range_to_resource(&range, dev_node, &tmp_res); + if (err) + continue; + + res = devm_kmemdup(dev, &tmp_res, sizeof(tmp_res), GFP_KERNEL); if (!res) { err = -ENOMEM; goto failed; } - err = of_pci_range_to_resource(&range, dev_node, res); - if (err) { - devm_kfree(dev, res); - continue; - } - if (resource_type(res) == IORESOURCE_IO) { if (!io_base) { dev_err(dev, "I/O range found for %pOF. Please provide an io_base pointer to save CPU base address\n", -- cgit From d3252ace0bc652a1a244455556b6a549f969bf99 Mon Sep 17 00:00:00 2001 From: Christian König Date: Fri, 29 Jun 2018 19:54:55 -0500 Subject: PCI: Restore resized BAR state on resume MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resize BARs after resume to the expected size again. BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=199959 Fixes: d6895ad39f3b ("drm/amdgpu: resize VRAM BAR for CPU access v6") Fixes: 276b738deb5b ("PCI: Add resizable BAR infrastructure") Signed-off-by: Christian König Signed-off-by: Bjorn Helgaas CC: stable@vger.kernel.org # v4.15+ --- drivers/pci/pci.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'drivers/pci') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 97acba712e4e..44ccfb31363e 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1171,6 +1171,33 @@ static void pci_restore_config_space(struct pci_dev *pdev) } } +static void pci_restore_rebar_state(struct pci_dev *pdev) +{ + unsigned int pos, nbars, i; + u32 ctrl; + + pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_REBAR); + if (!pos) + return; + + pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl); + nbars = (ctrl & PCI_REBAR_CTRL_NBAR_MASK) >> + PCI_REBAR_CTRL_NBAR_SHIFT; + + for (i = 0; i < nbars; i++, pos += 8) { + struct resource *res; + int bar_idx, size; + + pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl); + bar_idx = ctrl & PCI_REBAR_CTRL_BAR_IDX; + res = pdev->resource + bar_idx; + size = order_base_2((resource_size(res) >> 20) | 1) - 1; + ctrl &= ~PCI_REBAR_CTRL_BAR_SIZE; + ctrl |= size << 8; + pci_write_config_dword(pdev, pos + PCI_REBAR_CTRL, ctrl); + } +} + /** * pci_restore_state - Restore the saved state of a PCI device * @dev: - PCI device that we're dealing with @@ -1186,6 +1213,7 @@ void pci_restore_state(struct pci_dev *dev) pci_restore_pri_state(dev); pci_restore_ats_state(dev); pci_restore_vc_state(dev); + pci_restore_rebar_state(dev); pci_cleanup_aer_error_status_regs(dev); -- cgit From b1277a226d8c519b8c33e23fe68b4e1658f15963 Mon Sep 17 00:00:00 2001 From: Christian König Date: Fri, 29 Jun 2018 19:55:03 -0500 Subject: PCI: Cleanup PCI_REBAR_CTRL_BAR_SHIFT handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cleanup PCI_REBAR_CTRL_BAR_SHIFT handling. That was hard coded instead of properly defined in the header for some reason. Signed-off-by: Christian König Signed-off-by: Bjorn Helgaas --- drivers/pci/pci.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 44ccfb31363e..1b20c4392f09 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1193,7 +1193,7 @@ static void pci_restore_rebar_state(struct pci_dev *pdev) res = pdev->resource + bar_idx; size = order_base_2((resource_size(res) >> 20) | 1) - 1; ctrl &= ~PCI_REBAR_CTRL_BAR_SIZE; - ctrl |= size << 8; + ctrl |= size << PCI_REBAR_CTRL_BAR_SHIFT; pci_write_config_dword(pdev, pos + PCI_REBAR_CTRL, ctrl); } } @@ -3098,7 +3098,7 @@ int pci_rebar_get_current_size(struct pci_dev *pdev, int bar) return pos; pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl); - return (ctrl & PCI_REBAR_CTRL_BAR_SIZE) >> 8; + return (ctrl & PCI_REBAR_CTRL_BAR_SIZE) >> PCI_REBAR_CTRL_BAR_SHIFT; } /** @@ -3121,7 +3121,7 @@ int pci_rebar_set_size(struct pci_dev *pdev, int bar, int size) pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl); ctrl &= ~PCI_REBAR_CTRL_BAR_SIZE; - ctrl |= size << 8; + ctrl |= size << PCI_REBAR_CTRL_BAR_SHIFT; pci_write_config_dword(pdev, pos + PCI_REBAR_CTRL, ctrl); return 0; } -- cgit From 11eb0e0e8dea8b97cff972b09cf6fb033b729dff Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Mon, 4 Jun 2018 22:16:09 -0400 Subject: PCI: Make early dump functionality generic Move early dump functionality into common code so that it is available for all architectures. No need to carry arch-specific reads around as the read hooks are already initialized by the time pci_setup_device() is getting called during scan. Tested-by: Andy Shevchenko Signed-off-by: Sinan Kaya Signed-off-by: Bjorn Helgaas Reviewed-by: Andy Shevchenko --- drivers/pci/pci.c | 5 +++++ drivers/pci/pci.h | 1 + drivers/pci/probe.c | 17 +++++++++++++++++ 3 files changed, 23 insertions(+) (limited to 'drivers/pci') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 1b20c4392f09..e1b0bbd05fa3 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -115,6 +115,9 @@ static bool pcie_ari_disabled; /* If set, the PCIe ATS capability will not be used. */ static bool pcie_ats_disabled; +/* If set, the PCI config space of each device is printed during boot. */ +bool pci_early_dump; + bool pci_ats_disabled(void) { return pcie_ats_disabled; @@ -5833,6 +5836,8 @@ static int __init pci_setup(char *str) pcie_ats_disabled = true; } else if (!strcmp(str, "noaer")) { pci_no_aer(); + } else if (!strcmp(str, "earlydump")) { + pci_early_dump = true; } else if (!strncmp(str, "realloc=", 8)) { pci_realloc_get_opt(str + 8); } else if (!strncmp(str, "realloc", 7)) { diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index c358e7a07f3f..c33265e02c3a 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -7,6 +7,7 @@ #define PCI_VSEC_ID_INTEL_TBT 0x1234 /* Thunderbolt */ extern const unsigned char pcie_link_speed[]; +extern bool pci_early_dump; bool pcie_cap_has_lnkctl(const struct pci_dev *dev); diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index ac876e32de4b..84034a685f83 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1549,6 +1549,20 @@ static int pci_intx_mask_broken(struct pci_dev *dev) return 0; } +static void early_dump_pci_device(struct pci_dev *pdev) +{ + u32 value[256 / 4]; + int i; + + pci_info(pdev, "config space:\n"); + + for (i = 0; i < 256; i += 4) + pci_read_config_dword(pdev, i, &value[i / 4]); + + print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 1, + value, 256, false); +} + /** * pci_setup_device - Fill in class and map information of a device * @dev: the device structure to fill @@ -1598,6 +1612,9 @@ int pci_setup_device(struct pci_dev *dev) pci_printk(KERN_DEBUG, dev, "[%04x:%04x] type %02x class %#08x\n", dev->vendor, dev->device, dev->hdr_type, dev->class); + if (pci_early_dump) + early_dump_pci_device(dev); + /* Need to have dev->class ready */ dev->cfg_size = pci_cfg_space_size(dev); -- cgit From 445ec321e71b3124abacfb358f72ac6a70d87602 Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Tue, 5 Jun 2018 09:46:45 +0800 Subject: PCI: Avoid accessing memory outside the ROM BAR pci_get_rom_size() accepts the base and size of the ROM BAR as arguments. The byte at "rom + size" is the first byte *past* the ROM, so change ">" to ">=" to avoid accessing beyond the actual length of the ROM BAR. Signed-off-by: Rex Zhu [bhelgaas: changelog] Signed-off-by: Bjorn Helgaas Reviewed-by: Alex Deucher --- drivers/pci/rom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/pci') diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c index a7b5c37a85ec..946795fc0071 100644 --- a/drivers/pci/rom.c +++ b/drivers/pci/rom.c @@ -106,7 +106,7 @@ size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom, size_t size) length = readw(pds + 16); image += length * 512; /* Avoid iterating through memory outside the resource window */ - if (image > rom + size) + if (image >= rom + size) break; } while (length && !last_image); -- cgit From beced88e6af43c9653cee09f5111ae7495824e07 Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Tue, 5 Jun 2018 09:46:46 +0800 Subject: PCI: Add check code for last image indicator not set If the "last image" indicator was not set in the PCI data struct, print "No more image in the PCI ROM" instead of looping back and printing "Invalid PCI ROM header signature". Signed-off-by: Rex Zhu Signed-off-by: Bjorn Helgaas Reviewed-by: Alex Deucher --- drivers/pci/rom.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/pci') diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c index 946795fc0071..3a33f5ce314a 100644 --- a/drivers/pci/rom.c +++ b/drivers/pci/rom.c @@ -108,6 +108,12 @@ size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom, size_t size) /* Avoid iterating through memory outside the resource window */ if (image >= rom + size) break; + if (!last_image) { + if (readw(image) != 0xAA55) { + pci_info(pdev, "No more image in the PCI ROM\n"); + break; + } + } } while (length && !last_image); /* never return a size larger than the PCI resource window */ -- cgit From 783e84961b1d7a75045383586b8c49e02b7704cd Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 29 Jun 2018 21:17:26 -0500 Subject: PCI: Make pci_get_rom_size() static pci_get_rom_size() is called only from pci_map_rom(), so it can be static. Make it static and remove the declaration from include/linux/pci.h. Signed-off-by: Bjorn Helgaas --- drivers/pci/rom.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/pci') diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c index 3a33f5ce314a..137bf0cee897 100644 --- a/drivers/pci/rom.c +++ b/drivers/pci/rom.c @@ -80,7 +80,8 @@ EXPORT_SYMBOL_GPL(pci_disable_rom); * The PCI window size could be much larger than the * actual image size. */ -size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom, size_t size) +static size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom, + size_t size) { void __iomem *image; int last_image; -- cgit