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

debug.c (9346B)


      1// SPDX-License-Identifier: GPL-2.0
      2#include <linux/kernel.h>
      3#include <linux/device.h>
      4#include <linux/types.h>
      5#include <linux/spinlock.h>
      6#include <linux/debugfs.h>
      7#include <linux/seq_file.h>
      8#include <linux/uaccess.h>
      9#include <linux/usb/ch9.h>
     10#include <linux/usb/gadget.h>
     11#include <linux/usb/phy.h>
     12#include <linux/usb/otg.h>
     13#include <linux/usb/otg-fsm.h>
     14#include <linux/usb/chipidea.h>
     15
     16#include "ci.h"
     17#include "udc.h"
     18#include "bits.h"
     19#include "otg.h"
     20
     21/*
     22 * ci_device_show: prints information about device capabilities and status
     23 */
     24static int ci_device_show(struct seq_file *s, void *data)
     25{
     26	struct ci_hdrc *ci = s->private;
     27	struct usb_gadget *gadget = &ci->gadget;
     28
     29	seq_printf(s, "speed             = %d\n", gadget->speed);
     30	seq_printf(s, "max_speed         = %d\n", gadget->max_speed);
     31	seq_printf(s, "is_otg            = %d\n", gadget->is_otg);
     32	seq_printf(s, "is_a_peripheral   = %d\n", gadget->is_a_peripheral);
     33	seq_printf(s, "b_hnp_enable      = %d\n", gadget->b_hnp_enable);
     34	seq_printf(s, "a_hnp_support     = %d\n", gadget->a_hnp_support);
     35	seq_printf(s, "a_alt_hnp_support = %d\n", gadget->a_alt_hnp_support);
     36	seq_printf(s, "name              = %s\n",
     37		   (gadget->name ? gadget->name : ""));
     38
     39	if (!ci->driver)
     40		return 0;
     41
     42	seq_printf(s, "gadget function   = %s\n",
     43		       (ci->driver->function ? ci->driver->function : ""));
     44	seq_printf(s, "gadget max speed  = %d\n", ci->driver->max_speed);
     45
     46	return 0;
     47}
     48DEFINE_SHOW_ATTRIBUTE(ci_device);
     49
     50/*
     51 * ci_port_test_show: reads port test mode
     52 */
     53static int ci_port_test_show(struct seq_file *s, void *data)
     54{
     55	struct ci_hdrc *ci = s->private;
     56	unsigned long flags;
     57	unsigned mode;
     58
     59	pm_runtime_get_sync(ci->dev);
     60	spin_lock_irqsave(&ci->lock, flags);
     61	mode = hw_port_test_get(ci);
     62	spin_unlock_irqrestore(&ci->lock, flags);
     63	pm_runtime_put_sync(ci->dev);
     64
     65	seq_printf(s, "mode = %u\n", mode);
     66
     67	return 0;
     68}
     69
     70/*
     71 * ci_port_test_write: writes port test mode
     72 */
     73static ssize_t ci_port_test_write(struct file *file, const char __user *ubuf,
     74				  size_t count, loff_t *ppos)
     75{
     76	struct seq_file *s = file->private_data;
     77	struct ci_hdrc *ci = s->private;
     78	unsigned long flags;
     79	unsigned mode;
     80	char buf[32];
     81	int ret;
     82
     83	count = min_t(size_t, sizeof(buf) - 1, count);
     84	if (copy_from_user(buf, ubuf, count))
     85		return -EFAULT;
     86
     87	/* sscanf requires a zero terminated string */
     88	buf[count] = '\0';
     89
     90	if (sscanf(buf, "%u", &mode) != 1)
     91		return -EINVAL;
     92
     93	if (mode > 255)
     94		return -EBADRQC;
     95
     96	pm_runtime_get_sync(ci->dev);
     97	spin_lock_irqsave(&ci->lock, flags);
     98	ret = hw_port_test_set(ci, mode);
     99	spin_unlock_irqrestore(&ci->lock, flags);
    100	pm_runtime_put_sync(ci->dev);
    101
    102	return ret ? ret : count;
    103}
    104
    105static int ci_port_test_open(struct inode *inode, struct file *file)
    106{
    107	return single_open(file, ci_port_test_show, inode->i_private);
    108}
    109
    110static const struct file_operations ci_port_test_fops = {
    111	.open		= ci_port_test_open,
    112	.write		= ci_port_test_write,
    113	.read		= seq_read,
    114	.llseek		= seq_lseek,
    115	.release	= single_release,
    116};
    117
    118/*
    119 * ci_qheads_show: DMA contents of all queue heads
    120 */
    121static int ci_qheads_show(struct seq_file *s, void *data)
    122{
    123	struct ci_hdrc *ci = s->private;
    124	unsigned long flags;
    125	unsigned i, j;
    126
    127	if (ci->role != CI_ROLE_GADGET) {
    128		seq_printf(s, "not in gadget mode\n");
    129		return 0;
    130	}
    131
    132	spin_lock_irqsave(&ci->lock, flags);
    133	for (i = 0; i < ci->hw_ep_max/2; i++) {
    134		struct ci_hw_ep *hweprx = &ci->ci_hw_ep[i];
    135		struct ci_hw_ep *hweptx =
    136			&ci->ci_hw_ep[i + ci->hw_ep_max/2];
    137		seq_printf(s, "EP=%02i: RX=%08X TX=%08X\n",
    138			   i, (u32)hweprx->qh.dma, (u32)hweptx->qh.dma);
    139		for (j = 0; j < (sizeof(struct ci_hw_qh)/sizeof(u32)); j++)
    140			seq_printf(s, " %04X:    %08X    %08X\n", j,
    141				   *((u32 *)hweprx->qh.ptr + j),
    142				   *((u32 *)hweptx->qh.ptr + j));
    143	}
    144	spin_unlock_irqrestore(&ci->lock, flags);
    145
    146	return 0;
    147}
    148DEFINE_SHOW_ATTRIBUTE(ci_qheads);
    149
    150/*
    151 * ci_requests_show: DMA contents of all requests currently queued (all endpts)
    152 */
    153static int ci_requests_show(struct seq_file *s, void *data)
    154{
    155	struct ci_hdrc *ci = s->private;
    156	unsigned long flags;
    157	struct ci_hw_req *req = NULL;
    158	struct td_node *node, *tmpnode;
    159	unsigned i, j, qsize = sizeof(struct ci_hw_td)/sizeof(u32);
    160
    161	if (ci->role != CI_ROLE_GADGET) {
    162		seq_printf(s, "not in gadget mode\n");
    163		return 0;
    164	}
    165
    166	spin_lock_irqsave(&ci->lock, flags);
    167	for (i = 0; i < ci->hw_ep_max; i++)
    168		list_for_each_entry(req, &ci->ci_hw_ep[i].qh.queue, queue) {
    169			list_for_each_entry_safe(node, tmpnode, &req->tds, td) {
    170				seq_printf(s, "EP=%02i: TD=%08X %s\n",
    171					   i % (ci->hw_ep_max / 2),
    172					   (u32)node->dma,
    173					   ((i < ci->hw_ep_max/2) ?
    174					   "RX" : "TX"));
    175
    176				for (j = 0; j < qsize; j++)
    177					seq_printf(s, " %04X:    %08X\n", j,
    178						   *((u32 *)node->ptr + j));
    179			}
    180		}
    181	spin_unlock_irqrestore(&ci->lock, flags);
    182
    183	return 0;
    184}
    185DEFINE_SHOW_ATTRIBUTE(ci_requests);
    186
    187static int ci_otg_show(struct seq_file *s, void *unused)
    188{
    189	struct ci_hdrc *ci = s->private;
    190	struct otg_fsm *fsm;
    191
    192	if (!ci || !ci_otg_is_fsm_mode(ci))
    193		return 0;
    194
    195	fsm = &ci->fsm;
    196
    197	/* ------ State ----- */
    198	seq_printf(s, "OTG state: %s\n\n",
    199			usb_otg_state_string(ci->otg.state));
    200
    201	/* ------ State Machine Variables ----- */
    202	seq_printf(s, "a_bus_drop: %d\n", fsm->a_bus_drop);
    203
    204	seq_printf(s, "a_bus_req: %d\n", fsm->a_bus_req);
    205
    206	seq_printf(s, "a_srp_det: %d\n", fsm->a_srp_det);
    207
    208	seq_printf(s, "a_vbus_vld: %d\n", fsm->a_vbus_vld);
    209
    210	seq_printf(s, "b_conn: %d\n", fsm->b_conn);
    211
    212	seq_printf(s, "adp_change: %d\n", fsm->adp_change);
    213
    214	seq_printf(s, "power_up: %d\n", fsm->power_up);
    215
    216	seq_printf(s, "a_bus_resume: %d\n", fsm->a_bus_resume);
    217
    218	seq_printf(s, "a_bus_suspend: %d\n", fsm->a_bus_suspend);
    219
    220	seq_printf(s, "a_conn: %d\n", fsm->a_conn);
    221
    222	seq_printf(s, "b_bus_req: %d\n", fsm->b_bus_req);
    223
    224	seq_printf(s, "b_bus_suspend: %d\n", fsm->b_bus_suspend);
    225
    226	seq_printf(s, "b_se0_srp: %d\n", fsm->b_se0_srp);
    227
    228	seq_printf(s, "b_ssend_srp: %d\n", fsm->b_ssend_srp);
    229
    230	seq_printf(s, "b_sess_vld: %d\n", fsm->b_sess_vld);
    231
    232	seq_printf(s, "b_srp_done: %d\n", fsm->b_srp_done);
    233
    234	seq_printf(s, "drv_vbus: %d\n", fsm->drv_vbus);
    235
    236	seq_printf(s, "loc_conn: %d\n", fsm->loc_conn);
    237
    238	seq_printf(s, "loc_sof: %d\n", fsm->loc_sof);
    239
    240	seq_printf(s, "adp_prb: %d\n", fsm->adp_prb);
    241
    242	seq_printf(s, "id: %d\n", fsm->id);
    243
    244	seq_printf(s, "protocol: %d\n", fsm->protocol);
    245
    246	return 0;
    247}
    248DEFINE_SHOW_ATTRIBUTE(ci_otg);
    249
    250static int ci_role_show(struct seq_file *s, void *data)
    251{
    252	struct ci_hdrc *ci = s->private;
    253
    254	if (ci->role != CI_ROLE_END)
    255		seq_printf(s, "%s\n", ci_role(ci)->name);
    256
    257	return 0;
    258}
    259
    260static ssize_t ci_role_write(struct file *file, const char __user *ubuf,
    261			     size_t count, loff_t *ppos)
    262{
    263	struct seq_file *s = file->private_data;
    264	struct ci_hdrc *ci = s->private;
    265	enum ci_role role;
    266	char buf[8];
    267	int ret;
    268
    269	if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
    270		return -EFAULT;
    271
    272	for (role = CI_ROLE_HOST; role < CI_ROLE_END; role++)
    273		if (ci->roles[role] &&
    274		    !strncmp(buf, ci->roles[role]->name,
    275			     strlen(ci->roles[role]->name)))
    276			break;
    277
    278	if (role == CI_ROLE_END || role == ci->role)
    279		return -EINVAL;
    280
    281	pm_runtime_get_sync(ci->dev);
    282	disable_irq(ci->irq);
    283	ci_role_stop(ci);
    284	ret = ci_role_start(ci, role);
    285	enable_irq(ci->irq);
    286	pm_runtime_put_sync(ci->dev);
    287
    288	return ret ? ret : count;
    289}
    290
    291static int ci_role_open(struct inode *inode, struct file *file)
    292{
    293	return single_open(file, ci_role_show, inode->i_private);
    294}
    295
    296static const struct file_operations ci_role_fops = {
    297	.open		= ci_role_open,
    298	.write		= ci_role_write,
    299	.read		= seq_read,
    300	.llseek		= seq_lseek,
    301	.release	= single_release,
    302};
    303
    304static int ci_registers_show(struct seq_file *s, void *unused)
    305{
    306	struct ci_hdrc *ci = s->private;
    307	u32 tmp_reg;
    308
    309	if (!ci || ci->in_lpm)
    310		return -EPERM;
    311
    312	/* ------ Registers ----- */
    313	tmp_reg = hw_read_intr_enable(ci);
    314	seq_printf(s, "USBINTR reg: %08x\n", tmp_reg);
    315
    316	tmp_reg = hw_read_intr_status(ci);
    317	seq_printf(s, "USBSTS reg: %08x\n", tmp_reg);
    318
    319	tmp_reg = hw_read(ci, OP_USBMODE, ~0);
    320	seq_printf(s, "USBMODE reg: %08x\n", tmp_reg);
    321
    322	tmp_reg = hw_read(ci, OP_USBCMD, ~0);
    323	seq_printf(s, "USBCMD reg: %08x\n", tmp_reg);
    324
    325	tmp_reg = hw_read(ci, OP_PORTSC, ~0);
    326	seq_printf(s, "PORTSC reg: %08x\n", tmp_reg);
    327
    328	if (ci->is_otg) {
    329		tmp_reg = hw_read_otgsc(ci, ~0);
    330		seq_printf(s, "OTGSC reg: %08x\n", tmp_reg);
    331	}
    332
    333	return 0;
    334}
    335DEFINE_SHOW_ATTRIBUTE(ci_registers);
    336
    337/**
    338 * dbg_create_files: initializes the attribute interface
    339 * @ci: device
    340 *
    341 * This function returns an error code
    342 */
    343void dbg_create_files(struct ci_hdrc *ci)
    344{
    345	struct dentry *dir;
    346
    347	dir = debugfs_create_dir(dev_name(ci->dev), usb_debug_root);
    348
    349	debugfs_create_file("device", S_IRUGO, dir, ci, &ci_device_fops);
    350	debugfs_create_file("port_test", S_IRUGO | S_IWUSR, dir, ci, &ci_port_test_fops);
    351	debugfs_create_file("qheads", S_IRUGO, dir, ci, &ci_qheads_fops);
    352	debugfs_create_file("requests", S_IRUGO, dir, ci, &ci_requests_fops);
    353
    354	if (ci_otg_is_fsm_mode(ci))
    355		debugfs_create_file("otg", S_IRUGO, dir, ci, &ci_otg_fops);
    356
    357	debugfs_create_file("role", S_IRUGO | S_IWUSR, dir, ci, &ci_role_fops);
    358	debugfs_create_file("registers", S_IRUGO, dir, ci, &ci_registers_fops);
    359}
    360
    361/**
    362 * dbg_remove_files: destroys the attribute interface
    363 * @ci: device
    364 */
    365void dbg_remove_files(struct ci_hdrc *ci)
    366{
    367	debugfs_remove(debugfs_lookup(dev_name(ci->dev), usb_debug_root));
    368}