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_wwan.c (4578B)


      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 *  Chandrashekar Devegowda <chandrashekar.devegowda@intel.com>
      9 *  Haijun Liu <haijun.liu@mediatek.com>
     10 *  Moises Veleta <moises.veleta@intel.com>
     11 *  Ricardo Martinez <ricardo.martinez@linux.intel.com>
     12 *
     13 * Contributors:
     14 *  Andy Shevchenko <andriy.shevchenko@linux.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/atomic.h>
     21#include <linux/bitfield.h>
     22#include <linux/dev_printk.h>
     23#include <linux/err.h>
     24#include <linux/gfp.h>
     25#include <linux/minmax.h>
     26#include <linux/netdevice.h>
     27#include <linux/skbuff.h>
     28#include <linux/spinlock.h>
     29#include <linux/string.h>
     30#include <linux/wwan.h>
     31
     32#include "t7xx_port.h"
     33#include "t7xx_port_proxy.h"
     34#include "t7xx_state_monitor.h"
     35
     36static int t7xx_port_ctrl_start(struct wwan_port *port)
     37{
     38	struct t7xx_port *port_mtk = wwan_port_get_drvdata(port);
     39
     40	if (atomic_read(&port_mtk->usage_cnt))
     41		return -EBUSY;
     42
     43	atomic_inc(&port_mtk->usage_cnt);
     44	return 0;
     45}
     46
     47static void t7xx_port_ctrl_stop(struct wwan_port *port)
     48{
     49	struct t7xx_port *port_mtk = wwan_port_get_drvdata(port);
     50
     51	atomic_dec(&port_mtk->usage_cnt);
     52}
     53
     54static int t7xx_port_ctrl_tx(struct wwan_port *port, struct sk_buff *skb)
     55{
     56	struct t7xx_port *port_private = wwan_port_get_drvdata(port);
     57	size_t len, offset, chunk_len = 0, txq_mtu = CLDMA_MTU;
     58	const struct t7xx_port_conf *port_conf;
     59	struct t7xx_fsm_ctl *ctl;
     60	enum md_state md_state;
     61
     62	len = skb->len;
     63	if (!len || !port_private->chan_enable)
     64		return -EINVAL;
     65
     66	port_conf = port_private->port_conf;
     67	ctl = port_private->t7xx_dev->md->fsm_ctl;
     68	md_state = t7xx_fsm_get_md_state(ctl);
     69	if (md_state == MD_STATE_WAITING_FOR_HS1 || md_state == MD_STATE_WAITING_FOR_HS2) {
     70		dev_warn(port_private->dev, "Cannot write to %s port when md_state=%d\n",
     71			 port_conf->name, md_state);
     72		return -ENODEV;
     73	}
     74
     75	for (offset = 0; offset < len; offset += chunk_len) {
     76		struct sk_buff *skb_ccci;
     77		int ret;
     78
     79		chunk_len = min(len - offset, txq_mtu - sizeof(struct ccci_header));
     80		skb_ccci = t7xx_port_alloc_skb(chunk_len);
     81		if (!skb_ccci)
     82			return -ENOMEM;
     83
     84		skb_put_data(skb_ccci, skb->data + offset, chunk_len);
     85		ret = t7xx_port_send_skb(port_private, skb_ccci, 0, 0);
     86		if (ret) {
     87			dev_kfree_skb_any(skb_ccci);
     88			dev_err(port_private->dev, "Write error on %s port, %d\n",
     89				port_conf->name, ret);
     90			return ret;
     91		}
     92	}
     93
     94	dev_kfree_skb(skb);
     95	return 0;
     96}
     97
     98static const struct wwan_port_ops wwan_ops = {
     99	.start = t7xx_port_ctrl_start,
    100	.stop = t7xx_port_ctrl_stop,
    101	.tx = t7xx_port_ctrl_tx,
    102};
    103
    104static int t7xx_port_wwan_init(struct t7xx_port *port)
    105{
    106	port->rx_length_th = RX_QUEUE_MAXLEN;
    107	return 0;
    108}
    109
    110static void t7xx_port_wwan_uninit(struct t7xx_port *port)
    111{
    112	if (!port->wwan_port)
    113		return;
    114
    115	port->rx_length_th = 0;
    116	wwan_remove_port(port->wwan_port);
    117	port->wwan_port = NULL;
    118}
    119
    120static int t7xx_port_wwan_recv_skb(struct t7xx_port *port, struct sk_buff *skb)
    121{
    122	if (!atomic_read(&port->usage_cnt) || !port->chan_enable) {
    123		const struct t7xx_port_conf *port_conf = port->port_conf;
    124
    125		dev_kfree_skb_any(skb);
    126		dev_err_ratelimited(port->dev, "Port %s is not opened, drop packets\n",
    127				    port_conf->name);
    128		/* Dropping skb, caller should not access skb.*/
    129		return 0;
    130	}
    131
    132	wwan_port_rx(port->wwan_port, skb);
    133	return 0;
    134}
    135
    136static int t7xx_port_wwan_enable_chl(struct t7xx_port *port)
    137{
    138	spin_lock(&port->port_update_lock);
    139	port->chan_enable = true;
    140	spin_unlock(&port->port_update_lock);
    141
    142	return 0;
    143}
    144
    145static int t7xx_port_wwan_disable_chl(struct t7xx_port *port)
    146{
    147	spin_lock(&port->port_update_lock);
    148	port->chan_enable = false;
    149	spin_unlock(&port->port_update_lock);
    150
    151	return 0;
    152}
    153
    154static void t7xx_port_wwan_md_state_notify(struct t7xx_port *port, unsigned int state)
    155{
    156	const struct t7xx_port_conf *port_conf = port->port_conf;
    157
    158	if (state != MD_STATE_READY)
    159		return;
    160
    161	if (!port->wwan_port) {
    162		port->wwan_port = wwan_create_port(port->dev, port_conf->port_type,
    163						   &wwan_ops, port);
    164		if (IS_ERR(port->wwan_port))
    165			dev_err(port->dev, "Unable to create WWWAN port %s", port_conf->name);
    166	}
    167}
    168
    169struct port_ops wwan_sub_port_ops = {
    170	.init = t7xx_port_wwan_init,
    171	.recv_skb = t7xx_port_wwan_recv_skb,
    172	.uninit = t7xx_port_wwan_uninit,
    173	.enable_chl = t7xx_port_wwan_enable_chl,
    174	.disable_chl = t7xx_port_wwan_disable_chl,
    175	.md_state_notify = t7xx_port_wwan_md_state_notify,
    176};