aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/pci
diff options
context:
space:
mode:
authorJan Glauber <jang@linux.vnet.ibm.com>2012-12-11 08:53:35 -0500
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2012-12-14 04:01:17 -0500
commitd0b0885316ab7a97cc8a19027905de3ff7bd1e79 (patch)
tree43a490c63baf2da1d4768f7d083e2e9d6cf8467b /arch/s390/pci
parent7313264b899bbf3988841296265a6e0e8a7b6521 (diff)
s390/pci: performance statistics and debug infrastructure
Add support for reading the PCI function measurement block counters provided by the hypervisor. Add two s390 debug features, one for critical errors and one for tracing and provide wrappers to log data. Signed-off-by: Jan Glauber <jang@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/pci')
-rw-r--r--arch/s390/pci/Makefile2
-rw-r--r--arch/s390/pci/pci.c73
-rw-r--r--arch/s390/pci/pci_clp.c1
-rw-r--r--arch/s390/pci/pci_debug.c193
-rw-r--r--arch/s390/pci/pci_dma.c8
-rw-r--r--arch/s390/pci/pci_event.c2
6 files changed, 274 insertions, 5 deletions
diff --git a/arch/s390/pci/Makefile b/arch/s390/pci/Makefile
index ab0827b6bc4b..f0f426a113ce 100644
--- a/arch/s390/pci/Makefile
+++ b/arch/s390/pci/Makefile
@@ -3,4 +3,4 @@
3# 3#
4 4
5obj-$(CONFIG_PCI) += pci.o pci_dma.o pci_clp.o pci_msi.o \ 5obj-$(CONFIG_PCI) += pci.o pci_dma.o pci_clp.o pci_msi.o \
6 pci_sysfs.o pci_event.o 6 pci_sysfs.o pci_event.o pci_debug.o
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c
index 7ed38e5e3028..8fa416b8775f 100644
--- a/arch/s390/pci/pci.c
+++ b/arch/s390/pci/pci.c
@@ -98,6 +98,10 @@ EXPORT_SYMBOL_GPL(zpci_iomap_start);
98static int __read_mostly aisb_max; 98static int __read_mostly aisb_max;
99 99
100static struct kmem_cache *zdev_irq_cache; 100static struct kmem_cache *zdev_irq_cache;
101static struct kmem_cache *zdev_fmb_cache;
102
103debug_info_t *pci_debug_msg_id;
104debug_info_t *pci_debug_err_id;
101 105
102static inline int irq_to_msi_nr(unsigned int irq) 106static inline int irq_to_msi_nr(unsigned int irq)
103{ 107{
@@ -216,6 +220,7 @@ struct mod_pci_args {
216 u64 base; 220 u64 base;
217 u64 limit; 221 u64 limit;
218 u64 iota; 222 u64 iota;
223 u64 fmb_addr;
219}; 224};
220 225
221static int mod_pci(struct zpci_dev *zdev, int fn, u8 dmaas, struct mod_pci_args *args) 226static int mod_pci(struct zpci_dev *zdev, int fn, u8 dmaas, struct mod_pci_args *args)
@@ -232,6 +237,7 @@ static int mod_pci(struct zpci_dev *zdev, int fn, u8 dmaas, struct mod_pci_args
232 fib->pba = args->base; 237 fib->pba = args->base;
233 fib->pal = args->limit; 238 fib->pal = args->limit;
234 fib->iota = args->iota; 239 fib->iota = args->iota;
240 fib->fmb_addr = args->fmb_addr;
235 241
236 rc = mpcifc_instr(req, fib); 242 rc = mpcifc_instr(req, fib);
237 free_page((unsigned long) fib); 243 free_page((unsigned long) fib);
@@ -242,7 +248,7 @@ static int mod_pci(struct zpci_dev *zdev, int fn, u8 dmaas, struct mod_pci_args
242int zpci_register_ioat(struct zpci_dev *zdev, u8 dmaas, 248int zpci_register_ioat(struct zpci_dev *zdev, u8 dmaas,
243 u64 base, u64 limit, u64 iota) 249 u64 base, u64 limit, u64 iota)
244{ 250{
245 struct mod_pci_args args = { base, limit, iota }; 251 struct mod_pci_args args = { base, limit, iota, 0 };
246 252
247 WARN_ON_ONCE(iota & 0x3fff); 253 WARN_ON_ONCE(iota & 0x3fff);
248 args.iota |= ZPCI_IOTA_RTTO_FLAG; 254 args.iota |= ZPCI_IOTA_RTTO_FLAG;
@@ -252,7 +258,7 @@ int zpci_register_ioat(struct zpci_dev *zdev, u8 dmaas,
252/* Modify PCI: Unregister I/O address translation parameters */ 258/* Modify PCI: Unregister I/O address translation parameters */
253int zpci_unregister_ioat(struct zpci_dev *zdev, u8 dmaas) 259int zpci_unregister_ioat(struct zpci_dev *zdev, u8 dmaas)
254{ 260{
255 struct mod_pci_args args = { 0, 0, 0 }; 261 struct mod_pci_args args = { 0, 0, 0, 0 };
256 262
257 return mod_pci(zdev, ZPCI_MOD_FC_DEREG_IOAT, dmaas, &args); 263 return mod_pci(zdev, ZPCI_MOD_FC_DEREG_IOAT, dmaas, &args);
258} 264}
@@ -260,11 +266,46 @@ int zpci_unregister_ioat(struct zpci_dev *zdev, u8 dmaas)
260/* Modify PCI: Unregister adapter interruptions */ 266/* Modify PCI: Unregister adapter interruptions */
261static int zpci_unregister_airq(struct zpci_dev *zdev) 267static int zpci_unregister_airq(struct zpci_dev *zdev)
262{ 268{
263 struct mod_pci_args args = { 0, 0, 0 }; 269 struct mod_pci_args args = { 0, 0, 0, 0 };
264 270
265 return mod_pci(zdev, ZPCI_MOD_FC_DEREG_INT, 0, &args); 271 return mod_pci(zdev, ZPCI_MOD_FC_DEREG_INT, 0, &args);
266} 272}
267 273
274/* Modify PCI: Set PCI function measurement parameters */
275int zpci_fmb_enable_device(struct zpci_dev *zdev)
276{
277 struct mod_pci_args args = { 0, 0, 0, 0 };
278
279 if (zdev->fmb)
280 return -EINVAL;
281
282 zdev->fmb = kmem_cache_alloc(zdev_fmb_cache, GFP_KERNEL);
283 if (!zdev->fmb)
284 return -ENOMEM;
285 memset(zdev->fmb, 0, sizeof(*zdev->fmb));
286 WARN_ON((u64) zdev->fmb & 0xf);
287
288 args.fmb_addr = virt_to_phys(zdev->fmb);
289 return mod_pci(zdev, ZPCI_MOD_FC_SET_MEASURE, 0, &args);
290}
291
292/* Modify PCI: Disable PCI function measurement */
293int zpci_fmb_disable_device(struct zpci_dev *zdev)
294{
295 struct mod_pci_args args = { 0, 0, 0, 0 };
296 int rc;
297
298 if (!zdev->fmb)
299 return -EINVAL;
300
301 /* Function measurement is disabled if fmb address is zero */
302 rc = mod_pci(zdev, ZPCI_MOD_FC_SET_MEASURE, 0, &args);
303
304 kmem_cache_free(zdev_fmb_cache, zdev->fmb);
305 zdev->fmb = NULL;
306 return rc;
307}
308
268#define ZPCI_PCIAS_CFGSPC 15 309#define ZPCI_PCIAS_CFGSPC 15
269 310
270static int zpci_cfg_load(struct zpci_dev *zdev, int offset, u32 *val, u8 len) 311static int zpci_cfg_load(struct zpci_dev *zdev, int offset, u32 *val, u8 len)
@@ -633,6 +674,7 @@ static void zpci_remove_device(struct pci_dev *pdev)
633 dev_info(&pdev->dev, "Removing device %u\n", zdev->domain); 674 dev_info(&pdev->dev, "Removing device %u\n", zdev->domain);
634 zdev->state = ZPCI_FN_STATE_CONFIGURED; 675 zdev->state = ZPCI_FN_STATE_CONFIGURED;
635 zpci_dma_exit_device(zdev); 676 zpci_dma_exit_device(zdev);
677 zpci_fmb_disable_device(zdev);
636 zpci_sysfs_remove_device(&pdev->dev); 678 zpci_sysfs_remove_device(&pdev->dev);
637 zpci_unmap_resources(pdev); 679 zpci_unmap_resources(pdev);
638 list_del(&zdev->entry); /* can be called from init */ 680 list_del(&zdev->entry); /* can be called from init */
@@ -799,6 +841,16 @@ static void zpci_irq_exit(void)
799 kfree(bucket); 841 kfree(bucket);
800} 842}
801 843
844void zpci_debug_info(struct zpci_dev *zdev, struct seq_file *m)
845{
846 if (!zdev)
847 return;
848
849 seq_printf(m, "global irq retries: %u\n", atomic_read(&irq_retries));
850 seq_printf(m, "aibv[0]:%016lx aibv[1]:%016lx aisb:%016lx\n",
851 get_imap(0)->aibv, get_imap(1)->aibv, *bucket->aisb);
852}
853
802static struct resource *zpci_alloc_bus_resource(unsigned long start, unsigned long size, 854static struct resource *zpci_alloc_bus_resource(unsigned long start, unsigned long size,
803 unsigned long flags, int domain) 855 unsigned long flags, int domain)
804{ 856{
@@ -994,6 +1046,8 @@ int zpci_scan_device(struct zpci_dev *zdev)
994 goto out; 1046 goto out;
995 } 1047 }
996 1048
1049 zpci_debug_init_device(zdev);
1050 zpci_fmb_enable_device(zdev);
997 zpci_map_resources(zdev); 1051 zpci_map_resources(zdev);
998 pci_bus_add_devices(zdev->bus); 1052 pci_bus_add_devices(zdev->bus);
999 1053
@@ -1020,6 +1074,11 @@ static int zpci_mem_init(void)
1020 if (!zdev_irq_cache) 1074 if (!zdev_irq_cache)
1021 goto error_zdev; 1075 goto error_zdev;
1022 1076
1077 zdev_fmb_cache = kmem_cache_create("PCI_FMB_cache", sizeof(struct zpci_fmb),
1078 16, 0, NULL);
1079 if (!zdev_fmb_cache)
1080 goto error_fmb;
1081
1023 /* TODO: use realloc */ 1082 /* TODO: use realloc */
1024 zpci_iomap_start = kzalloc(ZPCI_IOMAP_MAX_ENTRIES * sizeof(*zpci_iomap_start), 1083 zpci_iomap_start = kzalloc(ZPCI_IOMAP_MAX_ENTRIES * sizeof(*zpci_iomap_start),
1025 GFP_KERNEL); 1084 GFP_KERNEL);
@@ -1028,6 +1087,8 @@ static int zpci_mem_init(void)
1028 return 0; 1087 return 0;
1029 1088
1030error_iomap: 1089error_iomap:
1090 kmem_cache_destroy(zdev_fmb_cache);
1091error_fmb:
1031 kmem_cache_destroy(zdev_irq_cache); 1092 kmem_cache_destroy(zdev_irq_cache);
1032error_zdev: 1093error_zdev:
1033 return -ENOMEM; 1094 return -ENOMEM;
@@ -1037,6 +1098,7 @@ static void zpci_mem_exit(void)
1037{ 1098{
1038 kfree(zpci_iomap_start); 1099 kfree(zpci_iomap_start);
1039 kmem_cache_destroy(zdev_irq_cache); 1100 kmem_cache_destroy(zdev_irq_cache);
1101 kmem_cache_destroy(zdev_fmb_cache);
1040} 1102}
1041 1103
1042unsigned int pci_probe = 1; 1104unsigned int pci_probe = 1;
@@ -1066,6 +1128,10 @@ static int __init pci_base_init(void)
1066 test_facility(69), test_facility(70), 1128 test_facility(69), test_facility(70),
1067 test_facility(71)); 1129 test_facility(71));
1068 1130
1131 rc = zpci_debug_init();
1132 if (rc)
1133 return rc;
1134
1069 rc = zpci_mem_init(); 1135 rc = zpci_mem_init();
1070 if (rc) 1136 if (rc)
1071 goto out_mem; 1137 goto out_mem;
@@ -1098,6 +1164,7 @@ out_irq:
1098out_hash: 1164out_hash:
1099 zpci_mem_exit(); 1165 zpci_mem_exit();
1100out_mem: 1166out_mem:
1167 zpci_debug_exit();
1101 return rc; 1168 return rc;
1102} 1169}
1103subsys_initcall(pci_base_init); 1170subsys_initcall(pci_base_init);
diff --git a/arch/s390/pci/pci_clp.c b/arch/s390/pci/pci_clp.c
index 7f4ce8d874a4..2c847143cbd1 100644
--- a/arch/s390/pci/pci_clp.c
+++ b/arch/s390/pci/pci_clp.c
@@ -51,6 +51,7 @@ static void clp_store_query_pci_fngrp(struct zpci_dev *zdev,
51 zdev->tlb_refresh = response->refresh; 51 zdev->tlb_refresh = response->refresh;
52 zdev->dma_mask = response->dasm; 52 zdev->dma_mask = response->dasm;
53 zdev->msi_addr = response->msia; 53 zdev->msi_addr = response->msia;
54 zdev->fmb_update = response->mui;
54 55
55 pr_debug("Supported number of MSI vectors: %u\n", response->noi); 56 pr_debug("Supported number of MSI vectors: %u\n", response->noi);
56 switch (response->version) { 57 switch (response->version) {
diff --git a/arch/s390/pci/pci_debug.c b/arch/s390/pci/pci_debug.c
new file mode 100644
index 000000000000..a303c95346cb
--- /dev/null
+++ b/arch/s390/pci/pci_debug.c
@@ -0,0 +1,193 @@
1/*
2 * Copyright IBM Corp. 2012
3 *
4 * Author(s):
5 * Jan Glauber <jang@linux.vnet.ibm.com>
6 */
7
8#define COMPONENT "zPCI"
9#define pr_fmt(fmt) COMPONENT ": " fmt
10
11#include <linux/kernel.h>
12#include <linux/seq_file.h>
13#include <linux/debugfs.h>
14#include <linux/pci.h>
15#include <asm/debug.h>
16
17#include <asm/pci_dma.h>
18
19static struct dentry *debugfs_root;
20
21static char *pci_perf_names[] = {
22 /* hardware counters */
23 "Load operations",
24 "Store operations",
25 "Store block operations",
26 "Refresh operations",
27 "DMA read bytes",
28 "DMA write bytes",
29 /* software counters */
30 "Allocated pages",
31 "Mapped pages",
32 "Unmapped pages",
33};
34
35static int pci_perf_show(struct seq_file *m, void *v)
36{
37 struct zpci_dev *zdev = m->private;
38 u64 *stat;
39 int i;
40
41 if (!zdev)
42 return 0;
43 if (!zdev->fmb)
44 return seq_printf(m, "FMB statistics disabled\n");
45
46 /* header */
47 seq_printf(m, "FMB @ %p\n", zdev->fmb);
48 seq_printf(m, "Update interval: %u ms\n", zdev->fmb_update);
49 seq_printf(m, "Samples: %u\n", zdev->fmb->samples);
50 seq_printf(m, "Last update TOD: %Lx\n", zdev->fmb->last_update);
51
52 /* hardware counters */
53 stat = (u64 *) &zdev->fmb->ld_ops;
54 for (i = 0; i < 4; i++)
55 seq_printf(m, "%26s:\t%llu\n",
56 pci_perf_names[i], *(stat + i));
57 if (zdev->fmb->dma_valid)
58 for (i = 4; i < 6; i++)
59 seq_printf(m, "%26s:\t%llu\n",
60 pci_perf_names[i], *(stat + i));
61 /* software counters */
62 for (i = 6; i < ARRAY_SIZE(pci_perf_names); i++)
63 seq_printf(m, "%26s:\t%llu\n",
64 pci_perf_names[i],
65 atomic64_read((atomic64_t *) (stat + i)));
66
67 return 0;
68}
69
70static ssize_t pci_perf_seq_write(struct file *file, const char __user *ubuf,
71 size_t count, loff_t *off)
72{
73 struct zpci_dev *zdev = ((struct seq_file *) file->private_data)->private;
74 unsigned long val;
75 int rc;
76
77 if (!zdev)
78 return 0;
79
80 rc = kstrtoul_from_user(ubuf, count, 10, &val);
81 if (rc)
82 return rc;
83
84 switch (val) {
85 case 0:
86 rc = zpci_fmb_disable_device(zdev);
87 if (rc)
88 return rc;
89 break;
90 case 1:
91 rc = zpci_fmb_enable_device(zdev);
92 if (rc)
93 return rc;
94 break;
95 }
96 return count;
97}
98
99static int pci_perf_seq_open(struct inode *inode, struct file *filp)
100{
101 return single_open(filp, pci_perf_show,
102 filp->f_path.dentry->d_inode->i_private);
103}
104
105static const struct file_operations debugfs_pci_perf_fops = {
106 .open = pci_perf_seq_open,
107 .read = seq_read,
108 .write = pci_perf_seq_write,
109 .llseek = seq_lseek,
110 .release = single_release,
111};
112
113static int pci_debug_show(struct seq_file *m, void *v)
114{
115 struct zpci_dev *zdev = m->private;
116
117 zpci_debug_info(zdev, m);
118 return 0;
119}
120
121static int pci_debug_seq_open(struct inode *inode, struct file *filp)
122{
123 return single_open(filp, pci_debug_show,
124 filp->f_path.dentry->d_inode->i_private);
125}
126
127static const struct file_operations debugfs_pci_debug_fops = {
128 .open = pci_debug_seq_open,
129 .read = seq_read,
130 .llseek = seq_lseek,
131 .release = single_release,
132};
133
134void zpci_debug_init_device(struct zpci_dev *zdev)
135{
136 zdev->debugfs_dev = debugfs_create_dir(dev_name(&zdev->pdev->dev),
137 debugfs_root);
138 if (IS_ERR(zdev->debugfs_dev))
139 zdev->debugfs_dev = NULL;
140
141 zdev->debugfs_perf = debugfs_create_file("statistics",
142 S_IFREG | S_IRUGO | S_IWUSR,
143 zdev->debugfs_dev, zdev,
144 &debugfs_pci_perf_fops);
145 if (IS_ERR(zdev->debugfs_perf))
146 zdev->debugfs_perf = NULL;
147
148 zdev->debugfs_debug = debugfs_create_file("debug",
149 S_IFREG | S_IRUGO | S_IWUSR,
150 zdev->debugfs_dev, zdev,
151 &debugfs_pci_debug_fops);
152 if (IS_ERR(zdev->debugfs_debug))
153 zdev->debugfs_debug = NULL;
154}
155
156void zpci_debug_exit_device(struct zpci_dev *zdev)
157{
158 debugfs_remove(zdev->debugfs_perf);
159 debugfs_remove(zdev->debugfs_debug);
160 debugfs_remove(zdev->debugfs_dev);
161}
162
163int __init zpci_debug_init(void)
164{
165 /* event trace buffer */
166 pci_debug_msg_id = debug_register("pci_msg", 16, 1, 16 * sizeof(long));
167 if (!pci_debug_msg_id)
168 return -EINVAL;
169 debug_register_view(pci_debug_msg_id, &debug_sprintf_view);
170 debug_set_level(pci_debug_msg_id, 3);
171 zpci_dbg("Debug view initialized\n");
172
173 /* error log */
174 pci_debug_err_id = debug_register("pci_error", 2, 1, 16);
175 if (!pci_debug_err_id)
176 return -EINVAL;
177 debug_register_view(pci_debug_err_id, &debug_hex_ascii_view);
178 debug_set_level(pci_debug_err_id, 6);
179 zpci_err("Debug view initialized\n");
180
181 debugfs_root = debugfs_create_dir("pci", NULL);
182 return 0;
183}
184
185void zpci_debug_exit(void)
186{
187 if (pci_debug_msg_id)
188 debug_unregister(pci_debug_msg_id);
189 if (pci_debug_err_id)
190 debug_unregister(pci_debug_err_id);
191
192 debugfs_remove(debugfs_root);
193}
diff --git a/arch/s390/pci/pci_dma.c b/arch/s390/pci/pci_dma.c
index c64b4b294b0a..6138468b420f 100644
--- a/arch/s390/pci/pci_dma.c
+++ b/arch/s390/pci/pci_dma.c
@@ -291,8 +291,10 @@ static dma_addr_t s390_dma_map_pages(struct device *dev, struct page *page,
291 if (direction == DMA_NONE || direction == DMA_TO_DEVICE) 291 if (direction == DMA_NONE || direction == DMA_TO_DEVICE)
292 flags |= ZPCI_TABLE_PROTECTED; 292 flags |= ZPCI_TABLE_PROTECTED;
293 293
294 if (!dma_update_trans(zdev, pa, dma_addr, size, flags)) 294 if (!dma_update_trans(zdev, pa, dma_addr, size, flags)) {
295 atomic64_add(nr_pages, (atomic64_t *) &zdev->fmb->mapped_pages);
295 return dma_addr + offset; 296 return dma_addr + offset;
297 }
296 298
297out_free: 299out_free:
298 dma_free_iommu(zdev, iommu_page_index, nr_pages); 300 dma_free_iommu(zdev, iommu_page_index, nr_pages);
@@ -315,6 +317,7 @@ static void s390_dma_unmap_pages(struct device *dev, dma_addr_t dma_addr,
315 ZPCI_TABLE_PROTECTED | ZPCI_PTE_INVALID)) 317 ZPCI_TABLE_PROTECTED | ZPCI_PTE_INVALID))
316 dev_err(dev, "Failed to unmap addr: %Lx\n", dma_addr); 318 dev_err(dev, "Failed to unmap addr: %Lx\n", dma_addr);
317 319
320 atomic64_add(npages, (atomic64_t *) &zdev->fmb->unmapped_pages);
318 iommu_page_index = (dma_addr - zdev->start_dma) >> PAGE_SHIFT; 321 iommu_page_index = (dma_addr - zdev->start_dma) >> PAGE_SHIFT;
319 dma_free_iommu(zdev, iommu_page_index, npages); 322 dma_free_iommu(zdev, iommu_page_index, npages);
320} 323}
@@ -323,6 +326,7 @@ static void *s390_dma_alloc(struct device *dev, size_t size,
323 dma_addr_t *dma_handle, gfp_t flag, 326 dma_addr_t *dma_handle, gfp_t flag,
324 struct dma_attrs *attrs) 327 struct dma_attrs *attrs)
325{ 328{
329 struct zpci_dev *zdev = get_zdev(container_of(dev, struct pci_dev, dev));
326 struct page *page; 330 struct page *page;
327 unsigned long pa; 331 unsigned long pa;
328 dma_addr_t map; 332 dma_addr_t map;
@@ -331,6 +335,8 @@ static void *s390_dma_alloc(struct device *dev, size_t size,
331 page = alloc_pages(flag, get_order(size)); 335 page = alloc_pages(flag, get_order(size));
332 if (!page) 336 if (!page)
333 return NULL; 337 return NULL;
338
339 atomic64_add(size / PAGE_SIZE, (atomic64_t *) &zdev->fmb->allocated_pages);
334 pa = page_to_phys(page); 340 pa = page_to_phys(page);
335 memset((void *) pa, 0, size); 341 memset((void *) pa, 0, size);
336 342
diff --git a/arch/s390/pci/pci_event.c b/arch/s390/pci/pci_event.c
index dbed8cd3370c..ec62e3a0dc09 100644
--- a/arch/s390/pci/pci_event.c
+++ b/arch/s390/pci/pci_event.c
@@ -45,6 +45,8 @@ static void zpci_event_log_err(struct zpci_ccdf_err *ccdf)
45{ 45{
46 struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid); 46 struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid);
47 47
48 zpci_err("SEI error CCD:\n");
49 zpci_err_hex(ccdf, sizeof(*ccdf));
48 dev_err(&zdev->pdev->dev, "event code: 0x%x\n", ccdf->pec); 50 dev_err(&zdev->pdev->dev, "event code: 0x%x\n", ccdf->pec);
49} 51}
50 52