cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

t7xx_port_proxy.c (13122B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (c) 2021, MediaTek Inc.
      4 * Copyright (c) 2021-2022, Intel Corporation.
      5 *
      6 * Authors:
      7 *  Amir Hanania <amir.hanania@intel.com>
      8 *  Haijun Liu <haijun.liu@mediatek.com>
      9 *  Moises Veleta <moises.veleta@intel.com>
     10 *  Ricardo Martinez <ricardo.martinez@linux.intel.com>
     11 *
     12 * Contributors:
     13 *  Andy Shevchenko <andriy.shevchenko@linux.intel.com>
     14 *  Chandrashekar Devegowda <chandrashekar.devegowda@intel.com>
     15 *  Chiranjeevi Rapolu <chiranjeevi.rapolu@intel.com>
     16 *  Eliot Lee <eliot.lee@intel.com>
     17 *  Sreehari Kancharla <sreehari.kancharla@intel.com>
     18 */
     19
     20#include <linux/bits.h>
     21#include <linux/bitfield.h>
     22#include <linux/device.h>
     23#include <linux/gfp.h>
     24#include <linux/kernel.h>
     25#include <linux/kthread.h>
     26#include <linux/list.h>
     27#include <linux/mutex.h>
     28#include <linux/netdevice.h>
     29#include <linux/skbuff.h>
     30#include <linux/spinlock.h>
     31#include <linux/wait.h>
     32#include <linux/wwan.h>
     33
     34#include "t7xx_hif_cldma.h"
     35#include "t7xx_modem_ops.h"
     36#include "t7xx_port.h"
     37#include "t7xx_port_proxy.h"
     38#include "t7xx_state_monitor.h"
     39
     40#define Q_IDX_CTRL			0
     41#define Q_IDX_MBIM			2
     42#define Q_IDX_AT_CMD			5
     43
     44#define INVALID_SEQ_NUM			GENMASK(15, 0)
     45
     46#define for_each_proxy_port(i, p, proxy)	\
     47	for (i = 0, (p) = &(proxy)->ports[i];	\
     48	     i < (proxy)->port_count;		\
     49	     i++, (p) = &(proxy)->ports[i])
     50
     51static const struct t7xx_port_conf t7xx_md_port_conf[] = {
     52	{
     53		.tx_ch = PORT_CH_UART2_TX,
     54		.rx_ch = PORT_CH_UART2_RX,
     55		.txq_index = Q_IDX_AT_CMD,
     56		.rxq_index = Q_IDX_AT_CMD,
     57		.txq_exp_index = 0xff,
     58		.rxq_exp_index = 0xff,
     59		.path_id = CLDMA_ID_MD,
     60		.ops = &wwan_sub_port_ops,
     61		.name = "AT",
     62		.port_type = WWAN_PORT_AT,
     63	}, {
     64		.tx_ch = PORT_CH_MBIM_TX,
     65		.rx_ch = PORT_CH_MBIM_RX,
     66		.txq_index = Q_IDX_MBIM,
     67		.rxq_index = Q_IDX_MBIM,
     68		.path_id = CLDMA_ID_MD,
     69		.ops = &wwan_sub_port_ops,
     70		.name = "MBIM",
     71		.port_type = WWAN_PORT_MBIM,
     72	}, {
     73		.tx_ch = PORT_CH_CONTROL_TX,
     74		.rx_ch = PORT_CH_CONTROL_RX,
     75		.txq_index = Q_IDX_CTRL,
     76		.rxq_index = Q_IDX_CTRL,
     77		.path_id = CLDMA_ID_MD,
     78		.ops = &ctl_port_ops,
     79		.name = "t7xx_ctrl",
     80	},
     81};
     82
     83static struct t7xx_port *t7xx_proxy_get_port_by_ch(struct port_proxy *port_prox, enum port_ch ch)
     84{
     85	const struct t7xx_port_conf *port_conf;
     86	struct t7xx_port *port;
     87	int i;
     88
     89	for_each_proxy_port(i, port, port_prox) {
     90		port_conf = port->port_conf;
     91		if (port_conf->rx_ch == ch || port_conf->tx_ch == ch)
     92			return port;
     93	}
     94
     95	return NULL;
     96}
     97
     98static u16 t7xx_port_next_rx_seq_num(struct t7xx_port *port, struct ccci_header *ccci_h)
     99{
    100	u32 status = le32_to_cpu(ccci_h->status);
    101	u16 seq_num, next_seq_num;
    102	bool assert_bit;
    103
    104	seq_num = FIELD_GET(CCCI_H_SEQ_FLD, status);
    105	next_seq_num = (seq_num + 1) & FIELD_MAX(CCCI_H_SEQ_FLD);
    106	assert_bit = status & CCCI_H_AST_BIT;
    107	if (!assert_bit || port->seq_nums[MTK_RX] == INVALID_SEQ_NUM)
    108		return next_seq_num;
    109
    110	if (seq_num != port->seq_nums[MTK_RX])
    111		dev_warn_ratelimited(port->dev,
    112				     "seq num out-of-order %u != %u (header %X, len %X)\n",
    113				     seq_num, port->seq_nums[MTK_RX],
    114				     le32_to_cpu(ccci_h->packet_header),
    115				     le32_to_cpu(ccci_h->packet_len));
    116
    117	return next_seq_num;
    118}
    119
    120void t7xx_port_proxy_reset(struct port_proxy *port_prox)
    121{
    122	struct t7xx_port *port;
    123	int i;
    124
    125	for_each_proxy_port(i, port, port_prox) {
    126		port->seq_nums[MTK_RX] = INVALID_SEQ_NUM;
    127		port->seq_nums[MTK_TX] = 0;
    128	}
    129}
    130
    131static int t7xx_port_get_queue_no(struct t7xx_port *port)
    132{
    133	const struct t7xx_port_conf *port_conf = port->port_conf;
    134	struct t7xx_fsm_ctl *ctl = port->t7xx_dev->md->fsm_ctl;
    135
    136	return t7xx_fsm_get_md_state(ctl) == MD_STATE_EXCEPTION ?
    137		port_conf->txq_exp_index : port_conf->txq_index;
    138}
    139
    140static void t7xx_port_struct_init(struct t7xx_port *port)
    141{
    142	INIT_LIST_HEAD(&port->entry);
    143	INIT_LIST_HEAD(&port->queue_entry);
    144	skb_queue_head_init(&port->rx_skb_list);
    145	init_waitqueue_head(&port->rx_wq);
    146	port->seq_nums[MTK_RX] = INVALID_SEQ_NUM;
    147	port->seq_nums[MTK_TX] = 0;
    148	atomic_set(&port->usage_cnt, 0);
    149}
    150
    151struct sk_buff *t7xx_port_alloc_skb(int payload)
    152{
    153	struct sk_buff *skb = __dev_alloc_skb(payload + sizeof(struct ccci_header), GFP_KERNEL);
    154
    155	if (skb)
    156		skb_reserve(skb, sizeof(struct ccci_header));
    157
    158	return skb;
    159}
    160
    161struct sk_buff *t7xx_ctrl_alloc_skb(int payload)
    162{
    163	struct sk_buff *skb = t7xx_port_alloc_skb(payload + sizeof(struct ctrl_msg_header));
    164
    165	if (skb)
    166		skb_reserve(skb, sizeof(struct ctrl_msg_header));
    167
    168	return skb;
    169}
    170
    171/**
    172 * t7xx_port_enqueue_skb() - Enqueue the received skb into the port's rx_skb_list.
    173 * @port: port context.
    174 * @skb: received skb.
    175 *
    176 * Return:
    177 * * 0		- Success.
    178 * * -ENOBUFS	- Not enough buffer space. Caller will try again later, skb is not consumed.
    179 */
    180int t7xx_port_enqueue_skb(struct t7xx_port *port, struct sk_buff *skb)
    181{
    182	unsigned long flags;
    183
    184	spin_lock_irqsave(&port->rx_wq.lock, flags);
    185	if (port->rx_skb_list.qlen >= port->rx_length_th) {
    186		spin_unlock_irqrestore(&port->rx_wq.lock, flags);
    187
    188		return -ENOBUFS;
    189	}
    190	__skb_queue_tail(&port->rx_skb_list, skb);
    191	spin_unlock_irqrestore(&port->rx_wq.lock, flags);
    192
    193	wake_up_all(&port->rx_wq);
    194	return 0;
    195}
    196
    197static int t7xx_port_send_raw_skb(struct t7xx_port *port, struct sk_buff *skb)
    198{
    199	enum cldma_id path_id = port->port_conf->path_id;
    200	struct cldma_ctrl *md_ctrl;
    201	int ret, tx_qno;
    202
    203	md_ctrl = port->t7xx_dev->md->md_ctrl[path_id];
    204	tx_qno = t7xx_port_get_queue_no(port);
    205	ret = t7xx_cldma_send_skb(md_ctrl, tx_qno, skb);
    206	if (ret)
    207		dev_err(port->dev, "Failed to send skb: %d\n", ret);
    208
    209	return ret;
    210}
    211
    212static int t7xx_port_send_ccci_skb(struct t7xx_port *port, struct sk_buff *skb,
    213				   unsigned int pkt_header, unsigned int ex_msg)
    214{
    215	const struct t7xx_port_conf *port_conf = port->port_conf;
    216	struct ccci_header *ccci_h;
    217	u32 status;
    218	int ret;
    219
    220	ccci_h = skb_push(skb, sizeof(*ccci_h));
    221	status = FIELD_PREP(CCCI_H_CHN_FLD, port_conf->tx_ch) |
    222		 FIELD_PREP(CCCI_H_SEQ_FLD, port->seq_nums[MTK_TX]) | CCCI_H_AST_BIT;
    223	ccci_h->status = cpu_to_le32(status);
    224	ccci_h->packet_header = cpu_to_le32(pkt_header);
    225	ccci_h->packet_len = cpu_to_le32(skb->len);
    226	ccci_h->ex_msg = cpu_to_le32(ex_msg);
    227
    228	ret = t7xx_port_send_raw_skb(port, skb);
    229	if (ret)
    230		return ret;
    231
    232	port->seq_nums[MTK_TX]++;
    233	return 0;
    234}
    235
    236int t7xx_port_send_ctl_skb(struct t7xx_port *port, struct sk_buff *skb, unsigned int msg,
    237			   unsigned int ex_msg)
    238{
    239	struct ctrl_msg_header *ctrl_msg_h;
    240	unsigned int msg_len = skb->len;
    241	u32 pkt_header = 0;
    242
    243	ctrl_msg_h = skb_push(skb, sizeof(*ctrl_msg_h));
    244	ctrl_msg_h->ctrl_msg_id = cpu_to_le32(msg);
    245	ctrl_msg_h->ex_msg = cpu_to_le32(ex_msg);
    246	ctrl_msg_h->data_length = cpu_to_le32(msg_len);
    247
    248	if (!msg_len)
    249		pkt_header = CCCI_HEADER_NO_DATA;
    250
    251	return t7xx_port_send_ccci_skb(port, skb, pkt_header, ex_msg);
    252}
    253
    254int t7xx_port_send_skb(struct t7xx_port *port, struct sk_buff *skb, unsigned int pkt_header,
    255		       unsigned int ex_msg)
    256{
    257	struct t7xx_fsm_ctl *ctl = port->t7xx_dev->md->fsm_ctl;
    258	unsigned int fsm_state;
    259
    260	fsm_state = t7xx_fsm_get_ctl_state(ctl);
    261	if (fsm_state != FSM_STATE_PRE_START) {
    262		const struct t7xx_port_conf *port_conf = port->port_conf;
    263		enum md_state md_state = t7xx_fsm_get_md_state(ctl);
    264
    265		switch (md_state) {
    266		case MD_STATE_EXCEPTION:
    267			if (port_conf->tx_ch != PORT_CH_MD_LOG_TX)
    268				return -EBUSY;
    269			break;
    270
    271		case MD_STATE_WAITING_FOR_HS1:
    272		case MD_STATE_WAITING_FOR_HS2:
    273		case MD_STATE_STOPPED:
    274		case MD_STATE_WAITING_TO_STOP:
    275		case MD_STATE_INVALID:
    276			return -ENODEV;
    277
    278		default:
    279			break;
    280		}
    281	}
    282
    283	return t7xx_port_send_ccci_skb(port, skb, pkt_header, ex_msg);
    284}
    285
    286static void t7xx_proxy_setup_ch_mapping(struct port_proxy *port_prox)
    287{
    288	struct t7xx_port *port;
    289
    290	int i, j;
    291
    292	for (i = 0; i < ARRAY_SIZE(port_prox->rx_ch_ports); i++)
    293		INIT_LIST_HEAD(&port_prox->rx_ch_ports[i]);
    294
    295	for (j = 0; j < ARRAY_SIZE(port_prox->queue_ports); j++) {
    296		for (i = 0; i < ARRAY_SIZE(port_prox->queue_ports[j]); i++)
    297			INIT_LIST_HEAD(&port_prox->queue_ports[j][i]);
    298	}
    299
    300	for_each_proxy_port(i, port, port_prox) {
    301		const struct t7xx_port_conf *port_conf = port->port_conf;
    302		enum cldma_id path_id = port_conf->path_id;
    303		u8 ch_id;
    304
    305		ch_id = FIELD_GET(PORT_CH_ID_MASK, port_conf->rx_ch);
    306		list_add_tail(&port->entry, &port_prox->rx_ch_ports[ch_id]);
    307		list_add_tail(&port->queue_entry,
    308			      &port_prox->queue_ports[path_id][port_conf->rxq_index]);
    309	}
    310}
    311
    312static struct t7xx_port *t7xx_port_proxy_find_port(struct t7xx_pci_dev *t7xx_dev,
    313						   struct cldma_queue *queue, u16 channel)
    314{
    315	struct port_proxy *port_prox = t7xx_dev->md->port_prox;
    316	struct list_head *port_list;
    317	struct t7xx_port *port;
    318	u8 ch_id;
    319
    320	ch_id = FIELD_GET(PORT_CH_ID_MASK, channel);
    321	port_list = &port_prox->rx_ch_ports[ch_id];
    322	list_for_each_entry(port, port_list, entry) {
    323		const struct t7xx_port_conf *port_conf = port->port_conf;
    324
    325		if (queue->md_ctrl->hif_id == port_conf->path_id &&
    326		    channel == port_conf->rx_ch)
    327			return port;
    328	}
    329
    330	return NULL;
    331}
    332
    333/**
    334 * t7xx_port_proxy_recv_skb() - Dispatch received skb.
    335 * @queue: CLDMA queue.
    336 * @skb: Socket buffer.
    337 *
    338 * Return:
    339 ** 0		- Packet consumed.
    340 ** -ERROR	- Failed to process skb.
    341 */
    342static int t7xx_port_proxy_recv_skb(struct cldma_queue *queue, struct sk_buff *skb)
    343{
    344	struct ccci_header *ccci_h = (struct ccci_header *)skb->data;
    345	struct t7xx_pci_dev *t7xx_dev = queue->md_ctrl->t7xx_dev;
    346	struct t7xx_fsm_ctl *ctl = t7xx_dev->md->fsm_ctl;
    347	struct device *dev = queue->md_ctrl->dev;
    348	const struct t7xx_port_conf *port_conf;
    349	struct t7xx_port *port;
    350	u16 seq_num, channel;
    351	int ret;
    352
    353	channel = FIELD_GET(CCCI_H_CHN_FLD, le32_to_cpu(ccci_h->status));
    354	if (t7xx_fsm_get_md_state(ctl) == MD_STATE_INVALID) {
    355		dev_err_ratelimited(dev, "Packet drop on channel 0x%x, modem not ready\n", channel);
    356		goto drop_skb;
    357	}
    358
    359	port = t7xx_port_proxy_find_port(t7xx_dev, queue, channel);
    360	if (!port) {
    361		dev_err_ratelimited(dev, "Packet drop on channel 0x%x, port not found\n", channel);
    362		goto drop_skb;
    363	}
    364
    365	seq_num = t7xx_port_next_rx_seq_num(port, ccci_h);
    366	port_conf = port->port_conf;
    367	skb_pull(skb, sizeof(*ccci_h));
    368
    369	ret = port_conf->ops->recv_skb(port, skb);
    370	/* Error indicates to try again later */
    371	if (ret) {
    372		skb_push(skb, sizeof(*ccci_h));
    373		return ret;
    374	}
    375
    376	port->seq_nums[MTK_RX] = seq_num;
    377	return 0;
    378
    379drop_skb:
    380	dev_kfree_skb_any(skb);
    381	return 0;
    382}
    383
    384/**
    385 * t7xx_port_proxy_md_status_notify() - Notify all ports of state.
    386 *@port_prox: The port_proxy pointer.
    387 *@state: State.
    388 *
    389 * Called by t7xx_fsm. Used to dispatch modem status for all ports,
    390 * which want to know MD state transition.
    391 */
    392void t7xx_port_proxy_md_status_notify(struct port_proxy *port_prox, unsigned int state)
    393{
    394	struct t7xx_port *port;
    395	int i;
    396
    397	for_each_proxy_port(i, port, port_prox) {
    398		const struct t7xx_port_conf *port_conf = port->port_conf;
    399
    400		if (port_conf->ops->md_state_notify)
    401			port_conf->ops->md_state_notify(port, state);
    402	}
    403}
    404
    405static void t7xx_proxy_init_all_ports(struct t7xx_modem *md)
    406{
    407	struct port_proxy *port_prox = md->port_prox;
    408	struct t7xx_port *port;
    409	int i;
    410
    411	for_each_proxy_port(i, port, port_prox) {
    412		const struct t7xx_port_conf *port_conf = port->port_conf;
    413
    414		t7xx_port_struct_init(port);
    415
    416		if (port_conf->tx_ch == PORT_CH_CONTROL_TX)
    417			md->core_md.ctl_port = port;
    418
    419		port->t7xx_dev = md->t7xx_dev;
    420		port->dev = &md->t7xx_dev->pdev->dev;
    421		spin_lock_init(&port->port_update_lock);
    422		port->chan_enable = false;
    423
    424		if (port_conf->ops->init)
    425			port_conf->ops->init(port);
    426	}
    427
    428	t7xx_proxy_setup_ch_mapping(port_prox);
    429}
    430
    431static int t7xx_proxy_alloc(struct t7xx_modem *md)
    432{
    433	unsigned int port_count = ARRAY_SIZE(t7xx_md_port_conf);
    434	struct device *dev = &md->t7xx_dev->pdev->dev;
    435	struct port_proxy *port_prox;
    436	int i;
    437
    438	port_prox = devm_kzalloc(dev, sizeof(*port_prox) + sizeof(struct t7xx_port) * port_count,
    439				 GFP_KERNEL);
    440	if (!port_prox)
    441		return -ENOMEM;
    442
    443	md->port_prox = port_prox;
    444	port_prox->dev = dev;
    445
    446	for (i = 0; i < port_count; i++)
    447		port_prox->ports[i].port_conf = &t7xx_md_port_conf[i];
    448
    449	port_prox->port_count = port_count;
    450	t7xx_proxy_init_all_ports(md);
    451	return 0;
    452}
    453
    454/**
    455 * t7xx_port_proxy_init() - Initialize ports.
    456 * @md: Modem.
    457 *
    458 * Create all port instances.
    459 *
    460 * Return:
    461 * * 0		- Success.
    462 * * -ERROR	- Error code from failure sub-initializations.
    463 */
    464int t7xx_port_proxy_init(struct t7xx_modem *md)
    465{
    466	int ret;
    467
    468	ret = t7xx_proxy_alloc(md);
    469	if (ret)
    470		return ret;
    471
    472	t7xx_cldma_set_recv_skb(md->md_ctrl[CLDMA_ID_MD], t7xx_port_proxy_recv_skb);
    473	return 0;
    474}
    475
    476void t7xx_port_proxy_uninit(struct port_proxy *port_prox)
    477{
    478	struct t7xx_port *port;
    479	int i;
    480
    481	for_each_proxy_port(i, port, port_prox) {
    482		const struct t7xx_port_conf *port_conf = port->port_conf;
    483
    484		if (port_conf->ops->uninit)
    485			port_conf->ops->uninit(port);
    486	}
    487}
    488
    489int t7xx_port_proxy_chl_enable_disable(struct port_proxy *port_prox, unsigned int ch_id,
    490				       bool en_flag)
    491{
    492	struct t7xx_port *port = t7xx_proxy_get_port_by_ch(port_prox, ch_id);
    493	const struct t7xx_port_conf *port_conf;
    494
    495	if (!port)
    496		return -EINVAL;
    497
    498	port_conf = port->port_conf;
    499
    500	if (en_flag) {
    501		if (port_conf->ops->enable_chl)
    502			port_conf->ops->enable_chl(port);
    503	} else {
    504		if (port_conf->ops->disable_chl)
    505			port_conf->ops->disable_chl(port);
    506	}
    507
    508	return 0;
    509}