From 0351e9eb5004b17df27e62948cf1b71f880b714e Mon Sep 17 00:00:00 2001
From: Adam Wujek <dev_public@wujek.eu>
Date: Wed, 9 Aug 2023 15:15:25 +0200
Subject: [PATCH] arch-wrs: add support for changing extension in runtime

Signed-off-by: Adam Wujek <dev_public@wujek.eu>
---
 Kconfig_ppsi                    |   6 -
 arch-wrs/include/ppsi-wrs.h     |   2 +
 arch-wrs/include/ppsi_exports.h |   6 +
 arch-wrs/wrs-ipcserver.c        |  49 ++++++
 arch-wrs/wrs-startup.c          | 281 ++++++++++++++++++++++----------
 include/ppsi/pp-instance.h      |  11 ++
 include/ppsi/ppsi.h             |  10 +-
 proto-ext-l1sync/l1e-api.h      |   7 +-
 proto-ext-whiterabbit/wr-api.h  |   5 +
 proto-standard/open-close.c     |  17 +-
 tools/ppsi_conf.c               |  47 ++++++
 tools/wrs_dump_shmem_ppsi.c     |   1 +
 12 files changed, 342 insertions(+), 100 deletions(-)

diff --git a/Kconfig_ppsi b/Kconfig_ppsi
index 860a37a2..18d2a984 100644
--- a/Kconfig_ppsi
+++ b/Kconfig_ppsi
@@ -244,12 +244,6 @@ config HAS_EXT_L1SYNC
 	default 1 if PROFILE_HA
 	default 0
 
-config HAS_EXT_NONE
-	int 
-	range 0 1
-	default 1 if !(PROFILE_WR || PROFILE_HA || PROFILE_CUSTOM)
-	default 0
-	
 config HAS_PROFILE_PTP
 	int 
 	range 0 1
diff --git a/arch-wrs/include/ppsi-wrs.h b/arch-wrs/include/ppsi-wrs.h
index 35c1fb8c..bbbad8a8 100644
--- a/arch-wrs/include/ppsi-wrs.h
+++ b/arch-wrs/include/ppsi-wrs.h
@@ -79,6 +79,8 @@ int32_t wrs_get_clock_period(void);
 
 /* wrs-startup.c */
 void enable_asymmetryCorrection(struct pp_instance *ppi, Boolean enable );
+int set_profile(struct pp_instance *ppi, int profile);
+int set_extension(struct pp_instance *ppi, int extension);
 
 /* wrs-time.c (some should moce to wrs-spll.c) */
 void wrs_init_rts_addr(uint32_t addr,const char *devname);
diff --git a/arch-wrs/include/ppsi_exports.h b/arch-wrs/include/ppsi_exports.h
index 28a27d59..c7553b77 100644
--- a/arch-wrs/include/ppsi_exports.h
+++ b/arch-wrs/include/ppsi_exports.h
@@ -26,10 +26,16 @@
 /* Commands for ppsiexp_update_param_instance_cmd */
 #define PPSIEXP_PARAM_INST_DELAY_REQ_INT_CMD			1
 #define PPSIEXP_PARAM_INST_SYNC_INT_CMD				2
+#define PPSIEXP_PARAM_INST_EXTENSION_CMD 			3
 
 /* Commands for ppsiexp_update_param_str_instance_cmd */
 #define PPSIEXP_PARAM_INST_STR_DIAG_CMD 			1
 
+/* Values for PPSIEXP_PARAM_INST_EXTENSION_CMD */
+#define PPSIEXP_PARAM_EXTENSION_NONE				PPSI_EXT_NONE
+#define PPSIEXP_PARAM_EXTENSION_WR				PPSI_EXT_WR
+#define PPSIEXP_PARAM_EXTENSION_L1SYNC				PPSI_EXT_L1S
+
 #define PPSI_INSTANCE_USE_PORT					0x80000000
 
 /* Export structures, shared by server and client for argument matching */
diff --git a/arch-wrs/wrs-ipcserver.c b/arch-wrs/wrs-ipcserver.c
index 352c1baa..a8662ef2 100644
--- a/arch-wrs/wrs-ipcserver.c
+++ b/arch-wrs/wrs-ipcserver.c
@@ -144,8 +144,57 @@ static int update_param_instance(struct pp_instance *ppi, int ppi_i,
 				 int param_type, int param_val)
 {
 	int rval = PPSIEXP_RET_OK;
+	int tmp = 0;
 
 	switch (param_type) {
+	case PPSIEXP_PARAM_INST_EXTENSION_CMD:
+		pp_diag(ppi, config, 2,
+			"%s: cmd %d (PPSIEXP_PARAM_INST_EXTENSION_CMD) "
+			"instance %d, port %s, value %d\n", __func__, param_type,
+			ppi_i, ppi->iface_name, param_val);
+
+		switch (param_val) {
+		case PPSIEXP_PARAM_EXTENSION_NONE:
+		case PPSIEXP_PARAM_EXTENSION_WR:
+		case PPSIEXP_PARAM_EXTENSION_L1SYNC:
+			/* Known value */
+			break;
+		default:
+			/* Value not known */
+			pp_diag(ppi, config, 1,
+				"Param update Error: value of "
+				"extension (%d) not in range! "
+				"cmd %d (PPSIEXP_PARAM_INST_EXTENSION_CMD) "
+				"instance %d, port %s\n",
+				param_val, param_type, ppi_i, ppi->iface_name);
+			return PPSIEXP_RET_ERROR_VAL;
+		}
+
+		set_extension(ppi, param_val);
+		/* Default value for PTP. Can be overwritten in specific init */
+		ppi->pdstate = PP_PDSTATE_NONE;
+		ppi->extState =
+			(ppi->protocol_extension == PPSI_EXT_NONE)
+			? PP_EXSTATE_DISABLE : PP_EXSTATE_ACTIVE;
+		/* TODO: set wrModeOn and wrMode with something better, or
+		 * check if WR ext is set */
+		wr_reset_process(ppi, WR_ROLE_NONE);
+		if (is_ext_hook_available(ppi, init))
+			tmp = ppi->ext_hooks->init(ppi, NULL, 0);
+		if (tmp) {
+			pp_diag(ppi, ext, 1, "%s: can't init extension\n",
+				__func__);
+			rval = PPSIEXP_RET_ERROR_VAL;
+			break;
+		}
+		/* When the extension/profile is changed the servo is not reset
+		 * nor initialized initialization of servo (wrh_servo_init) is
+		 * done via new_slave */
+		pp_servo_init(ppi);
+		if (is_ext_hook_available(ppi,new_slave))
+			ppi->ext_hooks->new_slave(ppi, NULL, 0);
+		break;
+
 	case PPSIEXP_PARAM_INST_DELAY_REQ_INT_CMD:
 		pp_diag(ppi, config, 2,
 			"%s: cmd %d (PPSIEXP_PARAM_INST_DELAY_REQ_INT_CMD) "
diff --git a/arch-wrs/wrs-startup.c b/arch-wrs/wrs-startup.c
index a2aa3b49..aee81e61 100644
--- a/arch-wrs/wrs-startup.c
+++ b/arch-wrs/wrs-startup.c
@@ -57,33 +57,200 @@ struct wrs_shm_head *ppsi_head;
 
 extern struct pp_ext_hooks  pp_hooks;
 
+static int init_extensions(struct pp_instance *ppi)
+{
+	struct pp_ext_mem *ppi_ext_data;
+
+	if (!(ppi_ext_data =
+			wrs_shm_alloc(ppsi_head,
+				      sizeof(struct pp_ext_mem) * (PPSI_EXT_N)))
+	   ) {
+		return -1;
+	}
+
+	/* Clean the allocated memory */
+	memset(ppi_ext_data, 0, sizeof(struct pp_ext_mem) * PPSI_EXT_N);
+
+	ppi->ext_mem = ppi_ext_data;
+
+#if CONFIG_HAS_EXT_WR
+	/* Add WR extension portDS */
+	if (!(ppi_ext_data[PPSI_EXT_WR].ext_dsport =
+			wrs_shm_alloc(ppsi_head, sizeof(struct wr_dsport)))
+	   ) {
+		return -1;
+	}
+
+	/* Allocate WR data extension */
+	if (!(ppi_ext_data[PPSI_EXT_WR].ext_data =
+			wrs_shm_alloc(ppsi_head, sizeof(struct wr_data)))
+	   ) {
+		return -1;
+	}
+
+	/* Set WR extension hooks */
+	ppi_ext_data[PPSI_EXT_WR].ext_hooks = &wr_ext_hooks;
+#endif
+
 #if CONFIG_HAS_EXT_L1SYNC
-/**
- * Enable the l1sync extension for a given ppsi instance
- */
-static  int enable_l1Sync(struct pp_instance *ppi, Boolean enable) {
-	if ( enable ) {
+	if (!(ppi_ext_data[PPSI_EXT_L1S].ext_dsport =
+			wrs_shm_alloc(ppsi_head, sizeof(l1e_ext_portDS_t)))
+	   ) {
+		return -1;
+	}
+
+	/* Allocate L1SYNC data extension */
+	if (!(ppi_ext_data[PPSI_EXT_L1S].ext_data =
+		wrs_shm_alloc(ppsi_head,sizeof(struct l1e_data)))
+	   ) {
+		return -1;
+	}
+
+	/* Set L1SYNC extension hooks */
+	ppi_ext_data[PPSI_EXT_L1S].ext_hooks = &l1e_ext_hooks;
+#endif
+
+	return 0;
+}
+
+int set_extension(struct pp_instance *ppi, int extension)
+{
+	pp_diag(ppi, config, 3, "%s: set extension: %s (%d)\n",
+		__func__, lut_extension_name[extension], extension);
+
+	switch (extension) {
+#if CONFIG_HAS_EXT_WR
+	case PPSI_EXT_WR:
+		ppi->portDS->ext_dsport = ppi->ext_mem[PPSI_EXT_WR].ext_dsport;
+		ppi->ext_data = ppi->ext_mem[PPSI_EXT_WR].ext_data;
+		ppi->ext_hooks = ppi->ext_mem[PPSI_EXT_WR].ext_hooks;
+		ppi->protocol_extension = PPSI_EXT_WR;
+		break;
+#endif
+
+#if CONFIG_HAS_EXT_L1SYNC
+	case PPSI_EXT_L1S:
+		ppi->portDS->ext_dsport = ppi->ext_mem[PPSI_EXT_L1S].ext_dsport;
+		ppi->ext_data = ppi->ext_mem[PPSI_EXT_L1S].ext_data;
+		ppi->ext_hooks = ppi->ext_mem[PPSI_EXT_L1S].ext_hooks;
+
 		ppi->protocol_extension=PPSI_EXT_L1S;
-		/* Add L1SYNC extension portDS */
-		if ( !(ppi->portDS->ext_dsport =wrs_shm_alloc(ppsi_head, sizeof(l1e_ext_portDS_t))) ) {
-			return 0;
-		}
 
-		/* Allocate L1SYNC data extension */
-		if (! (ppi->ext_data = wrs_shm_alloc(ppsi_head,sizeof(struct l1e_data))) ) {
-			return 0;
-		}
-		/* Set L1SYNC state. Must be done here because the init hook is called only in the initializing state. If
-		 * the port is not connected, the initializing is then never called so the L1SYNC state is invalid (0)
+		/* Set L1SYNC state. Must be done here because the init hook is
+		 * called only in the initializing state. If the port is not
+		 * connected, the initializing is then never called so the
+		 * L1SYNC state is invalid (0)
 		 */
-		L1E_DSPOR_BS(ppi)->L1SyncState=L1SYNC_DISABLED;
-		L1E_DSPOR_BS(ppi)->L1SyncEnabled=TRUE;
-		/* Set L1SYNC extension hooks */
-		ppi->ext_hooks=&l1e_ext_hooks;
+		L1E_DSPOR_BS(ppi)->L1SyncState = L1SYNC_DISABLED;
+		L1E_DSPOR_BS(ppi)->L1SyncEnabled = TRUE;
+		break;
+#endif
+
+	case PPSI_EXT_NONE:
+		ppi->portDS->ext_dsport = NULL;
+		ppi->ext_data = NULL;
+		ppi->ext_hooks = &pp_hooks;
+		ppi->protocol_extension = PPSI_EXT_NONE;
+		break;
+
+	default:
+		fprintf(stderr, "ppsi: Extension not supported\n");
+		return -1;
+		break;
 	}
-	return 1;
+
+	return 0;
 }
+
+int set_profile(struct pp_instance *ppi, int profile)
+{
+
+	switch (profile) {
+	case PPSI_PROFILE_PTP :
+		/* Disable extension */
+		if (set_extension(ppi, PPSI_EXT_NONE) < 0) {
+			/* Error */
+			return -1;
+		}
+
+		/* Do not take care of L1SYNC */
+		enable_asymmetryCorrection(ppi, ppi->cfg.asymmetryCorrectionEnable);
+		break;
+
+	case PPSI_PROFILE_WR :
+#if CONFIG_HAS_PROFILE_WR
+		if (set_extension(ppi, PPSI_EXT_WR) < 0) {
+			/* Error */
+			return -1;
+		}
+
+		/* Set WR extension hooks */
+		enable_asymmetryCorrection(ppi, TRUE);
+
+#else
+		fprintf(stderr, "ppsi: Profile WR not supported\n");
+		return -1;
+#endif /* CONFIG_HAS_PROFILE_WR */
+		break;
+
+	case PPSI_PROFILE_HA :
+#if CONFIG_HAS_PROFILE_HA
+		if (set_extension(ppi, PPSI_EXT_L1S) < 0) {
+			/* Error */
+			return -1;
+		}
+
+		/* Force mandatory attributes - Do not take care of the configuration */
+		L1E_DSPOR_BS(ppi)->rxCoherentIsRequired = TRUE;
+		L1E_DSPOR_BS(ppi)->txCoherentIsRequired = TRUE;
+		L1E_DSPOR_BS(ppi)->congruentIsRequired = TRUE;
+		L1E_DSPOR_BS(ppi)->L1SyncEnabled = TRUE;
+		L1E_DSPOR_BS(ppi)->optParamsEnabled = FALSE;
+		enable_asymmetryCorrection(ppi, TRUE);
+
+		break;
+#else
+		fprintf(stderr, "ppsi: Profile HA not supported\n");
+		return -1;
+#endif /* CONFIG_HAS_PROFILE_HA */
+
+	case PPSI_PROFILE_CUSTOM :
+#if CONFIG_HAS_PROFILE_CUSTOM
+		if (set_extension(ppi, PPSI_EXT_NONE) < 0) {
+			/* Error */
+			return -1;
+		}
+#if  CONFIG_HAS_EXT_L1SYNC
+		if (ppi->cfg.l1SyncEnabled ) {
+			if (set_extension(ppi, PPSI_EXT_L1S) < 0) {
+				/* Error */
+				return -1;
+			}
+
+			/* Read L1SYNC parameters */
+			L1E_DSPOR_BS(ppi)->rxCoherentIsRequired = ppi->cfg.l1SyncRxCoherentIsRequired;
+			L1E_DSPOR_BS(ppi)->txCoherentIsRequired = ppi->cfg.l1SyncTxCoherentIsRequired;
+			L1E_DSPOR_BS(ppi)->congruentIsRequired = ppi->cfg.l1SyncCongruentIsRequired;
+			L1E_DSPOR_BS(ppi)->optParamsEnabled = ppi->cfg.l1SyncOptParamsEnabled;
+			if (L1E_DSPOR_BS(ppi)->optParamsEnabled) {
+				L1E_DSPOR_OP(ppi)->timestampsCorrectedTx = ppi->cfg.l1SyncOptParamsTimestampsCorrectedTx;
+			}
+		}
+#endif /* CONFIG_HAS_EXT_L1SYNC*/
+		enable_asymmetryCorrection(ppi, ppi->cfg.asymmetryCorrectionEnable);
+#else
+		fprintf(stderr, "ppsi: Profile CUSTOM not supported\n");
+		return -1;
 #endif
+		break;
+
+	default:
+		fprintf(stderr, "ppsi: Not supported profile %d\n", profile);
+		return -1;
+	}
+
+	return 0;
+}
 
 /**
  * Enable/disable asymmetry correction
@@ -264,7 +431,7 @@ int main(int argc, char **argv)
 	/* And create your own channel, until we move to shmem too */
 	ppsi_ch = minipc_server_create("ptpd", 0);
 	if (!ppsi_ch) { /* FIXME should we retry ? */
-		pp_printf("ppsi: could not create minipc server");
+		pp_printf("ppsi: could not create minipc server\n");
 		exit(1);
 	}
 
@@ -343,74 +510,16 @@ int main(int argc, char **argv)
 		ppi->ext_hooks=&pp_hooks; /* Default value. Can be overwritten by an extension */
 		ppi->ptp_support=TRUE;
 		if (ppi->portDS) {
-			switch (ppi->cfg.profile) {
-			case PPSI_PROFILE_WR :
-#if CONFIG_HAS_PROFILE_WR
-					ppi->protocol_extension=PPSI_EXT_WR;
-					/* Add WR extension portDS */
-					if ( !(ppi->portDS->ext_dsport =
-							wrs_shm_alloc(ppsi_head, sizeof(struct wr_dsport))) ) {
-							goto exit_out_of_memory;
-					}
-
-					/* Allocate WR data extension */
-					if (! (ppi->ext_data = wrs_shm_alloc(ppsi_head,sizeof(struct wr_data))) ) {
-						goto exit_out_of_memory;
-					}
-					/* Set WR extension hooks */
-					ppi->ext_hooks=&wr_ext_hooks;
-					enable_asymmetryCorrection(ppi,TRUE);
-#else
-					fprintf(stderr, "ppsi: Profile WR not supported");
-					exit(1);
-#endif
-				break;
-			case PPSI_PROFILE_HA :
-#if CONFIG_HAS_PROFILE_HA
-				if ( !enable_l1Sync(ppi,TRUE) )
-					goto exit_out_of_memory;
-				/* Force mandatory attributes - Do not take care of the configuration */
-				L1E_DSPOR_BS(ppi)->rxCoherentIsRequired = TRUE;
-				L1E_DSPOR_BS(ppi)->txCoherentIsRequired = TRUE;
-				L1E_DSPOR_BS(ppi)->congruentIsRequired = TRUE;
-				L1E_DSPOR_BS(ppi)->L1SyncEnabled = TRUE;
-				L1E_DSPOR_BS(ppi)->optParamsEnabled = FALSE;
-				enable_asymmetryCorrection(ppi,TRUE);
+			if (init_extensions(ppi) < 0)
+				goto exit_out_of_memory;
 
-#else
-				fprintf(stderr, "ppsi: Profile HA not supported");
+			if (set_profile(ppi, ppi->cfg.profile) < 0) {
+				fprintf(stderr,
+					"ppsi: Profile %d not supported\n",
+					ppi->cfg.profile);
 				exit(1);
-#endif
-				break;
-			case PPSI_PROFILE_PTP :
-				/* Do not take care of L1SYNC */
-				enable_asymmetryCorrection(ppi,ppi->cfg.asymmetryCorrectionEnable);
-				ppi->protocol_extension=PPSI_EXT_NONE;
-				break;
-			case PPSI_PROFILE_CUSTOM :
-#if CONFIG_HAS_PROFILE_CUSTOM
-				ppi->protocol_extension=PPSI_EXT_NONE; /* can be changed ...*/
-#if CONFIG_HAS_EXT_L1SYNC
-				if (ppi->cfg.l1SyncEnabled ) {
-					if ( !enable_l1Sync(ppi,TRUE) )
-						goto exit_out_of_memory;
-					/* Read L1SYNC parameters */
-					L1E_DSPOR_BS(ppi)->rxCoherentIsRequired =ppi->cfg.l1SyncRxCoherentIsRequired;
-					L1E_DSPOR_BS(ppi)->txCoherentIsRequired =ppi->cfg.l1SyncTxCoherentIsRequired;
-					L1E_DSPOR_BS(ppi)->congruentIsRequired =ppi->cfg.l1SyncCongruentIsRequired;
-					L1E_DSPOR_BS(ppi)->optParamsEnabled=ppi->cfg.l1SyncOptParamsEnabled;
-					if ( L1E_DSPOR_BS(ppi)->optParamsEnabled ) {
-						L1E_DSPOR_OP(ppi)->timestampsCorrectedTx=ppi->cfg.l1SyncOptParamsTimestampsCorrectedTx;
-					}
-				}
-				enable_asymmetryCorrection(ppi,ppi->cfg.asymmetryCorrectionEnable);
-#endif
-#else
-					fprintf(stderr, "ppsi: Profile CUSTOM not supported");
-					exit(1);
-#endif
-				break;
 			}
+
 			/* Parameters profile independent */
 			ppi->timestampCorrectionPortDS.egressLatency=picos_to_interval(ppi->cfg.egressLatency_ps);
 			ppi->timestampCorrectionPortDS.ingressLatency=picos_to_interval(ppi->cfg.ingressLatency_ps);
diff --git a/include/ppsi/pp-instance.h b/include/ppsi/pp-instance.h
index a2abb66a..e480ceca 100644
--- a/include/ppsi/pp-instance.h
+++ b/include/ppsi/pp-instance.h
@@ -210,6 +210,13 @@ typedef enum {
 	PP_EXSTATE_ACTIVE, /* Extension active */
 	PP_EXSTATE_PTP /* Extension uses only PTP protocol */
 } pp_exstate_t;
+
+struct pp_ext_mem {
+	void *ext_dsport;
+	void *ext_data;
+	const struct pp_ext_hooks *ext_hooks;
+};
+
 /*
  * Structure for the individual ppsi link
  */
@@ -294,6 +301,10 @@ struct pp_instance {
 	Boolean bmca_execute; /* True: Ask fsm to run bmca state decision */
 	pp_pdstate_t pdstate;  /* Protocol detection state */
 	pp_exstate_t extState; /* Extension state */
+#if CONFIG_ARCH_IS_WRS
+	/* Several extensions are supported only in WRS */
+	struct pp_ext_mem *ext_mem; /* memory needed to when using several extensions */
+#endif
 };
 
 /* The following things used to be bit fields. Other flags are now enums */
diff --git a/include/ppsi/ppsi.h b/include/ppsi/ppsi.h
index 426499da..84fa7452 100644
--- a/include/ppsi/ppsi.h
+++ b/include/ppsi/ppsi.h
@@ -25,9 +25,6 @@
 
 #include <arch/arch.h> /* ntohs and so on -- and wr-api.h for wr archs */
 
-/* Protocol extensions */
-#include "../proto-ext-whiterabbit/wr-api.h"
-#include "../proto-ext-l1sync/l1e-api.h"
 
 /* At this point in time, we need ARRAY_SIZE to conditionally build vlan code */
 #undef ARRAY_SIZE
@@ -242,7 +239,7 @@ struct pp_ext_hooks {
 			struct pp_frgn_master *frgn_master); /* Called at the end of the S1 treatment in the BMCA */
 };
 
-#define is_ext_hook_available(p, c) ( /*p->ext_enabled && */ p->ext_hooks->c)
+#define is_ext_hook_available(p, c) ( /*p->ext_enabled && */ p->ext_hooks && p->ext_hooks->c)
 
 /*
  * Network methods are encapsulated in a structure, so each arch only needs
@@ -317,6 +314,7 @@ extern int pp_parse_cmdline(struct pp_globals *ppg, int argc, char **argv);
 #define PPSI_EXT_NONE	0
 #define PPSI_EXT_WR		1   /* WR extension */ 
 #define PPSI_EXT_L1S	2   /* L1SYNC extension */
+#define PPSI_EXT_N	3   /* Number of extensions */
 
 /* Define the PPSI profiles */  
 #define PPSI_PROFILE_PTP     0 /* Default PTP profile without extensions */
@@ -457,6 +455,10 @@ extern void pdstate_set_state_pdetection(struct pp_instance * ppi);
 extern void pdstate_set_state_pdetected(struct pp_instance * ppi);
 extern void pdstate_enable_extension(struct pp_instance * ppi);
 
+/* Protocol extensions */
+#include "../proto-ext-whiterabbit/wr-api.h"
+#include "../proto-ext-l1sync/l1e-api.h"
+
 #include <ppsi/faults.h>
 #include <ppsi/timeout_prot.h>
 #include <ppsi/conf.h>
diff --git a/proto-ext-l1sync/l1e-api.h b/proto-ext-l1sync/l1e-api.h
index fe07317e..44e2c066 100644
--- a/proto-ext-l1sync/l1e-api.h
+++ b/proto-ext-l1sync/l1e-api.h
@@ -102,7 +102,12 @@ typedef struct  {
 
 static inline l1e_ext_portDS_t *L1E_DSPOR(struct pp_instance *ppi)
 {
-	return (l1e_ext_portDS_t *) ppi->portDS->ext_dsport;
+#if CONFIG_ARCH_IS_WRS
+	/* Several extensions are supported only in WRS */
+	return ppi->ext_mem[PPSI_EXT_L1S].ext_dsport;
+#else
+	return ppi->portDS->ext_dsport;
+#endif
 }
 
 static inline L1SyncBasicPortDS_t *L1E_DSPOR_BS(struct pp_instance *ppi)
diff --git a/proto-ext-whiterabbit/wr-api.h b/proto-ext-whiterabbit/wr-api.h
index 1db46cf6..4f2157b9 100644
--- a/proto-ext-whiterabbit/wr-api.h
+++ b/proto-ext-whiterabbit/wr-api.h
@@ -64,7 +64,12 @@ struct wr_dsport {
 /* This uppercase name matches "DSPOR(ppi)" used by standard protocol */
 static inline struct wr_dsport *WR_DSPOR(struct pp_instance *ppi)
 {
+#if CONFIG_ARCH_IS_WRS
+	/* Several extensions are supported only in WRS */
 	return ppi->portDS->ext_dsport;
+#else
+	return ppi->ext_mem[PPSI_EXT_WR].ext_dsport;
+#endif
 }
 
 static inline Integer32 phase_to_cf_units(Integer32 phase)
diff --git a/proto-standard/open-close.c b/proto-standard/open-close.c
index bf0d210e..5790abdb 100644
--- a/proto-standard/open-close.c
+++ b/proto-standard/open-close.c
@@ -176,10 +176,21 @@ int pp_init_globals(struct pp_globals *ppg, struct pp_runtime_opts *pp_rt_opts)
 	for (i = 0; i < get_numberPorts(def); i++) {
 		struct pp_instance *ppi = INST(ppg, i);
 		int r;
-
-		if (is_ext_hook_available(ppi,open)) {
-		   ret=(r=ppi->ext_hooks->open(ppi, rt_opts))==0 ? ret : r;
+		int ext;
+#if CONFIG_ARCH_IS_WRS
+		/* Several extensions are supported only in WRS */
+		for (ext = 0; ext < PPSI_EXT_N; ext++) {
+			if (ppi->ext_mem[ext].ext_hooks && ppi->ext_mem[ext].ext_hooks->open) {
+				r = ppi->ext_mem[ext].ext_hooks->open(ppi, rt_opts);
+				ret = (r == 0) ? ret : r;
+			}
 		}
+#else
+		if (is_ext_hook_available(ppi, open)) {
+			r = ppi->ext_hooks->open(ppi, rt_opts);
+			ret = (r == 0) ? ret : r;
+		}
+#endif
 	}
 	return ret;
 }
diff --git a/tools/ppsi_conf.c b/tools/ppsi_conf.c
index 4a371f19..e9751fc3 100644
--- a/tools/ppsi_conf.c
+++ b/tools/ppsi_conf.c
@@ -30,6 +30,7 @@ enum input_arg {
 	arg_delay_req_interval,
 	arg_diags,
 	arg_diags_inst,
+	arg_extension,
 	arg_instance,
 	arg_port,
 	arg_prio1,
@@ -45,6 +46,7 @@ static struct option long_opts[] = {
 	{"delay-req-interval",          required_argument, NULL, arg_delay_req_interval},
 	{"diags",                       required_argument, NULL, arg_diags},
 	{"diags-inst",                  required_argument, NULL, arg_diags_inst},
+	{"extension",                   required_argument, NULL, arg_extension},
 	{"instance",                    required_argument, NULL, arg_instance},
 	{"ppi",                         required_argument, NULL, arg_instance},
 	{"port",                        required_argument, NULL, arg_port},
@@ -91,6 +93,8 @@ void help(char *prgname)
 		"  --diags-inst=<num>\n"
 		"                    - change PPSI's instance/port diagnostics to <num>\n"
 		"                      order: FSM, Time, Frames, Servo, BMC, Extension, Configuration\n"
+		"  --extension=<none|wr|l1s|l1sync>\n"
+		"                    - sets the extension; extension has to be supported by a selected profile\n"
 		"  --sync-interval=<num>\n"
 		"                    - sets logarithm to the base 2 of the mean interval of sync\n"
 		"                      message transmission; used when a port is in Master state\n"
@@ -204,6 +208,7 @@ int main(int argc, char *argv[])
 {
 	int opt;
 	int tmp;
+	char *tmp_str;
 	int ret;
 	int ppsi_instance = -1;
 	int ppsi_port = -1;
@@ -318,6 +323,48 @@ int main(int argc, char *argv[])
 			}
 			break;
 
+		case arg_extension:
+			/* Check if an instance is set. If not exit. */
+			check_instance(ppsi_instance);
+			if (!strcmp(optarg, "none") || !strcmp(optarg, "0")) {
+				tmp = PPSIEXP_PARAM_EXTENSION_NONE;
+				tmp_str = "none";
+			} else if (!strcmp(optarg, "wr") || !strcmp(optarg, "1")) {
+				tmp = PPSIEXP_PARAM_EXTENSION_WR;
+				tmp_str = "wr";
+			} else if (!strcmp(optarg, "l1s")
+			    || !strcmp(optarg, "l1sync")
+			    || !strcmp(optarg, "2")) {
+				tmp = PPSIEXP_PARAM_EXTENSION_L1SYNC;
+				tmp_str = "l1sync";
+			} else {
+				fprintf(stderr, "Error setting extension for %s"
+					" %d to %s, wrong value\n",
+					ppsi_port == -1 ? "instance" : "port",
+					ppsi_instance & ~PPSI_INSTANCE_USE_PORT,
+					optarg);
+				exit (1);
+			}
+
+			if (verbose)
+				printf("Setting extension for %s %d to %s\n",
+				       ppsi_port == -1 ? "instance" : "port",
+				       ppsi_instance & ~PPSI_INSTANCE_USE_PORT,
+				       tmp_str);
+				ret = ppsi_set_param_instance(
+					PPSIEXP_PARAM_INST_EXTENSION_CMD,
+					ppsi_instance,
+					tmp);
+			if (ret) {
+				fprintf(stderr, "Error setting extension for %s"
+					" %d to %s, ret %d\n",
+					ppsi_port == -1 ? "instance" : "port",
+					ppsi_instance & ~PPSI_INSTANCE_USE_PORT,
+					tmp_str, ret);
+				exit (1);
+			}
+			break;
+
 		case arg_instance:
 			ppsi_instance = atoi(optarg);
 			if (ppsi_instance == 0 && strcmp("0", optarg)
diff --git a/tools/wrs_dump_shmem_ppsi.c b/tools/wrs_dump_shmem_ppsi.c
index 97b02827..60554cd3 100644
--- a/tools/wrs_dump_shmem_ppsi.c
+++ b/tools/wrs_dump_shmem_ppsi.c
@@ -239,6 +239,7 @@ struct dump_info ppi_info [] = {
 	DUMP_FIELD(pp_pdstate,pdstate),
 	DUMP_FIELD(pointer, arch_inst_data),
 	DUMP_FIELD(pointer, ext_data),
+	DUMP_FIELD(pointer, ext_mem),
 	DUMP_FIELD(protocol_extension, protocol_extension),
 	DUMP_FIELD(pointer, ext_hooks),
 	DUMP_FIELD(pointer, servo),		/* FIXME: follow this */
-- 
GitLab