diff mbox series

[v4,net-next,2/5] net: wwan: t7xx: Infrastructure for early port configuration

Message ID 565d5f166b88ae2b7377ba6beb31dc9b6b2bc431.1673842618.git.m.chetan.kumar@linux.intel.com (mailing list archive)
State Superseded
Delegated to: Netdev Maintainers
Headers show
Series net: wwan: t7xx: fw flashing & coredump support | expand

Checks

Context Check Description
netdev/tree_selection success Clearly marked for net-next
netdev/fixes_present success Fixes tag not required for -next series
netdev/subject_prefix success Link
netdev/cover_letter success Series has a cover letter
netdev/patch_count success Link
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 0 this patch: 0
netdev/cc_maintainers warning 3 maintainers not CCed: matthias.bgg@gmail.com linux-arm-kernel@lists.infradead.org linux-mediatek@lists.infradead.org
netdev/build_clang success Errors and warnings before: 0 this patch: 0
netdev/module_param success Was 0 now: 0
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 0 this patch: 0
netdev/checkpatch warning WARNING: line length of 84 exceeds 80 columns WARNING: line length of 86 exceeds 80 columns WARNING: line length of 87 exceeds 80 columns WARNING: line length of 88 exceeds 80 columns WARNING: line length of 90 exceeds 80 columns WARNING: line length of 93 exceeds 80 columns WARNING: line length of 97 exceeds 80 columns WARNING: line length of 98 exceeds 80 columns
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Kumar, M Chetan Jan. 16, 2023, 6:04 a.m. UTC
From: M Chetan Kumar <m.chetan.kumar@linux.intel.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.

Signed-off-by: Haijun Liu <haijun.liu@mediatek.com>
Co-developed-by: Madhusmita Sahu <madhusmita.sahu@intel.com>
Signed-off-by: Madhusmita Sahu <madhusmita.sahu@intel.com>
Signed-off-by: Ricardo Martinez <ricardo.martinez@linux.intel.com>
Signed-off-by: Devegowda Chandrashekar <chandrashekar.devegowda@intel.com>
Signed-off-by: M Chetan Kumar <m.chetan.kumar@linux.intel.com>
--
v4:
 * Remove "this patch" in commit message.
 * MISC_DEV_STATUS_MASK & MISC_DEV_STATUS_INVALID is unused, drop it.
 * Drop unnecessary assignement for ret var inside fsm_routine_start.
 * cppcheck - reduce variableScope for stage var in fsm_routine_start.
v3:
 * No Change.
v2:
 * Move recv_skb handler to cldma_queue.
 * Drop cldma_queue_type.
 * Restore prototype of t7xx_port_send_raw_skb().
 * Remove PORT_CFG_ID_INVALID check in t7xx_port_proxy_set_cfg().
 * Add space before */.
 * Drop unnecessary logs.
 * Use WARN_ON on early port.
 * Use new MISC_DEV_STATUS_INVALID instead of MISC_DEV_STATUS.
 * Use macros instead of const identifiers.
 * Change ports member type from pointer to array type.
 * Prefix LK_EVENT_XX with MISC prefix.
 * Use t7xx prefix for device_stage enums.
 * Correct log messages.
 * Dont override pkt_size for non-download port under dedicated Queue.
 * Drop cldma_txq_rxq_ids.
 * Use macro for txq/rxq index.
 * Use warn_on for rxq_idx comparison.
 * Drop t7xx_port_proxy_get_port_by_name().
 * Replace fsm poll with read_poll_timeout().
 * Use "\n" consistently across log message.
 * Remove local var _dev prefixes in fsm_routine_start().
 * Use max_t.
---
 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_port.h          |  4 +
 drivers/net/wwan/t7xx/t7xx_port_proxy.c    | 89 +++++++++++++++++++---
 drivers/net/wwan/t7xx/t7xx_port_proxy.h    | 12 ++-
 drivers/net/wwan/t7xx/t7xx_port_wwan.c     |  3 +-
 drivers/net/wwan/t7xx/t7xx_reg.h           | 22 +++++-
 drivers/net/wwan/t7xx/t7xx_state_monitor.c | 85 ++++++++++++++++++---
 drivers/net/wwan/t7xx/t7xx_state_monitor.h |  1 +
 10 files changed, 235 insertions(+), 50 deletions(-)

Comments

Ilpo Järvinen Jan. 16, 2023, 12:56 p.m. UTC | #1
On Mon, 16 Jan 2023, m.chetan.kumar@linux.intel.com wrote:

> From: M Chetan Kumar <m.chetan.kumar@linux.intel.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.

This doesn't go into details why CLDMA_MTU -> CLDMA_SHARED_Q_BUFF_SZ 
rename was done (if it wouldn't have been in the same change at all, I 
could have immediately seen that, ah, it was just moving code around but 
now I had to go to check if the defines yield same values).

> Signed-off-by: Haijun Liu <haijun.liu@mediatek.com>
> Co-developed-by: Madhusmita Sahu <madhusmita.sahu@intel.com>
> Signed-off-by: Madhusmita Sahu <madhusmita.sahu@intel.com>
> Signed-off-by: Ricardo Martinez <ricardo.martinez@linux.intel.com>
> Signed-off-by: Devegowda Chandrashekar <chandrashekar.devegowda@intel.com>
> Signed-off-by: M Chetan Kumar <m.chetan.kumar@linux.intel.com>
> --
> v4:
>  * Remove "this patch" in commit message.
>  * MISC_DEV_STATUS_MASK & MISC_DEV_STATUS_INVALID is unused, drop it.
>  * Drop unnecessary assignement for ret var inside fsm_routine_start.
>  * cppcheck - reduce variableScope for stage var in fsm_routine_start.
> v3:
>  * No Change.
> v2:
>  * Move recv_skb handler to cldma_queue.
>  * Drop cldma_queue_type.
>  * Restore prototype of t7xx_port_send_raw_skb().
>  * Remove PORT_CFG_ID_INVALID check in t7xx_port_proxy_set_cfg().
>  * Add space before */.
>  * Drop unnecessary logs.
>  * Use WARN_ON on early port.
>  * Use new MISC_DEV_STATUS_INVALID instead of MISC_DEV_STATUS.
>  * Use macros instead of const identifiers.
>  * Change ports member type from pointer to array type.
>  * Prefix LK_EVENT_XX with MISC prefix.
>  * Use t7xx prefix for device_stage enums.
>  * Correct log messages.
>  * Dont override pkt_size for non-download port under dedicated Queue.
>  * Drop cldma_txq_rxq_ids.
>  * Use macro for txq/rxq index.
>  * Use warn_on for rxq_idx comparison.
>  * Drop t7xx_port_proxy_get_port_by_name().
>  * Replace fsm poll with read_poll_timeout().
>  * Use "\n" consistently across log message.
>  * Remove local var _dev prefixes in fsm_routine_start().
>  * Use max_t.
> ---
>  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_port.h          |  4 +
>  drivers/net/wwan/t7xx/t7xx_port_proxy.c    | 89 +++++++++++++++++++---
>  drivers/net/wwan/t7xx/t7xx_port_proxy.h    | 12 ++-
>  drivers/net/wwan/t7xx/t7xx_port_wwan.c     |  3 +-
>  drivers/net/wwan/t7xx/t7xx_reg.h           | 22 +++++-
>  drivers/net/wwan/t7xx/t7xx_state_monitor.c | 85 ++++++++++++++++++---
>  drivers/net/wwan/t7xx/t7xx_state_monitor.h |  1 +
>  10 files changed, 235 insertions(+), 50 deletions(-)
> 
> diff --git a/drivers/net/wwan/t7xx/t7xx_hif_cldma.c b/drivers/net/wwan/t7xx/t7xx_hif_cldma.c
> index 4f56d8cc0aea..12c9e9cba74a 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;
> @@ -1331,9 +1347,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..5453cfecbe19 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 24e7d491468e..cbd65aa48721 100644
> --- a/drivers/net/wwan/t7xx/t7xx_modem_ops.c
> +++ b/drivers/net/wwan/t7xx/t7xx_modem_ops.c
> @@ -529,7 +529,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;
> @@ -544,7 +544,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_port.h b/drivers/net/wwan/t7xx/t7xx_port.h
> index 4ae8a00a8532..09acb1ef144d 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_ID_UNIMPORTANT = 0xffff,
>  };
>  
>  struct t7xx_port;
> @@ -135,9 +137,11 @@ 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_raw_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_ctl_skb(struct t7xx_port *port, struct sk_buff *skb, unsigned int msg,
> diff --git a/drivers/net/wwan/t7xx/t7xx_port_proxy.c b/drivers/net/wwan/t7xx/t7xx_port_proxy.c
> index 274846d39fbf..b457e8da098e 100644
> --- a/drivers/net/wwan/t7xx/t7xx_port_proxy.c
> +++ b/drivers/net/wwan/t7xx/t7xx_port_proxy.c
> @@ -100,6 +100,18 @@ static const struct t7xx_port_conf t7xx_port_conf[] = {
>  	},
>  };
>  
> +static struct t7xx_port_conf t7xx_early_port_conf[] = {
> +	{
> +		.tx_ch = PORT_CH_ID_UNIMPORTANT,
> +		.rx_ch = PORT_CH_ID_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 +226,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 +351,30 @@ static void t7xx_proxy_setup_ch_mapping(struct port_proxy *port_prox)
>  	}
>  }
>  
> +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(port->port_conf->rxq_index != queue->index)) {

WARN_ON_ONCE would seem enough to alert to this problem and not as spammy?

> +		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 +405,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;
> @@ -451,26 +497,47 @@ static void t7xx_proxy_init_all_ports(struct t7xx_modem *md)
>  	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)
>  {
> +	u32 early_port_count = ARRAY_SIZE(t7xx_early_port_conf);
>  	unsigned int port_count = ARRAY_SIZE(t7xx_port_conf);

Why these are of different types?

>  	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,
> -				 GFP_KERNEL);
> +	port_count = max_t(u32, port_count, early_port_count);

If vars are using same type, you could do just max()

> +	port_prox = devm_kzalloc(dev, struct_size(port_prox, ports, port_count), GFP_KERNEL);

include <linux/overflow.h> missing?

This opencoding -> struct_size() seems independent change, no? If so, it 
should be in a separate patch. (It's a good change still and should be 
done.)

>  	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 +559,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;
>  }
>  
> diff --git a/drivers/net/wwan/t7xx/t7xx_port_proxy.h b/drivers/net/wwan/t7xx/t7xx_port_proxy.h
> index 81d059fbc0fb..0f3fb53259b7 100644
> --- a/drivers/net/wwan/t7xx/t7xx_port_proxy.h
> +++ b/drivers/net/wwan/t7xx/t7xx_port_proxy.h
> @@ -31,12 +31,19 @@
>  #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;
> -	struct t7xx_port	ports[];
> +	enum port_cfg_id	cfg_id;
> +	struct t7xx_port        ports[];

Spurious space change.

>  };
>  
>  struct ccci_header {
> @@ -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 24bd21942403..33fa8c22598a 100644
> --- a/drivers/net/wwan/t7xx/t7xx_port_wwan.c
> +++ b/drivers/net/wwan/t7xx/t7xx_port_wwan.c
> @@ -54,7 +54,7 @@ static void t7xx_port_ctrl_stop(struct wwan_port *port)
>  static int t7xx_port_ctrl_tx(struct wwan_port *port, struct sk_buff *skb)
>  {
>  	struct t7xx_port *port_private = wwan_port_get_drvdata(port);
> -	size_t len, offset, chunk_len = 0, txq_mtu = CLDMA_MTU;
> +	size_t len, offset, chunk_len = 0, txq_mtu;
>  	const struct t7xx_port_conf *port_conf;
>  	struct t7xx_fsm_ctl *ctl;
>  	enum md_state md_state;
> @@ -72,6 +72,7 @@ static int t7xx_port_ctrl_tx(struct wwan_port *port, struct sk_buff *skb)
>  		return -ENODEV;
>  	}
>  
> +	txq_mtu = t7xx_get_port_mtu(port_private);
>  	for (offset = 0; offset < len; offset += chunk_len) {
>  		struct sk_buff *skb_ccci;
>  		int ret;
> diff --git a/drivers/net/wwan/t7xx/t7xx_reg.h b/drivers/net/wwan/t7xx/t7xx_reg.h
> index c41d7d094c08..3b665c6116fe 100644
> --- a/drivers/net/wwan/t7xx/t7xx_reg.h
> +++ b/drivers/net/wwan/t7xx/t7xx_reg.h
> @@ -102,10 +102,26 @@ enum t7xx_pm_resume_state {
>  };
>  
>  #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)
> +
> +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,
> +};
> +
> +#define MISC_STAGE_MASK				GENMASK(2, 0)
> +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 80edb8e75a6a..6e957d3c0490 100644
> --- a/drivers/net/wwan/t7xx/t7xx_state_monitor.c
> +++ b/drivers/net/wwan/t7xx/t7xx_state_monitor.c
> @@ -206,6 +206,34 @@ static void fsm_routine_exception(struct t7xx_fsm_ctl *ctl, struct t7xx_fsm_comm
>  		fsm_finish_command(ctl, cmd, 0);
>  }
>  
> +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:
> +		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);
> +		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;
> @@ -317,7 +345,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)
> @@ -329,23 +358,56 @@ 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 = 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);
> +
>  	if (ret) {
> -		struct device *dev = &md->t7xx_dev->pdev->dev;
> +		ret = -ETIMEDOUT;

Is this necessary? Can read_poll_timeout() return anything else than 
-ETIMEDOUT??

> +		dev_err(dev, "read poll %d\n", ret);

read poll timeout ?

> +		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->prev_status) {
> +		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_info(dev, "BROM_STAGE Entered\n");

Somewhat questionable if info level is really desirable for these?

> +			ret = t7xx_fsm_append_cmd(ctl, FSM_CMD_START, 0);
> +			break;
> +
> +		case T7XX_DEV_STAGE_LK:
> +			dev_info(dev, "LK_STAGE Entered\n");
> +			t7xx_lk_stage_event_handling(ctl, status);
> +			break;
> +
> +		case T7XX_DEV_STAGE_LINUX:
> +			dev_info(dev, "LINUX_STAGE Entered\n");
> +			t7xx_cldma_hif_hw_init(md->md_ctrl[CLDMA_ID_AP]);
> +			t7xx_cldma_hif_hw_init(md->md_ctrl[CLDMA_ID_MD]);
> +			t7xx_mhccif_mask_clr(md->t7xx_dev, D2H_INT_PORT_ENUM |
> +					     D2H_INT_ASYNC_MD_HK | D2H_INT_ASYNC_AP_HK);
> +			t7xx_port_proxy_set_cfg(md, PORT_CFG_ID_NORMAL);
> +			ret = fsm_routine_starting(ctl);
> +			break;
> +
> +		default:
> +			break;
> +		}
> +		ctl->prev_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)
> @@ -516,6 +578,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->prev_status = 0;
>  }
>  
>  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 b6e76f3903c8..5e8012567ba1 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                     prev_status;
>  };
>  
>  struct t7xx_fsm_event {
>
Kumar, M Chetan Jan. 17, 2023, 5:44 a.m. UTC | #2
Hi Ilpo,
Thank you for the feedback.


On 1/16/2023 6:26 PM, Ilpo Järvinen wrote:
> On Mon, 16 Jan 2023, m.chetan.kumar@linux.intel.com wrote:
> 
>> From: M Chetan Kumar <m.chetan.kumar@linux.intel.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.
> 
> This doesn't go into details why CLDMA_MTU -> CLDMA_SHARED_Q_BUFF_SZ
> rename was done (if it wouldn't have been in the same change at all, I
> could have immediately seen that, ah, it was just moving code around but
> now I had to go to check if the defines yield same values).
> 
>> Signed-off-by: Haijun Liu <haijun.liu@mediatek.com>
>> Co-developed-by: Madhusmita Sahu <madhusmita.sahu@intel.com>
>> Signed-off-by: Madhusmita Sahu <madhusmita.sahu@intel.com>
>> Signed-off-by: Ricardo Martinez <ricardo.martinez@linux.intel.com>
>> Signed-off-by: Devegowda Chandrashekar <chandrashekar.devegowda@intel.com>
>> Signed-off-by: M Chetan Kumar <m.chetan.kumar@linux.intel.com>
>> --
>> v4:
>>   * Remove "this patch" in commit message.
>>   * MISC_DEV_STATUS_MASK & MISC_DEV_STATUS_INVALID is unused, drop it.
>>   * Drop unnecessary assignement for ret var inside fsm_routine_start.
>>   * cppcheck - reduce variableScope for stage var in fsm_routine_start.
>> v3:
>>   * No Change.
>> v2:
>>   * Move recv_skb handler to cldma_queue.
>>   * Drop cldma_queue_type.
>>   * Restore prototype of t7xx_port_send_raw_skb().
>>   * Remove PORT_CFG_ID_INVALID check in t7xx_port_proxy_set_cfg().
>>   * Add space before */.
>>   * Drop unnecessary logs.
>>   * Use WARN_ON on early port.
>>   * Use new MISC_DEV_STATUS_INVALID instead of MISC_DEV_STATUS.
>>   * Use macros instead of const identifiers.
>>   * Change ports member type from pointer to array type.
>>   * Prefix LK_EVENT_XX with MISC prefix.
>>   * Use t7xx prefix for device_stage enums.
>>   * Correct log messages.
>>   * Dont override pkt_size for non-download port under dedicated Queue.
>>   * Drop cldma_txq_rxq_ids.
>>   * Use macro for txq/rxq index.
>>   * Use warn_on for rxq_idx comparison.
>>   * Drop t7xx_port_proxy_get_port_by_name().
>>   * Replace fsm poll with read_poll_timeout().
>>   * Use "\n" consistently across log message.
>>   * Remove local var _dev prefixes in fsm_routine_start().
>>   * Use max_t.
>> ---
>>   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_port.h          |  4 +
>>   drivers/net/wwan/t7xx/t7xx_port_proxy.c    | 89 +++++++++++++++++++---
>>   drivers/net/wwan/t7xx/t7xx_port_proxy.h    | 12 ++-
>>   drivers/net/wwan/t7xx/t7xx_port_wwan.c     |  3 +-
>>   drivers/net/wwan/t7xx/t7xx_reg.h           | 22 +++++-
>>   drivers/net/wwan/t7xx/t7xx_state_monitor.c | 85 ++++++++++++++++++---
>>   drivers/net/wwan/t7xx/t7xx_state_monitor.h |  1 +
>>   10 files changed, 235 insertions(+), 50 deletions(-)
>>
>> diff --git a/drivers/net/wwan/t7xx/t7xx_hif_cldma.c b/drivers/net/wwan/t7xx/t7xx_hif_cldma.c
>> index 4f56d8cc0aea..12c9e9cba74a 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;
>> @@ -1331,9 +1347,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..5453cfecbe19 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 24e7d491468e..cbd65aa48721 100644
>> --- a/drivers/net/wwan/t7xx/t7xx_modem_ops.c
>> +++ b/drivers/net/wwan/t7xx/t7xx_modem_ops.c
>> @@ -529,7 +529,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;
>> @@ -544,7 +544,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_port.h b/drivers/net/wwan/t7xx/t7xx_port.h
>> index 4ae8a00a8532..09acb1ef144d 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_ID_UNIMPORTANT = 0xffff,
>>   };
>>   
>>   struct t7xx_port;
>> @@ -135,9 +137,11 @@ 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_raw_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_ctl_skb(struct t7xx_port *port, struct sk_buff *skb, unsigned int msg,
>> diff --git a/drivers/net/wwan/t7xx/t7xx_port_proxy.c b/drivers/net/wwan/t7xx/t7xx_port_proxy.c
>> index 274846d39fbf..b457e8da098e 100644
>> --- a/drivers/net/wwan/t7xx/t7xx_port_proxy.c
>> +++ b/drivers/net/wwan/t7xx/t7xx_port_proxy.c
>> @@ -100,6 +100,18 @@ static const struct t7xx_port_conf t7xx_port_conf[] = {
>>   	},
>>   };
>>   
>> +static struct t7xx_port_conf t7xx_early_port_conf[] = {
>> +	{
>> +		.tx_ch = PORT_CH_ID_UNIMPORTANT,
>> +		.rx_ch = PORT_CH_ID_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 +226,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 +351,30 @@ static void t7xx_proxy_setup_ch_mapping(struct port_proxy *port_prox)
>>   	}
>>   }
>>   
>> +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(port->port_conf->rxq_index != queue->index)) {
> 
> WARN_ON_ONCE would seem enough to alert to this problem and not as spammy?

Will change it to WARN_ON_ONCE.

> 
>> +		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 +405,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;
>> @@ -451,26 +497,47 @@ static void t7xx_proxy_init_all_ports(struct t7xx_modem *md)
>>   	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)
>>   {
>> +	u32 early_port_count = ARRAY_SIZE(t7xx_early_port_conf);
>>   	unsigned int port_count = ARRAY_SIZE(t7xx_port_conf);
> 
> Why these are of different types?

Will keep type of early_port_count same as port_count.

> 
>>   	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,
>> -				 GFP_KERNEL);
>> +	port_count = max_t(u32, port_count, early_port_count);
> 
> If vars are using same type, you could do just max()
> 
>> +	port_prox = devm_kzalloc(dev, struct_size(port_prox, ports, port_count), GFP_KERNEL);
> 
> include <linux/overflow.h> missing?
> 
> This opencoding -> struct_size() seems independent change, no? If so, it
> should be in a separate patch. (It's a good change still and should be
> done.)

Ya. this is an independent change.
I will drop it from this patch and push it as a seperate patch.

> 
>>   	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 +559,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;
>>   }
>>   
>> diff --git a/drivers/net/wwan/t7xx/t7xx_port_proxy.h b/drivers/net/wwan/t7xx/t7xx_port_proxy.h
>> index 81d059fbc0fb..0f3fb53259b7 100644
>> --- a/drivers/net/wwan/t7xx/t7xx_port_proxy.h
>> +++ b/drivers/net/wwan/t7xx/t7xx_port_proxy.h
>> @@ -31,12 +31,19 @@
>>   #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;
>> -	struct t7xx_port	ports[];
>> +	enum port_cfg_id	cfg_id;
>> +	struct t7xx_port        ports[];
> 
> Spurious space change.

Will check and fix it.

> 
>>   };
>>   
>>   struct ccci_header {
>> @@ -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 24bd21942403..33fa8c22598a 100644
>> --- a/drivers/net/wwan/t7xx/t7xx_port_wwan.c
>> +++ b/drivers/net/wwan/t7xx/t7xx_port_wwan.c
>> @@ -54,7 +54,7 @@ static void t7xx_port_ctrl_stop(struct wwan_port *port)
>>   static int t7xx_port_ctrl_tx(struct wwan_port *port, struct sk_buff *skb)
>>   {
>>   	struct t7xx_port *port_private = wwan_port_get_drvdata(port);
>> -	size_t len, offset, chunk_len = 0, txq_mtu = CLDMA_MTU;
>> +	size_t len, offset, chunk_len = 0, txq_mtu;
>>   	const struct t7xx_port_conf *port_conf;
>>   	struct t7xx_fsm_ctl *ctl;
>>   	enum md_state md_state;
>> @@ -72,6 +72,7 @@ static int t7xx_port_ctrl_tx(struct wwan_port *port, struct sk_buff *skb)
>>   		return -ENODEV;
>>   	}
>>   
>> +	txq_mtu = t7xx_get_port_mtu(port_private);
>>   	for (offset = 0; offset < len; offset += chunk_len) {
>>   		struct sk_buff *skb_ccci;
>>   		int ret;
>> diff --git a/drivers/net/wwan/t7xx/t7xx_reg.h b/drivers/net/wwan/t7xx/t7xx_reg.h
>> index c41d7d094c08..3b665c6116fe 100644
>> --- a/drivers/net/wwan/t7xx/t7xx_reg.h
>> +++ b/drivers/net/wwan/t7xx/t7xx_reg.h
>> @@ -102,10 +102,26 @@ enum t7xx_pm_resume_state {
>>   };
>>   
>>   #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)
>> +
>> +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,
>> +};
>> +
>> +#define MISC_STAGE_MASK				GENMASK(2, 0)
>> +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 80edb8e75a6a..6e957d3c0490 100644
>> --- a/drivers/net/wwan/t7xx/t7xx_state_monitor.c
>> +++ b/drivers/net/wwan/t7xx/t7xx_state_monitor.c
>> @@ -206,6 +206,34 @@ static void fsm_routine_exception(struct t7xx_fsm_ctl *ctl, struct t7xx_fsm_comm
>>   		fsm_finish_command(ctl, cmd, 0);
>>   }
>>   
>> +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:
>> +		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);
>> +		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;
>> @@ -317,7 +345,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)
>> @@ -329,23 +358,56 @@ 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 = 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);
>> +
>>   	if (ret) {
>> -		struct device *dev = &md->t7xx_dev->pdev->dev;
>> +		ret = -ETIMEDOUT;
> 
> Is this necessary? Can read_poll_timeout() return anything else than
> -ETIMEDOUT??

Not required will use return of read_poll_timeout().

> 
>> +		dev_err(dev, "read poll %d\n", ret);
> 
> read poll timeout ?

Will change it to "read poll timeout".

> 
>> +		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->prev_status) {
>> +		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_info(dev, "BROM_STAGE Entered\n");
> 
> Somewhat questionable if info level is really desirable for these?

Will change it dev_dbg.

> 
>> +			ret = t7xx_fsm_append_cmd(ctl, FSM_CMD_START, 0);
>> +			break;
>> +
>> +		case T7XX_DEV_STAGE_LK:
>> +			dev_info(dev, "LK_STAGE Entered\n");
>> +			t7xx_lk_stage_event_handling(ctl, status);
>> +			break;
>> +
>> +		case T7XX_DEV_STAGE_LINUX:
>> +			dev_info(dev, "LINUX_STAGE Entered\n");
>> +			t7xx_cldma_hif_hw_init(md->md_ctrl[CLDMA_ID_AP]);
>> +			t7xx_cldma_hif_hw_init(md->md_ctrl[CLDMA_ID_MD]);
>> +			t7xx_mhccif_mask_clr(md->t7xx_dev, D2H_INT_PORT_ENUM |
>> +					     D2H_INT_ASYNC_MD_HK | D2H_INT_ASYNC_AP_HK);
>> +			t7xx_port_proxy_set_cfg(md, PORT_CFG_ID_NORMAL);
>> +			ret = fsm_routine_starting(ctl);
>> +			break;
>> +
>> +		default:
>> +			break;
>> +		}
>> +		ctl->prev_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)
>> @@ -516,6 +578,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->prev_status = 0;
>>   }
>>   
>>   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 b6e76f3903c8..5e8012567ba1 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                     prev_status;
>>   };
>>   
>>   struct t7xx_fsm_event {
>>
>
diff mbox series

Patch

diff --git a/drivers/net/wwan/t7xx/t7xx_hif_cldma.c b/drivers/net/wwan/t7xx/t7xx_hif_cldma.c
index 4f56d8cc0aea..12c9e9cba74a 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;
@@ -1331,9 +1347,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..5453cfecbe19 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 24e7d491468e..cbd65aa48721 100644
--- a/drivers/net/wwan/t7xx/t7xx_modem_ops.c
+++ b/drivers/net/wwan/t7xx/t7xx_modem_ops.c
@@ -529,7 +529,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;
@@ -544,7 +544,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_port.h b/drivers/net/wwan/t7xx/t7xx_port.h
index 4ae8a00a8532..09acb1ef144d 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_ID_UNIMPORTANT = 0xffff,
 };
 
 struct t7xx_port;
@@ -135,9 +137,11 @@  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_raw_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_ctl_skb(struct t7xx_port *port, struct sk_buff *skb, unsigned int msg,
diff --git a/drivers/net/wwan/t7xx/t7xx_port_proxy.c b/drivers/net/wwan/t7xx/t7xx_port_proxy.c
index 274846d39fbf..b457e8da098e 100644
--- a/drivers/net/wwan/t7xx/t7xx_port_proxy.c
+++ b/drivers/net/wwan/t7xx/t7xx_port_proxy.c
@@ -100,6 +100,18 @@  static const struct t7xx_port_conf t7xx_port_conf[] = {
 	},
 };
 
+static struct t7xx_port_conf t7xx_early_port_conf[] = {
+	{
+		.tx_ch = PORT_CH_ID_UNIMPORTANT,
+		.rx_ch = PORT_CH_ID_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 +226,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 +351,30 @@  static void t7xx_proxy_setup_ch_mapping(struct port_proxy *port_prox)
 	}
 }
 
+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(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 +405,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;
@@ -451,26 +497,47 @@  static void t7xx_proxy_init_all_ports(struct t7xx_modem *md)
 	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)
 {
+	u32 early_port_count = ARRAY_SIZE(t7xx_early_port_conf);
 	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,
-				 GFP_KERNEL);
+	port_count = max_t(u32, port_count, early_port_count);
+	port_prox = devm_kzalloc(dev, struct_size(port_prox, ports, port_count), 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 +559,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;
 }
 
diff --git a/drivers/net/wwan/t7xx/t7xx_port_proxy.h b/drivers/net/wwan/t7xx/t7xx_port_proxy.h
index 81d059fbc0fb..0f3fb53259b7 100644
--- a/drivers/net/wwan/t7xx/t7xx_port_proxy.h
+++ b/drivers/net/wwan/t7xx/t7xx_port_proxy.h
@@ -31,12 +31,19 @@ 
 #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;
-	struct t7xx_port	ports[];
+	enum port_cfg_id	cfg_id;
+	struct t7xx_port        ports[];
 };
 
 struct ccci_header {
@@ -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 24bd21942403..33fa8c22598a 100644
--- a/drivers/net/wwan/t7xx/t7xx_port_wwan.c
+++ b/drivers/net/wwan/t7xx/t7xx_port_wwan.c
@@ -54,7 +54,7 @@  static void t7xx_port_ctrl_stop(struct wwan_port *port)
 static int t7xx_port_ctrl_tx(struct wwan_port *port, struct sk_buff *skb)
 {
 	struct t7xx_port *port_private = wwan_port_get_drvdata(port);
-	size_t len, offset, chunk_len = 0, txq_mtu = CLDMA_MTU;
+	size_t len, offset, chunk_len = 0, txq_mtu;
 	const struct t7xx_port_conf *port_conf;
 	struct t7xx_fsm_ctl *ctl;
 	enum md_state md_state;
@@ -72,6 +72,7 @@  static int t7xx_port_ctrl_tx(struct wwan_port *port, struct sk_buff *skb)
 		return -ENODEV;
 	}
 
+	txq_mtu = t7xx_get_port_mtu(port_private);
 	for (offset = 0; offset < len; offset += chunk_len) {
 		struct sk_buff *skb_ccci;
 		int ret;
diff --git a/drivers/net/wwan/t7xx/t7xx_reg.h b/drivers/net/wwan/t7xx/t7xx_reg.h
index c41d7d094c08..3b665c6116fe 100644
--- a/drivers/net/wwan/t7xx/t7xx_reg.h
+++ b/drivers/net/wwan/t7xx/t7xx_reg.h
@@ -102,10 +102,26 @@  enum t7xx_pm_resume_state {
 };
 
 #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)
+
+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,
+};
+
+#define MISC_STAGE_MASK				GENMASK(2, 0)
+
+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 80edb8e75a6a..6e957d3c0490 100644
--- a/drivers/net/wwan/t7xx/t7xx_state_monitor.c
+++ b/drivers/net/wwan/t7xx/t7xx_state_monitor.c
@@ -206,6 +206,34 @@  static void fsm_routine_exception(struct t7xx_fsm_ctl *ctl, struct t7xx_fsm_comm
 		fsm_finish_command(ctl, cmd, 0);
 }
 
+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:
+		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);
+		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;
@@ -317,7 +345,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)
@@ -329,23 +358,56 @@  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 = 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);
+
 	if (ret) {
-		struct device *dev = &md->t7xx_dev->pdev->dev;
+		ret = -ETIMEDOUT;
+		dev_err(dev, "read poll %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->prev_status) {
+		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_info(dev, "BROM_STAGE Entered\n");
+			ret = t7xx_fsm_append_cmd(ctl, FSM_CMD_START, 0);
+			break;
+
+		case T7XX_DEV_STAGE_LK:
+			dev_info(dev, "LK_STAGE Entered\n");
+			t7xx_lk_stage_event_handling(ctl, status);
+			break;
+
+		case T7XX_DEV_STAGE_LINUX:
+			dev_info(dev, "LINUX_STAGE Entered\n");
+			t7xx_cldma_hif_hw_init(md->md_ctrl[CLDMA_ID_AP]);
+			t7xx_cldma_hif_hw_init(md->md_ctrl[CLDMA_ID_MD]);
+			t7xx_mhccif_mask_clr(md->t7xx_dev, D2H_INT_PORT_ENUM |
+					     D2H_INT_ASYNC_MD_HK | D2H_INT_ASYNC_AP_HK);
+			t7xx_port_proxy_set_cfg(md, PORT_CFG_ID_NORMAL);
+			ret = fsm_routine_starting(ctl);
+			break;
+
+		default:
+			break;
+		}
+		ctl->prev_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)
@@ -516,6 +578,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->prev_status = 0;
 }
 
 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 b6e76f3903c8..5e8012567ba1 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                     prev_status;
 };
 
 struct t7xx_fsm_event {