Skip to content

Commit 53c49b6

Browse files
davejiangbjorn-helgaas
authored andcommitted
PCI/CXL: Add 'cxl_bus' reset method for devices below CXL Ports
By default Secondary Bus Reset (SBR) is masked for CXL Ports (see CXL r3.1, sec 8.1.5.2). Add cxl_reset_bus_function() (method "cxl_bus") to set the "Unmask SBR" bit in the upstream CXL Port before performing the bus reset and restore the original value afterwards. This method allows the user to perform a bus reset on a CXL device without needing to set the "Unmask SBR" bit via a user tool. Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Dave Jiang <[email protected]> [bhelgaas: simplify commit log, invert condition to avoid negation] Signed-off-by: Bjorn Helgaas <[email protected]> Reviewed-by: Jonathan Cameron <[email protected]> Reviewed-by: Dan Williams <[email protected]>
1 parent b1956e2 commit 53c49b6

File tree

2 files changed

+40
-1
lines changed

2 files changed

+40
-1
lines changed

drivers/pci/pci.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4980,6 +4980,44 @@ static int pci_reset_bus_function(struct pci_dev *dev, bool probe)
49804980
return pci_parent_bus_reset(dev, probe);
49814981
}
49824982

4983+
static int cxl_reset_bus_function(struct pci_dev *dev, bool probe)
4984+
{
4985+
struct pci_dev *bridge;
4986+
u16 dvsec, reg, val;
4987+
int rc;
4988+
4989+
bridge = pci_upstream_bridge(dev);
4990+
if (!bridge)
4991+
return -ENOTTY;
4992+
4993+
dvsec = cxl_port_dvsec(bridge);
4994+
if (!dvsec)
4995+
return -ENOTTY;
4996+
4997+
if (probe)
4998+
return 0;
4999+
5000+
rc = pci_read_config_word(bridge, dvsec + PCI_DVSEC_CXL_PORT_CTL, &reg);
5001+
if (rc)
5002+
return -ENOTTY;
5003+
5004+
if (reg & PCI_DVSEC_CXL_PORT_CTL_UNMASK_SBR) {
5005+
val = reg;
5006+
} else {
5007+
val = reg | PCI_DVSEC_CXL_PORT_CTL_UNMASK_SBR;
5008+
pci_write_config_word(bridge, dvsec + PCI_DVSEC_CXL_PORT_CTL,
5009+
val);
5010+
}
5011+
5012+
rc = pci_reset_bus_function(dev, probe);
5013+
5014+
if (reg != val)
5015+
pci_write_config_word(bridge, dvsec + PCI_DVSEC_CXL_PORT_CTL,
5016+
reg);
5017+
5018+
return rc;
5019+
}
5020+
49835021
void pci_dev_lock(struct pci_dev *dev)
49845022
{
49855023
/* block PM suspend, driver probe, etc. */
@@ -5064,6 +5102,7 @@ static const struct pci_reset_fn_method pci_reset_fn_methods[] = {
50645102
{ pci_af_flr, .name = "af_flr" },
50655103
{ pci_pm_reset, .name = "pm" },
50665104
{ pci_reset_bus_function, .name = "bus" },
5105+
{ cxl_reset_bus_function, .name = "cxl_bus" },
50675106
};
50685107

50695108
static ssize_t reset_method_show(struct device *dev,

include/linux/pci.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
PCI_STATUS_PARITY)
5252

5353
/* Number of reset methods used in pci_reset_fn_methods array in pci.c */
54-
#define PCI_NUM_RESET_METHODS 7
54+
#define PCI_NUM_RESET_METHODS 8
5555

5656
#define PCI_RESET_PROBE true
5757
#define PCI_RESET_DO_RESET false

0 commit comments

Comments
 (0)