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

ufs-debugfs.c (6285B)


      1// SPDX-License-Identifier: GPL-2.0
      2// Copyright (C) 2020 Intel Corporation
      3
      4#include <linux/debugfs.h>
      5
      6#include "ufs-debugfs.h"
      7#include <ufs/ufshcd.h>
      8#include "ufshcd-priv.h"
      9
     10static struct dentry *ufs_debugfs_root;
     11
     12struct ufs_debugfs_attr {
     13	const char			*name;
     14	mode_t				mode;
     15	const struct file_operations	*fops;
     16};
     17
     18/* @file corresponds to a debugfs attribute in directory hba->debugfs_root. */
     19static inline struct ufs_hba *hba_from_file(const struct file *file)
     20{
     21	return d_inode(file->f_path.dentry->d_parent)->i_private;
     22}
     23
     24void __init ufs_debugfs_init(void)
     25{
     26	ufs_debugfs_root = debugfs_create_dir("ufshcd", NULL);
     27}
     28
     29void ufs_debugfs_exit(void)
     30{
     31	debugfs_remove_recursive(ufs_debugfs_root);
     32}
     33
     34static int ufs_debugfs_stats_show(struct seq_file *s, void *data)
     35{
     36	struct ufs_hba *hba = hba_from_file(s->file);
     37	struct ufs_event_hist *e = hba->ufs_stats.event;
     38
     39#define PRT(fmt, typ) \
     40	seq_printf(s, fmt, e[UFS_EVT_ ## typ].cnt)
     41
     42	PRT("PHY Adapter Layer errors (except LINERESET): %llu\n", PA_ERR);
     43	PRT("Data Link Layer errors: %llu\n", DL_ERR);
     44	PRT("Network Layer errors: %llu\n", NL_ERR);
     45	PRT("Transport Layer errors: %llu\n", TL_ERR);
     46	PRT("Generic DME errors: %llu\n", DME_ERR);
     47	PRT("Auto-hibernate errors: %llu\n", AUTO_HIBERN8_ERR);
     48	PRT("IS Fatal errors (CEFES, SBFES, HCFES, DFES): %llu\n", FATAL_ERR);
     49	PRT("DME Link Startup errors: %llu\n", LINK_STARTUP_FAIL);
     50	PRT("PM Resume errors: %llu\n", RESUME_ERR);
     51	PRT("PM Suspend errors : %llu\n", SUSPEND_ERR);
     52	PRT("Logical Unit Resets: %llu\n", DEV_RESET);
     53	PRT("Host Resets: %llu\n", HOST_RESET);
     54	PRT("SCSI command aborts: %llu\n", ABORT);
     55#undef PRT
     56	return 0;
     57}
     58DEFINE_SHOW_ATTRIBUTE(ufs_debugfs_stats);
     59
     60static int ee_usr_mask_get(void *data, u64 *val)
     61{
     62	struct ufs_hba *hba = data;
     63
     64	*val = hba->ee_usr_mask;
     65	return 0;
     66}
     67
     68static int ufs_debugfs_get_user_access(struct ufs_hba *hba)
     69__acquires(&hba->host_sem)
     70{
     71	down(&hba->host_sem);
     72	if (!ufshcd_is_user_access_allowed(hba)) {
     73		up(&hba->host_sem);
     74		return -EBUSY;
     75	}
     76	ufshcd_rpm_get_sync(hba);
     77	return 0;
     78}
     79
     80static void ufs_debugfs_put_user_access(struct ufs_hba *hba)
     81__releases(&hba->host_sem)
     82{
     83	ufshcd_rpm_put_sync(hba);
     84	up(&hba->host_sem);
     85}
     86
     87static int ee_usr_mask_set(void *data, u64 val)
     88{
     89	struct ufs_hba *hba = data;
     90	int err;
     91
     92	if (val & ~(u64)MASK_EE_STATUS)
     93		return -EINVAL;
     94	err = ufs_debugfs_get_user_access(hba);
     95	if (err)
     96		return err;
     97	err = ufshcd_update_ee_usr_mask(hba, val, MASK_EE_STATUS);
     98	ufs_debugfs_put_user_access(hba);
     99	return err;
    100}
    101
    102DEFINE_DEBUGFS_ATTRIBUTE(ee_usr_mask_fops, ee_usr_mask_get, ee_usr_mask_set, "%#llx\n");
    103
    104void ufs_debugfs_exception_event(struct ufs_hba *hba, u16 status)
    105{
    106	bool chgd = false;
    107	u16 ee_ctrl_mask;
    108	int err = 0;
    109
    110	if (!hba->debugfs_ee_rate_limit_ms || !status)
    111		return;
    112
    113	mutex_lock(&hba->ee_ctrl_mutex);
    114	ee_ctrl_mask = hba->ee_drv_mask | (hba->ee_usr_mask & ~status);
    115	chgd = ee_ctrl_mask != hba->ee_ctrl_mask;
    116	if (chgd) {
    117		err = __ufshcd_write_ee_control(hba, ee_ctrl_mask);
    118		if (err)
    119			dev_err(hba->dev, "%s: failed to write ee control %d\n",
    120				__func__, err);
    121	}
    122	mutex_unlock(&hba->ee_ctrl_mutex);
    123
    124	if (chgd && !err) {
    125		unsigned long delay = msecs_to_jiffies(hba->debugfs_ee_rate_limit_ms);
    126
    127		queue_delayed_work(system_freezable_wq, &hba->debugfs_ee_work, delay);
    128	}
    129}
    130
    131static void ufs_debugfs_restart_ee(struct work_struct *work)
    132{
    133	struct ufs_hba *hba = container_of(work, struct ufs_hba, debugfs_ee_work.work);
    134
    135	if (!hba->ee_usr_mask || pm_runtime_suspended(hba->dev) ||
    136	    ufs_debugfs_get_user_access(hba))
    137		return;
    138	ufshcd_write_ee_control(hba);
    139	ufs_debugfs_put_user_access(hba);
    140}
    141
    142static int ufs_saved_err_show(struct seq_file *s, void *data)
    143{
    144	struct ufs_debugfs_attr *attr = s->private;
    145	struct ufs_hba *hba = hba_from_file(s->file);
    146	const int *p;
    147
    148	if (strcmp(attr->name, "saved_err") == 0) {
    149		p = &hba->saved_err;
    150	} else if (strcmp(attr->name, "saved_uic_err") == 0) {
    151		p = &hba->saved_uic_err;
    152	} else {
    153		return -ENOENT;
    154	}
    155
    156	seq_printf(s, "%d\n", *p);
    157	return 0;
    158}
    159
    160static ssize_t ufs_saved_err_write(struct file *file, const char __user *buf,
    161				   size_t count, loff_t *ppos)
    162{
    163	struct ufs_debugfs_attr *attr = file->f_inode->i_private;
    164	struct ufs_hba *hba = hba_from_file(file);
    165	char val_str[16] = { };
    166	int val, ret;
    167
    168	if (count > sizeof(val_str))
    169		return -EINVAL;
    170	if (copy_from_user(val_str, buf, count))
    171		return -EFAULT;
    172	ret = kstrtoint(val_str, 0, &val);
    173	if (ret < 0)
    174		return ret;
    175
    176	spin_lock_irq(hba->host->host_lock);
    177	if (strcmp(attr->name, "saved_err") == 0) {
    178		hba->saved_err = val;
    179	} else if (strcmp(attr->name, "saved_uic_err") == 0) {
    180		hba->saved_uic_err = val;
    181	} else {
    182		ret = -ENOENT;
    183	}
    184	if (ret == 0)
    185		ufshcd_schedule_eh_work(hba);
    186	spin_unlock_irq(hba->host->host_lock);
    187
    188	return ret < 0 ? ret : count;
    189}
    190
    191static int ufs_saved_err_open(struct inode *inode, struct file *file)
    192{
    193	return single_open(file, ufs_saved_err_show, inode->i_private);
    194}
    195
    196static const struct file_operations ufs_saved_err_fops = {
    197	.owner		= THIS_MODULE,
    198	.open		= ufs_saved_err_open,
    199	.read		= seq_read,
    200	.write		= ufs_saved_err_write,
    201	.llseek		= seq_lseek,
    202	.release	= single_release,
    203};
    204
    205static const struct ufs_debugfs_attr ufs_attrs[] = {
    206	{ "stats", 0400, &ufs_debugfs_stats_fops },
    207	{ "saved_err", 0600, &ufs_saved_err_fops },
    208	{ "saved_uic_err", 0600, &ufs_saved_err_fops },
    209	{ }
    210};
    211
    212void ufs_debugfs_hba_init(struct ufs_hba *hba)
    213{
    214	const struct ufs_debugfs_attr *attr;
    215	struct dentry *root;
    216
    217	/* Set default exception event rate limit period to 20ms */
    218	hba->debugfs_ee_rate_limit_ms = 20;
    219	INIT_DELAYED_WORK(&hba->debugfs_ee_work, ufs_debugfs_restart_ee);
    220
    221	root = debugfs_create_dir(dev_name(hba->dev), ufs_debugfs_root);
    222	if (IS_ERR_OR_NULL(root))
    223		return;
    224	hba->debugfs_root = root;
    225	d_inode(root)->i_private = hba;
    226	for (attr = ufs_attrs; attr->name; attr++)
    227		debugfs_create_file(attr->name, attr->mode, root, (void *)attr,
    228				    attr->fops);
    229	debugfs_create_file("exception_event_mask", 0600, hba->debugfs_root,
    230			    hba, &ee_usr_mask_fops);
    231	debugfs_create_u32("exception_event_rate_limit_ms", 0600, hba->debugfs_root,
    232			   &hba->debugfs_ee_rate_limit_ms);
    233}
    234
    235void ufs_debugfs_hba_exit(struct ufs_hba *hba)
    236{
    237	debugfs_remove_recursive(hba->debugfs_root);
    238	cancel_delayed_work_sync(&hba->debugfs_ee_work);
    239}