summaryrefslogtreecommitdiff
path: root/drivers/pci
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-09-07 17:23:00 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-09-07 17:23:00 +0200
commitdcf5b8a7ae4e3875878529597c05f8cac4121515 (patch)
tree0d86567a8feacb35b2a62c1ba6cf6c2fe3be65de /drivers/pci
parent864c971e923f55d3ff5ac3ebc87aab8108d30c8a (diff)
parent7cfc41f8e80f11ffa8382ed1a505154ceffb79c7 (diff)
Merge v6.18.50linux-rolling-lts
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/controller/dwc/pci-meson.c2
-rw-r--r--drivers/pci/controller/pci-hyperv.c1
-rw-r--r--drivers/pci/controller/plda/pcie-plda-host.c52
-rw-r--r--drivers/pci/msi/msi.c10
-rw-r--r--drivers/pci/pci-sysfs.c42
-rw-r--r--drivers/pci/pcie/aer.c29
-rw-r--r--drivers/pci/proc.c16
-rw-r--r--drivers/pci/quirks.c9
8 files changed, 135 insertions, 26 deletions
diff --git a/drivers/pci/controller/dwc/pci-meson.c b/drivers/pci/controller/dwc/pci-meson.c
index 225d887cd0a3..e3fe61ef862b 100644
--- a/drivers/pci/controller/dwc/pci-meson.c
+++ b/drivers/pci/controller/dwc/pci-meson.c
@@ -402,7 +402,7 @@ static int meson_pcie_probe(struct platform_device *pdev)
return PTR_ERR(mp->phy);
}
- mp->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+ mp->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(mp->reset_gpio)) {
dev_err(dev, "get reset gpio failed\n");
return PTR_ERR(mp->reset_gpio);
diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c
index 28b157297487..fff5df771d5b 100644
--- a/drivers/pci/controller/pci-hyperv.c
+++ b/drivers/pci/controller/pci-hyperv.c
@@ -2120,6 +2120,7 @@ static bool hv_pcie_init_dev_msi_info(struct device *dev, struct irq_domain *dom
info->ops->msi_prepare = hv_msi_prepare;
chip->irq_set_affinity = irq_chip_set_affinity_parent;
+ chip->irq_retrigger = irq_chip_retrigger_hierarchy;
if (IS_ENABLED(CONFIG_X86))
chip->flags |= IRQCHIP_MOVE_DEFERRED;
diff --git a/drivers/pci/controller/plda/pcie-plda-host.c b/drivers/pci/controller/plda/pcie-plda-host.c
index 3c2f68383010..dea3d443434c 100644
--- a/drivers/pci/controller/plda/pcie-plda-host.c
+++ b/drivers/pci/controller/plda/pcie-plda-host.c
@@ -419,6 +419,8 @@ static int plda_pcie_init_irq_domains(struct plda_pcie_rp *port)
return plda_allocate_msi_domains(port);
}
+static void plda_pcie_irq_domain_deinit(struct plda_pcie_rp *pcie);
+
int plda_init_interrupts(struct platform_device *pdev,
struct plda_pcie_rp *port,
const struct plda_event *event)
@@ -440,14 +442,17 @@ int plda_init_interrupts(struct platform_device *pdev,
}
port->irq = platform_get_irq(pdev, 0);
- if (port->irq < 0)
- return -ENODEV;
+ if (port->irq < 0) {
+ ret = -ENODEV;
+ goto err_irq_domain_deinit;
+ }
for_each_set_bit(i, &port->events_bitmap, port->num_events) {
event_irq = irq_create_mapping(port->event_domain, i);
if (!event_irq) {
dev_err(dev, "failed to map hwirq %d\n", i);
- return -ENXIO;
+ ret = -ENXIO;
+ goto err_irq_domain_deinit;
}
if (event->request_event_irq)
@@ -459,7 +464,7 @@ int plda_init_interrupts(struct platform_device *pdev,
if (ret) {
dev_err(dev, "failed to request IRQ %d\n", event_irq);
- return ret;
+ goto err_irq_domain_deinit;
}
}
@@ -467,7 +472,8 @@ int plda_init_interrupts(struct platform_device *pdev,
event->intx_event);
if (!port->intx_irq) {
dev_err(dev, "failed to map INTx interrupt\n");
- return -ENXIO;
+ ret = -ENXIO;
+ goto err_irq_domain_deinit;
}
/* Plug the INTx chained handler */
@@ -475,8 +481,11 @@ int plda_init_interrupts(struct platform_device *pdev,
port->msi_irq = irq_create_mapping(port->event_domain,
event->msi_event);
- if (!port->msi_irq)
- return -ENXIO;
+ if (!port->msi_irq) {
+ dev_err(dev, "failed to map MSI interrupt\n");
+ ret = -ENXIO;
+ goto err_irq_domain_deinit;
+ }
/* Plug the MSI chained handler */
irq_set_chained_handler_and_data(port->msi_irq, plda_handle_msi, port);
@@ -485,6 +494,11 @@ int plda_init_interrupts(struct platform_device *pdev,
irq_set_chained_handler_and_data(port->irq, plda_handle_event, port);
return 0;
+
+err_irq_domain_deinit:
+ plda_pcie_irq_domain_deinit(port);
+
+ return ret;
}
EXPORT_SYMBOL_GPL(plda_init_interrupts);
@@ -559,9 +573,27 @@ EXPORT_SYMBOL_GPL(plda_pcie_setup_iomems);
static void plda_pcie_irq_domain_deinit(struct plda_pcie_rp *pcie)
{
- irq_set_chained_handler_and_data(pcie->irq, NULL, NULL);
- irq_set_chained_handler_and_data(pcie->msi_irq, NULL, NULL);
- irq_set_chained_handler_and_data(pcie->intx_irq, NULL, NULL);
+ u32 i, event_irq;
+
+ if (pcie->irq > 0)
+ irq_set_chained_handler_and_data(pcie->irq, NULL, NULL);
+ if (pcie->msi_irq > 0)
+ irq_set_chained_handler_and_data(pcie->msi_irq, NULL, NULL);
+ if (pcie->intx_irq > 0)
+ irq_set_chained_handler_and_data(pcie->intx_irq, NULL, NULL);
+
+ for_each_set_bit(i, &pcie->events_bitmap, pcie->num_events) {
+ event_irq = irq_find_mapping(pcie->event_domain, i);
+ if (event_irq) {
+ devm_free_irq(pcie->dev, event_irq, pcie);
+ irq_dispose_mapping(event_irq);
+ }
+ }
+
+ if (pcie->intx_irq)
+ irq_dispose_mapping(pcie->intx_irq);
+ if (pcie->msi_irq)
+ irq_dispose_mapping(pcie->msi_irq);
irq_domain_remove(pcie->msi.dev_domain);
diff --git a/drivers/pci/msi/msi.c b/drivers/pci/msi/msi.c
index 34d664139f48..7e2332869306 100644
--- a/drivers/pci/msi/msi.c
+++ b/drivers/pci/msi/msi.c
@@ -860,6 +860,7 @@ void __pci_restore_msix_state(struct pci_dev *dev)
{
struct msi_desc *entry;
bool write_msg;
+ u16 cmd;
if (!dev->msix_enabled)
return;
@@ -869,6 +870,14 @@ void __pci_restore_msix_state(struct pci_dev *dev)
pci_msix_clear_and_set_ctrl(dev, 0,
PCI_MSIX_FLAGS_ENABLE | PCI_MSIX_FLAGS_MASKALL);
+ /*
+ * The restored device state may not have Memory Space enabled.
+ * Since the MSI-X Table and PBA are in Memory Space, enable it
+ * while restoring them.
+ */
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ pci_write_config_word(dev, PCI_COMMAND, cmd | PCI_COMMAND_MEMORY);
+
write_msg = arch_restore_msi_irqs(dev);
scoped_guard (msi_descs_lock, &dev->dev) {
@@ -879,6 +888,7 @@ void __pci_restore_msix_state(struct pci_dev *dev)
}
}
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
pci_msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_MASKALL, 0);
}
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index edb9bc34c0c5..f3b7f4e410a4 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -723,7 +723,7 @@ static ssize_t pci_read_config(struct file *filp, struct kobject *kobj,
else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
size = 128;
- if (off > size)
+ if (off >= size)
return 0;
if (off + count > size) {
size -= off;
@@ -804,7 +804,7 @@ static ssize_t pci_write_config(struct file *filp, struct kobject *kobj,
add_taint(TAINT_USER, LOCKDEP_STILL_OK);
}
- if (off > dev->cfg_size)
+ if (off >= dev->cfg_size)
return 0;
if (off + count > dev->cfg_size) {
size = dev->cfg_size - off;
@@ -906,12 +906,30 @@ static ssize_t pci_read_legacy_io(struct file *filp, struct kobject *kobj,
char *buf, loff_t off, size_t count)
{
struct pci_bus *bus = to_pci_bus(kobj_to_dev(kobj));
+ u32 val = 0;
+ int ret;
/* Only support 1, 2 or 4 byte accesses */
if (count != 1 && count != 2 && count != 4)
return -EINVAL;
- return pci_legacy_read(bus, off, (u32 *)buf, count);
+ ret = pci_legacy_read(bus, off, &val, count);
+ if (ret < 0)
+ return ret;
+
+ switch (count) {
+ case 1:
+ buf[0] = *(u8 *)&val;
+ break;
+ case 2:
+ put_unaligned_le16(*(u16 *)&val, buf);
+ break;
+ case 4:
+ put_unaligned_le32(val, buf);
+ break;
+ }
+
+ return ret;
}
/**
@@ -931,12 +949,24 @@ static ssize_t pci_write_legacy_io(struct file *filp, struct kobject *kobj,
char *buf, loff_t off, size_t count)
{
struct pci_bus *bus = to_pci_bus(kobj_to_dev(kobj));
+ u32 val;
- /* Only support 1, 2 or 4 byte accesses */
- if (count != 1 && count != 2 && count != 4)
+ /* Only support 1, 2 or 4 byte accesses. */
+ switch (count) {
+ case 1:
+ val = *(u8 *)buf;
+ break;
+ case 2:
+ val = get_unaligned_le16(buf);
+ break;
+ case 4:
+ val = get_unaligned_le32(buf);
+ break;
+ default:
return -EINVAL;
+ }
- return pci_legacy_write(bus, off, *(u32 *)buf, count);
+ return pci_legacy_write(bus, off, val, count);
}
/**
diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
index 85f1f0cf62d6..9f90abe3e88e 100644
--- a/drivers/pci/pcie/aer.c
+++ b/drivers/pci/pcie/aer.c
@@ -427,23 +427,32 @@ void pci_aer_exit(struct pci_dev *dev)
#define AER_AGENT_REQUESTER 1
#define AER_AGENT_COMPLETER 2
#define AER_AGENT_TRANSMITTER 3
+#define AER_AGENT_COMPONENT 4
#define AER_AGENT_REQUESTER_MASK(t) ((t == AER_CORRECTABLE) ? \
- 0 : (PCI_ERR_UNC_COMP_TIME|PCI_ERR_UNC_UNSUP))
+ 0 : PCI_ERR_UNC_COMP_TIME)
#define AER_AGENT_COMPLETER_MASK(t) ((t == AER_CORRECTABLE) ? \
0 : PCI_ERR_UNC_COMP_ABORT)
#define AER_AGENT_TRANSMITTER_MASK(t) ((t == AER_CORRECTABLE) ? \
- (PCI_ERR_COR_REP_ROLL|PCI_ERR_COR_REP_TIMER) : 0)
+ (PCI_ERR_COR_REP_ROLL|PCI_ERR_COR_REP_TIMER) : \
+ (PCI_ERR_UNC_POISON_BLK|PCI_ERR_UNC_ATOMEG| \
+ PCI_ERR_UNC_DMWR_BLK|PCI_ERR_UNC_XLAT_BLK| \
+ PCI_ERR_UNC_TLPPRE))
+#define AER_AGENT_COMPONENT_MASK(t) ((t == AER_CORRECTABLE) ? \
+ (PCI_ERR_COR_INTERNAL|PCI_ERR_COR_LOG_OVER) : \
+ (PCI_ERR_UNC_INTN|PCI_ERR_UNC_SURPDN))
#define AER_GET_AGENT(t, e) \
((e & AER_AGENT_COMPLETER_MASK(t)) ? AER_AGENT_COMPLETER : \
(e & AER_AGENT_REQUESTER_MASK(t)) ? AER_AGENT_REQUESTER : \
(e & AER_AGENT_TRANSMITTER_MASK(t)) ? AER_AGENT_TRANSMITTER : \
+ (e & AER_AGENT_COMPONENT_MASK(t)) ? AER_AGENT_COMPONENT : \
AER_AGENT_RECEIVER)
#define AER_PHYSICAL_LAYER_ERROR 0
#define AER_DATA_LINK_LAYER_ERROR 1
#define AER_TRANSACTION_LAYER_ERROR 2
+#define AER_GENERAL_ERROR 3
#define AER_PHYSICAL_LAYER_ERROR_MASK(t) ((t == AER_CORRECTABLE) ? \
PCI_ERR_COR_RCVR : 0)
@@ -451,11 +460,14 @@ void pci_aer_exit(struct pci_dev *dev)
(PCI_ERR_COR_BAD_TLP| \
PCI_ERR_COR_BAD_DLLP| \
PCI_ERR_COR_REP_ROLL| \
- PCI_ERR_COR_REP_TIMER) : PCI_ERR_UNC_DLP)
+ PCI_ERR_COR_REP_TIMER) : (PCI_ERR_UNC_DLP|PCI_ERR_UNC_SURPDN))
+#define AER_GENERAL_ERROR_MASK(t) ((t == AER_CORRECTABLE) ? \
+ (PCI_ERR_COR_INTERNAL|PCI_ERR_COR_LOG_OVER) : PCI_ERR_UNC_INTN)
#define AER_GET_LAYER_ERROR(t, e) \
((e & AER_PHYSICAL_LAYER_ERROR_MASK(t)) ? AER_PHYSICAL_LAYER_ERROR : \
(e & AER_DATA_LINK_LAYER_ERROR_MASK(t)) ? AER_DATA_LINK_LAYER_ERROR : \
+ (e & AER_GENERAL_ERROR_MASK(t)) ? AER_GENERAL_ERROR : \
AER_TRANSACTION_LAYER_ERROR)
/*
@@ -470,7 +482,8 @@ static const char * const aer_error_severity_string[] = {
static const char *aer_error_layer[] = {
"Physical Layer",
"Data Link Layer",
- "Transaction Layer"
+ "Transaction Layer",
+ "General",
};
static const char *aer_correctable_error_string[] = {
@@ -547,7 +560,8 @@ static const char *aer_agent_string[] = {
"Receiver ID",
"Requester ID",
"Completer ID",
- "Transmitter ID"
+ "Transmitter ID",
+ "Component ID",
};
#define aer_stats_dev_attr(name, stats_array, strings_array, \
@@ -938,7 +952,8 @@ void pci_print_aer(struct pci_dev *dev, int aer_severity,
status = aer->uncor_status;
mask = aer->uncor_mask;
info.level = KERN_ERR;
- tlp_header_valid = tlp_header_logged(status, aer->cap_control);
+ tlp_header_valid = tlp_header_logged(status & ~mask,
+ aer->cap_control);
}
info.status = status;
@@ -1427,7 +1442,7 @@ int aer_get_device_error_info(struct aer_err_info *info, int i)
pci_read_config_dword(dev, aer + PCI_ERR_CAP, &aercc);
info->first_error = PCI_ERR_CAP_FEP(aercc);
- if (tlp_header_logged(info->status, aercc)) {
+ if (tlp_header_logged(info->status & ~info->mask, aercc)) {
info->tlp_header_valid = 1;
pcie_read_tlp_log(dev, aer + PCI_ERR_HEADER_LOG,
aer + PCI_ERR_PREFIX_LOG,
diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
index 9348a0fb8084..005e5b455164 100644
--- a/drivers/pci/proc.c
+++ b/drivers/pci/proc.c
@@ -14,6 +14,8 @@
#include <linux/capability.h>
#include <linux/uaccess.h>
#include <linux/security.h>
+#include <linux/panic.h>
+#include <linux/sched.h>
#include <asm/byteorder.h>
#include "pci.h"
@@ -38,13 +40,16 @@ static ssize_t proc_bus_pci_read(struct file *file, char __user *buf,
* undefined locations (think of Intel PIIX4 as a typical example).
*/
- if (capable(CAP_SYS_ADMIN))
+ if (file_ns_capable(file, &init_user_ns, CAP_SYS_ADMIN))
size = dev->cfg_size;
else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
size = 128;
else
size = 64;
+ if (!nbytes)
+ return 0;
+
if (pos >= size)
return 0;
if (nbytes >= size)
@@ -121,6 +126,15 @@ static ssize_t proc_bus_pci_write(struct file *file, const char __user *buf,
if (ret)
return ret;
+ if (!nbytes)
+ return 0;
+
+ if (resource_is_exclusive(&dev->driver_exclusive_resource, pos, nbytes)) {
+ pci_warn_once(dev, "%s: Unexpected write to kernel-exclusive config offset %x",
+ current->comm, pos);
+ add_taint(TAINT_USER, LOCKDEP_STILL_OK);
+ }
+
if (pos >= size)
return 0;
if (nbytes >= size)
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index f6001be94955..af58057665d9 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -2506,6 +2506,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x10f1, quirk_disable_aspm_l0s);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x10f4, quirk_disable_aspm_l0s);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1508, quirk_disable_aspm_l0s);
+/* Realtek RTS525A generates a Replay Timer Timeout storm when L0s is enabled. */
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_REALTEK, 0x525a, quirk_disable_aspm_l0s);
+
static void quirk_disable_aspm_l0s_l1(struct pci_dev *dev)
{
pcie_aspm_remove_cap(dev,
@@ -5331,7 +5334,7 @@ static void pci_quirk_enable_intel_rp_mpc_acs(struct pci_dev *dev)
if (!(mpc & INTEL_MPC_REG_IRBNCE)) {
pci_info(dev, "Enabling MPC IRBNCE\n");
mpc |= INTEL_MPC_REG_IRBNCE;
- pci_write_config_word(dev, INTEL_MPC_REG, mpc);
+ pci_write_config_dword(dev, INTEL_MPC_REG, mpc);
}
}
@@ -6210,6 +6213,10 @@ DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_PERICOM, 0xb404,
pci_fixup_pericom_acs_store_forward);
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_PERICOM, 0xb404,
pci_fixup_pericom_acs_store_forward);
+DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_PERICOM, 0x2608,
+ pci_fixup_pericom_acs_store_forward);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_PERICOM, 0x2608,
+ pci_fixup_pericom_acs_store_forward);
static void nvidia_ion_ahci_fixup(struct pci_dev *pdev)
{