@@ -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
790791static 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+
11181166static 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-
14531489static 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
16451688static 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
16921735static 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