@@ -105,6 +105,12 @@ struct role {
105105 const char * dbus_val ;
106106};
107107
108+ // Endpoint poll context for bridged endpoint polling
109+ struct ep_poll_ctx {
110+ struct peer * bridge ;
111+ mctp_eid_t poll_eid ;
112+ };
113+
108114static const struct role roles [] = {
109115 [ENDPOINT_ROLE_UNKNOWN ] = {
110116 .role = ENDPOINT_ROLE_UNKNOWN ,
@@ -203,6 +209,10 @@ struct peer {
203209 // Pool size
204210 uint8_t pool_size ;
205211 uint8_t pool_start ;
212+
213+ struct {
214+ sd_event_source * * sources ;
215+ } bridge_ep_poll ;
206216};
207217
208218struct msg_type_support {
@@ -288,6 +298,7 @@ static int add_peer_from_addr(struct ctx *ctx,
288298 const struct sockaddr_mctp_ext * addr ,
289299 struct peer * * ret_peer );
290300static int remove_peer (struct peer * peer );
301+ static int remove_bridged_peers (struct peer * bridge );
291302static int query_peer_properties (struct peer * peer );
292303static int setup_added_peer (struct peer * peer );
293304static void add_peer_route (struct peer * peer );
@@ -1983,6 +1994,55 @@ static int check_peer_struct(const struct peer *peer, const struct net *n)
19831994 return 0 ;
19841995}
19851996
1997+ static int remove_bridged_peers (struct peer * bridge )
1998+ {
1999+ mctp_eid_t ep , pool_start , pool_end ;
2000+ struct ep_poll_ctx * pctx = NULL ;
2001+ struct peer * peer = NULL ;
2002+ struct net * n = NULL ;
2003+ int rc = 0 ;
2004+
2005+ sd_event_source * * sources = bridge -> bridge_ep_poll .sources ;
2006+ pool_end = bridge -> pool_start + bridge -> pool_size - 1 ;
2007+ n = lookup_net (bridge -> ctx , bridge -> net );
2008+ pool_start = bridge -> pool_start ;
2009+
2010+ if (!sources )
2011+ return 0 ;
2012+
2013+ for (ep = pool_start ; ep <= pool_end ; ep ++ ) {
2014+ // stop endpoint polling before removing peer
2015+ // else next trigger will create peer again.
2016+ int idx = ep - pool_start ;
2017+
2018+ if (sources [idx ]) {
2019+ pctx = sd_event_source_get_userdata (sources [idx ]);
2020+ rc = sd_event_source_set_enabled (sources [idx ],
2021+ SD_EVENT_OFF );
2022+ if (rc < 0 ) {
2023+ warnx ("Failed to stop polling timer while removing peer %d: %s" ,
2024+ ep , strerror (- rc ));
2025+ }
2026+
2027+ sd_event_source_unref (sources [idx ]);
2028+ sources [idx ] = NULL ;
2029+ free (pctx );
2030+ }
2031+ peer = n -> peers [ep ];
2032+ if (!peer )
2033+ continue ;
2034+
2035+ rc = remove_peer (peer );
2036+ if (rc < 0 ) {
2037+ warnx ("Failed to remove peer %d from bridge eid %d pool [%d - %d]: %s" ,
2038+ ep , bridge -> eid , pool_start , pool_end ,
2039+ strerror (- rc ));
2040+ }
2041+ }
2042+
2043+ return 0 ;
2044+ }
2045+
19862046static int remove_peer (struct peer * peer )
19872047{
19882048 struct ctx * ctx = peer -> ctx ;
@@ -2017,6 +2077,12 @@ static int remove_peer(struct peer *peer)
20172077 sd_event_source_unref (peer -> recovery .source );
20182078 }
20192079
2080+ if (peer -> pool_size ) {
2081+ remove_bridged_peers (peer );
2082+ free (peer -> bridge_ep_poll .sources );
2083+ peer -> bridge_ep_poll .sources = NULL ;
2084+ }
2085+
20202086 n -> peers [peer -> eid ] = NULL ;
20212087 free (peer -> message_types );
20222088 free (peer -> uuid );
@@ -2063,6 +2129,7 @@ static void free_peers(struct ctx *ctx)
20632129 free (peer -> message_types );
20642130 free (peer -> uuid );
20652131 free (peer -> path );
2132+ free (peer -> bridge_ep_poll .sources );
20662133 sd_bus_slot_unref (peer -> slot_obmc_endpoint );
20672134 sd_bus_slot_unref (peer -> slot_cc_endpoint );
20682135 sd_bus_slot_unref (peer -> slot_bridge );
@@ -5263,6 +5330,187 @@ static int endpoint_send_allocate_endpoint_ids(
52635330 return rc ;
52645331}
52655332
5333+ /* DSP0236 section 8.17.6 Reclaiming EIDs from hot-plug devices
5334+ *
5335+ * The bus owner/bridge can detect a removed device or devices by
5336+ * validating the EIDs that are presently allocated to endpoints that
5337+ * are directly on the bus and identifying which EIDs are missing.
5338+ * It can do this by attempting to access each endpoint that the bridge
5339+ * has listed in its routing table as being a device that is directly on
5340+ * the particular bus. Attempting to access each endpoint can be accomplished
5341+ * by issuing the Get Endpoint ID command...
5342+
5343+
5344+ * since bridged endpoints are routed from bridge, direct query
5345+ * to eid should work if gateway routes are in place.
5346+ */
5347+
5348+ static int peer_reschedule_poll (sd_event_source * source , uint64_t usec )
5349+ {
5350+ int rc = 0 ;
5351+ rc = mctp_ops .sd_event .source_set_time_relative (source , usec );
5352+ if (rc >= 0 ) {
5353+ rc = sd_event_source_set_enabled (source , SD_EVENT_ONESHOT );
5354+ }
5355+
5356+ return 0 ;
5357+ }
5358+
5359+ static int peer_endpoint_poll (sd_event_source * s , uint64_t usec , void * userdata )
5360+ {
5361+ struct sockaddr_mctp_ext resp_addr = { 0 };
5362+ struct mctp_ctrl_resp_get_eid * resp = NULL ;
5363+ struct sockaddr_mctp_ext req_addr = { 0 };
5364+ struct mctp_ctrl_cmd_get_eid req = { 0 };
5365+ mctp_eid_t pool_start , idx , ret_eid = 0 ;
5366+ struct ep_poll_ctx * pctx = userdata ;
5367+ struct peer * bridge = pctx -> bridge ;
5368+ sd_event_source * source = NULL ;
5369+ struct peer * peer = NULL ;
5370+ uint8_t * buf = NULL ;
5371+ size_t buf_size ;
5372+ struct net * n ;
5373+ uint8_t iid ;
5374+ int rc = 0 ;
5375+
5376+ if (!bridge ) {
5377+ free (pctx );
5378+ return 0 ;
5379+ }
5380+
5381+ pool_start = bridge -> pool_start ;
5382+ mctp_eid_t ep = pctx -> poll_eid ;
5383+ idx = ep - pool_start ;
5384+ source = bridge -> bridge_ep_poll .sources [idx ];
5385+
5386+ /* Polling policy :
5387+ *
5388+ * Once bridge eid pool space is allocated and gateway
5389+ * routes for downstream endpoints are in place, busowner
5390+ * would initiate periodic GET_ENDPOINT_ID command at an
5391+ * interval of atleast 1/2 * TRECLAIM.
5392+
5393+ 1. The downstream endpoint if present behind the bridge,
5394+ responds to send poll command, that endpoint path is
5395+ considered accessible.
5396+ The endpoint path would be published as reachable to d-bus and
5397+ polling will no longer continue.
5398+
5399+ 2. If endpoint is not present or doesn't responds to send poll
5400+ commmand, then it has not been establed yet that endpoint
5401+ path from the bridge is accessible or not, thus continue
5402+ to poll.
5403+ */
5404+
5405+ req_addr .smctp_base .smctp_type = MCTP_CTRL_HDR_MSG_TYPE ;
5406+ req_addr .smctp_base .smctp_network = bridge -> net ;
5407+ req_addr .smctp_base .smctp_tag = MCTP_TAG_OWNER ;
5408+ req_addr .smctp_base .smctp_family = AF_MCTP ;
5409+ req_addr .smctp_base .smctp_addr .s_addr = ep ;
5410+ iid = mctp_next_iid (bridge -> ctx );
5411+
5412+ mctp_ctrl_msg_hdr_init_req (& req .ctrl_hdr , iid ,
5413+ MCTP_CTRL_CMD_GET_ENDPOINT_ID );
5414+
5415+ rc = endpoint_query_addr (bridge -> ctx , & req_addr , false, & req ,
5416+ sizeof (req ), & buf , & buf_size , & resp_addr );
5417+ if (rc < 0 ) {
5418+ if (rc == - ETIMEDOUT ) {
5419+ free (buf );
5420+ peer_reschedule_poll (source ,
5421+ bridge -> ctx -> endpoint_poll );
5422+ return 0 ;
5423+ }
5424+ goto exit ;
5425+ }
5426+
5427+ resp = (void * )buf ;
5428+ if (!resp ) {
5429+ warnx ("Invalid response buffer" );
5430+ return - ENOMEM ;
5431+ }
5432+
5433+ ret_eid = resp -> eid ;
5434+ if (ret_eid != ep ) {
5435+ warnx ("Unexpected eid %d abort polling for eid %d" , ret_eid ,
5436+ ep );
5437+ goto exit ;
5438+ }
5439+
5440+ if (bridge -> ctx -> verbose ) {
5441+ fprintf (stderr , "Endpoint %d is accessible\n" , ep );
5442+ }
5443+
5444+ n = lookup_net (bridge -> ctx , bridge -> net );
5445+ peer = n -> peers [ep ];
5446+ if (!peer ) {
5447+ rc = add_peer (bridge -> ctx , & (bridge -> phys ), ep , bridge -> net ,
5448+ & peer , true);
5449+ if (rc < 0 )
5450+ goto exit ;
5451+ }
5452+
5453+ rc = setup_added_peer (peer );
5454+ if (rc < 0 ) {
5455+ free (buf );
5456+ peer_reschedule_poll (source , bridge -> ctx -> endpoint_poll );
5457+ return 0 ;
5458+ }
5459+
5460+ exit :
5461+ assert (sd_event_source_get_enabled (source , NULL ) == 0 );
5462+ sd_event_source_unref (source );
5463+ bridge -> bridge_ep_poll .sources [idx ] = NULL ;
5464+ free (pctx );
5465+ free (buf );
5466+ return rc ;
5467+ }
5468+
5469+ static int bridge_poll_start (struct peer * bridge )
5470+ {
5471+ mctp_eid_t pool_start = bridge -> pool_start ;
5472+ mctp_eid_t pool_size = bridge -> pool_size ;
5473+ sd_event_source * * sources = NULL ;
5474+ struct ctx * ctx ;
5475+ int rc ;
5476+ int i ;
5477+
5478+ sources = calloc (pool_size , sizeof (* sources ));
5479+ bridge -> bridge_ep_poll .sources = sources ;
5480+ ctx = bridge -> ctx ;
5481+
5482+ if (!sources ) {
5483+ rc = - ENOMEM ;
5484+ warn ("Failed to setup periodic polling for bridge (eid %d)" ,
5485+ bridge -> eid );
5486+ return rc ;
5487+ }
5488+
5489+ for (i = 0 ; i < pool_size ; i ++ ) {
5490+ struct ep_poll_ctx * pctx = calloc (1 , sizeof (* pctx ));
5491+ if (!pctx ) {
5492+ warnx ("Failed to allocate memory, skip polling for eid %d" ,
5493+ pool_start + i );
5494+ continue ;
5495+ }
5496+
5497+ pctx -> bridge = bridge ;
5498+ pctx -> poll_eid = pool_start + i ;
5499+ rc = mctp_ops .sd_event .add_time_relative (
5500+ ctx -> event , & bridge -> bridge_ep_poll .sources [i ],
5501+ CLOCK_MONOTONIC , ctx -> endpoint_poll , 0 ,
5502+ peer_endpoint_poll , pctx );
5503+ if (rc < 0 ) {
5504+ warnx ("Failed to setup poll event source for eid %d" ,
5505+ (pool_start + i ));
5506+ free (pctx );
5507+ continue ;
5508+ }
5509+ }
5510+
5511+ return 0 ;
5512+ }
5513+
52665514static int endpoint_allocate_eids (struct peer * peer )
52675515{
52685516 uint8_t allocated_pool_size = 0 ;
@@ -5331,7 +5579,10 @@ static int endpoint_allocate_eids(struct peer *peer)
53315579 peer -> pool_size );
53325580 }
53335581
5334- // TODO: Polling logic for downstream EID
5582+ // Poll for downstream endpoint accessibility
5583+ if (peer -> ctx -> endpoint_poll ) {
5584+ bridge_poll_start (peer );
5585+ }
53355586
53365587 return 0 ;
53375588}
0 commit comments