+// SPDX-License-Identifier: GPL-2.0
/*
* PCI Bus Services, see include/linux/pci.h for further explanation.
*
}
__setup("pcie_port_pm=", pcie_port_pm_setup);
+/* Time to wait after a reset for device to become responsive */
+#define PCIE_RESET_READY_POLL_MS 60000
+
/**
* pci_bus_max_busnr - returns maximum PCI bus number of given bus' children
* @bus: pointer to PCI bus structure to search
* Make sure the BAR is actually a memory resource, not an IO resource
*/
if (res->flags & IORESOURCE_UNSET || !(res->flags & IORESOURCE_MEM)) {
- dev_warn(&pdev->dev, "can't ioremap BAR %d: %pR\n", bar, res);
+ pci_warn(pdev, "can't ioremap BAR %d: %pR\n", bar, res);
return NULL;
}
return ioremap_nocache(res->start, resource_size(res));
*/
if (state != PCI_D0 && dev->current_state <= PCI_D3cold
&& dev->current_state > state) {
- dev_err(&dev->dev, "invalid power transition (from state %d to %d)\n",
+ pci_err(dev, "invalid power transition (from state %d to %d)\n",
dev->current_state, state);
return -EINVAL;
}
pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
dev->current_state = (pmcsr & PCI_PM_CTRL_STATE_MASK);
if (dev->current_state != state && printk_ratelimit())
- dev_info(&dev->dev, "Refused to change power state, currently in D%d\n",
+ pci_info(dev, "Refused to change power state, currently in D%d\n",
dev->current_state);
/*
case PM_EVENT_HIBERNATE:
return PCI_D3hot;
default:
- dev_info(&dev->dev, "unrecognized suspend event %d\n",
+ pci_info(dev, "unrecognized suspend event %d\n",
state.event);
BUG();
}
save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
if (!save_state) {
- dev_err(&dev->dev, "buffer not found in %s\n", __func__);
+ pci_err(dev, "buffer not found in %s\n", __func__);
return -ENOMEM;
}
save_state = pci_find_saved_cap(dev, PCI_CAP_ID_PCIX);
if (!save_state) {
- dev_err(&dev->dev, "buffer not found in %s\n", __func__);
+ pci_err(dev, "buffer not found in %s\n", __func__);
return -ENOMEM;
}
return;
for (;;) {
- dev_dbg(&pdev->dev, "restoring config space at offset %#x (was %#x, writing %#x)\n",
+ pci_dbg(pdev, "restoring config space at offset %#x (was %#x, writing %#x)\n",
offset, val, saved_val);
pci_write_config_dword(pdev, offset, saved_val);
if (retry-- <= 0)
retval = pci_enable_device(dev);
if (retval)
- dev_err(&dev->dev, "Error enabling bridge (%d), continuing\n",
+ pci_err(dev, "Error enabling bridge (%d), continuing\n",
retval);
pci_set_master(dev);
}
pme_dev = kmalloc(sizeof(struct pci_pme_device),
GFP_KERNEL);
if (!pme_dev) {
- dev_warn(&dev->dev, "can't enable PME#\n");
+ pci_warn(dev, "can't enable PME#\n");
return;
}
pme_dev->dev = dev;
}
}
- dev_dbg(&dev->dev, "PME# %s\n", enable ? "enabled" : "disabled");
+ pci_dbg(dev, "PME# %s\n", enable ? "enabled" : "disabled");
}
EXPORT_SYMBOL(pci_pme_active);
pci_read_config_word(dev, pm + PCI_PM_PMC, &pmc);
if ((pmc & PCI_PM_CAP_VER_MASK) > 3) {
- dev_err(&dev->dev, "unsupported PM cap regs version (%u)\n",
+ pci_err(dev, "unsupported PM cap regs version (%u)\n",
pmc & PCI_PM_CAP_VER_MASK);
return;
}
dev->d2_support = true;
if (dev->d1_support || dev->d2_support)
- dev_printk(KERN_DEBUG, &dev->dev, "supports%s%s\n",
+ pci_printk(KERN_DEBUG, dev, "supports%s%s\n",
dev->d1_support ? " D1" : "",
dev->d2_support ? " D2" : "");
}
pmc &= PCI_PM_CAP_PME_MASK;
if (pmc) {
- dev_printk(KERN_DEBUG, &dev->dev,
- "PME# supported from%s%s%s%s%s\n",
+ pci_printk(KERN_DEBUG, dev, "PME# supported from%s%s%s%s%s\n",
(pmc & PCI_PM_CAP_PME_D0) ? " D0" : "",
(pmc & PCI_PM_CAP_PME_D1) ? " D1" : "",
(pmc & PCI_PM_CAP_PME_D2) ? " D2" : "",
res = pci_ea_get_resource(dev, bei, prop);
if (!res) {
- dev_err(&dev->dev, "Unsupported EA entry BEI: %u\n", bei);
+ pci_err(dev, "Unsupported EA entry BEI: %u\n", bei);
goto out;
}
flags = pci_ea_flags(dev, prop);
if (!flags) {
- dev_err(&dev->dev, "Unsupported EA properties: %#x\n", prop);
+ pci_err(dev, "Unsupported EA properties: %#x\n", prop);
goto out;
}
}
if (end < start) {
- dev_err(&dev->dev, "EA Entry crosses address boundary\n");
+ pci_err(dev, "EA Entry crosses address boundary\n");
goto out;
}
if (ent_size != ent_offset - offset) {
- dev_err(&dev->dev,
- "EA Entry Size (%d) does not match length read (%d)\n",
+ pci_err(dev, "EA Entry Size (%d) does not match length read (%d)\n",
ent_size, ent_offset - offset);
goto out;
}
res->flags = flags;
if (bei <= PCI_EA_BEI_BAR5)
- dev_printk(KERN_DEBUG, &dev->dev, "BAR %d: %pR (from Enhanced Allocation, properties %#02x)\n",
+ pci_printk(KERN_DEBUG, dev, "BAR %d: %pR (from Enhanced Allocation, properties %#02x)\n",
bei, res, prop);
else if (bei == PCI_EA_BEI_ROM)
- dev_printk(KERN_DEBUG, &dev->dev, "ROM: %pR (from Enhanced Allocation, properties %#02x)\n",
+ pci_printk(KERN_DEBUG, dev, "ROM: %pR (from Enhanced Allocation, properties %#02x)\n",
res, prop);
else if (bei >= PCI_EA_BEI_VF_BAR0 && bei <= PCI_EA_BEI_VF_BAR5)
- dev_printk(KERN_DEBUG, &dev->dev, "VF BAR %d: %pR (from Enhanced Allocation, properties %#02x)\n",
+ pci_printk(KERN_DEBUG, dev, "VF BAR %d: %pR (from Enhanced Allocation, properties %#02x)\n",
bei - PCI_EA_BEI_VF_BAR0, res, prop);
else
- dev_printk(KERN_DEBUG, &dev->dev, "BEI %d res: %pR (from Enhanced Allocation, properties %#02x)\n",
+ pci_printk(KERN_DEBUG, dev, "BEI %d res: %pR (from Enhanced Allocation, properties %#02x)\n",
bei, res, prop);
out:
error = pci_add_cap_save_buffer(dev, PCI_CAP_ID_EXP,
PCI_EXP_SAVE_REGS * sizeof(u16));
if (error)
- dev_err(&dev->dev,
- "unable to preallocate PCI Express save buffer\n");
+ pci_err(dev, "unable to preallocate PCI Express save buffer\n");
error = pci_add_cap_save_buffer(dev, PCI_CAP_ID_PCIX, sizeof(u16));
if (error)
- dev_err(&dev->dev,
- "unable to preallocate PCI-X save buffer\n");
+ pci_err(dev, "unable to preallocate PCI-X save buffer\n");
pci_allocate_vc_save_buffers(dev);
}
return 0;
}
+/**
+ * pci_enable_atomic_ops_to_root - enable AtomicOp requests to root port
+ * @dev: the PCI device
+ * @cap_mask: mask of desired AtomicOp sizes, including one or more of:
+ * PCI_EXP_DEVCAP2_ATOMIC_COMP32
+ * PCI_EXP_DEVCAP2_ATOMIC_COMP64
+ * PCI_EXP_DEVCAP2_ATOMIC_COMP128
+ *
+ * Return 0 if all upstream bridges support AtomicOp routing, egress
+ * blocking is disabled on all upstream ports, and the root port supports
+ * the requested completion capabilities (32-bit, 64-bit and/or 128-bit
+ * AtomicOp completion), or negative otherwise.
+ */
+int pci_enable_atomic_ops_to_root(struct pci_dev *dev, u32 cap_mask)
+{
+ struct pci_bus *bus = dev->bus;
+ struct pci_dev *bridge;
+ u32 cap, ctl2;
+
+ if (!pci_is_pcie(dev))
+ return -EINVAL;
+
+ /*
+ * Per PCIe r4.0, sec 6.15, endpoints and root ports may be
+ * AtomicOp requesters. For now, we only support endpoints as
+ * requesters and root ports as completers. No endpoints as
+ * completers, and no peer-to-peer.
+ */
+
+ switch (pci_pcie_type(dev)) {
+ case PCI_EXP_TYPE_ENDPOINT:
+ case PCI_EXP_TYPE_LEG_END:
+ case PCI_EXP_TYPE_RC_END:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ while (bus->parent) {
+ bridge = bus->self;
+
+ pcie_capability_read_dword(bridge, PCI_EXP_DEVCAP2, &cap);
+
+ switch (pci_pcie_type(bridge)) {
+ /* Ensure switch ports support AtomicOp routing */
+ case PCI_EXP_TYPE_UPSTREAM:
+ case PCI_EXP_TYPE_DOWNSTREAM:
+ if (!(cap & PCI_EXP_DEVCAP2_ATOMIC_ROUTE))
+ return -EINVAL;
+ break;
+
+ /* Ensure root port supports all the sizes we care about */
+ case PCI_EXP_TYPE_ROOT_PORT:
+ if ((cap & cap_mask) != cap_mask)
+ return -EINVAL;
+ break;
+ }
+
+ /* Ensure upstream ports don't block AtomicOps on egress */
+ if (!bridge->has_secondary_link) {
+ pcie_capability_read_dword(bridge, PCI_EXP_DEVCTL2,
+ &ctl2);
+ if (ctl2 & PCI_EXP_DEVCTL2_ATOMIC_EGRESS_BLOCK)
+ return -EINVAL;
+ }
+
+ bus = bus->parent;
+ }
+
+ pcie_capability_set_word(dev, PCI_EXP_DEVCTL2,
+ PCI_EXP_DEVCTL2_ATOMIC_REQ);
+ return 0;
+}
+EXPORT_SYMBOL(pci_enable_atomic_ops_to_root);
+
/**
* pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge
* @dev: the PCI device
return 0;
err_out:
- dev_warn(&pdev->dev, "BAR %d: can't reserve %pR\n", bar,
+ pci_warn(pdev, "BAR %d: can't reserve %pR\n", bar,
&pdev->resource[bar]);
return -EBUSY;
}
else
cmd = old_cmd & ~PCI_COMMAND_MASTER;
if (cmd != old_cmd) {
- dev_dbg(&dev->dev, "%s bus mastering\n",
+ pci_dbg(dev, "%s bus mastering\n",
enable ? "enabling" : "disabling");
pci_write_config_word(dev, PCI_COMMAND, cmd);
}
if (cacheline_size == pci_cache_line_size)
return 0;
- dev_printk(KERN_DEBUG, &dev->dev, "cache line size of %d is not supported\n",
+ pci_printk(KERN_DEBUG, dev, "cache line size of %d is not supported\n",
pci_cache_line_size << 2);
return -EINVAL;
pci_read_config_word(dev, PCI_COMMAND, &cmd);
if (!(cmd & PCI_COMMAND_INVALIDATE)) {
- dev_dbg(&dev->dev, "enabling Mem-Wr-Inval\n");
+ pci_dbg(dev, "enabling Mem-Wr-Inval\n");
cmd |= PCI_COMMAND_INVALIDATE;
pci_write_config_word(dev, PCI_COMMAND, cmd);
}
}
EXPORT_SYMBOL(pci_wait_for_pending_transaction);
-static void pci_flr_wait(struct pci_dev *dev)
+static int pci_dev_wait(struct pci_dev *dev, char *reset_type, int timeout)
{
- int delay = 1, timeout = 60000;
+ int delay = 1;
u32 id;
/*
- * Per PCIe r3.1, sec 6.6.2, a device must complete an FLR within
- * 100ms, but may silently discard requests while the FLR is in
- * progress. Wait 100ms before trying to access the device.
- */
- msleep(100);
-
- /*
- * After 100ms, the device should not silently discard config
+ * After reset, the device should not silently discard config
* requests, but it may still indicate that it needs more time by
* responding to them with CRS completions. The Root Port will
* generally synthesize ~0 data to complete the read (except when
pci_read_config_dword(dev, PCI_COMMAND, &id);
while (id == ~0) {
if (delay > timeout) {
- dev_warn(&dev->dev, "not ready %dms after FLR; giving up\n",
- 100 + delay - 1);
- return;
+ pci_warn(dev, "not ready %dms after %s; giving up\n",
+ delay - 1, reset_type);
+ return -ENOTTY;
}
if (delay > 1000)
- dev_info(&dev->dev, "not ready %dms after FLR; waiting\n",
- 100 + delay - 1);
+ pci_info(dev, "not ready %dms after %s; waiting\n",
+ delay - 1, reset_type);
msleep(delay);
delay *= 2;
}
if (delay > 1000)
- dev_info(&dev->dev, "ready %dms after FLR\n", 100 + delay - 1);
+ pci_info(dev, "ready %dms after %s\n", delay - 1,
+ reset_type);
+
+ return 0;
}
/**
* device supports FLR before calling this function, e.g. by using the
* pcie_has_flr() helper.
*/
-void pcie_flr(struct pci_dev *dev)
+int pcie_flr(struct pci_dev *dev)
{
if (!pci_wait_for_pending_transaction(dev))
- dev_err(&dev->dev, "timed out waiting for pending transaction; performing function level reset anyway\n");
+ pci_err(dev, "timed out waiting for pending transaction; performing function level reset anyway\n");
pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_BCR_FLR);
- pci_flr_wait(dev);
+
+ /*
+ * Per PCIe r4.0, sec 6.6.2, a device must complete an FLR within
+ * 100ms, but may silently discard requests while the FLR is in
+ * progress. Wait 100ms before trying to access the device.
+ */
+ msleep(100);
+
+ return pci_dev_wait(dev, "FLR", PCIE_RESET_READY_POLL_MS);
}
EXPORT_SYMBOL_GPL(pcie_flr);
*/
if (!pci_wait_for_pending(dev, pos + PCI_AF_CTRL,
PCI_AF_STATUS_TP << 8))
- dev_err(&dev->dev, "timed out waiting for pending transaction; performing AF function level reset anyway\n");
+ pci_err(dev, "timed out waiting for pending transaction; performing AF function level reset anyway\n");
pci_write_config_byte(dev, pos + PCI_AF_CTRL, PCI_AF_CTRL_FLR);
- pci_flr_wait(dev);
- return 0;
+
+ /*
+ * Per Advanced Capabilities for Conventional PCI ECN, 13 April 2006,
+ * updated 27 July 2006; a device must complete an FLR within
+ * 100ms, but may silently discard requests while the FLR is in
+ * progress. Wait 100ms before trying to access the device.
+ */
+ msleep(100);
+
+ return pci_dev_wait(dev, "AF_FLR", PCIE_RESET_READY_POLL_MS);
}
/**
pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, csr);
pci_dev_d3_sleep(dev);
- return 0;
+ return pci_dev_wait(dev, "PM D3->D0", PCIE_RESET_READY_POLL_MS);
}
void pci_reset_secondary_bus(struct pci_dev *dev)
if (rc != -ENOTTY)
return rc;
if (pcie_has_flr(dev)) {
- pcie_flr(dev);
- return 0;
+ rc = pcie_flr(dev);
+ if (rc != -ENOTTY)
+ return rc;
}
rc = pci_af_flr(dev, 0);
if (rc != -ENOTTY)
{
int rc;
- rc = pci_probe_reset_function(dev);
- if (rc)
- return rc;
+ if (!dev->reset_fn)
+ return -ENOTTY;
pci_dev_lock(dev);
pci_dev_save_and_disable(dev);
{
int rc;
- rc = pci_probe_reset_function(dev);
- if (rc)
- return rc;
+ if (!dev->reset_fn)
+ return -ENOTTY;
pci_dev_save_and_disable(dev);
{
int rc;
- rc = pci_probe_reset_function(dev);
- if (rc)
- return rc;
+ if (!dev->reset_fn)
+ return -ENOTTY;
if (!pci_dev_trylock(dev))
return -EAGAIN;
pci_dev_save_and_disable(dev);
rc = __pci_reset_function_locked(dev);
+ pci_dev_restore(dev);
pci_dev_unlock(dev);
- pci_dev_restore(dev);
return rc;
}
EXPORT_SYMBOL_GPL(pci_try_reset_function);
list_for_each_entry(dev, &slot->bus->devices, bus_list) {
if (!dev->slot || dev->slot != slot)
continue;
+ pci_dev_lock(dev);
pci_dev_restore(dev);
+ pci_dev_unlock(dev);
if (dev->subordinate)
pci_bus_restore(dev->subordinate);
}
dev->dma_alias_mask = kcalloc(BITS_TO_LONGS(U8_MAX),
sizeof(long), GFP_KERNEL);
if (!dev->dma_alias_mask) {
- dev_warn(&dev->dev, "Unable to allocate DMA alias mask\n");
+ pci_warn(dev, "Unable to allocate DMA alias mask\n");
return;
}
set_bit(devfn, dev->dma_alias_mask);
- dev_info(&dev->dev, "Enabling fixed DMA alias to %02x.%d\n",
+ pci_info(dev, "Enabling fixed DMA alias to %02x.%d\n",
PCI_SLOT(devfn), PCI_FUNC(devfn));
}
return;
if (r->flags & IORESOURCE_PCI_FIXED) {
- dev_info(&dev->dev, "BAR%d %pR: ignoring requested alignment %#llx\n",
+ pci_info(dev, "BAR%d %pR: ignoring requested alignment %#llx\n",
bar, r, (unsigned long long)align);
return;
}
* devices and we use the second.
*/
- dev_info(&dev->dev, "BAR%d %pR: requesting alignment to %#llx\n",
+ pci_info(dev, "BAR%d %pR: requesting alignment to %#llx\n",
bar, r, (unsigned long long)align);
if (resize) {
if (dev->hdr_type == PCI_HEADER_TYPE_NORMAL &&
(dev->class >> 8) == PCI_CLASS_BRIDGE_HOST) {
- dev_warn(&dev->dev,
- "Can't reassign resources to host bridge.\n");
+ pci_warn(dev, "Can't reassign resources to host bridge\n");
return;
}
- dev_info(&dev->dev,
- "Disabling memory decoding and releasing memory resources.\n");
+ pci_info(dev, "Disabling memory decoding and releasing memory resources\n");
pci_read_config_word(dev, PCI_COMMAND, &command);
command &= ~PCI_COMMAND_MEMORY;
pci_write_config_word(dev, PCI_COMMAND, command);