Commit 4ec3b4aa authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'wan-t7x-fastboot'



Jinjian Song says:

====================
net: wwan: t7xx: Add fastboot interface

Add support for t7xx WWAN device firmware flashing & coredump collection
using fastboot interface.

Using fastboot protocol command through /dev/wwan0fastboot0 WWAN port to
support firmware flashing and coredump collection, userspace get device
mode from /sys/bus/pci/devices/${bdf}/t7xx_mode.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 20ad4018 2dac6381
Loading
Loading
Loading
Loading
+46 −0
Original line number Diff line number Diff line
@@ -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:

- ``unknown`` represents that device in unknown status
- ``ready`` represents that device in ready status
- ``reset`` represents that device in reset status
- ``fastboot_switching`` represents that device in fastboot switching status
- ``fastboot_download`` represents that device in fastboot download status
- ``fastboot_dump`` 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_switching > /sys/bus/pci/devices/${bdf}/t7xx_mode

Management application development
==================================
The driver and userspace interfaces are described below. The MBIM protocol is
@@ -97,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_switching``
mode.

The MediaTek's T700 modem supports the 3GPP TS 27.007 [4] specification.

References
@@ -118,3 +160,7 @@ speak the Mobile Interface Broadband Model (MBIM) protocol"*
[4] *Specification # 27.007 - 3GPP*

- https://www.3gpp.org/DynaReport/27007.htm

[5] *fastboot "a mechanism for communicating with bootloaders"*

- https://android.googlesource.com/platform/system/core/+/refs/heads/main/fastboot/README.md
+32 −15
Original line number Diff line number Diff line
@@ -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);
}

+13 −5
Original line number Diff line number Diff line
@@ -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);
+11 −3
Original line number Diff line number Diff line
@@ -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;
@@ -529,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;
@@ -544,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);
@@ -758,6 +764,7 @@ int t7xx_md_init(struct t7xx_pci_dev *t7xx_dev)

void t7xx_md_exit(struct t7xx_pci_dev *t7xx_dev)
{
	enum t7xx_mode mode = READ_ONCE(t7xx_dev->mode);
	struct t7xx_modem *md = t7xx_dev->md;

	t7xx_pcie_mac_clear_int(t7xx_dev, SAP_RGU_INT);
@@ -765,6 +772,7 @@ void t7xx_md_exit(struct t7xx_pci_dev *t7xx_dev)
	if (!md->md_init_finish)
		return;

	if (mode != T7XX_RESET && mode != T7XX_UNKNOWN)
		t7xx_fsm_append_cmd(md->fsm_ctl, FSM_CMD_PRE_STOP, FSM_CMD_FLAG_WAIT_FOR_COMPLETION);
	t7xx_port_proxy_uninit(md->port_prox);
	t7xx_cldma_exit(md->md_ctrl[CLDMA_ID_AP]);
+1 −0
Original line number Diff line number Diff line
@@ -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__ */
Loading