netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [net-next v7 1/4] wwan: core: Add WWAN fastboot port type
       [not found] <20240201151340.4963-1-songjinjian@hotmail.com>
@ 2024-02-01 15:13 ` Jinjian Song
  2024-02-01 15:13 ` [net-next v7 2/4] net: wwan: t7xx: Add sysfs attribute for device state machine Jinjian Song
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 10+ messages in thread
From: Jinjian Song @ 2024-02-01 15:13 UTC (permalink / raw)
  To: netdev
  Cc: chandrashekar.devegowda, chiranjeevi.rapolu, haijun.liu,
	m.chetan.kumar, ricardo.martinez, loic.poulain, ryazanov.s.a,
	johannes, davem, edumazet, kuba, pabeni, linux-kernel, vsankar,
	letitia.tsai, pin-hao.huang, danielwinkler, nmarupaka, joey.zhao,
	liuqf, felix.yan, angel.huang, freddy.lin, alan.zhang1, zhangrc,
	Jinjian Song

From: Jinjian Song <jinjian.song@fibocom.com>

Add a new WWAN port that connects to the device fastboot protocol
interface.

Signed-off-by: Jinjian Song <jinjian.song@fibocom.com>
---
v2-v7:
 * no change
---
 drivers/net/wwan/wwan_core.c | 4 ++++
 include/linux/wwan.h         | 2 ++
 2 files changed, 6 insertions(+)

diff --git a/drivers/net/wwan/wwan_core.c b/drivers/net/wwan/wwan_core.c
index 72e01e550a16..2ed20b20e7fc 100644
--- a/drivers/net/wwan/wwan_core.c
+++ b/drivers/net/wwan/wwan_core.c
@@ -328,6 +328,10 @@ static const struct {
 		.name = "XMMRPC",
 		.devsuf = "xmmrpc",
 	},
+	[WWAN_PORT_FASTBOOT] = {
+		.name = "FASTBOOT",
+		.devsuf = "fastboot",
+	},
 };
 
 static ssize_t type_show(struct device *dev, struct device_attribute *attr,
diff --git a/include/linux/wwan.h b/include/linux/wwan.h
index 01fa15506286..170fdee6339c 100644
--- a/include/linux/wwan.h
+++ b/include/linux/wwan.h
@@ -16,6 +16,7 @@
  * @WWAN_PORT_QCDM: Qcom Modem diagnostic interface
  * @WWAN_PORT_FIREHOSE: XML based command protocol
  * @WWAN_PORT_XMMRPC: Control protocol for Intel XMM modems
+ * @WWAN_PORT_FASTBOOT: Fastboot protocol control
  *
  * @WWAN_PORT_MAX: Highest supported port types
  * @WWAN_PORT_UNKNOWN: Special value to indicate an unknown port type
@@ -28,6 +29,7 @@ enum wwan_port_type {
 	WWAN_PORT_QCDM,
 	WWAN_PORT_FIREHOSE,
 	WWAN_PORT_XMMRPC,
+	WWAN_PORT_FASTBOOT,
 
 	/* Add new port types above this line */
 
-- 
2.34.1


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

* [net-next v7 2/4] net: wwan: t7xx: Add sysfs attribute for device state machine
       [not found] <20240201151340.4963-1-songjinjian@hotmail.com>
  2024-02-01 15:13 ` [net-next v7 1/4] wwan: core: Add WWAN fastboot port type Jinjian Song
@ 2024-02-01 15:13 ` Jinjian Song
  2024-02-01 16:11   ` Jiri Pirko
  2024-02-02  2:16   ` Jinjian Song
  2024-02-01 15:13 ` [net-next v7 3/4] net: wwan: t7xx: Infrastructure for early port configuration Jinjian Song
  2024-02-01 15:13 ` [net-next v7 4/4] net: wwan: t7xx: Add fastboot WWAN port Jinjian Song
  3 siblings, 2 replies; 10+ messages in thread
From: Jinjian Song @ 2024-02-01 15:13 UTC (permalink / raw)
  To: netdev
  Cc: chandrashekar.devegowda, chiranjeevi.rapolu, haijun.liu,
	m.chetan.kumar, ricardo.martinez, loic.poulain, ryazanov.s.a,
	johannes, davem, edumazet, kuba, pabeni, linux-kernel, vsankar,
	letitia.tsai, pin-hao.huang, danielwinkler, nmarupaka, joey.zhao,
	liuqf, felix.yan, angel.huang, freddy.lin, alan.zhang1, zhangrc,
	Jinjian Song

From: Jinjian Song <jinjian.song@fibocom.com>

Add support for userspace to get/set the device mode, device's state machine
changes between (UNKNOWN/READY/RESET/FASTBOOT_DL_MODE/FASTBOOT_DUMP_MODE).

Get the device state mode:
 - 'cat /sys/bus/pci/devices/${bdf}/t7xx_mode'

Set the device state mode:
 - reset(cold reset): 'echo RESET > /sys/bus/pci/devices/${bdf}/t7xx_mode'
 - fastboot: 'echo FASTBOOT_DL_SWITCHING > /sys/bus/pci/devices/${bdf}/t7xx_mode'
Reload driver to get the new device state after setting operation.

Signed-off-by: Jinjian Song <jinjian.song@fibocom.com>
---
v7:
 * add sysfs description to commit info 
 * update t7xx_dev->mode after reset by sysfs t7xx_mode
v6:
 * change code style in t7xx_mode_store()
v5:
 * add cold reset support via sysfs t7xx_mode
v4:
 * narrow down the set of accepted values in t7xx_mode_store()
 * change mode type atomic to u32 with READ_ONCE()/WRITE_ONCE()
 * delete 'T7XX_MODEM' prefix and using sysfs_emit in t7xx_mode_show()
 * add description of sysfs t7xx_mode in document t7xx.rst
v2:
 * optimizing using goto label in t7xx_pci_probe
---
 .../networking/device_drivers/wwan/t7xx.rst   | 28 ++++++
 drivers/net/wwan/t7xx/t7xx_modem_ops.c        |  6 ++
 drivers/net/wwan/t7xx/t7xx_modem_ops.h        |  1 +
 drivers/net/wwan/t7xx/t7xx_pci.c              | 98 ++++++++++++++++++-
 drivers/net/wwan/t7xx/t7xx_pci.h              | 14 ++-
 drivers/net/wwan/t7xx/t7xx_state_monitor.c    |  1 +
 6 files changed, 143 insertions(+), 5 deletions(-)

diff --git a/Documentation/networking/device_drivers/wwan/t7xx.rst b/Documentation/networking/device_drivers/wwan/t7xx.rst
index dd5b731957ca..d13624a52d8b 100644
--- a/Documentation/networking/device_drivers/wwan/t7xx.rst
+++ b/Documentation/networking/device_drivers/wwan/t7xx.rst
@@ -39,6 +39,34 @@ command and receive response:
 
 - open the AT control channel using a UART tool or a special user tool
 
+Sysfs
+=====
+The driver provides sysfs interfaces to userspace.
+
+t7xx_mode
+---------
+The sysfs interface provides userspace with access to the device mode, this interface
+supports read and write operations.
+
+Device mode:
+
+- ``UNKNOW`` represents that device in unknown status
+- ``READY`` represents that device in ready status
+- ``RESET`` represents that device in reset status
+- ``FASTBOOT_DL_SWITCHING`` represents that device in fastboot switching status
+- ``FASTBOOT_DL_MODE`` represents that device in fastboot download status
+- ``FASTBOOT_DL_DUMP_MODE`` represents that device in fastboot dump status
+
+Read from userspace to get the current device mode.
+
+::
+  $ cat /sys/bus/pci/devices/${bdf}/t7xx_mode
+
+Write from userspace to set the device mode.
+
+::
+  $ echo FASTBOOT_DL_SWITCHING > /sys/bus/pci/devices/${bdf}/t7xx_mode
+
 Management application development
 ==================================
 The driver and userspace interfaces are described below. The MBIM protocol is
diff --git a/drivers/net/wwan/t7xx/t7xx_modem_ops.c b/drivers/net/wwan/t7xx/t7xx_modem_ops.c
index 24e7d491468e..ca262d2961ed 100644
--- a/drivers/net/wwan/t7xx/t7xx_modem_ops.c
+++ b/drivers/net/wwan/t7xx/t7xx_modem_ops.c
@@ -177,6 +177,11 @@ int t7xx_acpi_fldr_func(struct t7xx_pci_dev *t7xx_dev)
 	return t7xx_acpi_reset(t7xx_dev, "_RST");
 }
 
+int t7xx_acpi_pldr_func(struct t7xx_pci_dev *t7xx_dev)
+{
+	return t7xx_acpi_reset(t7xx_dev, "MRST._RST");
+}
+
 static void t7xx_reset_device_via_pmic(struct t7xx_pci_dev *t7xx_dev)
 {
 	u32 val;
@@ -192,6 +197,7 @@ static irqreturn_t t7xx_rgu_isr_thread(int irq, void *data)
 {
 	struct t7xx_pci_dev *t7xx_dev = data;
 
+	t7xx_mode_update(t7xx_dev, T7XX_RESET);
 	msleep(RGU_RESET_DELAY_MS);
 	t7xx_reset_device_via_pmic(t7xx_dev);
 	return IRQ_HANDLED;
diff --git a/drivers/net/wwan/t7xx/t7xx_modem_ops.h b/drivers/net/wwan/t7xx/t7xx_modem_ops.h
index abe633cf7adc..b39e945a92e0 100644
--- a/drivers/net/wwan/t7xx/t7xx_modem_ops.h
+++ b/drivers/net/wwan/t7xx/t7xx_modem_ops.h
@@ -85,6 +85,7 @@ int t7xx_md_init(struct t7xx_pci_dev *t7xx_dev);
 void t7xx_md_exit(struct t7xx_pci_dev *t7xx_dev);
 void t7xx_clear_rgu_irq(struct t7xx_pci_dev *t7xx_dev);
 int t7xx_acpi_fldr_func(struct t7xx_pci_dev *t7xx_dev);
+int t7xx_acpi_pldr_func(struct t7xx_pci_dev *t7xx_dev);
 int t7xx_pci_mhccif_isr(struct t7xx_pci_dev *t7xx_dev);
 
 #endif	/* __T7XX_MODEM_OPS_H__ */
diff --git a/drivers/net/wwan/t7xx/t7xx_pci.c b/drivers/net/wwan/t7xx/t7xx_pci.c
index 91256e005b84..1a10afd948c7 100644
--- a/drivers/net/wwan/t7xx/t7xx_pci.c
+++ b/drivers/net/wwan/t7xx/t7xx_pci.c
@@ -52,6 +52,81 @@
 #define PM_RESOURCE_POLL_TIMEOUT_US	10000
 #define PM_RESOURCE_POLL_STEP_US	100
 
+static const char * const mode_names[] = {
+	[T7XX_UNKNOWN] = "UNKNOWN",
+	[T7XX_READY] = "READY",
+	[T7XX_RESET] = "RESET",
+	[T7XX_FASTBOOT_DL_SWITCHING] = "FASTBOOT_DL_SWITCHING",
+	[T7XX_FASTBOOT_DL_MODE] = "FASTBOOT_DL_MODE",
+	[T7XX_FASTBOOT_DUMP_MODE] = "FASTBOOT_DUMP_MODE",
+};
+
+static_assert(ARRAY_SIZE(mode_names) == T7XX_MODE_LAST);
+
+static ssize_t t7xx_mode_store(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t count)
+{
+	struct t7xx_pci_dev *t7xx_dev;
+	struct pci_dev *pdev;
+	int index = 0;
+
+	pdev = to_pci_dev(dev);
+	t7xx_dev = pci_get_drvdata(pdev);
+	if (!t7xx_dev)
+		return -ENODEV;
+
+	index = sysfs_match_string(mode_names, buf);
+	if (index == T7XX_FASTBOOT_DL_SWITCHING) {
+		WRITE_ONCE(t7xx_dev->mode, T7XX_FASTBOOT_DL_SWITCHING);
+	} else if (index == T7XX_RESET) {
+		WRITE_ONCE(t7xx_dev->mode, T7XX_RESET);
+		t7xx_acpi_pldr_func(t7xx_dev);
+	}
+
+	return count;
+};
+
+static ssize_t t7xx_mode_show(struct device *dev,
+			      struct device_attribute *attr,
+			      char *buf)
+{
+	enum t7xx_mode mode = T7XX_UNKNOWN;
+	struct t7xx_pci_dev *t7xx_dev;
+	struct pci_dev *pdev;
+
+	pdev = to_pci_dev(dev);
+	t7xx_dev = pci_get_drvdata(pdev);
+	if (!t7xx_dev)
+		return -ENODEV;
+
+	mode = READ_ONCE(t7xx_dev->mode);
+	if (mode < T7XX_MODE_LAST)
+		return sysfs_emit(buf, "%s\n", mode_names[mode]);
+
+	return sysfs_emit(buf, "%s\n", mode_names[T7XX_UNKNOWN]);
+}
+
+static DEVICE_ATTR_RW(t7xx_mode);
+
+static struct attribute *t7xx_mode_attr[] = {
+	&dev_attr_t7xx_mode.attr,
+	NULL
+};
+
+static const struct attribute_group t7xx_mode_attribute_group = {
+	.attrs = t7xx_mode_attr,
+};
+
+void t7xx_mode_update(struct t7xx_pci_dev *t7xx_dev, enum t7xx_mode mode)
+{
+	if (!t7xx_dev)
+		return;
+
+	WRITE_ONCE(t7xx_dev->mode, mode);
+	sysfs_notify(&t7xx_dev->pdev->dev.kobj, NULL, "t7xx_mode");
+}
+
 enum t7xx_pm_state {
 	MTK_PM_EXCEPTION,
 	MTK_PM_INIT,		/* Device initialized, but handshake not completed */
@@ -729,16 +804,28 @@ static int t7xx_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
 	t7xx_pcie_mac_interrupts_dis(t7xx_dev);
 
+	ret = sysfs_create_group(&t7xx_dev->pdev->dev.kobj,
+				 &t7xx_mode_attribute_group);
+	if (ret)
+		goto err_md_exit;
+
 	ret = t7xx_interrupt_init(t7xx_dev);
-	if (ret) {
-		t7xx_md_exit(t7xx_dev);
-		return ret;
-	}
+	if (ret)
+		goto err_remove_group;
+
 
 	t7xx_pcie_mac_set_int(t7xx_dev, MHCCIF_INT);
 	t7xx_pcie_mac_interrupts_en(t7xx_dev);
 
 	return 0;
+
+err_remove_group:
+	sysfs_remove_group(&t7xx_dev->pdev->dev.kobj,
+			   &t7xx_mode_attribute_group);
+
+err_md_exit:
+	t7xx_md_exit(t7xx_dev);
+	return ret;
 }
 
 static void t7xx_pci_remove(struct pci_dev *pdev)
@@ -747,6 +834,9 @@ static void t7xx_pci_remove(struct pci_dev *pdev)
 	int i;
 
 	t7xx_dev = pci_get_drvdata(pdev);
+
+	sysfs_remove_group(&t7xx_dev->pdev->dev.kobj,
+			   &t7xx_mode_attribute_group);
 	t7xx_md_exit(t7xx_dev);
 
 	for (i = 0; i < EXT_INT_NUM; i++) {
diff --git a/drivers/net/wwan/t7xx/t7xx_pci.h b/drivers/net/wwan/t7xx/t7xx_pci.h
index f08f1ab74469..0abba7e6f8aa 100644
--- a/drivers/net/wwan/t7xx/t7xx_pci.h
+++ b/drivers/net/wwan/t7xx/t7xx_pci.h
@@ -43,6 +43,16 @@ struct t7xx_addr_base {
 
 typedef irqreturn_t (*t7xx_intr_callback)(int irq, void *param);
 
+enum t7xx_mode {
+	T7XX_UNKNOWN,
+	T7XX_READY,
+	T7XX_RESET,
+	T7XX_FASTBOOT_DL_SWITCHING,
+	T7XX_FASTBOOT_DL_MODE,
+	T7XX_FASTBOOT_DUMP_MODE,
+	T7XX_MODE_LAST, /* must always be last */
+};
+
 /* struct t7xx_pci_dev - MTK device context structure
  * @intr_handler: array of handler function for request_threaded_irq
  * @intr_thread: array of thread_fn for request_threaded_irq
@@ -59,6 +69,7 @@ typedef irqreturn_t (*t7xx_intr_callback)(int irq, void *param);
  * @md_pm_lock: protects PCIe sleep lock
  * @sleep_disable_count: PCIe L1.2 lock counter
  * @sleep_lock_acquire: indicates that sleep has been disabled
+ * @mode: indicates the device mode
  */
 struct t7xx_pci_dev {
 	t7xx_intr_callback	intr_handler[EXT_INT_NUM];
@@ -82,6 +93,7 @@ struct t7xx_pci_dev {
 #ifdef CONFIG_WWAN_DEBUGFS
 	struct dentry		*debugfs_dir;
 #endif
+	u32			mode;
 };
 
 enum t7xx_pm_id {
@@ -120,5 +132,5 @@ int t7xx_pci_pm_entity_register(struct t7xx_pci_dev *t7xx_dev, struct md_pm_enti
 int t7xx_pci_pm_entity_unregister(struct t7xx_pci_dev *t7xx_dev, struct md_pm_entity *pm_entity);
 void t7xx_pci_pm_init_late(struct t7xx_pci_dev *t7xx_dev);
 void t7xx_pci_pm_exp_detected(struct t7xx_pci_dev *t7xx_dev);
-
+void t7xx_mode_update(struct t7xx_pci_dev *t7xx_dev, enum t7xx_mode mode);
 #endif /* __T7XX_PCI_H__ */
diff --git a/drivers/net/wwan/t7xx/t7xx_state_monitor.c b/drivers/net/wwan/t7xx/t7xx_state_monitor.c
index 0bc97430211b..c5d46f45fa62 100644
--- a/drivers/net/wwan/t7xx/t7xx_state_monitor.c
+++ b/drivers/net/wwan/t7xx/t7xx_state_monitor.c
@@ -272,6 +272,7 @@ static void fsm_routine_ready(struct t7xx_fsm_ctl *ctl)
 
 	ctl->curr_state = FSM_STATE_READY;
 	t7xx_fsm_broadcast_ready_state(ctl);
+	t7xx_mode_update(md->t7xx_dev, T7XX_READY);
 	t7xx_md_event_notify(md, FSM_READY);
 }
 
-- 
2.34.1


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

* [net-next v7 3/4] net: wwan: t7xx: Infrastructure for early port configuration
       [not found] <20240201151340.4963-1-songjinjian@hotmail.com>
  2024-02-01 15:13 ` [net-next v7 1/4] wwan: core: Add WWAN fastboot port type Jinjian Song
  2024-02-01 15:13 ` [net-next v7 2/4] net: wwan: t7xx: Add sysfs attribute for device state machine Jinjian Song
@ 2024-02-01 15:13 ` Jinjian Song
  2024-02-01 15:13 ` [net-next v7 4/4] net: wwan: t7xx: Add fastboot WWAN port Jinjian Song
  3 siblings, 0 replies; 10+ messages in thread
From: Jinjian Song @ 2024-02-01 15:13 UTC (permalink / raw)
  To: netdev
  Cc: chandrashekar.devegowda, chiranjeevi.rapolu, haijun.liu,
	m.chetan.kumar, ricardo.martinez, loic.poulain, ryazanov.s.a,
	johannes, davem, edumazet, kuba, pabeni, linux-kernel, vsankar,
	letitia.tsai, pin-hao.huang, danielwinkler, nmarupaka, joey.zhao,
	liuqf, felix.yan, angel.huang, freddy.lin, alan.zhang1, zhangrc,
	Jinjian Song

From: Jinjian Song <jinjian.song@fibocom.com>

To support cases such as FW update or Core dump, the t7xx
device is capable of signaling the host that a special port
needs to be created before the handshake phase.

Adds the infrastructure required to create the early ports
which also requires a different configuration of CLDMA queues.

Base on the v5 patch version of follow series:
'net: wwan: t7xx: fw flashing & coredump support'
(https://patchwork.kernel.org/project/netdevbpf/patch/3777bb382f4b0395cb594a602c5c79dbab86c9e0.1674307425.git.m.chetan.kumar@linux.intel.com/)

Signed-off-by: Jinjian Song <jinjian.song@fibocom.com>
---
v7:
 * optimize fsm_routine_stopping()
v5:
 * using t7xx_mode_update to update sysfs t7xx_mode
v4:
 * change PORT_CH_ID_UNIMPORTANT to PORT_CH_UNIMPORTANT
 * delete t7xx_wait_pm_config() in t7xx_pci_pm_init()
 * define T7XX_MAX_POSSIBLE_PORTS_NUM to get max port num
 * define macro wait_for_expected_dev_stage to be more readable
 * change prev_status to status in struct t7xx_fsm_ctl
---
 drivers/net/wwan/t7xx/t7xx_hif_cldma.c     |  47 +++++---
 drivers/net/wwan/t7xx/t7xx_hif_cldma.h     |  18 ++-
 drivers/net/wwan/t7xx/t7xx_modem_ops.c     |   4 +-
 drivers/net/wwan/t7xx/t7xx_pci.c           |   2 +-
 drivers/net/wwan/t7xx/t7xx_port.h          |   4 +
 drivers/net/wwan/t7xx/t7xx_port_proxy.c    | 105 ++++++++++++++---
 drivers/net/wwan/t7xx/t7xx_port_proxy.h    |  10 ++
 drivers/net/wwan/t7xx/t7xx_port_wwan.c     |   5 +-
 drivers/net/wwan/t7xx/t7xx_reg.h           |  24 +++-
 drivers/net/wwan/t7xx/t7xx_state_monitor.c | 131 +++++++++++++++++----
 drivers/net/wwan/t7xx/t7xx_state_monitor.h |   1 +
 11 files changed, 290 insertions(+), 61 deletions(-)

diff --git a/drivers/net/wwan/t7xx/t7xx_hif_cldma.c b/drivers/net/wwan/t7xx/t7xx_hif_cldma.c
index cc70360364b7..abc41a7089fa 100644
--- a/drivers/net/wwan/t7xx/t7xx_hif_cldma.c
+++ b/drivers/net/wwan/t7xx/t7xx_hif_cldma.c
@@ -57,8 +57,6 @@
 #define CHECK_Q_STOP_TIMEOUT_US		1000000
 #define CHECK_Q_STOP_STEP_US		10000
 
-#define CLDMA_JUMBO_BUFF_SZ		(63 * 1024 + sizeof(struct ccci_header))
-
 static void md_cd_queue_struct_reset(struct cldma_queue *queue, struct cldma_ctrl *md_ctrl,
 				     enum mtk_txrx tx_rx, unsigned int index)
 {
@@ -161,7 +159,7 @@ static int t7xx_cldma_gpd_rx_from_q(struct cldma_queue *queue, int budget, bool
 		skb_reset_tail_pointer(skb);
 		skb_put(skb, le16_to_cpu(gpd->data_buff_len));
 
-		ret = md_ctrl->recv_skb(queue, skb);
+		ret = queue->recv_skb(queue, skb);
 		/* Break processing, will try again later */
 		if (ret < 0)
 			return ret;
@@ -897,13 +895,13 @@ static void t7xx_cldma_hw_start_send(struct cldma_ctrl *md_ctrl, int qno,
 
 /**
  * t7xx_cldma_set_recv_skb() - Set the callback to handle RX packets.
- * @md_ctrl: CLDMA context structure.
+ * @queue: CLDMA queue.
  * @recv_skb: Receiving skb callback.
  */
-void t7xx_cldma_set_recv_skb(struct cldma_ctrl *md_ctrl,
+void t7xx_cldma_set_recv_skb(struct cldma_queue *queue,
 			     int (*recv_skb)(struct cldma_queue *queue, struct sk_buff *skb))
 {
-	md_ctrl->recv_skb = recv_skb;
+	queue->recv_skb = recv_skb;
 }
 
 /**
@@ -993,6 +991,28 @@ int t7xx_cldma_send_skb(struct cldma_ctrl *md_ctrl, int qno, struct sk_buff *skb
 	return ret;
 }
 
+static void t7xx_cldma_adjust_config(struct cldma_ctrl *md_ctrl, enum cldma_cfg cfg_id)
+{
+	int qno;
+
+	for (qno = 0; qno < CLDMA_RXQ_NUM; qno++) {
+		md_ctrl->rx_ring[qno].pkt_size = CLDMA_SHARED_Q_BUFF_SZ;
+		t7xx_cldma_set_recv_skb(&md_ctrl->rxq[qno], t7xx_port_proxy_recv_skb);
+	}
+
+	md_ctrl->rx_ring[CLDMA_RXQ_NUM - 1].pkt_size = CLDMA_JUMBO_BUFF_SZ;
+
+	for (qno = 0; qno < CLDMA_TXQ_NUM; qno++)
+		md_ctrl->tx_ring[qno].pkt_size = CLDMA_SHARED_Q_BUFF_SZ;
+
+	if (cfg_id == CLDMA_DEDICATED_Q_CFG) {
+		md_ctrl->tx_ring[CLDMA_Q_IDX_DUMP].pkt_size = CLDMA_DEDICATED_Q_BUFF_SZ;
+		md_ctrl->rx_ring[CLDMA_Q_IDX_DUMP].pkt_size = CLDMA_DEDICATED_Q_BUFF_SZ;
+		t7xx_cldma_set_recv_skb(&md_ctrl->rxq[CLDMA_Q_IDX_DUMP],
+					t7xx_port_proxy_recv_skb_from_dedicated_queue);
+	}
+}
+
 static int t7xx_cldma_late_init(struct cldma_ctrl *md_ctrl)
 {
 	char dma_pool_name[32];
@@ -1018,16 +1038,9 @@ static int t7xx_cldma_late_init(struct cldma_ctrl *md_ctrl)
 			dev_err(md_ctrl->dev, "control TX ring init fail\n");
 			goto err_free_tx_ring;
 		}
-
-		md_ctrl->tx_ring[i].pkt_size = CLDMA_MTU;
 	}
 
 	for (j = 0; j < CLDMA_RXQ_NUM; j++) {
-		md_ctrl->rx_ring[j].pkt_size = CLDMA_MTU;
-
-		if (j == CLDMA_RXQ_NUM - 1)
-			md_ctrl->rx_ring[j].pkt_size = CLDMA_JUMBO_BUFF_SZ;
-
 		ret = t7xx_cldma_rx_ring_init(md_ctrl, &md_ctrl->rx_ring[j]);
 		if (ret) {
 			dev_err(md_ctrl->dev, "Control RX ring init fail\n");
@@ -1094,6 +1107,7 @@ int t7xx_cldma_alloc(enum cldma_id hif_id, struct t7xx_pci_dev *t7xx_dev)
 {
 	struct device *dev = &t7xx_dev->pdev->dev;
 	struct cldma_ctrl *md_ctrl;
+	int qno;
 
 	md_ctrl = devm_kzalloc(dev, sizeof(*md_ctrl), GFP_KERNEL);
 	if (!md_ctrl)
@@ -1102,7 +1116,9 @@ int t7xx_cldma_alloc(enum cldma_id hif_id, struct t7xx_pci_dev *t7xx_dev)
 	md_ctrl->t7xx_dev = t7xx_dev;
 	md_ctrl->dev = dev;
 	md_ctrl->hif_id = hif_id;
-	md_ctrl->recv_skb = t7xx_cldma_default_recv_skb;
+	for (qno = 0; qno < CLDMA_RXQ_NUM; qno++)
+		md_ctrl->rxq[qno].recv_skb = t7xx_cldma_default_recv_skb;
+
 	t7xx_hw_info_init(md_ctrl);
 	t7xx_dev->md->md_ctrl[hif_id] = md_ctrl;
 	return 0;
@@ -1332,9 +1348,10 @@ int t7xx_cldma_init(struct cldma_ctrl *md_ctrl)
 	return -ENOMEM;
 }
 
-void t7xx_cldma_switch_cfg(struct cldma_ctrl *md_ctrl)
+void t7xx_cldma_switch_cfg(struct cldma_ctrl *md_ctrl, enum cldma_cfg cfg_id)
 {
 	t7xx_cldma_late_release(md_ctrl);
+	t7xx_cldma_adjust_config(md_ctrl, cfg_id);
 	t7xx_cldma_late_init(md_ctrl);
 }
 
diff --git a/drivers/net/wwan/t7xx/t7xx_hif_cldma.h b/drivers/net/wwan/t7xx/t7xx_hif_cldma.h
index 4410bac6993a..f2d9941be9c8 100644
--- a/drivers/net/wwan/t7xx/t7xx_hif_cldma.h
+++ b/drivers/net/wwan/t7xx/t7xx_hif_cldma.h
@@ -31,6 +31,10 @@
 #include "t7xx_cldma.h"
 #include "t7xx_pci.h"
 
+#define CLDMA_JUMBO_BUFF_SZ		(63 * 1024 + sizeof(struct ccci_header))
+#define CLDMA_SHARED_Q_BUFF_SZ		3584
+#define CLDMA_DEDICATED_Q_BUFF_SZ	2048
+
 /**
  * enum cldma_id - Identifiers for CLDMA HW units.
  * @CLDMA_ID_MD: Modem control channel.
@@ -55,6 +59,11 @@ struct cldma_gpd {
 	__le16 not_used2;
 };
 
+enum cldma_cfg {
+	CLDMA_SHARED_Q_CFG,
+	CLDMA_DEDICATED_Q_CFG,
+};
+
 struct cldma_request {
 	struct cldma_gpd *gpd;	/* Virtual address for CPU */
 	dma_addr_t gpd_addr;	/* Physical address for DMA */
@@ -82,6 +91,7 @@ struct cldma_queue {
 	wait_queue_head_t req_wq;	/* Only for TX */
 	struct workqueue_struct *worker;
 	struct work_struct cldma_work;
+	int (*recv_skb)(struct cldma_queue *queue, struct sk_buff *skb);
 };
 
 struct cldma_ctrl {
@@ -101,24 +111,22 @@ struct cldma_ctrl {
 	struct md_pm_entity *pm_entity;
 	struct t7xx_cldma_hw hw_info;
 	bool is_late_init;
-	int (*recv_skb)(struct cldma_queue *queue, struct sk_buff *skb);
 };
 
+#define CLDMA_Q_IDX_DUMP	1
 #define GPD_FLAGS_HWO		BIT(0)
 #define GPD_FLAGS_IOC		BIT(7)
 #define GPD_DMAPOOL_ALIGN	16
 
-#define CLDMA_MTU		3584	/* 3.5kB */
-
 int t7xx_cldma_alloc(enum cldma_id hif_id, struct t7xx_pci_dev *t7xx_dev);
 void t7xx_cldma_hif_hw_init(struct cldma_ctrl *md_ctrl);
 int t7xx_cldma_init(struct cldma_ctrl *md_ctrl);
 void t7xx_cldma_exit(struct cldma_ctrl *md_ctrl);
-void t7xx_cldma_switch_cfg(struct cldma_ctrl *md_ctrl);
+void t7xx_cldma_switch_cfg(struct cldma_ctrl *md_ctrl, enum cldma_cfg cfg_id);
 void t7xx_cldma_start(struct cldma_ctrl *md_ctrl);
 int t7xx_cldma_stop(struct cldma_ctrl *md_ctrl);
 void t7xx_cldma_reset(struct cldma_ctrl *md_ctrl);
-void t7xx_cldma_set_recv_skb(struct cldma_ctrl *md_ctrl,
+void t7xx_cldma_set_recv_skb(struct cldma_queue *queue,
 			     int (*recv_skb)(struct cldma_queue *queue, struct sk_buff *skb));
 int t7xx_cldma_send_skb(struct cldma_ctrl *md_ctrl, int qno, struct sk_buff *skb);
 void t7xx_cldma_stop_all_qs(struct cldma_ctrl *md_ctrl, enum mtk_txrx tx_rx);
diff --git a/drivers/net/wwan/t7xx/t7xx_modem_ops.c b/drivers/net/wwan/t7xx/t7xx_modem_ops.c
index ca262d2961ed..fd79a2a1cc6f 100644
--- a/drivers/net/wwan/t7xx/t7xx_modem_ops.c
+++ b/drivers/net/wwan/t7xx/t7xx_modem_ops.c
@@ -535,7 +535,7 @@ static void t7xx_md_hk_wq(struct work_struct *work)
 
 	/* Clear the HS2 EXIT event appended in core_reset() */
 	t7xx_fsm_clr_event(ctl, FSM_EVENT_MD_HS2_EXIT);
-	t7xx_cldma_switch_cfg(md->md_ctrl[CLDMA_ID_MD]);
+	t7xx_cldma_switch_cfg(md->md_ctrl[CLDMA_ID_MD], CLDMA_SHARED_Q_CFG);
 	t7xx_cldma_start(md->md_ctrl[CLDMA_ID_MD]);
 	t7xx_fsm_broadcast_state(ctl, MD_STATE_WAITING_FOR_HS2);
 	md->core_md.handshake_ongoing = true;
@@ -550,7 +550,7 @@ static void t7xx_ap_hk_wq(struct work_struct *work)
 	 /* Clear the HS2 EXIT event appended in t7xx_core_reset(). */
 	t7xx_fsm_clr_event(ctl, FSM_EVENT_AP_HS2_EXIT);
 	t7xx_cldma_stop(md->md_ctrl[CLDMA_ID_AP]);
-	t7xx_cldma_switch_cfg(md->md_ctrl[CLDMA_ID_AP]);
+	t7xx_cldma_switch_cfg(md->md_ctrl[CLDMA_ID_AP], CLDMA_SHARED_Q_CFG);
 	t7xx_cldma_start(md->md_ctrl[CLDMA_ID_AP]);
 	md->core_ap.handshake_ongoing = true;
 	t7xx_core_hk_handler(md, &md->core_ap, ctl, FSM_EVENT_AP_HS2, FSM_EVENT_AP_HS2_EXIT);
diff --git a/drivers/net/wwan/t7xx/t7xx_pci.c b/drivers/net/wwan/t7xx/t7xx_pci.c
index 1a10afd948c7..06e97778fd2f 100644
--- a/drivers/net/wwan/t7xx/t7xx_pci.c
+++ b/drivers/net/wwan/t7xx/t7xx_pci.c
@@ -183,7 +183,7 @@ static int t7xx_pci_pm_init(struct t7xx_pci_dev *t7xx_dev)
 	pm_runtime_set_autosuspend_delay(&pdev->dev, PM_AUTOSUSPEND_MS);
 	pm_runtime_use_autosuspend(&pdev->dev);
 
-	return t7xx_wait_pm_config(t7xx_dev);
+	return 0;
 }
 
 void t7xx_pci_pm_init_late(struct t7xx_pci_dev *t7xx_dev)
diff --git a/drivers/net/wwan/t7xx/t7xx_port.h b/drivers/net/wwan/t7xx/t7xx_port.h
index 4ae8a00a8532..f74d3bab810d 100644
--- a/drivers/net/wwan/t7xx/t7xx_port.h
+++ b/drivers/net/wwan/t7xx/t7xx_port.h
@@ -75,6 +75,8 @@ enum port_ch {
 	PORT_CH_DSS6_TX = 0x20df,
 	PORT_CH_DSS7_RX = 0x20e0,
 	PORT_CH_DSS7_TX = 0x20e1,
+
+	PORT_CH_UNIMPORTANT = 0xffff,
 };
 
 struct t7xx_port;
@@ -135,11 +137,13 @@ struct t7xx_port {
 	};
 };
 
+int t7xx_get_port_mtu(struct t7xx_port *port);
 struct sk_buff *t7xx_port_alloc_skb(int payload);
 struct sk_buff *t7xx_ctrl_alloc_skb(int payload);
 int t7xx_port_enqueue_skb(struct t7xx_port *port, struct sk_buff *skb);
 int t7xx_port_send_skb(struct t7xx_port *port, struct sk_buff *skb, unsigned int pkt_header,
 		       unsigned int ex_msg);
+int t7xx_port_send_raw_skb(struct t7xx_port *port, struct sk_buff *skb);
 int t7xx_port_send_ctl_skb(struct t7xx_port *port, struct sk_buff *skb, unsigned int msg,
 			   unsigned int ex_msg);
 
diff --git a/drivers/net/wwan/t7xx/t7xx_port_proxy.c b/drivers/net/wwan/t7xx/t7xx_port_proxy.c
index 274846d39fbf..e53a152faee4 100644
--- a/drivers/net/wwan/t7xx/t7xx_port_proxy.c
+++ b/drivers/net/wwan/t7xx/t7xx_port_proxy.c
@@ -48,6 +48,9 @@
 	     i < (proxy)->port_count;		\
 	     i++, (p) = &(proxy)->ports[i])
 
+#define T7XX_MAX_POSSIBLE_PORTS_NUM	\
+	(max(ARRAY_SIZE(t7xx_port_conf), ARRAY_SIZE(t7xx_early_port_conf)))
+
 static const struct t7xx_port_conf t7xx_port_conf[] = {
 	{
 		.tx_ch = PORT_CH_UART2_TX,
@@ -100,6 +103,18 @@ static const struct t7xx_port_conf t7xx_port_conf[] = {
 	},
 };
 
+static const struct t7xx_port_conf t7xx_early_port_conf[] = {
+	{
+		.tx_ch = PORT_CH_UNIMPORTANT,
+		.rx_ch = PORT_CH_UNIMPORTANT,
+		.txq_index = CLDMA_Q_IDX_DUMP,
+		.rxq_index = CLDMA_Q_IDX_DUMP,
+		.txq_exp_index = CLDMA_Q_IDX_DUMP,
+		.rxq_exp_index = CLDMA_Q_IDX_DUMP,
+		.path_id = CLDMA_ID_AP,
+	},
+};
+
 static struct t7xx_port *t7xx_proxy_get_port_by_ch(struct port_proxy *port_prox, enum port_ch ch)
 {
 	const struct t7xx_port_conf *port_conf;
@@ -214,7 +229,17 @@ int t7xx_port_enqueue_skb(struct t7xx_port *port, struct sk_buff *skb)
 	return 0;
 }
 
-static int t7xx_port_send_raw_skb(struct t7xx_port *port, struct sk_buff *skb)
+int t7xx_get_port_mtu(struct t7xx_port *port)
+{
+	enum cldma_id path_id = port->port_conf->path_id;
+	int tx_qno = t7xx_port_get_queue_no(port);
+	struct cldma_ctrl *md_ctrl;
+
+	md_ctrl = port->t7xx_dev->md->md_ctrl[path_id];
+	return md_ctrl->tx_ring[tx_qno].pkt_size;
+}
+
+int t7xx_port_send_raw_skb(struct t7xx_port *port, struct sk_buff *skb)
 {
 	enum cldma_id path_id = port->port_conf->path_id;
 	struct cldma_ctrl *md_ctrl;
@@ -329,6 +354,39 @@ static void t7xx_proxy_setup_ch_mapping(struct port_proxy *port_prox)
 	}
 }
 
+/**
+ * t7xx_port_proxy_recv_skb_from_dedicated_queue() - Dispatch early port received skb.
+ * @queue: CLDMA queue.
+ * @skb: Socket buffer.
+ *
+ * Return:
+ ** 0		- Packet consumed.
+ ** -ERROR	- Failed to process skb.
+ */
+int t7xx_port_proxy_recv_skb_from_dedicated_queue(struct cldma_queue *queue, struct sk_buff *skb)
+{
+	struct t7xx_pci_dev *t7xx_dev = queue->md_ctrl->t7xx_dev;
+	struct port_proxy *port_prox = t7xx_dev->md->port_prox;
+	const struct t7xx_port_conf *port_conf;
+	struct t7xx_port *port;
+	int ret;
+
+	port = &port_prox->ports[0];
+	if (WARN_ON_ONCE(port->port_conf->rxq_index != queue->index)) {
+		dev_kfree_skb_any(skb);
+		return -EINVAL;
+	}
+
+	port_conf = port->port_conf;
+	ret = port_conf->ops->recv_skb(port, skb);
+	if (ret < 0 && ret != -ENOBUFS) {
+		dev_err(port->dev, "drop on RX ch %d, %d\n", port_conf->rx_ch, ret);
+		dev_kfree_skb_any(skb);
+	}
+
+	return ret;
+}
+
 static struct t7xx_port *t7xx_port_proxy_find_port(struct t7xx_pci_dev *t7xx_dev,
 						   struct cldma_queue *queue, u16 channel)
 {
@@ -359,7 +417,7 @@ static struct t7xx_port *t7xx_port_proxy_find_port(struct t7xx_pci_dev *t7xx_dev
  ** 0		- Packet consumed.
  ** -ERROR	- Failed to process skb.
  */
-static int t7xx_port_proxy_recv_skb(struct cldma_queue *queue, struct sk_buff *skb)
+int t7xx_port_proxy_recv_skb(struct cldma_queue *queue, struct sk_buff *skb)
 {
 	struct ccci_header *ccci_h = (struct ccci_header *)skb->data;
 	struct t7xx_pci_dev *t7xx_dev = queue->md_ctrl->t7xx_dev;
@@ -444,33 +502,54 @@ static void t7xx_proxy_init_all_ports(struct t7xx_modem *md)
 		spin_lock_init(&port->port_update_lock);
 		port->chan_enable = false;
 
-		if (port_conf->ops->init)
+		if (port_conf->ops && port_conf->ops->init)
 			port_conf->ops->init(port);
 	}
 
 	t7xx_proxy_setup_ch_mapping(port_prox);
 }
 
+void t7xx_port_proxy_set_cfg(struct t7xx_modem *md, enum port_cfg_id cfg_id)
+{
+	struct port_proxy *port_prox = md->port_prox;
+	const struct t7xx_port_conf *port_conf;
+	u32 port_count;
+	int i;
+
+	t7xx_port_proxy_uninit(port_prox);
+
+	if (cfg_id == PORT_CFG_ID_EARLY) {
+		port_conf = t7xx_early_port_conf;
+		port_count = ARRAY_SIZE(t7xx_early_port_conf);
+	} else {
+		port_conf = t7xx_port_conf;
+		port_count = ARRAY_SIZE(t7xx_port_conf);
+	}
+
+	for (i = 0; i < port_count; i++)
+		port_prox->ports[i].port_conf = &port_conf[i];
+
+	port_prox->cfg_id = cfg_id;
+	port_prox->port_count = port_count;
+
+	t7xx_proxy_init_all_ports(md);
+}
+
 static int t7xx_proxy_alloc(struct t7xx_modem *md)
 {
-	unsigned int port_count = ARRAY_SIZE(t7xx_port_conf);
 	struct device *dev = &md->t7xx_dev->pdev->dev;
 	struct port_proxy *port_prox;
-	int i;
 
-	port_prox = devm_kzalloc(dev, sizeof(*port_prox) + sizeof(struct t7xx_port) * port_count,
+	port_prox = devm_kzalloc(dev, sizeof(*port_prox) +
+				 sizeof(struct t7xx_port) * T7XX_MAX_POSSIBLE_PORTS_NUM,
 				 GFP_KERNEL);
 	if (!port_prox)
 		return -ENOMEM;
 
 	md->port_prox = port_prox;
 	port_prox->dev = dev;
+	t7xx_port_proxy_set_cfg(md, PORT_CFG_ID_EARLY);
 
-	for (i = 0; i < port_count; i++)
-		port_prox->ports[i].port_conf = &t7xx_port_conf[i];
-
-	port_prox->port_count = port_count;
-	t7xx_proxy_init_all_ports(md);
 	return 0;
 }
 
@@ -492,8 +571,6 @@ int t7xx_port_proxy_init(struct t7xx_modem *md)
 	if (ret)
 		return ret;
 
-	t7xx_cldma_set_recv_skb(md->md_ctrl[CLDMA_ID_AP], t7xx_port_proxy_recv_skb);
-	t7xx_cldma_set_recv_skb(md->md_ctrl[CLDMA_ID_MD], t7xx_port_proxy_recv_skb);
 	return 0;
 }
 
@@ -505,7 +582,7 @@ void t7xx_port_proxy_uninit(struct port_proxy *port_prox)
 	for_each_proxy_port(i, port, port_prox) {
 		const struct t7xx_port_conf *port_conf = port->port_conf;
 
-		if (port_conf->ops->uninit)
+		if (port_conf->ops && port_conf->ops->uninit)
 			port_conf->ops->uninit(port);
 	}
 }
diff --git a/drivers/net/wwan/t7xx/t7xx_port_proxy.h b/drivers/net/wwan/t7xx/t7xx_port_proxy.h
index 81d059fbc0fb..7f5706811445 100644
--- a/drivers/net/wwan/t7xx/t7xx_port_proxy.h
+++ b/drivers/net/wwan/t7xx/t7xx_port_proxy.h
@@ -31,11 +31,18 @@
 #define RX_QUEUE_MAXLEN		32
 #define CTRL_QUEUE_MAXLEN	16
 
+enum port_cfg_id {
+	PORT_CFG_ID_INVALID,
+	PORT_CFG_ID_NORMAL,
+	PORT_CFG_ID_EARLY,
+};
+
 struct port_proxy {
 	int			port_count;
 	struct list_head	rx_ch_ports[PORT_CH_ID_MASK + 1];
 	struct list_head	queue_ports[CLDMA_NUM][MTK_QUEUES];
 	struct device		*dev;
+	enum port_cfg_id	cfg_id;
 	struct t7xx_port	ports[];
 };
 
@@ -98,5 +105,8 @@ void t7xx_port_proxy_md_status_notify(struct port_proxy *port_prox, unsigned int
 int t7xx_port_enum_msg_handler(struct t7xx_modem *md, void *msg);
 int t7xx_port_proxy_chl_enable_disable(struct port_proxy *port_prox, unsigned int ch_id,
 				       bool en_flag);
+void t7xx_port_proxy_set_cfg(struct t7xx_modem *md, enum port_cfg_id cfg_id);
+int t7xx_port_proxy_recv_skb(struct cldma_queue *queue, struct sk_buff *skb);
+int t7xx_port_proxy_recv_skb_from_dedicated_queue(struct cldma_queue *queue, struct sk_buff *skb);
 
 #endif /* __T7XX_PORT_PROXY_H__ */
diff --git a/drivers/net/wwan/t7xx/t7xx_port_wwan.c b/drivers/net/wwan/t7xx/t7xx_port_wwan.c
index 17389c8f6600..ddc20ddfa734 100644
--- a/drivers/net/wwan/t7xx/t7xx_port_wwan.c
+++ b/drivers/net/wwan/t7xx/t7xx_port_wwan.c
@@ -152,14 +152,15 @@ static int t7xx_port_wwan_disable_chl(struct t7xx_port *port)
 static void t7xx_port_wwan_md_state_notify(struct t7xx_port *port, unsigned int state)
 {
 	const struct t7xx_port_conf *port_conf = port->port_conf;
-	unsigned int header_len = sizeof(struct ccci_header);
+	unsigned int header_len = sizeof(struct ccci_header), mtu;
 	struct wwan_port_caps caps;
 
 	if (state != MD_STATE_READY)
 		return;
 
 	if (!port->wwan.wwan_port) {
-		caps.frag_len = CLDMA_MTU - header_len;
+		mtu = t7xx_get_port_mtu(port);
+		caps.frag_len = mtu - header_len;
 		caps.headroom_len = header_len;
 		port->wwan.wwan_port = wwan_create_port(port->dev, port_conf->port_type,
 							&wwan_ops, &caps, port);
diff --git a/drivers/net/wwan/t7xx/t7xx_reg.h b/drivers/net/wwan/t7xx/t7xx_reg.h
index c41d7d094c08..9c7dc72ac6f6 100644
--- a/drivers/net/wwan/t7xx/t7xx_reg.h
+++ b/drivers/net/wwan/t7xx/t7xx_reg.h
@@ -101,11 +101,33 @@ enum t7xx_pm_resume_state {
 	PM_RESUME_REG_STATE_L2_EXP,
 };
 
+enum host_event_e {
+	HOST_EVENT_INIT = 0,
+	FASTBOOT_DL_NOTIFY = 0x3,
+};
+
 #define T7XX_PCIE_MISC_DEV_STATUS		0x0d1c
 #define MISC_STAGE_MASK				GENMASK(2, 0)
 #define MISC_RESET_TYPE_PLDR			BIT(26)
 #define MISC_RESET_TYPE_FLDR			BIT(27)
-#define LINUX_STAGE				4
+#define MISC_RESET_TYPE_PLDR			BIT(26)
+#define MISC_LK_EVENT_MASK			GENMASK(11, 8)
+#define HOST_EVENT_MASK				GENMASK(31, 28)
+
+enum lk_event_id {
+	LK_EVENT_NORMAL = 0,
+	LK_EVENT_CREATE_PD_PORT = 1,
+	LK_EVENT_CREATE_POST_DL_PORT = 2,
+	LK_EVENT_RESET = 7,
+};
+
+enum t7xx_device_stage {
+	T7XX_DEV_STAGE_INIT = 0,
+	T7XX_DEV_STAGE_BROM_PRE = 1,
+	T7XX_DEV_STAGE_BROM_POST = 2,
+	T7XX_DEV_STAGE_LK = 3,
+	T7XX_DEV_STAGE_LINUX = 4,
+};
 
 #define T7XX_PCIE_RESOURCE_STATUS		0x0d28
 #define T7XX_PCIE_RESOURCE_STS_MSK		GENMASK(4, 0)
diff --git a/drivers/net/wwan/t7xx/t7xx_state_monitor.c b/drivers/net/wwan/t7xx/t7xx_state_monitor.c
index c5d46f45fa62..b98ad4a1709b 100644
--- a/drivers/net/wwan/t7xx/t7xx_state_monitor.c
+++ b/drivers/net/wwan/t7xx/t7xx_state_monitor.c
@@ -47,6 +47,13 @@
 #define FSM_MD_EX_PASS_TIMEOUT_MS		45000
 #define FSM_CMD_TIMEOUT_MS			2000
 
+#define wait_for_expected_dev_stage(status)	\
+	read_poll_timeout(ioread32, status,	\
+			  ((status & MISC_STAGE_MASK) == T7XX_DEV_STAGE_LINUX) ||	\
+			  ((status & MISC_STAGE_MASK) == T7XX_DEV_STAGE_LK), 100000,	\
+			  20000000, false, IREG_BASE(md->t7xx_dev) +	\
+			  T7XX_PCIE_MISC_DEV_STATUS)
+
 void t7xx_fsm_notifier_register(struct t7xx_modem *md, struct t7xx_fsm_notifier *notifier)
 {
 	struct t7xx_fsm_ctl *ctl = md->fsm_ctl;
@@ -206,6 +213,51 @@ static void fsm_routine_exception(struct t7xx_fsm_ctl *ctl, struct t7xx_fsm_comm
 		fsm_finish_command(ctl, cmd, 0);
 }
 
+static void t7xx_host_event_notify(struct t7xx_modem *md, unsigned int event_id)
+{
+	u32 value;
+
+	value = ioread32(IREG_BASE(md->t7xx_dev) + T7XX_PCIE_MISC_DEV_STATUS);
+	value &= ~HOST_EVENT_MASK;
+	value |= FIELD_PREP(HOST_EVENT_MASK, event_id);
+	iowrite32(value, IREG_BASE(md->t7xx_dev) + T7XX_PCIE_MISC_DEV_STATUS);
+}
+
+static void t7xx_lk_stage_event_handling(struct t7xx_fsm_ctl *ctl, unsigned int status)
+{
+	struct t7xx_modem *md = ctl->md;
+	struct cldma_ctrl *md_ctrl;
+	enum lk_event_id lk_event;
+	struct device *dev;
+
+	dev = &md->t7xx_dev->pdev->dev;
+	lk_event = FIELD_GET(MISC_LK_EVENT_MASK, status);
+	switch (lk_event) {
+	case LK_EVENT_NORMAL:
+	case LK_EVENT_RESET:
+		break;
+
+	case LK_EVENT_CREATE_PD_PORT:
+	case LK_EVENT_CREATE_POST_DL_PORT:
+		md_ctrl = md->md_ctrl[CLDMA_ID_AP];
+		t7xx_cldma_hif_hw_init(md_ctrl);
+		t7xx_cldma_stop(md_ctrl);
+		t7xx_cldma_switch_cfg(md_ctrl, CLDMA_DEDICATED_Q_CFG);
+
+		t7xx_cldma_start(md_ctrl);
+
+		if (lk_event == LK_EVENT_CREATE_POST_DL_PORT)
+			t7xx_mode_update(md->t7xx_dev, T7XX_FASTBOOT_DL_MODE);
+		else
+			t7xx_mode_update(md->t7xx_dev, T7XX_FASTBOOT_DUMP_MODE);
+		break;
+
+	default:
+		dev_err(dev, "Invalid LK event %d\n", lk_event);
+		break;
+	}
+}
+
 static int fsm_stopped_handler(struct t7xx_fsm_ctl *ctl)
 {
 	ctl->curr_state = FSM_STATE_STOPPED;
@@ -226,27 +278,32 @@ static void fsm_routine_stopped(struct t7xx_fsm_ctl *ctl, struct t7xx_fsm_comman
 
 static void fsm_routine_stopping(struct t7xx_fsm_ctl *ctl, struct t7xx_fsm_command *cmd)
 {
-	struct t7xx_pci_dev *t7xx_dev;
-	struct cldma_ctrl *md_ctrl;
+	struct cldma_ctrl *md_ctrl = ctl->md->md_ctrl[CLDMA_ID_MD];
+	struct t7xx_pci_dev *t7xx_dev = ctl->md->t7xx_dev;
+	u32 mode = READ_ONCE(t7xx_dev->mode);
 	int err;
 
-	if (ctl->curr_state == FSM_STATE_STOPPED || ctl->curr_state == FSM_STATE_STOPPING) {
+	if (ctl->curr_state == FSM_STATE_STOPPED ||
+	    ctl->curr_state == FSM_STATE_STOPPING ||
+	    mode == T7XX_RESET) {
 		fsm_finish_command(ctl, cmd, -EINVAL);
 		return;
 	}
 
-	md_ctrl = ctl->md->md_ctrl[CLDMA_ID_MD];
-	t7xx_dev = ctl->md->t7xx_dev;
-
 	ctl->curr_state = FSM_STATE_STOPPING;
 	t7xx_fsm_broadcast_state(ctl, MD_STATE_WAITING_TO_STOP);
 	t7xx_cldma_stop(md_ctrl);
 
-	if (!ctl->md->rgu_irq_asserted) {
-		t7xx_mhccif_h2d_swint_trigger(t7xx_dev, H2D_CH_DRM_DISABLE_AP);
-		/* Wait for the DRM disable to take effect */
-		msleep(FSM_DRM_DISABLE_DELAY_MS);
+	if (mode == T7XX_FASTBOOT_DL_SWITCHING)
+		t7xx_host_event_notify(ctl->md, FASTBOOT_DL_NOTIFY);
+
+	t7xx_mhccif_h2d_swint_trigger(t7xx_dev, H2D_CH_DRM_DISABLE_AP);
+	/* Wait for the DRM disable to take effect */
+	msleep(FSM_DRM_DISABLE_DELAY_MS);
 
+	if (mode == T7XX_FASTBOOT_DL_SWITCHING) {
+		t7xx_mhccif_h2d_swint_trigger(t7xx_dev, H2D_CH_DEVICE_RESET);
+	} else {
 		err = t7xx_acpi_fldr_func(t7xx_dev);
 		if (err)
 			t7xx_mhccif_h2d_swint_trigger(t7xx_dev, H2D_CH_DEVICE_RESET);
@@ -318,7 +375,8 @@ static int fsm_routine_starting(struct t7xx_fsm_ctl *ctl)
 static void fsm_routine_start(struct t7xx_fsm_ctl *ctl, struct t7xx_fsm_command *cmd)
 {
 	struct t7xx_modem *md = ctl->md;
-	u32 dev_status;
+	struct device *dev;
+	u32 status;
 	int ret;
 
 	if (!md)
@@ -330,23 +388,53 @@ static void fsm_routine_start(struct t7xx_fsm_ctl *ctl, struct t7xx_fsm_command
 		return;
 	}
 
+	dev = &md->t7xx_dev->pdev->dev;
 	ctl->curr_state = FSM_STATE_PRE_START;
 	t7xx_md_event_notify(md, FSM_PRE_START);
 
-	ret = read_poll_timeout(ioread32, dev_status,
-				(dev_status & MISC_STAGE_MASK) == LINUX_STAGE, 20000, 2000000,
-				false, IREG_BASE(md->t7xx_dev) + T7XX_PCIE_MISC_DEV_STATUS);
+	ret = wait_for_expected_dev_stage(status);
+
 	if (ret) {
-		struct device *dev = &md->t7xx_dev->pdev->dev;
+		dev_err(dev, "read poll timeout %d\n", ret);
+		goto finish_command;
+	}
 
-		fsm_finish_command(ctl, cmd, -ETIMEDOUT);
-		dev_err(dev, "Invalid device status 0x%lx\n", dev_status & MISC_STAGE_MASK);
-		return;
+	if (status != ctl->status || cmd->flag != 0) {
+		u32 stage = FIELD_GET(MISC_STAGE_MASK, status);
+
+		switch (stage) {
+		case T7XX_DEV_STAGE_INIT:
+		case T7XX_DEV_STAGE_BROM_PRE:
+		case T7XX_DEV_STAGE_BROM_POST:
+			dev_dbg(dev, "BROM_STAGE Entered\n");
+			ret = t7xx_fsm_append_cmd(ctl, FSM_CMD_START, 0);
+			break;
+
+		case T7XX_DEV_STAGE_LK:
+			dev_dbg(dev, "LK_STAGE Entered\n");
+			t7xx_lk_stage_event_handling(ctl, status);
+			break;
+
+		case T7XX_DEV_STAGE_LINUX:
+			dev_dbg(dev, "LINUX_STAGE Entered\n");
+			t7xx_mhccif_mask_clr(md->t7xx_dev, D2H_INT_PORT_ENUM |
+					     D2H_INT_ASYNC_MD_HK | D2H_INT_ASYNC_AP_HK);
+			if (cmd->flag == 0)
+				break;
+			t7xx_cldma_hif_hw_init(md->md_ctrl[CLDMA_ID_AP]);
+			t7xx_cldma_hif_hw_init(md->md_ctrl[CLDMA_ID_MD]);
+			t7xx_port_proxy_set_cfg(md, PORT_CFG_ID_NORMAL);
+			ret = fsm_routine_starting(ctl);
+			break;
+
+		default:
+			break;
+		}
+		ctl->status = status;
 	}
 
-	t7xx_cldma_hif_hw_init(md->md_ctrl[CLDMA_ID_AP]);
-	t7xx_cldma_hif_hw_init(md->md_ctrl[CLDMA_ID_MD]);
-	fsm_finish_command(ctl, cmd, fsm_routine_starting(ctl));
+finish_command:
+	fsm_finish_command(ctl, cmd, ret);
 }
 
 static int fsm_main_thread(void *data)
@@ -518,6 +606,7 @@ void t7xx_fsm_reset(struct t7xx_modem *md)
 	fsm_flush_event_cmd_qs(ctl);
 	ctl->curr_state = FSM_STATE_STOPPED;
 	ctl->exp_flg = false;
+	ctl->status = T7XX_DEV_STAGE_INIT;
 }
 
 int t7xx_fsm_init(struct t7xx_modem *md)
diff --git a/drivers/net/wwan/t7xx/t7xx_state_monitor.h b/drivers/net/wwan/t7xx/t7xx_state_monitor.h
index b0b3662ae6d7..7b0a9baf488c 100644
--- a/drivers/net/wwan/t7xx/t7xx_state_monitor.h
+++ b/drivers/net/wwan/t7xx/t7xx_state_monitor.h
@@ -96,6 +96,7 @@ struct t7xx_fsm_ctl {
 	bool			exp_flg;
 	spinlock_t		notifier_lock;		/* Protects notifier list */
 	struct list_head	notifier_list;
+	u32			status;			/* Device boot stage */
 };
 
 struct t7xx_fsm_event {
-- 
2.34.1


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

* [net-next v7 4/4] net: wwan: t7xx: Add fastboot WWAN port
       [not found] <20240201151340.4963-1-songjinjian@hotmail.com>
                   ` (2 preceding siblings ...)
  2024-02-01 15:13 ` [net-next v7 3/4] net: wwan: t7xx: Infrastructure for early port configuration Jinjian Song
@ 2024-02-01 15:13 ` Jinjian Song
  2024-02-01 16:12   ` Jiri Pirko
  2024-02-02  2:17   ` Jinjian Song
  3 siblings, 2 replies; 10+ messages in thread
From: Jinjian Song @ 2024-02-01 15:13 UTC (permalink / raw)
  To: netdev
  Cc: chandrashekar.devegowda, chiranjeevi.rapolu, haijun.liu,
	m.chetan.kumar, ricardo.martinez, loic.poulain, ryazanov.s.a,
	johannes, davem, edumazet, kuba, pabeni, linux-kernel, vsankar,
	letitia.tsai, pin-hao.huang, danielwinkler, nmarupaka, joey.zhao,
	liuqf, felix.yan, angel.huang, freddy.lin, alan.zhang1, zhangrc,
	Jinjian Song

From: Jinjian Song <jinjian.song@fibocom.com>

On early detection of wwan device in fastboot mode, driver sets
up CLDMA0 HW tx/rx queues for raw data transfer and then create
fastboot port to userspace.

Application can use this port to flash firmware and collect
core dump by fastboot protocol commands.
E.g., flash firmware through fastboot port:
 - "download:%08x": write data to memory with the download size.
 - "flash:%s": write the previously downloaded image to the named partition.
 - "reboot": reboot the device.

Link: https://android.googlesource.com/platform/system/core/+/refs/heads/main/fastboot/README.md

Signed-off-by: Jinjian Song <jinjian.song@fibocom.com>
---
v7:
 * add fastboot protocol link and command description to commit info 
v6:
 * reorganize code to avoid dumplication
v4:
 * change function prefix to t7xx_port_fastboot
 * change the name 'FASTBOOT' to fastboot in struct t7xx_early_port_conf
---
 .../networking/device_drivers/wwan/t7xx.rst   |  14 +++
 drivers/net/wwan/t7xx/t7xx_port_proxy.c       |   3 +
 drivers/net/wwan/t7xx/t7xx_port_wwan.c        | 116 ++++++++++++++----
 drivers/net/wwan/t7xx/t7xx_state_monitor.c    |   4 +
 4 files changed, 111 insertions(+), 26 deletions(-)

diff --git a/Documentation/networking/device_drivers/wwan/t7xx.rst b/Documentation/networking/device_drivers/wwan/t7xx.rst
index d13624a52d8b..7257ede90152 100644
--- a/Documentation/networking/device_drivers/wwan/t7xx.rst
+++ b/Documentation/networking/device_drivers/wwan/t7xx.rst
@@ -125,6 +125,20 @@ The driver exposes an AT port by implementing AT WWAN Port.
 The userspace end of the control port is a /dev/wwan0at0 character
 device. Application shall use this interface to issue AT commands.
 
+fastboot port userspace ABI
+---------------------------
+
+/dev/wwan0fastboot0 character device
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The driver exposes a fastboot protocol interface by implementing
+fastboot WWAN Port. The userspace end of the fastboot channel pipe is a
+/dev/wwan0fastboot0 character device. Application shall use this interface for
+fastboot protocol communication.
+
+Please note that driver needs to be reloaded to export /dev/wwan0fastboot0
+port, because device needs a cold reset after enter ``FASTBOOT_DL_SWITCHING``
+mode.
+
 The MediaTek's T700 modem supports the 3GPP TS 27.007 [4] specification.
 
 References
diff --git a/drivers/net/wwan/t7xx/t7xx_port_proxy.c b/drivers/net/wwan/t7xx/t7xx_port_proxy.c
index e53a152faee4..8f5e01705af2 100644
--- a/drivers/net/wwan/t7xx/t7xx_port_proxy.c
+++ b/drivers/net/wwan/t7xx/t7xx_port_proxy.c
@@ -112,6 +112,9 @@ static const struct t7xx_port_conf t7xx_early_port_conf[] = {
 		.txq_exp_index = CLDMA_Q_IDX_DUMP,
 		.rxq_exp_index = CLDMA_Q_IDX_DUMP,
 		.path_id = CLDMA_ID_AP,
+		.ops = &wwan_sub_port_ops,
+		.name = "fastboot",
+		.port_type = WWAN_PORT_FASTBOOT,
 	},
 };
 
diff --git a/drivers/net/wwan/t7xx/t7xx_port_wwan.c b/drivers/net/wwan/t7xx/t7xx_port_wwan.c
index ddc20ddfa734..1d3372848cb6 100644
--- a/drivers/net/wwan/t7xx/t7xx_port_wwan.c
+++ b/drivers/net/wwan/t7xx/t7xx_port_wwan.c
@@ -2,6 +2,7 @@
 /*
  * Copyright (c) 2021, MediaTek Inc.
  * Copyright (c) 2021-2022, Intel Corporation.
+ * Copyright (c) 2024, Fibocom Wireless Inc.
  *
  * Authors:
  *  Amir Hanania <amir.hanania@intel.com>
@@ -15,6 +16,7 @@
  *  Chiranjeevi Rapolu <chiranjeevi.rapolu@intel.com>
  *  Eliot Lee <eliot.lee@intel.com>
  *  Sreehari Kancharla <sreehari.kancharla@intel.com>
+ *  Jinjian Song <jinjian.song@fibocom.com>
  */
 
 #include <linux/atomic.h>
@@ -33,7 +35,7 @@
 #include "t7xx_port_proxy.h"
 #include "t7xx_state_monitor.h"
 
-static int t7xx_port_ctrl_start(struct wwan_port *port)
+static int t7xx_port_wwan_start(struct wwan_port *port)
 {
 	struct t7xx_port *port_mtk = wwan_port_get_drvdata(port);
 
@@ -44,30 +46,60 @@ static int t7xx_port_ctrl_start(struct wwan_port *port)
 	return 0;
 }
 
-static void t7xx_port_ctrl_stop(struct wwan_port *port)
+static void t7xx_port_wwan_stop(struct wwan_port *port)
 {
 	struct t7xx_port *port_mtk = wwan_port_get_drvdata(port);
 
 	atomic_dec(&port_mtk->usage_cnt);
 }
 
-static int t7xx_port_ctrl_tx(struct wwan_port *port, struct sk_buff *skb)
+static int t7xx_port_fastboot_tx(struct t7xx_port *port, struct sk_buff *skb)
+{
+	struct sk_buff *cur = skb, *tx_skb;
+	size_t actual, len, offset = 0;
+	int txq_mtu;
+	int ret;
+
+	txq_mtu = t7xx_get_port_mtu(port);
+	if (txq_mtu < 0)
+		return -EINVAL;
+
+	actual = cur->len;
+	while (actual) {
+		len = min_t(size_t, actual, txq_mtu);
+		tx_skb = __dev_alloc_skb(len, GFP_KERNEL);
+		if (!tx_skb)
+			return -ENOMEM;
+
+		skb_put_data(tx_skb, cur->data + offset, len);
+
+		ret = t7xx_port_send_raw_skb(port, tx_skb);
+		if (ret) {
+			dev_kfree_skb(tx_skb);
+			dev_err(port->dev, "Write error on fastboot port, %d\n", ret);
+			break;
+		}
+		offset += len;
+		actual -= len;
+	}
+
+	dev_kfree_skb(skb);
+	return 0;
+}
+
+static int t7xx_port_ctrl_tx(struct t7xx_port *port, struct sk_buff *skb)
 {
-	struct t7xx_port *port_private = wwan_port_get_drvdata(port);
 	const struct t7xx_port_conf *port_conf;
 	struct sk_buff *cur = skb, *cloned;
 	struct t7xx_fsm_ctl *ctl;
 	enum md_state md_state;
 	int cnt = 0, ret;
 
-	if (!port_private->chan_enable)
-		return -EINVAL;
-
-	port_conf = port_private->port_conf;
-	ctl = port_private->t7xx_dev->md->fsm_ctl;
+	port_conf = port->port_conf;
+	ctl = port->t7xx_dev->md->fsm_ctl;
 	md_state = t7xx_fsm_get_md_state(ctl);
 	if (md_state == MD_STATE_WAITING_FOR_HS1 || md_state == MD_STATE_WAITING_FOR_HS2) {
-		dev_warn(port_private->dev, "Cannot write to %s port when md_state=%d\n",
+		dev_warn(port->dev, "Cannot write to %s port when md_state=%d\n",
 			 port_conf->name, md_state);
 		return -ENODEV;
 	}
@@ -75,10 +107,10 @@ static int t7xx_port_ctrl_tx(struct wwan_port *port, struct sk_buff *skb)
 	while (cur) {
 		cloned = skb_clone(cur, GFP_KERNEL);
 		cloned->len = skb_headlen(cur);
-		ret = t7xx_port_send_skb(port_private, cloned, 0, 0);
+		ret = t7xx_port_send_skb(port, cloned, 0, 0);
 		if (ret) {
 			dev_kfree_skb(cloned);
-			dev_err(port_private->dev, "Write error on %s port, %d\n",
+			dev_err(port->dev, "Write error on %s port, %d\n",
 				port_conf->name, ret);
 			return cnt ? cnt + ret : ret;
 		}
@@ -93,14 +125,53 @@ static int t7xx_port_ctrl_tx(struct wwan_port *port, struct sk_buff *skb)
 	return 0;
 }
 
+static int t7xx_port_wwan_tx(struct wwan_port *port, struct sk_buff *skb)
+{
+	struct t7xx_port *port_private = wwan_port_get_drvdata(port);
+	const struct t7xx_port_conf *port_conf = port_private->port_conf;
+	int ret;
+
+	if (!port_private->chan_enable)
+		return -EINVAL;
+
+	if (port_conf->port_type != WWAN_PORT_FASTBOOT)
+		ret = t7xx_port_ctrl_tx(port_private, skb);
+	else
+		ret = t7xx_port_fastboot_tx(port_private, skb);
+
+	return ret;
+}
+
 static const struct wwan_port_ops wwan_ops = {
-	.start = t7xx_port_ctrl_start,
-	.stop = t7xx_port_ctrl_stop,
-	.tx = t7xx_port_ctrl_tx,
+	.start = t7xx_port_wwan_start,
+	.stop = t7xx_port_wwan_stop,
+	.tx = t7xx_port_wwan_tx,
 };
 
+static void t7xx_port_wwan_create(struct t7xx_port *port)
+{
+	const struct t7xx_port_conf *port_conf = port->port_conf;
+	unsigned int header_len = sizeof(struct ccci_header), mtu;
+	struct wwan_port_caps caps;
+
+	if (!port->wwan.wwan_port) {
+		mtu = t7xx_get_port_mtu(port);
+		caps.frag_len = mtu - header_len;
+		caps.headroom_len = header_len;
+		port->wwan.wwan_port = wwan_create_port(port->dev, port_conf->port_type,
+							&wwan_ops, &caps, port);
+		if (IS_ERR(port->wwan.wwan_port))
+			dev_err(port->dev, "Unable to create WWWAN port %s", port_conf->name);
+	}
+}
+
 static int t7xx_port_wwan_init(struct t7xx_port *port)
 {
+	const struct t7xx_port_conf *port_conf = port->port_conf;
+
+	if (port_conf->port_type == WWAN_PORT_FASTBOOT)
+		t7xx_port_wwan_create(port);
+
 	port->rx_length_th = RX_QUEUE_MAXLEN;
 	return 0;
 }
@@ -152,21 +223,14 @@ static int t7xx_port_wwan_disable_chl(struct t7xx_port *port)
 static void t7xx_port_wwan_md_state_notify(struct t7xx_port *port, unsigned int state)
 {
 	const struct t7xx_port_conf *port_conf = port->port_conf;
-	unsigned int header_len = sizeof(struct ccci_header), mtu;
-	struct wwan_port_caps caps;
+
+	if (port_conf->port_type == WWAN_PORT_FASTBOOT)
+		return;
 
 	if (state != MD_STATE_READY)
 		return;
 
-	if (!port->wwan.wwan_port) {
-		mtu = t7xx_get_port_mtu(port);
-		caps.frag_len = mtu - header_len;
-		caps.headroom_len = header_len;
-		port->wwan.wwan_port = wwan_create_port(port->dev, port_conf->port_type,
-							&wwan_ops, &caps, port);
-		if (IS_ERR(port->wwan.wwan_port))
-			dev_err(port->dev, "Unable to create WWWAN port %s", port_conf->name);
-	}
+	t7xx_port_wwan_create(port);
 }
 
 struct port_ops wwan_sub_port_ops = {
diff --git a/drivers/net/wwan/t7xx/t7xx_state_monitor.c b/drivers/net/wwan/t7xx/t7xx_state_monitor.c
index b98ad4a1709b..11906f00c875 100644
--- a/drivers/net/wwan/t7xx/t7xx_state_monitor.c
+++ b/drivers/net/wwan/t7xx/t7xx_state_monitor.c
@@ -229,6 +229,7 @@ static void t7xx_lk_stage_event_handling(struct t7xx_fsm_ctl *ctl, unsigned int
 	struct cldma_ctrl *md_ctrl;
 	enum lk_event_id lk_event;
 	struct device *dev;
+	struct t7xx_port *port;
 
 	dev = &md->t7xx_dev->pdev->dev;
 	lk_event = FIELD_GET(MISC_LK_EVENT_MASK, status);
@@ -244,6 +245,9 @@ static void t7xx_lk_stage_event_handling(struct t7xx_fsm_ctl *ctl, unsigned int
 		t7xx_cldma_stop(md_ctrl);
 		t7xx_cldma_switch_cfg(md_ctrl, CLDMA_DEDICATED_Q_CFG);
 
+		port = &ctl->md->port_prox->ports[0];
+		port->port_conf->ops->enable_chl(port);
+
 		t7xx_cldma_start(md_ctrl);
 
 		if (lk_event == LK_EVENT_CREATE_POST_DL_PORT)
-- 
2.34.1


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

* Re: [net-next v7 2/4] net: wwan: t7xx: Add sysfs attribute for device state machine
  2024-02-01 15:13 ` [net-next v7 2/4] net: wwan: t7xx: Add sysfs attribute for device state machine Jinjian Song
@ 2024-02-01 16:11   ` Jiri Pirko
  2024-02-02  2:16   ` Jinjian Song
  1 sibling, 0 replies; 10+ messages in thread
From: Jiri Pirko @ 2024-02-01 16:11 UTC (permalink / raw)
  To: Jinjian Song
  Cc: netdev, chandrashekar.devegowda, chiranjeevi.rapolu, haijun.liu,
	m.chetan.kumar, ricardo.martinez, loic.poulain, ryazanov.s.a,
	johannes, davem, edumazet, kuba, pabeni, linux-kernel, vsankar,
	letitia.tsai, pin-hao.huang, danielwinkler, nmarupaka, joey.zhao,
	liuqf, felix.yan, angel.huang, freddy.lin, alan.zhang1, zhangrc,
	Jinjian Song

Thu, Feb 01, 2024 at 04:13:38PM CET, songjinjian@hotmail.com wrote:
>From: Jinjian Song <jinjian.song@fibocom.com>
>
>Add support for userspace to get/set the device mode, device's state machine
>changes between (UNKNOWN/READY/RESET/FASTBOOT_DL_MODE/FASTBOOT_DUMP_MODE).
>
>Get the device state mode:
> - 'cat /sys/bus/pci/devices/${bdf}/t7xx_mode'
>
>Set the device state mode:
> - reset(cold reset): 'echo RESET > /sys/bus/pci/devices/${bdf}/t7xx_mode'
> - fastboot: 'echo FASTBOOT_DL_SWITCHING > /sys/bus/pci/devices/${bdf}/t7xx_mode'
>Reload driver to get the new device state after setting operation.
>
>Signed-off-by: Jinjian Song <jinjian.song@fibocom.com>
>---
>v7:
> * add sysfs description to commit info 
> * update t7xx_dev->mode after reset by sysfs t7xx_mode
>v6:
> * change code style in t7xx_mode_store()
>v5:
> * add cold reset support via sysfs t7xx_mode
>v4:
> * narrow down the set of accepted values in t7xx_mode_store()
> * change mode type atomic to u32 with READ_ONCE()/WRITE_ONCE()
> * delete 'T7XX_MODEM' prefix and using sysfs_emit in t7xx_mode_show()
> * add description of sysfs t7xx_mode in document t7xx.rst
>v2:
> * optimizing using goto label in t7xx_pci_probe
>---
> .../networking/device_drivers/wwan/t7xx.rst   | 28 ++++++
> drivers/net/wwan/t7xx/t7xx_modem_ops.c        |  6 ++
> drivers/net/wwan/t7xx/t7xx_modem_ops.h        |  1 +
> drivers/net/wwan/t7xx/t7xx_pci.c              | 98 ++++++++++++++++++-
> drivers/net/wwan/t7xx/t7xx_pci.h              | 14 ++-
> drivers/net/wwan/t7xx/t7xx_state_monitor.c    |  1 +
> 6 files changed, 143 insertions(+), 5 deletions(-)
>
>diff --git a/Documentation/networking/device_drivers/wwan/t7xx.rst b/Documentation/networking/device_drivers/wwan/t7xx.rst
>index dd5b731957ca..d13624a52d8b 100644
>--- a/Documentation/networking/device_drivers/wwan/t7xx.rst
>+++ b/Documentation/networking/device_drivers/wwan/t7xx.rst
>@@ -39,6 +39,34 @@ command and receive response:
> 
> - open the AT control channel using a UART tool or a special user tool
> 
>+Sysfs
>+=====
>+The driver provides sysfs interfaces to userspace.
>+
>+t7xx_mode
>+---------
>+The sysfs interface provides userspace with access to the device mode, this interface
>+supports read and write operations.
>+
>+Device mode:
>+
>+- ``UNKNOW`` represents that device in unknown status

should be "unknown", missing "n".

Btw, why are you using capitals for the mode names?



>+- ``READY`` represents that device in ready status
>+- ``RESET`` represents that device in reset status
>+- ``FASTBOOT_DL_SWITCHING`` represents that device in fastboot switching status
>+- ``FASTBOOT_DL_MODE`` represents that device in fastboot download status
>+- ``FASTBOOT_DL_DUMP_MODE`` represents that device in fastboot dump status
>+
>+Read from userspace to get the current device mode.
>+
>+::
>+  $ cat /sys/bus/pci/devices/${bdf}/t7xx_mode
>+
>+Write from userspace to set the device mode.
>+
>+::
>+  $ echo FASTBOOT_DL_SWITCHING > /sys/bus/pci/devices/${bdf}/t7xx_mode
>+
> Management application development
> ==================================
> The driver and userspace interfaces are described below. The MBIM protocol is
>diff --git a/drivers/net/wwan/t7xx/t7xx_modem_ops.c b/drivers/net/wwan/t7xx/t7xx_modem_ops.c
>index 24e7d491468e..ca262d2961ed 100644
>--- a/drivers/net/wwan/t7xx/t7xx_modem_ops.c
>+++ b/drivers/net/wwan/t7xx/t7xx_modem_ops.c
>@@ -177,6 +177,11 @@ int t7xx_acpi_fldr_func(struct t7xx_pci_dev *t7xx_dev)
> 	return t7xx_acpi_reset(t7xx_dev, "_RST");
> }
> 
>+int t7xx_acpi_pldr_func(struct t7xx_pci_dev *t7xx_dev)
>+{
>+	return t7xx_acpi_reset(t7xx_dev, "MRST._RST");
>+}
>+
> static void t7xx_reset_device_via_pmic(struct t7xx_pci_dev *t7xx_dev)
> {
> 	u32 val;
>@@ -192,6 +197,7 @@ static irqreturn_t t7xx_rgu_isr_thread(int irq, void *data)
> {
> 	struct t7xx_pci_dev *t7xx_dev = data;
> 
>+	t7xx_mode_update(t7xx_dev, T7XX_RESET);
> 	msleep(RGU_RESET_DELAY_MS);
> 	t7xx_reset_device_via_pmic(t7xx_dev);
> 	return IRQ_HANDLED;
>diff --git a/drivers/net/wwan/t7xx/t7xx_modem_ops.h b/drivers/net/wwan/t7xx/t7xx_modem_ops.h
>index abe633cf7adc..b39e945a92e0 100644
>--- a/drivers/net/wwan/t7xx/t7xx_modem_ops.h
>+++ b/drivers/net/wwan/t7xx/t7xx_modem_ops.h
>@@ -85,6 +85,7 @@ int t7xx_md_init(struct t7xx_pci_dev *t7xx_dev);
> void t7xx_md_exit(struct t7xx_pci_dev *t7xx_dev);
> void t7xx_clear_rgu_irq(struct t7xx_pci_dev *t7xx_dev);
> int t7xx_acpi_fldr_func(struct t7xx_pci_dev *t7xx_dev);
>+int t7xx_acpi_pldr_func(struct t7xx_pci_dev *t7xx_dev);
> int t7xx_pci_mhccif_isr(struct t7xx_pci_dev *t7xx_dev);
> 
> #endif	/* __T7XX_MODEM_OPS_H__ */
>diff --git a/drivers/net/wwan/t7xx/t7xx_pci.c b/drivers/net/wwan/t7xx/t7xx_pci.c
>index 91256e005b84..1a10afd948c7 100644
>--- a/drivers/net/wwan/t7xx/t7xx_pci.c
>+++ b/drivers/net/wwan/t7xx/t7xx_pci.c
>@@ -52,6 +52,81 @@
> #define PM_RESOURCE_POLL_TIMEOUT_US	10000
> #define PM_RESOURCE_POLL_STEP_US	100
> 
>+static const char * const mode_names[] = {

t7xx_mode_names


>+	[T7XX_UNKNOWN] = "UNKNOWN",
>+	[T7XX_READY] = "READY",
>+	[T7XX_RESET] = "RESET",
>+	[T7XX_FASTBOOT_DL_SWITCHING] = "FASTBOOT_DL_SWITCHING",
>+	[T7XX_FASTBOOT_DL_MODE] = "FASTBOOT_DL_MODE",
>+	[T7XX_FASTBOOT_DUMP_MODE] = "FASTBOOT_DUMP_MODE",
>+};
>+
>+static_assert(ARRAY_SIZE(mode_names) == T7XX_MODE_LAST);
>+
>+static ssize_t t7xx_mode_store(struct device *dev,
>+			       struct device_attribute *attr,
>+			       const char *buf, size_t count)
>+{
>+	struct t7xx_pci_dev *t7xx_dev;
>+	struct pci_dev *pdev;
>+	int index = 0;
>+
>+	pdev = to_pci_dev(dev);
>+	t7xx_dev = pci_get_drvdata(pdev);
>+	if (!t7xx_dev)
>+		return -ENODEV;
>+
>+	index = sysfs_match_string(mode_names, buf);
>+	if (index == T7XX_FASTBOOT_DL_SWITCHING) {
>+		WRITE_ONCE(t7xx_dev->mode, T7XX_FASTBOOT_DL_SWITCHING);
>+	} else if (index == T7XX_RESET) {
>+		WRITE_ONCE(t7xx_dev->mode, T7XX_RESET);
>+		t7xx_acpi_pldr_func(t7xx_dev);
>+	}
>+
>+	return count;
>+};
>+
>+static ssize_t t7xx_mode_show(struct device *dev,
>+			      struct device_attribute *attr,
>+			      char *buf)
>+{
>+	enum t7xx_mode mode = T7XX_UNKNOWN;
>+	struct t7xx_pci_dev *t7xx_dev;
>+	struct pci_dev *pdev;
>+
>+	pdev = to_pci_dev(dev);
>+	t7xx_dev = pci_get_drvdata(pdev);
>+	if (!t7xx_dev)
>+		return -ENODEV;
>+
>+	mode = READ_ONCE(t7xx_dev->mode);
>+	if (mode < T7XX_MODE_LAST)
>+		return sysfs_emit(buf, "%s\n", mode_names[mode]);
>+
>+	return sysfs_emit(buf, "%s\n", mode_names[T7XX_UNKNOWN]);
>+}
>+
>+static DEVICE_ATTR_RW(t7xx_mode);
>+
>+static struct attribute *t7xx_mode_attr[] = {
>+	&dev_attr_t7xx_mode.attr,
>+	NULL
>+};
>+
>+static const struct attribute_group t7xx_mode_attribute_group = {
>+	.attrs = t7xx_mode_attr,
>+};
>+
>+void t7xx_mode_update(struct t7xx_pci_dev *t7xx_dev, enum t7xx_mode mode)
>+{
>+	if (!t7xx_dev)
>+		return;
>+
>+	WRITE_ONCE(t7xx_dev->mode, mode);
>+	sysfs_notify(&t7xx_dev->pdev->dev.kobj, NULL, "t7xx_mode");
>+}
>+
> enum t7xx_pm_state {
> 	MTK_PM_EXCEPTION,
> 	MTK_PM_INIT,		/* Device initialized, but handshake not completed */
>@@ -729,16 +804,28 @@ static int t7xx_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
> 
> 	t7xx_pcie_mac_interrupts_dis(t7xx_dev);
> 
>+	ret = sysfs_create_group(&t7xx_dev->pdev->dev.kobj,
>+				 &t7xx_mode_attribute_group);
>+	if (ret)
>+		goto err_md_exit;
>+
> 	ret = t7xx_interrupt_init(t7xx_dev);
>-	if (ret) {
>-		t7xx_md_exit(t7xx_dev);
>-		return ret;
>-	}
>+	if (ret)
>+		goto err_remove_group;
>+
> 
> 	t7xx_pcie_mac_set_int(t7xx_dev, MHCCIF_INT);
> 	t7xx_pcie_mac_interrupts_en(t7xx_dev);
> 
> 	return 0;
>+
>+err_remove_group:
>+	sysfs_remove_group(&t7xx_dev->pdev->dev.kobj,
>+			   &t7xx_mode_attribute_group);
>+
>+err_md_exit:
>+	t7xx_md_exit(t7xx_dev);
>+	return ret;
> }
> 
> static void t7xx_pci_remove(struct pci_dev *pdev)
>@@ -747,6 +834,9 @@ static void t7xx_pci_remove(struct pci_dev *pdev)
> 	int i;
> 
> 	t7xx_dev = pci_get_drvdata(pdev);
>+
>+	sysfs_remove_group(&t7xx_dev->pdev->dev.kobj,
>+			   &t7xx_mode_attribute_group);
> 	t7xx_md_exit(t7xx_dev);
> 
> 	for (i = 0; i < EXT_INT_NUM; i++) {
>diff --git a/drivers/net/wwan/t7xx/t7xx_pci.h b/drivers/net/wwan/t7xx/t7xx_pci.h
>index f08f1ab74469..0abba7e6f8aa 100644
>--- a/drivers/net/wwan/t7xx/t7xx_pci.h
>+++ b/drivers/net/wwan/t7xx/t7xx_pci.h
>@@ -43,6 +43,16 @@ struct t7xx_addr_base {
> 
> typedef irqreturn_t (*t7xx_intr_callback)(int irq, void *param);
> 
>+enum t7xx_mode {
>+	T7XX_UNKNOWN,
>+	T7XX_READY,
>+	T7XX_RESET,
>+	T7XX_FASTBOOT_DL_SWITCHING,
>+	T7XX_FASTBOOT_DL_MODE,
>+	T7XX_FASTBOOT_DUMP_MODE,
>+	T7XX_MODE_LAST, /* must always be last */
>+};
>+
> /* struct t7xx_pci_dev - MTK device context structure
>  * @intr_handler: array of handler function for request_threaded_irq
>  * @intr_thread: array of thread_fn for request_threaded_irq
>@@ -59,6 +69,7 @@ typedef irqreturn_t (*t7xx_intr_callback)(int irq, void *param);
>  * @md_pm_lock: protects PCIe sleep lock
>  * @sleep_disable_count: PCIe L1.2 lock counter
>  * @sleep_lock_acquire: indicates that sleep has been disabled
>+ * @mode: indicates the device mode
>  */
> struct t7xx_pci_dev {
> 	t7xx_intr_callback	intr_handler[EXT_INT_NUM];
>@@ -82,6 +93,7 @@ struct t7xx_pci_dev {
> #ifdef CONFIG_WWAN_DEBUGFS
> 	struct dentry		*debugfs_dir;
> #endif
>+	u32			mode;
> };
> 
> enum t7xx_pm_id {
>@@ -120,5 +132,5 @@ int t7xx_pci_pm_entity_register(struct t7xx_pci_dev *t7xx_dev, struct md_pm_enti
> int t7xx_pci_pm_entity_unregister(struct t7xx_pci_dev *t7xx_dev, struct md_pm_entity *pm_entity);
> void t7xx_pci_pm_init_late(struct t7xx_pci_dev *t7xx_dev);
> void t7xx_pci_pm_exp_detected(struct t7xx_pci_dev *t7xx_dev);
>-
>+void t7xx_mode_update(struct t7xx_pci_dev *t7xx_dev, enum t7xx_mode mode);
> #endif /* __T7XX_PCI_H__ */
>diff --git a/drivers/net/wwan/t7xx/t7xx_state_monitor.c b/drivers/net/wwan/t7xx/t7xx_state_monitor.c
>index 0bc97430211b..c5d46f45fa62 100644
>--- a/drivers/net/wwan/t7xx/t7xx_state_monitor.c
>+++ b/drivers/net/wwan/t7xx/t7xx_state_monitor.c
>@@ -272,6 +272,7 @@ static void fsm_routine_ready(struct t7xx_fsm_ctl *ctl)
> 
> 	ctl->curr_state = FSM_STATE_READY;
> 	t7xx_fsm_broadcast_ready_state(ctl);
>+	t7xx_mode_update(md->t7xx_dev, T7XX_READY);
> 	t7xx_md_event_notify(md, FSM_READY);
> }
> 
>-- 
>2.34.1
>
>

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

* Re: [net-next v7 4/4] net: wwan: t7xx: Add fastboot WWAN port
  2024-02-01 15:13 ` [net-next v7 4/4] net: wwan: t7xx: Add fastboot WWAN port Jinjian Song
@ 2024-02-01 16:12   ` Jiri Pirko
  2024-02-02  2:17   ` Jinjian Song
  1 sibling, 0 replies; 10+ messages in thread
From: Jiri Pirko @ 2024-02-01 16:12 UTC (permalink / raw)
  To: Jinjian Song
  Cc: netdev, chandrashekar.devegowda, chiranjeevi.rapolu, haijun.liu,
	m.chetan.kumar, ricardo.martinez, loic.poulain, ryazanov.s.a,
	johannes, davem, edumazet, kuba, pabeni, linux-kernel, vsankar,
	letitia.tsai, pin-hao.huang, danielwinkler, nmarupaka, joey.zhao,
	liuqf, felix.yan, angel.huang, freddy.lin, alan.zhang1, zhangrc,
	Jinjian Song

Thu, Feb 01, 2024 at 04:13:40PM CET, songjinjian@hotmail.com wrote:
>From: Jinjian Song <jinjian.song@fibocom.com>

[...]

>+static void t7xx_port_wwan_create(struct t7xx_port *port)
>+{
>+	const struct t7xx_port_conf *port_conf = port->port_conf;
>+	unsigned int header_len = sizeof(struct ccci_header), mtu;
>+	struct wwan_port_caps caps;
>+
>+	if (!port->wwan.wwan_port) {
>+		mtu = t7xx_get_port_mtu(port);
>+		caps.frag_len = mtu - header_len;
>+		caps.headroom_len = header_len;
>+		port->wwan.wwan_port = wwan_create_port(port->dev, port_conf->port_type,
>+							&wwan_ops, &caps, port);
>+		if (IS_ERR(port->wwan.wwan_port))
>+			dev_err(port->dev, "Unable to create WWWAN port %s", port_conf->name);

To many "W"s.

>+	}
>+}

[...]

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

* Re: [net-next v7 2/4] net: wwan: t7xx: Add sysfs attribute for device state machine
  2024-02-01 15:13 ` [net-next v7 2/4] net: wwan: t7xx: Add sysfs attribute for device state machine Jinjian Song
  2024-02-01 16:11   ` Jiri Pirko
@ 2024-02-02  2:16   ` Jinjian Song
  2024-02-02  7:23     ` Jiri Pirko
  1 sibling, 1 reply; 10+ messages in thread
From: Jinjian Song @ 2024-02-02  2:16 UTC (permalink / raw)
  To: jiri
  Cc: alan.zhang1, angel.huang, chandrashekar.devegowda,
	chiranjeevi.rapolu, danielwinkler, davem, edumazet, felix.yan,
	freddy.lin, haijun.liu, jinjian.song, joey.zhao, johannes, kuba,
	letitia.tsai, linux-kernel, liuqf, loic.poulain, m.chetan.kumar,
	netdev, nmarupaka, pabeni, pin-hao.huang, ricardo.martinez,
	ryazanov.s.a, songjinjian, vsankar, zhangrc

>Thu, Feb 01, 2024 at 04:13:38PM CET, songjinjian@hotmail.com wrote:
>>From: Jinjian Song <jinjian.song@fibocom.com>
>>
>>Add support for userspace to get/set the device mode, device's state machine
>>changes between (UNKNOWN/READY/RESET/FASTBOOT_DL_MODE/FASTBOOT_DUMP_MODE).
>>
>>diff --git a/Documentation/networking/device_drivers/wwan/t7xx.rst b/Documentation/networking/device_drivers/wwan/t7xx.rst
>>index dd5b731957ca..d13624a52d8b 100644
>>--- a/Documentation/networking/device_drivers/wwan/t7xx.rst
>>+++ b/Documentation/networking/device_drivers/wwan/t7xx.rst
>>@@ -39,6 +39,34 @@ command and receive response:
>> 
>>+supports read and write operations.
>>+
>>+Device mode:
>>+
>>+- ``UNKNOW`` represents that device in unknown status
>
>should be "unknown", missing "n".
>
>Btw, why are you using capitals for the mode names?

Thanks, let me change it to lowercase and modify the word. 
Previously considering it represents a state machine and with udev to report the state.

>>+- ``READY`` represents that device in ready status
>>+- ``RESET`` represents that device in reset status
>>+- ``FASTBOOT_DL_SWITCHING`` represents that device in fastboot switching status
>>+- ``FASTBOOT_DL_MODE`` represents that device in fastboot download status
>>+- ``FASTBOOT_DL_DUMP_MODE`` represents that device in fastboot dump status
>>+
>>+Read from userspace to get the current device mode.
>>+
>>+::
>>+  $ cat /sys/bus/pci/devices/${bdf}/t7xx_mode
>>+
>>+Write from userspace to set the device mode.
>>+
>>+::
>>+  $ echo FASTBOOT_DL_SWITCHING > /sys/bus/pci/devices/${bdf}/t7xx_mode
>>+
>>+static const char * const mode_names[] = {
>
>t7xx_mode_names

Let me rename it.

Best Regards,
Jinjian

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

* Re: [net-next v7 4/4] net: wwan: t7xx: Add fastboot WWAN port
  2024-02-01 15:13 ` [net-next v7 4/4] net: wwan: t7xx: Add fastboot WWAN port Jinjian Song
  2024-02-01 16:12   ` Jiri Pirko
@ 2024-02-02  2:17   ` Jinjian Song
  1 sibling, 0 replies; 10+ messages in thread
From: Jinjian Song @ 2024-02-02  2:17 UTC (permalink / raw)
  To: jiri
  Cc: alan.zhang1, angel.huang, chandrashekar.devegowda,
	chiranjeevi.rapolu, danielwinkler, davem, edumazet, felix.yan,
	freddy.lin, haijun.liu, jinjian.song, joey.zhao, johannes, kuba,
	letitia.tsai, linux-kernel, liuqf, loic.poulain, m.chetan.kumar,
	netdev, nmarupaka, pabeni, pin-hao.huang, ricardo.martinez,
	ryazanov.s.a, songjinjian, vsankar, zhangrc

>Thu, Feb 01, 2024 at 04:13:40PM CET, songjinjian@hotmail.com wrote:
>>From: Jinjian Song <jinjian.song@fibocom.com>
>
>[...]
>
>>+static void t7xx_port_wwan_create(struct t7xx_port *port)
>>+{
>>+	const struct t7xx_port_conf *port_conf = port->port_conf;
>>+	unsigned int header_len = sizeof(struct ccci_header), mtu;
>>+	struct wwan_port_caps caps;
>>+
>>+	if (!port->wwan.wwan_port) {
>>+		mtu = t7xx_get_port_mtu(port);
>>+		caps.frag_len = mtu - header_len;
>>+		caps.headroom_len = header_len;
>>+		port->wwan.wwan_port = wwan_create_port(port->dev, port_conf->port_type,
>>+							&wwan_ops, &caps, port);
>>+		if (IS_ERR(port->wwan.wwan_port))
>>+			dev_err(port->dev, "Unable to create WWWAN port %s", port_conf->name);
>
>To many "W"s.

Thanks, let me change that.

>>+	}
>>+}
>
>[...]
>
>

Best Regards,
Jinjian

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

* Re: [net-next v7 2/4] net: wwan: t7xx: Add sysfs attribute for device state machine
  2024-02-02  2:16   ` Jinjian Song
@ 2024-02-02  7:23     ` Jiri Pirko
  2024-02-02 15:07       ` Jinjian Song
  0 siblings, 1 reply; 10+ messages in thread
From: Jiri Pirko @ 2024-02-02  7:23 UTC (permalink / raw)
  To: Jinjian Song
  Cc: alan.zhang1, angel.huang, chandrashekar.devegowda,
	chiranjeevi.rapolu, danielwinkler, davem, edumazet, felix.yan,
	freddy.lin, haijun.liu, jinjian.song, joey.zhao, johannes, kuba,
	letitia.tsai, linux-kernel, liuqf, loic.poulain, m.chetan.kumar,
	netdev, nmarupaka, pabeni, pin-hao.huang, ricardo.martinez,
	ryazanov.s.a, vsankar, zhangrc

Fri, Feb 02, 2024 at 03:16:12AM CET, songjinjian@hotmail.com wrote:
>>Thu, Feb 01, 2024 at 04:13:38PM CET, songjinjian@hotmail.com wrote:
>>>From: Jinjian Song <jinjian.song@fibocom.com>

Could you please fix your email client? You clearly reply to my email,
yet the threading is wrong. Thanks!


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

* Re: [net-next v7 2/4] net: wwan: t7xx: Add sysfs attribute for device state machine
  2024-02-02  7:23     ` Jiri Pirko
@ 2024-02-02 15:07       ` Jinjian Song
  0 siblings, 0 replies; 10+ messages in thread
From: Jinjian Song @ 2024-02-02 15:07 UTC (permalink / raw)
  To: jiri
  Cc: alan.zhang1, angel.huang, chandrashekar.devegowda,
	chiranjeevi.rapolu, danielwinkler, davem, edumazet, felix.yan,
	freddy.lin, haijun.liu, jinjian.song, joey.zhao, johannes, kuba,
	letitia.tsai, linux-kernel, liuqf, loic.poulain, m.chetan.kumar,
	netdev, nmarupaka, pabeni, pin-hao.huang, ricardo.martinez,
	ryazanov.s.a, songjinjian, vsankar, zhangrc

>Fri, Feb 02, 2024 at 03:16:12AM CET, songjinjian@hotmail.com wrote:
>>>Thu, Feb 01, 2024 at 04:13:38PM CET, songjinjian@hotmail.com wrote:
>>>>From: Jinjian Song <jinjian.song@fibocom.com>
>
>Could you please fix your email client? You clearly reply to my email,
>yet the threading is wrong. Thanks!
>

Yes, sorry for that, please let me try to fix it, thanks.

Best Regards,
Jinjian



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

end of thread, other threads:[~2024-02-02 15:08 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <20240201151340.4963-1-songjinjian@hotmail.com>
2024-02-01 15:13 ` [net-next v7 1/4] wwan: core: Add WWAN fastboot port type Jinjian Song
2024-02-01 15:13 ` [net-next v7 2/4] net: wwan: t7xx: Add sysfs attribute for device state machine Jinjian Song
2024-02-01 16:11   ` Jiri Pirko
2024-02-02  2:16   ` Jinjian Song
2024-02-02  7:23     ` Jiri Pirko
2024-02-02 15:07       ` Jinjian Song
2024-02-01 15:13 ` [net-next v7 3/4] net: wwan: t7xx: Infrastructure for early port configuration Jinjian Song
2024-02-01 15:13 ` [net-next v7 4/4] net: wwan: t7xx: Add fastboot WWAN port Jinjian Song
2024-02-01 16:12   ` Jiri Pirko
2024-02-02  2:17   ` Jinjian Song

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).