• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Intel MIC Platform Software Stack (MPSS)
3  *
4  * Copyright(c) 2013 Intel Corporation.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License, version 2, as
8  * published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * General Public License for more details.
14  *
15  * The full GNU General Public License is included in this distribution in
16  * the file called "COPYING".
17  *
18  * Intel MIC Host driver.
19  *
20  */
21 #include <linux/debugfs.h>
22 #include <linux/pci.h>
23 #include <linux/seq_file.h>
24 
25 #include <linux/mic_common.h>
26 #include "../common/mic_dev.h"
27 #include "mic_device.h"
28 #include "mic_smpt.h"
29 #include "mic_virtio.h"
30 
31 /* Debugfs parent dir */
32 static struct dentry *mic_dbg;
33 
mic_smpt_show(struct seq_file * s,void * pos)34 static int mic_smpt_show(struct seq_file *s, void *pos)
35 {
36 	int i;
37 	struct mic_device *mdev = s->private;
38 	unsigned long flags;
39 
40 	seq_printf(s, "MIC %-2d |%-10s| %-14s %-10s\n",
41 		   mdev->id, "SMPT entry", "SW DMA addr", "RefCount");
42 	seq_puts(s, "====================================================\n");
43 
44 	if (mdev->smpt) {
45 		struct mic_smpt_info *smpt_info = mdev->smpt;
46 		spin_lock_irqsave(&smpt_info->smpt_lock, flags);
47 		for (i = 0; i < smpt_info->info.num_reg; i++) {
48 			seq_printf(s, "%9s|%-10d| %-#14llx %-10lld\n",
49 				   " ",  i, smpt_info->entry[i].dma_addr,
50 				   smpt_info->entry[i].ref_count);
51 		}
52 		spin_unlock_irqrestore(&smpt_info->smpt_lock, flags);
53 	}
54 	seq_puts(s, "====================================================\n");
55 	return 0;
56 }
57 
mic_smpt_debug_open(struct inode * inode,struct file * file)58 static int mic_smpt_debug_open(struct inode *inode, struct file *file)
59 {
60 	return single_open(file, mic_smpt_show, inode->i_private);
61 }
62 
mic_smpt_debug_release(struct inode * inode,struct file * file)63 static int mic_smpt_debug_release(struct inode *inode, struct file *file)
64 {
65 	return single_release(inode, file);
66 }
67 
68 static const struct file_operations smpt_file_ops = {
69 	.owner   = THIS_MODULE,
70 	.open    = mic_smpt_debug_open,
71 	.read    = seq_read,
72 	.llseek  = seq_lseek,
73 	.release = mic_smpt_debug_release
74 };
75 
mic_post_code_show(struct seq_file * s,void * pos)76 static int mic_post_code_show(struct seq_file *s, void *pos)
77 {
78 	struct mic_device *mdev = s->private;
79 	u32 reg = mdev->ops->get_postcode(mdev);
80 
81 	seq_printf(s, "%c%c", reg & 0xff, (reg >> 8) & 0xff);
82 	return 0;
83 }
84 
mic_post_code_debug_open(struct inode * inode,struct file * file)85 static int mic_post_code_debug_open(struct inode *inode, struct file *file)
86 {
87 	return single_open(file, mic_post_code_show, inode->i_private);
88 }
89 
mic_post_code_debug_release(struct inode * inode,struct file * file)90 static int mic_post_code_debug_release(struct inode *inode, struct file *file)
91 {
92 	return single_release(inode, file);
93 }
94 
95 static const struct file_operations post_code_ops = {
96 	.owner   = THIS_MODULE,
97 	.open    = mic_post_code_debug_open,
98 	.read    = seq_read,
99 	.llseek  = seq_lseek,
100 	.release = mic_post_code_debug_release
101 };
102 
mic_dp_show(struct seq_file * s,void * pos)103 static int mic_dp_show(struct seq_file *s, void *pos)
104 {
105 	struct mic_device *mdev = s->private;
106 	struct mic_device_desc *d;
107 	struct mic_device_ctrl *dc;
108 	struct mic_vqconfig *vqconfig;
109 	__u32 *features;
110 	__u8 *config;
111 	struct mic_bootparam *bootparam = mdev->dp;
112 	int i, j;
113 
114 	seq_printf(s, "Bootparam: magic 0x%x\n",
115 		   bootparam->magic);
116 	seq_printf(s, "Bootparam: h2c_config_db %d\n",
117 		   bootparam->h2c_config_db);
118 	seq_printf(s, "Bootparam: node_id %d\n",
119 		   bootparam->node_id);
120 	seq_printf(s, "Bootparam: c2h_scif_db %d\n",
121 		   bootparam->c2h_scif_db);
122 	seq_printf(s, "Bootparam: h2c_scif_db %d\n",
123 		   bootparam->h2c_scif_db);
124 	seq_printf(s, "Bootparam: scif_host_dma_addr 0x%llx\n",
125 		   bootparam->scif_host_dma_addr);
126 	seq_printf(s, "Bootparam: scif_card_dma_addr 0x%llx\n",
127 		   bootparam->scif_card_dma_addr);
128 
129 
130 	for (i = sizeof(*bootparam); i < MIC_DP_SIZE;
131 	     i += mic_total_desc_size(d)) {
132 		d = mdev->dp + i;
133 		dc = (void *)d + mic_aligned_desc_size(d);
134 
135 		/* end of list */
136 		if (d->type == 0)
137 			break;
138 
139 		if (d->type == -1)
140 			continue;
141 
142 		seq_printf(s, "Type %d ", d->type);
143 		seq_printf(s, "Num VQ %d ", d->num_vq);
144 		seq_printf(s, "Feature Len %d\n", d->feature_len);
145 		seq_printf(s, "Config Len %d ", d->config_len);
146 		seq_printf(s, "Shutdown Status %d\n", d->status);
147 
148 		for (j = 0; j < d->num_vq; j++) {
149 			vqconfig = mic_vq_config(d) + j;
150 			seq_printf(s, "vqconfig[%d]: ", j);
151 			seq_printf(s, "address 0x%llx ", vqconfig->address);
152 			seq_printf(s, "num %d ", vqconfig->num);
153 			seq_printf(s, "used address 0x%llx\n",
154 				   vqconfig->used_address);
155 		}
156 
157 		features = (__u32 *)mic_vq_features(d);
158 		seq_printf(s, "Features: Host 0x%x ", features[0]);
159 		seq_printf(s, "Guest 0x%x\n", features[1]);
160 
161 		config = mic_vq_configspace(d);
162 		for (j = 0; j < d->config_len; j++)
163 			seq_printf(s, "config[%d]=%d\n", j, config[j]);
164 
165 		seq_puts(s, "Device control:\n");
166 		seq_printf(s, "Config Change %d ", dc->config_change);
167 		seq_printf(s, "Vdev reset %d\n", dc->vdev_reset);
168 		seq_printf(s, "Guest Ack %d ", dc->guest_ack);
169 		seq_printf(s, "Host ack %d\n", dc->host_ack);
170 		seq_printf(s, "Used address updated %d ",
171 			   dc->used_address_updated);
172 		seq_printf(s, "Vdev 0x%llx\n", dc->vdev);
173 		seq_printf(s, "c2h doorbell %d ", dc->c2h_vdev_db);
174 		seq_printf(s, "h2c doorbell %d\n", dc->h2c_vdev_db);
175 	}
176 
177 	return 0;
178 }
179 
mic_dp_debug_open(struct inode * inode,struct file * file)180 static int mic_dp_debug_open(struct inode *inode, struct file *file)
181 {
182 	return single_open(file, mic_dp_show, inode->i_private);
183 }
184 
mic_dp_debug_release(struct inode * inode,struct file * file)185 static int mic_dp_debug_release(struct inode *inode, struct file *file)
186 {
187 	return single_release(inode, file);
188 }
189 
190 static const struct file_operations dp_ops = {
191 	.owner   = THIS_MODULE,
192 	.open    = mic_dp_debug_open,
193 	.read    = seq_read,
194 	.llseek  = seq_lseek,
195 	.release = mic_dp_debug_release
196 };
197 
mic_vdev_info_show(struct seq_file * s,void * unused)198 static int mic_vdev_info_show(struct seq_file *s, void *unused)
199 {
200 	struct mic_device *mdev = s->private;
201 	struct list_head *pos, *tmp;
202 	struct mic_vdev *mvdev;
203 	int i, j;
204 
205 	mutex_lock(&mdev->mic_mutex);
206 	list_for_each_safe(pos, tmp, &mdev->vdev_list) {
207 		mvdev = list_entry(pos, struct mic_vdev, list);
208 		seq_printf(s, "VDEV type %d state %s in %ld out %ld\n",
209 			   mvdev->virtio_id,
210 			   mic_vdevup(mvdev) ? "UP" : "DOWN",
211 			   mvdev->in_bytes,
212 			   mvdev->out_bytes);
213 		for (i = 0; i < MIC_MAX_VRINGS; i++) {
214 			struct vring_desc *desc;
215 			struct vring_avail *avail;
216 			struct vring_used *used;
217 			struct mic_vringh *mvr = &mvdev->mvr[i];
218 			struct vringh *vrh = &mvr->vrh;
219 			int num = vrh->vring.num;
220 			if (!num)
221 				continue;
222 			desc = vrh->vring.desc;
223 			seq_printf(s, "vring i %d avail_idx %d",
224 				   i, mvr->vring.info->avail_idx & (num - 1));
225 			seq_printf(s, " vring i %d avail_idx %d\n",
226 				   i, mvr->vring.info->avail_idx);
227 			seq_printf(s, "vrh i %d weak_barriers %d",
228 				   i, vrh->weak_barriers);
229 			seq_printf(s, " last_avail_idx %d last_used_idx %d",
230 				   vrh->last_avail_idx, vrh->last_used_idx);
231 			seq_printf(s, " completed %d\n", vrh->completed);
232 			for (j = 0; j < num; j++) {
233 				seq_printf(s, "desc[%d] addr 0x%llx len %d",
234 					   j, desc->addr, desc->len);
235 				seq_printf(s, " flags 0x%x next %d\n",
236 					   desc->flags, desc->next);
237 				desc++;
238 			}
239 			avail = vrh->vring.avail;
240 			seq_printf(s, "avail flags 0x%x idx %d\n",
241 				   vringh16_to_cpu(vrh, avail->flags),
242 				   vringh16_to_cpu(vrh, avail->idx) & (num - 1));
243 			seq_printf(s, "avail flags 0x%x idx %d\n",
244 				   vringh16_to_cpu(vrh, avail->flags),
245 				   vringh16_to_cpu(vrh, avail->idx));
246 			for (j = 0; j < num; j++)
247 				seq_printf(s, "avail ring[%d] %d\n",
248 					   j, avail->ring[j]);
249 			used = vrh->vring.used;
250 			seq_printf(s, "used flags 0x%x idx %d\n",
251 				   vringh16_to_cpu(vrh, used->flags),
252 				   vringh16_to_cpu(vrh, used->idx) & (num - 1));
253 			seq_printf(s, "used flags 0x%x idx %d\n",
254 				   vringh16_to_cpu(vrh, used->flags),
255 				   vringh16_to_cpu(vrh, used->idx));
256 			for (j = 0; j < num; j++)
257 				seq_printf(s, "used ring[%d] id %d len %d\n",
258 					   j, vringh32_to_cpu(vrh,
259 							      used->ring[j].id),
260 					   vringh32_to_cpu(vrh,
261 							   used->ring[j].len));
262 		}
263 	}
264 	mutex_unlock(&mdev->mic_mutex);
265 
266 	return 0;
267 }
268 
mic_vdev_info_debug_open(struct inode * inode,struct file * file)269 static int mic_vdev_info_debug_open(struct inode *inode, struct file *file)
270 {
271 	return single_open(file, mic_vdev_info_show, inode->i_private);
272 }
273 
mic_vdev_info_debug_release(struct inode * inode,struct file * file)274 static int mic_vdev_info_debug_release(struct inode *inode, struct file *file)
275 {
276 	return single_release(inode, file);
277 }
278 
279 static const struct file_operations vdev_info_ops = {
280 	.owner   = THIS_MODULE,
281 	.open    = mic_vdev_info_debug_open,
282 	.read    = seq_read,
283 	.llseek  = seq_lseek,
284 	.release = mic_vdev_info_debug_release
285 };
286 
mic_msi_irq_info_show(struct seq_file * s,void * pos)287 static int mic_msi_irq_info_show(struct seq_file *s, void *pos)
288 {
289 	struct mic_device *mdev  = s->private;
290 	int reg;
291 	int i, j;
292 	u16 entry;
293 	u16 vector;
294 	struct pci_dev *pdev = mdev->pdev;
295 
296 	if (pci_dev_msi_enabled(pdev)) {
297 		for (i = 0; i < mdev->irq_info.num_vectors; i++) {
298 			if (pdev->msix_enabled) {
299 				entry = mdev->irq_info.msix_entries[i].entry;
300 				vector = mdev->irq_info.msix_entries[i].vector;
301 			} else {
302 				entry = 0;
303 				vector = pdev->irq;
304 			}
305 
306 			reg = mdev->intr_ops->read_msi_to_src_map(mdev, entry);
307 
308 			seq_printf(s, "%s %-10d %s %-10d MXAR[%d]: %08X\n",
309 				   "IRQ:", vector, "Entry:", entry, i, reg);
310 
311 			seq_printf(s, "%-10s", "offset:");
312 			for (j = (MIC_NUM_OFFSETS - 1); j >= 0; j--)
313 				seq_printf(s, "%4d ", j);
314 			seq_puts(s, "\n");
315 
316 
317 			seq_printf(s, "%-10s", "count:");
318 			for (j = (MIC_NUM_OFFSETS - 1); j >= 0; j--)
319 				seq_printf(s, "%4d ",
320 					   (mdev->irq_info.mic_msi_map[i] &
321 					   BIT(j)) ? 1 : 0);
322 			seq_puts(s, "\n\n");
323 		}
324 	} else {
325 		seq_puts(s, "MSI/MSIx interrupts not enabled\n");
326 	}
327 
328 	return 0;
329 }
330 
mic_msi_irq_info_debug_open(struct inode * inode,struct file * file)331 static int mic_msi_irq_info_debug_open(struct inode *inode, struct file *file)
332 {
333 	return single_open(file, mic_msi_irq_info_show, inode->i_private);
334 }
335 
336 static int
mic_msi_irq_info_debug_release(struct inode * inode,struct file * file)337 mic_msi_irq_info_debug_release(struct inode *inode, struct file *file)
338 {
339 	return single_release(inode, file);
340 }
341 
342 static const struct file_operations msi_irq_info_ops = {
343 	.owner   = THIS_MODULE,
344 	.open    = mic_msi_irq_info_debug_open,
345 	.read    = seq_read,
346 	.llseek  = seq_lseek,
347 	.release = mic_msi_irq_info_debug_release
348 };
349 
350 /**
351  * mic_create_debug_dir - Initialize MIC debugfs entries.
352  */
mic_create_debug_dir(struct mic_device * mdev)353 void mic_create_debug_dir(struct mic_device *mdev)
354 {
355 	char name[16];
356 
357 	if (!mic_dbg)
358 		return;
359 
360 	scnprintf(name, sizeof(name), "mic%d", mdev->id);
361 	mdev->dbg_dir = debugfs_create_dir(name, mic_dbg);
362 	if (!mdev->dbg_dir)
363 		return;
364 
365 	debugfs_create_file("smpt", 0444, mdev->dbg_dir, mdev, &smpt_file_ops);
366 
367 	debugfs_create_file("post_code", 0444, mdev->dbg_dir, mdev,
368 			    &post_code_ops);
369 
370 	debugfs_create_file("dp", 0444, mdev->dbg_dir, mdev, &dp_ops);
371 
372 	debugfs_create_file("vdev_info", 0444, mdev->dbg_dir, mdev,
373 			    &vdev_info_ops);
374 
375 	debugfs_create_file("msi_irq_info", 0444, mdev->dbg_dir, mdev,
376 			    &msi_irq_info_ops);
377 }
378 
379 /**
380  * mic_delete_debug_dir - Uninitialize MIC debugfs entries.
381  */
mic_delete_debug_dir(struct mic_device * mdev)382 void mic_delete_debug_dir(struct mic_device *mdev)
383 {
384 	if (!mdev->dbg_dir)
385 		return;
386 
387 	debugfs_remove_recursive(mdev->dbg_dir);
388 }
389 
390 /**
391  * mic_init_debugfs - Initialize global debugfs entry.
392  */
mic_init_debugfs(void)393 void __init mic_init_debugfs(void)
394 {
395 	mic_dbg = debugfs_create_dir(KBUILD_MODNAME, NULL);
396 	if (!mic_dbg)
397 		pr_err("can't create debugfs dir\n");
398 }
399 
400 /**
401  * mic_exit_debugfs - Uninitialize global debugfs entry
402  */
mic_exit_debugfs(void)403 void mic_exit_debugfs(void)
404 {
405 	debugfs_remove(mic_dbg);
406 }
407