1 /* Intel Ethernet Switch Host Interface Driver 2 * Copyright(c) 2013 - 2015 Intel Corporation. 3 * 4 * This program is free software; you can redistribute it and/or modify it 5 * under the terms and conditions of the GNU General Public License, 6 * version 2, as published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope it will be useful, but WITHOUT 9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 * more details. 12 * 13 * The full GNU General Public License is included in this distribution in 14 * the file called "COPYING". 15 * 16 * Contact Information: 17 * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> 18 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 19 */ 20 21 #ifdef CONFIG_DEBUG_FS 22 23 #include "fm10k.h" 24 25 #include <linux/debugfs.h> 26 #include <linux/seq_file.h> 27 28 static struct dentry *dbg_root; 29 30 /* Descriptor Seq Functions */ 31 32 static void *fm10k_dbg_desc_seq_start(struct seq_file *s, loff_t *pos) 33 { 34 struct fm10k_ring *ring = s->private; 35 36 return (*pos < ring->count) ? pos : NULL; 37 } 38 39 static void *fm10k_dbg_desc_seq_next(struct seq_file *s, 40 void __always_unused *v, 41 loff_t *pos) 42 { 43 struct fm10k_ring *ring = s->private; 44 45 return (++(*pos) < ring->count) ? pos : NULL; 46 } 47 48 static void fm10k_dbg_desc_seq_stop(struct seq_file __always_unused *s, 49 void __always_unused *v) 50 { 51 /* Do nothing. */ 52 } 53 54 static void fm10k_dbg_desc_break(struct seq_file *s, int i) 55 { 56 while (i--) 57 seq_puts(s, "-"); 58 59 seq_puts(s, "\n"); 60 } 61 62 static int fm10k_dbg_tx_desc_seq_show(struct seq_file *s, void *v) 63 { 64 struct fm10k_ring *ring = s->private; 65 int i = *(loff_t *)v; 66 static const char tx_desc_hdr[] = 67 "DES BUFFER_ADDRESS LENGTH VLAN MSS HDRLEN FLAGS\n"; 68 69 /* Generate header */ 70 if (!i) { 71 seq_printf(s, tx_desc_hdr); 72 fm10k_dbg_desc_break(s, sizeof(tx_desc_hdr) - 1); 73 } 74 75 /* Validate descriptor allocation */ 76 if (!ring->desc) { 77 seq_printf(s, "%03X Descriptor ring not allocated.\n", i); 78 } else { 79 struct fm10k_tx_desc *txd = FM10K_TX_DESC(ring, i); 80 81 seq_printf(s, "%03X %#018llx %#06x %#06x %#06x %#06x %#04x\n", 82 i, txd->buffer_addr, txd->buflen, txd->vlan, 83 txd->mss, txd->hdrlen, txd->flags); 84 } 85 86 return 0; 87 } 88 89 static int fm10k_dbg_rx_desc_seq_show(struct seq_file *s, void *v) 90 { 91 struct fm10k_ring *ring = s->private; 92 int i = *(loff_t *)v; 93 static const char rx_desc_hdr[] = 94 "DES DATA RSS STATERR LENGTH VLAN DGLORT SGLORT TIMESTAMP\n"; 95 96 /* Generate header */ 97 if (!i) { 98 seq_printf(s, rx_desc_hdr); 99 fm10k_dbg_desc_break(s, sizeof(rx_desc_hdr) - 1); 100 } 101 102 /* Validate descriptor allocation */ 103 if (!ring->desc) { 104 seq_printf(s, "%03X Descriptor ring not allocated.\n", i); 105 } else { 106 union fm10k_rx_desc *rxd = FM10K_RX_DESC(ring, i); 107 108 seq_printf(s, 109 "%03X %#010x %#010x %#010x %#06x %#06x %#06x %#06x %#018llx\n", 110 i, rxd->d.data, rxd->d.rss, rxd->d.staterr, 111 rxd->w.length, rxd->w.vlan, rxd->w.dglort, 112 rxd->w.sglort, rxd->q.timestamp); 113 } 114 115 return 0; 116 } 117 118 static const struct seq_operations fm10k_dbg_tx_desc_seq_ops = { 119 .start = fm10k_dbg_desc_seq_start, 120 .next = fm10k_dbg_desc_seq_next, 121 .stop = fm10k_dbg_desc_seq_stop, 122 .show = fm10k_dbg_tx_desc_seq_show, 123 }; 124 125 static const struct seq_operations fm10k_dbg_rx_desc_seq_ops = { 126 .start = fm10k_dbg_desc_seq_start, 127 .next = fm10k_dbg_desc_seq_next, 128 .stop = fm10k_dbg_desc_seq_stop, 129 .show = fm10k_dbg_rx_desc_seq_show, 130 }; 131 132 static int fm10k_dbg_desc_open(struct inode *inode, struct file *filep) 133 { 134 struct fm10k_ring *ring = inode->i_private; 135 struct fm10k_q_vector *q_vector = ring->q_vector; 136 const struct seq_operations *desc_seq_ops; 137 int err; 138 139 if (ring < q_vector->rx.ring) 140 desc_seq_ops = &fm10k_dbg_tx_desc_seq_ops; 141 else 142 desc_seq_ops = &fm10k_dbg_rx_desc_seq_ops; 143 144 err = seq_open(filep, desc_seq_ops); 145 if (err) 146 return err; 147 148 ((struct seq_file *)filep->private_data)->private = ring; 149 150 return 0; 151 } 152 153 static const struct file_operations fm10k_dbg_desc_fops = { 154 .owner = THIS_MODULE, 155 .open = fm10k_dbg_desc_open, 156 .read = seq_read, 157 .llseek = seq_lseek, 158 .release = seq_release, 159 }; 160 161 /** 162 * fm10k_dbg_q_vector_init - setup debugfs for the q_vectors 163 * @q_vector: q_vector to allocate directories for 164 * 165 * A folder is created for each q_vector found. In each q_vector 166 * folder, a debugfs file is created for each tx and rx ring 167 * allocated to the q_vector. 168 **/ 169 void fm10k_dbg_q_vector_init(struct fm10k_q_vector *q_vector) 170 { 171 struct fm10k_intfc *interface = q_vector->interface; 172 char name[16]; 173 int i; 174 175 if (!interface->dbg_intfc) 176 return; 177 178 /* Generate a folder for each q_vector */ 179 snprintf(name, sizeof(name), "q_vector.%03d", q_vector->v_idx); 180 181 q_vector->dbg_q_vector = debugfs_create_dir(name, interface->dbg_intfc); 182 if (!q_vector->dbg_q_vector) 183 return; 184 185 /* Generate a file for each rx ring in the q_vector */ 186 for (i = 0; i < q_vector->tx.count; i++) { 187 struct fm10k_ring *ring = &q_vector->tx.ring[i]; 188 189 snprintf(name, sizeof(name), "tx_ring.%03d", ring->queue_index); 190 191 debugfs_create_file(name, 0600, 192 q_vector->dbg_q_vector, ring, 193 &fm10k_dbg_desc_fops); 194 } 195 196 /* Generate a file for each rx ring in the q_vector */ 197 for (i = 0; i < q_vector->rx.count; i++) { 198 struct fm10k_ring *ring = &q_vector->rx.ring[i]; 199 200 snprintf(name, sizeof(name), "rx_ring.%03d", ring->queue_index); 201 202 debugfs_create_file(name, 0600, 203 q_vector->dbg_q_vector, ring, 204 &fm10k_dbg_desc_fops); 205 } 206 } 207 208 /** 209 * fm10k_dbg_free_q_vector_dir - setup debugfs for the q_vectors 210 * @q_vector: q_vector to allocate directories for 211 **/ 212 void fm10k_dbg_q_vector_exit(struct fm10k_q_vector *q_vector) 213 { 214 struct fm10k_intfc *interface = q_vector->interface; 215 216 if (interface->dbg_intfc) 217 debugfs_remove_recursive(q_vector->dbg_q_vector); 218 q_vector->dbg_q_vector = NULL; 219 } 220 221 /** 222 * fm10k_dbg_intfc_init - setup the debugfs directory for the intferface 223 * @interface: the interface that is starting up 224 **/ 225 226 void fm10k_dbg_intfc_init(struct fm10k_intfc *interface) 227 { 228 const char *name = pci_name(interface->pdev); 229 230 if (dbg_root) 231 interface->dbg_intfc = debugfs_create_dir(name, dbg_root); 232 } 233 234 /** 235 * fm10k_dbg_intfc_exit - clean out the interface's debugfs entries 236 * @interface: the interface that is stopping 237 **/ 238 void fm10k_dbg_intfc_exit(struct fm10k_intfc *interface) 239 { 240 if (dbg_root) 241 debugfs_remove_recursive(interface->dbg_intfc); 242 interface->dbg_intfc = NULL; 243 } 244 245 /** 246 * fm10k_dbg_init - start up debugfs for the driver 247 **/ 248 void fm10k_dbg_init(void) 249 { 250 dbg_root = debugfs_create_dir(fm10k_driver_name, NULL); 251 } 252 253 /** 254 * fm10k_dbg_exit - clean out the driver's debugfs entries 255 **/ 256 void fm10k_dbg_exit(void) 257 { 258 debugfs_remove_recursive(dbg_root); 259 dbg_root = NULL; 260 } 261 262 #endif /* CONFIG_DEBUG_FS */ 263