kernel_samsung_a53x/drivers/soc/samsung/cpif/modem_dump.c
2024-06-15 16:02:09 -03:00

166 lines
3.8 KiB
C
Executable file

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2016 Samsung Electronics.
*
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <soc/samsung/shm_ipc.h>
#include "modem_prj.h"
#include "modem_utils.h"
#include "link_device_memory.h"
static int save_log_dump(struct io_device *iod, struct link_device *ld, u8 __iomem *base,
size_t size)
{
struct sk_buff *skb = NULL;
size_t alloc_size = 0xE00;
size_t copied = 0;
int ret = 0;
if (!base) {
mif_err("base is null\n");
return -EINVAL;
}
if (!size) {
mif_err("size is 0\n");
return -EINVAL;
}
while (copied < size) {
if (size - copied < alloc_size)
alloc_size = size - copied;
skb = alloc_skb(alloc_size, GFP_KERNEL);
if (!skb) {
skb_queue_purge(&iod->sk_rx_q);
mif_err("alloc_skb() error\n");
return -ENOMEM;
}
memcpy(skb_put(skb, alloc_size), base + copied, alloc_size);
copied += alloc_size;
skbpriv(skb)->iod = iod;
skbpriv(skb)->ld = ld;
skbpriv(skb)->lnk_hdr = false;
skbpriv(skb)->sipc_ch = iod->ch;
skbpriv(skb)->napi = NULL;
ret = iod->recv_skb_single(iod, ld, skb);
if (unlikely(ret < 0)) {
struct modem_ctl *mc = ld->mc;
mif_err_limited("%s: %s<-%s: %s->recv_skb fail (%d)\n",
ld->name, iod->name, mc->name, iod->name, ret);
dev_kfree_skb_any(skb);
return ret;
}
}
mif_info("Complete:%zu bytes\n", copied);
return 0;
}
int cp_get_log_dump(struct io_device *iod, struct link_device *ld, unsigned long arg)
{
struct mem_link_device *mld = to_mem_link_device(ld);
struct modem_data *modem = ld->mdm_data;
void __user *uarg = (void __user *)arg;
struct cp_log_dump log_dump;
u8 __iomem *base = NULL;
u32 size = 0;
int ret = 0;
u32 cp_num;
ret = copy_from_user(&log_dump, uarg, sizeof(log_dump));
if (ret) {
mif_err("copy_from_user() error:%d\n", ret);
return ret;
}
log_dump.name[sizeof(log_dump.name) - 1] = '\0';
mif_info("%s log name:%s index:%d\n", iod->name, log_dump.name, log_dump.idx);
cp_num = ld->mdm_data->cp_num;
switch (log_dump.idx) {
case LOG_IDX_SHMEM:
if (modem->legacy_raw_rx_buffer_cached) {
base = phys_to_virt(cp_shmem_get_base(cp_num, SHMEM_IPC));
size = cp_shmem_get_size(cp_num, SHMEM_IPC);
} else {
base = mld->base;
size = mld->size;
}
break;
case LOG_IDX_VSS:
base = mld->vss_base;
size = cp_shmem_get_size(cp_num, SHMEM_VSS);
break;
case LOG_IDX_ACPM:
base = mld->acpm_base;
size = mld->acpm_size;
break;
#if IS_ENABLED(CONFIG_CP_BTL)
case LOG_IDX_CP_BTL:
if (!ld->mdm_data->btl.enabled) {
mif_info("%s CP BTL is disabled\n", iod->name);
return -EPERM;
}
base = ld->mdm_data->btl.mem.v_base;
size = ld->mdm_data->btl.mem.size;
break;
#endif
case LOG_IDX_DATABUF:
base = phys_to_virt(cp_shmem_get_base(cp_num, SHMEM_PKTPROC));
#if IS_ENABLED(CONFIG_CP_PKTPROC_UL)
size = cp_shmem_get_size(cp_num, SHMEM_PKTPROC) +
cp_shmem_get_size(cp_num, SHMEM_PKTPROC_UL);
#else
size = cp_shmem_get_size(cp_num, SHMEM_PKTPROC);
#endif
break;
case LOG_IDX_L2B:
base = phys_to_virt(cp_shmem_get_base(cp_num, SHMEM_L2B));
size = cp_shmem_get_size(cp_num, SHMEM_L2B);
break;
case LOG_IDX_DDM:
base = phys_to_virt(cp_shmem_get_base(cp_num, SHMEM_DDM));
size = cp_shmem_get_size(cp_num, SHMEM_DDM);
break;
default:
mif_err("%s: invalid index:%d\n", iod->name, log_dump.idx);
return -EINVAL;
}
if (!base) {
mif_err("base is null for %s\n", log_dump.name);
return -EINVAL;
}
if (!size) {
mif_err("size is 0 for %s\n", log_dump.name);
return -EINVAL;
}
log_dump.size = size;
mif_info("%s log size:%d\n", iod->name, log_dump.size);
ret = copy_to_user(uarg, &log_dump, sizeof(log_dump));
if (ret) {
mif_err("copy_to_user() error:%d\n", ret);
return ret;
}
return save_log_dump(iod, ld, base, size);
}