Netdev Archive on lore.kernel.org
help / color / mirror / Atom feed
* [PATCH net-next 0/5] net: ipa: defer taking uC proxy clock
@ 2021-07-26 20:11 Alex Elder
  2021-07-26 20:11 ` [PATCH net-next 1/5] net: ipa: kill ipa_modem_setup() Alex Elder
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Alex Elder @ 2021-07-26 20:11 UTC (permalink / raw)
  To: davem, kuba
  Cc: bjorn.andersson, evgreen, cpratapa, subashab, elder, netdev,
	linux-kernel

This series rearranges some of the IPA initialization code.

The first patch gets rid of two trivial setup and teardown
functions, open-coding them in their callers instead.

The second patch has memory regions get configured before endpoints.

IPA interrupts do not depend on GSI being initialized.  Therefore
they can be initialized in the config phase rather than waiting for
setup.  The third patch moves this initialization earlier; memory
regions must already be defined, so it's done after memory config.

The microcontroller also has no dependency on GSI, though it does
require IPA interrupts to be configured.  The fourth patch moves
microcontroller initialization so it too happens during the config
phase rather than setup.

Finally, we currently take a "proxy clock" for the microcontroller
during the config phase, dropping it only after we learn the
microcontroller is initialized.  But microcontroller initialization
is started by the modem, so there's no point in taking that clock
reference before we know the modem has booted.  So the last patch
arranges to wait to take the "proxy clock" for the microcontroller
until we know the modem is about to boot.

					-Alex

Alex Elder (5):
  net: ipa: kill ipa_modem_setup()
  net: ipa: configure memory regions early
  net: ipa: set up IPA interrupts earlier
  net: ipa: set up the microcontroller earlier
  net: ipa: introduce ipa_uc_clock()

 drivers/net/ipa/ipa.h           |  2 ++
 drivers/net/ipa/ipa_interrupt.c |  8 ++---
 drivers/net/ipa/ipa_interrupt.h |  8 ++---
 drivers/net/ipa/ipa_main.c      | 56 ++++++++++++++++++---------------
 drivers/net/ipa/ipa_modem.c     | 12 ++-----
 drivers/net/ipa/ipa_modem.h     |  4 ---
 drivers/net/ipa/ipa_qmi.c       |  6 ++--
 drivers/net/ipa/ipa_qmi.h       | 19 +++++++++++
 drivers/net/ipa/ipa_uc.c        | 52 +++++++++++++++++-------------
 drivers/net/ipa/ipa_uc.h        | 22 ++++++++++---
 10 files changed, 112 insertions(+), 77 deletions(-)

-- 
2.27.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH net-next 1/5] net: ipa: kill ipa_modem_setup()
  2021-07-26 20:11 [PATCH net-next 0/5] net: ipa: defer taking uC proxy clock Alex Elder
@ 2021-07-26 20:11 ` Alex Elder
  2021-07-26 20:11 ` [PATCH net-next 2/5] net: ipa: configure memory regions early Alex Elder
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Alex Elder @ 2021-07-26 20:11 UTC (permalink / raw)
  To: davem, kuba
  Cc: bjorn.andersson, evgreen, cpratapa, subashab, elder, netdev,
	linux-kernel

The functions ipa_modem_setup() and ipa_modem_teardown() are trivial
wrappers that call ipa_qmi_setup() and ipa_qmi_teardown().  Just
call the QMI functions directly, and get rid of the wrappers.

Improve the documentation of what setting up QMI does.

Signed-off-by: Alex Elder <elder@linaro.org>
---
 drivers/net/ipa/ipa_main.c  |  4 ++--
 drivers/net/ipa/ipa_modem.c | 10 ----------
 drivers/net/ipa/ipa_modem.h |  4 ----
 drivers/net/ipa/ipa_qmi.c   |  6 ++----
 drivers/net/ipa/ipa_qmi.h   | 19 +++++++++++++++++++
 5 files changed, 23 insertions(+), 20 deletions(-)

diff --git a/drivers/net/ipa/ipa_main.c b/drivers/net/ipa/ipa_main.c
index 9810c61a03202..91e2ec3a0c133 100644
--- a/drivers/net/ipa/ipa_main.c
+++ b/drivers/net/ipa/ipa_main.c
@@ -167,7 +167,7 @@ int ipa_setup(struct ipa *ipa)
 	ipa_endpoint_default_route_set(ipa, exception_endpoint->endpoint_id);
 
 	/* We're all set.  Now prepare for communication with the modem */
-	ret = ipa_modem_setup(ipa);
+	ret = ipa_qmi_setup(ipa);
 	if (ret)
 		goto err_default_route_clear;
 
@@ -204,7 +204,7 @@ static void ipa_teardown(struct ipa *ipa)
 	struct ipa_endpoint *exception_endpoint;
 	struct ipa_endpoint *command_endpoint;
 
-	ipa_modem_teardown(ipa);
+	ipa_qmi_teardown(ipa);
 	ipa_endpoint_default_route_clear(ipa);
 	exception_endpoint = ipa->name_map[IPA_ENDPOINT_AP_LAN_RX];
 	ipa_endpoint_disable_one(exception_endpoint);
diff --git a/drivers/net/ipa/ipa_modem.c b/drivers/net/ipa/ipa_modem.c
index af9aedbde717a..5cb60e2ea6042 100644
--- a/drivers/net/ipa/ipa_modem.c
+++ b/drivers/net/ipa/ipa_modem.c
@@ -377,13 +377,3 @@ void ipa_modem_deconfig(struct ipa *ipa)
 	ipa->notifier = NULL;
 	memset(&ipa->nb, 0, sizeof(ipa->nb));
 }
-
-int ipa_modem_setup(struct ipa *ipa)
-{
-	return ipa_qmi_setup(ipa);
-}
-
-void ipa_modem_teardown(struct ipa *ipa)
-{
-	ipa_qmi_teardown(ipa);
-}
diff --git a/drivers/net/ipa/ipa_modem.h b/drivers/net/ipa/ipa_modem.h
index 2de3e216d1d43..5e6e3d234454a 100644
--- a/drivers/net/ipa/ipa_modem.h
+++ b/drivers/net/ipa/ipa_modem.h
@@ -7,7 +7,6 @@
 #define _IPA_MODEM_H_
 
 struct ipa;
-struct ipa_endpoint;
 struct net_device;
 struct sk_buff;
 
@@ -25,7 +24,4 @@ void ipa_modem_exit(struct ipa *ipa);
 int ipa_modem_config(struct ipa *ipa);
 void ipa_modem_deconfig(struct ipa *ipa);
 
-int ipa_modem_setup(struct ipa *ipa);
-void ipa_modem_teardown(struct ipa *ipa);
-
 #endif /* _IPA_MODEM_H_ */
diff --git a/drivers/net/ipa/ipa_qmi.c b/drivers/net/ipa/ipa_qmi.c
index 4661105ce7ab2..90f3aec55b365 100644
--- a/drivers/net/ipa/ipa_qmi.c
+++ b/drivers/net/ipa/ipa_qmi.c
@@ -467,10 +467,7 @@ static const struct qmi_ops ipa_client_ops = {
 	.new_server	= ipa_client_new_server,
 };
 
-/* This is called by ipa_setup().  We can be informed via remoteproc that
- * the modem has shut down, in which case this function will be called
- * again to prepare for it coming back up again.
- */
+/* Set up for QMI message exchange */
 int ipa_qmi_setup(struct ipa *ipa)
 {
 	struct ipa_qmi *ipa_qmi = &ipa->qmi;
@@ -526,6 +523,7 @@ int ipa_qmi_setup(struct ipa *ipa)
 	return ret;
 }
 
+/* Tear down IPA QMI handles */
 void ipa_qmi_teardown(struct ipa *ipa)
 {
 	cancel_work_sync(&ipa->qmi.init_driver_work);
diff --git a/drivers/net/ipa/ipa_qmi.h b/drivers/net/ipa/ipa_qmi.h
index b6f2055d35a68..856ef629ccc8d 100644
--- a/drivers/net/ipa/ipa_qmi.h
+++ b/drivers/net/ipa/ipa_qmi.h
@@ -39,7 +39,26 @@ struct ipa_qmi {
 	bool indication_sent;
 };
 
+/**
+ * ipa_qmi_setup() - Set up for QMI message exchange
+ * @ipa:		IPA pointer
+ *
+ * This is called at the end of ipa_setup(), to prepare for the exchange
+ * of QMI messages that perform a "handshake" between the AP and modem.
+ * When the modem QMI server announces its presence, an AP request message
+ * supplies operating parameters to be used to the modem, and the modem
+ * acknowledges receipt of those parameters.  The modem will not touch the
+ * IPA hardware until this handshake is complete.
+ *
+ * If the modem crashes (or shuts down) a new handshake begins when the
+ * modem's QMI server is started again.
+ */
 int ipa_qmi_setup(struct ipa *ipa);
+
+/**
+ * ipa_qmi_teardown() - Tear down IPA QMI handles
+ * @ipa:		IPA pointer
+ */
 void ipa_qmi_teardown(struct ipa *ipa);
 
 #endif /* !_IPA_QMI_H_ */
-- 
2.27.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH net-next 2/5] net: ipa: configure memory regions early
  2021-07-26 20:11 [PATCH net-next 0/5] net: ipa: defer taking uC proxy clock Alex Elder
  2021-07-26 20:11 ` [PATCH net-next 1/5] net: ipa: kill ipa_modem_setup() Alex Elder
@ 2021-07-26 20:11 ` Alex Elder
  2021-07-26 20:11 ` [PATCH net-next 3/5] net: ipa: set up IPA interrupts earlier Alex Elder
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Alex Elder @ 2021-07-26 20:11 UTC (permalink / raw)
  To: davem, kuba
  Cc: bjorn.andersson, evgreen, cpratapa, subashab, elder, netdev,
	linux-kernel

IPA-resident memory is one of the most primitive resources that
needs initialization, so call init_mem_config() early in
ipa_config().

This is in preparation for initializing the IPA-resident
microcontroller earlier.

Signed-off-by: Alex Elder <elder@linaro.org>
---
 drivers/net/ipa/ipa_main.c | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/drivers/net/ipa/ipa_main.c b/drivers/net/ipa/ipa_main.c
index 91e2ec3a0c133..8768e52854d08 100644
--- a/drivers/net/ipa/ipa_main.c
+++ b/drivers/net/ipa/ipa_main.c
@@ -471,31 +471,31 @@ static int ipa_config(struct ipa *ipa, const struct ipa_data *data)
 
 	ipa_hardware_config(ipa, data);
 
-	ret = ipa_endpoint_config(ipa);
-	if (ret)
-		goto err_hardware_deconfig;
-
 	ret = ipa_mem_config(ipa);
 	if (ret)
-		goto err_endpoint_deconfig;
+		goto err_hardware_deconfig;
+
+	ret = ipa_endpoint_config(ipa);
+	if (ret)
+		goto err_mem_deconfig;
 
 	ipa_table_config(ipa);		/* No deconfig required */
 
 	/* Assign resource limitation to each group; no deconfig required */
 	ret = ipa_resource_config(ipa, data->resource_data);
 	if (ret)
-		goto err_mem_deconfig;
+		goto err_endpoint_deconfig;
 
 	ret = ipa_modem_config(ipa);
 	if (ret)
-		goto err_mem_deconfig;
+		goto err_endpoint_deconfig;
 
 	return 0;
 
-err_mem_deconfig:
-	ipa_mem_deconfig(ipa);
 err_endpoint_deconfig:
 	ipa_endpoint_deconfig(ipa);
+err_mem_deconfig:
+	ipa_mem_deconfig(ipa);
 err_hardware_deconfig:
 	ipa_hardware_deconfig(ipa);
 	ipa_clock_put(ipa);
@@ -510,8 +510,8 @@ static int ipa_config(struct ipa *ipa, const struct ipa_data *data)
 static void ipa_deconfig(struct ipa *ipa)
 {
 	ipa_modem_deconfig(ipa);
-	ipa_mem_deconfig(ipa);
 	ipa_endpoint_deconfig(ipa);
+	ipa_mem_deconfig(ipa);
 	ipa_hardware_deconfig(ipa);
 	ipa_clock_put(ipa);
 }
-- 
2.27.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH net-next 3/5] net: ipa: set up IPA interrupts earlier
  2021-07-26 20:11 [PATCH net-next 0/5] net: ipa: defer taking uC proxy clock Alex Elder
  2021-07-26 20:11 ` [PATCH net-next 1/5] net: ipa: kill ipa_modem_setup() Alex Elder
  2021-07-26 20:11 ` [PATCH net-next 2/5] net: ipa: configure memory regions early Alex Elder
@ 2021-07-26 20:11 ` Alex Elder
  2021-07-26 20:11 ` [PATCH net-next 4/5] net: ipa: set up the microcontroller earlier Alex Elder
  2021-07-26 20:11 ` [PATCH net-next 5/5] net: ipa: introduce ipa_uc_clock() Alex Elder
  4 siblings, 0 replies; 6+ messages in thread
From: Alex Elder @ 2021-07-26 20:11 UTC (permalink / raw)
  To: davem, kuba
  Cc: bjorn.andersson, evgreen, cpratapa, subashab, elder, netdev,
	linux-kernel

Initialization of the IPA driver has several phases:
   - "init" phase can be done without any access to IPA hardware
   - "config" phase requires the IPA hardware to be clocked
   - "setup" phase requires the GSI layer to be functional

Currently, initialization for the IPA interrupt handling code occurs
in the setup phase.  It requires access to the IPA hardware but does
not need GSI, so it can be moved to the config phase instead.

Call the interrupt configuration function early in ipa_config()
rather than from ipa_setup().  Rename ipa_interrupt_setup() to be
ipa_interrupt_config(), and ipa_interrupt_teardown() to be
ipa_interupt_deconfig(), so their names properly indicate when
they get called.

Signed-off-by: Alex Elder <elder@linaro.org>
---
 drivers/net/ipa/ipa_interrupt.c |  8 ++++----
 drivers/net/ipa/ipa_interrupt.h |  8 ++++----
 drivers/net/ipa/ipa_main.c      | 24 ++++++++++++++----------
 3 files changed, 22 insertions(+), 18 deletions(-)

diff --git a/drivers/net/ipa/ipa_interrupt.c b/drivers/net/ipa/ipa_interrupt.c
index c46df0b7c4e50..46a983aeebc8b 100644
--- a/drivers/net/ipa/ipa_interrupt.c
+++ b/drivers/net/ipa/ipa_interrupt.c
@@ -231,8 +231,8 @@ ipa_interrupt_remove(struct ipa_interrupt *interrupt, enum ipa_irq_id ipa_irq)
 	interrupt->handler[ipa_irq] = NULL;
 }
 
-/* Set up the IPA interrupt framework */
-struct ipa_interrupt *ipa_interrupt_setup(struct ipa *ipa)
+/* Configure the IPA interrupt framework */
+struct ipa_interrupt *ipa_interrupt_config(struct ipa *ipa)
 {
 	struct device *dev = &ipa->pdev->dev;
 	struct ipa_interrupt *interrupt;
@@ -281,8 +281,8 @@ struct ipa_interrupt *ipa_interrupt_setup(struct ipa *ipa)
 	return ERR_PTR(ret);
 }
 
-/* Tear down the IPA interrupt framework */
-void ipa_interrupt_teardown(struct ipa_interrupt *interrupt)
+/* Inverse of ipa_interrupt_config() */
+void ipa_interrupt_deconfig(struct ipa_interrupt *interrupt)
 {
 	struct device *dev = &interrupt->ipa->pdev->dev;
 	int ret;
diff --git a/drivers/net/ipa/ipa_interrupt.h b/drivers/net/ipa/ipa_interrupt.h
index d5c486a6800d9..231390cea52a2 100644
--- a/drivers/net/ipa/ipa_interrupt.h
+++ b/drivers/net/ipa/ipa_interrupt.h
@@ -86,17 +86,17 @@ void ipa_interrupt_suspend_clear_all(struct ipa_interrupt *interrupt);
 void ipa_interrupt_simulate_suspend(struct ipa_interrupt *interrupt);
 
 /**
- * ipa_interrupt_setup() - Set up the IPA interrupt framework
+ * ipa_interrupt_config() - Configure the IPA interrupt framework
  * @ipa:	IPA pointer
  *
  * Return:	Pointer to IPA SMP2P info, or a pointer-coded error
  */
-struct ipa_interrupt *ipa_interrupt_setup(struct ipa *ipa);
+struct ipa_interrupt *ipa_interrupt_config(struct ipa *ipa);
 
 /**
- * ipa_interrupt_teardown() - Tear down the IPA interrupt framework
+ * ipa_interrupt_deconfig() - Inverse of ipa_interrupt_config()
  * @interrupt:	IPA interrupt structure
  */
-void ipa_interrupt_teardown(struct ipa_interrupt *interrupt);
+void ipa_interrupt_deconfig(struct ipa_interrupt *interrupt);
 
 #endif /* _IPA_INTERRUPT_H_ */
diff --git a/drivers/net/ipa/ipa_main.c b/drivers/net/ipa/ipa_main.c
index 8768e52854d08..c26acd8b1cb91 100644
--- a/drivers/net/ipa/ipa_main.c
+++ b/drivers/net/ipa/ipa_main.c
@@ -124,11 +124,6 @@ int ipa_setup(struct ipa *ipa)
 	if (ret)
 		return ret;
 
-	ipa->interrupt = ipa_interrupt_setup(ipa);
-	if (IS_ERR(ipa->interrupt)) {
-		ret = PTR_ERR(ipa->interrupt);
-		goto err_gsi_teardown;
-	}
 	ipa_interrupt_add(ipa->interrupt, IPA_IRQ_TX_SUSPEND,
 			  ipa_suspend_handler);
 
@@ -188,8 +183,6 @@ int ipa_setup(struct ipa *ipa)
 err_uc_teardown:
 	ipa_uc_teardown(ipa);
 	ipa_interrupt_remove(ipa->interrupt, IPA_IRQ_TX_SUSPEND);
-	ipa_interrupt_teardown(ipa->interrupt);
-err_gsi_teardown:
 	gsi_teardown(&ipa->gsi);
 
 	return ret;
@@ -214,7 +207,6 @@ static void ipa_teardown(struct ipa *ipa)
 	(void)device_init_wakeup(&ipa->pdev->dev, false);
 	ipa_uc_teardown(ipa);
 	ipa_interrupt_remove(ipa->interrupt, IPA_IRQ_TX_SUSPEND);
-	ipa_interrupt_teardown(ipa->interrupt);
 	gsi_teardown(&ipa->gsi);
 }
 
@@ -475,9 +467,16 @@ static int ipa_config(struct ipa *ipa, const struct ipa_data *data)
 	if (ret)
 		goto err_hardware_deconfig;
 
-	ret = ipa_endpoint_config(ipa);
-	if (ret)
+	ipa->interrupt = ipa_interrupt_config(ipa);
+	if (IS_ERR(ipa->interrupt)) {
+		ret = PTR_ERR(ipa->interrupt);
+		ipa->interrupt = NULL;
 		goto err_mem_deconfig;
+	}
+
+	ret = ipa_endpoint_config(ipa);
+	if (ret)
+		goto err_interrupt_deconfig;
 
 	ipa_table_config(ipa);		/* No deconfig required */
 
@@ -494,6 +493,9 @@ static int ipa_config(struct ipa *ipa, const struct ipa_data *data)
 
 err_endpoint_deconfig:
 	ipa_endpoint_deconfig(ipa);
+err_interrupt_deconfig:
+	ipa_interrupt_deconfig(ipa->interrupt);
+	ipa->interrupt = NULL;
 err_mem_deconfig:
 	ipa_mem_deconfig(ipa);
 err_hardware_deconfig:
@@ -511,6 +513,8 @@ static void ipa_deconfig(struct ipa *ipa)
 {
 	ipa_modem_deconfig(ipa);
 	ipa_endpoint_deconfig(ipa);
+	ipa_interrupt_deconfig(ipa->interrupt);
+	ipa->interrupt = NULL;
 	ipa_mem_deconfig(ipa);
 	ipa_hardware_deconfig(ipa);
 	ipa_clock_put(ipa);
-- 
2.27.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH net-next 4/5] net: ipa: set up the microcontroller earlier
  2021-07-26 20:11 [PATCH net-next 0/5] net: ipa: defer taking uC proxy clock Alex Elder
                   ` (2 preceding siblings ...)
  2021-07-26 20:11 ` [PATCH net-next 3/5] net: ipa: set up IPA interrupts earlier Alex Elder
@ 2021-07-26 20:11 ` Alex Elder
  2021-07-26 20:11 ` [PATCH net-next 5/5] net: ipa: introduce ipa_uc_clock() Alex Elder
  4 siblings, 0 replies; 6+ messages in thread
From: Alex Elder @ 2021-07-26 20:11 UTC (permalink / raw)
  To: davem, kuba
  Cc: bjorn.andersson, evgreen, cpratapa, subashab, elder, netdev,
	linux-kernel

Initializing up the IPA-resident microcontroller requires the IPA
clock, and sets up two IPA interrupt handlers, but this does not
require GSI access.  The interrupt handlers also require the clock
to be enabled, and require the IPA memory regions to be configured,
but neither requires GSI access.  As a result, the microcontroller
can be initialized during the "config" rather than "setup" phase of
IPA initialization.

Initialize the microcontroller in ipa_config() rather than
ipa_setup(), and rename the called function ipa_uc_config().
Do the inverse in ipa_deconfig() rather than ipa_teardown(),
and rename the function for that case ipa_uc_deconfig().

Signed-off-by: Alex Elder <elder@linaro.org>
---
 drivers/net/ipa/ipa_main.c | 12 ++++++------
 drivers/net/ipa/ipa_uc.c   |  8 ++++----
 drivers/net/ipa/ipa_uc.h   |  8 ++++----
 3 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/drivers/net/ipa/ipa_main.c b/drivers/net/ipa/ipa_main.c
index c26acd8b1cb91..d83322bf9e7e5 100644
--- a/drivers/net/ipa/ipa_main.c
+++ b/drivers/net/ipa/ipa_main.c
@@ -127,11 +127,9 @@ int ipa_setup(struct ipa *ipa)
 	ipa_interrupt_add(ipa->interrupt, IPA_IRQ_TX_SUSPEND,
 			  ipa_suspend_handler);
 
-	ipa_uc_setup(ipa);
-
 	ret = device_init_wakeup(dev, true);
 	if (ret)
-		goto err_uc_teardown;
+		goto err_interrupt_remove;
 
 	ipa_endpoint_setup(ipa);
 
@@ -180,8 +178,7 @@ int ipa_setup(struct ipa *ipa)
 err_endpoint_teardown:
 	ipa_endpoint_teardown(ipa);
 	(void)device_init_wakeup(dev, false);
-err_uc_teardown:
-	ipa_uc_teardown(ipa);
+err_interrupt_remove:
 	ipa_interrupt_remove(ipa->interrupt, IPA_IRQ_TX_SUSPEND);
 	gsi_teardown(&ipa->gsi);
 
@@ -205,7 +202,6 @@ static void ipa_teardown(struct ipa *ipa)
 	ipa_endpoint_disable_one(command_endpoint);
 	ipa_endpoint_teardown(ipa);
 	(void)device_init_wakeup(&ipa->pdev->dev, false);
-	ipa_uc_teardown(ipa);
 	ipa_interrupt_remove(ipa->interrupt, IPA_IRQ_TX_SUSPEND);
 	gsi_teardown(&ipa->gsi);
 }
@@ -474,6 +470,8 @@ static int ipa_config(struct ipa *ipa, const struct ipa_data *data)
 		goto err_mem_deconfig;
 	}
 
+	ipa_uc_config(ipa);
+
 	ret = ipa_endpoint_config(ipa);
 	if (ret)
 		goto err_interrupt_deconfig;
@@ -494,6 +492,7 @@ static int ipa_config(struct ipa *ipa, const struct ipa_data *data)
 err_endpoint_deconfig:
 	ipa_endpoint_deconfig(ipa);
 err_interrupt_deconfig:
+	ipa_uc_deconfig(ipa);
 	ipa_interrupt_deconfig(ipa->interrupt);
 	ipa->interrupt = NULL;
 err_mem_deconfig:
@@ -513,6 +512,7 @@ static void ipa_deconfig(struct ipa *ipa)
 {
 	ipa_modem_deconfig(ipa);
 	ipa_endpoint_deconfig(ipa);
+	ipa_uc_deconfig(ipa);
 	ipa_interrupt_deconfig(ipa->interrupt);
 	ipa->interrupt = NULL;
 	ipa_mem_deconfig(ipa);
diff --git a/drivers/net/ipa/ipa_uc.c b/drivers/net/ipa/ipa_uc.c
index fd9219863234c..8b5e75711b644 100644
--- a/drivers/net/ipa/ipa_uc.c
+++ b/drivers/net/ipa/ipa_uc.c
@@ -162,8 +162,8 @@ static void ipa_uc_response_hdlr(struct ipa *ipa, enum ipa_irq_id irq_id)
 	}
 }
 
-/* ipa_uc_setup() - Set up the microcontroller */
-void ipa_uc_setup(struct ipa *ipa)
+/* Configure the IPA microcontroller subsystem */
+void ipa_uc_config(struct ipa *ipa)
 {
 	/* The microcontroller needs the IPA clock running until it has
 	 * completed its initialization.  It signals this by sending an
@@ -180,8 +180,8 @@ void ipa_uc_setup(struct ipa *ipa)
 	ipa_interrupt_add(ipa->interrupt, IPA_IRQ_UC_1, ipa_uc_response_hdlr);
 }
 
-/* Inverse of ipa_uc_setup() */
-void ipa_uc_teardown(struct ipa *ipa)
+/* Inverse of ipa_uc_config() */
+void ipa_uc_deconfig(struct ipa *ipa)
 {
 	ipa_interrupt_remove(ipa->interrupt, IPA_IRQ_UC_1);
 	ipa_interrupt_remove(ipa->interrupt, IPA_IRQ_UC_0);
diff --git a/drivers/net/ipa/ipa_uc.h b/drivers/net/ipa/ipa_uc.h
index e8510899a3f0a..cb0a224022f58 100644
--- a/drivers/net/ipa/ipa_uc.h
+++ b/drivers/net/ipa/ipa_uc.h
@@ -9,16 +9,16 @@
 struct ipa;
 
 /**
- * ipa_uc_setup() - set up the IPA microcontroller subsystem
+ * ipa_uc_config() - Configure the IPA microcontroller subsystem
  * @ipa:	IPA pointer
  */
-void ipa_uc_setup(struct ipa *ipa);
+void ipa_uc_config(struct ipa *ipa);
 
 /**
- * ipa_uc_teardown() - inverse of ipa_uc_setup()
+ * ipa_uc_deconfig() - Inverse of ipa_uc_config()
  * @ipa:	IPA pointer
  */
-void ipa_uc_teardown(struct ipa *ipa);
+void ipa_uc_deconfig(struct ipa *ipa);
 
 /**
  * ipa_uc_panic_notifier()
-- 
2.27.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH net-next 5/5] net: ipa: introduce ipa_uc_clock()
  2021-07-26 20:11 [PATCH net-next 0/5] net: ipa: defer taking uC proxy clock Alex Elder
                   ` (3 preceding siblings ...)
  2021-07-26 20:11 ` [PATCH net-next 4/5] net: ipa: set up the microcontroller earlier Alex Elder
@ 2021-07-26 20:11 ` Alex Elder
  4 siblings, 0 replies; 6+ messages in thread
From: Alex Elder @ 2021-07-26 20:11 UTC (permalink / raw)
  To: davem, kuba
  Cc: bjorn.andersson, evgreen, cpratapa, subashab, elder, netdev,
	linux-kernel

The first time it's booted, the modem loads and starts the
IPA-resident microcontroller.  Once the microcontroller has
completed its initialization, it notifies the AP it's "ready"
by sending an INIT_COMPLETED response message.

Until it receives that microcontroller message, the AP must ensure
the IPA core clock remains operational.  Currently, a "proxy" clock
reference is taken in ipa_uc_config(), dropping it again once the
message is received.

However there could be a long delay between when ipa_config()
completes and when modem actually starts.  And because the
microcontroller gets loaded by the modem, there's no need to
get the modem "proxy clock" until the first time it starts.

Create a new function ipa_uc_clock() which takes the "proxy" clock
reference for the microcontroller.  Call it when we get remoteproc
SSR notification that the modem is about to start.  Keep an
additional flag to record whether this proxy clock reference needs
to be dropped at shutdown time, and issue a warning if we get the
microcontroller message either before the clock reference is taken,
or after it has already been dropped.

Drop the nearby use of "hh" length modifiers, which are no longer
encouraged in the kernel.

Signed-off-by: Alex Elder <elder@linaro.org>
---
 drivers/net/ipa/ipa.h       |  2 ++
 drivers/net/ipa/ipa_modem.c |  2 ++
 drivers/net/ipa/ipa_uc.c    | 44 +++++++++++++++++++++++--------------
 drivers/net/ipa/ipa_uc.h    | 14 ++++++++++++
 4 files changed, 45 insertions(+), 17 deletions(-)

diff --git a/drivers/net/ipa/ipa.h b/drivers/net/ipa/ipa.h
index 744406832a774..71ba996096bb9 100644
--- a/drivers/net/ipa/ipa.h
+++ b/drivers/net/ipa/ipa.h
@@ -51,6 +51,7 @@ enum ipa_flag {
  * @table_addr:		DMA address of filter/route table content
  * @table_virt:		Virtual address of filter/route table content
  * @interrupt:		IPA Interrupt information
+ * @uc_clocked:		true if clock is active by proxy for microcontroller
  * @uc_loaded:		true after microcontroller has reported it's ready
  * @reg_addr:		DMA address used for IPA register access
  * @reg_virt:		Virtual address used for IPA register access
@@ -95,6 +96,7 @@ struct ipa {
 	__le64 *table_virt;
 
 	struct ipa_interrupt *interrupt;
+	bool uc_clocked;
 	bool uc_loaded;
 
 	dma_addr_t reg_addr;
diff --git a/drivers/net/ipa/ipa_modem.c b/drivers/net/ipa/ipa_modem.c
index 5cb60e2ea6042..c851e2cf12552 100644
--- a/drivers/net/ipa/ipa_modem.c
+++ b/drivers/net/ipa/ipa_modem.c
@@ -19,6 +19,7 @@
 #include "ipa_modem.h"
 #include "ipa_smp2p.h"
 #include "ipa_qmi.h"
+#include "ipa_uc.h"
 
 #define IPA_NETDEV_NAME		"rmnet_ipa%d"
 #define IPA_NETDEV_TAILROOM	0	/* for padding by mux layer */
@@ -314,6 +315,7 @@ static int ipa_modem_notify(struct notifier_block *nb, unsigned long action,
 	switch (action) {
 	case QCOM_SSR_BEFORE_POWERUP:
 		dev_info(dev, "received modem starting event\n");
+		ipa_uc_clock(ipa);
 		ipa_smp2p_notify_reset(ipa);
 		break;
 
diff --git a/drivers/net/ipa/ipa_uc.c b/drivers/net/ipa/ipa_uc.c
index 8b5e75711b644..f88ee02457d49 100644
--- a/drivers/net/ipa/ipa_uc.c
+++ b/drivers/net/ipa/ipa_uc.c
@@ -131,7 +131,7 @@ static void ipa_uc_event_handler(struct ipa *ipa, enum ipa_irq_id irq_id)
 	if (shared->event == IPA_UC_EVENT_ERROR)
 		dev_err(dev, "microcontroller error event\n");
 	else if (shared->event != IPA_UC_EVENT_LOG_INFO)
-		dev_err(dev, "unsupported microcontroller event %hhu\n",
+		dev_err(dev, "unsupported microcontroller event %u\n",
 			shared->event);
 	/* The LOG_INFO event can be safely ignored */
 }
@@ -140,23 +140,28 @@ static void ipa_uc_event_handler(struct ipa *ipa, enum ipa_irq_id irq_id)
 static void ipa_uc_response_hdlr(struct ipa *ipa, enum ipa_irq_id irq_id)
 {
 	struct ipa_uc_mem_area *shared = ipa_uc_shared(ipa);
+	struct device *dev = &ipa->pdev->dev;
 
 	/* An INIT_COMPLETED response message is sent to the AP by the
 	 * microcontroller when it is operational.  Other than this, the AP
 	 * should only receive responses from the microcontroller when it has
 	 * sent it a request message.
 	 *
-	 * We can drop the clock reference taken in ipa_uc_setup() once we
+	 * We can drop the clock reference taken in ipa_uc_clock() once we
 	 * know the microcontroller has finished its initialization.
 	 */
 	switch (shared->response) {
 	case IPA_UC_RESPONSE_INIT_COMPLETED:
-		ipa->uc_loaded = true;
-		ipa_clock_put(ipa);
+		if (ipa->uc_clocked) {
+			ipa->uc_loaded = true;
+			ipa_clock_put(ipa);
+			ipa->uc_clocked = false;
+		} else {
+			dev_warn(dev, "unexpected init_completed response\n");
+		}
 		break;
 	default:
-		dev_warn(&ipa->pdev->dev,
-			 "unsupported microcontroller response %hhu\n",
+		dev_warn(dev, "unsupported microcontroller response %u\n",
 			 shared->response);
 		break;
 	}
@@ -165,16 +170,7 @@ static void ipa_uc_response_hdlr(struct ipa *ipa, enum ipa_irq_id irq_id)
 /* Configure the IPA microcontroller subsystem */
 void ipa_uc_config(struct ipa *ipa)
 {
-	/* The microcontroller needs the IPA clock running until it has
-	 * completed its initialization.  It signals this by sending an
-	 * INIT_COMPLETED response message to the AP.  This could occur after
-	 * we have finished doing the rest of the IPA initialization, so we
-	 * need to take an extra "proxy" reference, and hold it until we've
-	 * received that signal.  (This reference is dropped in
-	 * ipa_uc_response_hdlr(), above.)
-	 */
-	ipa_clock_get(ipa);
-
+	ipa->uc_clocked = false;
 	ipa->uc_loaded = false;
 	ipa_interrupt_add(ipa->interrupt, IPA_IRQ_UC_0, ipa_uc_event_handler);
 	ipa_interrupt_add(ipa->interrupt, IPA_IRQ_UC_1, ipa_uc_response_hdlr);
@@ -185,10 +181,24 @@ void ipa_uc_deconfig(struct ipa *ipa)
 {
 	ipa_interrupt_remove(ipa->interrupt, IPA_IRQ_UC_1);
 	ipa_interrupt_remove(ipa->interrupt, IPA_IRQ_UC_0);
-	if (!ipa->uc_loaded)
+	if (ipa->uc_clocked)
 		ipa_clock_put(ipa);
 }
 
+/* Take a proxy clock reference for the microcontroller */
+void ipa_uc_clock(struct ipa *ipa)
+{
+	static bool already;
+
+	if (already)
+		return;
+	already = true;		/* Only do this on first boot */
+
+	/* This clock reference dropped in ipa_uc_response_hdlr() above */
+	ipa_clock_get(ipa);
+	ipa->uc_clocked = true;
+}
+
 /* Send a command to the microcontroller */
 static void send_uc_command(struct ipa *ipa, u32 command, u32 command_param)
 {
diff --git a/drivers/net/ipa/ipa_uc.h b/drivers/net/ipa/ipa_uc.h
index cb0a224022f58..14e4e1115aa79 100644
--- a/drivers/net/ipa/ipa_uc.h
+++ b/drivers/net/ipa/ipa_uc.h
@@ -20,6 +20,20 @@ void ipa_uc_config(struct ipa *ipa);
  */
 void ipa_uc_deconfig(struct ipa *ipa);
 
+/**
+ * ipa_uc_clock() - Take a proxy clock reference for the microcontroller
+ * @ipa:	IPA pointer
+ *
+ * The first time the modem boots, it loads firmware for and starts the
+ * IPA-resident microcontroller.  The microcontroller signals that it
+ * has completed its initialization by sending an INIT_COMPLETED response
+ * message to the AP.  The AP must ensure the IPA core clock is operating
+ * until it receives this message, and to do so we take a "proxy" clock
+ * reference on its behalf here.  Once we receive the INIT_COMPLETED
+ * message (in ipa_uc_response_hdlr()) we drop this clock reference.
+ */
+void ipa_uc_clock(struct ipa *ipa);
+
 /**
  * ipa_uc_panic_notifier()
  * @ipa:	IPA pointer
-- 
2.27.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2021-07-26 20:12 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-26 20:11 [PATCH net-next 0/5] net: ipa: defer taking uC proxy clock Alex Elder
2021-07-26 20:11 ` [PATCH net-next 1/5] net: ipa: kill ipa_modem_setup() Alex Elder
2021-07-26 20:11 ` [PATCH net-next 2/5] net: ipa: configure memory regions early Alex Elder
2021-07-26 20:11 ` [PATCH net-next 3/5] net: ipa: set up IPA interrupts earlier Alex Elder
2021-07-26 20:11 ` [PATCH net-next 4/5] net: ipa: set up the microcontroller earlier Alex Elder
2021-07-26 20:11 ` [PATCH net-next 5/5] net: ipa: introduce ipa_uc_clock() Alex Elder

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).