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 */ 32static struct dentry *mic_dbg; 33 34/** 35 * mic_log_buf_show - Display MIC kernel log buffer. 36 * 37 * log_buf addr/len is read from System.map by user space 38 * and populated in sysfs entries. 39 */ 40static int mic_log_buf_show(struct seq_file *s, void *unused) 41{ 42 void __iomem *log_buf_va; 43 int __iomem *log_buf_len_va; 44 struct mic_device *mdev = s->private; 45 void *kva; 46 int size; 47 unsigned long aper_offset; 48 49 if (!mdev || !mdev->log_buf_addr || !mdev->log_buf_len) 50 goto done; 51 /* 52 * Card kernel will never be relocated and any kernel text/data mapping 53 * can be translated to phys address by subtracting __START_KERNEL_map. 54 */ 55 aper_offset = (unsigned long)mdev->log_buf_len - __START_KERNEL_map; 56 log_buf_len_va = mdev->aper.va + aper_offset; 57 aper_offset = (unsigned long)mdev->log_buf_addr - __START_KERNEL_map; 58 log_buf_va = mdev->aper.va + aper_offset; 59 size = ioread32(log_buf_len_va); 60 61 kva = kmalloc(size, GFP_KERNEL); 62 if (!kva) 63 goto done; 64 mutex_lock(&mdev->mic_mutex); 65 memcpy_fromio(kva, log_buf_va, size); 66 switch (mdev->state) { 67 case MIC_ONLINE: 68 /* Fall through */ 69 case MIC_SHUTTING_DOWN: 70 seq_write(s, kva, size); 71 break; 72 default: 73 break; 74 } 75 mutex_unlock(&mdev->mic_mutex); 76 kfree(kva); 77done: 78 return 0; 79} 80 81static int mic_log_buf_open(struct inode *inode, struct file *file) 82{ 83 return single_open(file, mic_log_buf_show, inode->i_private); 84} 85 86static int mic_log_buf_release(struct inode *inode, struct file *file) 87{ 88 return single_release(inode, file); 89} 90 91static const struct file_operations log_buf_ops = { 92 .owner = THIS_MODULE, 93 .open = mic_log_buf_open, 94 .read = seq_read, 95 .llseek = seq_lseek, 96 .release = mic_log_buf_release 97}; 98 99static int mic_smpt_show(struct seq_file *s, void *pos) 100{ 101 int i; 102 struct mic_device *mdev = s->private; 103 unsigned long flags; 104 105 seq_printf(s, "MIC %-2d |%-10s| %-14s %-10s\n", 106 mdev->id, "SMPT entry", "SW DMA addr", "RefCount"); 107 seq_puts(s, "====================================================\n"); 108 109 if (mdev->smpt) { 110 struct mic_smpt_info *smpt_info = mdev->smpt; 111 spin_lock_irqsave(&smpt_info->smpt_lock, flags); 112 for (i = 0; i < smpt_info->info.num_reg; i++) { 113 seq_printf(s, "%9s|%-10d| %-#14llx %-10lld\n", 114 " ", i, smpt_info->entry[i].dma_addr, 115 smpt_info->entry[i].ref_count); 116 } 117 spin_unlock_irqrestore(&smpt_info->smpt_lock, flags); 118 } 119 seq_puts(s, "====================================================\n"); 120 return 0; 121} 122 123static int mic_smpt_debug_open(struct inode *inode, struct file *file) 124{ 125 return single_open(file, mic_smpt_show, inode->i_private); 126} 127 128static int mic_smpt_debug_release(struct inode *inode, struct file *file) 129{ 130 return single_release(inode, file); 131} 132 133static const struct file_operations smpt_file_ops = { 134 .owner = THIS_MODULE, 135 .open = mic_smpt_debug_open, 136 .read = seq_read, 137 .llseek = seq_lseek, 138 .release = mic_smpt_debug_release 139}; 140 141static int mic_soft_reset_show(struct seq_file *s, void *pos) 142{ 143 struct mic_device *mdev = s->private; 144 145 mic_stop(mdev, true); 146 return 0; 147} 148 149static int mic_soft_reset_debug_open(struct inode *inode, struct file *file) 150{ 151 return single_open(file, mic_soft_reset_show, inode->i_private); 152} 153 154static int mic_soft_reset_debug_release(struct inode *inode, struct file *file) 155{ 156 return single_release(inode, file); 157} 158 159static const struct file_operations soft_reset_ops = { 160 .owner = THIS_MODULE, 161 .open = mic_soft_reset_debug_open, 162 .read = seq_read, 163 .llseek = seq_lseek, 164 .release = mic_soft_reset_debug_release 165}; 166 167static int mic_post_code_show(struct seq_file *s, void *pos) 168{ 169 struct mic_device *mdev = s->private; 170 u32 reg = mdev->ops->get_postcode(mdev); 171 172 seq_printf(s, "%c%c", reg & 0xff, (reg >> 8) & 0xff); 173 return 0; 174} 175 176static int mic_post_code_debug_open(struct inode *inode, struct file *file) 177{ 178 return single_open(file, mic_post_code_show, inode->i_private); 179} 180 181static int mic_post_code_debug_release(struct inode *inode, struct file *file) 182{ 183 return single_release(inode, file); 184} 185 186static const struct file_operations post_code_ops = { 187 .owner = THIS_MODULE, 188 .open = mic_post_code_debug_open, 189 .read = seq_read, 190 .llseek = seq_lseek, 191 .release = mic_post_code_debug_release 192}; 193 194static int mic_dp_show(struct seq_file *s, void *pos) 195{ 196 struct mic_device *mdev = s->private; 197 struct mic_device_desc *d; 198 struct mic_device_ctrl *dc; 199 struct mic_vqconfig *vqconfig; 200 __u32 *features; 201 __u8 *config; 202 struct mic_bootparam *bootparam = mdev->dp; 203 int i, j; 204 205 seq_printf(s, "Bootparam: magic 0x%x\n", 206 bootparam->magic); 207 seq_printf(s, "Bootparam: h2c_shutdown_db %d\n", 208 bootparam->h2c_shutdown_db); 209 seq_printf(s, "Bootparam: h2c_config_db %d\n", 210 bootparam->h2c_config_db); 211 seq_printf(s, "Bootparam: c2h_shutdown_db %d\n", 212 bootparam->c2h_shutdown_db); 213 seq_printf(s, "Bootparam: shutdown_status %d\n", 214 bootparam->shutdown_status); 215 seq_printf(s, "Bootparam: shutdown_card %d\n", 216 bootparam->shutdown_card); 217 218 for (i = sizeof(*bootparam); i < MIC_DP_SIZE; 219 i += mic_total_desc_size(d)) { 220 d = mdev->dp + i; 221 dc = (void *)d + mic_aligned_desc_size(d); 222 223 /* end of list */ 224 if (d->type == 0) 225 break; 226 227 if (d->type == -1) 228 continue; 229 230 seq_printf(s, "Type %d ", d->type); 231 seq_printf(s, "Num VQ %d ", d->num_vq); 232 seq_printf(s, "Feature Len %d\n", d->feature_len); 233 seq_printf(s, "Config Len %d ", d->config_len); 234 seq_printf(s, "Shutdown Status %d\n", d->status); 235 236 for (j = 0; j < d->num_vq; j++) { 237 vqconfig = mic_vq_config(d) + j; 238 seq_printf(s, "vqconfig[%d]: ", j); 239 seq_printf(s, "address 0x%llx ", vqconfig->address); 240 seq_printf(s, "num %d ", vqconfig->num); 241 seq_printf(s, "used address 0x%llx\n", 242 vqconfig->used_address); 243 } 244 245 features = (__u32 *)mic_vq_features(d); 246 seq_printf(s, "Features: Host 0x%x ", features[0]); 247 seq_printf(s, "Guest 0x%x\n", features[1]); 248 249 config = mic_vq_configspace(d); 250 for (j = 0; j < d->config_len; j++) 251 seq_printf(s, "config[%d]=%d\n", j, config[j]); 252 253 seq_puts(s, "Device control:\n"); 254 seq_printf(s, "Config Change %d ", dc->config_change); 255 seq_printf(s, "Vdev reset %d\n", dc->vdev_reset); 256 seq_printf(s, "Guest Ack %d ", dc->guest_ack); 257 seq_printf(s, "Host ack %d\n", dc->host_ack); 258 seq_printf(s, "Used address updated %d ", 259 dc->used_address_updated); 260 seq_printf(s, "Vdev 0x%llx\n", dc->vdev); 261 seq_printf(s, "c2h doorbell %d ", dc->c2h_vdev_db); 262 seq_printf(s, "h2c doorbell %d\n", dc->h2c_vdev_db); 263 } 264 265 return 0; 266} 267 268static int mic_dp_debug_open(struct inode *inode, struct file *file) 269{ 270 return single_open(file, mic_dp_show, inode->i_private); 271} 272 273static int mic_dp_debug_release(struct inode *inode, struct file *file) 274{ 275 return single_release(inode, file); 276} 277 278static const struct file_operations dp_ops = { 279 .owner = THIS_MODULE, 280 .open = mic_dp_debug_open, 281 .read = seq_read, 282 .llseek = seq_lseek, 283 .release = mic_dp_debug_release 284}; 285 286static int mic_vdev_info_show(struct seq_file *s, void *unused) 287{ 288 struct mic_device *mdev = s->private; 289 struct list_head *pos, *tmp; 290 struct mic_vdev *mvdev; 291 int i, j; 292 293 mutex_lock(&mdev->mic_mutex); 294 list_for_each_safe(pos, tmp, &mdev->vdev_list) { 295 mvdev = list_entry(pos, struct mic_vdev, list); 296 seq_printf(s, "VDEV type %d state %s in %ld out %ld\n", 297 mvdev->virtio_id, 298 mic_vdevup(mvdev) ? "UP" : "DOWN", 299 mvdev->in_bytes, 300 mvdev->out_bytes); 301 for (i = 0; i < MIC_MAX_VRINGS; i++) { 302 struct vring_desc *desc; 303 struct vring_avail *avail; 304 struct vring_used *used; 305 struct mic_vringh *mvr = &mvdev->mvr[i]; 306 struct vringh *vrh = &mvr->vrh; 307 int num = vrh->vring.num; 308 if (!num) 309 continue; 310 desc = vrh->vring.desc; 311 seq_printf(s, "vring i %d avail_idx %d", 312 i, mvr->vring.info->avail_idx & (num - 1)); 313 seq_printf(s, " vring i %d avail_idx %d\n", 314 i, mvr->vring.info->avail_idx); 315 seq_printf(s, "vrh i %d weak_barriers %d", 316 i, vrh->weak_barriers); 317 seq_printf(s, " last_avail_idx %d last_used_idx %d", 318 vrh->last_avail_idx, vrh->last_used_idx); 319 seq_printf(s, " completed %d\n", vrh->completed); 320 for (j = 0; j < num; j++) { 321 seq_printf(s, "desc[%d] addr 0x%llx len %d", 322 j, desc->addr, desc->len); 323 seq_printf(s, " flags 0x%x next %d\n", 324 desc->flags, desc->next); 325 desc++; 326 } 327 avail = vrh->vring.avail; 328 seq_printf(s, "avail flags 0x%x idx %d\n", 329 vringh16_to_cpu(vrh, avail->flags), 330 vringh16_to_cpu(vrh, avail->idx) & (num - 1)); 331 seq_printf(s, "avail flags 0x%x idx %d\n", 332 vringh16_to_cpu(vrh, avail->flags), 333 vringh16_to_cpu(vrh, avail->idx)); 334 for (j = 0; j < num; j++) 335 seq_printf(s, "avail ring[%d] %d\n", 336 j, avail->ring[j]); 337 used = vrh->vring.used; 338 seq_printf(s, "used flags 0x%x idx %d\n", 339 vringh16_to_cpu(vrh, used->flags), 340 vringh16_to_cpu(vrh, used->idx) & (num - 1)); 341 seq_printf(s, "used flags 0x%x idx %d\n", 342 vringh16_to_cpu(vrh, used->flags), 343 vringh16_to_cpu(vrh, used->idx)); 344 for (j = 0; j < num; j++) 345 seq_printf(s, "used ring[%d] id %d len %d\n", 346 j, vringh32_to_cpu(vrh, 347 used->ring[j].id), 348 vringh32_to_cpu(vrh, 349 used->ring[j].len)); 350 } 351 } 352 mutex_unlock(&mdev->mic_mutex); 353 354 return 0; 355} 356 357static int mic_vdev_info_debug_open(struct inode *inode, struct file *file) 358{ 359 return single_open(file, mic_vdev_info_show, inode->i_private); 360} 361 362static int mic_vdev_info_debug_release(struct inode *inode, struct file *file) 363{ 364 return single_release(inode, file); 365} 366 367static const struct file_operations vdev_info_ops = { 368 .owner = THIS_MODULE, 369 .open = mic_vdev_info_debug_open, 370 .read = seq_read, 371 .llseek = seq_lseek, 372 .release = mic_vdev_info_debug_release 373}; 374 375static int mic_msi_irq_info_show(struct seq_file *s, void *pos) 376{ 377 struct mic_device *mdev = s->private; 378 int reg; 379 int i, j; 380 u16 entry; 381 u16 vector; 382 struct pci_dev *pdev = container_of(mdev->sdev->parent, 383 struct pci_dev, dev); 384 385 if (pci_dev_msi_enabled(pdev)) { 386 for (i = 0; i < mdev->irq_info.num_vectors; i++) { 387 if (pdev->msix_enabled) { 388 entry = mdev->irq_info.msix_entries[i].entry; 389 vector = mdev->irq_info.msix_entries[i].vector; 390 } else { 391 entry = 0; 392 vector = pdev->irq; 393 } 394 395 reg = mdev->intr_ops->read_msi_to_src_map(mdev, entry); 396 397 seq_printf(s, "%s %-10d %s %-10d MXAR[%d]: %08X\n", 398 "IRQ:", vector, "Entry:", entry, i, reg); 399 400 seq_printf(s, "%-10s", "offset:"); 401 for (j = (MIC_NUM_OFFSETS - 1); j >= 0; j--) 402 seq_printf(s, "%4d ", j); 403 seq_puts(s, "\n"); 404 405 406 seq_printf(s, "%-10s", "count:"); 407 for (j = (MIC_NUM_OFFSETS - 1); j >= 0; j--) 408 seq_printf(s, "%4d ", 409 (mdev->irq_info.mic_msi_map[i] & 410 BIT(j)) ? 1 : 0); 411 seq_puts(s, "\n\n"); 412 } 413 } else { 414 seq_puts(s, "MSI/MSIx interrupts not enabled\n"); 415 } 416 417 return 0; 418} 419 420static int mic_msi_irq_info_debug_open(struct inode *inode, struct file *file) 421{ 422 return single_open(file, mic_msi_irq_info_show, inode->i_private); 423} 424 425static int 426mic_msi_irq_info_debug_release(struct inode *inode, struct file *file) 427{ 428 return single_release(inode, file); 429} 430 431static const struct file_operations msi_irq_info_ops = { 432 .owner = THIS_MODULE, 433 .open = mic_msi_irq_info_debug_open, 434 .read = seq_read, 435 .llseek = seq_lseek, 436 .release = mic_msi_irq_info_debug_release 437}; 438 439/** 440 * mic_create_debug_dir - Initialize MIC debugfs entries. 441 */ 442void mic_create_debug_dir(struct mic_device *mdev) 443{ 444 if (!mic_dbg) 445 return; 446 447 mdev->dbg_dir = debugfs_create_dir(dev_name(mdev->sdev), mic_dbg); 448 if (!mdev->dbg_dir) 449 return; 450 451 debugfs_create_file("log_buf", 0444, mdev->dbg_dir, mdev, &log_buf_ops); 452 453 debugfs_create_file("smpt", 0444, mdev->dbg_dir, mdev, &smpt_file_ops); 454 455 debugfs_create_file("soft_reset", 0444, mdev->dbg_dir, mdev, 456 &soft_reset_ops); 457 458 debugfs_create_file("post_code", 0444, mdev->dbg_dir, mdev, 459 &post_code_ops); 460 461 debugfs_create_file("dp", 0444, mdev->dbg_dir, mdev, &dp_ops); 462 463 debugfs_create_file("vdev_info", 0444, mdev->dbg_dir, mdev, 464 &vdev_info_ops); 465 466 debugfs_create_file("msi_irq_info", 0444, mdev->dbg_dir, mdev, 467 &msi_irq_info_ops); 468} 469 470/** 471 * mic_delete_debug_dir - Uninitialize MIC debugfs entries. 472 */ 473void mic_delete_debug_dir(struct mic_device *mdev) 474{ 475 if (!mdev->dbg_dir) 476 return; 477 478 debugfs_remove_recursive(mdev->dbg_dir); 479} 480 481/** 482 * mic_init_debugfs - Initialize global debugfs entry. 483 */ 484void __init mic_init_debugfs(void) 485{ 486 mic_dbg = debugfs_create_dir(KBUILD_MODNAME, NULL); 487 if (!mic_dbg) 488 pr_err("can't create debugfs dir\n"); 489} 490 491/** 492 * mic_exit_debugfs - Uninitialize global debugfs entry 493 */ 494void mic_exit_debugfs(void) 495{ 496 debugfs_remove(mic_dbg); 497} 498