Skip to content

Commit 0da3050

Browse files
committed
Merge branch 'for-7.0/cxl-aer-prep' into cxl-for-next
Fixup and refactor downstream port enumeration to prepare for CXL port protocol error handling. Main motivation is to move endpoint component register mapping to a port object. cxl/port: Unify endpoint and switch port lookup cxl/port: Move endpoint component register management to cxl_port cxl/port: Map Port RAS registers cxl/port: Move dport RAS setup to dport add time cxl/port: Move dport probe operations to a driver event cxl/port: Move decoder setup before dport creation cxl/port: Cleanup dport removal with a devres group cxl/port: Reduce number of @DPORT variables in cxl_port_add_dport() cxl/port: Cleanup handling of the nr_dports 0 -> 1 transition
2 parents 63050be + 2d2b3fe commit 0da3050

15 files changed

Lines changed: 311 additions & 225 deletions

File tree

drivers/cxl/core/core.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,14 @@ int cxl_pci_get_bandwidth(struct pci_dev *pdev, struct access_coordinate *c);
144144
int cxl_port_get_switch_dport_bandwidth(struct cxl_port *port,
145145
struct access_coordinate *c);
146146

147+
static inline struct device *dport_to_host(struct cxl_dport *dport)
148+
{
149+
struct cxl_port *port = dport->port;
150+
151+
if (is_cxl_root(port))
152+
return port->uport_dev;
153+
return &port->dev;
154+
}
147155
#ifdef CONFIG_CXL_RAS
148156
int cxl_ras_init(void);
149157
void cxl_ras_exit(void);
@@ -152,6 +160,7 @@ void cxl_handle_cor_ras(struct device *dev, void __iomem *ras_base);
152160
void cxl_dport_map_rch_aer(struct cxl_dport *dport);
153161
void cxl_disable_rch_root_ints(struct cxl_dport *dport);
154162
void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds);
163+
void devm_cxl_dport_ras_setup(struct cxl_dport *dport);
155164
#else
156165
static inline int cxl_ras_init(void)
157166
{
@@ -166,6 +175,7 @@ static inline void cxl_handle_cor_ras(struct device *dev, void __iomem *ras_base
166175
static inline void cxl_dport_map_rch_aer(struct cxl_dport *dport) { }
167176
static inline void cxl_disable_rch_root_ints(struct cxl_dport *dport) { }
168177
static inline void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds) { }
178+
static inline void devm_cxl_dport_ras_setup(struct cxl_dport *dport) { }
169179
#endif /* CONFIG_CXL_RAS */
170180

171181
int cxl_gpf_port_setup(struct cxl_dport *dport);

drivers/cxl/core/hdm.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1218,12 +1218,12 @@ static int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm,
12181218
}
12191219

12201220
/**
1221-
* __devm_cxl_switch_port_decoders_setup - allocate and setup switch decoders
1221+
* devm_cxl_switch_port_decoders_setup - allocate and setup switch decoders
12221222
* @port: CXL port context
12231223
*
12241224
* Return 0 or -errno on error
12251225
*/
1226-
int __devm_cxl_switch_port_decoders_setup(struct cxl_port *port)
1226+
int devm_cxl_switch_port_decoders_setup(struct cxl_port *port)
12271227
{
12281228
struct cxl_hdm *cxlhdm;
12291229

@@ -1247,7 +1247,7 @@ int __devm_cxl_switch_port_decoders_setup(struct cxl_port *port)
12471247
dev_err(&port->dev, "HDM decoder capability not found\n");
12481248
return -ENXIO;
12491249
}
1250-
EXPORT_SYMBOL_NS_GPL(__devm_cxl_switch_port_decoders_setup, "CXL");
1250+
EXPORT_SYMBOL_NS_GPL(devm_cxl_switch_port_decoders_setup, "CXL");
12511251

12521252
/**
12531253
* devm_cxl_endpoint_decoders_setup - allocate and setup endpoint decoders

drivers/cxl/core/pci.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,14 @@ static int pci_get_port_num(struct pci_dev *pdev)
4141
}
4242

4343
/**
44-
* __devm_cxl_add_dport_by_dev - allocate a dport by dport device
44+
* devm_cxl_add_dport_by_dev - allocate a dport by dport device
4545
* @port: cxl_port that hosts the dport
4646
* @dport_dev: 'struct device' of the dport
4747
*
4848
* Returns the allocated dport on success or ERR_PTR() of -errno on error
4949
*/
50-
struct cxl_dport *__devm_cxl_add_dport_by_dev(struct cxl_port *port,
51-
struct device *dport_dev)
50+
struct cxl_dport *devm_cxl_add_dport_by_dev(struct cxl_port *port,
51+
struct device *dport_dev)
5252
{
5353
struct cxl_register_map map;
5454
struct pci_dev *pdev;
@@ -69,7 +69,7 @@ struct cxl_dport *__devm_cxl_add_dport_by_dev(struct cxl_port *port,
6969
device_lock_assert(&port->dev);
7070
return devm_cxl_add_dport(port, dport_dev, port_num, map.resource);
7171
}
72-
EXPORT_SYMBOL_NS_GPL(__devm_cxl_add_dport_by_dev, "CXL");
72+
EXPORT_SYMBOL_NS_GPL(devm_cxl_add_dport_by_dev, "CXL");
7373

7474
static int cxl_dvsec_mem_range_valid(struct cxl_dev_state *cxlds, int id)
7575
{

drivers/cxl/core/port.c

Lines changed: 101 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -778,14 +778,15 @@ static int cxl_setup_comp_regs(struct device *host, struct cxl_register_map *map
778778
return cxl_setup_regs(map);
779779
}
780780

781-
static int cxl_port_setup_regs(struct cxl_port *port,
781+
int cxl_port_setup_regs(struct cxl_port *port,
782782
resource_size_t component_reg_phys)
783783
{
784784
if (dev_is_platform(port->uport_dev))
785785
return 0;
786786
return cxl_setup_comp_regs(&port->dev, &port->reg_map,
787787
component_reg_phys);
788788
}
789+
EXPORT_SYMBOL_NS_GPL(cxl_port_setup_regs, "CXL");
789790

790791
static int cxl_dport_setup_regs(struct device *host, struct cxl_dport *dport,
791792
resource_size_t component_reg_phys)
@@ -1068,11 +1069,15 @@ static int add_dport(struct cxl_port *port, struct cxl_dport *dport)
10681069
return -EBUSY;
10691070
}
10701071

1072+
/* Arrange for dport_dev to be valid through remove_dport() */
1073+
struct device *dev __free(put_device) = get_device(dport->dport_dev);
1074+
10711075
rc = xa_insert(&port->dports, (unsigned long)dport->dport_dev, dport,
10721076
GFP_KERNEL);
10731077
if (rc)
10741078
return rc;
10751079

1080+
retain_and_null_ptr(dev);
10761081
port->nr_dports++;
10771082
return 0;
10781083
}
@@ -1101,6 +1106,7 @@ static void cxl_dport_remove(void *data)
11011106
struct cxl_dport *dport = data;
11021107
struct cxl_port *port = dport->port;
11031108

1109+
port->nr_dports--;
11041110
xa_erase(&port->dports, (unsigned long) dport->dport_dev);
11051111
put_device(dport->dport_dev);
11061112
}
@@ -1115,6 +1121,48 @@ static void cxl_dport_unlink(void *data)
11151121
sysfs_remove_link(&port->dev.kobj, link_name);
11161122
}
11171123

1124+
static void free_dport(void *dport)
1125+
{
1126+
kfree(dport);
1127+
}
1128+
1129+
/*
1130+
* Upon return either a group is established with one action (free_dport()), or
1131+
* no group established and @dport is freed.
1132+
*/
1133+
static void *cxl_dport_open_dr_group_or_free(struct cxl_dport *dport)
1134+
{
1135+
int rc;
1136+
struct device *host = dport_to_host(dport);
1137+
void *group = devres_open_group(host, dport, GFP_KERNEL);
1138+
1139+
if (!group) {
1140+
kfree(dport);
1141+
return NULL;
1142+
}
1143+
1144+
rc = devm_add_action_or_reset(host, free_dport, dport);
1145+
if (rc) {
1146+
devres_release_group(host, group);
1147+
return NULL;
1148+
}
1149+
1150+
return group;
1151+
}
1152+
1153+
static void cxl_dport_close_dr_group(struct cxl_dport *dport, void *group)
1154+
{
1155+
devres_close_group(dport_to_host(dport), group);
1156+
}
1157+
1158+
static void del_dport(struct cxl_dport *dport)
1159+
{
1160+
devres_release_group(dport_to_host(dport), dport);
1161+
}
1162+
1163+
/* The dport group id is the dport */
1164+
DEFINE_FREE(cxl_dport_release_dr_group, void *, if (_T) del_dport(_T))
1165+
11181166
static struct cxl_dport *
11191167
__devm_cxl_add_dport(struct cxl_port *port, struct device *dport_dev,
11201168
int port_id, resource_size_t component_reg_phys,
@@ -1140,14 +1188,20 @@ __devm_cxl_add_dport(struct cxl_port *port, struct device *dport_dev,
11401188
CXL_TARGET_STRLEN)
11411189
return ERR_PTR(-EINVAL);
11421190

1143-
dport = devm_kzalloc(host, sizeof(*dport), GFP_KERNEL);
1191+
dport = kzalloc(sizeof(*dport), GFP_KERNEL);
11441192
if (!dport)
11451193
return ERR_PTR(-ENOMEM);
11461194

1195+
/* Just enough init to manage the devres group */
11471196
dport->dport_dev = dport_dev;
11481197
dport->port_id = port_id;
11491198
dport->port = port;
11501199

1200+
void *dport_dr_group __free(cxl_dport_release_dr_group) =
1201+
cxl_dport_open_dr_group_or_free(dport);
1202+
if (!dport_dr_group)
1203+
return ERR_PTR(-ENOMEM);
1204+
11511205
if (rcrb == CXL_RESOURCE_NONE) {
11521206
rc = cxl_dport_setup_regs(&port->dev, dport,
11531207
component_reg_phys);
@@ -1183,21 +1237,6 @@ __devm_cxl_add_dport(struct cxl_port *port, struct device *dport_dev,
11831237
if (rc)
11841238
return ERR_PTR(rc);
11851239

1186-
/*
1187-
* Setup port register if this is the first dport showed up. Having
1188-
* a dport also means that there is at least 1 active link.
1189-
*/
1190-
if (port->nr_dports == 1 &&
1191-
port->component_reg_phys != CXL_RESOURCE_NONE) {
1192-
rc = cxl_port_setup_regs(port, port->component_reg_phys);
1193-
if (rc) {
1194-
xa_erase(&port->dports, (unsigned long)dport->dport_dev);
1195-
return ERR_PTR(rc);
1196-
}
1197-
port->component_reg_phys = CXL_RESOURCE_NONE;
1198-
}
1199-
1200-
get_device(dport_dev);
12011240
rc = devm_add_action_or_reset(host, cxl_dport_remove, dport);
12021241
if (rc)
12031242
return ERR_PTR(rc);
@@ -1215,6 +1254,12 @@ __devm_cxl_add_dport(struct cxl_port *port, struct device *dport_dev,
12151254

12161255
cxl_debugfs_create_dport_dir(dport);
12171256

1257+
if (!dport->rch)
1258+
devm_cxl_dport_ras_setup(dport);
1259+
1260+
/* keep the group, and mark the end of devm actions */
1261+
cxl_dport_close_dr_group(dport, no_free_ptr(dport_dr_group));
1262+
12181263
return dport;
12191264
}
12201265

@@ -1441,15 +1486,6 @@ static void delete_switch_port(struct cxl_port *port)
14411486
devm_release_action(port->dev.parent, unregister_port, port);
14421487
}
14431488

1444-
static void del_dport(struct cxl_dport *dport)
1445-
{
1446-
struct cxl_port *port = dport->port;
1447-
1448-
devm_release_action(&port->dev, cxl_dport_unlink, dport);
1449-
devm_release_action(&port->dev, cxl_dport_remove, dport);
1450-
devm_kfree(&port->dev, dport);
1451-
}
1452-
14531489
static void del_dports(struct cxl_port *port)
14541490
{
14551491
struct cxl_dport *dport;
@@ -1556,10 +1592,20 @@ static int match_port_by_uport(struct device *dev, const void *data)
15561592
return 0;
15571593

15581594
port = to_cxl_port(dev);
1595+
/* Endpoint ports are hosted by memdevs */
1596+
if (is_cxl_memdev(port->uport_dev))
1597+
return uport_dev == port->uport_dev->parent;
15591598
return uport_dev == port->uport_dev;
15601599
}
15611600

1562-
/*
1601+
/**
1602+
* find_cxl_port_by_uport - Find a CXL port device companion
1603+
* @uport_dev: Device that acts as a switch or endpoint in the CXL hierarchy
1604+
*
1605+
* In the case of endpoint ports recall that port->uport_dev points to a 'struct
1606+
* cxl_memdev' device. So, the @uport_dev argument is the parent device of the
1607+
* 'struct cxl_memdev' in that case.
1608+
*
15631609
* Function takes a device reference on the port device. Caller should do a
15641610
* put_device() when done.
15651611
*/
@@ -1599,47 +1645,44 @@ static int update_decoder_targets(struct device *dev, void *data)
15991645
return 0;
16001646
}
16011647

1602-
DEFINE_FREE(del_cxl_dport, struct cxl_dport *, if (!IS_ERR_OR_NULL(_T)) del_dport(_T))
1603-
static struct cxl_dport *cxl_port_add_dport(struct cxl_port *port,
1604-
struct device *dport_dev)
1648+
void cxl_port_update_decoder_targets(struct cxl_port *port,
1649+
struct cxl_dport *dport)
16051650
{
1606-
struct cxl_dport *dport;
1607-
int rc;
1651+
device_for_each_child(&port->dev, dport, update_decoder_targets);
1652+
}
1653+
EXPORT_SYMBOL_NS_GPL(cxl_port_update_decoder_targets, "CXL");
16081654

1609-
device_lock_assert(&port->dev);
1610-
if (!port->dev.driver)
1611-
return ERR_PTR(-ENXIO);
1655+
static bool dport_exists(struct cxl_port *port, struct device *dport_dev)
1656+
{
1657+
struct cxl_dport *dport = cxl_find_dport_by_dev(port, dport_dev);
16121658

1613-
dport = cxl_find_dport_by_dev(port, dport_dev);
16141659
if (dport) {
16151660
dev_dbg(&port->dev, "dport%d:%s already exists\n",
16161661
dport->port_id, dev_name(dport_dev));
1617-
return ERR_PTR(-EBUSY);
1662+
return true;
16181663
}
16191664

1620-
struct cxl_dport *new_dport __free(del_cxl_dport) =
1621-
devm_cxl_add_dport_by_dev(port, dport_dev);
1622-
if (IS_ERR(new_dport))
1623-
return new_dport;
1665+
return false;
1666+
}
16241667

1625-
cxl_switch_parse_cdat(new_dport);
1668+
static struct cxl_dport *probe_dport(struct cxl_port *port,
1669+
struct device *dport_dev)
1670+
{
1671+
struct cxl_driver *drv;
16261672

1627-
if (ida_is_empty(&port->decoder_ida)) {
1628-
rc = devm_cxl_switch_port_decoders_setup(port);
1629-
if (rc)
1630-
return ERR_PTR(rc);
1631-
dev_dbg(&port->dev, "first dport%d:%s added with decoders\n",
1632-
new_dport->port_id, dev_name(dport_dev));
1633-
return no_free_ptr(new_dport);
1634-
}
1673+
device_lock_assert(&port->dev);
1674+
if (!port->dev.driver)
1675+
return ERR_PTR(-ENXIO);
16351676

1636-
/* New dport added, update the decoder targets */
1637-
device_for_each_child(&port->dev, new_dport, update_decoder_targets);
1677+
if (dport_exists(port, dport_dev))
1678+
return ERR_PTR(-EBUSY);
16381679

1639-
dev_dbg(&port->dev, "dport%d:%s added\n", new_dport->port_id,
1640-
dev_name(dport_dev));
1680+
drv = container_of(port->dev.driver, struct cxl_driver, drv);
1681+
if (!drv->add_dport)
1682+
return ERR_PTR(-ENXIO);
16411683

1642-
return no_free_ptr(new_dport);
1684+
/* see cxl_port_add_dport() */
1685+
return drv->add_dport(port, dport_dev);
16431686
}
16441687

16451688
static struct cxl_dport *devm_cxl_create_port(struct device *ep_dev,
@@ -1686,7 +1729,7 @@ static struct cxl_dport *devm_cxl_create_port(struct device *ep_dev,
16861729
}
16871730

16881731
guard(device)(&port->dev);
1689-
return cxl_port_add_dport(port, dport_dev);
1732+
return probe_dport(port, dport_dev);
16901733
}
16911734

16921735
static int add_port_attach_ep(struct cxl_memdev *cxlmd,
@@ -1718,7 +1761,7 @@ static int add_port_attach_ep(struct cxl_memdev *cxlmd,
17181761
scoped_guard(device, &parent_port->dev) {
17191762
parent_dport = cxl_find_dport_by_dev(parent_port, dparent);
17201763
if (!parent_dport) {
1721-
parent_dport = cxl_port_add_dport(parent_port, dparent);
1764+
parent_dport = probe_dport(parent_port, dparent);
17221765
if (IS_ERR(parent_dport))
17231766
return PTR_ERR(parent_dport);
17241767
}
@@ -1754,7 +1797,7 @@ static struct cxl_dport *find_or_add_dport(struct cxl_port *port,
17541797
device_lock_assert(&port->dev);
17551798
dport = cxl_find_dport_by_dev(port, dport_dev);
17561799
if (!dport) {
1757-
dport = cxl_port_add_dport(port, dport_dev);
1800+
dport = probe_dport(port, dport_dev);
17581801
if (IS_ERR(dport))
17591802
return dport;
17601803

0 commit comments

Comments
 (0)