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

mtu3_debugfs.c (13796B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * mtu3_debugfs.c - debugfs interface
      4 *
      5 * Copyright (C) 2019 MediaTek Inc.
      6 *
      7 * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
      8 */
      9
     10#include <linux/uaccess.h>
     11
     12#include "mtu3.h"
     13#include "mtu3_dr.h"
     14#include "mtu3_debug.h"
     15
     16#define dump_register(nm)		\
     17{					\
     18	.name = __stringify(nm),	\
     19	.offset = U3D_ ##nm,		\
     20}
     21
     22#define dump_prb_reg(nm, os)	\
     23{				\
     24	.name = nm,		\
     25	.offset = os,		\
     26}
     27
     28static const struct debugfs_reg32 mtu3_ippc_regs[] = {
     29	dump_register(SSUSB_IP_PW_CTRL0),
     30	dump_register(SSUSB_IP_PW_CTRL1),
     31	dump_register(SSUSB_IP_PW_CTRL2),
     32	dump_register(SSUSB_IP_PW_CTRL3),
     33	dump_register(SSUSB_IP_PW_STS1),
     34	dump_register(SSUSB_OTG_STS),
     35	dump_register(SSUSB_IP_XHCI_CAP),
     36	dump_register(SSUSB_IP_DEV_CAP),
     37	dump_register(SSUSB_U3_CTRL_0P),
     38	dump_register(SSUSB_U2_CTRL_0P),
     39	dump_register(SSUSB_HW_ID),
     40	dump_register(SSUSB_HW_SUB_ID),
     41	dump_register(SSUSB_IP_SPARE0),
     42};
     43
     44static const struct debugfs_reg32 mtu3_dev_regs[] = {
     45	dump_register(LV1ISR),
     46	dump_register(LV1IER),
     47	dump_register(EPISR),
     48	dump_register(EPIER),
     49	dump_register(EP0CSR),
     50	dump_register(RXCOUNT0),
     51	dump_register(QISAR0),
     52	dump_register(QIER0),
     53	dump_register(QISAR1),
     54	dump_register(QIER1),
     55	dump_register(CAP_EPNTXFFSZ),
     56	dump_register(CAP_EPNRXFFSZ),
     57	dump_register(CAP_EPINFO),
     58	dump_register(MISC_CTRL),
     59};
     60
     61static const struct debugfs_reg32 mtu3_csr_regs[] = {
     62	dump_register(DEVICE_CONF),
     63	dump_register(DEV_LINK_INTR_ENABLE),
     64	dump_register(DEV_LINK_INTR),
     65	dump_register(LTSSM_CTRL),
     66	dump_register(USB3_CONFIG),
     67	dump_register(LINK_STATE_MACHINE),
     68	dump_register(LTSSM_INTR_ENABLE),
     69	dump_register(LTSSM_INTR),
     70	dump_register(U3U2_SWITCH_CTRL),
     71	dump_register(POWER_MANAGEMENT),
     72	dump_register(DEVICE_CONTROL),
     73	dump_register(COMMON_USB_INTR_ENABLE),
     74	dump_register(COMMON_USB_INTR),
     75	dump_register(USB20_MISC_CONTROL),
     76	dump_register(USB20_OPSTATE),
     77};
     78
     79static int mtu3_link_state_show(struct seq_file *sf, void *unused)
     80{
     81	struct mtu3 *mtu = sf->private;
     82	void __iomem *mbase = mtu->mac_base;
     83
     84	seq_printf(sf, "opstate: %#x, ltssm: %#x\n",
     85		   mtu3_readl(mbase, U3D_USB20_OPSTATE),
     86		   LTSSM_STATE(mtu3_readl(mbase, U3D_LINK_STATE_MACHINE)));
     87
     88	return 0;
     89}
     90
     91static int mtu3_ep_used_show(struct seq_file *sf, void *unused)
     92{
     93	struct mtu3 *mtu = sf->private;
     94	struct mtu3_ep *mep;
     95	unsigned long flags;
     96	int used = 0;
     97	int i;
     98
     99	spin_lock_irqsave(&mtu->lock, flags);
    100
    101	for (i = 0; i < mtu->num_eps; i++) {
    102		mep = mtu->in_eps + i;
    103		if (mep->flags & MTU3_EP_ENABLED) {
    104			seq_printf(sf, "%s - type: %d\n", mep->name, mep->type);
    105			used++;
    106		}
    107
    108		mep = mtu->out_eps + i;
    109		if (mep->flags & MTU3_EP_ENABLED) {
    110			seq_printf(sf, "%s - type: %d\n", mep->name, mep->type);
    111			used++;
    112		}
    113	}
    114	seq_printf(sf, "total used: %d eps\n", used);
    115
    116	spin_unlock_irqrestore(&mtu->lock, flags);
    117
    118	return 0;
    119}
    120
    121DEFINE_SHOW_ATTRIBUTE(mtu3_link_state);
    122DEFINE_SHOW_ATTRIBUTE(mtu3_ep_used);
    123
    124static void mtu3_debugfs_regset(struct mtu3 *mtu, void __iomem *base,
    125				const struct debugfs_reg32 *regs, size_t nregs,
    126				const char *name, struct dentry *parent)
    127{
    128	struct debugfs_regset32 *regset;
    129	struct mtu3_regset *mregs;
    130
    131	mregs = devm_kzalloc(mtu->dev, sizeof(*mregs), GFP_KERNEL);
    132	if (!mregs)
    133		return;
    134
    135	sprintf(mregs->name, "%s", name);
    136	regset = &mregs->regset;
    137	regset->regs = regs;
    138	regset->nregs = nregs;
    139	regset->base = base;
    140
    141	debugfs_create_regset32(mregs->name, 0444, parent, regset);
    142}
    143
    144static void mtu3_debugfs_ep_regset(struct mtu3 *mtu, struct mtu3_ep *mep,
    145				   struct dentry *parent)
    146{
    147	struct debugfs_reg32 *regs;
    148	int epnum = mep->epnum;
    149	int in = mep->is_in;
    150
    151	regs = devm_kcalloc(mtu->dev, 7, sizeof(*regs), GFP_KERNEL);
    152	if (!regs)
    153		return;
    154
    155	regs[0].name = in ? "TCR0" : "RCR0";
    156	regs[0].offset = in ? MU3D_EP_TXCR0(epnum) : MU3D_EP_RXCR0(epnum);
    157	regs[1].name = in ? "TCR1" : "RCR1";
    158	regs[1].offset = in ? MU3D_EP_TXCR1(epnum) : MU3D_EP_RXCR1(epnum);
    159	regs[2].name = in ? "TCR2" : "RCR2";
    160	regs[2].offset = in ? MU3D_EP_TXCR2(epnum) : MU3D_EP_RXCR2(epnum);
    161	regs[3].name = in ? "TQHIAR" : "RQHIAR";
    162	regs[3].offset = in ? USB_QMU_TQHIAR(epnum) : USB_QMU_RQHIAR(epnum);
    163	regs[4].name = in ? "TQCSR" : "RQCSR";
    164	regs[4].offset = in ? USB_QMU_TQCSR(epnum) : USB_QMU_RQCSR(epnum);
    165	regs[5].name = in ? "TQSAR" : "RQSAR";
    166	regs[5].offset = in ? USB_QMU_TQSAR(epnum) : USB_QMU_RQSAR(epnum);
    167	regs[6].name = in ? "TQCPR" : "RQCPR";
    168	regs[6].offset = in ? USB_QMU_TQCPR(epnum) : USB_QMU_RQCPR(epnum);
    169
    170	mtu3_debugfs_regset(mtu, mtu->mac_base, regs, 7, "ep-regs", parent);
    171}
    172
    173static int mtu3_ep_info_show(struct seq_file *sf, void *unused)
    174{
    175	struct mtu3_ep *mep = sf->private;
    176	struct mtu3 *mtu = mep->mtu;
    177	unsigned long flags;
    178
    179	spin_lock_irqsave(&mtu->lock, flags);
    180	seq_printf(sf, "ep - type:%d, maxp:%d, slot:%d, flags:%x\n",
    181		   mep->type, mep->maxp, mep->slot, mep->flags);
    182	spin_unlock_irqrestore(&mtu->lock, flags);
    183
    184	return 0;
    185}
    186
    187static int mtu3_fifo_show(struct seq_file *sf, void *unused)
    188{
    189	struct mtu3_ep *mep = sf->private;
    190	struct mtu3 *mtu = mep->mtu;
    191	unsigned long flags;
    192
    193	spin_lock_irqsave(&mtu->lock, flags);
    194	seq_printf(sf, "fifo - seg_size:%d, addr:%d, size:%d\n",
    195		   mep->fifo_seg_size, mep->fifo_addr, mep->fifo_size);
    196	spin_unlock_irqrestore(&mtu->lock, flags);
    197
    198	return 0;
    199}
    200
    201static int mtu3_qmu_ring_show(struct seq_file *sf, void *unused)
    202{
    203	struct mtu3_ep *mep = sf->private;
    204	struct mtu3 *mtu = mep->mtu;
    205	struct mtu3_gpd_ring *ring;
    206	unsigned long flags;
    207
    208	ring = &mep->gpd_ring;
    209	spin_lock_irqsave(&mtu->lock, flags);
    210	seq_printf(sf,
    211		   "qmu-ring - dma:%pad, start:%p, end:%p, enq:%p, dep:%p\n",
    212		   &ring->dma, ring->start, ring->end,
    213		   ring->enqueue, ring->dequeue);
    214	spin_unlock_irqrestore(&mtu->lock, flags);
    215
    216	return 0;
    217}
    218
    219static int mtu3_qmu_gpd_show(struct seq_file *sf, void *unused)
    220{
    221	struct mtu3_ep *mep = sf->private;
    222	struct mtu3 *mtu = mep->mtu;
    223	struct mtu3_gpd_ring *ring;
    224	struct qmu_gpd *gpd;
    225	dma_addr_t dma;
    226	unsigned long flags;
    227	int i;
    228
    229	spin_lock_irqsave(&mtu->lock, flags);
    230	ring = &mep->gpd_ring;
    231	gpd = ring->start;
    232	if (!gpd || !(mep->flags & MTU3_EP_ENABLED)) {
    233		seq_puts(sf, "empty!\n");
    234		goto out;
    235	}
    236
    237	for (i = 0; i < MAX_GPD_NUM; i++, gpd++) {
    238		dma = ring->dma + i * sizeof(*gpd);
    239		seq_printf(sf, "gpd.%03d -> %pad, %p: %08x %08x %08x %08x\n",
    240			   i, &dma, gpd, gpd->dw0_info, gpd->next_gpd,
    241			   gpd->buffer, gpd->dw3_info);
    242	}
    243
    244out:
    245	spin_unlock_irqrestore(&mtu->lock, flags);
    246
    247	return 0;
    248}
    249
    250static const struct mtu3_file_map mtu3_ep_files[] = {
    251	{"ep-info", mtu3_ep_info_show, },
    252	{"fifo", mtu3_fifo_show, },
    253	{"qmu-ring", mtu3_qmu_ring_show, },
    254	{"qmu-gpd", mtu3_qmu_gpd_show, },
    255};
    256
    257static int mtu3_ep_open(struct inode *inode, struct file *file)
    258{
    259	const char *file_name = file_dentry(file)->d_iname;
    260	const struct mtu3_file_map *f_map;
    261	int i;
    262
    263	for (i = 0; i < ARRAY_SIZE(mtu3_ep_files); i++) {
    264		f_map = &mtu3_ep_files[i];
    265
    266		if (strcmp(f_map->name, file_name) == 0)
    267			break;
    268	}
    269
    270	return single_open(file, f_map->show, inode->i_private);
    271}
    272
    273static const struct file_operations mtu3_ep_fops = {
    274	.open = mtu3_ep_open,
    275	.read = seq_read,
    276	.llseek = seq_lseek,
    277	.release = single_release,
    278};
    279
    280static const struct debugfs_reg32 mtu3_prb_regs[] = {
    281	dump_prb_reg("enable", U3D_SSUSB_PRB_CTRL0),
    282	dump_prb_reg("byte-sell", U3D_SSUSB_PRB_CTRL1),
    283	dump_prb_reg("byte-selh", U3D_SSUSB_PRB_CTRL2),
    284	dump_prb_reg("module-sel", U3D_SSUSB_PRB_CTRL3),
    285	dump_prb_reg("sw-out", U3D_SSUSB_PRB_CTRL4),
    286	dump_prb_reg("data", U3D_SSUSB_PRB_CTRL5),
    287};
    288
    289static int mtu3_probe_show(struct seq_file *sf, void *unused)
    290{
    291	const char *file_name = file_dentry(sf->file)->d_iname;
    292	struct mtu3 *mtu = sf->private;
    293	const struct debugfs_reg32 *regs;
    294	int i;
    295
    296	for (i = 0; i < ARRAY_SIZE(mtu3_prb_regs); i++) {
    297		regs = &mtu3_prb_regs[i];
    298
    299		if (strcmp(regs->name, file_name) == 0)
    300			break;
    301	}
    302
    303	seq_printf(sf, "0x%04x - 0x%08x\n", (u32)regs->offset,
    304		   mtu3_readl(mtu->ippc_base, (u32)regs->offset));
    305
    306	return 0;
    307}
    308
    309static int mtu3_probe_open(struct inode *inode, struct file *file)
    310{
    311	return single_open(file, mtu3_probe_show, inode->i_private);
    312}
    313
    314static ssize_t mtu3_probe_write(struct file *file, const char __user *ubuf,
    315				size_t count, loff_t *ppos)
    316{
    317	const char *file_name = file_dentry(file)->d_iname;
    318	struct seq_file *sf = file->private_data;
    319	struct mtu3 *mtu = sf->private;
    320	const struct debugfs_reg32 *regs;
    321	char buf[32];
    322	u32 val;
    323	int i;
    324
    325	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
    326		return -EFAULT;
    327
    328	if (kstrtou32(buf, 0, &val))
    329		return -EINVAL;
    330
    331	for (i = 0; i < ARRAY_SIZE(mtu3_prb_regs); i++) {
    332		regs = &mtu3_prb_regs[i];
    333
    334		if (strcmp(regs->name, file_name) == 0)
    335			break;
    336	}
    337	mtu3_writel(mtu->ippc_base, (u32)regs->offset, val);
    338
    339	return count;
    340}
    341
    342static const struct file_operations mtu3_probe_fops = {
    343	.open = mtu3_probe_open,
    344	.write = mtu3_probe_write,
    345	.read = seq_read,
    346	.llseek = seq_lseek,
    347	.release = single_release,
    348};
    349
    350static void mtu3_debugfs_create_prb_files(struct mtu3 *mtu)
    351{
    352	struct ssusb_mtk *ssusb = mtu->ssusb;
    353	const struct debugfs_reg32 *regs;
    354	struct dentry *dir_prb;
    355	int i;
    356
    357	dir_prb = debugfs_create_dir("probe", ssusb->dbgfs_root);
    358
    359	for (i = 0; i < ARRAY_SIZE(mtu3_prb_regs); i++) {
    360		regs = &mtu3_prb_regs[i];
    361		debugfs_create_file(regs->name, 0644, dir_prb,
    362				    mtu, &mtu3_probe_fops);
    363	}
    364
    365	mtu3_debugfs_regset(mtu, mtu->ippc_base, mtu3_prb_regs,
    366			    ARRAY_SIZE(mtu3_prb_regs), "regs", dir_prb);
    367}
    368
    369static void mtu3_debugfs_create_ep_dir(struct mtu3_ep *mep,
    370				       struct dentry *parent)
    371{
    372	const struct mtu3_file_map *files;
    373	struct dentry *dir_ep;
    374	int i;
    375
    376	dir_ep = debugfs_create_dir(mep->name, parent);
    377	mtu3_debugfs_ep_regset(mep->mtu, mep, dir_ep);
    378
    379	for (i = 0; i < ARRAY_SIZE(mtu3_ep_files); i++) {
    380		files = &mtu3_ep_files[i];
    381
    382		debugfs_create_file(files->name, 0444, dir_ep,
    383				    mep, &mtu3_ep_fops);
    384	}
    385}
    386
    387static void mtu3_debugfs_create_ep_dirs(struct mtu3 *mtu)
    388{
    389	struct ssusb_mtk *ssusb = mtu->ssusb;
    390	struct dentry *dir_eps;
    391	int i;
    392
    393	dir_eps = debugfs_create_dir("eps", ssusb->dbgfs_root);
    394
    395	for (i = 1; i < mtu->num_eps; i++) {
    396		mtu3_debugfs_create_ep_dir(mtu->in_eps + i, dir_eps);
    397		mtu3_debugfs_create_ep_dir(mtu->out_eps + i, dir_eps);
    398	}
    399}
    400
    401void ssusb_dev_debugfs_init(struct ssusb_mtk *ssusb)
    402{
    403	struct mtu3 *mtu = ssusb->u3d;
    404	struct dentry *dir_regs;
    405
    406	dir_regs = debugfs_create_dir("regs", ssusb->dbgfs_root);
    407
    408	mtu3_debugfs_regset(mtu, mtu->ippc_base,
    409			    mtu3_ippc_regs, ARRAY_SIZE(mtu3_ippc_regs),
    410			    "reg-ippc", dir_regs);
    411
    412	mtu3_debugfs_regset(mtu, mtu->mac_base,
    413			    mtu3_dev_regs, ARRAY_SIZE(mtu3_dev_regs),
    414			    "reg-dev", dir_regs);
    415
    416	mtu3_debugfs_regset(mtu, mtu->mac_base,
    417			    mtu3_csr_regs, ARRAY_SIZE(mtu3_csr_regs),
    418			    "reg-csr", dir_regs);
    419
    420	mtu3_debugfs_create_ep_dirs(mtu);
    421
    422	mtu3_debugfs_create_prb_files(mtu);
    423
    424	debugfs_create_file("link-state", 0444, ssusb->dbgfs_root,
    425			    mtu, &mtu3_link_state_fops);
    426	debugfs_create_file("ep-used", 0444, ssusb->dbgfs_root,
    427			    mtu, &mtu3_ep_used_fops);
    428}
    429
    430static int ssusb_mode_show(struct seq_file *sf, void *unused)
    431{
    432	struct ssusb_mtk *ssusb = sf->private;
    433
    434	seq_printf(sf, "current mode: %s(%s drd)\n(echo device/host)\n",
    435		   ssusb->is_host ? "host" : "device",
    436		   ssusb->otg_switch.manual_drd_enabled ? "manual" : "auto");
    437
    438	return 0;
    439}
    440
    441static int ssusb_mode_open(struct inode *inode, struct file *file)
    442{
    443	return single_open(file, ssusb_mode_show, inode->i_private);
    444}
    445
    446static ssize_t ssusb_mode_write(struct file *file, const char __user *ubuf,
    447				size_t count, loff_t *ppos)
    448{
    449	struct seq_file *sf = file->private_data;
    450	struct ssusb_mtk *ssusb = sf->private;
    451	char buf[16];
    452
    453	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
    454		return -EFAULT;
    455
    456	if (!strncmp(buf, "host", 4) && !ssusb->is_host) {
    457		ssusb_mode_switch(ssusb, 1);
    458	} else if (!strncmp(buf, "device", 6) && ssusb->is_host) {
    459		ssusb_mode_switch(ssusb, 0);
    460	} else {
    461		dev_err(ssusb->dev, "wrong or duplicated setting\n");
    462		return -EINVAL;
    463	}
    464
    465	return count;
    466}
    467
    468static const struct file_operations ssusb_mode_fops = {
    469	.open = ssusb_mode_open,
    470	.write = ssusb_mode_write,
    471	.read = seq_read,
    472	.llseek = seq_lseek,
    473	.release = single_release,
    474};
    475
    476static int ssusb_vbus_show(struct seq_file *sf, void *unused)
    477{
    478	struct ssusb_mtk *ssusb = sf->private;
    479	struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
    480
    481	seq_printf(sf, "vbus state: %s\n(echo on/off)\n",
    482		   regulator_is_enabled(otg_sx->vbus) ? "on" : "off");
    483
    484	return 0;
    485}
    486
    487static int ssusb_vbus_open(struct inode *inode, struct file *file)
    488{
    489	return single_open(file, ssusb_vbus_show, inode->i_private);
    490}
    491
    492static ssize_t ssusb_vbus_write(struct file *file, const char __user *ubuf,
    493				size_t count, loff_t *ppos)
    494{
    495	struct seq_file *sf = file->private_data;
    496	struct ssusb_mtk *ssusb = sf->private;
    497	struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
    498	char buf[16];
    499	bool enable;
    500
    501	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
    502		return -EFAULT;
    503
    504	if (kstrtobool(buf, &enable)) {
    505		dev_err(ssusb->dev, "wrong setting\n");
    506		return -EINVAL;
    507	}
    508
    509	ssusb_set_vbus(otg_sx, enable);
    510
    511	return count;
    512}
    513
    514static const struct file_operations ssusb_vbus_fops = {
    515	.open = ssusb_vbus_open,
    516	.write = ssusb_vbus_write,
    517	.read = seq_read,
    518	.llseek = seq_lseek,
    519	.release = single_release,
    520};
    521
    522void ssusb_dr_debugfs_init(struct ssusb_mtk *ssusb)
    523{
    524	struct dentry *root = ssusb->dbgfs_root;
    525
    526	debugfs_create_file("mode", 0644, root, ssusb, &ssusb_mode_fops);
    527	debugfs_create_file("vbus", 0644, root, ssusb, &ssusb_vbus_fops);
    528}
    529
    530void ssusb_debugfs_create_root(struct ssusb_mtk *ssusb)
    531{
    532	ssusb->dbgfs_root =
    533		debugfs_create_dir(dev_name(ssusb->dev), usb_debug_root);
    534}
    535
    536void ssusb_debugfs_remove_root(struct ssusb_mtk *ssusb)
    537{
    538	debugfs_remove_recursive(ssusb->dbgfs_root);
    539	ssusb->dbgfs_root = NULL;
    540}