Blame view
drivers/fmc/fmc-debug.c
4.27 KB
81f7e3824 Initial Release, ... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 |
/* * Copyright (C) 2015 CERN (www.cern.ch) * Author: Federico Vaga <federico.vaga@cern.ch> * * Released according to the GNU GPL, version 2 or any later version. */ #include <linux/module.h> #include <linux/device.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/debugfs.h> #include <linux/seq_file.h> #include <asm/byteorder.h> #include <linux/fmc.h> #include <linux/sdb.h> #include <linux/fmc-sdb.h> #define FMC_DBG_SDB_DUMP "dump_sdb" static char *__strip_trailing_space(char *buf, char *str, int len) { int i = len - 1; memcpy(buf, str, len); buf[len] = '\0'; while (i >= 0 && buf[i] == ' ') buf[i--] = '\0'; return buf; } #define __sdb_string(buf, field) ({ \ BUILD_BUG_ON(sizeof(buf) < sizeof(field)); \ __strip_trailing_space(buf, (void *)(field), sizeof(field)); \ }) /** * We do not check seq_printf() errors because we want to see things in any case */ static void fmc_sdb_dump_recursive(struct fmc_device *fmc, struct seq_file *s, const struct sdb_array *arr) { unsigned long base = arr->baseaddr; int i, j, n = arr->len, level = arr->level; char tmp[64]; for (i = 0; i < n; i++) { union sdb_record *r; struct sdb_product *p; struct sdb_component *c; r = &arr->record[i]; c = &r->dev.sdb_component; p = &c->product; for (j = 0; j < level; j++) seq_printf(s, " "); switch (r->empty.record_type) { case sdb_type_interconnect: seq_printf(s, "%08llx:%08x %.19s ", __be64_to_cpu(p->vendor_id), __be32_to_cpu(p->device_id), p->name); break; case sdb_type_device: seq_printf(s, "%08llx:%08x %.19s (%08llx-%08llx) ", __be64_to_cpu(p->vendor_id), __be32_to_cpu(p->device_id), p->name, __be64_to_cpu(c->addr_first) + base, __be64_to_cpu(c->addr_last) + base); break; case sdb_type_bridge: seq_printf(s, "%08llx:%08x %.19s (bridge: %08llx) ", __be64_to_cpu(p->vendor_id), __be32_to_cpu(p->device_id), p->name, __be64_to_cpu(c->addr_first) + base); if (IS_ERR(arr->subtree[i])) { seq_printf(s, "SDB: (bridge error %li) ", PTR_ERR(arr->subtree[i])); break; } fmc_sdb_dump_recursive(fmc, s, arr->subtree[i]); break; case sdb_type_integration: seq_printf(s, "integration "); break; case sdb_type_repo_url: seq_printf(s, "Synthesis repository: %s ", __sdb_string(tmp, r->repo_url.repo_url)); break; case sdb_type_synthesis: seq_printf(s, "Bitstream '%s' ", __sdb_string(tmp, r->synthesis.syn_name)); seq_printf(s, "synthesized %08x by %s ", __be32_to_cpu(r->synthesis.date), __sdb_string(tmp, r->synthesis.user_name)); seq_printf(s, "(%s version %x), ", __sdb_string(tmp, r->synthesis.tool_name), __be32_to_cpu(r->synthesis.tool_version)); seq_printf(s, "commit %pm ", r->synthesis.commit_id); break; case sdb_type_empty: seq_printf(s, "empty "); break; default: seq_printf(s, "UNKNOWN TYPE 0x%02x ", r->empty.record_type); break; } } } static int fmc_sdb_dump(struct seq_file *s, void *offset) { struct fmc_device *fmc = s->private; if (!fmc->sdb) { seq_printf(s, "no SDB information "); return 0; } seq_printf(s, "FMC: %s (%s), slot %i, device %s ", dev_name(fmc->hwdev), fmc->carrier_name, fmc->slot_id, dev_name(&fmc->dev)); /* Dump SDB information */ fmc_sdb_dump_recursive(fmc, s, fmc->sdb); return 0; } static int fmc_sdb_dump_open(struct inode *inode, struct file *file) { struct fmc_device *fmc = inode->i_private; return single_open(file, fmc_sdb_dump, fmc); } const struct file_operations fmc_dbgfs_sdb_dump = { .owner = THIS_MODULE, .open = fmc_sdb_dump_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; int fmc_debug_init(struct fmc_device *fmc) { fmc->dbg_dir = debugfs_create_dir(dev_name(&fmc->dev), NULL); if (IS_ERR_OR_NULL(fmc->dbg_dir)) { pr_err("FMC: Cannot create debugfs "); return PTR_ERR(fmc->dbg_dir); } fmc->dbg_sdb_dump = debugfs_create_file(FMC_DBG_SDB_DUMP, 0444, fmc->dbg_dir, fmc, &fmc_dbgfs_sdb_dump); if (IS_ERR_OR_NULL(fmc->dbg_sdb_dump)) pr_err("FMC: Cannot create debugfs file %s ", FMC_DBG_SDB_DUMP); return 0; } void fmc_debug_exit(struct fmc_device *fmc) { if (fmc->dbg_dir) debugfs_remove_recursive(fmc->dbg_dir); } |