]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/pci/pci.c
Merge branch 'pci/host-thunder' into next
[linux.git] / drivers / pci / pci.c
index 3e0557bb02c8a43fad16815effb06883d225115c..b03e91aa8fec5b92e27a22458ab40aada62eb744 100644 (file)
@@ -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
@@ -3471,7 +3572,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);
@@ -4145,35 +4246,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.
@@ -4199,6 +4271,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;
@@ -4264,8 +4344,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 +4380,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.
  *