Skip to content

Commit 83711a1

Browse files
committed
Merge branch 'pci/cxl'
- Lock the upstream bridge while using it to perform a Secondary Bus Reset (Dave Jiang) - Return failure when attempting Secondary Bus Reset below a CXL Port that has SBR masked (Dave Jiang) - Add a "cxl_bus" reset method that temporarily unmasks SBR (Dave Jiang) - Add a warning if we reset a CXL type 3 memory device that was in use while being reset (Dave Jiang) * pci/cxl: cxl: Add post-reset warning if reset results in loss of previously committed HDM decoders PCI/CXL: Add 'cxl_bus' reset method for devices below CXL Ports PCI/CXL: Fail bus reset if upstream CXL Port has SBR masked PCI: Lock upstream bridge for pci_reset_function() PCI/CXL: Move CXL Vendor ID to pci_ids.h
2 parents a6faf3f + 934edcd commit 83711a1

File tree

13 files changed

+175
-8
lines changed

13 files changed

+175
-8
lines changed

drivers/cxl/core/pci.c

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -525,7 +525,7 @@ static int cxl_cdat_get_length(struct device *dev,
525525
__le32 response[2];
526526
int rc;
527527

528-
rc = pci_doe(doe_mb, PCI_DVSEC_VENDOR_ID_CXL,
528+
rc = pci_doe(doe_mb, PCI_VENDOR_ID_CXL,
529529
CXL_DOE_PROTOCOL_TABLE_ACCESS,
530530
&request, sizeof(request),
531531
&response, sizeof(response));
@@ -555,7 +555,7 @@ static int cxl_cdat_read_table(struct device *dev,
555555
__le32 request = CDAT_DOE_REQ(entry_handle);
556556
int rc;
557557

558-
rc = pci_doe(doe_mb, PCI_DVSEC_VENDOR_ID_CXL,
558+
rc = pci_doe(doe_mb, PCI_VENDOR_ID_CXL,
559559
CXL_DOE_PROTOCOL_TABLE_ACCESS,
560560
&request, sizeof(request),
561561
rsp, sizeof(*rsp) + remaining);
@@ -640,7 +640,7 @@ void read_cdat_data(struct cxl_port *port)
640640
if (!pdev)
641641
return;
642642

643-
doe_mb = pci_find_doe_mailbox(pdev, PCI_DVSEC_VENDOR_ID_CXL,
643+
doe_mb = pci_find_doe_mailbox(pdev, PCI_VENDOR_ID_CXL,
644644
CXL_DOE_PROTOCOL_TABLE_ACCESS);
645645
if (!doe_mb) {
646646
dev_dbg(dev, "No CDAT mailbox\n");
@@ -1045,3 +1045,32 @@ long cxl_pci_get_latency(struct pci_dev *pdev)
10451045

10461046
return cxl_flit_size(pdev) * MEGA / bw;
10471047
}
1048+
1049+
static int __cxl_endpoint_decoder_reset_detected(struct device *dev, void *data)
1050+
{
1051+
struct cxl_port *port = data;
1052+
struct cxl_decoder *cxld;
1053+
struct cxl_hdm *cxlhdm;
1054+
void __iomem *hdm;
1055+
u32 ctrl;
1056+
1057+
if (!is_endpoint_decoder(dev))
1058+
return 0;
1059+
1060+
cxld = to_cxl_decoder(dev);
1061+
if ((cxld->flags & CXL_DECODER_F_ENABLE) == 0)
1062+
return 0;
1063+
1064+
cxlhdm = dev_get_drvdata(&port->dev);
1065+
hdm = cxlhdm->regs.hdm_decoder;
1066+
ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(cxld->id));
1067+
1068+
return !FIELD_GET(CXL_HDM_DECODER0_CTRL_COMMITTED, ctrl);
1069+
}
1070+
1071+
bool cxl_endpoint_decoder_reset_detected(struct cxl_port *port)
1072+
{
1073+
return device_for_each_child(&port->dev, port,
1074+
__cxl_endpoint_decoder_reset_detected);
1075+
}
1076+
EXPORT_SYMBOL_NS_GPL(cxl_endpoint_decoder_reset_detected, CXL);

drivers/cxl/core/regs.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ int cxl_find_regblock_instance(struct pci_dev *pdev, enum cxl_regloc_type type,
313313
.resource = CXL_RESOURCE_NONE,
314314
};
315315

316-
regloc = pci_find_dvsec_capability(pdev, PCI_DVSEC_VENDOR_ID_CXL,
316+
regloc = pci_find_dvsec_capability(pdev, PCI_VENDOR_ID_CXL,
317317
CXL_DVSEC_REG_LOCATOR);
318318
if (!regloc)
319319
return -ENXIO;

drivers/cxl/cxl.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -895,6 +895,8 @@ void cxl_coordinates_combine(struct access_coordinate *out,
895895
struct access_coordinate *c1,
896896
struct access_coordinate *c2);
897897

898+
bool cxl_endpoint_decoder_reset_detected(struct cxl_port *port);
899+
898900
/*
899901
* Unit test builds overrides this to __weak, find the 'strong' version
900902
* of these symbols in tools/testing/cxl/.

drivers/cxl/cxlpci.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
* "DVSEC" redundancies removed. When obvious, abbreviations may be used.
1414
*/
1515
#define PCI_DVSEC_HEADER1_LENGTH_MASK GENMASK(31, 20)
16-
#define PCI_DVSEC_VENDOR_ID_CXL 0x1E98
1716

1817
/* CXL 2.0 8.1.3: PCIe DVSEC for CXL Device */
1918
#define CXL_DVSEC_PCIE_DEVICE 0

drivers/cxl/pci.c

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -817,7 +817,7 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
817817
cxlds->rcd = is_cxl_restricted(pdev);
818818
cxlds->serial = pci_get_dsn(pdev);
819819
cxlds->cxl_dvsec = pci_find_dvsec_capability(
820-
pdev, PCI_DVSEC_VENDOR_ID_CXL, CXL_DVSEC_PCIE_DEVICE);
820+
pdev, PCI_VENDOR_ID_CXL, CXL_DVSEC_PCIE_DEVICE);
821821
if (!cxlds->cxl_dvsec)
822822
dev_warn(&pdev->dev,
823823
"Device DVSEC not present, skip CXL.mem init\n");
@@ -957,11 +957,33 @@ static void cxl_error_resume(struct pci_dev *pdev)
957957
dev->driver ? "successful" : "failed");
958958
}
959959

960+
static void cxl_reset_done(struct pci_dev *pdev)
961+
{
962+
struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
963+
struct cxl_memdev *cxlmd = cxlds->cxlmd;
964+
struct device *dev = &pdev->dev;
965+
966+
/*
967+
* FLR does not expect to touch the HDM decoders and related
968+
* registers. SBR, however, will wipe all device configurations.
969+
* Issue a warning if there was an active decoder before the reset
970+
* that no longer exists.
971+
*/
972+
guard(device)(&cxlmd->dev);
973+
if (cxlmd->endpoint &&
974+
cxl_endpoint_decoder_reset_detected(cxlmd->endpoint)) {
975+
dev_crit(dev, "SBR happened without memory regions removal.\n");
976+
dev_crit(dev, "System may be unstable if regions hosted system memory.\n");
977+
add_taint(TAINT_USER, LOCKDEP_STILL_OK);
978+
}
979+
}
980+
960981
static const struct pci_error_handlers cxl_error_handlers = {
961982
.error_detected = cxl_error_detected,
962983
.slot_reset = cxl_slot_reset,
963984
.resume = cxl_error_resume,
964985
.cor_error_detected = cxl_cor_error_detected,
986+
.reset_done = cxl_reset_done,
965987
};
966988

967989
static struct pci_driver cxl_pci_driver = {

drivers/pci/access.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,8 @@ void pci_cfg_access_lock(struct pci_dev *dev)
275275
{
276276
might_sleep();
277277

278+
lock_map_acquire(&dev->cfg_access_lock);
279+
278280
raw_spin_lock_irq(&pci_lock);
279281
if (dev->block_cfg_access)
280282
pci_wait_cfg(dev);
@@ -329,6 +331,8 @@ void pci_cfg_access_unlock(struct pci_dev *dev)
329331
raw_spin_unlock_irqrestore(&pci_lock, flags);
330332

331333
wake_up_all(&pci_cfg_wait);
334+
335+
lock_map_release(&dev->cfg_access_lock);
332336
}
333337
EXPORT_SYMBOL_GPL(pci_cfg_access_unlock);
334338

drivers/pci/pci.c

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4879,6 +4879,7 @@ void __weak pcibios_reset_secondary_bus(struct pci_dev *dev)
48794879
*/
48804880
int pci_bridge_secondary_bus_reset(struct pci_dev *dev)
48814881
{
4882+
lock_map_assert_held(&dev->cfg_access_lock);
48824883
pcibios_reset_secondary_bus(dev);
48834884

48844885
return pci_bridge_wait_for_secondary_bus(dev, "bus reset");
@@ -4927,16 +4928,96 @@ static int pci_dev_reset_slot_function(struct pci_dev *dev, bool probe)
49274928
return pci_reset_hotplug_slot(dev->slot->hotplug, probe);
49284929
}
49294930

4931+
static u16 cxl_port_dvsec(struct pci_dev *dev)
4932+
{
4933+
return pci_find_dvsec_capability(dev, PCI_VENDOR_ID_CXL,
4934+
PCI_DVSEC_CXL_PORT);
4935+
}
4936+
4937+
static bool cxl_sbr_masked(struct pci_dev *dev)
4938+
{
4939+
u16 dvsec, reg;
4940+
int rc;
4941+
4942+
dvsec = cxl_port_dvsec(dev);
4943+
if (!dvsec)
4944+
return false;
4945+
4946+
rc = pci_read_config_word(dev, dvsec + PCI_DVSEC_CXL_PORT_CTL, &reg);
4947+
if (rc || PCI_POSSIBLE_ERROR(reg))
4948+
return false;
4949+
4950+
/*
4951+
* Per CXL spec r3.1, sec 8.1.5.2, when "Unmask SBR" is 0, the SBR
4952+
* bit in Bridge Control has no effect. When 1, the Port generates
4953+
* hot reset when the SBR bit is set to 1.
4954+
*/
4955+
if (reg & PCI_DVSEC_CXL_PORT_CTL_UNMASK_SBR)
4956+
return false;
4957+
4958+
return true;
4959+
}
4960+
49304961
static int pci_reset_bus_function(struct pci_dev *dev, bool probe)
49314962
{
4963+
struct pci_dev *bridge = pci_upstream_bridge(dev);
49324964
int rc;
49334965

4966+
/*
4967+
* If "dev" is below a CXL port that has SBR control masked, SBR
4968+
* won't do anything, so return error.
4969+
*/
4970+
if (bridge && cxl_sbr_masked(bridge)) {
4971+
if (probe)
4972+
return 0;
4973+
4974+
return -ENOTTY;
4975+
}
4976+
49344977
rc = pci_dev_reset_slot_function(dev, probe);
49354978
if (rc != -ENOTTY)
49364979
return rc;
49374980
return pci_parent_bus_reset(dev, probe);
49384981
}
49394982

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+
49405021
void pci_dev_lock(struct pci_dev *dev)
49415022
{
49425023
/* block PM suspend, driver probe, etc. */
@@ -5021,6 +5102,7 @@ static const struct pci_reset_fn_method pci_reset_fn_methods[] = {
50215102
{ pci_af_flr, .name = "af_flr" },
50225103
{ pci_pm_reset, .name = "pm" },
50235104
{ pci_reset_bus_function, .name = "bus" },
5105+
{ cxl_reset_bus_function, .name = "cxl_bus" },
50245106
};
50255107

50265108
static ssize_t reset_method_show(struct device *dev,
@@ -5245,11 +5327,20 @@ void pci_init_reset_methods(struct pci_dev *dev)
52455327
*/
52465328
int pci_reset_function(struct pci_dev *dev)
52475329
{
5330+
struct pci_dev *bridge;
52485331
int rc;
52495332

52505333
if (!pci_reset_supported(dev))
52515334
return -ENOTTY;
52525335

5336+
/*
5337+
* If there's no upstream bridge, no locking is needed since there is
5338+
* no upstream bridge configuration to hold consistent.
5339+
*/
5340+
bridge = pci_upstream_bridge(dev);
5341+
if (bridge)
5342+
pci_dev_lock(bridge);
5343+
52535344
pci_dev_lock(dev);
52545345
pci_dev_save_and_disable(dev);
52555346

@@ -5258,6 +5349,9 @@ int pci_reset_function(struct pci_dev *dev)
52585349
pci_dev_restore(dev);
52595350
pci_dev_unlock(dev);
52605351

5352+
if (bridge)
5353+
pci_dev_unlock(bridge);
5354+
52615355
return rc;
52625356
}
52635357
EXPORT_SYMBOL_GPL(pci_reset_function);

drivers/pci/probe.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2543,6 +2543,9 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
25432543
dev->dev.dma_mask = &dev->dma_mask;
25442544
dev->dev.dma_parms = &dev->dma_parms;
25452545
dev->dev.coherent_dma_mask = 0xffffffffull;
2546+
lockdep_register_key(&dev->cfg_access_key);
2547+
lockdep_init_map(&dev->cfg_access_lock, dev_name(&dev->dev),
2548+
&dev->cfg_access_key, 0);
25462549

25472550
dma_set_max_seg_size(&dev->dev, 65536);
25482551
dma_set_seg_boundary(&dev->dev, 0xffffffff);

drivers/perf/cxl_pmu.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ static ssize_t cxl_pmu_event_sysfs_show(struct device *dev,
345345

346346
/* For CXL spec defined events */
347347
#define CXL_PMU_EVENT_CXL_ATTR(_name, _gid, _msk) \
348-
CXL_PMU_EVENT_ATTR(_name, PCI_DVSEC_VENDOR_ID_CXL, _gid, _msk)
348+
CXL_PMU_EVENT_ATTR(_name, PCI_VENDOR_ID_CXL, _gid, _msk)
349349

350350
static struct attribute *cxl_pmu_event_attrs[] = {
351351
CXL_PMU_EVENT_CXL_ATTR(clock_ticks, CXL_PMU_GID_CLOCK_TICKS, BIT(0)),

include/linux/lockdep.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,9 @@ extern void lock_unpin_lock(struct lockdep_map *lock, struct pin_cookie);
297297
.wait_type_inner = _wait_type, \
298298
.lock_type = LD_LOCK_WAIT_OVERRIDE, }
299299

300+
#define lock_map_assert_held(l) \
301+
lockdep_assert(lock_is_held(l) != LOCK_STATE_NOT_HELD)
302+
300303
#else /* !CONFIG_LOCKDEP */
301304

302305
static inline void lockdep_init_task(struct task_struct *task)
@@ -388,6 +391,8 @@ extern int lockdep_is_held(const void *);
388391
#define DEFINE_WAIT_OVERRIDE_MAP(_name, _wait_type) \
389392
struct lockdep_map __maybe_unused _name = {}
390393

394+
#define lock_map_assert_held(l) do { (void)(l); } while (0)
395+
391396
#endif /* !LOCKDEP */
392397

393398
#ifdef CONFIG_PROVE_LOCKING

0 commit comments

Comments
 (0)