diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-18 13:06:00 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-18 13:06:00 -0500 |
| commit | 7b077868cb8bc31aa5a0dad961ecc9f157bff744 (patch) | |
| tree | 02edce8760040ab5c15c242eb648fb3a342c58d7 | |
| parent | 16e024f30ce96ef5fa651e2914e19d175a924cab (diff) | |
| parent | 1f1c96102ff848778cd596e81bdbd45f81a40119 (diff) | |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 update #2 from Martin Schwidefsky:
"The main patch is the function measurement blocks extension for PCI to
do performance statistics and help with debugging. The other patch is
a small cleanup in ccwdev.h."
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux:
s390/ccwdev: Include asm/schid.h.
s390/pci: performance statistics and debug infrastructure
| -rw-r--r-- | arch/s390/include/asm/ccwdev.h | 4 | ||||
| -rw-r--r-- | arch/s390/include/asm/pci.h | 39 | ||||
| -rw-r--r-- | arch/s390/include/asm/pci_debug.h | 36 | ||||
| -rw-r--r-- | arch/s390/pci/Makefile | 2 | ||||
| -rw-r--r-- | arch/s390/pci/pci.c | 73 | ||||
| -rw-r--r-- | arch/s390/pci/pci_clp.c | 1 | ||||
| -rw-r--r-- | arch/s390/pci/pci_debug.c | 193 | ||||
| -rw-r--r-- | arch/s390/pci/pci_dma.c | 8 | ||||
| -rw-r--r-- | arch/s390/pci/pci_event.c | 2 |
9 files changed, 350 insertions, 8 deletions
diff --git a/arch/s390/include/asm/ccwdev.h b/arch/s390/include/asm/ccwdev.h index 6d1f3573f0df..e6061617a50b 100644 --- a/arch/s390/include/asm/ccwdev.h +++ b/arch/s390/include/asm/ccwdev.h | |||
| @@ -12,15 +12,13 @@ | |||
| 12 | #include <linux/mod_devicetable.h> | 12 | #include <linux/mod_devicetable.h> |
| 13 | #include <asm/fcx.h> | 13 | #include <asm/fcx.h> |
| 14 | #include <asm/irq.h> | 14 | #include <asm/irq.h> |
| 15 | #include <asm/schid.h> | ||
| 15 | 16 | ||
| 16 | /* structs from asm/cio.h */ | 17 | /* structs from asm/cio.h */ |
| 17 | struct irb; | 18 | struct irb; |
| 18 | struct ccw1; | 19 | struct ccw1; |
| 19 | struct ccw_dev_id; | 20 | struct ccw_dev_id; |
| 20 | 21 | ||
| 21 | /* from asm/schid.h */ | ||
| 22 | struct subchannel_id; | ||
| 23 | |||
| 24 | /* simplified initializers for struct ccw_device: | 22 | /* simplified initializers for struct ccw_device: |
| 25 | * CCW_DEVICE and CCW_DEVICE_DEVTYPE initialize one | 23 | * CCW_DEVICE and CCW_DEVICE_DEVTYPE initialize one |
| 26 | * entry in your MODULE_DEVICE_TABLE and set the match_flag correctly */ | 24 | * entry in your MODULE_DEVICE_TABLE and set the match_flag correctly */ |
diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h index a6175ad0c42f..b1fa93c606ad 100644 --- a/arch/s390/include/asm/pci.h +++ b/arch/s390/include/asm/pci.h | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include <asm-generic/pci.h> | 9 | #include <asm-generic/pci.h> |
| 10 | #include <asm-generic/pci-dma-compat.h> | 10 | #include <asm-generic/pci-dma-compat.h> |
| 11 | #include <asm/pci_clp.h> | 11 | #include <asm/pci_clp.h> |
| 12 | #include <asm/pci_debug.h> | ||
| 12 | 13 | ||
| 13 | #define PCIBIOS_MIN_IO 0x1000 | 14 | #define PCIBIOS_MIN_IO 0x1000 |
| 14 | #define PCIBIOS_MIN_MEM 0x10000000 | 15 | #define PCIBIOS_MIN_MEM 0x10000000 |
| @@ -33,6 +34,25 @@ int pci_proc_domain(struct pci_bus *); | |||
| 33 | #define ZPCI_FC_BLOCKED 0x20 | 34 | #define ZPCI_FC_BLOCKED 0x20 |
| 34 | #define ZPCI_FC_DMA_ENABLED 0x10 | 35 | #define ZPCI_FC_DMA_ENABLED 0x10 |
| 35 | 36 | ||
| 37 | struct zpci_fmb { | ||
| 38 | u32 format : 8; | ||
| 39 | u32 dma_valid : 1; | ||
| 40 | u32 : 23; | ||
| 41 | u32 samples; | ||
| 42 | u64 last_update; | ||
| 43 | /* hardware counters */ | ||
| 44 | u64 ld_ops; | ||
| 45 | u64 st_ops; | ||
| 46 | u64 stb_ops; | ||
| 47 | u64 rpcit_ops; | ||
| 48 | u64 dma_rbytes; | ||
| 49 | u64 dma_wbytes; | ||
| 50 | /* software counters */ | ||
| 51 | atomic64_t allocated_pages; | ||
| 52 | atomic64_t mapped_pages; | ||
| 53 | atomic64_t unmapped_pages; | ||
| 54 | } __packed __aligned(16); | ||
| 55 | |||
| 36 | struct msi_map { | 56 | struct msi_map { |
| 37 | unsigned long irq; | 57 | unsigned long irq; |
| 38 | struct msi_desc *msi; | 58 | struct msi_desc *msi; |
| @@ -92,7 +112,15 @@ struct zpci_dev { | |||
| 92 | u64 end_dma; /* End of available DMA addresses */ | 112 | u64 end_dma; /* End of available DMA addresses */ |
| 93 | u64 dma_mask; /* DMA address space mask */ | 113 | u64 dma_mask; /* DMA address space mask */ |
| 94 | 114 | ||
| 115 | /* Function measurement block */ | ||
| 116 | struct zpci_fmb *fmb; | ||
| 117 | u16 fmb_update; /* update interval */ | ||
| 118 | |||
| 95 | enum pci_bus_speed max_bus_speed; | 119 | enum pci_bus_speed max_bus_speed; |
| 120 | |||
| 121 | struct dentry *debugfs_dev; | ||
| 122 | struct dentry *debugfs_perf; | ||
| 123 | struct dentry *debugfs_debug; | ||
| 96 | }; | 124 | }; |
| 97 | 125 | ||
| 98 | struct pci_hp_callback_ops { | 126 | struct pci_hp_callback_ops { |
| @@ -155,4 +183,15 @@ extern struct list_head zpci_list; | |||
| 155 | extern struct pci_hp_callback_ops hotplug_ops; | 183 | extern struct pci_hp_callback_ops hotplug_ops; |
| 156 | extern unsigned int pci_probe; | 184 | extern unsigned int pci_probe; |
| 157 | 185 | ||
| 186 | /* FMB */ | ||
| 187 | int zpci_fmb_enable_device(struct zpci_dev *); | ||
| 188 | int zpci_fmb_disable_device(struct zpci_dev *); | ||
| 189 | |||
| 190 | /* Debug */ | ||
| 191 | int zpci_debug_init(void); | ||
| 192 | void zpci_debug_exit(void); | ||
| 193 | void zpci_debug_init_device(struct zpci_dev *); | ||
| 194 | void zpci_debug_exit_device(struct zpci_dev *); | ||
| 195 | void zpci_debug_info(struct zpci_dev *, struct seq_file *); | ||
| 196 | |||
| 158 | #endif | 197 | #endif |
diff --git a/arch/s390/include/asm/pci_debug.h b/arch/s390/include/asm/pci_debug.h new file mode 100644 index 000000000000..6bbec4265b6e --- /dev/null +++ b/arch/s390/include/asm/pci_debug.h | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | #ifndef _S390_ASM_PCI_DEBUG_H | ||
| 2 | #define _S390_ASM_PCI_DEBUG_H | ||
| 3 | |||
| 4 | #include <asm/debug.h> | ||
| 5 | |||
| 6 | extern debug_info_t *pci_debug_msg_id; | ||
| 7 | extern debug_info_t *pci_debug_err_id; | ||
| 8 | |||
| 9 | #ifdef CONFIG_PCI_DEBUG | ||
| 10 | #define zpci_dbg(fmt, args...) \ | ||
| 11 | do { \ | ||
| 12 | if (pci_debug_msg_id->level >= 2) \ | ||
| 13 | debug_sprintf_event(pci_debug_msg_id, 2, fmt , ## args);\ | ||
| 14 | } while (0) | ||
| 15 | |||
| 16 | #else /* !CONFIG_PCI_DEBUG */ | ||
| 17 | #define zpci_dbg(fmt, args...) do { } while (0) | ||
| 18 | #endif | ||
| 19 | |||
| 20 | #define zpci_err(text...) \ | ||
| 21 | do { \ | ||
| 22 | char debug_buffer[16]; \ | ||
| 23 | snprintf(debug_buffer, 16, text); \ | ||
| 24 | debug_text_event(pci_debug_err_id, 0, debug_buffer); \ | ||
| 25 | } while (0) | ||
| 26 | |||
| 27 | static inline void zpci_err_hex(void *addr, int len) | ||
| 28 | { | ||
| 29 | while (len > 0) { | ||
| 30 | debug_event(pci_debug_err_id, 0, (void *) addr, len); | ||
| 31 | len -= pci_debug_err_id->buf_size; | ||
| 32 | addr += pci_debug_err_id->buf_size; | ||
| 33 | } | ||
| 34 | } | ||
| 35 | |||
| 36 | #endif | ||
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 | ||
| 5 | obj-$(CONFIG_PCI) += pci.o pci_dma.o pci_clp.o pci_msi.o \ | 5 | obj-$(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); | |||
| 98 | static int __read_mostly aisb_max; | 98 | static int __read_mostly aisb_max; |
| 99 | 99 | ||
| 100 | static struct kmem_cache *zdev_irq_cache; | 100 | static struct kmem_cache *zdev_irq_cache; |
| 101 | static struct kmem_cache *zdev_fmb_cache; | ||
| 102 | |||
| 103 | debug_info_t *pci_debug_msg_id; | ||
| 104 | debug_info_t *pci_debug_err_id; | ||
| 101 | 105 | ||
| 102 | static inline int irq_to_msi_nr(unsigned int irq) | 106 | static 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 | ||
| 221 | static int mod_pci(struct zpci_dev *zdev, int fn, u8 dmaas, struct mod_pci_args *args) | 226 | static 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 | |||
| 242 | int zpci_register_ioat(struct zpci_dev *zdev, u8 dmaas, | 248 | int 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 */ |
| 253 | int zpci_unregister_ioat(struct zpci_dev *zdev, u8 dmaas) | 259 | int 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 */ |
| 261 | static int zpci_unregister_airq(struct zpci_dev *zdev) | 267 | static 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 */ | ||
| 275 | int 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 */ | ||
| 293 | int 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 | ||
| 270 | static int zpci_cfg_load(struct zpci_dev *zdev, int offset, u32 *val, u8 len) | 311 | static 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 | ||
| 844 | void 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 | |||
| 802 | static struct resource *zpci_alloc_bus_resource(unsigned long start, unsigned long size, | 854 | static 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 | ||
| 1030 | error_iomap: | 1089 | error_iomap: |
| 1090 | kmem_cache_destroy(zdev_fmb_cache); | ||
| 1091 | error_fmb: | ||
| 1031 | kmem_cache_destroy(zdev_irq_cache); | 1092 | kmem_cache_destroy(zdev_irq_cache); |
| 1032 | error_zdev: | 1093 | error_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 | ||
| 1042 | unsigned int pci_probe = 1; | 1104 | unsigned 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: | |||
| 1098 | out_hash: | 1164 | out_hash: |
| 1099 | zpci_mem_exit(); | 1165 | zpci_mem_exit(); |
| 1100 | out_mem: | 1166 | out_mem: |
| 1167 | zpci_debug_exit(); | ||
| 1101 | return rc; | 1168 | return rc; |
| 1102 | } | 1169 | } |
| 1103 | subsys_initcall(pci_base_init); | 1170 | subsys_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 | |||
| 19 | static struct dentry *debugfs_root; | ||
| 20 | |||
| 21 | static 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 | |||
| 35 | static 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 | |||
| 70 | static 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 | |||
| 99 | static 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 | |||
| 105 | static 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 | |||
| 113 | static 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 | |||
| 121 | static 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 | |||
| 127 | static 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 | |||
| 134 | void 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 | |||
| 156 | void 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 | |||
| 163 | int __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 | |||
| 185 | void 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 | ||
| 297 | out_free: | 299 | out_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 | ||
