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}