mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-17 18:56:24 +00:00
36bd28c1cb
wwan_port_fops_write inputs the SKB parameter to the TX callback of the WWAN device driver. However, the WWAN device (e.g., t7xx) may have an MTU less than the size of SKB, causing the TX buffer to be sliced and copied once more in the WWAN device driver. This patch implements the slicing in the WWAN subsystem and gives the WWAN devices driver the option to slice(by frag_len) or not. By doing so, the additional memory copy is reduced. Meanwhile, this patch gives WWAN devices driver the option to reserve headroom in fragments for the device-specific metadata. Signed-off-by: haozhe chang <haozhe.chang@mediatek.com> Reviewed-by: Loic Poulain <loic.poulain@linaro.org> Link: https://lore.kernel.org/r/20230316095826.181904-1-haozhe.chang@mediatek.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
87 lines
2.0 KiB
C
87 lines
2.0 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Copyright (C) 2020-21 Intel Corporation.
|
|
*/
|
|
|
|
#include "iosm_ipc_chnl_cfg.h"
|
|
#include "iosm_ipc_imem_ops.h"
|
|
#include "iosm_ipc_port.h"
|
|
|
|
/* open logical channel for control communication */
|
|
static int ipc_port_ctrl_start(struct wwan_port *port)
|
|
{
|
|
struct iosm_cdev *ipc_port = wwan_port_get_drvdata(port);
|
|
int ret = 0;
|
|
|
|
ipc_port->channel = ipc_imem_sys_port_open(ipc_port->ipc_imem,
|
|
ipc_port->chl_id,
|
|
IPC_HP_CDEV_OPEN);
|
|
if (!ipc_port->channel)
|
|
ret = -EIO;
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* close logical channel */
|
|
static void ipc_port_ctrl_stop(struct wwan_port *port)
|
|
{
|
|
struct iosm_cdev *ipc_port = wwan_port_get_drvdata(port);
|
|
|
|
ipc_imem_sys_port_close(ipc_port->ipc_imem, ipc_port->channel);
|
|
}
|
|
|
|
/* transfer control data to modem */
|
|
static int ipc_port_ctrl_tx(struct wwan_port *port, struct sk_buff *skb)
|
|
{
|
|
struct iosm_cdev *ipc_port = wwan_port_get_drvdata(port);
|
|
|
|
return ipc_imem_sys_cdev_write(ipc_port, skb);
|
|
}
|
|
|
|
static const struct wwan_port_ops ipc_wwan_ctrl_ops = {
|
|
.start = ipc_port_ctrl_start,
|
|
.stop = ipc_port_ctrl_stop,
|
|
.tx = ipc_port_ctrl_tx,
|
|
};
|
|
|
|
/* Port init func */
|
|
struct iosm_cdev *ipc_port_init(struct iosm_imem *ipc_imem,
|
|
struct ipc_chnl_cfg ipc_port_cfg)
|
|
{
|
|
struct iosm_cdev *ipc_port = kzalloc(sizeof(*ipc_port), GFP_KERNEL);
|
|
enum wwan_port_type port_type = ipc_port_cfg.wwan_port_type;
|
|
enum ipc_channel_id chl_id = ipc_port_cfg.id;
|
|
|
|
if (!ipc_port)
|
|
return NULL;
|
|
|
|
ipc_port->dev = ipc_imem->dev;
|
|
ipc_port->pcie = ipc_imem->pcie;
|
|
|
|
ipc_port->port_type = port_type;
|
|
ipc_port->chl_id = chl_id;
|
|
ipc_port->ipc_imem = ipc_imem;
|
|
|
|
ipc_port->iosm_port = wwan_create_port(ipc_port->dev, port_type,
|
|
&ipc_wwan_ctrl_ops, NULL,
|
|
ipc_port);
|
|
|
|
return ipc_port;
|
|
}
|
|
|
|
/* Port deinit func */
|
|
void ipc_port_deinit(struct iosm_cdev *port[])
|
|
{
|
|
struct iosm_cdev *ipc_port;
|
|
u8 ctrl_chl_nr;
|
|
|
|
for (ctrl_chl_nr = 0; ctrl_chl_nr < IPC_MEM_MAX_CHANNELS;
|
|
ctrl_chl_nr++) {
|
|
if (port[ctrl_chl_nr]) {
|
|
ipc_port = port[ctrl_chl_nr];
|
|
wwan_remove_port(ipc_port->iosm_port);
|
|
kfree(ipc_port);
|
|
}
|
|
}
|
|
}
|