@@ -103,6 +103,12 @@ struct role {
103103 const char * dbus_val ;
104104};
105105
106+ // Endpoint poll context for bridged endpoint polling
107+ struct ep_poll_ctx {
108+ struct peer * bridge ;
109+ mctp_eid_t poll_eid ;
110+ };
111+
106112static const struct role roles [] = {
107113 [ENDPOINT_ROLE_UNKNOWN ] = {
108114 .role = ENDPOINT_ROLE_UNKNOWN ,
@@ -201,6 +207,10 @@ struct peer {
201207 // Pool size
202208 uint8_t pool_size ;
203209 uint8_t pool_start ;
210+
211+ struct {
212+ sd_event_source * * sources ;
213+ } bridge_ep_poll ;
204214};
205215
206216struct msg_type_support {
@@ -286,6 +296,7 @@ static int add_peer_from_addr(struct ctx *ctx,
286296 const struct sockaddr_mctp_ext * addr ,
287297 struct peer * * ret_peer );
288298static int remove_peer (struct peer * peer );
299+ static int remove_bridged_peers (struct peer * bridge );
289300static int query_peer_properties (struct peer * peer );
290301static int setup_added_peer (struct peer * peer );
291302static void add_peer_route (struct peer * peer );
@@ -1965,6 +1976,55 @@ static int check_peer_struct(const struct peer *peer, const struct net *n)
19651976 return 0 ;
19661977}
19671978
1979+ static int remove_bridged_peers (struct peer * bridge )
1980+ {
1981+ mctp_eid_t ep , pool_start , pool_end ;
1982+ struct ep_poll_ctx * pctx = NULL ;
1983+ struct peer * peer = NULL ;
1984+ struct net * n = NULL ;
1985+ int rc = 0 ;
1986+
1987+ sd_event_source * * sources = bridge -> bridge_ep_poll .sources ;
1988+ pool_end = bridge -> pool_start + bridge -> pool_size - 1 ;
1989+ n = lookup_net (bridge -> ctx , bridge -> net );
1990+ pool_start = bridge -> pool_start ;
1991+
1992+ if (!sources )
1993+ return 0 ;
1994+
1995+ for (ep = pool_start ; ep <= pool_end ; ep ++ ) {
1996+ // stop endpoint polling before removing peer
1997+ // else next trigger will create peer again.
1998+ int idx = ep - pool_start ;
1999+
2000+ if (sources [idx ]) {
2001+ pctx = sd_event_source_get_userdata (sources [idx ]);
2002+ rc = sd_event_source_set_enabled (sources [idx ],
2003+ SD_EVENT_OFF );
2004+ if (rc < 0 ) {
2005+ warnx ("Failed to stop polling timer while removing peer %d: %s" ,
2006+ ep , strerror (- rc ));
2007+ }
2008+
2009+ sd_event_source_unref (sources [idx ]);
2010+ sources [idx ] = NULL ;
2011+ free (pctx );
2012+ }
2013+ peer = n -> peers [ep ];
2014+ if (!peer )
2015+ continue ;
2016+
2017+ rc = remove_peer (peer );
2018+ if (rc < 0 ) {
2019+ warnx ("Failed to remove peer %d from bridge eid %d pool [%d - %d]: %s" ,
2020+ ep , bridge -> eid , pool_start , pool_end ,
2021+ strerror (- rc ));
2022+ }
2023+ }
2024+
2025+ return 0 ;
2026+ }
2027+
19682028static int remove_peer (struct peer * peer )
19692029{
19702030 struct ctx * ctx = peer -> ctx ;
@@ -1999,6 +2059,12 @@ static int remove_peer(struct peer *peer)
19992059 sd_event_source_unref (peer -> recovery .source );
20002060 }
20012061
2062+ if (peer -> pool_size ) {
2063+ remove_bridged_peers (peer );
2064+ free (peer -> bridge_ep_poll .sources );
2065+ peer -> bridge_ep_poll .sources = NULL ;
2066+ }
2067+
20022068 n -> peers [peer -> eid ] = NULL ;
20032069 free (peer -> message_types );
20042070 free (peer -> uuid );
@@ -2045,6 +2111,7 @@ static void free_peers(struct ctx *ctx)
20452111 free (peer -> message_types );
20462112 free (peer -> uuid );
20472113 free (peer -> path );
2114+ free (peer -> bridge_ep_poll .sources );
20482115 sd_bus_slot_unref (peer -> slot_obmc_endpoint );
20492116 sd_bus_slot_unref (peer -> slot_cc_endpoint );
20502117 sd_bus_slot_unref (peer -> slot_bridge );
@@ -2374,8 +2441,10 @@ static int query_get_endpoint_id(struct ctx *ctx, const dest_phys *dest,
23742441 resp = (void * )buf ;
23752442
23762443 * ret_eid = resp -> eid ;
2377- * ret_ep_type = resp -> eid_type ;
2378- * ret_media_spec = resp -> medium_data ;
2444+ if (ret_ep_type )
2445+ * ret_ep_type = resp -> eid_type ;
2446+ if (ret_media_spec )
2447+ * ret_media_spec = resp -> medium_data ;
23792448out :
23802449 free (buf );
23812450 return rc ;
@@ -5205,6 +5274,161 @@ static int endpoint_send_allocate_endpoint_ids(
52055274 return rc ;
52065275}
52075276
5277+ /* DSP0236 section 8.17.6 Reclaiming EIDs from hot-plug devices
5278+ *
5279+ * The bus owner/bridge can detect a removed device or devices by
5280+ * validating the EIDs that are presently allocated to endpoints that
5281+ * are directly on the bus and identifying which EIDs are missing.
5282+ * It can do this by attempting to access each endpoint that the bridge
5283+ * has listed in its routing table as being a device that is directly on
5284+ * the particular bus. Attempting to access each endpoint can be accomplished
5285+ * by issuing the Get Endpoint ID command...
5286+
5287+
5288+ * since bridged endpoints are routed from bridge, direct query
5289+ * to eid should work if gateway routes are in place.
5290+ */
5291+
5292+ static int peer_reschedule_poll (sd_event_source * source , uint64_t usec )
5293+ {
5294+ int rc = 0 ;
5295+ rc = mctp_ops .sd_event .source_set_time_relative (source , usec );
5296+ if (rc >= 0 ) {
5297+ rc = sd_event_source_set_enabled (source , SD_EVENT_ONESHOT );
5298+ }
5299+
5300+ return 0 ;
5301+ }
5302+
5303+ static int peer_endpoint_poll (sd_event_source * s , uint64_t usec , void * userdata )
5304+ {
5305+ struct ep_poll_ctx * pctx = userdata ;
5306+ struct peer * bridge = pctx -> bridge ;
5307+ sd_event_source * source = NULL ;
5308+ mctp_eid_t ep = pctx -> poll_eid ;
5309+ mctp_eid_t pool_start , idx ;
5310+ struct peer * peer = NULL ;
5311+ mctp_eid_t ret_eid = 0 ;
5312+ struct net * n ;
5313+ int rc = 0 ;
5314+
5315+ if (!bridge ) {
5316+ free (pctx );
5317+ return 0 ;
5318+ }
5319+
5320+ pool_start = bridge -> pool_start ;
5321+ idx = ep - pool_start ;
5322+ source = bridge -> bridge_ep_poll .sources [idx ];
5323+
5324+ /* Polling policy :
5325+ *
5326+ * Once bridge eid pool space is allocated and gateway
5327+ * routes for downstream endpoints are in place, busowner
5328+ * would initiate periodic GET_ENDPOINT_ID command at an
5329+ * interval of atleast 1/2 * TRECLAIM.
5330+
5331+ 1. The downstream endpoint if present behind the bridge,
5332+ responds to send poll command, that endpoint path is
5333+ considered accessible.
5334+ The endpoint path would be published as reachable to d-bus and
5335+ polling will no longer continue.
5336+
5337+ 2. If endpoint is not present or doesn't responds to send poll
5338+ commmand, then it has not been establed yet that endpoint
5339+ path from the bridge is accessible or not, thus continue
5340+ to poll.
5341+ */
5342+
5343+ n = lookup_net (bridge -> ctx , bridge -> net );
5344+ peer = n -> peers [ep ];
5345+ if (!peer ) {
5346+ rc = add_peer (bridge -> ctx , & (bridge -> phys ), ep , bridge -> net ,
5347+ & peer , true);
5348+ if (rc < 0 )
5349+ goto exit ;
5350+ }
5351+
5352+ rc = query_get_endpoint_id (bridge -> ctx , & (bridge -> phys ), & ret_eid , NULL ,
5353+ NULL , peer );
5354+ if (rc < 0 ) {
5355+ if (rc == - ETIMEDOUT ) {
5356+ peer_reschedule_poll (source ,
5357+ bridge -> ctx -> endpoint_poll );
5358+ return 0 ;
5359+ }
5360+ goto exit ;
5361+ }
5362+
5363+ if (ret_eid != ep ) {
5364+ warnx ("Unexpected eid %d abort polling for eid %d" , ret_eid ,
5365+ ep );
5366+ goto exit ;
5367+ }
5368+
5369+ if (bridge -> ctx -> verbose ) {
5370+ fprintf (stderr , "Endpoint %d is accessible\n" , ep );
5371+ }
5372+
5373+ rc = setup_added_peer (peer );
5374+ if (rc < 0 ) {
5375+ peer_reschedule_poll (source , bridge -> ctx -> endpoint_poll );
5376+ return 0 ;
5377+ }
5378+
5379+ exit :
5380+ assert (sd_event_source_get_enabled (source , NULL ) == 0 );
5381+ sd_event_source_unref (source );
5382+ bridge -> bridge_ep_poll .sources [idx ] = NULL ;
5383+ free (pctx );
5384+ return rc ;
5385+ }
5386+
5387+ static int bridge_poll_start (struct peer * bridge )
5388+ {
5389+ mctp_eid_t pool_start = bridge -> pool_start ;
5390+ mctp_eid_t pool_size = bridge -> pool_size ;
5391+ sd_event_source * * sources = NULL ;
5392+ struct ctx * ctx ;
5393+ int rc ;
5394+ int i ;
5395+
5396+ sources = calloc (pool_size , sizeof (* sources ));
5397+ bridge -> bridge_ep_poll .sources = sources ;
5398+ ctx = bridge -> ctx ;
5399+
5400+ if (!sources ) {
5401+ rc = - ENOMEM ;
5402+ warn ("Failed to setup periodic polling for bridge (eid %d)" ,
5403+ bridge -> eid );
5404+ return rc ;
5405+ }
5406+
5407+ for (i = 0 ; i < pool_size ; i ++ ) {
5408+ struct ep_poll_ctx * pctx = calloc (1 , sizeof (* pctx ));
5409+ if (!pctx ) {
5410+ warnx ("Failed to allocate memory, skip polling for eid %d" ,
5411+ pool_start + i );
5412+ continue ;
5413+ }
5414+
5415+ pctx -> bridge = bridge ;
5416+ pctx -> poll_eid = pool_start + i ;
5417+ rc = mctp_ops .sd_event .add_time_relative (
5418+ ctx -> event , & bridge -> bridge_ep_poll .sources [i ],
5419+ CLOCK_MONOTONIC , ctx -> endpoint_poll , 0 ,
5420+ peer_endpoint_poll , pctx );
5421+ if (rc < 0 ) {
5422+ warnx ("Failed to setup poll event source for eid %d" ,
5423+ (pool_start + i ));
5424+ free (pctx );
5425+ continue ;
5426+ }
5427+ }
5428+
5429+ return 0 ;
5430+ }
5431+
52085432static int endpoint_allocate_eids (struct peer * peer )
52095433{
52105434 uint8_t allocated_pool_size = 0 ;
@@ -5273,7 +5497,10 @@ static int endpoint_allocate_eids(struct peer *peer)
52735497 peer -> pool_size );
52745498 }
52755499
5276- // TODO: Polling logic for downstream EID
5500+ // Poll for downstream endpoint accessibility
5501+ if (peer -> ctx -> endpoint_poll ) {
5502+ bridge_poll_start (peer );
5503+ }
52775504
52785505 return 0 ;
52795506}
0 commit comments