From 79e699b648b93f76d0f6e692499d5c6a2295ef05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=2E=20Sch=C3=B6nherr?= Date: Wed, 6 Sep 2017 01:21:23 +0200 Subject: PCI: Remove unused function __pci_reset_function() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The last caller of __pci_reset_function() has been removed. Remove the function as well. Signed-off-by: Jan H. Schönherr Signed-off-by: Bjorn Helgaas --- drivers/pci/pci.c | 35 +++-------------------------------- 1 file changed, 3 insertions(+), 32 deletions(-) (limited to 'drivers/pci/pci.c') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 6078dfc11b11..f0d68066c726 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -4145,35 +4145,6 @@ static void pci_dev_restore(struct pci_dev *dev) err_handler->reset_done(dev); } -/** - * __pci_reset_function - reset a PCI device function - * @dev: PCI device to reset - * - * Some devices allow an individual function to be reset without affecting - * other functions in the same device. The PCI device must be responsive - * to PCI config space in order to use this function. - * - * The device function is presumed to be unused when this function is called. - * Resetting the device will make the contents of PCI configuration space - * random, so any caller of this must be prepared to reinitialise the - * device including MSI, bus mastering, BARs, decoding IO and memory spaces, - * etc. - * - * Returns 0 if the device function was successfully reset or negative if the - * device doesn't support resetting a single function. - */ -int __pci_reset_function(struct pci_dev *dev) -{ - int ret; - - pci_dev_lock(dev); - ret = __pci_reset_function_locked(dev); - pci_dev_unlock(dev); - - return ret; -} -EXPORT_SYMBOL_GPL(__pci_reset_function); - /** * __pci_reset_function_locked - reset a PCI device function while holding * the @dev mutex lock. @@ -4264,8 +4235,8 @@ int pci_probe_reset_function(struct pci_dev *dev) * * This function does not just reset the PCI portion of a device, but * clears all the state associated with the device. This function differs - * from __pci_reset_function in that it saves and restores device state - * over the reset. + * from __pci_reset_function_locked() in that it saves and restores device state + * over the reset and takes the PCI device lock. * * Returns 0 if the device function was successfully reset or negative if the * device doesn't support resetting a single function. @@ -4300,7 +4271,7 @@ EXPORT_SYMBOL_GPL(pci_reset_function); * * This function does not just reset the PCI portion of a device, but * clears all the state associated with the device. This function differs - * from __pci_reset_function() in that it saves and restores device state + * from __pci_reset_function_locked() in that it saves and restores device state * over the reset. It also differs from pci_reset_function() in that it * requires the PCI device lock to be held. * -- cgit v1.2.3 From 357027786f3523d26f42391aa4c075b8495e5d28 Mon Sep 17 00:00:00 2001 From: David Daney Date: Fri, 8 Sep 2017 10:10:31 +0200 Subject: PCI: Avoid bus reset if bridge itself is broken When checking to see if a PCI bus can safely be reset, we previously checked to see if any of the children had their PCI_DEV_FLAGS_NO_BUS_RESET flag set. Children marked with that flag are known not to behave well after a bus reset. Some PCIe root port bridges also do not behave well after a bus reset, sometimes causing the devices behind the bridge to become unusable. Add a check for PCI_DEV_FLAGS_NO_BUS_RESET being set in the bridge device to allow these bridges to be flagged, and prevent their secondary buses from being reset. Signed-off-by: David Daney [jglauber@cavium.com: fixed typo] Signed-off-by: Jan Glauber Signed-off-by: Bjorn Helgaas Reviewed-by: Alex Williamson --- drivers/pci/pci.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/pci/pci.c') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 6078dfc11b11..74f1c57ab93b 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -4356,6 +4356,10 @@ static bool pci_bus_resetable(struct pci_bus *bus) { struct pci_dev *dev; + + if (bus->self && (bus->self->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET)) + return false; + list_for_each_entry(dev, &bus->devices, bus_list) { if (dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET || (dev->subordinate && !pci_bus_resetable(dev->subordinate))) -- cgit v1.2.3 From 33ba90aa4d4432b884fc0ed57ba9dc12eb8fa288 Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Fri, 8 Sep 2017 10:10:33 +0200 Subject: PCI: Avoid slot reset if bridge itself is broken When checking to see if a PCI slot can safely be reset, we previously checked to see if any of the children had their PCI_DEV_FLAGS_NO_BUS_RESET flag set. Some PCIe root port bridges do not behave well after a slot reset, and may cause the device in the slot to become unusable. Add a check for PCI_DEV_FLAGS_NO_BUS_RESET being set in the bridge device to prevent the slot from being reset. Signed-off-by: Jan Glauber Signed-off-by: Bjorn Helgaas Reviewed-by: Alex Williamson --- drivers/pci/pci.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/pci/pci.c') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 74f1c57ab93b..3e0557bb02c8 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -4424,6 +4424,10 @@ static bool pci_slot_resetable(struct pci_slot *slot) { struct pci_dev *dev; + if (slot->bus->self && + (slot->bus->self->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET)) + return false; + list_for_each_entry(dev, &slot->bus->devices, bus_list) { if (!dev->slot || dev->slot != slot) continue; -- cgit v1.2.3 From 276b738deb5bf856b9f6049fcd92a967f52643d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Tue, 24 Oct 2017 14:40:20 -0500 Subject: PCI: Add resizable BAR infrastructure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add resizable BAR infrastructure, including defines and helper functions to read the possible sizes of a BAR and update its size. See PCIe r3.1, sec 7.22. Link: https://pcisig.com/sites/default/files/specification_documents/ECN_Resizable-BAR_24Apr2008.pdf Signed-off-by: Christian König [bhelgaas: rename to functions with "rebar" (to match #defines), drop shift #defines, drop "_MASK" suffixes, fix typos, fix kerneldoc] Signed-off-by: Bjorn Helgaas Reviewed-by: Andy Shevchenko --- drivers/pci/pci.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) (limited to 'drivers/pci/pci.c') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 6078dfc11b11..832b96756e83 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -2965,6 +2965,107 @@ bool pci_acs_path_enabled(struct pci_dev *start, return true; } +/** + * pci_rebar_find_pos - find position of resize ctrl reg for BAR + * @pdev: PCI device + * @bar: BAR to find + * + * Helper to find the position of the ctrl register for a BAR. + * Returns -ENOTSUPP if resizable BARs are not supported at all. + * Returns -ENOENT if no ctrl register for the BAR could be found. + */ +static int pci_rebar_find_pos(struct pci_dev *pdev, int bar) +{ + unsigned int pos, nbars, i; + u32 ctrl; + + pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_REBAR); + if (!pos) + return -ENOTSUPP; + + 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) { + int bar_idx; + + pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl); + bar_idx = ctrl & PCI_REBAR_CTRL_BAR_IDX; + if (bar_idx == bar) + return pos; + } + + return -ENOENT; +} + +/** + * pci_rebar_get_possible_sizes - get possible sizes for BAR + * @pdev: PCI device + * @bar: BAR to query + * + * Get the possible sizes of a resizable BAR as bitmask defined in the spec + * (bit 0=1MB, bit 19=512GB). Returns 0 if BAR isn't resizable. + */ +u32 pci_rebar_get_possible_sizes(struct pci_dev *pdev, int bar) +{ + int pos; + u32 cap; + + pos = pci_rebar_find_pos(pdev, bar); + if (pos < 0) + return 0; + + pci_read_config_dword(pdev, pos + PCI_REBAR_CAP, &cap); + return (cap & PCI_REBAR_CAP_SIZES) >> 4; +} + +/** + * pci_rebar_get_current_size - get the current size of a BAR + * @pdev: PCI device + * @bar: BAR to set size to + * + * Read the size of a BAR from the resizable BAR config. + * Returns size if found or negative error code. + */ +int pci_rebar_get_current_size(struct pci_dev *pdev, int bar) +{ + int pos; + u32 ctrl; + + pos = pci_rebar_find_pos(pdev, bar); + if (pos < 0) + return pos; + + pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl); + return (ctrl & PCI_REBAR_CTRL_BAR_SIZE) >> 8; +} + +/** + * pci_rebar_set_size - set a new size for a BAR + * @pdev: PCI device + * @bar: BAR to set size to + * @size: new size as defined in the spec (0=1MB, 19=512GB) + * + * Set the new size of a BAR as defined in the spec. + * Returns zero if resizing was successful, error code otherwise. + */ +int pci_rebar_set_size(struct pci_dev *pdev, int bar, int size) +{ + int pos; + u32 ctrl; + + pos = pci_rebar_find_pos(pdev, bar); + if (pos < 0) + return pos; + + pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl); + ctrl &= ~PCI_REBAR_CTRL_BAR_SIZE; + ctrl |= size << 8; + pci_write_config_dword(pdev, pos + PCI_REBAR_CTRL, ctrl); + return 0; +} + /** * pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge * @dev: the PCI device -- cgit v1.2.3 From 832c418a1530afba54fd96a2cca0912ec9036080 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 25 Oct 2017 17:09:24 -0500 Subject: PCI: Document reset method return values The pci_reset_function() path may try several different reset methods: device-specific resets, PCIe Function Level Resets, PCI Advanced Features Function Level Reset, etc. Add a comment about what the return values from these methods mean. If one of the methods fails, in some cases we want to continue and try the next one in the list, but sometimes we want to stop trying. Signed-off-by: Bjorn Helgaas --- drivers/pci/pci.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/pci/pci.c') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index f0d68066c726..3ff0c3c18276 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -4170,6 +4170,14 @@ int __pci_reset_function_locked(struct pci_dev *dev) might_sleep(); + /* + * A reset method returns -ENOTTY if it doesn't support this device + * and we should try the next method. + * + * If it returns 0 (success), we're finished. If it returns any + * other error, we're also finished: this indicates that further + * reset mechanisms might be broken on the device. + */ rc = pci_dev_specific_reset(dev, 0); if (rc != -ENOTTY) return rc; -- cgit v1.2.3 From 505fb74664d534618258f4120d7e110a8b885c87 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 29 Oct 2017 17:07:11 -0700 Subject: PCI: Fix kernel-doc build warning Fix build error in kernel-doc notation: ../drivers/pci/pci.c:3479: ERROR: Unexpected indentation. "::" tells the kernel-doc "reStructuredText" processor that the following block is a literal block of some blob that should be kept as is. Signed-off-by: Randy Dunlap [bhelgaas: add hint about "::" meaning] Signed-off-by: Bjorn Helgaas --- drivers/pci/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/pci/pci.c') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 6078dfc11b11..d50c58d6acd3 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -3471,7 +3471,7 @@ EXPORT_SYMBOL(devm_pci_remap_cfgspace); * All operations are managed and will be undone on driver detach. * * Returns a pointer to the remapped memory or an ERR_PTR() encoded error code - * on failure. Usage example: + * on failure. Usage example:: * * res = platform_get_resource(pdev, IORESOURCE_MEM, 0); * base = devm_pci_remap_cfg_resource(&pdev->dev, res); -- cgit v1.2.3