1 /* Intel Ethernet Switch Host Interface Driver 2 * Copyright(c) 2013 - 2014 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, void *v, loff_t *pos) 40 { 41 struct fm10k_ring *ring = s->private; 42 43 return (++(*pos) < ring->count) ? pos : NULL; 44 } 45 46 static void fm10k_dbg_desc_seq_stop(struct seq_file *s, void *v) 47 { 48 /* Do nothing. */ 49 } 50 51 static void fm10k_dbg_desc_break(struct seq_file *s, int i) 52 { 53 while (i--) 54 seq_puts(s, "-"); 55 56 seq_puts(s, "\n"); 57 } 58 59 static int fm10k_dbg_tx_desc_seq_show(struct seq_file *s, void *v) 60 { 61 struct fm10k_ring *ring = s->private; 62 int i = *(loff_t *)v; 63 static const char tx_desc_hdr[] = 64 "DES BUFFER_ADDRESS LENGTH VLAN MSS HDRLEN FLAGS\n"; 65 66 /* Generate header */ 67 if (!i) { 68 seq_printf(s, tx_desc_hdr); 69 fm10k_dbg_desc_break(s, sizeof(tx_desc_hdr) - 1); 70 } 71 72 /* Validate descriptor allocation */ 73 if (!ring->desc) { 74 seq_printf(s, "%03X Descriptor ring not allocated.\n", i); 75 } else { 76 struct fm10k_tx_desc *txd = FM10K_TX_DESC(ring, i); 77 78 seq_printf(s, "%03X %#018llx %#06x %#06x %#06x %#06x %#04x\n", 79 i, txd->buffer_addr, txd->buflen, txd->vlan, 80 txd->mss, txd->hdrlen, txd->flags); 81 } 82 83 return 0; 84 } 85 86 static int fm10k_dbg_rx_desc_seq_show(struct seq_file *s, void *v) 87 { 88 struct fm10k_ring *ring = s->private; 89 int i = *(loff_t *)v; 90 static const char rx_desc_hdr[] = 91 "DES DATA RSS STATERR LENGTH VLAN DGLORT SGLORT TIMESTAMP\n"; 92 93 /* Generate header */ 94 if (!i) { 95 seq_printf(s, rx_desc_hdr); 96 fm10k_dbg_desc_break(s, sizeof(rx_desc_hdr) - 1); 97 } 98 99 /* Validate descriptor allocation */ 100 if (!ring->desc) { 101 seq_printf(s, "%03X Descriptor ring not allocated.\n", i); 102 } else { 103 union fm10k_rx_desc *rxd = FM10K_RX_DESC(ring, i); 104 105 seq_printf(s, 106 "%03X %#010x %#010x %#010x %#06x %#06x %#06x %#06x %#018llx\n", 107 i, rxd->d.data, rxd->d.rss, rxd->d.staterr, 108 rxd->w.length, rxd->w.vlan, rxd->w.dglort, 109 rxd->w.sglort, rxd->q.timestamp); 110 } 111 112 return 0; 113 } 114 115 static const struct seq_operations fm10k_dbg_tx_desc_seq_ops = { 116 .start = fm10k_dbg_desc_seq_start, 117 .next = fm10k_dbg_desc_seq_next, 118 .stop = fm10k_dbg_desc_seq_stop, 119 .show = fm10k_dbg_tx_desc_seq_show, 120 }; 121 122 static const struct seq_operations fm10k_dbg_rx_desc_seq_ops = { 123 .start = fm10k_dbg_desc_seq_start, 124 .next = fm10k_dbg_desc_seq_next, 125 .stop = fm10k_dbg_desc_seq_stop, 126 .show = fm10k_dbg_rx_desc_seq_show, 127 }; 128 129 static int fm10k_dbg_desc_open(struct inode *inode, struct file *filep) 130 { 131 struct fm10k_ring *ring = inode->i_private; 132 struct fm10k_q_vector *q_vector = ring->q_vector; 133 const struct seq_operations *desc_seq_ops; 134 int err; 135 136 if (ring < q_vector->rx.ring) 137 desc_seq_ops = &fm10k_dbg_tx_desc_seq_ops; 138 else 139 desc_seq_ops = &fm10k_dbg_rx_desc_seq_ops; 140 141 err = seq_open(filep, desc_seq_ops); 142 if (err) 143 return err; 144 145 ((struct seq_file *)filep->private_data)->private = ring; 146 147 return 0; 148 } 149 150 static const struct file_operations fm10k_dbg_desc_fops = { 151 .owner = THIS_MODULE, 152 .open = fm10k_dbg_desc_open, 153 .read = seq_read, 154 .llseek = seq_lseek, 155 .release = seq_release, 156 }; 157 158 /** 159 * fm10k_dbg_q_vector_init - setup debugfs for the q_vectors 160 * @q_vector: q_vector to allocate directories for 161 * 162 * A folder is created for each q_vector found. In each q_vector 163 * folder, a debugfs file is created for each tx and rx ring 164 * allocated to the q_vector. 165 **/ 166 void fm10k_dbg_q_vector_init(struct fm10k_q_vector *q_vector) 167 { 168 struct fm10k_intfc *interface = q_vector->interface; 169 char name[16]; 170 int i; 171 172 if (!interface->dbg_intfc) 173 return; 174 175 /* Generate a folder for each q_vector */ 176 sprintf(name, "q_vector.%03d", q_vector->v_idx); 177 178 q_vector->dbg_q_vector = debugfs_create_dir(name, interface->dbg_intfc); 179 if (!q_vector->dbg_q_vector) 180 return; 181 182 /* Generate a file for each rx ring in the q_vector */ 183 for (i = 0; i < q_vector->tx.count; i++) { 184 struct fm10k_ring *ring = &q_vector->tx.ring[i]; 185 186 sprintf(name, "tx_ring.%03d", ring->queue_index); 187 188 debugfs_create_file(name, 0600, 189 q_vector->dbg_q_vector, ring, 190 &fm10k_dbg_desc_fops); 191 } 192 193 /* Generate a file for each rx ring in the q_vector */ 194 for (i = 0; i < q_vector->rx.count; i++) { 195 struct fm10k_ring *ring = &q_vector->rx.ring[i]; 196 197 sprintf(name, "rx_ring.%03d", ring->queue_index); 198 199 debugfs_create_file(name, 0600, 200 q_vector->dbg_q_vector, ring, 201 &fm10k_dbg_desc_fops); 202 } 203 } 204 205 /** 206 * fm10k_dbg_free_q_vector_dir - setup debugfs for the q_vectors 207 * @q_vector: q_vector to allocate directories for 208 **/ 209 void fm10k_dbg_q_vector_exit(struct fm10k_q_vector *q_vector) 210 { 211 struct fm10k_intfc *interface = q_vector->interface; 212 213 if (interface->dbg_intfc) 214 debugfs_remove_recursive(q_vector->dbg_q_vector); 215 q_vector->dbg_q_vector = NULL; 216 } 217 218 /** 219 * fm10k_dbg_intfc_init - setup the debugfs directory for the intferface 220 * @interface: the interface that is starting up 221 **/ 222 223 void fm10k_dbg_intfc_init(struct fm10k_intfc *interface) 224 { 225 const char *name = pci_name(interface->pdev); 226 227 if (dbg_root) 228 interface->dbg_intfc = debugfs_create_dir(name, dbg_root); 229 } 230 231 /** 232 * fm10k_dbg_intfc_exit - clean out the interface's debugfs entries 233 * @interface: the interface that is stopping 234 **/ 235 void fm10k_dbg_intfc_exit(struct fm10k_intfc *interface) 236 { 237 if (dbg_root) 238 debugfs_remove_recursive(interface->dbg_intfc); 239 interface->dbg_intfc = NULL; 240 } 241 242 /** 243 * fm10k_dbg_init - start up debugfs for the driver 244 **/ 245 void fm10k_dbg_init(void) 246 { 247 dbg_root = debugfs_create_dir(fm10k_driver_name, NULL); 248 } 249 250 /** 251 * fm10k_dbg_exit - clean out the driver's debugfs entries 252 **/ 253 void fm10k_dbg_exit(void) 254 { 255 debugfs_remove_recursive(dbg_root); 256 dbg_root = NULL; 257 } 258 259 #endif /* CONFIG_DEBUG_FS */ 260