Prechádzať zdrojové kódy

ipanat: move NAT table on request from modem

On request from modem move NAT table to DDR only
or back to hybrid mode. send QMI indication when
transition has finished.

Change-Id: I6d7fd5576519016da5b99e13e7019a925109244a
Signed-off-by: Amir Levy <[email protected]>
Amir Levy 3 rokov pred
rodič
commit
3b421c7536

+ 10 - 2
ipanat/inc/ipa_nat_drv.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -256,8 +256,16 @@ void ipa_nat_dump_ipv4_table(uint32_t tbl_hdl);
 int ipa_nat_vote_clock(
 	enum ipa_app_clock_vote_type vote_type );
 
+/**
+ * ipa_nat_switch_to() - While in HYBRID mode only, used for switching
+ * from SRAM to DDR or the reverse.
+ * @nmi: memory type to switch to
+ * @hold_state: Will the new memory type get locked in (ie. no more
+ *              oscilation between the memory types)
+ */
 int ipa_nat_switch_to(
-	enum ipa3_nat_mem_in nmi );
+	enum ipa3_nat_mem_in nmi,
+	bool                 hold_state );
 
 #endif
 

+ 46 - 1
ipanat/inc/ipa_nat_statemach.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -31,6 +31,8 @@
 
 typedef uintptr_t arb_t;
 
+#define MAKE_AS_STR_CASE(v) case v: return #v
+
 /******************************************************************************/
 /**
  * The following enum represents the states that a nati object can be
@@ -46,6 +48,26 @@ typedef enum {
 	NATI_STATE_LAST
 } ipa_nati_state;
 
+/* KEEP THE FOLLOWING IN SYNC WITH ABOVE. */
+static inline const char* ipa_nati_state_as_str(
+	ipa_nati_state s )
+{
+	switch ( s )
+	{
+		MAKE_AS_STR_CASE(NATI_STATE_NULL);
+		MAKE_AS_STR_CASE(NATI_STATE_DDR_ONLY);
+		MAKE_AS_STR_CASE(NATI_STATE_SRAM_ONLY);
+		MAKE_AS_STR_CASE(NATI_STATE_HYBRID);
+		MAKE_AS_STR_CASE(NATI_STATE_HYBRID_DDR);
+		MAKE_AS_STR_CASE(NATI_STATE_LAST);
+
+	default:
+		break;
+	}
+
+	return "???";
+}
+
 # undef strcasesame
 # define strcasesame(a, b) (!strcasecmp(a, b))
 
@@ -116,6 +138,8 @@ typedef struct
 {
 	ipa_nati_state prev_state;
 	ipa_nati_state curr_state;
+	bool           hold_state;
+	ipa_nati_state state_to_hold;
 	uint32_t       ddr_tbl_hdl;
 	uint32_t       sram_tbl_hdl;
 	uint32_t       tot_slots_in_sram;
@@ -146,11 +170,32 @@ typedef struct
 #define DDR_SUB  0
 #define SRAM_SUB 1
 
+#undef BACK2_UNSTARTED_STATE
+#define BACK2_UNSTARTED_STATE() \
+	nati_obj.prev_state = nati_obj.curr_state = NATI_STATE_NULL;
+
+#undef IN_UNSTARTED_STATE
+#define IN_UNSTARTED_STATE() \
+	( nati_obj.prev_state == NATI_STATE_NULL )
+
 #undef IN_HYBRID_STATE
 #define IN_HYBRID_STATE() \
 	( nati_obj.curr_state == NATI_STATE_HYBRID || \
 	  nati_obj.curr_state == NATI_STATE_HYBRID_DDR )
 
+#undef COMPATIBLE_NMI_4SWITCH
+#define COMPATIBLE_NMI_4SWITCH(n) \
+	( (n) == IPA_NAT_MEM_IN_SRAM && nati_obj.curr_state == NATI_STATE_HYBRID_DDR ) || \
+	( (n) == IPA_NAT_MEM_IN_DDR  && nati_obj.curr_state == NATI_STATE_HYBRID ) || \
+	( (n) == IPA_NAT_MEM_IN_DDR  && nati_obj.curr_state == NATI_STATE_DDR_ONLY ) || \
+	( (n) == IPA_NAT_MEM_IN_SRAM && nati_obj.curr_state == NATI_STATE_SRAM_ONLY )
+
+#undef GEN_HOLD_STATE
+#define GEN_HOLD_STATE() \
+	( ! IN_HYBRID_STATE() ) ? nati_obj.curr_state : \
+	(nati_obj.curr_state == NATI_STATE_HYBRID) ? NATI_STATE_SRAM_ONLY : \
+	NATI_STATE_DDR_ONLY
+
 #undef  SRAM_CURRENTLY_ACTIVE
 #define SRAM_CURRENTLY_ACTIVE() \
 	( nati_obj.curr_state == NATI_STATE_SRAM_ONLY || \

+ 274 - 50
ipanat/src/ipa_nat_statemach.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -111,7 +111,9 @@
  */
 static ipa_nati_obj nati_obj = {
 	.prev_state          = NATI_STATE_NULL,
-	.curr_state          = NATI_STATE_DDR_ONLY,
+	.curr_state          = NATI_STATE_NULL,
+	.hold_state          = false,
+	.state_to_hold       = NATI_STATE_NULL,
 	.ddr_tbl_hdl         = 0,
 	.sram_tbl_hdl        = 0,
 	.tot_slots_in_sram   = 0,
@@ -186,6 +188,53 @@ bail:
 	return ret;
 }
 
+/*
+ * Function for taking/locking the mutex...
+ */
+static int take_mutex()
+{
+	int ret;
+
+	if ( nat_mutex_init )
+	{
+again:
+		ret = pthread_mutex_lock(&nat_mutex);
+	}
+	else
+	{
+		ret = mutex_init();
+
+		if ( ret == 0 )
+		{
+			goto again;
+		}
+	}
+
+	if ( ret != 0 )
+	{
+		IPAERR("Unable to lock the %s nat mutex\n",
+			   (nat_mutex_init) ? "initialized" : "uninitialized");
+	}
+
+	return ret;
+}
+
+/*
+ * Function for giving/unlocking the mutex...
+ */
+static int give_mutex()
+{
+	int ret = (nat_mutex_init) ? pthread_mutex_unlock(&nat_mutex) : -1;
+
+	if ( ret != 0 )
+	{
+		IPAERR("Unable to unlock the %s nat mutex\n",
+			   (nat_mutex_init) ? "initialized" : "uninitialized");
+	}
+
+	return ret;
+}
+
 /*
  * ****************************************************************************
  *
@@ -203,22 +252,13 @@ int ipa_nati_add_ipv4_tbl(
 		(arb_t*) public_ip_addr,
 		(arb_t*) number_of_entries,
 		(arb_t*) tbl_hdl,
+		(arb_t*) mem_type_ptr,
 	};
 
 	int ret;
 
 	IPADBG("In\n");
 
-	/*
-	 * If first time in here, then let XML drive initial state...
-	 */
-	if (nati_obj.prev_state == NATI_STATE_NULL)
-	{
-		SET_NATIOBJ_STATE(
-			&nati_obj,
-			mem_type_str_to_ipa_nati_state(mem_type_ptr));
-	}
-
 	ret = ipa_nati_statemach(&nati_obj, NATI_TRIG_ADD_TABLE, args);
 
 	if ( ret == 0 )
@@ -388,27 +428,142 @@ int ipa_nati_query_timestamp(
 }
 
 int ipa_nat_switch_to(
-	enum ipa3_nat_mem_in nmi )
+	enum ipa3_nat_mem_in nmi,
+	bool                 hold_state )
 {
-	int ret = 0;
+	int ret = -1;
 
-	IPADBG("In\n");
+	IPADBG("In - current state %s\n",
+		   ipa_nati_state_as_str(nati_obj.curr_state));
 
-	if ( ! IPA_VALID_NAT_MEM_IN(nmi) || ! IN_HYBRID_STATE() )
+	if ( ! IPA_VALID_NAT_MEM_IN(nmi) )
 	{
-		IPAERR("Bad nmi(%s) and/or not in hybrid state\n",
-			   ipa3_nat_mem_in_as_str(nmi));
+		IPAERR("Bad nmi(%s)\n", ipa3_nat_mem_in_as_str(nmi));
+
 		ret = -1;
+
 		goto bail;
 	}
 
-	if ( (nmi == IPA_NAT_MEM_IN_SRAM && nati_obj.curr_state == NATI_STATE_HYBRID_DDR)
-		 ||
-		 (nmi == IPA_NAT_MEM_IN_DDR  && nati_obj.curr_state == NATI_STATE_HYBRID) )
+	ret = take_mutex();
+
+	if ( ret != 0 )
 	{
-		ret = ipa_nati_statemach(&nati_obj, NATI_TRIG_TBL_SWITCH, 0);
+		goto bail;
 	}
 
+	/*
+	 * Are we here before the state machine has been started?
+	 */
+	if ( IN_UNSTARTED_STATE() )
+	{
+		nati_obj.hold_state = hold_state;
+
+		nati_obj.state_to_hold =
+			(nmi == IPA_NAT_MEM_IN_DDR) ?
+			NATI_STATE_DDR_ONLY         :
+			NATI_STATE_SRAM_ONLY;
+
+		IPADBG(
+			"Initial state will be %s before table init and it %s be held\n",
+			ipa_nati_state_as_str(nati_obj.state_to_hold),
+			(hold_state) ? "will" : "will not");
+
+		ret = 0;
+
+		goto unlock;
+	}
+
+	/*
+	 * Are we here after we've already started in hybrid state?
+	 */
+	if ( IN_HYBRID_STATE() )
+	{
+		ret = 0;
+
+		if ( COMPATIBLE_NMI_4SWITCH(nmi) )
+		{
+			ret = ipa_nati_statemach(&nati_obj, NATI_TRIG_TBL_SWITCH, 0);
+		}
+
+		if ( ret == 0 )
+		{
+			nati_obj.hold_state = hold_state;
+
+			if ( hold_state )
+			{
+				nati_obj.state_to_hold = GEN_HOLD_STATE();
+			}
+
+			IPADBG(
+				"Current state is %s and it %s be held\n",
+				ipa_nati_state_as_str(nati_obj.curr_state),
+				(hold_state) ? "will" : "will not");
+		}
+
+		goto unlock;
+	}
+
+	/*
+	 * We've gotten here because we're not in an unstarted state, nor
+	 * are we in hybrid state. This means we're either in
+	 * NATI_STATE_DDR_ONLY or NATI_STATE_SRAM_ONLY
+	 *
+	 * Let's see what's being attempted and if it's OK...
+	 */
+	if ( hold_state )
+	{
+		if ( COMPATIBLE_NMI_4SWITCH(nmi) )
+		{
+			/*
+			 * If we've gotten here, it means that the requested nmi,
+			 * the current state, and the hold are compatible...
+			 */
+			nati_obj.state_to_hold = GEN_HOLD_STATE();
+			nati_obj.hold_state    = hold_state;
+
+			IPADBG(
+				"Requesting to hold memory type %s at "
+				"current state %s will be done\n",
+				ipa3_nat_mem_in_as_str(nmi),
+				ipa_nati_state_as_str(nati_obj.curr_state));
+
+			ret = 0;
+
+			goto unlock;
+		}
+		else
+		{
+			/*
+			 * The requested nmi, the current state, and the hold are
+			 * not compatible...
+			 */
+			IPAERR(
+				"Requesting to hold memory type %s and "
+				"current state %s are incompatible\n",
+				ipa3_nat_mem_in_as_str(nmi),
+				ipa_nati_state_as_str(nati_obj.curr_state));
+
+			ret = -1;
+
+			goto unlock;
+		}
+	}
+
+	/*
+	 * If we've gotten here, it's because the holding of state is no
+	 * longer desired...
+	 */
+	nati_obj.state_to_hold = NATI_STATE_NULL;
+	nati_obj.hold_state    = hold_state;
+
+	IPADBG("Holding of state is no longer desired\n");
+
+	ret = 0;
+
+unlock:
+	ret = give_mutex();
+
 bail:
 	IPADBG("Out\n");
 
@@ -666,6 +821,69 @@ static int _smDelTbl(
 
 	ret = ipa_NATI_del_ipv4_table(tbl_hdl);
 
+	if ( ret == 0 && ! IN_HYBRID_STATE() )
+	{
+		/*
+		 * The following will create the preferred "initial state" for
+		 * restart...
+		 */
+		BACK2_UNSTARTED_STATE();
+	}
+
+	IPADBG("Out\n");
+
+	return ret;
+}
+
+/******************************************************************************/
+/*
+ * FUNCTION: _smFirstTbl
+ *
+ * PARAMS:
+ *
+ *   nati_obj_ptr (IN) A pointer to an initialized nati object
+ *
+ *   trigger      (IN) The trigger to run through the state machine
+ *
+ *   arb_data_ptr (IN) Whatever you like
+ *
+ * DESCRIPTION:
+ *
+ *   The following will cause the creation of the very first NAT table(s)
+ *   before any others have ever been created...
+ *
+ * RETURNS:
+ *
+ *   zero on success, otherwise non-zero
+ */
+static int _smFirstTbl(
+	ipa_nati_obj*    nati_obj_ptr,
+	ipa_nati_trigger trigger,
+	arb_t*           arb_data_ptr )
+{
+	arb_t**   args = arb_data_ptr;
+
+	uint32_t    public_ip_addr    = (uint32_t)    args[0];
+	uint16_t    number_of_entries = (uint16_t)    args[1];
+	uint32_t*   tbl_hdl_ptr       = (uint32_t*)   args[2];
+	const char* mem_type_ptr      = (const char*) args[3];
+
+	int ret;
+
+	IPADBG("In\n");
+
+	/*
+	 * This is the first time in here.  Let the ipacm's XML config (or
+	 * state_to_hold) drive initial state...
+	 */
+	SET_NATIOBJ_STATE(
+		nati_obj_ptr,
+		(nati_obj_ptr->hold_state && nati_obj_ptr->state_to_hold) ?
+		nati_obj_ptr->state_to_hold                               :
+		mem_type_str_to_ipa_nati_state(mem_type_ptr));
+
+	ret = ipa_nati_statemach(nati_obj_ptr, NATI_TRIG_ADD_TABLE, args);
+
 	IPADBG("Out\n");
 
 	return ret;
@@ -973,7 +1191,15 @@ static int _smDelSramAndDdrTbl(
 		};
 
 		ret = _smDelTbl(nati_obj_ptr, trigger, new_args);
+	}
 
+	if ( ret == 0 )
+	{
+		/*
+		 * The following will create the preferred "initial state" for
+		 * restart...
+		 */
+		BACK2_UNSTARTED_STATE();
 	}
 
 	IPADBG("Out\n");
@@ -1482,7 +1708,9 @@ static int _smAddRuleHybrid(
 	}
 	else
 	{
-		if ( nati_obj_ptr->curr_state == NATI_STATE_HYBRID )
+		if ( nati_obj_ptr->curr_state == NATI_STATE_HYBRID
+			 &&
+			 ! nati_obj_ptr->hold_state )
 		{
 			/*
 			 * In hybrid mode, we always start in SRAM...hence
@@ -1612,7 +1840,9 @@ static int _smDelRuleHybrid(
 			 */
 			uint32_t* cnt_ptr = CHOOSE_CNTR();
 
-			if ( *cnt_ptr <= nati_obj_ptr->back_to_sram_thresh )
+			if ( *cnt_ptr <= nati_obj_ptr->back_to_sram_thresh
+				 &&
+				 ! nati_obj_ptr->hold_state )
 			{
 				/*
 				 * The following will focus us on SRAM and cause the copy
@@ -1768,12 +1998,16 @@ static int _smSwitchFromDdrToSram(
 
 	uint64_t           start, stop;
 
-	int stats_ret, ret;
+	int                stats_ret, ret;
+
+	bool               collect_stats = (bool) arb_data_ptr;
 
 	IPADBG("In\n");
 
-	stats_ret = ipa_NATI_ipv4_tbl_stats(
-		nati_obj_ptr->ddr_tbl_hdl, &nat_stats, &idx_stats);
+	stats_ret = (collect_stats) ?
+		ipa_NATI_ipv4_tbl_stats(
+			nati_obj_ptr->ddr_tbl_hdl, &nat_stats, &idx_stats) :
+		-1;
 
 	currTimeAs(TimeAsNanSecs, &start);
 
@@ -1934,12 +2168,16 @@ static int _smSwitchFromSramToDdr(
 
 	uint64_t           start, stop;
 
-	int stats_ret, ret;
+	int                stats_ret, ret;
+
+	bool               collect_stats = (bool) arb_data_ptr;
 
 	IPADBG("In\n");
 
-	stats_ret = ipa_NATI_ipv4_tbl_stats(
-		nati_obj_ptr->sram_tbl_hdl, &nat_stats, &idx_stats);
+	stats_ret = (collect_stats) ?
+		ipa_NATI_ipv4_tbl_stats(
+			nati_obj_ptr->sram_tbl_hdl, &nat_stats, &idx_stats) :
+		-1;
 
 	currTimeAs(TimeAsNanSecs, &start);
 
@@ -2185,7 +2423,7 @@ _state_mach_tbl[NATI_STATE_LAST+1][NATI_TRIG_LAST+1] =
 {
 	{
 		SM_ROW( NATI_STATE_NULL,       NATI_TRIG_NULL,       _smUndef ),
-		SM_ROW( NATI_STATE_NULL,       NATI_TRIG_ADD_TABLE,  _smUndef ),
+		SM_ROW( NATI_STATE_NULL,       NATI_TRIG_ADD_TABLE,  _smFirstTbl ),
 		SM_ROW( NATI_STATE_NULL,       NATI_TRIG_DEL_TABLE,  _smUndef ),
 		SM_ROW( NATI_STATE_NULL,       NATI_TRIG_CLR_TABLE,  _smUndef ),
 		SM_ROW( NATI_STATE_NULL,       NATI_TRIG_WLK_TABLE,  _smUndef ),
@@ -2201,7 +2439,7 @@ _state_mach_tbl[NATI_STATE_LAST+1][NATI_TRIG_LAST+1] =
 
 	{
 		SM_ROW( NATI_STATE_DDR_ONLY,   NATI_TRIG_NULL,       _smUndef ),
-		SM_ROW( NATI_STATE_DDR_ONLY,   NATI_TRIG_ADD_TABLE,  _smAddDdrTbl),
+		SM_ROW( NATI_STATE_DDR_ONLY,   NATI_TRIG_ADD_TABLE,  _smAddDdrTbl ),
 		SM_ROW( NATI_STATE_DDR_ONLY,   NATI_TRIG_DEL_TABLE,  _smDelTbl ),
 		SM_ROW( NATI_STATE_DDR_ONLY,   NATI_TRIG_CLR_TABLE,  _smClrTbl ),
 		SM_ROW( NATI_STATE_DDR_ONLY,   NATI_TRIG_WLK_TABLE,  _smWalkTbl ),
@@ -2217,7 +2455,7 @@ _state_mach_tbl[NATI_STATE_LAST+1][NATI_TRIG_LAST+1] =
 
 	{
 		SM_ROW( NATI_STATE_SRAM_ONLY,  NATI_TRIG_NULL,       _smUndef ),
-		SM_ROW( NATI_STATE_SRAM_ONLY,  NATI_TRIG_ADD_TABLE,  _smAddSramTbl),
+		SM_ROW( NATI_STATE_SRAM_ONLY,  NATI_TRIG_ADD_TABLE,  _smAddSramTbl ),
 		SM_ROW( NATI_STATE_SRAM_ONLY,  NATI_TRIG_DEL_TABLE,  _smDelTbl ),
 		SM_ROW( NATI_STATE_SRAM_ONLY,  NATI_TRIG_CLR_TABLE,  _smClrTbl ),
 		SM_ROW( NATI_STATE_SRAM_ONLY,  NATI_TRIG_WLK_TABLE,  _smWalkTbl ),
@@ -2351,20 +2589,10 @@ int ipa_nati_statemach(
 
 	IPADBG("In\n");
 
-	if ( ! nat_mutex_init )
-	{
-		ret = mutex_init();
-
-		if ( ret != 0 )
-		{
-			goto bail;
-		}
-	}
+	ret = take_mutex();
 
-	if ( pthread_mutex_lock(&nat_mutex) )
+	if ( ret != 0 )
 	{
-		IPAERR("Unable to lock the nat mutex\n");
-		ret = -EINVAL;
 		goto bail;
 	}
 
@@ -2400,11 +2628,7 @@ int ipa_nati_statemach(
 	}
 
 unlock:
-	if ( pthread_mutex_unlock(&nat_mutex) )
-	{
-		IPAERR("Unable to unlock the nat mutex\n");
-		ret = (ret) ? ret : -EPERM;
-	}
+	ret = give_mutex();
 
 bail:
 	IPADBG("Out\n");