Pull s390 updates from Martin Schwidefsky: "The bulk of the s390 updates for v3.14. New features are the perf support for the CPU-Measurement Sample Facility and the EP11 support for the crypto cards. And the normal cleanups and bug-fixes" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (44 commits) s390/cpum_sf: fix printk format warnings s390: Fix misspellings using 'codespell' tool s390/qdio: bridgeport support - CHSC part s390: delete new instances of __cpuinit usage s390/compat: fix PSW32_USER_BITS definition s390/zcrypt: add support for EP11 coprocessor cards s390/mm: optimize randomize_et_dyn for !PF_RANDOMIZE s390: use IS_ENABLED to check if a CONFIG is set to y or m s390/cio: use device_lock to synchronize calls to the ccwgroup driver s390/cio: use device_lock to synchronize calls to the ccw driver s390/cio: fix unlocked access of online member s390/cpum_sf: Add flag to process full SDBs only s390/cpum_sf: Add raw data sampling to support the diagnostic-sampling function s390/cpum_sf: Filter perf events based event->attr.exclude_* settings s390/cpum_sf: Detect KVM guest samples s390/cpum_sf: Add helper to read TOD from trailer entries s390/cpum_sf: Atomically reset trailer entry fields of sample-data-blocks s390/cpum_sf: Dynamically extend the sampling buffer if overflows occur s390/pci: reenable per default s390/pci/dma: fix accounting of allocated_pages ...
Unified · Split
| @@ -0,0 +1,20 @@ | ||
| 1 | +/*? | |
| 2 | + * Text: "Cryptographic device %x failed and was set offline\n" | |
| 3 | + * Severity: Error | |
| 4 | + * Parameter: | |
| 5 | + * @1: device index | |
| 6 | + * Description: | |
| 7 | + * A cryptographic device failed to process a cryptographic request. | |
| 8 | + * The cryptographic device driver could not correct the error and | |
| 9 | + * set the device offline. The application that issued the | |
| 10 | + * request received an indication that the request has failed. | |
| 11 | + * User action: | |
| 12 | + * Use the lszcrypt command to confirm that the cryptographic | |
| 13 | + * hardware is still configured to your LPAR or z/VM guest virtual | |
| 14 | + * machine. If the device is available to your Linux instance the | |
| 15 | + * command output contains a line that begins with 'card<device index>', | |
| 16 | + * where <device index> is the two-digit decimal number in the message text. | |
| 17 | + * After ensuring that the device is available, use the chzcrypt command to | |
| 18 | + * set it online again. | |
| 19 | + * If the error persists, contact your support organization. | |
| 20 | + */ | |
| @@ -38,7 +38,8 @@ · 37 unmodified lines | ||
| 38 | 38 | |
| 39 | 39 | #define PSW32_USER_BITS (PSW32_MASK_DAT | PSW32_MASK_IO | PSW32_MASK_EXT | \ |
| 40 | 40 | PSW32_DEFAULT_KEY | PSW32_MASK_BASE | \ |
| 41 | − PSW32_MASK_MCHECK | PSW32_MASK_PSTATE | PSW32_ASC_HOME) | |
| 41 | + PSW32_MASK_MCHECK | PSW32_MASK_PSTATE | \ | |
| 42 | + PSW32_ASC_PRIMARY) | |
| 42 | 43 | |
| 43 | 44 | #define COMPAT_USER_HZ 100 |
| 44 | 45 | #define COMPAT_UTS_MACHINE "s390\0\0\0\0" |
| @@ -56,6 +56,96 @@ struct cpumf_ctr_info { · 55 unmodified lines | ||
| 56 | 56 | u32 reserved2[12]; |
| 57 | 57 | } __packed; |
| 58 | 58 | |
| 59 | +/* QUERY SAMPLING INFORMATION block */ | |
| 60 | +struct hws_qsi_info_block { /* Bit(s) */ | |
| 61 | + unsigned int b0_13:14; /* 0-13: zeros */ | |
| 62 | + unsigned int as:1; /* 14: basic-sampling authorization */ | |
| 63 | + unsigned int ad:1; /* 15: diag-sampling authorization */ | |
| 64 | + unsigned int b16_21:6; /* 16-21: zeros */ | |
| 65 | + unsigned int es:1; /* 22: basic-sampling enable control */ | |
| 66 | + unsigned int ed:1; /* 23: diag-sampling enable control */ | |
| 67 | + unsigned int b24_29:6; /* 24-29: zeros */ | |
| 68 | + unsigned int cs:1; /* 30: basic-sampling activation control */ | |
| 69 | + unsigned int cd:1; /* 31: diag-sampling activation control */ | |
| 70 | + unsigned int bsdes:16; /* 4-5: size of basic sampling entry */ | |
| 71 | + unsigned int dsdes:16; /* 6-7: size of diagnostic sampling entry */ | |
| 72 | + unsigned long min_sampl_rate; /* 8-15: minimum sampling interval */ | |
| 73 | + unsigned long max_sampl_rate; /* 16-23: maximum sampling interval*/ | |
| 74 | + unsigned long tear; /* 24-31: TEAR contents */ | |
| 75 | + unsigned long dear; /* 32-39: DEAR contents */ | |
| 76 | + unsigned int rsvrd0; /* 40-43: reserved */ | |
| 77 | + unsigned int cpu_speed; /* 44-47: CPU speed */ | |
| 78 | + unsigned long long rsvrd1; /* 48-55: reserved */ | |
| 79 | + unsigned long long rsvrd2; /* 56-63: reserved */ | |
| 80 | +} __packed; | |
| 81 | + | |
| 82 | +/* SET SAMPLING CONTROLS request block */ | |
| 83 | +struct hws_lsctl_request_block { | |
| 84 | + unsigned int s:1; /* 0: maximum buffer indicator */ | |
| 85 | + unsigned int h:1; /* 1: part. level reserved for VM use*/ | |
| 86 | + unsigned long long b2_53:52;/* 2-53: zeros */ | |
| 87 | + unsigned int es:1; /* 54: basic-sampling enable control */ | |
| 88 | + unsigned int ed:1; /* 55: diag-sampling enable control */ | |
| 89 | + unsigned int b56_61:6; /* 56-61: - zeros */ | |
| 90 | + unsigned int cs:1; /* 62: basic-sampling activation control */ | |
| 91 | + unsigned int cd:1; /* 63: diag-sampling activation control */ | |
| 92 | + unsigned long interval; /* 8-15: sampling interval */ | |
| 93 | + unsigned long tear; /* 16-23: TEAR contents */ | |
| 94 | + unsigned long dear; /* 24-31: DEAR contents */ | |
| 95 | + /* 32-63: */ | |
| 96 | + unsigned long rsvrd1; /* reserved */ | |
| 97 | + unsigned long rsvrd2; /* reserved */ | |
| 98 | + unsigned long rsvrd3; /* reserved */ | |
| 99 | + unsigned long rsvrd4; /* reserved */ | |
| 100 | +} __packed; | |
| 101 | + | |
| 102 | +struct hws_basic_entry { | |
| 103 | + unsigned int def:16; /* 0-15 Data Entry Format */ | |
| 104 | + unsigned int R:4; /* 16-19 reserved */ | |
| 105 | + unsigned int U:4; /* 20-23 Number of unique instruct. */ | |
| 106 | + unsigned int z:2; /* zeros */ | |
| 107 | + unsigned int T:1; /* 26 PSW DAT mode */ | |
| 108 | + unsigned int W:1; /* 27 PSW wait state */ | |
| 109 | + unsigned int P:1; /* 28 PSW Problem state */ | |
| 110 | + unsigned int AS:2; /* 29-30 PSW address-space control */ | |
| 111 | + unsigned int I:1; /* 31 entry valid or invalid */ | |
| 112 | + unsigned int:16; | |
| 113 | + unsigned int prim_asn:16; /* primary ASN */ | |
| 114 | + unsigned long long ia; /* Instruction Address */ | |
| 115 | + unsigned long long gpp; /* Guest Program Parameter */ | |
| 116 | + unsigned long long hpp; /* Host Program Parameter */ | |
| 117 | +} __packed; | |
| 118 | + | |
| 119 | +struct hws_diag_entry { | |
| 120 | + unsigned int def:16; /* 0-15 Data Entry Format */ | |
| 121 | + unsigned int R:14; /* 16-19 and 20-30 reserved */ | |
| 122 | + unsigned int I:1; /* 31 entry valid or invalid */ | |
| 123 | + u8 data[]; /* Machine-dependent sample data */ | |
| 124 | +} __packed; | |
| 125 | + | |
| 126 | +struct hws_combined_entry { | |
| 127 | + struct hws_basic_entry basic; /* Basic-sampling data entry */ | |
| 128 | + struct hws_diag_entry diag; /* Diagnostic-sampling data entry */ | |
| 129 | +} __packed; | |
| 130 | + | |
| 131 | +struct hws_trailer_entry { | |
| 132 | + union { | |
| 133 | + struct { | |
| 134 | + unsigned int f:1; /* 0 - Block Full Indicator */ | |
| 135 | + unsigned int a:1; /* 1 - Alert request control */ | |
| 136 | + unsigned int t:1; /* 2 - Timestamp format */ | |
| 137 | + unsigned long long:61; /* 3 - 63: Reserved */ | |
| 138 | + }; | |
| 139 | + unsigned long long flags; /* 0 - 63: All indicators */ | |
| 140 | + }; | |
| 141 | + unsigned long long overflow; /* 64 - sample Overflow count */ | |
| 142 | + unsigned char timestamp[16]; /* 16 - 31 timestamp */ | |
| 143 | + unsigned long long reserved1; /* 32 -Reserved */ | |
| 144 | + unsigned long long reserved2; /* */ | |
| 145 | + unsigned long long progusage1; /* 48 - reserved for programming use */ | |
| 146 | + unsigned long long progusage2; /* */ | |
| 147 | +} __packed; | |
| 148 | + | |
| 59 | 149 | /* Query counter information */ |
| 60 | 150 | static inline int qctri(struct cpumf_ctr_info *info) |
| 61 | 151 | { |
| @@ -99,4 +189,95 @@ static inline int ecctr(u64 ctr, u64 *val) · 37 unmodified lines | ||
| 99 | 189 | return cc; |
| 100 | 190 | } |
| 101 | 191 | |
| 192 | +/* Query sampling information */ | |
| 193 | +static inline int qsi(struct hws_qsi_info_block *info) | |
| 194 | +{ | |
| 195 | + int cc; | |
| 196 | + cc = 1; | |
| 197 | + | |
| 198 | + asm volatile( | |
| 199 | + "0: .insn s,0xb2860000,0(%1)\n" | |
| 200 | + "1: lhi %0,0\n" | |
| 201 | + "2:\n" | |
| 202 | + EX_TABLE(0b, 2b) EX_TABLE(1b, 2b) | |
| 203 | + : "=d" (cc), "+a" (info) | |
| 204 | + : "m" (*info) | |
| 205 | + : "cc", "memory"); | |
| 206 | + | |
| 207 | + return cc ? -EINVAL : 0; | |
| 208 | +} | |
| 209 | + | |
| 210 | +/* Load sampling controls */ | |
| 211 | +static inline int lsctl(struct hws_lsctl_request_block *req) | |
| 212 | +{ | |
| 213 | + int cc; | |
| 214 | + | |
| 215 | + cc = 1; | |
| 216 | + asm volatile( | |
| 217 | + "0: .insn s,0xb2870000,0(%1)\n" | |
| 218 | + "1: ipm %0\n" | |
| 219 | + " srl %0,28\n" | |
| 220 | + "2:\n" | |
| 221 | + EX_TABLE(0b, 2b) EX_TABLE(1b, 2b) | |
| 222 | + : "+d" (cc), "+a" (req) | |
| 223 | + : "m" (*req) | |
| 224 | + : "cc", "memory"); | |
| 225 | + | |
| 226 | + return cc ? -EINVAL : 0; | |
| 227 | +} | |
| 228 | + | |
| 229 | +/* Sampling control helper functions */ | |
| 230 | + | |
| 231 | +#include <linux/time.h> | |
| 232 | + | |
| 233 | +static inline unsigned long freq_to_sample_rate(struct hws_qsi_info_block *qsi, | |
| 234 | + unsigned long freq) | |
| 235 | +{ | |
| 236 | + return (USEC_PER_SEC / freq) * qsi->cpu_speed; | |
| 237 | +} | |
| 238 | + | |
| 239 | +static inline unsigned long sample_rate_to_freq(struct hws_qsi_info_block *qsi, | |
| 240 | + unsigned long rate) | |
| 241 | +{ | |
| 242 | + return USEC_PER_SEC * qsi->cpu_speed / rate; | |
| 243 | +} | |
| 244 | + | |
| 245 | +#define SDB_TE_ALERT_REQ_MASK 0x4000000000000000UL | |
| 246 | +#define SDB_TE_BUFFER_FULL_MASK 0x8000000000000000UL | |
| 247 | + | |
| 248 | +/* Return TOD timestamp contained in an trailer entry */ | |
| 249 | +static inline unsigned long long trailer_timestamp(struct hws_trailer_entry *te) | |
| 250 | +{ | |
| 251 | + /* TOD in STCKE format */ | |
| 252 | + if (te->t) | |
| 253 | + return *((unsigned long long *) &te->timestamp[1]); | |
| 254 | + | |
| 255 | + /* TOD in STCK format */ | |
| 256 | + return *((unsigned long long *) &te->timestamp[0]); | |
| 257 | +} | |
| 258 | + | |
| 259 | +/* Return pointer to trailer entry of an sample data block */ | |
| 260 | +static inline unsigned long *trailer_entry_ptr(unsigned long v) | |
| 261 | +{ | |
| 262 | + void *ret; | |
| 263 | + | |
| 264 | + ret = (void *) v; | |
| 265 | + ret += PAGE_SIZE; | |
| 266 | + ret -= sizeof(struct hws_trailer_entry); | |
| 267 | + | |
| 268 | + return (unsigned long *) ret; | |
| 269 | +} | |
| 270 | + | |
| 271 | +/* Return if the entry in the sample data block table (sdbt) | |
| 272 | + * is a link to the next sdbt */ | |
| 273 | +static inline int is_link_entry(unsigned long *s) | |
| 274 | +{ | |
| 275 | + return *s & 0x1ul ? 1 : 0; | |
| 276 | +} | |
| 277 | + | |
| 278 | +/* Return pointer to the linked sdbt */ | |
| 279 | +static inline unsigned long *get_next_sdbt(unsigned long *s) | |
| 280 | +{ | |
| 281 | + return (unsigned long *) (*s & ~0x1ul); | |
| 282 | +} | |
| 102 | 283 | #endif /* _ASM_S390_CPU_MF_H */ |
| @@ -29,6 +29,8 @@ struct css_general_char { · 28 unmodified lines | ||
| 29 | 29 | u32 fcx : 1; /* bit 88 */ |
| 30 | 30 | u32 : 19; |
| 31 | 31 | u32 alt_ssi : 1; /* bit 108 */ |
| 32 | + u32:1; | |
| 33 | + u32 narf:1; /* bit 110 */ | |
| 32 | 34 | } __packed; |
| 33 | 35 | |
| 34 | 36 | extern struct css_general_char css_general_characteristics; |
| @@ -144,6 +144,7 @@ int clp_disable_fh(struct zpci_dev *); · 143 unmodified lines | ||
| 144 | 144 | void zpci_event_error(void *); |
| 145 | 145 | void zpci_event_availability(void *); |
| 146 | 146 | void zpci_rescan(void); |
| 147 | +bool zpci_is_enabled(void); | |
| 147 | 148 | #else /* CONFIG_PCI */ |
| 148 | 149 | static inline void zpci_event_error(void *e) {} |
| 149 | 150 | static inline void zpci_event_availability(void *e) {} |
| @@ -1,21 +1,40 @@ | ||
| 1 | 1 | /* |
| 2 | 2 | * Performance event support - s390 specific definitions. |
| 3 | 3 | * |
| 4 | − * Copyright IBM Corp. 2009, 2012 | |
| 4 | + * Copyright IBM Corp. 2009, 2013 | |
| 5 | 5 | * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> |
| 6 | 6 | * Hendrik Brueckner <brueckner@linux.vnet.ibm.com> |
| 7 | 7 | */ |
| 8 | 8 | |
| 9 | −#include <asm/cpu_mf.h> | |
| 9 | +#ifndef _ASM_S390_PERF_EVENT_H | |
| 10 | +#define _ASM_S390_PERF_EVENT_H | |
| 10 | 11 | |
| 11 | −/* CPU-measurement counter facility */ | |
| 12 | −#define PERF_CPUM_CF_MAX_CTR 256 | |
| 12 | +#ifdef CONFIG_64BIT | |
| 13 | + | |
| 14 | +#include <linux/perf_event.h> | |
| 15 | +#include <linux/device.h> | |
| 16 | +#include <asm/cpu_mf.h> | |
| 13 | 17 | |
| 14 | 18 | /* Per-CPU flags for PMU states */ |
| 15 | 19 | #define PMU_F_RESERVED 0x1000 |
| 16 | 20 | #define PMU_F_ENABLED 0x2000 |
| 21 | +#define PMU_F_IN_USE 0x4000 | |
| 22 | +#define PMU_F_ERR_IBE 0x0100 | |
| 23 | +#define PMU_F_ERR_LSDA 0x0200 | |
| 24 | +#define PMU_F_ERR_MASK (PMU_F_ERR_IBE|PMU_F_ERR_LSDA) | |
| 25 | + | |
| 26 | +/* Perf defintions for PMU event attributes in sysfs */ | |
| 27 | +extern __init const struct attribute_group **cpumf_cf_event_group(void); | |
| 28 | +extern ssize_t cpumf_events_sysfs_show(struct device *dev, | |
| 29 | + struct device_attribute *attr, | |
| 30 | + char *page); | |
| 31 | +#define EVENT_VAR(_cat, _name) event_attr_##_cat##_##_name | |
| 32 | +#define EVENT_PTR(_cat, _name) (&EVENT_VAR(_cat, _name).attr.attr) | |
| 33 | + | |
| 34 | +#define CPUMF_EVENT_ATTR(cat, name, id) \ | |
| 35 | + PMU_EVENT_ATTR(name, EVENT_VAR(cat, name), id, cpumf_events_sysfs_show) | |
| 36 | +#define CPUMF_EVENT_PTR(cat, name) EVENT_PTR(cat, name) | |
| 17 | 37 | |
| 18 | −#ifdef CONFIG_64BIT | |
| 19 | 38 | |
| 20 | 39 | /* Perf callbacks */ |
| 21 | 40 | struct pt_regs; |
| @@ -23,4 +42,55 @@ extern unsigned long perf_instruction_pointer(struct pt_regs *regs); · 1 unmodified line | ||
| 23 | 42 | extern unsigned long perf_misc_flags(struct pt_regs *regs); |
| 24 | 43 | #define perf_misc_flags(regs) perf_misc_flags(regs) |
| 25 | 44 | |
| 45 | +/* Perf pt_regs extension for sample-data-entry indicators */ | |
| 46 | +struct perf_sf_sde_regs { | |
| 47 | + unsigned char in_guest:1; /* guest sample */ | |
| 48 | + unsigned long reserved:63; /* reserved */ | |
| 49 | +}; | |
| 50 | + | |
| 51 | +/* Perf PMU definitions for the counter facility */ | |
| 52 | +#define PERF_CPUM_CF_MAX_CTR 256 | |
| 53 | + | |
| 54 | +/* Perf PMU definitions for the sampling facility */ | |
| 55 | +#define PERF_CPUM_SF_MAX_CTR 2 | |
| 56 | +#define PERF_EVENT_CPUM_SF 0xB0000UL /* Event: Basic-sampling */ | |
| 57 | +#define PERF_EVENT_CPUM_SF_DIAG 0xBD000UL /* Event: Combined-sampling */ | |
| 58 | +#define PERF_CPUM_SF_BASIC_MODE 0x0001 /* Basic-sampling flag */ | |
| 59 | +#define PERF_CPUM_SF_DIAG_MODE 0x0002 /* Diagnostic-sampling flag */ | |
| 60 | +#define PERF_CPUM_SF_MODE_MASK (PERF_CPUM_SF_BASIC_MODE| \ | |
| 61 | + PERF_CPUM_SF_DIAG_MODE) | |
| 62 | +#define PERF_CPUM_SF_FULL_BLOCKS 0x0004 /* Process full SDBs only */ | |
| 63 | + | |
| 64 | +#define REG_NONE 0 | |
| 65 | +#define REG_OVERFLOW 1 | |
| 66 | +#define OVERFLOW_REG(hwc) ((hwc)->extra_reg.config) | |
| 67 | +#define SFB_ALLOC_REG(hwc) ((hwc)->extra_reg.alloc) | |
| 68 | +#define RAWSAMPLE_REG(hwc) ((hwc)->config) | |
| 69 | +#define TEAR_REG(hwc) ((hwc)->last_tag) | |
| 70 | +#define SAMPL_RATE(hwc) ((hwc)->event_base) | |
| 71 | +#define SAMPL_FLAGS(hwc) ((hwc)->config_base) | |
| 72 | +#define SAMPL_DIAG_MODE(hwc) (SAMPL_FLAGS(hwc) & PERF_CPUM_SF_DIAG_MODE) | |
| 73 | +#define SDB_FULL_BLOCKS(hwc) (SAMPL_FLAGS(hwc) & PERF_CPUM_SF_FULL_BLOCKS) | |
| 74 | + | |
| 75 | +/* Structure for sampling data entries to be passed as perf raw sample data | |
| 76 | + * to user space. Note that raw sample data must be aligned and, thus, might | |
| 77 | + * be padded with zeros. | |
| 78 | + */ | |
| 79 | +struct sf_raw_sample { | |
| 80 | +#define SF_RAW_SAMPLE_BASIC PERF_CPUM_SF_BASIC_MODE | |
| 81 | +#define SF_RAW_SAMPLE_DIAG PERF_CPUM_SF_DIAG_MODE | |
| 82 | + u64 format; | |
| 83 | + u32 size; /* Size of sf_raw_sample */ | |
| 84 | + u16 bsdes; /* Basic-sampling data entry size */ | |
| 85 | + u16 dsdes; /* Diagnostic-sampling data entry size */ | |
| 86 | + struct hws_basic_entry basic; /* Basic-sampling data entry */ | |
| 87 | + struct hws_diag_entry diag; /* Diagnostic-sampling data entry */ | |
| 88 | + u8 padding[]; /* Padding to next multiple of 8 */ | |
| 89 | +} __packed; | |
| 90 | + | |
| 91 | +/* Perf hardware reserve and release functions */ | |
| 92 | +int perf_reserve_sampling(void); | |
| 93 | +void perf_release_sampling(void); | |
| 94 | + | |
| 26 | 95 | #endif /* CONFIG_64BIT */ |
| 96 | +#endif /* _ASM_S390_PERF_EVENT_H */ | |
| @@ -336,7 +336,7 @@ typedef void qdio_handler_t(struct ccw_device *, unsigned int, int, · 335 unmodified lines | ||
| 336 | 336 | #define QDIO_FLAG_CLEANUP_USING_HALT 0x02 |
| 337 | 337 | |
| 338 | 338 | /** |
| 339 | − * struct qdio_initialize - qdio initalization data | |
| 339 | + * struct qdio_initialize - qdio initialization data | |
| 340 | 340 | * @cdev: associated ccw device |
| 341 | 341 | * @q_format: queue format |
| 342 | 342 | * @adapter_name: name for the adapter |
| @@ -378,6 +378,34 @@ struct qdio_initialize { · 35 unmodified lines | ||
| 378 | 378 | struct qdio_outbuf_state *output_sbal_state_array; |
| 379 | 379 | }; |
| 380 | 380 | |
| 381 | +/** | |
| 382 | + * enum qdio_brinfo_entry_type - type of address entry for qdio_brinfo_desc() | |
| 383 | + * @l3_ipv6_addr: entry contains IPv6 address | |
| 384 | + * @l3_ipv4_addr: entry contains IPv4 address | |
| 385 | + * @l2_addr_lnid: entry contains MAC address and VLAN ID | |
| 386 | + */ | |
| 387 | +enum qdio_brinfo_entry_type {l3_ipv6_addr, l3_ipv4_addr, l2_addr_lnid}; | |
| 388 | + | |
| 389 | +/** | |
| 390 | + * struct qdio_brinfo_entry_XXX - Address entry for qdio_brinfo_desc() | |
| 391 | + * @nit: Network interface token | |
| 392 | + * @addr: Address of one of the three types | |
| 393 | + * | |
| 394 | + * The struct is passed to the callback function by qdio_brinfo_desc() | |
| 395 | + */ | |
| 396 | +struct qdio_brinfo_entry_l3_ipv6 { | |
| 397 | + u64 nit; | |
| 398 | + struct { unsigned char _s6_addr[16]; } addr; | |
| 399 | +} __packed; | |
| 400 | +struct qdio_brinfo_entry_l3_ipv4 { | |
| 401 | + u64 nit; | |
| 402 | + struct { uint32_t _s_addr; } addr; | |
| 403 | +} __packed; | |
| 404 | +struct qdio_brinfo_entry_l2 { | |
| 405 | + u64 nit; | |
| 406 | + struct { u8 mac[6]; u16 lnid; } addr_lnid; | |
| 407 | +} __packed; | |
| 408 | + | |
| 381 | 409 | #define QDIO_STATE_INACTIVE 0x00000002 /* after qdio_cleanup */ |
| 382 | 410 | #define QDIO_STATE_ESTABLISHED 0x00000004 /* after qdio_establish */ |
| 383 | 411 | #define QDIO_STATE_ACTIVE 0x00000008 /* after qdio_activate */ |
| @@ -399,5 +427,10 @@ extern int qdio_get_next_buffers(struct ccw_device *, int, int *, int *); · 15 unmodified lines | ||
| 399 | 427 | extern int qdio_shutdown(struct ccw_device *, int); |
| 400 | 428 | extern int qdio_free(struct ccw_device *); |
| 401 | 429 | extern int qdio_get_ssqd_desc(struct ccw_device *, struct qdio_ssqd_desc *); |
| 430 | +extern int qdio_pnso_brinfo(struct subchannel_id schid, | |
| 431 | + int cnc, u16 *response, | |
| 432 | + void (*cb)(void *priv, enum qdio_brinfo_entry_type type, | |
| 433 | + void *entry), | |
| 434 | + void *priv); | |
| 402 | 435 | |
| 403 | 436 | #endif /* __QDIO_H__ */ |
| @@ -52,8 +52,8 @@ int sclp_chp_configure(struct chp_id chpid); · 51 unmodified lines | ||
| 52 | 52 | int sclp_chp_deconfigure(struct chp_id chpid); |
| 53 | 53 | int sclp_chp_read_info(struct sclp_chp_info *info); |
| 54 | 54 | void sclp_get_ipl_info(struct sclp_ipl_info *info); |
| 55 | −bool sclp_has_linemode(void); | |
| 56 | −bool sclp_has_vt220(void); | |
| 55 | +bool __init sclp_has_linemode(void); | |
| 56 | +bool __init sclp_has_vt220(void); | |
| 57 | 57 | int sclp_pci_configure(u32 fid); |
| 58 | 58 | int sclp_pci_deconfigure(u32 fid); |
| 59 | 59 | int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode); |
| @@ -154,6 +154,67 @@ struct ica_xcRB { · 153 unmodified lines | ||
| 154 | 154 | unsigned short priority_window; |
| 155 | 155 | unsigned int status; |
| 156 | 156 | } __attribute__((packed)); |
| 157 | + | |
| 158 | +/** | |
| 159 | + * struct ep11_cprb - EP11 connectivity programming request block | |
| 160 | + * @cprb_len: CPRB header length [0x0020] | |
| 161 | + * @cprb_ver_id: CPRB version id. [0x04] | |
| 162 | + * @pad_000: Alignment pad bytes | |
| 163 | + * @flags: Admin cmd [0x80] or functional cmd [0x00] | |
| 164 | + * @func_id: Function id / subtype [0x5434] | |
| 165 | + * @source_id: Source id [originator id] | |
| 166 | + * @target_id: Target id [usage/ctrl domain id] | |
| 167 | + * @ret_code: Return code | |
| 168 | + * @reserved1: Reserved | |
| 169 | + * @reserved2: Reserved | |
| 170 | + * @payload_len: Payload length | |
| 171 | + */ | |
| 172 | +struct ep11_cprb { | |
| 173 | + uint16_t cprb_len; | |
| 174 | + unsigned char cprb_ver_id; | |
| 175 | + unsigned char pad_000[2]; | |
| 176 | + unsigned char flags; | |
| 177 | + unsigned char func_id[2]; | |
| 178 | + uint32_t source_id; | |
| 179 | + uint32_t target_id; | |
| 180 | + uint32_t ret_code; | |
| 181 | + uint32_t reserved1; | |
| 182 | + uint32_t reserved2; | |
| 183 | + uint32_t payload_len; | |
| 184 | +} __attribute__((packed)); | |
| 185 | + | |
| 186 | +/** | |
| 187 | + * struct ep11_target_dev - EP11 target device list | |
| 188 | + * @ap_id: AP device id | |
| 189 | + * @dom_id: Usage domain id | |
| 190 | + */ | |
| 191 | +struct ep11_target_dev { | |
| 192 | + uint16_t ap_id; | |
| 193 | + uint16_t dom_id; | |
| 194 | +}; | |
| 195 | + | |
| 196 | +/** | |
| 197 | + * struct ep11_urb - EP11 user request block | |
| 198 | + * @targets_num: Number of target adapters | |
| 199 | + * @targets: Addr to target adapter list | |
| 200 | + * @weight: Level of request priority | |
| 201 | + * @req_no: Request id/number | |
| 202 | + * @req_len: Request length | |
| 203 | + * @req: Addr to request block | |
| 204 | + * @resp_len: Response length | |
| 205 | + * @resp: Addr to response block | |
| 206 | + */ | |
| 207 | +struct ep11_urb { | |
| 208 | + uint16_t targets_num; | |
| 209 | + uint64_t targets; | |
| 210 | + uint64_t weight; | |
| 211 | + uint64_t req_no; | |
| 212 | + uint64_t req_len; | |
| 213 | + uint64_t req; | |
| 214 | + uint64_t resp_len; | |
| 215 | + uint64_t resp; | |
| 216 | +} __attribute__((packed)); | |
| 217 | + | |
| 157 | 218 | #define AUTOSELECT ((unsigned int)0xFFFFFFFF) |
| 158 | 219 | |
| 159 | 220 | #define ZCRYPT_IOCTL_MAGIC 'z' |
| @@ -183,6 +244,9 @@ struct ica_xcRB { · 23 unmodified lines | ||
| 183 | 244 | * ZSECSENDCPRB |
| 184 | 245 | * Send an arbitrary CPRB to a crypto card. |
| 185 | 246 | * |
| 247 | + * ZSENDEP11CPRB | |
| 248 | + * Send an arbitrary EP11 CPRB to an EP11 coprocessor crypto card. | |
| 249 | + * | |
| 186 | 250 | * Z90STAT_STATUS_MASK |
| 187 | 251 | * Return an 64 element array of unsigned chars for the status of |
| 188 | 252 | * all devices. |
| @@ -256,6 +320,7 @@ struct ica_xcRB { · 67 unmodified lines | ||
| 256 | 320 | #define ICARSAMODEXPO _IOC(_IOC_READ|_IOC_WRITE, ZCRYPT_IOCTL_MAGIC, 0x05, 0) |
| 257 | 321 | #define ICARSACRT _IOC(_IOC_READ|_IOC_WRITE, ZCRYPT_IOCTL_MAGIC, 0x06, 0) |
| 258 | 322 | #define ZSECSENDCPRB _IOC(_IOC_READ|_IOC_WRITE, ZCRYPT_IOCTL_MAGIC, 0x81, 0) |
| 323 | +#define ZSENDEP11CPRB _IOC(_IOC_READ|_IOC_WRITE, ZCRYPT_IOCTL_MAGIC, 0x04, 0) | |
| 259 | 324 | |
| 260 | 325 | /* New status calls */ |
| 261 | 326 | #define Z90STAT_TOTALCOUNT _IOR(ZCRYPT_IOCTL_MAGIC, 0x40, int) |
| @@ -60,7 +60,8 @@ obj-$(CONFIG_FTRACE_SYSCALLS) += ftrace.o · 59 unmodified lines | ||
| 60 | 60 | obj-$(CONFIG_CRASH_DUMP) += crash_dump.o |
| 61 | 61 | |
| 62 | 62 | ifdef CONFIG_64BIT |
| 63 | −obj-$(CONFIG_PERF_EVENTS) += perf_event.o perf_cpum_cf.o | |
| 63 | +obj-$(CONFIG_PERF_EVENTS) += perf_event.o perf_cpum_cf.o perf_cpum_sf.o \ | |
| 64 | + perf_cpum_cf_events.o | |
| 64 | 65 | obj-y += runtime_instr.o cache.o |
| 65 | 66 | endif |
| 66 | 67 | |
| @@ -412,8 +412,9 @@ static int setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info, · 411 unmodified lines | ||
| 412 | 412 | regs->gprs[14] = (__u64 __force) ka->sa.sa_restorer | PSW32_ADDR_AMODE; |
| 413 | 413 | } else { |
| 414 | 414 | regs->gprs[14] = (__u64 __force) frame->retcode | PSW32_ADDR_AMODE; |
| 415 | − err |= __put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn, | |
| 416 | − (u16 __force __user *)(frame->retcode)); | |
| 415 | + if (__put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn, | |
| 416 | + (u16 __force __user *)(frame->retcode))) | |
| 417 | + goto give_sigsegv; | |
| 417 | 418 | } |
| 418 | 419 | |
| 419 | 420 | /* Set up backchain. */ |
| @@ -74,7 +74,7 @@ _TIF_TRACE = (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | \ · 73 unmodified lines | ||
| 74 | 74 | .endm |
| 75 | 75 | |
| 76 | 76 | .macro LPP newpp |
| 77 | −#if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE) | |
| 77 | +#if IS_ENABLED(CONFIG_KVM) | |
| 78 | 78 | tm __LC_MACHINE_FLAGS+6,0x20 # MACHINE_FLAG_LPP |
| 79 | 79 | jz .+8 |
| 80 | 80 | .insn s,0xb2800000,\newpp |
| @@ -82,7 +82,7 @@ _TIF_TRACE = (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | \ · 1 unmodified line | ||
| 82 | 82 | .endm |
| 83 | 83 | |
| 84 | 84 | .macro HANDLE_SIE_INTERCEPT scratch,reason |
| 85 | −#if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE) | |
| 85 | +#if IS_ENABLED(CONFIG_KVM) | |
| 86 | 86 | tmhh %r8,0x0001 # interrupting from user ? |
| 87 | 87 | jnz .+62 |
| 88 | 88 | lgr \scratch,%r9 |
| @@ -946,7 +946,7 @@ cleanup_idle_insn: · 857 unmodified lines | ||
| 946 | 946 | .quad __critical_end - __critical_start |
| 947 | 947 | |
| 948 | 948 | |
| 949 | −#if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE) | |
| 949 | +#if IS_ENABLED(CONFIG_KVM) | |
| 950 | 950 | /* |
| 951 | 951 | * sie64a calling convention: |
| 952 | 952 | * %r2 pointer to sie control block |
| @@ -975,7 +975,7 @@ sie_done: · 22 unmodified lines | ||
| 975 | 975 | lctlg %c1,%c1,__LC_USER_ASCE # load primary asce |
| 976 | 976 | # some program checks are suppressing. C code (e.g. do_protection_exception) |
| 977 | 977 | # will rewind the PSW by the ILC, which is 4 bytes in case of SIE. Other |
| 978 | −# instructions beween sie64a and sie_done should not cause program | |
| 978 | +# instructions between sie64a and sie_done should not cause program | |
| 979 | 979 | # interrupts. So lets use a nop (47 00 00 00) as a landing pad. |
| 980 | 980 | # See also HANDLE_SIE_INTERCEPT |
| 981 | 981 | rewind_pad: |
| @@ -680,6 +680,7 @@ static int __init cpumf_pmu_init(void) · 679 unmodified lines | ||
| 680 | 680 | goto out; |
| 681 | 681 | } |
| 682 | 682 | |
| 683 | + cpumf_pmu.attr_groups = cpumf_cf_event_group(); | |
| 683 | 684 | rc = perf_pmu_register(&cpumf_pmu, "cpum_cf", PERF_TYPE_RAW); |
| 684 | 685 | if (rc) { |
| 685 | 686 | pr_err("Registering the cpum_cf PMU failed with rc=%i\n", rc); |
| @@ -0,0 +1,322 @@ | ||
| 1 | +/* | |
| 2 | + * Perf PMU sysfs events attributes for available CPU-measurement counters | |
| 3 | + * | |
| 4 | + */ | |
| 5 | + | |
| 6 | +#include <linux/slab.h> | |
| 7 | +#include <linux/perf_event.h> | |
| 8 | + | |
| 9 | + | |
| 10 | +/* BEGIN: CPUM_CF COUNTER DEFINITIONS =================================== */ | |
| 11 | + | |
| 12 | +CPUMF_EVENT_ATTR(cf, CPU_CYCLES, 0x0000); | |
| 13 | +CPUMF_EVENT_ATTR(cf, INSTRUCTIONS, 0x0001); | |
| 14 | +CPUMF_EVENT_ATTR(cf, L1I_DIR_WRITES, 0x0002); | |
| 15 | +CPUMF_EVENT_ATTR(cf, L1I_PENALTY_CYCLES, 0x0003); | |
| 16 | +CPUMF_EVENT_ATTR(cf, PROBLEM_STATE_CPU_CYCLES, 0x0020); | |
| 17 | +CPUMF_EVENT_ATTR(cf, PROBLEM_STATE_INSTRUCTIONS, 0x0021); | |
| 18 | +CPUMF_EVENT_ATTR(cf, PROBLEM_STATE_L1I_DIR_WRITES, 0x0022); | |
| 19 | +CPUMF_EVENT_ATTR(cf, PROBLEM_STATE_L1I_PENALTY_CYCLES, 0x0023); | |
| 20 | +CPUMF_EVENT_ATTR(cf, PROBLEM_STATE_L1D_DIR_WRITES, 0x0024); | |
| 21 | +CPUMF_EVENT_ATTR(cf, PROBLEM_STATE_L1D_PENALTY_CYCLES, 0x0025); | |
| 22 | +CPUMF_EVENT_ATTR(cf, L1D_DIR_WRITES, 0x0004); | |
| 23 | +CPUMF_EVENT_ATTR(cf, L1D_PENALTY_CYCLES, 0x0005); | |
| 24 | +CPUMF_EVENT_ATTR(cf, PRNG_FUNCTIONS, 0x0040); | |
| 25 | +CPUMF_EVENT_ATTR(cf, PRNG_CYCLES, 0x0041); | |
| 26 | +CPUMF_EVENT_ATTR(cf, PRNG_BLOCKED_FUNCTIONS, 0x0042); | |
| 27 | +CPUMF_EVENT_ATTR(cf, PRNG_BLOCKED_CYCLES, 0x0043); | |
| 28 | +CPUMF_EVENT_ATTR(cf, SHA_FUNCTIONS, 0x0044); | |
| 29 | +CPUMF_EVENT_ATTR(cf, SHA_CYCLES, 0x0045); | |
| 30 | +CPUMF_EVENT_ATTR(cf, SHA_BLOCKED_FUNCTIONS, 0x0046); | |
| 31 | +CPUMF_EVENT_ATTR(cf, SHA_BLOCKED_CYCLES, 0x0047); | |
| 32 | +CPUMF_EVENT_ATTR(cf, DEA_FUNCTIONS, 0x0048); | |
| 33 | +CPUMF_EVENT_ATTR(cf, DEA_CYCLES, 0x0049); | |
| 34 | +CPUMF_EVENT_ATTR(cf, DEA_BLOCKED_FUNCTIONS, 0x004a); | |
| 35 | +CPUMF_EVENT_ATTR(cf, DEA_BLOCKED_CYCLES, 0x004b); | |
| 36 | +CPUMF_EVENT_ATTR(cf, AES_FUNCTIONS, 0x004c); | |
| 37 | +CPUMF_EVENT_ATTR(cf, AES_CYCLES, 0x004d); | |
| 38 | +CPUMF_EVENT_ATTR(cf, AES_BLOCKED_FUNCTIONS, 0x004e); | |
| 39 | +CPUMF_EVENT_ATTR(cf, AES_BLOCKED_CYCLES, 0x004f); | |
| 40 | +CPUMF_EVENT_ATTR(cf_z10, L1I_L2_SOURCED_WRITES, 0x0080); | |
| 41 | +CPUMF_EVENT_ATTR(cf_z10, L1D_L2_SOURCED_WRITES, 0x0081); | |
| 42 | +CPUMF_EVENT_ATTR(cf_z10, L1I_L3_LOCAL_WRITES, 0x0082); | |
| 43 | +CPUMF_EVENT_ATTR(cf_z10, L1D_L3_LOCAL_WRITES, 0x0083); | |
| 44 | +CPUMF_EVENT_ATTR(cf_z10, L1I_L3_REMOTE_WRITES, 0x0084); | |
| 45 | +CPUMF_EVENT_ATTR(cf_z10, L1D_L3_REMOTE_WRITES, 0x0085); | |
| 46 | +CPUMF_EVENT_ATTR(cf_z10, L1D_LMEM_SOURCED_WRITES, 0x0086); | |
| 47 | +CPUMF_EVENT_ATTR(cf_z10, L1I_LMEM_SOURCED_WRITES, 0x0087); | |
| 48 | +CPUMF_EVENT_ATTR(cf_z10, L1D_RO_EXCL_WRITES, 0x0088); | |
| 49 | +CPUMF_EVENT_ATTR(cf_z10, L1I_CACHELINE_INVALIDATES, 0x0089); | |
| 50 | +CPUMF_EVENT_ATTR(cf_z10, ITLB1_WRITES, 0x008a); | |
| 51 | +CPUMF_EVENT_ATTR(cf_z10, DTLB1_WRITES, 0x008b); | |
| 52 | +CPUMF_EVENT_ATTR(cf_z10, TLB2_PTE_WRITES, 0x008c); | |
| 53 | +CPUMF_EVENT_ATTR(cf_z10, TLB2_CRSTE_WRITES, 0x008d); | |
| 54 | +CPUMF_EVENT_ATTR(cf_z10, TLB2_CRSTE_HPAGE_WRITES, 0x008e); | |
| 55 | +CPUMF_EVENT_ATTR(cf_z10, ITLB1_MISSES, 0x0091); | |
| 56 | +CPUMF_EVENT_ATTR(cf_z10, DTLB1_MISSES, 0x0092); | |
| 57 | +CPUMF_EVENT_ATTR(cf_z10, L2C_STORES_SENT, 0x0093); | |
| 58 | +CPUMF_EVENT_ATTR(cf_z196, L1D_L2_SOURCED_WRITES, 0x0080); | |
| 59 | +CPUMF_EVENT_ATTR(cf_z196, L1I_L2_SOURCED_WRITES, 0x0081); | |
| 60 | +CPUMF_EVENT_ATTR(cf_z196, DTLB1_MISSES, 0x0082); | |
| 61 | +CPUMF_EVENT_ATTR(cf_z196, ITLB1_MISSES, 0x0083); | |
| 62 | +CPUMF_EVENT_ATTR(cf_z196, L2C_STORES_SENT, 0x0085); | |
| 63 | +CPUMF_EVENT_ATTR(cf_z196, L1D_OFFBOOK_L3_SOURCED_WRITES, 0x0086); | |
| 64 | +CPUMF_EVENT_ATTR(cf_z196, L1D_ONBOOK_L4_SOURCED_WRITES, 0x0087); | |
| 65 | +CPUMF_EVENT_ATTR(cf_z196, L1I_ONBOOK_L4_SOURCED_WRITES, 0x0088); | |
| 66 | +CPUMF_EVENT_ATTR(cf_z196, L1D_RO_EXCL_WRITES, 0x0089); | |
| 67 | +CPUMF_EVENT_ATTR(cf_z196, L1D_OFFBOOK_L4_SOURCED_WRITES, 0x008a); | |
| 68 | +CPUMF_EVENT_ATTR(cf_z196, L1I_OFFBOOK_L4_SOURCED_WRITES, 0x008b); | |
| 69 | +CPUMF_EVENT_ATTR(cf_z196, DTLB1_HPAGE_WRITES, 0x008c); | |
| 70 | +CPUMF_EVENT_ATTR(cf_z196, L1D_LMEM_SOURCED_WRITES, 0x008d); | |
| 71 | +CPUMF_EVENT_ATTR(cf_z196, L1I_LMEM_SOURCED_WRITES, 0x008e); | |
| 72 | +CPUMF_EVENT_ATTR(cf_z196, L1I_OFFBOOK_L3_SOURCED_WRITES, 0x008f); | |
| 73 | +CPUMF_EVENT_ATTR(cf_z196, DTLB1_WRITES, 0x0090); | |
| 74 | +CPUMF_EVENT_ATTR(cf_z196, ITLB1_WRITES, 0x0091); | |
| 75 | +CPUMF_EVENT_ATTR(cf_z196, TLB2_PTE_WRITES, 0x0092); | |
| 76 | +CPUMF_EVENT_ATTR(cf_z196, TLB2_CRSTE_HPAGE_WRITES, 0x0093); | |
| 77 | +CPUMF_EVENT_ATTR(cf_z196, TLB2_CRSTE_WRITES, 0x0094); | |
| 78 | +CPUMF_EVENT_ATTR(cf_z196, L1D_ONCHIP_L3_SOURCED_WRITES, 0x0096); | |
| 79 | +CPUMF_EVENT_ATTR(cf_z196, L1D_OFFCHIP_L3_SOURCED_WRITES, 0x0098); | |
| 80 | +CPUMF_EVENT_ATTR(cf_z196, L1I_ONCHIP_L3_SOURCED_WRITES, 0x0099); | |
| 81 | +CPUMF_EVENT_ATTR(cf_z196, L1I_OFFCHIP_L3_SOURCED_WRITES, 0x009b); | |
| 82 | +CPUMF_EVENT_ATTR(cf_zec12, DTLB1_MISSES, 0x0080); | |
| 83 | +CPUMF_EVENT_ATTR(cf_zec12, ITLB1_MISSES, 0x0081); | |
| 84 | +CPUMF_EVENT_ATTR(cf_zec12, L1D_L2I_SOURCED_WRITES, 0x0082); | |
| 85 | +CPUMF_EVENT_ATTR(cf_zec12, L1I_L2I_SOURCED_WRITES, 0x0083); | |
| 86 | +CPUMF_EVENT_ATTR(cf_zec12, L1D_L2D_SOURCED_WRITES, 0x0084); | |
| 87 | +CPUMF_EVENT_ATTR(cf_zec12, DTLB1_WRITES, 0x0085); | |
| 88 | +CPUMF_EVENT_ATTR(cf_zec12, L1D_LMEM_SOURCED_WRITES, 0x0087); | |
| 89 | +CPUMF_EVENT_ATTR(cf_zec12, L1I_LMEM_SOURCED_WRITES, 0x0089); | |
| 90 | +CPUMF_EVENT_ATTR(cf_zec12, L1D_RO_EXCL_WRITES, 0x008a); | |
| 91 | +CPUMF_EVENT_ATTR(cf_zec12, DTLB1_HPAGE_WRITES, 0x008b); | |
| 92 | +CPUMF_EVENT_ATTR(cf_zec12, ITLB1_WRITES, 0x008c); | |
| 93 | +CPUMF_EVENT_ATTR(cf_zec12, TLB2_PTE_WRITES, 0x008d); | |
| 94 | +CPUMF_EVENT_ATTR(cf_zec12, TLB2_CRSTE_HPAGE_WRITES, 0x008e); | |
| 95 | +CPUMF_EVENT_ATTR(cf_zec12, TLB2_CRSTE_WRITES, 0x008f); | |
| 96 | +CPUMF_EVENT_ATTR(cf_zec12, L1D_ONCHIP_L3_SOURCED_WRITES, 0x0090); | |
| 97 | +CPUMF_EVENT_ATTR(cf_zec12, L1D_OFFCHIP_L3_SOURCED_WRITES, 0x0091); | |
| 98 | +CPUMF_EVENT_ATTR(cf_zec12, L1D_OFFBOOK_L3_SOURCED_WRITES, 0x0092); | |
| 99 | +CPUMF_EVENT_ATTR(cf_zec12, L1D_ONBOOK_L4_SOURCED_WRITES, 0x0093); | |
| 100 | +CPUMF_EVENT_ATTR(cf_zec12, L1D_OFFBOOK_L4_SOURCED_WRITES, 0x0094); | |
| 101 | +CPUMF_EVENT_ATTR(cf_zec12, TX_NC_TEND, 0x0095); | |
| 102 | +CPUMF_EVENT_ATTR(cf_zec12, L1D_ONCHIP_L3_SOURCED_WRITES_IV, 0x0096); | |
| 103 | +CPUMF_EVENT_ATTR(cf_zec12, L1D_OFFCHIP_L3_SOURCED_WRITES_IV, 0x0097); | |
| 104 | +CPUMF_EVENT_ATTR(cf_zec12, L1D_OFFBOOK_L3_SOURCED_WRITES_IV, 0x0098); | |
| 105 | +CPUMF_EVENT_ATTR(cf_zec12, L1I_ONCHIP_L3_SOURCED_WRITES, 0x0099); | |
| 106 | +CPUMF_EVENT_ATTR(cf_zec12, L1I_OFFCHIP_L3_SOURCED_WRITES, 0x009a); | |
| 107 | +CPUMF_EVENT_ATTR(cf_zec12, L1I_OFFBOOK_L3_SOURCED_WRITES, 0x009b); | |
| 108 | +CPUMF_EVENT_ATTR(cf_zec12, L1I_ONBOOK_L4_SOURCED_WRITES, 0x009c); | |
| 109 | +CPUMF_EVENT_ATTR(cf_zec12, L1I_OFFBOOK_L4_SOURCED_WRITES, 0x009d); | |
| 110 | +CPUMF_EVENT_ATTR(cf_zec12, TX_C_TEND, 0x009e); | |
| 111 | +CPUMF_EVENT_ATTR(cf_zec12, L1I_ONCHIP_L3_SOURCED_WRITES_IV, 0x009f); | |
| 112 | +CPUMF_EVENT_ATTR(cf_zec12, L1I_OFFCHIP_L3_SOURCED_WRITES_IV, 0x00a0); | |
| 113 | +CPUMF_EVENT_ATTR(cf_zec12, L1I_OFFBOOK_L3_SOURCED_WRITES_IV, 0x00a1); | |
| 114 | +CPUMF_EVENT_ATTR(cf_zec12, TX_NC_TABORT, 0x00b1); | |
| 115 | +CPUMF_EVENT_ATTR(cf_zec12, TX_C_TABORT_NO_SPECIAL, 0x00b2); | |
| 116 | +CPUMF_EVENT_ATTR(cf_zec12, TX_C_TABORT_SPECIAL, 0x00b3); | |
| 117 | + | |
| 118 | +static struct attribute *cpumcf_pmu_event_attr[] = { | |
| 119 | + CPUMF_EVENT_PTR(cf, CPU_CYCLES), | |
| 120 | + CPUMF_EVENT_PTR(cf, INSTRUCTIONS), | |
| 121 | + CPUMF_EVENT_PTR(cf, L1I_DIR_WRITES), | |
| 122 | + CPUMF_EVENT_PTR(cf, L1I_PENALTY_CYCLES), | |
| 123 | + CPUMF_EVENT_PTR(cf, PROBLEM_STATE_CPU_CYCLES), | |
| 124 | + CPUMF_EVENT_PTR(cf, PROBLEM_STATE_INSTRUCTIONS), | |
| 125 | + CPUMF_EVENT_PTR(cf, PROBLEM_STATE_L1I_DIR_WRITES), | |
| 126 | + CPUMF_EVENT_PTR(cf, PROBLEM_STATE_L1I_PENALTY_CYCLES), | |
| 127 | + CPUMF_EVENT_PTR(cf, PROBLEM_STATE_L1D_DIR_WRITES), | |
| 128 | + CPUMF_EVENT_PTR(cf, PROBLEM_STATE_L1D_PENALTY_CYCLES), | |
| 129 | + CPUMF_EVENT_PTR(cf, L1D_DIR_WRITES), | |
| 130 | + CPUMF_EVENT_PTR(cf, L1D_PENALTY_CYCLES), | |
| 131 | + CPUMF_EVENT_PTR(cf, PRNG_FUNCTIONS), | |
| 132 | + CPUMF_EVENT_PTR(cf, PRNG_CYCLES), | |
| 133 | + CPUMF_EVENT_PTR(cf, PRNG_BLOCKED_FUNCTIONS), | |
| 134 | + CPUMF_EVENT_PTR(cf, PRNG_BLOCKED_CYCLES), | |
| 135 | + CPUMF_EVENT_PTR(cf, SHA_FUNCTIONS), | |
| 136 | + CPUMF_EVENT_PTR(cf, SHA_CYCLES), | |
| 137 | + CPUMF_EVENT_PTR(cf, SHA_BLOCKED_FUNCTIONS), | |
| 138 | + CPUMF_EVENT_PTR(cf, SHA_BLOCKED_CYCLES), | |
| 139 | + CPUMF_EVENT_PTR(cf, DEA_FUNCTIONS), | |
| 140 | + CPUMF_EVENT_PTR(cf, DEA_CYCLES), | |
| 141 | + CPUMF_EVENT_PTR(cf, DEA_BLOCKED_FUNCTIONS), | |
| 142 | + CPUMF_EVENT_PTR(cf, DEA_BLOCKED_CYCLES), | |
| 143 | + CPUMF_EVENT_PTR(cf, AES_FUNCTIONS), | |
| 144 | + CPUMF_EVENT_PTR(cf, AES_CYCLES), | |
| 145 | + CPUMF_EVENT_PTR(cf, AES_BLOCKED_FUNCTIONS), | |
| 146 | + CPUMF_EVENT_PTR(cf, AES_BLOCKED_CYCLES), | |
| 147 | + NULL, | |
| 148 | +}; | |
| 149 | + | |
| 150 | +static struct attribute *cpumcf_z10_pmu_event_attr[] __initdata = { | |
| 151 | + CPUMF_EVENT_PTR(cf_z10, L1I_L2_SOURCED_WRITES), | |
| 152 | + CPUMF_EVENT_PTR(cf_z10, L1D_L2_SOURCED_WRITES), | |
| 153 | + CPUMF_EVENT_PTR(cf_z10, L1I_L3_LOCAL_WRITES), | |
| 154 | + CPUMF_EVENT_PTR(cf_z10, L1D_L3_LOCAL_WRITES), | |
| 155 | + CPUMF_EVENT_PTR(cf_z10, L1I_L3_REMOTE_WRITES), | |
| 156 | + CPUMF_EVENT_PTR(cf_z10, L1D_L3_REMOTE_WRITES), | |
| 157 | + CPUMF_EVENT_PTR(cf_z10, L1D_LMEM_SOURCED_WRITES), | |
| 158 | + CPUMF_EVENT_PTR(cf_z10, L1I_LMEM_SOURCED_WRITES), | |
| 159 | + CPUMF_EVENT_PTR(cf_z10, L1D_RO_EXCL_WRITES), | |
| 160 | + CPUMF_EVENT_PTR(cf_z10, L1I_CACHELINE_INVALIDATES), | |
| 161 | + CPUMF_EVENT_PTR(cf_z10, ITLB1_WRITES), | |
| 162 | + CPUMF_EVENT_PTR(cf_z10, DTLB1_WRITES), | |
| 163 | + CPUMF_EVENT_PTR(cf_z10, TLB2_PTE_WRITES), | |
| 164 | + CPUMF_EVENT_PTR(cf_z10, TLB2_CRSTE_WRITES), | |
| 165 | + CPUMF_EVENT_PTR(cf_z10, TLB2_CRSTE_HPAGE_WRITES), | |
| 166 | + CPUMF_EVENT_PTR(cf_z10, ITLB1_MISSES), | |
| 167 | + CPUMF_EVENT_PTR(cf_z10, DTLB1_MISSES), | |
| 168 | + CPUMF_EVENT_PTR(cf_z10, L2C_STORES_SENT), | |
| 169 | + NULL, | |
| 170 | +}; | |
| 171 | + | |
| 172 | +static struct attribute *cpumcf_z196_pmu_event_attr[] __initdata = { | |
| 173 | + CPUMF_EVENT_PTR(cf_z196, L1D_L2_SOURCED_WRITES), | |
| 174 | + CPUMF_EVENT_PTR(cf_z196, L1I_L2_SOURCED_WRITES), | |
| 175 | + CPUMF_EVENT_PTR(cf_z196, DTLB1_MISSES), | |
| 176 | + CPUMF_EVENT_PTR(cf_z196, ITLB1_MISSES), | |
| 177 | + CPUMF_EVENT_PTR(cf_z196, L2C_STORES_SENT), | |
| 178 | + CPUMF_EVENT_PTR(cf_z196, L1D_OFFBOOK_L3_SOURCED_WRITES), | |
| 179 | + CPUMF_EVENT_PTR(cf_z196, L1D_ONBOOK_L4_SOURCED_WRITES), | |
| 180 | + CPUMF_EVENT_PTR(cf_z196, L1I_ONBOOK_L4_SOURCED_WRITES), | |
| 181 | + CPUMF_EVENT_PTR(cf_z196, L1D_RO_EXCL_WRITES), | |
| 182 | + CPUMF_EVENT_PTR(cf_z196, L1D_OFFBOOK_L4_SOURCED_WRITES), | |
| 183 | + CPUMF_EVENT_PTR(cf_z196, L1I_OFFBOOK_L4_SOURCED_WRITES), | |
| 184 | + CPUMF_EVENT_PTR(cf_z196, DTLB1_HPAGE_WRITES), | |
| 185 | + CPUMF_EVENT_PTR(cf_z196, L1D_LMEM_SOURCED_WRITES), | |
| 186 | + CPUMF_EVENT_PTR(cf_z196, L1I_LMEM_SOURCED_WRITES), | |
| 187 | + CPUMF_EVENT_PTR(cf_z196, L1I_OFFBOOK_L3_SOURCED_WRITES), | |
| 188 | + CPUMF_EVENT_PTR(cf_z196, DTLB1_WRITES), | |
| 189 | + CPUMF_EVENT_PTR(cf_z196, ITLB1_WRITES), | |
| 190 | + CPUMF_EVENT_PTR(cf_z196, TLB2_PTE_WRITES), | |
| 191 | + CPUMF_EVENT_PTR(cf_z196, TLB2_CRSTE_HPAGE_WRITES), | |
| 192 | + CPUMF_EVENT_PTR(cf_z196, TLB2_CRSTE_WRITES), | |
| 193 | + CPUMF_EVENT_PTR(cf_z196, L1D_ONCHIP_L3_SOURCED_WRITES), | |
| 194 | + CPUMF_EVENT_PTR(cf_z196, L1D_OFFCHIP_L3_SOURCED_WRITES), | |
| 195 | + CPUMF_EVENT_PTR(cf_z196, L1I_ONCHIP_L3_SOURCED_WRITES), | |
| 196 | + CPUMF_EVENT_PTR(cf_z196, L1I_OFFCHIP_L3_SOURCED_WRITES), | |
| 197 | + NULL, | |
| 198 | +}; | |
| 199 | + | |
| 200 | +static struct attribute *cpumcf_zec12_pmu_event_attr[] __initdata = { | |
| 201 | + CPUMF_EVENT_PTR(cf_zec12, DTLB1_MISSES), | |
| 202 | + CPUMF_EVENT_PTR(cf_zec12, ITLB1_MISSES), | |
| 203 | + CPUMF_EVENT_PTR(cf_zec12, L1D_L2I_SOURCED_WRITES), | |
| 204 | + CPUMF_EVENT_PTR(cf_zec12, L1I_L2I_SOURCED_WRITES), | |
| 205 | + CPUMF_EVENT_PTR(cf_zec12, L1D_L2D_SOURCED_WRITES), | |
| 206 | + CPUMF_EVENT_PTR(cf_zec12, DTLB1_WRITES), | |
| 207 | + CPUMF_EVENT_PTR(cf_zec12, L1D_LMEM_SOURCED_WRITES), | |
| 208 | + CPUMF_EVENT_PTR(cf_zec12, L1I_LMEM_SOURCED_WRITES), | |
| 209 | + CPUMF_EVENT_PTR(cf_zec12, L1D_RO_EXCL_WRITES), | |
| 210 | + CPUMF_EVENT_PTR(cf_zec12, DTLB1_HPAGE_WRITES), | |
| 211 | + CPUMF_EVENT_PTR(cf_zec12, ITLB1_WRITES), | |
| 212 | + CPUMF_EVENT_PTR(cf_zec12, TLB2_PTE_WRITES), | |
| 213 | + CPUMF_EVENT_PTR(cf_zec12, TLB2_CRSTE_HPAGE_WRITES), | |
| 214 | + CPUMF_EVENT_PTR(cf_zec12, TLB2_CRSTE_WRITES), | |
| 215 | + CPUMF_EVENT_PTR(cf_zec12, L1D_ONCHIP_L3_SOURCED_WRITES), | |
| 216 | + CPUMF_EVENT_PTR(cf_zec12, L1D_OFFCHIP_L3_SOURCED_WRITES), | |
| 217 | + CPUMF_EVENT_PTR(cf_zec12, L1D_OFFBOOK_L3_SOURCED_WRITES), | |
| 218 | + CPUMF_EVENT_PTR(cf_zec12, L1D_ONBOOK_L4_SOURCED_WRITES), | |
| 219 | + CPUMF_EVENT_PTR(cf_zec12, L1D_OFFBOOK_L4_SOURCED_WRITES), | |
| 220 | + CPUMF_EVENT_PTR(cf_zec12, TX_NC_TEND), | |
| 221 | + CPUMF_EVENT_PTR(cf_zec12, L1D_ONCHIP_L3_SOURCED_WRITES_IV), | |
| 222 | + CPUMF_EVENT_PTR(cf_zec12, L1D_OFFCHIP_L3_SOURCED_WRITES_IV), | |
| 223 | + CPUMF_EVENT_PTR(cf_zec12, L1D_OFFBOOK_L3_SOURCED_WRITES_IV), | |
| 224 | + CPUMF_EVENT_PTR(cf_zec12, L1I_ONCHIP_L3_SOURCED_WRITES), | |
| 225 | + CPUMF_EVENT_PTR(cf_zec12, L1I_OFFCHIP_L3_SOURCED_WRITES), | |
| 226 | + CPUMF_EVENT_PTR(cf_zec12, L1I_OFFBOOK_L3_SOURCED_WRITES), | |
| 227 | + CPUMF_EVENT_PTR(cf_zec12, L1I_ONBOOK_L4_SOURCED_WRITES), | |
| 228 | + CPUMF_EVENT_PTR(cf_zec12, L1I_OFFBOOK_L4_SOURCED_WRITES), | |
| 229 | + CPUMF_EVENT_PTR(cf_zec12, TX_C_TEND), | |
| 230 | + CPUMF_EVENT_PTR(cf_zec12, L1I_ONCHIP_L3_SOURCED_WRITES_IV), | |
| 231 | + CPUMF_EVENT_PTR(cf_zec12, L1I_OFFCHIP_L3_SOURCED_WRITES_IV), | |
| 232 | + CPUMF_EVENT_PTR(cf_zec12, L1I_OFFBOOK_L3_SOURCED_WRITES_IV), | |
| 233 | + CPUMF_EVENT_PTR(cf_zec12, TX_NC_TABORT), | |
| 234 | + CPUMF_EVENT_PTR(cf_zec12, TX_C_TABORT_NO_SPECIAL), | |
| 235 | + CPUMF_EVENT_PTR(cf_zec12, TX_C_TABORT_SPECIAL), | |
| 236 | + NULL, | |
| 237 | +}; | |
| 238 | + | |
| 239 | +/* END: CPUM_CF COUNTER DEFINITIONS ===================================== */ | |
| 240 | + | |
| 241 | +static struct attribute_group cpumsf_pmu_events_group = { | |
| 242 | + .name = "events", | |
| 243 | + .attrs = cpumcf_pmu_event_attr, | |
| 244 | +}; | |
| 245 | + | |
| 246 | +PMU_FORMAT_ATTR(event, "config:0-63"); | |
| 247 | + | |
| 248 | +static struct attribute *cpumsf_pmu_format_attr[] = { | |
| 249 | + &format_attr_event.attr, | |
| 250 | + NULL, | |
| 251 | +}; | |
| 252 | + | |
| 253 | +static struct attribute_group cpumsf_pmu_format_group = { | |
| 254 | + .name = "format", | |
| 255 | + .attrs = cpumsf_pmu_format_attr, | |
| 256 | +}; | |
| 257 | + | |
| 258 | +static const struct attribute_group *cpumsf_pmu_attr_groups[] = { | |
| 259 | + &cpumsf_pmu_events_group, | |
| 260 | + &cpumsf_pmu_format_group, | |
| 261 | + NULL, | |
| 262 | +}; | |
| 263 | + | |
| 264 | + | |
| 265 | +static __init struct attribute **merge_attr(struct attribute **a, | |
| 266 | + struct attribute **b) | |
| 267 | +{ | |
| 268 | + struct attribute **new; | |
| 269 | + int j, i; | |
| 270 | + | |
| 271 | + for (j = 0; a[j]; j++) | |
| 272 | + ; | |
| 273 | + for (i = 0; b[i]; i++) | |
| 274 | + j++; | |
| 275 | + j++; | |
| 276 | + | |
| 277 | + new = kmalloc(sizeof(struct attribute *) * j, GFP_KERNEL); | |
| 278 | + if (!new) | |
| 279 | + return NULL; | |
| 280 | + j = 0; | |
| 281 | + for (i = 0; a[i]; i++) | |
| 282 | + new[j++] = a[i]; | |
| 283 | + for (i = 0; b[i]; i++) | |
| 284 | + new[j++] = b[i]; | |
| 285 | + new[j] = NULL; | |
| 286 | + | |
| 287 | + return new; | |
| 288 | +} | |
| 289 | + | |
| 290 | +__init const struct attribute_group **cpumf_cf_event_group(void) | |
| 291 | +{ | |
| 292 | + struct attribute **combined, **model; | |
| 293 | + struct cpuid cpu_id; | |
| 294 | + | |
| 295 | + get_cpu_id(&cpu_id); | |
| 296 | + switch (cpu_id.machine) { | |
| 297 | + case 0x2097: | |
| 298 | + case 0x2098: | |
| 299 | + model = cpumcf_z10_pmu_event_attr; | |
| 300 | + break; | |
| 301 | + case 0x2817: | |
| 302 | + case 0x2818: | |
| 303 | + model = cpumcf_z196_pmu_event_attr; | |
| 304 | + break; | |
| 305 | + case 0x2827: | |
| 306 | + case 0x2828: | |
| 307 | + model = cpumcf_zec12_pmu_event_attr; | |
| 308 | + break; | |
| 309 | + default: | |
| 310 | + model = NULL; | |
| 311 | + break; | |
| 312 | + }; | |
| 313 | + | |
| 314 | + if (!model) | |
| 315 | + goto out; | |
| 316 | + | |
| 317 | + combined = merge_attr(cpumcf_pmu_event_attr, model); | |
| 318 | + if (combined) | |
| 319 | + cpumsf_pmu_events_group.attrs = combined; | |
| 320 | +out: | |
| 321 | + return cpumsf_pmu_attr_groups; | |
| 322 | +} | |
| @@ -0,0 +1,1641 @@ | ||
| 1 | +/* | |
| 2 | + * Performance event support for the System z CPU-measurement Sampling Facility | |
| 3 | + * | |
| 4 | + * Copyright IBM Corp. 2013 | |
| 5 | + * Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com> | |
| 6 | + * | |
| 7 | + * This program is free software; you can redistribute it and/or modify | |
| 8 | + * it under the terms of the GNU General Public License (version 2 only) | |
| 9 | + * as published by the Free Software Foundation. | |
| 10 | + */ | |
| 11 | +#define KMSG_COMPONENT "cpum_sf" | |
| 12 | +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | |
| 13 | + | |
| 14 | +#include <linux/kernel.h> | |
| 15 | +#include <linux/kernel_stat.h> | |
| 16 | +#include <linux/perf_event.h> | |
| 17 | +#include <linux/percpu.h> | |
| 18 | +#include <linux/notifier.h> | |
| 19 | +#include <linux/export.h> | |
| 20 | +#include <linux/slab.h> | |
| 21 | +#include <linux/mm.h> | |
| 22 | +#include <linux/moduleparam.h> | |
| 23 | +#include <asm/cpu_mf.h> | |
| 24 | +#include <asm/irq.h> | |
| 25 | +#include <asm/debug.h> | |
| 26 | +#include <asm/timex.h> | |
| 27 | + | |
| 28 | +/* Minimum number of sample-data-block-tables: | |
| 29 | + * At least one table is required for the sampling buffer structure. | |
| 30 | + * A single table contains up to 511 pointers to sample-data-blocks. | |
| 31 | + */ | |
| 32 | +#define CPUM_SF_MIN_SDBT 1 | |
| 33 | + | |
| 34 | +/* Number of sample-data-blocks per sample-data-block-table (SDBT): | |
| 35 | + * A table contains SDB pointers (8 bytes) and one table-link entry | |
| 36 | + * that points to the origin of the next SDBT. | |
| 37 | + */ | |
| 38 | +#define CPUM_SF_SDB_PER_TABLE ((PAGE_SIZE - 8) / 8) | |
| 39 | + | |
| 40 | +/* Maximum page offset for an SDBT table-link entry: | |
| 41 | + * If this page offset is reached, a table-link entry to the next SDBT | |
| 42 | + * must be added. | |
| 43 | + */ | |
| 44 | +#define CPUM_SF_SDBT_TL_OFFSET (CPUM_SF_SDB_PER_TABLE * 8) | |
| 45 | +static inline int require_table_link(const void *sdbt) | |
| 46 | +{ | |
| 47 | + return ((unsigned long) sdbt & ~PAGE_MASK) == CPUM_SF_SDBT_TL_OFFSET; | |
| 48 | +} | |
| 49 | + | |
| 50 | +/* Minimum and maximum sampling buffer sizes: | |
| 51 | + * | |
| 52 | + * This number represents the maximum size of the sampling buffer taking | |
| 53 | + * the number of sample-data-block-tables into account. Note that these | |
| 54 | + * numbers apply to the basic-sampling function only. | |
| 55 | + * The maximum number of SDBs is increased by CPUM_SF_SDB_DIAG_FACTOR if | |
| 56 | + * the diagnostic-sampling function is active. | |
| 57 | + * | |
| 58 | + * Sampling buffer size Buffer characteristics | |
| 59 | + * --------------------------------------------------- | |
| 60 | + * 64KB == 16 pages (4KB per page) | |
| 61 | + * 1 page for SDB-tables | |
| 62 | + * 15 pages for SDBs | |
| 63 | + * | |
| 64 | + * 32MB == 8192 pages (4KB per page) | |
| 65 | + * 16 pages for SDB-tables | |
| 66 | + * 8176 pages for SDBs | |
| 67 | + */ | |
| 68 | +static unsigned long __read_mostly CPUM_SF_MIN_SDB = 15; | |
| 69 | +static unsigned long __read_mostly CPUM_SF_MAX_SDB = 8176; | |
| 70 | +static unsigned long __read_mostly CPUM_SF_SDB_DIAG_FACTOR = 1; | |
| 71 | + | |
| 72 | +struct sf_buffer { | |
| 73 | + unsigned long *sdbt; /* Sample-data-block-table origin */ | |
| 74 | + /* buffer characteristics (required for buffer increments) */ | |
| 75 | + unsigned long num_sdb; /* Number of sample-data-blocks */ | |
| 76 | + unsigned long num_sdbt; /* Number of sample-data-block-tables */ | |
| 77 | + unsigned long *tail; /* last sample-data-block-table */ | |
| 78 | +}; | |
| 79 | + | |
| 80 | +struct cpu_hw_sf { | |
| 81 | + /* CPU-measurement sampling information block */ | |
| 82 | + struct hws_qsi_info_block qsi; | |
| 83 | + /* CPU-measurement sampling control block */ | |
| 84 | + struct hws_lsctl_request_block lsctl; | |
| 85 | + struct sf_buffer sfb; /* Sampling buffer */ | |
| 86 | + unsigned int flags; /* Status flags */ | |
| 87 | + struct perf_event *event; /* Scheduled perf event */ | |
| 88 | +}; | |
| 89 | +static DEFINE_PER_CPU(struct cpu_hw_sf, cpu_hw_sf); | |
| 90 | + | |
| 91 | +/* Debug feature */ | |
| 92 | +static debug_info_t *sfdbg; | |
| 93 | + | |
| 94 | +/* | |
| 95 | + * sf_disable() - Switch off sampling facility | |
| 96 | + */ | |
| 97 | +static int sf_disable(void) | |
| 98 | +{ | |
| 99 | + struct hws_lsctl_request_block sreq; | |
| 100 | + | |
| 101 | + memset(&sreq, 0, sizeof(sreq)); | |
| 102 | + return lsctl(&sreq); | |
| 103 | +} | |
| 104 | + | |
| 105 | +/* | |
| 106 | + * sf_buffer_available() - Check for an allocated sampling buffer | |
| 107 | + */ | |
| 108 | +static int sf_buffer_available(struct cpu_hw_sf *cpuhw) | |
| 109 | +{ | |
| 110 | + return !!cpuhw->sfb.sdbt; | |
| 111 | +} | |
| 112 | + | |
| 113 | +/* | |
| 114 | + * deallocate sampling facility buffer | |
| 115 | + */ | |
| 116 | +static void free_sampling_buffer(struct sf_buffer *sfb) | |
| 117 | +{ | |
| 118 | + unsigned long *sdbt, *curr; | |
| 119 | + | |
| 120 | + if (!sfb->sdbt) | |
| 121 | + return; | |
| 122 | + | |
| 123 | + sdbt = sfb->sdbt; | |
| 124 | + curr = sdbt; | |
| 125 | + | |
| 126 | + /* Free the SDBT after all SDBs are processed... */ | |
| 127 | + while (1) { | |
| 128 | + if (!*curr || !sdbt) | |
| 129 | + break; | |
| 130 | + | |
| 131 | + /* Process table-link entries */ | |
| 132 | + if (is_link_entry(curr)) { | |
| 133 | + curr = get_next_sdbt(curr); | |
| 134 | + if (sdbt) | |
| 135 | + free_page((unsigned long) sdbt); | |
| 136 | + | |
| 137 | + /* If the origin is reached, sampling buffer is freed */ | |
| 138 | + if (curr == sfb->sdbt) | |
| 139 | + break; | |
| 140 | + else | |
| 141 | + sdbt = curr; | |
| 142 | + } else { | |
| 143 | + /* Process SDB pointer */ | |
| 144 | + if (*curr) { | |
| 145 | + free_page(*curr); | |
| 146 | + curr++; | |
| 147 | + } | |
| 148 | + } | |
| 149 | + } | |
| 150 | + | |
| 151 | + debug_sprintf_event(sfdbg, 5, | |
| 152 | + "free_sampling_buffer: freed sdbt=%p\n", sfb->sdbt); | |
| 153 | + memset(sfb, 0, sizeof(*sfb)); | |
| 154 | +} | |
| 155 | + | |
| 156 | +static int alloc_sample_data_block(unsigned long *sdbt, gfp_t gfp_flags) | |
| 157 | +{ | |
| 158 | + unsigned long sdb, *trailer; | |
| 159 | + | |
| 160 | + /* Allocate and initialize sample-data-block */ | |
| 161 | + sdb = get_zeroed_page(gfp_flags); | |
| 162 | + if (!sdb) | |
| 163 | + return -ENOMEM; | |
| 164 | + trailer = trailer_entry_ptr(sdb); | |
| 165 | + *trailer = SDB_TE_ALERT_REQ_MASK; | |
| 166 | + | |
| 167 | + /* Link SDB into the sample-data-block-table */ | |
| 168 | + *sdbt = sdb; | |
| 169 | + | |
| 170 | + return 0; | |
| 171 | +} | |
| 172 | + | |
| 173 | +/* | |
| 174 | + * realloc_sampling_buffer() - extend sampler memory | |
| 175 | + * | |
| 176 | + * Allocates new sample-data-blocks and adds them to the specified sampling | |
| 177 | + * buffer memory. | |
| 178 | + * | |
| 179 | + * Important: This modifies the sampling buffer and must be called when the | |
| 180 | + * sampling facility is disabled. | |
| 181 | + * | |
| 182 | + * Returns zero on success, non-zero otherwise. | |
| 183 | + */ | |
| 184 | +static int realloc_sampling_buffer(struct sf_buffer *sfb, | |
| 185 | + unsigned long num_sdb, gfp_t gfp_flags) | |
| 186 | +{ | |
| 187 | + int i, rc; | |
| 188 | + unsigned long *new, *tail; | |
| 189 | + | |
| 190 | + if (!sfb->sdbt || !sfb->tail) | |
| 191 | + return -EINVAL; | |
| 192 | + | |
| 193 | + if (!is_link_entry(sfb->tail)) | |
| 194 | + return -EINVAL; | |
| 195 | + | |
| 196 | + /* Append to the existing sampling buffer, overwriting the table-link | |
| 197 | + * register. | |
| 198 | + * The tail variables always points to the "tail" (last and table-link) | |
| 199 | + * entry in an SDB-table. | |
| 200 | + */ | |
| 201 | + tail = sfb->tail; | |
| 202 | + | |
| 203 | + /* Do a sanity check whether the table-link entry points to | |
| 204 | + * the sampling buffer origin. | |
| 205 | + */ | |
| 206 | + if (sfb->sdbt != get_next_sdbt(tail)) { | |
| 207 | + debug_sprintf_event(sfdbg, 3, "realloc_sampling_buffer: " | |
| 208 | + "sampling buffer is not linked: origin=%p" | |
| 209 | + "tail=%p\n", | |
| 210 | + (void *) sfb->sdbt, (void *) tail); | |
| 211 | + return -EINVAL; | |
| 212 | + } | |
| 213 | + | |
| 214 | + /* Allocate remaining SDBs */ | |
| 215 | + rc = 0; | |
| 216 | + for (i = 0; i < num_sdb; i++) { | |
| 217 | + /* Allocate a new SDB-table if it is full. */ | |
| 218 | + if (require_table_link(tail)) { | |
| 219 | + new = (unsigned long *) get_zeroed_page(gfp_flags); | |
| 220 | + if (!new) { | |
| 221 | + rc = -ENOMEM; | |
| 222 | + break; | |
| 223 | + } | |
| 224 | + sfb->num_sdbt++; | |
| 225 | + /* Link current page to tail of chain */ | |
| 226 | + *tail = (unsigned long)(void *) new + 1; | |
| 227 | + tail = new; | |
| 228 | + } | |
| 229 | + | |
| 230 | + /* Allocate a new sample-data-block. | |
| 231 | + * If there is not enough memory, stop the realloc process | |
| 232 | + * and simply use what was allocated. If this is a temporary | |
| 233 | + * issue, a new realloc call (if required) might succeed. | |
| 234 | + */ | |
| 235 | + rc = alloc_sample_data_block(tail, gfp_flags); | |
| 236 | + if (rc) | |
| 237 | + break; | |
| 238 | + sfb->num_sdb++; | |
| 239 | + tail++; | |
| 240 | + } | |
| 241 | + | |
| 242 | + /* Link sampling buffer to its origin */ | |
| 243 | + *tail = (unsigned long) sfb->sdbt + 1; | |
| 244 | + sfb->tail = tail; | |
| 245 | + | |
| 246 | + debug_sprintf_event(sfdbg, 4, "realloc_sampling_buffer: new buffer" | |
| 247 | + " settings: sdbt=%lu sdb=%lu\n", | |
| 248 | + sfb->num_sdbt, sfb->num_sdb); | |
| 249 | + return rc; | |
| 250 | +} | |
| 251 | + | |
| 252 | +/* | |
| 253 | + * allocate_sampling_buffer() - allocate sampler memory | |
| 254 | + * | |
| 255 | + * Allocates and initializes a sampling buffer structure using the | |
| 256 | + * specified number of sample-data-blocks (SDB). For each allocation, | |
| 257 | + * a 4K page is used. The number of sample-data-block-tables (SDBT) | |
| 258 | + * are calculated from SDBs. | |
| 259 | + * Also set the ALERT_REQ mask in each SDBs trailer. | |
| 260 | + * | |
| 261 | + * Returns zero on success, non-zero otherwise. | |
| 262 | + */ | |
| 263 | +static int alloc_sampling_buffer(struct sf_buffer *sfb, unsigned long num_sdb) | |
| 264 | +{ | |
| 265 | + int rc; | |
| 266 | + | |
| 267 | + if (sfb->sdbt) | |
| 268 | + return -EINVAL; | |
| 269 | + | |
| 270 | + /* Allocate the sample-data-block-table origin */ | |
| 271 | + sfb->sdbt = (unsigned long *) get_zeroed_page(GFP_KERNEL); | |
| 272 | + if (!sfb->sdbt) | |
| 273 | + return -ENOMEM; | |
| 274 | + sfb->num_sdb = 0; | |
| 275 | + sfb->num_sdbt = 1; | |
| 276 | + | |
| 277 | + /* Link the table origin to point to itself to prepare for | |
| 278 | + * realloc_sampling_buffer() invocation. | |
| 279 | + */ | |
| 280 | + sfb->tail = sfb->sdbt; | |
| 281 | + *sfb->tail = (unsigned long)(void *) sfb->sdbt + 1; | |
| 282 | + | |
| 283 | + /* Allocate requested number of sample-data-blocks */ | |
| 284 | + rc = realloc_sampling_buffer(sfb, num_sdb, GFP_KERNEL); | |
| 285 | + if (rc) { | |
| 286 | + free_sampling_buffer(sfb); | |
| 287 | + debug_sprintf_event(sfdbg, 4, "alloc_sampling_buffer: " | |
| 288 | + "realloc_sampling_buffer failed with rc=%i\n", rc); | |
| 289 | + } else | |
| 290 | + debug_sprintf_event(sfdbg, 4, | |
| 291 | + "alloc_sampling_buffer: tear=%p dear=%p\n", | |
| 292 | + sfb->sdbt, (void *) *sfb->sdbt); | |
| 293 | + return rc; | |
| 294 | +} | |
| 295 | + | |
| 296 | +static void sfb_set_limits(unsigned long min, unsigned long max) | |
| 297 | +{ | |
| 298 | + struct hws_qsi_info_block si; | |
| 299 | + | |
| 300 | + CPUM_SF_MIN_SDB = min; | |
| 301 | + CPUM_SF_MAX_SDB = max; | |
| 302 | + | |
| 303 | + memset(&si, 0, sizeof(si)); | |
| 304 | + if (!qsi(&si)) | |
| 305 | + CPUM_SF_SDB_DIAG_FACTOR = DIV_ROUND_UP(si.dsdes, si.bsdes); | |
| 306 | +} | |
| 307 | + | |
| 308 | +static unsigned long sfb_max_limit(struct hw_perf_event *hwc) | |
| 309 | +{ | |
| 310 | + return SAMPL_DIAG_MODE(hwc) ? CPUM_SF_MAX_SDB * CPUM_SF_SDB_DIAG_FACTOR | |
| 311 | + : CPUM_SF_MAX_SDB; | |
| 312 | +} | |
| 313 | + | |
| 314 | +static unsigned long sfb_pending_allocs(struct sf_buffer *sfb, | |
| 315 | + struct hw_perf_event *hwc) | |
| 316 | +{ | |
| 317 | + if (!sfb->sdbt) | |
| 318 | + return SFB_ALLOC_REG(hwc); | |
| 319 | + if (SFB_ALLOC_REG(hwc) > sfb->num_sdb) | |
| 320 | + return SFB_ALLOC_REG(hwc) - sfb->num_sdb; | |
| 321 | + return 0; | |
| 322 | +} | |
| 323 | + | |
| 324 | +static int sfb_has_pending_allocs(struct sf_buffer *sfb, | |
| 325 | + struct hw_perf_event *hwc) | |
| 326 | +{ | |
| 327 | + return sfb_pending_allocs(sfb, hwc) > 0; | |
| 328 | +} | |
| 329 | + | |
| 330 | +static void sfb_account_allocs(unsigned long num, struct hw_perf_event *hwc) | |
| 331 | +{ | |
| 332 | + /* Limit the number of SDBs to not exceed the maximum */ | |
| 333 | + num = min_t(unsigned long, num, sfb_max_limit(hwc) - SFB_ALLOC_REG(hwc)); | |
| 334 | + if (num) | |
| 335 | + SFB_ALLOC_REG(hwc) += num; | |
| 336 | +} | |
| 337 | + | |
| 338 | +static void sfb_init_allocs(unsigned long num, struct hw_perf_event *hwc) | |
| 339 | +{ | |
| 340 | + SFB_ALLOC_REG(hwc) = 0; | |
| 341 | + sfb_account_allocs(num, hwc); | |
| 342 | +} | |
| 343 | + | |
| 344 | +static size_t event_sample_size(struct hw_perf_event *hwc) | |
| 345 | +{ | |
| 346 | + struct sf_raw_sample *sfr = (struct sf_raw_sample *) RAWSAMPLE_REG(hwc); | |
| 347 | + size_t sample_size; | |
| 348 | + | |
| 349 | + /* The sample size depends on the sampling function: The basic-sampling | |
| 350 | + * function must be always enabled, diagnostic-sampling function is | |
| 351 | + * optional. | |
| 352 | + */ | |
| 353 | + sample_size = sfr->bsdes; | |
| 354 | + if (SAMPL_DIAG_MODE(hwc)) | |
| 355 | + sample_size += sfr->dsdes; | |
| 356 | + | |
| 357 | + return sample_size; | |
| 358 | +} | |
| 359 | + | |
| 360 | +static void deallocate_buffers(struct cpu_hw_sf *cpuhw) | |
| 361 | +{ | |
| 362 | + if (cpuhw->sfb.sdbt) | |
| 363 | + free_sampling_buffer(&cpuhw->sfb); | |
| 364 | +} | |
| 365 | + | |
| 366 | +static int allocate_buffers(struct cpu_hw_sf *cpuhw, struct hw_perf_event *hwc) | |
| 367 | +{ | |
| 368 | + unsigned long n_sdb, freq, factor; | |
| 369 | + size_t sfr_size, sample_size; | |
| 370 | + struct sf_raw_sample *sfr; | |
| 371 | + | |
| 372 | + /* Allocate raw sample buffer | |
| 373 | + * | |
| 374 | + * The raw sample buffer is used to temporarily store sampling data | |
| 375 | + * entries for perf raw sample processing. The buffer size mainly | |
| 376 | + * depends on the size of diagnostic-sampling data entries which is | |
| 377 | + * machine-specific. The exact size calculation includes: | |
| 378 | + * 1. The first 4 bytes of diagnostic-sampling data entries are | |
| 379 | + * already reflected in the sf_raw_sample structure. Subtract | |
| 380 | + * these bytes. | |
| 381 | + * 2. The perf raw sample data must be 8-byte aligned (u64) and | |
| 382 | + * perf's internal data size must be considered too. So add | |
| 383 | + * an additional u32 for correct alignment and subtract before | |
| 384 | + * allocating the buffer. | |
| 385 | + * 3. Store the raw sample buffer pointer in the perf event | |
| 386 | + * hardware structure. | |
| 387 | + */ | |
| 388 | + sfr_size = ALIGN((sizeof(*sfr) - sizeof(sfr->diag) + cpuhw->qsi.dsdes) + | |
| 389 | + sizeof(u32), sizeof(u64)); | |
| 390 | + sfr_size -= sizeof(u32); | |
| 391 | + sfr = kzalloc(sfr_size, GFP_KERNEL); | |
| 392 | + if (!sfr) | |
| 393 | + return -ENOMEM; | |
| 394 | + sfr->size = sfr_size; | |
| 395 | + sfr->bsdes = cpuhw->qsi.bsdes; | |
| 396 | + sfr->dsdes = cpuhw->qsi.dsdes; | |
| 397 | + RAWSAMPLE_REG(hwc) = (unsigned long) sfr; | |
| 398 | + | |
| 399 | + /* Calculate sampling buffers using 4K pages | |
| 400 | + * | |
| 401 | + * 1. Determine the sample data size which depends on the used | |
| 402 | + * sampling functions, for example, basic-sampling or | |
| 403 | + * basic-sampling with diagnostic-sampling. | |
| 404 | + * | |
| 405 | + * 2. Use the sampling frequency as input. The sampling buffer is | |
| 406 | + * designed for almost one second. This can be adjusted through | |
| 407 | + * the "factor" variable. | |
| 408 | + * In any case, alloc_sampling_buffer() sets the Alert Request | |
| 409 | + * Control indicator to trigger a measurement-alert to harvest | |
| 410 | + * sample-data-blocks (sdb). | |
| 411 | + * | |
| 412 | + * 3. Compute the number of sample-data-blocks and ensure a minimum | |
| 413 | + * of CPUM_SF_MIN_SDB. Also ensure the upper limit does not | |
| 414 | + * exceed a "calculated" maximum. The symbolic maximum is | |
| 415 | + * designed for basic-sampling only and needs to be increased if | |
| 416 | + * diagnostic-sampling is active. | |
| 417 | + * See also the remarks for these symbolic constants. | |
| 418 | + * | |
| 419 | + * 4. Compute the number of sample-data-block-tables (SDBT) and | |
| 420 | + * ensure a minimum of CPUM_SF_MIN_SDBT (one table can manage up | |
| 421 | + * to 511 SDBs). | |
| 422 | + */ | |
| 423 | + sample_size = event_sample_size(hwc); | |
| 424 | + freq = sample_rate_to_freq(&cpuhw->qsi, SAMPL_RATE(hwc)); | |
| 425 | + factor = 1; | |
| 426 | + n_sdb = DIV_ROUND_UP(freq, factor * ((PAGE_SIZE-64) / sample_size)); | |
| 427 | + if (n_sdb < CPUM_SF_MIN_SDB) | |
| 428 | + n_sdb = CPUM_SF_MIN_SDB; | |
| 429 | + | |
| 430 | + /* If there is already a sampling buffer allocated, it is very likely | |
| 431 | + * that the sampling facility is enabled too. If the event to be | |
| 432 | + * initialized requires a greater sampling buffer, the allocation must | |
| 433 | + * be postponed. Changing the sampling buffer requires the sampling | |
| 434 | + * facility to be in the disabled state. So, account the number of | |
| 435 | + * required SDBs and let cpumsf_pmu_enable() resize the buffer just | |
| 436 | + * before the event is started. | |
| 437 | + */ | |
| 438 | + sfb_init_allocs(n_sdb, hwc); | |
| 439 | + if (sf_buffer_available(cpuhw)) | |
| 440 | + return 0; | |
| 441 | + | |
| 442 | + debug_sprintf_event(sfdbg, 3, | |
| 443 | + "allocate_buffers: rate=%lu f=%lu sdb=%lu/%lu" | |
| 444 | + " sample_size=%lu cpuhw=%p\n", | |
| 445 | + SAMPL_RATE(hwc), freq, n_sdb, sfb_max_limit(hwc), | |
| 446 | + sample_size, cpuhw); | |
| 447 | + | |
| 448 | + return alloc_sampling_buffer(&cpuhw->sfb, | |
| 449 | + sfb_pending_allocs(&cpuhw->sfb, hwc)); | |
| 450 | +} | |
| 451 | + | |
| 452 | +static unsigned long min_percent(unsigned int percent, unsigned long base, | |
| 453 | + unsigned long min) | |
| 454 | +{ | |
| 455 | + return min_t(unsigned long, min, DIV_ROUND_UP(percent * base, 100)); | |
| 456 | +} | |
| 457 | + | |
| 458 | +static unsigned long compute_sfb_extent(unsigned long ratio, unsigned long base) | |
| 459 | +{ | |
| 460 | + /* Use a percentage-based approach to extend the sampling facility | |
| 461 | + * buffer. Accept up to 5% sample data loss. | |
| 462 | + * Vary the extents between 1% to 5% of the current number of | |
| 463 | + * sample-data-blocks. | |
| 464 | + */ | |
| 465 | + if (ratio <= 5) | |
| 466 | + return 0; | |
| 467 | + if (ratio <= 25) | |
| 468 | + return min_percent(1, base, 1); | |
| 469 | + if (ratio <= 50) | |
| 470 | + return min_percent(1, base, 1); | |
| 471 | + if (ratio <= 75) | |
| 472 | + return min_percent(2, base, 2); | |
| 473 | + if (ratio <= 100) | |
| 474 | + return min_percent(3, base, 3); | |
| 475 | + if (ratio <= 250) | |
| 476 | + return min_percent(4, base, 4); | |
| 477 | + | |
| 478 | + return min_percent(5, base, 8); | |
| 479 | +} | |
| 480 | + | |
| 481 | +static void sfb_account_overflows(struct cpu_hw_sf *cpuhw, | |
| 482 | + struct hw_perf_event *hwc) | |
| 483 | +{ | |
| 484 | + unsigned long ratio, num; | |
| 485 | + | |
| 486 | + if (!OVERFLOW_REG(hwc)) | |
| 487 | + return; | |
| 488 | + | |
| 489 | + /* The sample_overflow contains the average number of sample data | |
| 490 | + * that has been lost because sample-data-blocks were full. | |
| 491 | + * | |
| 492 | + * Calculate the total number of sample data entries that has been | |
| 493 | + * discarded. Then calculate the ratio of lost samples to total samples | |
| 494 | + * per second in percent. | |
| 495 | + */ | |
| 496 | + ratio = DIV_ROUND_UP(100 * OVERFLOW_REG(hwc) * cpuhw->sfb.num_sdb, | |
| 497 | + sample_rate_to_freq(&cpuhw->qsi, SAMPL_RATE(hwc))); | |
| 498 | + | |
| 499 | + /* Compute number of sample-data-blocks */ | |
| 500 | + num = compute_sfb_extent(ratio, cpuhw->sfb.num_sdb); | |
| 501 | + if (num) | |
| 502 | + sfb_account_allocs(num, hwc); | |
| 503 | + | |
| 504 | + debug_sprintf_event(sfdbg, 5, "sfb: overflow: overflow=%llu ratio=%lu" | |
| 505 | + " num=%lu\n", OVERFLOW_REG(hwc), ratio, num); | |
| 506 | + OVERFLOW_REG(hwc) = 0; | |
| 507 | +} | |
| 508 | + | |
| 509 | +/* extend_sampling_buffer() - Extend sampling buffer | |
| 510 | + * @sfb: Sampling buffer structure (for local CPU) | |
| 511 | + * @hwc: Perf event hardware structure | |
| 512 | + * | |
| 513 | + * Use this function to extend the sampling buffer based on the overflow counter | |
| 514 | + * and postponed allocation extents stored in the specified Perf event hardware. | |
| 515 | + * | |
| 516 | + * Important: This function disables the sampling facility in order to safely | |
| 517 | + * change the sampling buffer structure. Do not call this function | |
| 518 | + * when the PMU is active. | |
| 519 | + */ | |
| 520 | +static void extend_sampling_buffer(struct sf_buffer *sfb, | |
| 521 | + struct hw_perf_event *hwc) | |
| 522 | +{ | |
| 523 | + unsigned long num, num_old; | |
| 524 | + int rc; | |
| 525 | + | |
| 526 | + num = sfb_pending_allocs(sfb, hwc); | |
| 527 | + if (!num) | |
| 528 | + return; | |
| 529 | + num_old = sfb->num_sdb; | |
| 530 | + | |
| 531 | + /* Disable the sampling facility to reset any states and also | |
| 532 | + * clear pending measurement alerts. | |
| 533 | + */ | |
| 534 | + sf_disable(); | |
| 535 | + | |
| 536 | + /* Extend the sampling buffer. | |
| 537 | + * This memory allocation typically happens in an atomic context when | |
| 538 | + * called by perf. Because this is a reallocation, it is fine if the | |
| 539 | + * new SDB-request cannot be satisfied immediately. | |
| 540 | + */ | |
| 541 | + rc = realloc_sampling_buffer(sfb, num, GFP_ATOMIC); | |
| 542 | + if (rc) | |
| 543 | + debug_sprintf_event(sfdbg, 5, "sfb: extend: realloc " | |
| 544 | + "failed with rc=%i\n", rc); | |
| 545 | + | |
| 546 | + if (sfb_has_pending_allocs(sfb, hwc)) | |
| 547 | + debug_sprintf_event(sfdbg, 5, "sfb: extend: " | |
| 548 | + "req=%lu alloc=%lu remaining=%lu\n", | |
| 549 | + num, sfb->num_sdb - num_old, | |
| 550 | + sfb_pending_allocs(sfb, hwc)); | |
| 551 | +} | |
| 552 | + | |
| 553 | + | |
| 554 | +/* Number of perf events counting hardware events */ | |
| 555 | +static atomic_t num_events; | |
| 556 | +/* Used to avoid races in calling reserve/release_cpumf_hardware */ | |
| 557 | +static DEFINE_MUTEX(pmc_reserve_mutex); | |
| 558 | + | |
| 559 | +#define PMC_INIT 0 | |
| 560 | +#define PMC_RELEASE 1 | |
| 561 | +#define PMC_FAILURE 2 | |
| 562 | +static void setup_pmc_cpu(void *flags) | |
| 563 | +{ | |
| 564 | + int err; | |
| 565 | + struct cpu_hw_sf *cpusf = &__get_cpu_var(cpu_hw_sf); | |
| 566 | + | |
| 567 | + err = 0; | |
| 568 | + switch (*((int *) flags)) { | |
| 569 | + case PMC_INIT: | |
| 570 | + memset(cpusf, 0, sizeof(*cpusf)); | |
| 571 | + err = qsi(&cpusf->qsi); | |
| 572 | + if (err) | |
| 573 | + break; | |
| 574 | + cpusf->flags |= PMU_F_RESERVED; | |
| 575 | + err = sf_disable(); | |
| 576 | + if (err) | |
| 577 | + pr_err("Switching off the sampling facility failed " | |
| 578 | + "with rc=%i\n", err); | |
| 579 | + debug_sprintf_event(sfdbg, 5, | |
| 580 | + "setup_pmc_cpu: initialized: cpuhw=%p\n", cpusf); | |
| 581 | + break; | |
| 582 | + case PMC_RELEASE: | |
| 583 | + cpusf->flags &= ~PMU_F_RESERVED; | |
| 584 | + err = sf_disable(); | |
| 585 | + if (err) { | |
| 586 | + pr_err("Switching off the sampling facility failed " | |
| 587 | + "with rc=%i\n", err); | |
| 588 | + } else | |
| 589 | + deallocate_buffers(cpusf); | |
| 590 | + debug_sprintf_event(sfdbg, 5, | |
| 591 | + "setup_pmc_cpu: released: cpuhw=%p\n", cpusf); | |
| 592 | + break; | |
| 593 | + } | |
| 594 | + if (err) | |
| 595 | + *((int *) flags) |= PMC_FAILURE; | |
| 596 | +} | |
| 597 | + | |
| 598 | +static void release_pmc_hardware(void) | |
| 599 | +{ | |
| 600 | + int flags = PMC_RELEASE; | |
| 601 | + | |
| 602 | + irq_subclass_unregister(IRQ_SUBCLASS_MEASUREMENT_ALERT); | |
| 603 | + on_each_cpu(setup_pmc_cpu, &flags, 1); | |
| 604 | + perf_release_sampling(); | |
| 605 | +} | |
| 606 | + | |
| 607 | +static int reserve_pmc_hardware(void) | |
| 608 | +{ | |
| 609 | + int flags = PMC_INIT; | |
| 610 | + int err; | |
| 611 | + | |
| 612 | + err = perf_reserve_sampling(); | |
| 613 | + if (err) | |
| 614 | + return err; | |
| 615 | + on_each_cpu(setup_pmc_cpu, &flags, 1); | |
| 616 | + if (flags & PMC_FAILURE) { | |
| 617 | + release_pmc_hardware(); | |
| 618 | + return -ENODEV; | |
| 619 | + } | |
| 620 | + irq_subclass_register(IRQ_SUBCLASS_MEASUREMENT_ALERT); | |
| 621 | + | |
| 622 | + return 0; | |
| 623 | +} | |
| 624 | + | |
| 625 | +static void hw_perf_event_destroy(struct perf_event *event) | |
| 626 | +{ | |
| 627 | + /* Free raw sample buffer */ | |
| 628 | + if (RAWSAMPLE_REG(&event->hw)) | |
| 629 | + kfree((void *) RAWSAMPLE_REG(&event->hw)); | |
| 630 | + | |
| 631 | + /* Release PMC if this is the last perf event */ | |
| 632 | + if (!atomic_add_unless(&num_events, -1, 1)) { | |
| 633 | + mutex_lock(&pmc_reserve_mutex); | |
| 634 | + if (atomic_dec_return(&num_events) == 0) | |
| 635 | + release_pmc_hardware(); | |
| 636 | + mutex_unlock(&pmc_reserve_mutex); | |
| 637 | + } | |
| 638 | +} | |
| 639 | + | |
| 640 | +static void hw_init_period(struct hw_perf_event *hwc, u64 period) | |
| 641 | +{ | |
| 642 | + hwc->sample_period = period; | |
| 643 | + hwc->last_period = hwc->sample_period; | |
| 644 | + local64_set(&hwc->period_left, hwc->sample_period); | |
| 645 | +} | |
| 646 | + | |
| 647 | +static void hw_reset_registers(struct hw_perf_event *hwc, | |
| 648 | + unsigned long *sdbt_origin) | |
| 649 | +{ | |
| 650 | + struct sf_raw_sample *sfr; | |
| 651 | + | |
| 652 | + /* (Re)set to first sample-data-block-table */ | |
| 653 | + TEAR_REG(hwc) = (unsigned long) sdbt_origin; | |
| 654 | + | |
| 655 | + /* (Re)set raw sampling buffer register */ | |
| 656 | + sfr = (struct sf_raw_sample *) RAWSAMPLE_REG(hwc); | |
| 657 | + memset(&sfr->basic, 0, sizeof(sfr->basic)); | |
| 658 | + memset(&sfr->diag, 0, sfr->dsdes); | |
| 659 | +} | |
| 660 | + | |
| 661 | +static unsigned long hw_limit_rate(const struct hws_qsi_info_block *si, | |
| 662 | + unsigned long rate) | |
| 663 | +{ | |
| 664 | + return clamp_t(unsigned long, rate, | |
| 665 | + si->min_sampl_rate, si->max_sampl_rate); | |
| 666 | +} | |
| 667 | + | |
| 668 | +static int __hw_perf_event_init(struct perf_event *event) | |
| 669 | +{ | |
| 670 | + struct cpu_hw_sf *cpuhw; | |
| 671 | + struct hws_qsi_info_block si; | |
| 672 | + struct perf_event_attr *attr = &event->attr; | |
| 673 | + struct hw_perf_event *hwc = &event->hw; | |
| 674 | + unsigned long rate; | |
| 675 | + int cpu, err; | |
| 676 | + | |
| 677 | + /* Reserve CPU-measurement sampling facility */ | |
| 678 | + err = 0; | |
| 679 | + if (!atomic_inc_not_zero(&num_events)) { | |
| 680 | + mutex_lock(&pmc_reserve_mutex); | |
| 681 | + if (atomic_read(&num_events) == 0 && reserve_pmc_hardware()) | |
| 682 | + err = -EBUSY; | |
| 683 | + else | |
| 684 | + atomic_inc(&num_events); | |
| 685 | + mutex_unlock(&pmc_reserve_mutex); | |
| 686 | + } | |
| 687 | + event->destroy = hw_perf_event_destroy; | |
| 688 | + | |
| 689 | + if (err) | |
| 690 | + goto out; | |
| 691 | + | |
| 692 | + /* Access per-CPU sampling information (query sampling info) */ | |
| 693 | + /* | |
| 694 | + * The event->cpu value can be -1 to count on every CPU, for example, | |
| 695 | + * when attaching to a task. If this is specified, use the query | |
| 696 | + * sampling info from the current CPU, otherwise use event->cpu to | |
| 697 | + * retrieve the per-CPU information. | |
| 698 | + * Later, cpuhw indicates whether to allocate sampling buffers for a | |
| 699 | + * particular CPU (cpuhw!=NULL) or each online CPU (cpuw==NULL). | |
| 700 | + */ | |
| 701 | + memset(&si, 0, sizeof(si)); | |
| 702 | + cpuhw = NULL; | |
| 703 | + if (event->cpu == -1) | |
| 704 | + qsi(&si); | |
| 705 | + else { | |
| 706 | + /* Event is pinned to a particular CPU, retrieve the per-CPU | |
| 707 | + * sampling structure for accessing the CPU-specific QSI. | |
| 708 | + */ | |
| 709 | + cpuhw = &per_cpu(cpu_hw_sf, event->cpu); | |
| 710 | + si = cpuhw->qsi; | |
| 711 | + } | |
| 712 | + | |
| 713 | + /* Check sampling facility authorization and, if not authorized, | |
| 714 | + * fall back to other PMUs. It is safe to check any CPU because | |
| 715 | + * the authorization is identical for all configured CPUs. | |
| 716 | + */ | |
| 717 | + if (!si.as) { | |
| 718 | + err = -ENOENT; | |
| 719 | + goto out; | |
| 720 | + } | |
| 721 | + | |
| 722 | + /* Always enable basic sampling */ | |
| 723 | + SAMPL_FLAGS(hwc) = PERF_CPUM_SF_BASIC_MODE; | |
| 724 | + | |
| 725 | + /* Check if diagnostic sampling is requested. Deny if the required | |
| 726 | + * sampling authorization is missing. | |
| 727 | + */ | |
| 728 | + if (attr->config == PERF_EVENT_CPUM_SF_DIAG) { | |
| 729 | + if (!si.ad) { | |
| 730 | + err = -EPERM; | |
| 731 | + goto out; | |
| 732 | + } | |
| 733 | + SAMPL_FLAGS(hwc) |= PERF_CPUM_SF_DIAG_MODE; | |
| 734 | + } | |
| 735 | + | |
| 736 | + /* Check and set other sampling flags */ | |
| 737 | + if (attr->config1 & PERF_CPUM_SF_FULL_BLOCKS) | |
| 738 | + SAMPL_FLAGS(hwc) |= PERF_CPUM_SF_FULL_BLOCKS; | |
| 739 | + | |
| 740 | + /* The sampling information (si) contains information about the | |
| 741 | + * min/max sampling intervals and the CPU speed. So calculate the | |
| 742 | + * correct sampling interval and avoid the whole period adjust | |
| 743 | + * feedback loop. | |
| 744 | + */ | |
| 745 | + rate = 0; | |
| 746 | + if (attr->freq) { | |
| 747 | + rate = freq_to_sample_rate(&si, attr->sample_freq); | |
| 748 | + rate = hw_limit_rate(&si, rate); | |
| 749 | + attr->freq = 0; | |
| 750 | + attr->sample_period = rate; | |
| 751 | + } else { | |
| 752 | + /* The min/max sampling rates specifies the valid range | |
| 753 | + * of sample periods. If the specified sample period is | |
| 754 | + * out of range, limit the period to the range boundary. | |
| 755 | + */ | |
| 756 | + rate = hw_limit_rate(&si, hwc->sample_period); | |
| 757 | + | |
| 758 | + /* The perf core maintains a maximum sample rate that is | |
| 759 | + * configurable through the sysctl interface. Ensure the | |
| 760 | + * sampling rate does not exceed this value. This also helps | |
| 761 | + * to avoid throttling when pushing samples with | |
| 762 | + * perf_event_overflow(). | |
| 763 | + */ | |
| 764 | + if (sample_rate_to_freq(&si, rate) > | |
| 765 | + sysctl_perf_event_sample_rate) { | |
| 766 | + err = -EINVAL; | |
| 767 | + debug_sprintf_event(sfdbg, 1, "Sampling rate exceeds maximum perf sample rate\n"); | |
| 768 | + goto out; | |
| 769 | + } | |
| 770 | + } | |
| 771 | + SAMPL_RATE(hwc) = rate; | |
| 772 | + hw_init_period(hwc, SAMPL_RATE(hwc)); | |
| 773 | + | |
| 774 | + /* Initialize sample data overflow accounting */ | |
| 775 | + hwc->extra_reg.reg = REG_OVERFLOW; | |
| 776 | + OVERFLOW_REG(hwc) = 0; | |
| 777 | + | |
| 778 | + /* Allocate the per-CPU sampling buffer using the CPU information | |
| 779 | + * from the event. If the event is not pinned to a particular | |
| 780 | + * CPU (event->cpu == -1; or cpuhw == NULL), allocate sampling | |
| 781 | + * buffers for each online CPU. | |
| 782 | + */ | |
| 783 | + if (cpuhw) | |
| 784 | + /* Event is pinned to a particular CPU */ | |
| 785 | + err = allocate_buffers(cpuhw, hwc); | |
| 786 | + else { | |
| 787 | + /* Event is not pinned, allocate sampling buffer on | |
| 788 | + * each online CPU | |
| 789 | + */ | |
| 790 | + for_each_online_cpu(cpu) { | |
| 791 | + cpuhw = &per_cpu(cpu_hw_sf, cpu); | |
| 792 | + err = allocate_buffers(cpuhw, hwc); | |
| 793 | + if (err) | |
| 794 | + break; | |
| 795 | + } | |
| 796 | + } | |
| 797 | +out: | |
| 798 | + return err; | |
| 799 | +} | |
| 800 | + | |
| 801 | +static int cpumsf_pmu_event_init(struct perf_event *event) | |
| 802 | +{ | |
| 803 | + int err; | |
| 804 | + | |
| 805 | + /* No support for taken branch sampling */ | |
| 806 | + if (has_branch_stack(event)) | |
| 807 | + return -EOPNOTSUPP; | |
| 808 | + | |
| 809 | + switch (event->attr.type) { | |
| 810 | + case PERF_TYPE_RAW: | |
| 811 | + if ((event->attr.config != PERF_EVENT_CPUM_SF) && | |
| 812 | + (event->attr.config != PERF_EVENT_CPUM_SF_DIAG)) | |
| 813 | + return -ENOENT; | |
| 814 | + break; | |
| 815 | + case PERF_TYPE_HARDWARE: | |
| 816 | + /* Support sampling of CPU cycles in addition to the | |
| 817 | + * counter facility. However, the counter facility | |
| 818 | + * is more precise and, hence, restrict this PMU to | |
| 819 | + * sampling events only. | |
| 820 | + */ | |
| 821 | + if (event->attr.config != PERF_COUNT_HW_CPU_CYCLES) | |
| 822 | + return -ENOENT; | |
| 823 | + if (!is_sampling_event(event)) | |
| 824 | + return -ENOENT; | |
| 825 | + break; | |
| 826 | + default: | |
| 827 | + return -ENOENT; | |
| 828 | + } | |
| 829 | + | |
| 830 | + /* Check online status of the CPU to which the event is pinned */ | |
| 831 | + if (event->cpu >= nr_cpumask_bits || | |
| 832 | + (event->cpu >= 0 && !cpu_online(event->cpu))) | |
| 833 | + return -ENODEV; | |
| 834 | + | |
| 835 | + /* Force reset of idle/hv excludes regardless of what the | |
| 836 | + * user requested. | |
| 837 | + */ | |
| 838 | + if (event->attr.exclude_hv) | |
| 839 | + event->attr.exclude_hv = 0; | |
| 840 | + if (event->attr.exclude_idle) | |
| 841 | + event->attr.exclude_idle = 0; | |
| 842 | + | |
| 843 | + err = __hw_perf_event_init(event); | |
| 844 | + if (unlikely(err)) | |
| 845 | + if (event->destroy) | |
| 846 | + event->destroy(event); | |
| 847 | + return err; | |
| 848 | +} | |
| 849 | + | |
| 850 | +static void cpumsf_pmu_enable(struct pmu *pmu) | |
| 851 | +{ | |
| 852 | + struct cpu_hw_sf *cpuhw = &__get_cpu_var(cpu_hw_sf); | |
| 853 | + struct hw_perf_event *hwc; | |
| 854 | + int err; | |
| 855 | + | |
| 856 | + if (cpuhw->flags & PMU_F_ENABLED) | |
| 857 | + return; | |
| 858 | + | |
| 859 | + if (cpuhw->flags & PMU_F_ERR_MASK) | |
| 860 | + return; | |
| 861 | + | |
| 862 | + /* Check whether to extent the sampling buffer. | |
| 863 | + * | |
| 864 | + * Two conditions trigger an increase of the sampling buffer for a | |
| 865 | + * perf event: | |
| 866 | + * 1. Postponed buffer allocations from the event initialization. | |
| 867 | + * 2. Sampling overflows that contribute to pending allocations. | |
| 868 | + * | |
| 869 | + * Note that the extend_sampling_buffer() function disables the sampling | |
| 870 | + * facility, but it can be fully re-enabled using sampling controls that | |
| 871 | + * have been saved in cpumsf_pmu_disable(). | |
| 872 | + */ | |
| 873 | + if (cpuhw->event) { | |
| 874 | + hwc = &cpuhw->event->hw; | |
| 875 | + /* Account number of overflow-designated buffer extents */ | |
| 876 | + sfb_account_overflows(cpuhw, hwc); | |
| 877 | + if (sfb_has_pending_allocs(&cpuhw->sfb, hwc)) | |
| 878 | + extend_sampling_buffer(&cpuhw->sfb, hwc); | |
| 879 | + } | |
| 880 | + | |
| 881 | + /* (Re)enable the PMU and sampling facility */ | |
| 882 | + cpuhw->flags |= PMU_F_ENABLED; | |
| 883 | + barrier(); | |
| 884 | + | |
| 885 | + err = lsctl(&cpuhw->lsctl); | |
| 886 | + if (err) { | |
| 887 | + cpuhw->flags &= ~PMU_F_ENABLED; | |
| 888 | + pr_err("Loading sampling controls failed: op=%i err=%i\n", | |
| 889 | + 1, err); | |
| 890 | + return; | |
| 891 | + } | |
| 892 | + | |
| 893 | + debug_sprintf_event(sfdbg, 6, "pmu_enable: es=%i cs=%i ed=%i cd=%i " | |
| 894 | + "tear=%p dear=%p\n", cpuhw->lsctl.es, cpuhw->lsctl.cs, | |
| 895 | + cpuhw->lsctl.ed, cpuhw->lsctl.cd, | |
| 896 | + (void *) cpuhw->lsctl.tear, (void *) cpuhw->lsctl.dear); | |
| 897 | +} | |
| 898 | + | |
| 899 | +static void cpumsf_pmu_disable(struct pmu *pmu) | |
| 900 | +{ | |
| 901 | + struct cpu_hw_sf *cpuhw = &__get_cpu_var(cpu_hw_sf); | |
| 902 | + struct hws_lsctl_request_block inactive; | |
| 903 | + struct hws_qsi_info_block si; | |
| 904 | + int err; | |
| 905 | + | |
| 906 | + if (!(cpuhw->flags & PMU_F_ENABLED)) | |
| 907 | + return; | |
| 908 | + | |
| 909 | + if (cpuhw->flags & PMU_F_ERR_MASK) | |
| 910 | + return; | |
| 911 | + | |
| 912 | + /* Switch off sampling activation control */ | |
| 913 | + inactive = cpuhw->lsctl; | |
| 914 | + inactive.cs = 0; | |
| 915 | + inactive.cd = 0; | |
| 916 | + | |
| 917 | + err = lsctl(&inactive); | |
| 918 | + if (err) { | |
| 919 | + pr_err("Loading sampling controls failed: op=%i err=%i\n", | |
| 920 | + 2, err); | |
| 921 | + return; | |
| 922 | + } | |
| 923 | + | |
| 924 | + /* Save state of TEAR and DEAR register contents */ | |
| 925 | + if (!qsi(&si)) { | |
| 926 | + /* TEAR/DEAR values are valid only if the sampling facility is | |
| 927 | + * enabled. Note that cpumsf_pmu_disable() might be called even | |
| 928 | + * for a disabled sampling facility because cpumsf_pmu_enable() | |
| 929 | + * controls the enable/disable state. | |
| 930 | + */ | |
| 931 | + if (si.es) { | |
| 932 | + cpuhw->lsctl.tear = si.tear; | |
| 933 | + cpuhw->lsctl.dear = si.dear; | |
| 934 | + } | |
| 935 | + } else | |
| 936 | + debug_sprintf_event(sfdbg, 3, "cpumsf_pmu_disable: " | |
| 937 | + "qsi() failed with err=%i\n", err); | |
| 938 | + | |
| 939 | + cpuhw->flags &= ~PMU_F_ENABLED; | |
| 940 | +} | |
| 941 | + | |
| 942 | +/* perf_exclude_event() - Filter event | |
| 943 | + * @event: The perf event | |
| 944 | + * @regs: pt_regs structure | |
| 945 | + * @sde_regs: Sample-data-entry (sde) regs structure | |
| 946 | + * | |
| 947 | + * Filter perf events according to their exclude specification. | |
| 948 | + * | |
| 949 | + * Return non-zero if the event shall be excluded. | |
| 950 | + */ | |
| 951 | +static int perf_exclude_event(struct perf_event *event, struct pt_regs *regs, | |
| 952 | + struct perf_sf_sde_regs *sde_regs) | |
| 953 | +{ | |
| 954 | + if (event->attr.exclude_user && user_mode(regs)) | |
| 955 | + return 1; | |
| 956 | + if (event->attr.exclude_kernel && !user_mode(regs)) | |
| 957 | + return 1; | |
| 958 | + if (event->attr.exclude_guest && sde_regs->in_guest) | |
| 959 | + return 1; | |
| 960 | + if (event->attr.exclude_host && !sde_regs->in_guest) | |
| 961 | + return 1; | |
| 962 | + return 0; | |
| 963 | +} | |
| 964 | + | |
| 965 | +/* perf_push_sample() - Push samples to perf | |
| 966 | + * @event: The perf event | |
| 967 | + * @sample: Hardware sample data | |
| 968 | + * | |
| 969 | + * Use the hardware sample data to create perf event sample. The sample | |
| 970 | + * is the pushed to the event subsystem and the function checks for | |
| 971 | + * possible event overflows. If an event overflow occurs, the PMU is | |
| 972 | + * stopped. | |
| 973 | + * | |
| 974 | + * Return non-zero if an event overflow occurred. | |
| 975 | + */ | |
| 976 | +static int perf_push_sample(struct perf_event *event, struct sf_raw_sample *sfr) | |
| 977 | +{ | |
| 978 | + int overflow; | |
| 979 | + struct pt_regs regs; | |
| 980 | + struct perf_sf_sde_regs *sde_regs; | |
| 981 | + struct perf_sample_data data; | |
| 982 | + struct perf_raw_record raw; | |
| 983 | + | |
| 984 | + /* Setup perf sample */ | |
| 985 | + perf_sample_data_init(&data, 0, event->hw.last_period); | |
| 986 | + raw.size = sfr->size; | |
| 987 | + raw.data = sfr; | |
| 988 | + data.raw = &raw; | |
| 989 | + | |
| 990 | + /* Setup pt_regs to look like an CPU-measurement external interrupt | |
| 991 | + * using the Program Request Alert code. The regs.int_parm_long | |
| 992 | + * field which is unused contains additional sample-data-entry related | |
| 993 | + * indicators. | |
| 994 | + */ | |
| 995 | + memset(®s, 0, sizeof(regs)); | |
| 996 | + regs.int_code = 0x1407; | |
| 997 | + regs.int_parm = CPU_MF_INT_SF_PRA; | |
| 998 | + sde_regs = (struct perf_sf_sde_regs *) ®s.int_parm_long; | |
| 999 | + | |
| 1000 | + regs.psw.addr = sfr->basic.ia; | |
| 1001 | + if (sfr->basic.T) | |
| 1002 | + regs.psw.mask |= PSW_MASK_DAT; | |
| 1003 | + if (sfr->basic.W) | |
| 1004 | + regs.psw.mask |= PSW_MASK_WAIT; | |
| 1005 | + if (sfr->basic.P) | |
| 1006 | + regs.psw.mask |= PSW_MASK_PSTATE; | |
| 1007 | + switch (sfr->basic.AS) { | |
| 1008 | + case 0x0: | |
| 1009 | + regs.psw.mask |= PSW_ASC_PRIMARY; | |
| 1010 | + break; | |
| 1011 | + case 0x1: | |
| 1012 | + regs.psw.mask |= PSW_ASC_ACCREG; | |
| 1013 | + break; | |
| 1014 | + case 0x2: | |
| 1015 | + regs.psw.mask |= PSW_ASC_SECONDARY; | |
| 1016 | + break; | |
| 1017 | + case 0x3: | |
| 1018 | + regs.psw.mask |= PSW_ASC_HOME; | |
| 1019 | + break; | |
| 1020 | + } | |
| 1021 | + | |
| 1022 | + /* The host-program-parameter (hpp) contains the sie control | |
| 1023 | + * block that is set by sie64a() in entry64.S. Check if hpp | |
| 1024 | + * refers to a valid control block and set sde_regs flags | |
| 1025 | + * accordingly. This would allow to use hpp values for other | |
| 1026 | + * purposes too. | |
| 1027 | + * For now, simply use a non-zero value as guest indicator. | |
| 1028 | + */ | |
| 1029 | + if (sfr->basic.hpp) | |
| 1030 | + sde_regs->in_guest = 1; | |
| 1031 | + | |
| 1032 | + overflow = 0; | |
| 1033 | + if (perf_exclude_event(event, ®s, sde_regs)) | |
| 1034 | + goto out; | |
| 1035 | + if (perf_event_overflow(event, &data, ®s)) { | |
| 1036 | + overflow = 1; | |
| 1037 | + event->pmu->stop(event, 0); | |
| 1038 | + } | |
| 1039 | + perf_event_update_userpage(event); | |
| 1040 | +out: | |
| 1041 | + return overflow; | |
| 1042 | +} | |
| 1043 | + | |
| 1044 | +static void perf_event_count_update(struct perf_event *event, u64 count) | |
| 1045 | +{ | |
| 1046 | + local64_add(count, &event->count); | |
| 1047 | +} | |
| 1048 | + | |
| 1049 | +static int sample_format_is_valid(struct hws_combined_entry *sample, | |
| 1050 | + unsigned int flags) | |
| 1051 | +{ | |
| 1052 | + if (likely(flags & PERF_CPUM_SF_BASIC_MODE)) | |
| 1053 | + /* Only basic-sampling data entries with data-entry-format | |
| 1054 | + * version of 0x0001 can be processed. | |
| 1055 | + */ | |
| 1056 | + if (sample->basic.def != 0x0001) | |
| 1057 | + return 0; | |
| 1058 | + if (flags & PERF_CPUM_SF_DIAG_MODE) | |
| 1059 | + /* The data-entry-format number of diagnostic-sampling data | |
| 1060 | + * entries can vary. Because diagnostic data is just passed | |
| 1061 | + * through, do only a sanity check on the DEF. | |
| 1062 | + */ | |
| 1063 | + if (sample->diag.def < 0x8001) | |
| 1064 | + return 0; | |
| 1065 | + return 1; | |
| 1066 | +} | |
| 1067 | + | |
| 1068 | +static int sample_is_consistent(struct hws_combined_entry *sample, | |
| 1069 | + unsigned long flags) | |
| 1070 | +{ | |
| 1071 | + /* This check applies only to basic-sampling data entries of potentially | |
| 1072 | + * combined-sampling data entries. Invalid entries cannot be processed | |
| 1073 | + * by the PMU and, thus, do not deliver an associated | |
| 1074 | + * diagnostic-sampling data entry. | |
| 1075 | + */ | |
| 1076 | + if (unlikely(!(flags & PERF_CPUM_SF_BASIC_MODE))) | |
| 1077 | + return 0; | |
| 1078 | + /* | |
| 1079 | + * Samples are skipped, if they are invalid or for which the | |
| 1080 | + * instruction address is not predictable, i.e., the wait-state bit is | |
| 1081 | + * set. | |
| 1082 | + */ | |
| 1083 | + if (sample->basic.I || sample->basic.W) | |
| 1084 | + return 0; | |
| 1085 | + return 1; | |
| 1086 | +} | |
| 1087 | + | |
| 1088 | +static void reset_sample_slot(struct hws_combined_entry *sample, | |
| 1089 | + unsigned long flags) | |
| 1090 | +{ | |
| 1091 | + if (likely(flags & PERF_CPUM_SF_BASIC_MODE)) | |
| 1092 | + sample->basic.def = 0; | |
| 1093 | + if (flags & PERF_CPUM_SF_DIAG_MODE) | |
| 1094 | + sample->diag.def = 0; | |
| 1095 | +} | |
| 1096 | + | |
| 1097 | +static void sfr_store_sample(struct sf_raw_sample *sfr, | |
| 1098 | + struct hws_combined_entry *sample) | |
| 1099 | +{ | |
| 1100 | + if (likely(sfr->format & PERF_CPUM_SF_BASIC_MODE)) | |
| 1101 | + sfr->basic = sample->basic; | |
| 1102 | + if (sfr->format & PERF_CPUM_SF_DIAG_MODE) | |
| 1103 | + memcpy(&sfr->diag, &sample->diag, sfr->dsdes); | |
| 1104 | +} | |
| 1105 | + | |
| 1106 | +static void debug_sample_entry(struct hws_combined_entry *sample, | |
| 1107 | + struct hws_trailer_entry *te, | |
| 1108 | + unsigned long flags) | |
| 1109 | +{ | |
| 1110 | + debug_sprintf_event(sfdbg, 4, "hw_collect_samples: Found unknown " | |
| 1111 | + "sampling data entry: te->f=%i basic.def=%04x (%p)" | |
| 1112 | + " diag.def=%04x (%p)\n", te->f, | |
| 1113 | + sample->basic.def, &sample->basic, | |
| 1114 | + (flags & PERF_CPUM_SF_DIAG_MODE) | |
| 1115 | + ? sample->diag.def : 0xFFFF, | |
| 1116 | + (flags & PERF_CPUM_SF_DIAG_MODE) | |
| 1117 | + ? &sample->diag : NULL); | |
| 1118 | +} | |
| 1119 | + | |
| 1120 | +/* hw_collect_samples() - Walk through a sample-data-block and collect samples | |
| 1121 | + * @event: The perf event | |
| 1122 | + * @sdbt: Sample-data-block table | |
| 1123 | + * @overflow: Event overflow counter | |
| 1124 | + * | |
| 1125 | + * Walks through a sample-data-block and collects sampling data entries that are | |
| 1126 | + * then pushed to the perf event subsystem. Depending on the sampling function, | |
| 1127 | + * there can be either basic-sampling or combined-sampling data entries. A | |
| 1128 | + * combined-sampling data entry consists of a basic- and a diagnostic-sampling | |
| 1129 | + * data entry. The sampling function is determined by the flags in the perf | |
| 1130 | + * event hardware structure. The function always works with a combined-sampling | |
| 1131 | + * data entry but ignores the the diagnostic portion if it is not available. | |
| 1132 | + * | |
| 1133 | + * Note that the implementation focuses on basic-sampling data entries and, if | |
| 1134 | + * such an entry is not valid, the entire combined-sampling data entry is | |
| 1135 | + * ignored. | |
| 1136 | + * | |
| 1137 | + * The overflow variables counts the number of samples that has been discarded | |
| 1138 | + * due to a perf event overflow. | |
| 1139 | + */ | |
| 1140 | +static void hw_collect_samples(struct perf_event *event, unsigned long *sdbt, | |
| 1141 | + unsigned long long *overflow) | |
| 1142 | +{ | |
| 1143 | + unsigned long flags = SAMPL_FLAGS(&event->hw); | |
| 1144 | + struct hws_combined_entry *sample; | |
| 1145 | + struct hws_trailer_entry *te; | |
| 1146 | + struct sf_raw_sample *sfr; | |
| 1147 | + size_t sample_size; | |
| 1148 | + | |
| 1149 | + /* Prepare and initialize raw sample data */ | |
| 1150 | + sfr = (struct sf_raw_sample *) RAWSAMPLE_REG(&event->hw); | |
| 1151 | + sfr->format = flags & PERF_CPUM_SF_MODE_MASK; | |
| 1152 | + | |
| 1153 | + sample_size = event_sample_size(&event->hw); | |
| 1154 | + te = (struct hws_trailer_entry *) trailer_entry_ptr(*sdbt); | |
| 1155 | + sample = (struct hws_combined_entry *) *sdbt; | |
| 1156 | + while ((unsigned long *) sample < (unsigned long *) te) { | |
| 1157 | + /* Check for an empty sample */ | |
| 1158 | + if (!sample->basic.def) | |
| 1159 | + break; | |
| 1160 | + | |
| 1161 | + /* Update perf event period */ | |
| 1162 | + perf_event_count_update(event, SAMPL_RATE(&event->hw)); | |
| 1163 | + | |
| 1164 | + /* Check sampling data entry */ | |
| 1165 | + if (sample_format_is_valid(sample, flags)) { | |
| 1166 | + /* If an event overflow occurred, the PMU is stopped to | |
| 1167 | + * throttle event delivery. Remaining sample data is | |
| 1168 | + * discarded. | |
| 1169 | + */ | |
| 1170 | + if (!*overflow) { | |
| 1171 | + if (sample_is_consistent(sample, flags)) { | |
| 1172 | + /* Deliver sample data to perf */ | |
| 1173 | + sfr_store_sample(sfr, sample); | |
| 1174 | + *overflow = perf_push_sample(event, sfr); | |
| 1175 | + } | |
| 1176 | + } else | |
| 1177 | + /* Count discarded samples */ | |
| 1178 | + *overflow += 1; | |
| 1179 | + } else { | |
| 1180 | + debug_sample_entry(sample, te, flags); | |
| 1181 | + /* Sample slot is not yet written or other record. | |
| 1182 | + * | |
| 1183 | + * This condition can occur if the buffer was reused | |
| 1184 | + * from a combined basic- and diagnostic-sampling. | |
| 1185 | + * If only basic-sampling is then active, entries are | |
| 1186 | + * written into the larger diagnostic entries. | |
| 1187 | + * This is typically the case for sample-data-blocks | |
| 1188 | + * that are not full. Stop processing if the first | |
| 1189 | + * invalid format was detected. | |
| 1190 | + */ | |
| 1191 | + if (!te->f) | |
| 1192 | + break; | |
| 1193 | + } | |
| 1194 | + | |
| 1195 | + /* Reset sample slot and advance to next sample */ | |
| 1196 | + reset_sample_slot(sample, flags); | |
| 1197 | + sample += sample_size; | |
| 1198 | + } | |
| 1199 | +} | |
| 1200 | + | |
| 1201 | +/* hw_perf_event_update() - Process sampling buffer | |
| 1202 | + * @event: The perf event | |
| 1203 | + * @flush_all: Flag to also flush partially filled sample-data-blocks | |
| 1204 | + * | |
| 1205 | + * Processes the sampling buffer and create perf event samples. | |
| 1206 | + * The sampling buffer position are retrieved and saved in the TEAR_REG | |
| 1207 | + * register of the specified perf event. | |
| 1208 | + * | |
| 1209 | + * Only full sample-data-blocks are processed. Specify the flash_all flag | |
| 1210 | + * to also walk through partially filled sample-data-blocks. It is ignored | |
| 1211 | + * if PERF_CPUM_SF_FULL_BLOCKS is set. The PERF_CPUM_SF_FULL_BLOCKS flag | |
| 1212 | + * enforces the processing of full sample-data-blocks only (trailer entries | |
| 1213 | + * with the block-full-indicator bit set). | |
| 1214 | + */ | |
| 1215 | +static void hw_perf_event_update(struct perf_event *event, int flush_all) | |
| 1216 | +{ | |
| 1217 | + struct hw_perf_event *hwc = &event->hw; | |
| 1218 | + struct hws_trailer_entry *te; | |
| 1219 | + unsigned long *sdbt; | |
| 1220 | + unsigned long long event_overflow, sampl_overflow, num_sdb, te_flags; | |
| 1221 | + int done; | |
| 1222 | + | |
| 1223 | + if (flush_all && SDB_FULL_BLOCKS(hwc)) | |
| 1224 | + flush_all = 0; | |
| 1225 | + | |
| 1226 | + sdbt = (unsigned long *) TEAR_REG(hwc); | |
| 1227 | + done = event_overflow = sampl_overflow = num_sdb = 0; | |
| 1228 | + while (!done) { | |
| 1229 | + /* Get the trailer entry of the sample-data-block */ | |
| 1230 | + te = (struct hws_trailer_entry *) trailer_entry_ptr(*sdbt); | |
| 1231 | + | |
| 1232 | + /* Leave loop if no more work to do (block full indicator) */ | |
| 1233 | + if (!te->f) { | |
| 1234 | + done = 1; | |
| 1235 | + if (!flush_all) | |
| 1236 | + break; | |
| 1237 | + } | |
| 1238 | + | |
| 1239 | + /* Check the sample overflow count */ | |
| 1240 | + if (te->overflow) | |
| 1241 | + /* Account sample overflows and, if a particular limit | |
| 1242 | + * is reached, extend the sampling buffer. | |
| 1243 | + * For details, see sfb_account_overflows(). | |
| 1244 | + */ | |
| 1245 | + sampl_overflow += te->overflow; | |
| 1246 | + | |
| 1247 | + /* Timestamps are valid for full sample-data-blocks only */ | |
| 1248 | + debug_sprintf_event(sfdbg, 6, "hw_perf_event_update: sdbt=%p " | |
| 1249 | + "overflow=%llu timestamp=0x%llx\n", | |
| 1250 | + sdbt, te->overflow, | |
| 1251 | + (te->f) ? trailer_timestamp(te) : 0ULL); | |
| 1252 | + | |
| 1253 | + /* Collect all samples from a single sample-data-block and | |
| 1254 | + * flag if an (perf) event overflow happened. If so, the PMU | |
| 1255 | + * is stopped and remaining samples will be discarded. | |
| 1256 | + */ | |
| 1257 | + hw_collect_samples(event, sdbt, &event_overflow); | |
| 1258 | + num_sdb++; | |
| 1259 | + | |
| 1260 | + /* Reset trailer (using compare-double-and-swap) */ | |
| 1261 | + do { | |
| 1262 | + te_flags = te->flags & ~SDB_TE_BUFFER_FULL_MASK; | |
| 1263 | + te_flags |= SDB_TE_ALERT_REQ_MASK; | |
| 1264 | + } while (!cmpxchg_double(&te->flags, &te->overflow, | |
| 1265 | + te->flags, te->overflow, | |
| 1266 | + te_flags, 0ULL)); | |
| 1267 | + | |
| 1268 | + /* Advance to next sample-data-block */ | |
| 1269 | + sdbt++; | |
| 1270 | + if (is_link_entry(sdbt)) | |
| 1271 | + sdbt = get_next_sdbt(sdbt); | |
| 1272 | + | |
| 1273 | + /* Update event hardware registers */ | |
| 1274 | + TEAR_REG(hwc) = (unsigned long) sdbt; | |
| 1275 | + | |
| 1276 | + /* Stop processing sample-data if all samples of the current | |
| 1277 | + * sample-data-block were flushed even if it was not full. | |
| 1278 | + */ | |
| 1279 | + if (flush_all && done) | |
| 1280 | + break; | |
| 1281 | + | |
| 1282 | + /* If an event overflow happened, discard samples by | |
| 1283 | + * processing any remaining sample-data-blocks. | |
| 1284 | + */ | |
| 1285 | + if (event_overflow) | |
| 1286 | + flush_all = 1; | |
| 1287 | + } | |
| 1288 | + | |
| 1289 | + /* Account sample overflows in the event hardware structure */ | |
| 1290 | + if (sampl_overflow) | |
| 1291 | + OVERFLOW_REG(hwc) = DIV_ROUND_UP(OVERFLOW_REG(hwc) + | |
| 1292 | + sampl_overflow, 1 + num_sdb); | |
| 1293 | + if (sampl_overflow || event_overflow) | |
| 1294 | + debug_sprintf_event(sfdbg, 4, "hw_perf_event_update: " | |
| 1295 | + "overflow stats: sample=%llu event=%llu\n", | |
| 1296 | + sampl_overflow, event_overflow); | |
| 1297 | +} | |
| 1298 | + | |
| 1299 | +static void cpumsf_pmu_read(struct perf_event *event) | |
| 1300 | +{ | |
| 1301 | + /* Nothing to do ... updates are interrupt-driven */ | |
| 1302 | +} | |
| 1303 | + | |
| 1304 | +/* Activate sampling control. | |
| 1305 | + * Next call of pmu_enable() starts sampling. | |
| 1306 | + */ | |
| 1307 | +static void cpumsf_pmu_start(struct perf_event *event, int flags) | |
| 1308 | +{ | |
| 1309 | + struct cpu_hw_sf *cpuhw = &__get_cpu_var(cpu_hw_sf); | |
| 1310 | + | |
| 1311 | + if (WARN_ON_ONCE(!(event->hw.state & PERF_HES_STOPPED))) | |
| 1312 | + return; | |
| 1313 | + | |
| 1314 | + if (flags & PERF_EF_RELOAD) | |
| 1315 | + WARN_ON_ONCE(!(event->hw.state & PERF_HES_UPTODATE)); | |
| 1316 | + | |
| 1317 | + perf_pmu_disable(event->pmu); | |
| 1318 | + event->hw.state = 0; | |
| 1319 | + cpuhw->lsctl.cs = 1; | |
| 1320 | + if (SAMPL_DIAG_MODE(&event->hw)) | |
| 1321 | + cpuhw->lsctl.cd = 1; | |
| 1322 | + perf_pmu_enable(event->pmu); | |
| 1323 | +} | |
| 1324 | + | |
| 1325 | +/* Deactivate sampling control. | |
| 1326 | + * Next call of pmu_enable() stops sampling. | |
| 1327 | + */ | |
| 1328 | +static void cpumsf_pmu_stop(struct perf_event *event, int flags) | |
| 1329 | +{ | |
| 1330 | + struct cpu_hw_sf *cpuhw = &__get_cpu_var(cpu_hw_sf); | |
| 1331 | + | |
| 1332 | + if (event->hw.state & PERF_HES_STOPPED) | |
| 1333 | + return; | |
| 1334 | + | |
| 1335 | + perf_pmu_disable(event->pmu); | |
| 1336 | + cpuhw->lsctl.cs = 0; | |
| 1337 | + cpuhw->lsctl.cd = 0; | |
| 1338 | + event->hw.state |= PERF_HES_STOPPED; | |
| 1339 | + | |
| 1340 | + if ((flags & PERF_EF_UPDATE) && !(event->hw.state & PERF_HES_UPTODATE)) { | |
| 1341 | + hw_perf_event_update(event, 1); | |
| 1342 | + event->hw.state |= PERF_HES_UPTODATE; | |
| 1343 | + } | |
| 1344 | + perf_pmu_enable(event->pmu); | |
| 1345 | +} | |
| 1346 | + | |
| 1347 | +static int cpumsf_pmu_add(struct perf_event *event, int flags) | |
| 1348 | +{ | |
| 1349 | + struct cpu_hw_sf *cpuhw = &__get_cpu_var(cpu_hw_sf); | |
| 1350 | + int err; | |
| 1351 | + | |
| 1352 | + if (cpuhw->flags & PMU_F_IN_USE) | |
| 1353 | + return -EAGAIN; | |
| 1354 | + | |
| 1355 | + if (!cpuhw->sfb.sdbt) | |
| 1356 | + return -EINVAL; | |
| 1357 | + | |
| 1358 | + err = 0; | |
| 1359 | + perf_pmu_disable(event->pmu); | |
| 1360 | + | |
| 1361 | + event->hw.state = PERF_HES_UPTODATE | PERF_HES_STOPPED; | |
| 1362 | + | |
| 1363 | + /* Set up sampling controls. Always program the sampling register | |
| 1364 | + * using the SDB-table start. Reset TEAR_REG event hardware register | |
| 1365 | + * that is used by hw_perf_event_update() to store the sampling buffer | |
| 1366 | + * position after samples have been flushed. | |
| 1367 | + */ | |
| 1368 | + cpuhw->lsctl.s = 0; | |
| 1369 | + cpuhw->lsctl.h = 1; | |
| 1370 | + cpuhw->lsctl.tear = (unsigned long) cpuhw->sfb.sdbt; | |
| 1371 | + cpuhw->lsctl.dear = *(unsigned long *) cpuhw->sfb.sdbt; | |
| 1372 | + cpuhw->lsctl.interval = SAMPL_RATE(&event->hw); | |
| 1373 | + hw_reset_registers(&event->hw, cpuhw->sfb.sdbt); | |
| 1374 | + | |
| 1375 | + /* Ensure sampling functions are in the disabled state. If disabled, | |
| 1376 | + * switch on sampling enable control. */ | |
| 1377 | + if (WARN_ON_ONCE(cpuhw->lsctl.es == 1 || cpuhw->lsctl.ed == 1)) { | |
| 1378 | + err = -EAGAIN; | |
| 1379 | + goto out; | |
| 1380 | + } | |
| 1381 | + cpuhw->lsctl.es = 1; | |
| 1382 | + if (SAMPL_DIAG_MODE(&event->hw)) | |
| 1383 | + cpuhw->lsctl.ed = 1; | |
| 1384 | + | |
| 1385 | + /* Set in_use flag and store event */ | |
| 1386 | + event->hw.idx = 0; /* only one sampling event per CPU supported */ | |
| 1387 | + cpuhw->event = event; | |
| 1388 | + cpuhw->flags |= PMU_F_IN_USE; | |
| 1389 | + | |
| 1390 | + if (flags & PERF_EF_START) | |
| 1391 | + cpumsf_pmu_start(event, PERF_EF_RELOAD); | |
| 1392 | +out: | |
| 1393 | + perf_event_update_userpage(event); | |
| 1394 | + perf_pmu_enable(event->pmu); | |
| 1395 | + return err; | |
| 1396 | +} | |
| 1397 | + | |
| 1398 | +static void cpumsf_pmu_del(struct perf_event *event, int flags) | |
| 1399 | +{ | |
| 1400 | + struct cpu_hw_sf *cpuhw = &__get_cpu_var(cpu_hw_sf); | |
| 1401 | + | |
| 1402 | + perf_pmu_disable(event->pmu); | |
| 1403 | + cpumsf_pmu_stop(event, PERF_EF_UPDATE); | |
| 1404 | + | |
| 1405 | + cpuhw->lsctl.es = 0; | |
| 1406 | + cpuhw->lsctl.ed = 0; | |
| 1407 | + cpuhw->flags &= ~PMU_F_IN_USE; | |
| 1408 | + cpuhw->event = NULL; | |
| 1409 | + | |
| 1410 | + perf_event_update_userpage(event); | |
| 1411 | + perf_pmu_enable(event->pmu); | |
| 1412 | +} | |
| 1413 | + | |
| 1414 | +static int cpumsf_pmu_event_idx(struct perf_event *event) | |
| 1415 | +{ | |
| 1416 | + return event->hw.idx; | |
| 1417 | +} | |
| 1418 | + | |
| 1419 | +CPUMF_EVENT_ATTR(SF, SF_CYCLES_BASIC, PERF_EVENT_CPUM_SF); | |
| 1420 | +CPUMF_EVENT_ATTR(SF, SF_CYCLES_BASIC_DIAG, PERF_EVENT_CPUM_SF_DIAG); | |
| 1421 | + | |
| 1422 | +static struct attribute *cpumsf_pmu_events_attr[] = { | |
| 1423 | + CPUMF_EVENT_PTR(SF, SF_CYCLES_BASIC), | |
| 1424 | + CPUMF_EVENT_PTR(SF, SF_CYCLES_BASIC_DIAG), | |
| 1425 | + NULL, | |
| 1426 | +}; | |
| 1427 | + | |
| 1428 | +PMU_FORMAT_ATTR(event, "config:0-63"); | |
| 1429 | + | |
| 1430 | +static struct attribute *cpumsf_pmu_format_attr[] = { | |
| 1431 | + &format_attr_event.attr, | |
| 1432 | + NULL, | |
| 1433 | +}; | |
| 1434 | + | |
| 1435 | +static struct attribute_group cpumsf_pmu_events_group = { | |
| 1436 | + .name = "events", | |
| 1437 | + .attrs = cpumsf_pmu_events_attr, | |
| 1438 | +}; | |
| 1439 | +static struct attribute_group cpumsf_pmu_format_group = { | |
| 1440 | + .name = "format", | |
| 1441 | + .attrs = cpumsf_pmu_format_attr, | |
| 1442 | +}; | |
| 1443 | +static const struct attribute_group *cpumsf_pmu_attr_groups[] = { | |
| 1444 | + &cpumsf_pmu_events_group, | |
| 1445 | + &cpumsf_pmu_format_group, | |
| 1446 | + NULL, | |
| 1447 | +}; | |
| 1448 | + | |
| 1449 | +static struct pmu cpumf_sampling = { | |
| 1450 | + .pmu_enable = cpumsf_pmu_enable, | |
| 1451 | + .pmu_disable = cpumsf_pmu_disable, | |
| 1452 | + | |
| 1453 | + .event_init = cpumsf_pmu_event_init, | |
| 1454 | + .add = cpumsf_pmu_add, | |
| 1455 | + .del = cpumsf_pmu_del, | |
| 1456 | + | |
| 1457 | + .start = cpumsf_pmu_start, | |
| 1458 | + .stop = cpumsf_pmu_stop, | |
| 1459 | + .read = cpumsf_pmu_read, | |
| 1460 | + | |
| 1461 | + .event_idx = cpumsf_pmu_event_idx, | |
| 1462 | + .attr_groups = cpumsf_pmu_attr_groups, | |
| 1463 | +}; | |
| 1464 | + | |
| 1465 | +static void cpumf_measurement_alert(struct ext_code ext_code, | |
| 1466 | + unsigned int alert, unsigned long unused) | |
| 1467 | +{ | |
| 1468 | + struct cpu_hw_sf *cpuhw; | |
| 1469 | + | |
| 1470 | + if (!(alert & CPU_MF_INT_SF_MASK)) | |
| 1471 | + return; | |
| 1472 | + inc_irq_stat(IRQEXT_CMS); | |
| 1473 | + cpuhw = &__get_cpu_var(cpu_hw_sf); | |
| 1474 | + | |
| 1475 | + /* Measurement alerts are shared and might happen when the PMU | |
| 1476 | + * is not reserved. Ignore these alerts in this case. */ | |
| 1477 | + if (!(cpuhw->flags & PMU_F_RESERVED)) | |
| 1478 | + return; | |
| 1479 | + | |
| 1480 | + /* The processing below must take care of multiple alert events that | |
| 1481 | + * might be indicated concurrently. */ | |
| 1482 | + | |
| 1483 | + /* Program alert request */ | |
| 1484 | + if (alert & CPU_MF_INT_SF_PRA) { | |
| 1485 | + if (cpuhw->flags & PMU_F_IN_USE) | |
| 1486 | + hw_perf_event_update(cpuhw->event, 0); | |
| 1487 | + else | |
| 1488 | + WARN_ON_ONCE(!(cpuhw->flags & PMU_F_IN_USE)); | |
| 1489 | + } | |
| 1490 | + | |
| 1491 | + /* Report measurement alerts only for non-PRA codes */ | |
| 1492 | + if (alert != CPU_MF_INT_SF_PRA) | |
| 1493 | + debug_sprintf_event(sfdbg, 6, "measurement alert: 0x%x\n", alert); | |
| 1494 | + | |
| 1495 | + /* Sampling authorization change request */ | |
| 1496 | + if (alert & CPU_MF_INT_SF_SACA) | |
| 1497 | + qsi(&cpuhw->qsi); | |
| 1498 | + | |
| 1499 | + /* Loss of sample data due to high-priority machine activities */ | |
| 1500 | + if (alert & CPU_MF_INT_SF_LSDA) { | |
| 1501 | + pr_err("Sample data was lost\n"); | |
| 1502 | + cpuhw->flags |= PMU_F_ERR_LSDA; | |
| 1503 | + sf_disable(); | |
| 1504 | + } | |
| 1505 | + | |
| 1506 | + /* Invalid sampling buffer entry */ | |
| 1507 | + if (alert & (CPU_MF_INT_SF_IAE|CPU_MF_INT_SF_ISE)) { | |
| 1508 | + pr_err("A sampling buffer entry is incorrect (alert=0x%x)\n", | |
| 1509 | + alert); | |
| 1510 | + cpuhw->flags |= PMU_F_ERR_IBE; | |
| 1511 | + sf_disable(); | |
| 1512 | + } | |
| 1513 | +} | |
| 1514 | + | |
| 1515 | +static int cpumf_pmu_notifier(struct notifier_block *self, | |
| 1516 | + unsigned long action, void *hcpu) | |
| 1517 | +{ | |
| 1518 | + unsigned int cpu = (long) hcpu; | |
| 1519 | + int flags; | |
| 1520 | + | |
| 1521 | + /* Ignore the notification if no events are scheduled on the PMU. | |
| 1522 | + * This might be racy... | |
| 1523 | + */ | |
| 1524 | + if (!atomic_read(&num_events)) | |
| 1525 | + return NOTIFY_OK; | |
| 1526 | + | |
| 1527 | + switch (action & ~CPU_TASKS_FROZEN) { | |
| 1528 | + case CPU_ONLINE: | |
| 1529 | + case CPU_ONLINE_FROZEN: | |
| 1530 | + flags = PMC_INIT; | |
| 1531 | + smp_call_function_single(cpu, setup_pmc_cpu, &flags, 1); | |
| 1532 | + break; | |
| 1533 | + case CPU_DOWN_PREPARE: | |
| 1534 | + flags = PMC_RELEASE; | |
| 1535 | + smp_call_function_single(cpu, setup_pmc_cpu, &flags, 1); | |
| 1536 | + break; | |
| 1537 | + default: | |
| 1538 | + break; | |
| 1539 | + } | |
| 1540 | + | |
| 1541 | + return NOTIFY_OK; | |
| 1542 | +} | |
| 1543 | + | |
| 1544 | +static int param_get_sfb_size(char *buffer, const struct kernel_param *kp) | |
| 1545 | +{ | |
| 1546 | + if (!cpum_sf_avail()) | |
| 1547 | + return -ENODEV; | |
| 1548 | + return sprintf(buffer, "%lu,%lu", CPUM_SF_MIN_SDB, CPUM_SF_MAX_SDB); | |
| 1549 | +} | |
| 1550 | + | |
| 1551 | +static int param_set_sfb_size(const char *val, const struct kernel_param *kp) | |
| 1552 | +{ | |
| 1553 | + int rc; | |
| 1554 | + unsigned long min, max; | |
| 1555 | + | |
| 1556 | + if (!cpum_sf_avail()) | |
| 1557 | + return -ENODEV; | |
| 1558 | + if (!val || !strlen(val)) | |
| 1559 | + return -EINVAL; | |
| 1560 | + | |
| 1561 | + /* Valid parameter values: "min,max" or "max" */ | |
| 1562 | + min = CPUM_SF_MIN_SDB; | |
| 1563 | + max = CPUM_SF_MAX_SDB; | |
| 1564 | + if (strchr(val, ',')) | |
| 1565 | + rc = (sscanf(val, "%lu,%lu", &min, &max) == 2) ? 0 : -EINVAL; | |
| 1566 | + else | |
| 1567 | + rc = kstrtoul(val, 10, &max); | |
| 1568 | + | |
| 1569 | + if (min < 2 || min >= max || max > get_num_physpages()) | |
| 1570 | + rc = -EINVAL; | |
| 1571 | + if (rc) | |
| 1572 | + return rc; | |
| 1573 | + | |
| 1574 | + sfb_set_limits(min, max); | |
| 1575 | + pr_info("The sampling buffer limits have changed to: " | |
| 1576 | + "min=%lu max=%lu (diag=x%lu)\n", | |
| 1577 | + CPUM_SF_MIN_SDB, CPUM_SF_MAX_SDB, CPUM_SF_SDB_DIAG_FACTOR); | |
| 1578 | + return 0; | |
| 1579 | +} | |
| 1580 | + | |
| 1581 | +#define param_check_sfb_size(name, p) __param_check(name, p, void) | |
| 1582 | +static struct kernel_param_ops param_ops_sfb_size = { | |
| 1583 | + .set = param_set_sfb_size, | |
| 1584 | + .get = param_get_sfb_size, | |
| 1585 | +}; | |
| 1586 | + | |
| 1587 | +#define RS_INIT_FAILURE_QSI 0x0001 | |
| 1588 | +#define RS_INIT_FAILURE_BSDES 0x0002 | |
| 1589 | +#define RS_INIT_FAILURE_ALRT 0x0003 | |
| 1590 | +#define RS_INIT_FAILURE_PERF 0x0004 | |
| 1591 | +static void __init pr_cpumsf_err(unsigned int reason) | |
| 1592 | +{ | |
| 1593 | + pr_err("Sampling facility support for perf is not available: " | |
| 1594 | + "reason=%04x\n", reason); | |
| 1595 | +} | |
| 1596 | + | |
| 1597 | +static int __init init_cpum_sampling_pmu(void) | |
| 1598 | +{ | |
| 1599 | + struct hws_qsi_info_block si; | |
| 1600 | + int err; | |
| 1601 | + | |
| 1602 | + if (!cpum_sf_avail()) | |
| 1603 | + return -ENODEV; | |
| 1604 | + | |
| 1605 | + memset(&si, 0, sizeof(si)); | |
| 1606 | + if (qsi(&si)) { | |
| 1607 | + pr_cpumsf_err(RS_INIT_FAILURE_QSI); | |
| 1608 | + return -ENODEV; | |
| 1609 | + } | |
| 1610 | + | |
| 1611 | + if (si.bsdes != sizeof(struct hws_basic_entry)) { | |
| 1612 | + pr_cpumsf_err(RS_INIT_FAILURE_BSDES); | |
| 1613 | + return -EINVAL; | |
| 1614 | + } | |
| 1615 | + | |
| 1616 | + if (si.ad) | |
| 1617 | + sfb_set_limits(CPUM_SF_MIN_SDB, CPUM_SF_MAX_SDB); | |
| 1618 | + | |
| 1619 | + sfdbg = debug_register(KMSG_COMPONENT, 2, 1, 80); | |
| 1620 | + if (!sfdbg) | |
| 1621 | + pr_err("Registering for s390dbf failed\n"); | |
| 1622 | + debug_register_view(sfdbg, &debug_sprintf_view); | |
| 1623 | + | |
| 1624 | + err = register_external_interrupt(0x1407, cpumf_measurement_alert); | |
| 1625 | + if (err) { | |
| 1626 | + pr_cpumsf_err(RS_INIT_FAILURE_ALRT); | |
| 1627 | + goto out; | |
| 1628 | + } | |
| 1629 | + | |
| 1630 | + err = perf_pmu_register(&cpumf_sampling, "cpum_sf", PERF_TYPE_RAW); | |
| 1631 | + if (err) { | |
| 1632 | + pr_cpumsf_err(RS_INIT_FAILURE_PERF); | |
| 1633 | + unregister_external_interrupt(0x1407, cpumf_measurement_alert); | |
| 1634 | + goto out; | |
| 1635 | + } | |
| 1636 | + perf_cpu_notifier(cpumf_pmu_notifier); | |
| 1637 | +out: | |
| 1638 | + return err; | |
| 1639 | +} | |
| 1640 | +arch_initcall(init_cpum_sampling_pmu); | |
| 1641 | +core_param(cpum_sfb_size, CPUM_SF_MAX_SDB, sfb_size, 0640); | |
| @@ -1,7 +1,7 @@ | ||
| 1 | 1 | /* |
| 2 | 2 | * Performance event support for s390x |
| 3 | 3 | * |
| 4 | − * Copyright IBM Corp. 2012 | |
| 4 | + * Copyright IBM Corp. 2012, 2013 | |
| 5 | 5 | * Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com> |
| 6 | 6 | * |
| 7 | 7 | * This program is free software; you can redistribute it and/or modify |
| @@ -16,15 +16,19 @@ · 8 unmodified lines | ||
| 16 | 16 | #include <linux/kvm_host.h> |
| 17 | 17 | #include <linux/percpu.h> |
| 18 | 18 | #include <linux/export.h> |
| 19 | +#include <linux/seq_file.h> | |
| 20 | +#include <linux/spinlock.h> | |
| 21 | +#include <linux/sysfs.h> | |
| 19 | 22 | #include <asm/irq.h> |
| 20 | 23 | #include <asm/cpu_mf.h> |
| 21 | 24 | #include <asm/lowcore.h> |
| 22 | 25 | #include <asm/processor.h> |
| 26 | +#include <asm/sysinfo.h> | |
| 23 | 27 | |
| 24 | 28 | const char *perf_pmu_name(void) |
| 25 | 29 | { |
| 26 | 30 | if (cpum_cf_avail() || cpum_sf_avail()) |
| 27 | − return "CPU-measurement facilities (CPUMF)"; | |
| 31 | + return "CPU-Measurement Facilities (CPU-MF)"; | |
| 28 | 32 | return "pmu"; |
| 29 | 33 | } |
| 30 | 34 | EXPORT_SYMBOL(perf_pmu_name); |
| @@ -35,6 +39,8 @@ int perf_num_counters(void) · 4 unmodified lines | ||
| 35 | 39 | |
| 36 | 40 | if (cpum_cf_avail()) |
| 37 | 41 | num += PERF_CPUM_CF_MAX_CTR; |
| 42 | + if (cpum_sf_avail()) | |
| 43 | + num += PERF_CPUM_SF_MAX_CTR; | |
| 38 | 44 | |
| 39 | 45 | return num; |
| 40 | 46 | } |
| @@ -54,7 +60,7 @@ static bool is_in_guest(struct pt_regs *regs) · 13 unmodified lines | ||
| 54 | 60 | { |
| 55 | 61 | if (user_mode(regs)) |
| 56 | 62 | return false; |
| 57 | −#if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE) | |
| 63 | +#if IS_ENABLED(CONFIG_KVM) | |
| 58 | 64 | return instruction_pointer(regs) == (unsigned long) &sie_exit; |
| 59 | 65 | #else |
| 60 | 66 | return false; |
| @@ -83,8 +89,31 @@ static unsigned long perf_misc_guest_flags(struct pt_regs *regs) · 22 unmodified lines | ||
| 83 | 89 | : PERF_RECORD_MISC_GUEST_KERNEL; |
| 84 | 90 | } |
| 85 | 91 | |
| 92 | +static unsigned long perf_misc_flags_sf(struct pt_regs *regs) | |
| 93 | +{ | |
| 94 | + struct perf_sf_sde_regs *sde_regs; | |
| 95 | + unsigned long flags; | |
| 96 | + | |
| 97 | + sde_regs = (struct perf_sf_sde_regs *) ®s->int_parm_long; | |
| 98 | + if (sde_regs->in_guest) | |
| 99 | + flags = user_mode(regs) ? PERF_RECORD_MISC_GUEST_USER | |
| 100 | + : PERF_RECORD_MISC_GUEST_KERNEL; | |
| 101 | + else | |
| 102 | + flags = user_mode(regs) ? PERF_RECORD_MISC_USER | |
| 103 | + : PERF_RECORD_MISC_KERNEL; | |
| 104 | + return flags; | |
| 105 | +} | |
| 106 | + | |
| 86 | 107 | unsigned long perf_misc_flags(struct pt_regs *regs) |
| 87 | 108 | { |
| 109 | + /* Check if the cpum_sf PMU has created the pt_regs structure. | |
| 110 | + * In this case, perf misc flags can be easily extracted. Otherwise, | |
| 111 | + * do regular checks on the pt_regs content. | |
| 112 | + */ | |
| 113 | + if (regs->int_code == 0x1407 && regs->int_parm == CPU_MF_INT_SF_PRA) | |
| 114 | + if (!regs->gprs[15]) | |
| 115 | + return perf_misc_flags_sf(regs); | |
| 116 | + | |
| 88 | 117 | if (is_in_guest(regs)) |
| 89 | 118 | return perf_misc_guest_flags(regs); |
| 90 | 119 | |
| @@ -92,27 +121,107 @@ unsigned long perf_misc_flags(struct pt_regs *regs) · 1 unmodified line | ||
| 92 | 121 | : PERF_RECORD_MISC_KERNEL; |
| 93 | 122 | } |
| 94 | 123 | |
| 95 | −void perf_event_print_debug(void) | |
| 124 | +void print_debug_cf(void) | |
| 96 | 125 | { |
| 97 | 126 | struct cpumf_ctr_info cf_info; |
| 98 | − unsigned long flags; | |
| 99 | − int cpu; | |
| 100 | − | |
| 101 | − if (!cpum_cf_avail()) | |
| 102 | − return; | |
| 103 | − | |
| 104 | − local_irq_save(flags); | |
| 127 | + int cpu = smp_processor_id(); | |
| 105 | 128 | |
| 106 | − cpu = smp_processor_id(); | |
| 107 | 129 | memset(&cf_info, 0, sizeof(cf_info)); |
| 108 | 130 | if (!qctri(&cf_info)) |
| 109 | 131 | pr_info("CPU[%i] CPUM_CF: ver=%u.%u A=%04x E=%04x C=%04x\n", |
| 110 | 132 | cpu, cf_info.cfvn, cf_info.csvn, |
| 111 | 133 | cf_info.auth_ctl, cf_info.enable_ctl, cf_info.act_ctl); |
| 134 | +} | |
| 135 | + | |
| 136 | +static void print_debug_sf(void) | |
| 137 | +{ | |
| 138 | + struct hws_qsi_info_block si; | |
| 139 | + int cpu = smp_processor_id(); | |
| 112 | 140 | |
| 141 | + memset(&si, 0, sizeof(si)); | |
| 142 | + if (qsi(&si)) | |
| 143 | + return; | |
| 144 | + | |
| 145 | + pr_info("CPU[%i] CPUM_SF: basic=%i diag=%i min=%lu max=%lu cpu_speed=%u\n", | |
| 146 | + cpu, si.as, si.ad, si.min_sampl_rate, si.max_sampl_rate, | |
| 147 | + si.cpu_speed); | |
| 148 | + | |
| 149 | + if (si.as) | |
| 150 | + pr_info("CPU[%i] CPUM_SF: Basic-sampling: a=%i e=%i c=%i" | |
| 151 | + " bsdes=%i tear=%016lx dear=%016lx\n", cpu, | |
| 152 | + si.as, si.es, si.cs, si.bsdes, si.tear, si.dear); | |
| 153 | + if (si.ad) | |
| 154 | + pr_info("CPU[%i] CPUM_SF: Diagnostic-sampling: a=%i e=%i c=%i" | |
| 155 | + " dsdes=%i tear=%016lx dear=%016lx\n", cpu, | |
| 156 | + si.ad, si.ed, si.cd, si.dsdes, si.tear, si.dear); | |
| 157 | +} | |
| 158 | + | |
| 159 | +void perf_event_print_debug(void) | |
| 160 | +{ | |
| 161 | + unsigned long flags; | |
| 162 | + | |
| 163 | + local_irq_save(flags); | |
| 164 | + if (cpum_cf_avail()) | |
| 165 | + print_debug_cf(); | |
| 166 | + if (cpum_sf_avail()) | |
| 167 | + print_debug_sf(); | |
| 113 | 168 | local_irq_restore(flags); |
| 114 | 169 | } |
| 115 | 170 | |
| 171 | +/* Service level infrastructure */ | |
| 172 | +static void sl_print_counter(struct seq_file *m) | |
| 173 | +{ | |
| 174 | + struct cpumf_ctr_info ci; | |
| 175 | + | |
| 176 | + memset(&ci, 0, sizeof(ci)); | |
| 177 | + if (qctri(&ci)) | |
| 178 | + return; | |
| 179 | + | |
| 180 | + seq_printf(m, "CPU-MF: Counter facility: version=%u.%u " | |
| 181 | + "authorization=%04x\n", ci.cfvn, ci.csvn, ci.auth_ctl); | |
| 182 | +} | |
| 183 | + | |
| 184 | +static void sl_print_sampling(struct seq_file *m) | |
| 185 | +{ | |
| 186 | + struct hws_qsi_info_block si; | |
| 187 | + | |
| 188 | + memset(&si, 0, sizeof(si)); | |
| 189 | + if (qsi(&si)) | |
| 190 | + return; | |
| 191 | + | |
| 192 | + if (!si.as && !si.ad) | |
| 193 | + return; | |
| 194 | + | |
| 195 | + seq_printf(m, "CPU-MF: Sampling facility: min_rate=%lu max_rate=%lu" | |
| 196 | + " cpu_speed=%u\n", si.min_sampl_rate, si.max_sampl_rate, | |
| 197 | + si.cpu_speed); | |
| 198 | + if (si.as) | |
| 199 | + seq_printf(m, "CPU-MF: Sampling facility: mode=basic" | |
| 200 | + " sample_size=%u\n", si.bsdes); | |
| 201 | + if (si.ad) | |
| 202 | + seq_printf(m, "CPU-MF: Sampling facility: mode=diagnostic" | |
| 203 | + " sample_size=%u\n", si.dsdes); | |
| 204 | +} | |
| 205 | + | |
| 206 | +static void service_level_perf_print(struct seq_file *m, | |
| 207 | + struct service_level *sl) | |
| 208 | +{ | |
| 209 | + if (cpum_cf_avail()) | |
| 210 | + sl_print_counter(m); | |
| 211 | + if (cpum_sf_avail()) | |
| 212 | + sl_print_sampling(m); | |
| 213 | +} | |
| 214 | + | |
| 215 | +static struct service_level service_level_perf = { | |
| 216 | + .seq_print = service_level_perf_print, | |
| 217 | +}; | |
| 218 | + | |
| 219 | +static int __init service_level_perf_register(void) | |
| 220 | +{ | |
| 221 | + return register_service_level(&service_level_perf); | |
| 222 | +} | |
| 223 | +arch_initcall(service_level_perf_register); | |
| 224 | + | |
| 116 | 225 | /* See also arch/s390/kernel/traps.c */ |
| 117 | 226 | static unsigned long __store_trace(struct perf_callchain_entry *entry, |
| 118 | 227 | unsigned long sp, |
| @@ -172,3 +281,44 @@ void perf_callchain_kernel(struct perf_callchain_entry *entry, · 53 unmodified lines | ||
| 172 | 281 | __store_trace(entry, head, S390_lowcore.thread_info, |
| 173 | 282 | S390_lowcore.thread_info + THREAD_SIZE); |
| 174 | 283 | } |
| 284 | + | |
| 285 | +/* Perf defintions for PMU event attributes in sysfs */ | |
| 286 | +ssize_t cpumf_events_sysfs_show(struct device *dev, | |
| 287 | + struct device_attribute *attr, char *page) | |
| 288 | +{ | |
| 289 | + struct perf_pmu_events_attr *pmu_attr; | |
| 290 | + | |
| 291 | + pmu_attr = container_of(attr, struct perf_pmu_events_attr, attr); | |
| 292 | + return sprintf(page, "event=0x%04llx,name=%s\n", | |
| 293 | + pmu_attr->id, attr->attr.name); | |
| 294 | +} | |
| 295 | + | |
| 296 | +/* Reserve/release functions for sharing perf hardware */ | |
| 297 | +static DEFINE_SPINLOCK(perf_hw_owner_lock); | |
| 298 | +static void *perf_sampling_owner; | |
| 299 | + | |
| 300 | +int perf_reserve_sampling(void) | |
| 301 | +{ | |
| 302 | + int err; | |
| 303 | + | |
| 304 | + err = 0; | |
| 305 | + spin_lock(&perf_hw_owner_lock); | |
| 306 | + if (perf_sampling_owner) { | |
| 307 | + pr_warn("The sampling facility is already reserved by %p\n", | |
| 308 | + perf_sampling_owner); | |
| 309 | + err = -EBUSY; | |
| 310 | + } else | |
| 311 | + perf_sampling_owner = __builtin_return_address(0); | |
| 312 | + spin_unlock(&perf_hw_owner_lock); | |
| 313 | + return err; | |
| 314 | +} | |
| 315 | +EXPORT_SYMBOL(perf_reserve_sampling); | |
| 316 | + | |
| 317 | +void perf_release_sampling(void) | |
| 318 | +{ | |
| 319 | + spin_lock(&perf_hw_owner_lock); | |
| 320 | + WARN_ON(!perf_sampling_owner); | |
| 321 | + perf_sampling_owner = NULL; | |
| 322 | + spin_unlock(&perf_hw_owner_lock); | |
| 323 | +} | |
| 324 | +EXPORT_SYMBOL(perf_release_sampling); | |
| @@ -261,20 +261,18 @@ static inline unsigned long brk_rnd(void) · 260 unmodified lines | ||
| 261 | 261 | |
| 262 | 262 | unsigned long arch_randomize_brk(struct mm_struct *mm) |
| 263 | 263 | { |
| 264 | − unsigned long ret = PAGE_ALIGN(mm->brk + brk_rnd()); | |
| 264 | + unsigned long ret; | |
| 265 | 265 | |
| 266 | − if (ret < mm->brk) | |
| 267 | − return mm->brk; | |
| 268 | − return ret; | |
| 266 | + ret = PAGE_ALIGN(mm->brk + brk_rnd()); | |
| 267 | + return (ret > mm->brk) ? ret : mm->brk; | |
| 269 | 268 | } |
| 270 | 269 | |
| 271 | 270 | unsigned long randomize_et_dyn(unsigned long base) |
| 272 | 271 | { |
| 273 | − unsigned long ret = PAGE_ALIGN(base + brk_rnd()); | |
| 272 | + unsigned long ret; | |
| 274 | 273 | |
| 275 | 274 | if (!(current->flags & PF_RANDOMIZE)) |
| 276 | 275 | return base; |
| 277 | − if (ret < base) | |
| 278 | − return base; | |
| 279 | − return ret; | |
| 276 | + ret = PAGE_ALIGN(base + brk_rnd()); | |
| 277 | + return (ret > base) ? ret : base; | |
| 280 | 278 | } |
| @@ -56,25 +56,26 @@ void update_cr_regs(struct task_struct *task) · 55 unmodified lines | ||
| 56 | 56 | #ifdef CONFIG_64BIT |
| 57 | 57 | /* Take care of the enable/disable of transactional execution. */ |
| 58 | 58 | if (MACHINE_HAS_TE) { |
| 59 | − unsigned long cr[3], cr_new[3]; | |
| 59 | + unsigned long cr, cr_new; | |
| 60 | 60 | |
| 61 | − __ctl_store(cr, 0, 2); | |
| 62 | − cr_new[1] = cr[1]; | |
| 61 | + __ctl_store(cr, 0, 0); | |
| 63 | 62 | /* Set or clear transaction execution TXC bit 8. */ |
| 63 | + cr_new = cr | (1UL << 55); | |
| 64 | 64 | if (task->thread.per_flags & PER_FLAG_NO_TE) |
| 65 | − cr_new[0] = cr[0] & ~(1UL << 55); | |
| 66 | − else | |
| 67 | − cr_new[0] = cr[0] | (1UL << 55); | |
| 65 | + cr_new &= ~(1UL << 55); | |
| 66 | + if (cr_new != cr) | |
| 67 | + __ctl_load(cr, 0, 0); | |
| 68 | 68 | /* Set or clear transaction execution TDC bits 62 and 63. */ |
| 69 | − cr_new[2] = cr[2] & ~3UL; | |
| 69 | + __ctl_store(cr, 2, 2); | |
| 70 | + cr_new = cr & ~3UL; | |
| 70 | 71 | if (task->thread.per_flags & PER_FLAG_TE_ABORT_RAND) { |
| 71 | 72 | if (task->thread.per_flags & PER_FLAG_TE_ABORT_RAND_TEND) |
| 72 | − cr_new[2] |= 1UL; | |
| 73 | + cr_new |= 1UL; | |
| 73 | 74 | else |
| 74 | − cr_new[2] |= 2UL; | |
| 75 | + cr_new |= 2UL; | |
| 75 | 76 | } |
| 76 | − if (memcmp(&cr_new, &cr, sizeof(cr))) | |
| 77 | − __ctl_load(cr_new, 0, 2); | |
| 77 | + if (cr_new != cr) | |
| 78 | + __ctl_load(cr_new, 2, 2); | |
| 78 | 79 | } |
| 79 | 80 | #endif |
| 80 | 81 | /* Copy user specified PER registers */ |
| @@ -107,15 +108,11 @@ void update_cr_regs(struct task_struct *task) · 26 unmodified lines | ||
| 107 | 108 | void user_enable_single_step(struct task_struct *task) |
| 108 | 109 | { |
| 109 | 110 | set_tsk_thread_flag(task, TIF_SINGLE_STEP); |
| 110 | − if (task == current) | |
| 111 | − update_cr_regs(task); | |
| 112 | 111 | } |
| 113 | 112 | |
| 114 | 113 | void user_disable_single_step(struct task_struct *task) |
| 115 | 114 | { |
| 116 | 115 | clear_tsk_thread_flag(task, TIF_SINGLE_STEP); |
| 117 | − if (task == current) | |
| 118 | − update_cr_regs(task); | |
| 119 | 116 | } |
| 120 | 117 | |
| 121 | 118 | /* |
| @@ -5,7 +5,7 @@ · 4 unmodified lines | ||
| 5 | 5 | #ifdef CONFIG_FUNCTION_TRACER |
| 6 | 6 | EXPORT_SYMBOL(_mcount); |
| 7 | 7 | #endif |
| 8 | −#if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE) | |
| 8 | +#if IS_ENABLED(CONFIG_KVM) | |
| 9 | 9 | EXPORT_SYMBOL(sie64a); |
| 10 | 10 | EXPORT_SYMBOL(sie_exit); |
| 11 | 11 | #endif |
| @@ -373,7 +373,7 @@ static void __init setup_lowcore(void) · 372 unmodified lines | ||
| 373 | 373 | |
| 374 | 374 | /* |
| 375 | 375 | * Set up PSW restart to call ipl.c:do_restart(). Copy the relevant |
| 376 | − * restart data to the absolute zero lowcore. This is necesary if | |
| 376 | + * restart data to the absolute zero lowcore. This is necessary if | |
| 377 | 377 | * PSW restart is done on an offline CPU that has lowcore zero. |
| 378 | 378 | */ |
| 379 | 379 | lc->restart_stack = (unsigned long) restart_stack; |
| @@ -59,7 +59,7 @@ enum { · 58 unmodified lines | ||
| 59 | 59 | }; |
| 60 | 60 | |
| 61 | 61 | struct pcpu { |
| 62 | − struct cpu cpu; | |
| 62 | + struct cpu *cpu; | |
| 63 | 63 | struct _lowcore *lowcore; /* lowcore page(s) for the cpu */ |
| 64 | 64 | unsigned long async_stack; /* async stack for the cpu */ |
| 65 | 65 | unsigned long panic_stack; /* panic stack for the cpu */ |
| @@ -159,9 +159,9 @@ static void pcpu_ec_call(struct pcpu *pcpu, int ec_bit) · 93 unmodified lines | ||
| 159 | 159 | { |
| 160 | 160 | int order; |
| 161 | 161 | |
| 162 | − set_bit(ec_bit, &pcpu->ec_mask); | |
| 163 | − order = pcpu_running(pcpu) ? | |
| 164 | − SIGP_EXTERNAL_CALL : SIGP_EMERGENCY_SIGNAL; | |
| 162 | + if (test_and_set_bit(ec_bit, &pcpu->ec_mask)) | |
| 163 | + return; | |
| 164 | + order = pcpu_running(pcpu) ? SIGP_EXTERNAL_CALL : SIGP_EMERGENCY_SIGNAL; | |
| 165 | 165 | pcpu_sigp_retry(pcpu, order, 0); |
| 166 | 166 | } |
| 167 | 167 | |
| @@ -965,7 +965,7 @@ static int smp_cpu_notify(struct notifier_block *self, unsigned long action, · 797 unmodified lines | ||
| 965 | 965 | void *hcpu) |
| 966 | 966 | { |
| 967 | 967 | unsigned int cpu = (unsigned int)(long)hcpu; |
| 968 | − struct cpu *c = &pcpu_devices[cpu].cpu; | |
| 968 | + struct cpu *c = pcpu_devices[cpu].cpu; | |
| 969 | 969 | struct device *s = &c->dev; |
| 970 | 970 | int err = 0; |
| 971 | 971 | |
| @@ -982,10 +982,15 @@ static int smp_cpu_notify(struct notifier_block *self, unsigned long action, · 10 unmodified lines | ||
| 982 | 982 | |
| 983 | 983 | static int smp_add_present_cpu(int cpu) |
| 984 | 984 | { |
| 985 | − struct cpu *c = &pcpu_devices[cpu].cpu; | |
| 986 | − struct device *s = &c->dev; | |
| 985 | + struct device *s; | |
| 986 | + struct cpu *c; | |
| 987 | 987 | int rc; |
| 988 | 988 | |
| 989 | + c = kzalloc(sizeof(*c), GFP_KERNEL); | |
| 990 | + if (!c) | |
| 991 | + return -ENOMEM; | |
| 992 | + pcpu_devices[cpu].cpu = c; | |
| 993 | + s = &c->dev; | |
| 989 | 994 | c->hotpluggable = 1; |
| 990 | 995 | rc = register_cpu(c, cpu); |
| 991 | 996 | if (rc) |
| @@ -275,7 +275,7 @@ static int handle_io_inst(struct kvm_vcpu *vcpu) · 274 unmodified lines | ||
| 275 | 275 | return -EOPNOTSUPP; |
| 276 | 276 | } else { |
| 277 | 277 | /* |
| 278 | − * Set condition code 3 to stop the guest from issueing channel | |
| 278 | + * Set condition code 3 to stop the guest from issuing channel | |
| 279 | 279 | * I/O instructions. |
| 280 | 280 | */ |
| 281 | 281 | kvm_s390_set_psw_cc(vcpu, 3); |
| @@ -74,8 +74,8 @@ static size_t copy_in_kernel(size_t count, void __user *to, · 73 unmodified lines | ||
| 74 | 74 | |
| 75 | 75 | /* |
| 76 | 76 | * Returns kernel address for user virtual address. If the returned address is |
| 77 | − * >= -4095 (IS_ERR_VALUE(x) returns true), a fault has occured and the address | |
| 78 | − * contains the (negative) exception code. | |
| 77 | + * >= -4095 (IS_ERR_VALUE(x) returns true), a fault has occurred and the | |
| 78 | + * address contains the (negative) exception code. | |
| 79 | 79 | */ |
| 80 | 80 | #ifdef CONFIG_64BIT |
| 81 | 81 | |
| @@ -293,7 +293,7 @@ static int gmap_alloc_table(struct gmap *gmap, · 292 unmodified lines | ||
| 293 | 293 | * @addr: address in the guest address space |
| 294 | 294 | * @len: length of the memory area to unmap |
| 295 | 295 | * |
| 296 | − * Returns 0 if the unmap succeded, -EINVAL if not. | |
| 296 | + * Returns 0 if the unmap succeeded, -EINVAL if not. | |
| 297 | 297 | */ |
| 298 | 298 | int gmap_unmap_segment(struct gmap *gmap, unsigned long to, unsigned long len) |
| 299 | 299 | { |
| @@ -344,7 +344,7 @@ EXPORT_SYMBOL_GPL(gmap_unmap_segment); · 44 unmodified lines | ||
| 344 | 344 | * @from: source address in the parent address space |
| 345 | 345 | * @to: target address in the guest address space |
| 346 | 346 | * |
| 347 | − * Returns 0 if the mmap succeded, -EINVAL or -ENOMEM if not. | |
| 347 | + * Returns 0 if the mmap succeeded, -EINVAL or -ENOMEM if not. | |
| 348 | 348 | */ |
| 349 | 349 | int gmap_map_segment(struct gmap *gmap, unsigned long from, |
| 350 | 350 | unsigned long to, unsigned long len) |
| @@ -26,9 +26,6 @@ · 25 unmodified lines | ||
| 26 | 26 | #define MAX_NUM_SDB 511 |
| 27 | 27 | #define MIN_NUM_SDB 1 |
| 28 | 28 | |
| 29 | −#define ALERT_REQ_MASK 0x4000000000000000ul | |
| 30 | −#define BUFFER_FULL_MASK 0x8000000000000000ul | |
| 31 | − | |
| 32 | 29 | DECLARE_PER_CPU(struct hws_cpu_buffer, sampler_cpu_buffer); |
| 33 | 30 | |
| 34 | 31 | struct hws_execute_parms { |
| @@ -44,6 +41,7 @@ static DEFINE_MUTEX(hws_sem_oom); · 9 unmodified lines | ||
| 44 | 41 | |
| 45 | 42 | static unsigned char hws_flush_all; |
| 46 | 43 | static unsigned int hws_oom; |
| 44 | +static unsigned int hws_alert; | |
| 47 | 45 | static struct workqueue_struct *hws_wq; |
| 48 | 46 | |
| 49 | 47 | static unsigned int hws_state; |
| @@ -65,43 +63,6 @@ static unsigned long interval; · 15 unmodified lines | ||
| 65 | 63 | static unsigned long min_sampler_rate; |
| 66 | 64 | static unsigned long max_sampler_rate; |
| 67 | 65 | |
| 68 | −static int ssctl(void *buffer) | |
| 69 | −{ | |
| 70 | − int cc; | |
| 71 | − | |
| 72 | − /* set in order to detect a program check */ | |
| 73 | − cc = 1; | |
| 74 | − | |
| 75 | − asm volatile( | |
| 76 | − "0: .insn s,0xB2870000,0(%1)\n" | |
| 77 | − "1: ipm %0\n" | |
| 78 | − " srl %0,28\n" | |
| 79 | − "2:\n" | |
| 80 | − EX_TABLE(0b, 2b) EX_TABLE(1b, 2b) | |
| 81 | − : "+d" (cc), "+a" (buffer) | |
| 82 | − : "m" (*((struct hws_ssctl_request_block *)buffer)) | |
| 83 | − : "cc", "memory"); | |
| 84 | − | |
| 85 | − return cc ? -EINVAL : 0 ; | |
| 86 | −} | |
| 87 | − | |
| 88 | −static int qsi(void *buffer) | |
| 89 | −{ | |
| 90 | − int cc; | |
| 91 | − cc = 1; | |
| 92 | − | |
| 93 | − asm volatile( | |
| 94 | − "0: .insn s,0xB2860000,0(%1)\n" | |
| 95 | − "1: lhi %0,0\n" | |
| 96 | − "2:\n" | |
| 97 | − EX_TABLE(0b, 2b) EX_TABLE(1b, 2b) | |
| 98 | − : "=d" (cc), "+a" (buffer) | |
| 99 | − : "m" (*((struct hws_qsi_info_block *)buffer)) | |
| 100 | − : "cc", "memory"); | |
| 101 | − | |
| 102 | − return cc ? -EINVAL : 0; | |
| 103 | −} | |
| 104 | − | |
| 105 | 66 | static void execute_qsi(void *parms) |
| 106 | 67 | { |
| 107 | 68 | struct hws_execute_parms *ep = parms; |
| @@ -113,7 +74,7 @@ static void execute_ssctl(void *parms) · 5 unmodified lines | ||
| 113 | 74 | { |
| 114 | 75 | struct hws_execute_parms *ep = parms; |
| 115 | 76 | |
| 116 | − ep->rc = ssctl(ep->buffer); | |
| 77 | + ep->rc = lsctl(ep->buffer); | |
| 117 | 78 | } |
| 118 | 79 | |
| 119 | 80 | static int smp_ctl_ssctl_stop(int cpu) |
| @@ -214,17 +175,6 @@ static int smp_ctl_qsi(int cpu) · 94 unmodified lines | ||
| 214 | 175 | return ep.rc; |
| 215 | 176 | } |
| 216 | 177 | |
| 217 | −static inline unsigned long *trailer_entry_ptr(unsigned long v) | |
| 218 | −{ | |
| 219 | − void *ret; | |
| 220 | − | |
| 221 | − ret = (void *)v; | |
| 222 | − ret += PAGE_SIZE; | |
| 223 | − ret -= sizeof(struct hws_trailer_entry); | |
| 224 | − | |
| 225 | − return (unsigned long *) ret; | |
| 226 | −} | |
| 227 | − | |
| 228 | 178 | static void hws_ext_handler(struct ext_code ext_code, |
| 229 | 179 | unsigned int param32, unsigned long param64) |
| 230 | 180 | { |
| @@ -233,6 +183,9 @@ static void hws_ext_handler(struct ext_code ext_code, · 2 unmodified lines | ||
| 233 | 183 | if (!(param32 & CPU_MF_INT_SF_MASK)) |
| 234 | 184 | return; |
| 235 | 185 | |
| 186 | + if (!hws_alert) | |
| 187 | + return; | |
| 188 | + | |
| 236 | 189 | inc_irq_stat(IRQEXT_CMS); |
| 237 | 190 | atomic_xchg(&cb->ext_params, atomic_read(&cb->ext_params) | param32); |
| 238 | 191 | |
| @@ -256,16 +209,6 @@ static void init_all_cpu_buffers(void) · 17 unmodified lines | ||
| 256 | 209 | } |
| 257 | 210 | } |
| 258 | 211 | |
| 259 | −static int is_link_entry(unsigned long *s) | |
| 260 | −{ | |
| 261 | − return *s & 0x1ul ? 1 : 0; | |
| 262 | −} | |
| 263 | − | |
| 264 | −static unsigned long *get_next_sdbt(unsigned long *s) | |
| 265 | −{ | |
| 266 | − return (unsigned long *) (*s & ~0x1ul); | |
| 267 | −} | |
| 268 | − | |
| 269 | 212 | static int prepare_cpu_buffers(void) |
| 270 | 213 | { |
| 271 | 214 | int cpu; |
| @@ -353,7 +296,7 @@ static int allocate_sdbt(int cpu) · 81 unmodified lines | ||
| 353 | 296 | } |
| 354 | 297 | *sdbt = sdb; |
| 355 | 298 | trailer = trailer_entry_ptr(*sdbt); |
| 356 | − *trailer = ALERT_REQ_MASK; | |
| 299 | + *trailer = SDB_TE_ALERT_REQ_MASK; | |
| 357 | 300 | sdbt++; |
| 358 | 301 | mutex_unlock(&hws_sem_oom); |
| 359 | 302 | } |
| @@ -829,7 +772,7 @@ static void worker_on_interrupt(unsigned int cpu) · 469 unmodified lines | ||
| 829 | 772 | |
| 830 | 773 | trailer = trailer_entry_ptr(*sdbt); |
| 831 | 774 | /* leave loop if no more work to do */ |
| 832 | − if (!(*trailer & BUFFER_FULL_MASK)) { | |
| 775 | + if (!(*trailer & SDB_TE_BUFFER_FULL_MASK)) { | |
| 833 | 776 | done = 1; |
| 834 | 777 | if (!hws_flush_all) |
| 835 | 778 | continue; |
| @@ -856,7 +799,7 @@ static void worker_on_interrupt(unsigned int cpu) · 20 unmodified lines | ||
| 856 | 799 | static void add_samples_to_oprofile(unsigned int cpu, unsigned long *sdbt, |
| 857 | 800 | unsigned long *dear) |
| 858 | 801 | { |
| 859 | − struct hws_data_entry *sample_data_ptr; | |
| 802 | + struct hws_basic_entry *sample_data_ptr; | |
| 860 | 803 | unsigned long *trailer; |
| 861 | 804 | |
| 862 | 805 | trailer = trailer_entry_ptr(*sdbt); |
| @@ -866,7 +809,7 @@ static void add_samples_to_oprofile(unsigned int cpu, unsigned long *sdbt, · 3 unmodified lines | ||
| 866 | 809 | trailer = dear; |
| 867 | 810 | } |
| 868 | 811 | |
| 869 | − sample_data_ptr = (struct hws_data_entry *)(*sdbt); | |
| 812 | + sample_data_ptr = (struct hws_basic_entry *)(*sdbt); | |
| 870 | 813 | |
| 871 | 814 | while ((unsigned long *)sample_data_ptr < trailer) { |
| 872 | 815 | struct pt_regs *regs = NULL; |
| @@ -1002,6 +945,7 @@ int hwsampler_deallocate(void) · 129 unmodified lines | ||
| 1002 | 945 | goto deallocate_exit; |
| 1003 | 946 | |
| 1004 | 947 | irq_subclass_unregister(IRQ_SUBCLASS_MEASUREMENT_ALERT); |
| 948 | + hws_alert = 0; | |
| 1005 | 949 | deallocate_sdbt(); |
| 1006 | 950 | |
| 1007 | 951 | hws_state = HWS_DEALLOCATED; |
| @@ -1116,6 +1060,7 @@ int hwsampler_shutdown(void) · 108 unmodified lines | ||
| 1116 | 1060 | |
| 1117 | 1061 | if (hws_state == HWS_STOPPED) { |
| 1118 | 1062 | irq_subclass_unregister(IRQ_SUBCLASS_MEASUREMENT_ALERT); |
| 1063 | + hws_alert = 0; | |
| 1119 | 1064 | deallocate_sdbt(); |
| 1120 | 1065 | } |
| 1121 | 1066 | if (hws_wq) { |
| @@ -1190,6 +1135,7 @@ start_all_exit: · 68 unmodified lines | ||
| 1190 | 1135 | hws_oom = 1; |
| 1191 | 1136 | hws_flush_all = 0; |
| 1192 | 1137 | /* now let them in, 1407 CPUMF external interrupts */ |
| 1138 | + hws_alert = 1; | |
| 1193 | 1139 | irq_subclass_register(IRQ_SUBCLASS_MEASUREMENT_ALERT); |
| 1194 | 1140 | |
| 1195 | 1141 | return 0; |
| @@ -9,27 +9,7 @@ · 8 unmodified lines | ||
| 9 | 9 | #define HWSAMPLER_H_ |
| 10 | 10 | |
| 11 | 11 | #include <linux/workqueue.h> |
| 12 | − | |
| 13 | −struct hws_qsi_info_block /* QUERY SAMPLING information block */ | |
| 14 | −{ /* Bit(s) */ | |
| 15 | − unsigned int b0_13:14; /* 0-13: zeros */ | |
| 16 | − unsigned int as:1; /* 14: sampling authorisation control*/ | |
| 17 | − unsigned int b15_21:7; /* 15-21: zeros */ | |
| 18 | − unsigned int es:1; /* 22: sampling enable control */ | |
| 19 | − unsigned int b23_29:7; /* 23-29: zeros */ | |
| 20 | − unsigned int cs:1; /* 30: sampling activation control */ | |
| 21 | − unsigned int:1; /* 31: reserved */ | |
| 22 | − unsigned int bsdes:16; /* 4-5: size of sampling entry */ | |
| 23 | − unsigned int:16; /* 6-7: reserved */ | |
| 24 | − unsigned long min_sampl_rate; /* 8-15: minimum sampling interval */ | |
| 25 | − unsigned long max_sampl_rate; /* 16-23: maximum sampling interval*/ | |
| 26 | − unsigned long tear; /* 24-31: TEAR contents */ | |
| 27 | − unsigned long dear; /* 32-39: DEAR contents */ | |
| 28 | − unsigned int rsvrd0; /* 40-43: reserved */ | |
| 29 | − unsigned int cpu_speed; /* 44-47: CPU speed */ | |
| 30 | − unsigned long long rsvrd1; /* 48-55: reserved */ | |
| 31 | − unsigned long long rsvrd2; /* 56-63: reserved */ | |
| 32 | −}; | |
| 12 | +#include <asm/cpu_mf.h> | |
| 33 | 13 | |
| 34 | 14 | struct hws_ssctl_request_block /* SET SAMPLING CONTROLS req block */ |
| 35 | 15 | { /* bytes 0 - 7 Bit(s) */ |
| @@ -68,36 +48,6 @@ struct hws_cpu_buffer { · 32 unmodified lines | ||
| 68 | 48 | unsigned int stop_mode:1; |
| 69 | 49 | }; |
| 70 | 50 | |
| 71 | −struct hws_data_entry { | |
| 72 | − unsigned int def:16; /* 0-15 Data Entry Format */ | |
| 73 | − unsigned int R:4; /* 16-19 reserved */ | |
| 74 | − unsigned int U:4; /* 20-23 Number of unique instruct. */ | |
| 75 | − unsigned int z:2; /* zeros */ | |
| 76 | − unsigned int T:1; /* 26 PSW DAT mode */ | |
| 77 | − unsigned int W:1; /* 27 PSW wait state */ | |
| 78 | − unsigned int P:1; /* 28 PSW Problem state */ | |
| 79 | − unsigned int AS:2; /* 29-30 PSW address-space control */ | |
| 80 | − unsigned int I:1; /* 31 entry valid or invalid */ | |
| 81 | − unsigned int:16; | |
| 82 | − unsigned int prim_asn:16; /* primary ASN */ | |
| 83 | − unsigned long long ia; /* Instruction Address */ | |
| 84 | − unsigned long long gpp; /* Guest Program Parameter */ | |
| 85 | − unsigned long long hpp; /* Host Program Parameter */ | |
| 86 | −}; | |
| 87 | − | |
| 88 | −struct hws_trailer_entry { | |
| 89 | − unsigned int f:1; /* 0 - Block Full Indicator */ | |
| 90 | − unsigned int a:1; /* 1 - Alert request control */ | |
| 91 | − unsigned long:62; /* 2 - 63: Reserved */ | |
| 92 | − unsigned long overflow; /* 64 - sample Overflow count */ | |
| 93 | − unsigned long timestamp; /* 16 - time-stamp */ | |
| 94 | − unsigned long timestamp1; /* */ | |
| 95 | − unsigned long reserved1; /* 32 -Reserved */ | |
| 96 | − unsigned long reserved2; /* */ | |
| 97 | − unsigned long progusage1; /* 48 - reserved for programming use */ | |
| 98 | − unsigned long progusage2; /* */ | |
| 99 | −}; | |
| 100 | − | |
| 101 | 51 | int hwsampler_setup(void); |
| 102 | 52 | int hwsampler_shutdown(void); |
| 103 | 53 | int hwsampler_allocate(unsigned long sdbt, unsigned long sdb); |
| @@ -10,6 +10,7 @@ · 9 unmodified lines | ||
| 10 | 10 | */ |
| 11 | 11 | |
| 12 | 12 | #include <linux/oprofile.h> |
| 13 | +#include <linux/perf_event.h> | |
| 13 | 14 | #include <linux/init.h> |
| 14 | 15 | #include <linux/errno.h> |
| 15 | 16 | #include <linux/fs.h> |
| @@ -67,6 +68,21 @@ module_param_call(cpu_type, set_cpu_type, NULL, NULL, 0); · 51 unmodified lines | ||
| 67 | 68 | MODULE_PARM_DESC(cpu_type, "Force legacy basic mode sampling" |
| 68 | 69 | "(report cpu_type \"timer\""); |
| 69 | 70 | |
| 71 | +static int __oprofile_hwsampler_start(void) | |
| 72 | +{ | |
| 73 | + int retval; | |
| 74 | + | |
| 75 | + retval = hwsampler_allocate(oprofile_sdbt_blocks, oprofile_sdb_blocks); | |
| 76 | + if (retval) | |
| 77 | + return retval; | |
| 78 | + | |
| 79 | + retval = hwsampler_start_all(oprofile_hw_interval); | |
| 80 | + if (retval) | |
| 81 | + hwsampler_deallocate(); | |
| 82 | + | |
| 83 | + return retval; | |
| 84 | +} | |
| 85 | + | |
| 70 | 86 | static int oprofile_hwsampler_start(void) |
| 71 | 87 | { |
| 72 | 88 | int retval; |
| @@ -76,13 +92,13 @@ static int oprofile_hwsampler_start(void) · 3 unmodified lines | ||
| 76 | 92 | if (!hwsampler_running) |
| 77 | 93 | return timer_ops.start(); |
| 78 | 94 | |
| 79 | − retval = hwsampler_allocate(oprofile_sdbt_blocks, oprofile_sdb_blocks); | |
| 95 | + retval = perf_reserve_sampling(); | |
| 80 | 96 | if (retval) |
| 81 | 97 | return retval; |
| 82 | 98 | |
| 83 | − retval = hwsampler_start_all(oprofile_hw_interval); | |
| 99 | + retval = __oprofile_hwsampler_start(); | |
| 84 | 100 | if (retval) |
| 85 | − hwsampler_deallocate(); | |
| 101 | + perf_release_sampling(); | |
| 86 | 102 | |
| 87 | 103 | return retval; |
| 88 | 104 | } |
| @@ -96,6 +112,7 @@ static void oprofile_hwsampler_stop(void) · 7 unmodified lines | ||
| 96 | 112 | |
| 97 | 113 | hwsampler_stop_all(); |
| 98 | 114 | hwsampler_deallocate(); |
| 115 | + perf_release_sampling(); | |
| 99 | 116 | return; |
| 100 | 117 | } |
| 101 | 118 | |
| @@ -919,17 +919,23 @@ static void zpci_mem_exit(void) · 918 unmodified lines | ||
| 919 | 919 | kmem_cache_destroy(zdev_fmb_cache); |
| 920 | 920 | } |
| 921 | 921 | |
| 922 | −static unsigned int s390_pci_probe; | |
| 922 | +static unsigned int s390_pci_probe = 1; | |
| 923 | +static unsigned int s390_pci_initialized; | |
| 923 | 924 | |
| 924 | 925 | char * __init pcibios_setup(char *str) |
| 925 | 926 | { |
| 926 | − if (!strcmp(str, "on")) { | |
| 927 | − s390_pci_probe = 1; | |
| 927 | + if (!strcmp(str, "off")) { | |
| 928 | + s390_pci_probe = 0; | |
| 928 | 929 | return NULL; |
| 929 | 930 | } |
| 930 | 931 | return str; |
| 931 | 932 | } |
| 932 | 933 | |
| 934 | +bool zpci_is_enabled(void) | |
| 935 | +{ | |
| 936 | + return s390_pci_initialized; | |
| 937 | +} | |
| 938 | + | |
| 933 | 939 | static int __init pci_base_init(void) |
| 934 | 940 | { |
| 935 | 941 | int rc; |
| @@ -961,6 +967,7 @@ static int __init pci_base_init(void) · 25 unmodified lines | ||
| 961 | 967 | if (rc) |
| 962 | 968 | goto out_find; |
| 963 | 969 | |
| 970 | + s390_pci_initialized = 1; | |
| 964 | 971 | return 0; |
| 965 | 972 | |
| 966 | 973 | out_find: |
| @@ -978,5 +985,6 @@ subsys_initcall_sync(pci_base_init); · 11 unmodified lines | ||
| 978 | 985 | |
| 979 | 986 | void zpci_rescan(void) |
| 980 | 987 | { |
| 981 | − clp_rescan_pci_devices_simple(); | |
| 988 | + if (zpci_is_enabled()) | |
| 989 | + clp_rescan_pci_devices_simple(); | |
| 982 | 990 | } |
| @@ -285,7 +285,7 @@ static dma_addr_t s390_dma_map_pages(struct device *dev, struct page *page, · 284 unmodified lines | ||
| 285 | 285 | flags |= ZPCI_TABLE_PROTECTED; |
| 286 | 286 | |
| 287 | 287 | if (!dma_update_trans(zdev, pa, dma_addr, size, flags)) { |
| 288 | − atomic64_add(nr_pages, (atomic64_t *) &zdev->fmb->mapped_pages); | |
| 288 | + atomic64_add(nr_pages, &zdev->fmb->mapped_pages); | |
| 289 | 289 | return dma_addr + (offset & ~PAGE_MASK); |
| 290 | 290 | } |
| 291 | 291 | |
| @@ -313,7 +313,7 @@ static void s390_dma_unmap_pages(struct device *dev, dma_addr_t dma_addr, · 21 unmodified lines | ||
| 313 | 313 | zpci_err_hex(&dma_addr, sizeof(dma_addr)); |
| 314 | 314 | } |
| 315 | 315 | |
| 316 | − atomic64_add(npages, (atomic64_t *) &zdev->fmb->unmapped_pages); | |
| 316 | + atomic64_add(npages, &zdev->fmb->unmapped_pages); | |
| 317 | 317 | iommu_page_index = (dma_addr - zdev->start_dma) >> PAGE_SHIFT; |
| 318 | 318 | dma_free_iommu(zdev, iommu_page_index, npages); |
| 319 | 319 | } |
| @@ -332,7 +332,6 @@ static void *s390_dma_alloc(struct device *dev, size_t size, · 12 unmodified lines | ||
| 332 | 332 | if (!page) |
| 333 | 333 | return NULL; |
| 334 | 334 | |
| 335 | − atomic64_add(size / PAGE_SIZE, (atomic64_t *) &zdev->fmb->allocated_pages); | |
| 336 | 335 | pa = page_to_phys(page); |
| 337 | 336 | memset((void *) pa, 0, size); |
| 338 | 337 | |
| @@ -343,6 +342,7 @@ static void *s390_dma_alloc(struct device *dev, size_t size, · 4 unmodified lines | ||
| 343 | 342 | return NULL; |
| 344 | 343 | } |
| 345 | 344 | |
| 345 | + atomic64_add(size / PAGE_SIZE, &zdev->fmb->allocated_pages); | |
| 346 | 346 | if (dma_handle) |
| 347 | 347 | *dma_handle = map; |
| 348 | 348 | return (void *) pa; |
| @@ -352,8 +352,11 @@ static void s390_dma_free(struct device *dev, size_t size, · 3 unmodified lines | ||
| 352 | 352 | void *pa, dma_addr_t dma_handle, |
| 353 | 353 | struct dma_attrs *attrs) |
| 354 | 354 | { |
| 355 | − s390_dma_unmap_pages(dev, dma_handle, PAGE_ALIGN(size), | |
| 356 | − DMA_BIDIRECTIONAL, NULL); | |
| 355 | + struct zpci_dev *zdev = get_zdev(to_pci_dev(dev)); | |
| 356 | + | |
| 357 | + size = PAGE_ALIGN(size); | |
| 358 | + atomic64_sub(size / PAGE_SIZE, &zdev->fmb->allocated_pages); | |
| 359 | + s390_dma_unmap_pages(dev, dma_handle, size, DMA_BIDIRECTIONAL, NULL); | |
| 357 | 360 | free_pages((unsigned long) pa, get_order(size)); |
| 358 | 361 | } |
| 359 | 362 | |
| @@ -43,9 +43,8 @@ struct zpci_ccdf_avail { · 42 unmodified lines | ||
| 43 | 43 | u16 pec; /* PCI event code */ |
| 44 | 44 | } __packed; |
| 45 | 45 | |
| 46 | −void zpci_event_error(void *data) | |
| 46 | +static void __zpci_event_error(struct zpci_ccdf_err *ccdf) | |
| 47 | 47 | { |
| 48 | − struct zpci_ccdf_err *ccdf = data; | |
| 49 | 48 | struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid); |
| 50 | 49 | |
| 51 | 50 | zpci_err("error CCDF:\n"); |
| @@ -58,9 +57,14 @@ void zpci_event_error(void *data) · 6 unmodified lines | ||
| 58 | 57 | pci_name(zdev->pdev), ccdf->pec, ccdf->fid); |
| 59 | 58 | } |
| 60 | 59 | |
| 61 | −void zpci_event_availability(void *data) | |
| 60 | +void zpci_event_error(void *data) | |
| 61 | +{ | |
| 62 | + if (zpci_is_enabled()) | |
| 63 | + __zpci_event_error(data); | |
| 64 | +} | |
| 65 | + | |
| 66 | +static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf) | |
| 62 | 67 | { |
| 63 | − struct zpci_ccdf_avail *ccdf = data; | |
| 64 | 68 | struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid); |
| 65 | 69 | struct pci_dev *pdev = zdev ? zdev->pdev : NULL; |
| 66 | 70 | int ret; |
| @@ -99,8 +103,12 @@ void zpci_event_availability(void *data) · 32 unmodified lines | ||
| 99 | 103 | |
| 100 | 104 | break; |
| 101 | 105 | case 0x0304: /* Configured -> Standby */ |
| 102 | − if (pdev) | |
| 106 | + if (pdev) { | |
| 107 | + /* Give the driver a hint that the function is | |
| 108 | + * already unusable. */ | |
| 109 | + pdev->error_state = pci_channel_io_perm_failure; | |
| 103 | 110 | pci_stop_and_remove_bus_device(pdev); |
| 111 | + } | |
| 104 | 112 | |
| 105 | 113 | zdev->fh = ccdf->fh; |
| 106 | 114 | zpci_disable_device(zdev); |
| @@ -110,6 +118,8 @@ void zpci_event_availability(void *data) · 3 unmodified lines | ||
| 110 | 118 | clp_rescan_pci_devices(); |
| 111 | 119 | break; |
| 112 | 120 | case 0x0308: /* Standby -> Reserved */ |
| 121 | + if (!zdev) | |
| 122 | + break; | |
| 113 | 123 | pci_stop_root_bus(zdev->bus); |
| 114 | 124 | pci_remove_root_bus(zdev->bus); |
| 115 | 125 | break; |
| @@ -117,3 +127,9 @@ void zpci_event_availability(void *data) · 1 unmodified line | ||
| 117 | 127 | break; |
| 118 | 128 | } |
| 119 | 129 | } |
| 130 | + | |
| 131 | +void zpci_event_availability(void *data) | |
| 132 | +{ | |
| 133 | + if (zpci_is_enabled()) | |
| 134 | + __zpci_event_availability(data); | |
| 135 | +} | |
| @@ -3386,7 +3386,7 @@ int dasd_generic_set_offline(struct ccw_device *cdev) · 3385 unmodified lines | ||
| 3386 | 3386 | |
| 3387 | 3387 | if (test_bit(DASD_FLAG_SAFE_OFFLINE_RUNNING, &device->flags)) { |
| 3388 | 3388 | /* |
| 3389 | − * safe offline allready running | |
| 3389 | + * safe offline already running | |
| 3390 | 3390 | * could only be called by normal offline so safe_offline flag |
| 3391 | 3391 | * needs to be removed to run normal offline and kill all I/O |
| 3392 | 3392 | */ |
| @@ -183,7 +183,6 @@ extern unsigned long sclp_console_full; · 182 unmodified lines | ||
| 183 | 183 | extern u8 sclp_fac84; |
| 184 | 184 | extern unsigned long long sclp_rzm; |
| 185 | 185 | extern unsigned long long sclp_rnmax; |
| 186 | −extern __initdata int sclp_early_read_info_sccb_valid; | |
| 187 | 186 | |
| 188 | 187 | /* useful inlines */ |
| 189 | 188 | |
| @@ -455,8 +455,6 @@ static int __init sclp_detect_standby_memory(void) · 454 unmodified lines | ||
| 455 | 455 | |
| 456 | 456 | if (OLDMEM_BASE) /* No standby memory in kdump mode */ |
| 457 | 457 | return 0; |
| 458 | − if (!sclp_early_read_info_sccb_valid) | |
| 459 | − return 0; | |
| 460 | 458 | if ((sclp_facilities & 0xe00000000000ULL) != 0xe00000000000ULL) |
| 461 | 459 | return 0; |
| 462 | 460 | rc = -ENOMEM; |
| @@ -35,11 +35,12 @@ struct read_info_sccb { · 34 unmodified lines | ||
| 35 | 35 | u8 _reserved5[4096 - 112]; /* 112-4095 */ |
| 36 | 36 | } __packed __aligned(PAGE_SIZE); |
| 37 | 37 | |
| 38 | −static __initdata struct read_info_sccb early_read_info_sccb; | |
| 39 | −static __initdata char sccb_early[PAGE_SIZE] __aligned(PAGE_SIZE); | |
| 38 | +static char sccb_early[PAGE_SIZE] __aligned(PAGE_SIZE) __initdata; | |
| 39 | +static unsigned int sclp_con_has_vt220 __initdata; | |
| 40 | +static unsigned int sclp_con_has_linemode __initdata; | |
| 40 | 41 | static unsigned long sclp_hsa_size; |
| 42 | +static struct sclp_ipl_info sclp_ipl_info; | |
| 41 | 43 | |
| 42 | −__initdata int sclp_early_read_info_sccb_valid; | |
| 43 | 44 | u64 sclp_facilities; |
| 44 | 45 | u8 sclp_fac84; |
| 45 | 46 | unsigned long long sclp_rzm; |
| @@ -63,15 +64,12 @@ out: · 17 unmodified lines | ||
| 63 | 64 | return rc; |
| 64 | 65 | } |
| 65 | 66 | |
| 66 | −static void __init sclp_read_info_early(void) | |
| 67 | +static int __init sclp_read_info_early(struct read_info_sccb *sccb) | |
| 67 | 68 | { |
| 68 | − int rc; | |
| 69 | − int i; | |
| 70 | − struct read_info_sccb *sccb; | |
| 69 | + int rc, i; | |
| 71 | 70 | sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED, |
| 72 | 71 | SCLP_CMDW_READ_SCP_INFO}; |
| 73 | 72 | |
| 74 | − sccb = &early_read_info_sccb; | |
| 75 | 73 | for (i = 0; i < ARRAY_SIZE(commands); i++) { |
| 76 | 74 | do { |
| 77 | 75 | memset(sccb, 0, sizeof(*sccb)); |
| @@ -83,24 +81,19 @@ static void __init sclp_read_info_early(void) · 5 unmodified lines | ||
| 83 | 81 | |
| 84 | 82 | if (rc) |
| 85 | 83 | break; |
| 86 | − if (sccb->header.response_code == 0x10) { | |
| 87 | − sclp_early_read_info_sccb_valid = 1; | |
| 88 | − break; | |
| 89 | − } | |
| 84 | + if (sccb->header.response_code == 0x10) | |
| 85 | + return 0; | |
| 90 | 86 | if (sccb->header.response_code != 0x1f0) |
| 91 | 87 | break; |
| 92 | 88 | } |
| 89 | + return -EIO; | |
| 93 | 90 | } |
| 94 | 91 | |
| 95 | −static void __init sclp_facilities_detect(void) | |
| 92 | +static void __init sclp_facilities_detect(struct read_info_sccb *sccb) | |
| 96 | 93 | { |
| 97 | − struct read_info_sccb *sccb; | |
| 98 | − | |
| 99 | − sclp_read_info_early(); | |
| 100 | − if (!sclp_early_read_info_sccb_valid) | |
| 94 | + if (sclp_read_info_early(sccb)) | |
| 101 | 95 | return; |
| 102 | 96 | |
| 103 | − sccb = &early_read_info_sccb; | |
| 104 | 97 | sclp_facilities = sccb->facilities; |
| 105 | 98 | sclp_fac84 = sccb->fac84; |
| 106 | 99 | if (sccb->fac85 & 0x02) |
| @@ -108,30 +101,22 @@ static void __init sclp_facilities_detect(void) · 1 unmodified line | ||
| 108 | 101 | sclp_rnmax = sccb->rnmax ? sccb->rnmax : sccb->rnmax2; |
| 109 | 102 | sclp_rzm = sccb->rnsize ? sccb->rnsize : sccb->rnsize2; |
| 110 | 103 | sclp_rzm <<= 20; |
| 104 | + | |
| 105 | + /* Save IPL information */ | |
| 106 | + sclp_ipl_info.is_valid = 1; | |
| 107 | + if (sccb->flags & 0x2) | |
| 108 | + sclp_ipl_info.has_dump = 1; | |
| 109 | + memcpy(&sclp_ipl_info.loadparm, &sccb->loadparm, LOADPARM_LEN); | |
| 111 | 110 | } |
| 112 | 111 | |
| 113 | 112 | bool __init sclp_has_linemode(void) |
| 114 | 113 | { |
| 115 | − struct init_sccb *sccb = (void *) &sccb_early; | |
| 116 | − | |
| 117 | − if (sccb->header.response_code != 0x20) | |
| 118 | − return 0; | |
| 119 | − if (!(sccb->sclp_send_mask & (EVTYP_OPCMD_MASK | EVTYP_PMSGCMD_MASK))) | |
| 120 | − return 0; | |
| 121 | − if (!(sccb->sclp_receive_mask & (EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK))) | |
| 122 | − return 0; | |
| 123 | − return 1; | |
| 114 | + return !!sclp_con_has_linemode; | |
| 124 | 115 | } |
| 125 | 116 | |
| 126 | 117 | bool __init sclp_has_vt220(void) |
| 127 | 118 | { |
| 128 | − struct init_sccb *sccb = (void *) &sccb_early; | |
| 129 | − | |
| 130 | − if (sccb->header.response_code != 0x20) | |
| 131 | − return 0; | |
| 132 | − if (sccb->sclp_send_mask & EVTYP_VT220MSG_MASK) | |
| 133 | − return 1; | |
| 134 | − return 0; | |
| 119 | + return !!sclp_con_has_vt220; | |
| 135 | 120 | } |
| 136 | 121 | |
| 137 | 122 | unsigned long long sclp_get_rnmax(void) |
| @@ -146,19 +131,12 @@ unsigned long long sclp_get_rzm(void) · 8 unmodified lines | ||
| 146 | 131 | |
| 147 | 132 | /* |
| 148 | 133 | * This function will be called after sclp_facilities_detect(), which gets |
| 149 | − * called from early.c code. Therefore the sccb should have valid contents. | |
| 134 | + * called from early.c code. The sclp_facilities_detect() function retrieves | |
| 135 | + * and saves the IPL information. | |
| 150 | 136 | */ |
| 151 | 137 | void __init sclp_get_ipl_info(struct sclp_ipl_info *info) |
| 152 | 138 | { |
| 153 | − struct read_info_sccb *sccb; | |
| 154 | − | |
| 155 | − if (!sclp_early_read_info_sccb_valid) | |
| 156 | − return; | |
| 157 | − sccb = &early_read_info_sccb; | |
| 158 | − info->is_valid = 1; | |
| 159 | − if (sccb->flags & 0x2) | |
| 160 | − info->has_dump = 1; | |
| 161 | − memcpy(&info->loadparm, &sccb->loadparm, LOADPARM_LEN); | |
| 139 | + *info = sclp_ipl_info; | |
| 162 | 140 | } |
| 163 | 141 | |
| 164 | 142 | static int __init sclp_cmd_early(sclp_cmdw_t cmd, void *sccb) |
| @@ -189,11 +167,10 @@ static void __init sccb_init_eq_size(struct sdias_sccb *sccb) · 24 unmodified lines | ||
| 189 | 167 | sccb->evbuf.dbs = 1; |
| 190 | 168 | } |
| 191 | 169 | |
| 192 | −static int __init sclp_set_event_mask(unsigned long receive_mask, | |
| 170 | +static int __init sclp_set_event_mask(struct init_sccb *sccb, | |
| 171 | + unsigned long receive_mask, | |
| 193 | 172 | unsigned long send_mask) |
| 194 | 173 | { |
| 195 | − struct init_sccb *sccb = (void *) &sccb_early; | |
| 196 | − | |
| 197 | 174 | memset(sccb, 0, sizeof(*sccb)); |
| 198 | 175 | sccb->header.length = sizeof(*sccb); |
| 199 | 176 | sccb->mask_length = sizeof(sccb_mask_t); |
| @@ -202,10 +179,8 @@ static int __init sclp_set_event_mask(unsigned long receive_mask, · 2 unmodified lines | ||
| 202 | 179 | return sclp_cmd_early(SCLP_CMDW_WRITE_EVENT_MASK, sccb); |
| 203 | 180 | } |
| 204 | 181 | |
| 205 | −static long __init sclp_hsa_size_init(void) | |
| 182 | +static long __init sclp_hsa_size_init(struct sdias_sccb *sccb) | |
| 206 | 183 | { |
| 207 | − struct sdias_sccb *sccb = (void *) &sccb_early; | |
| 208 | − | |
| 209 | 184 | sccb_init_eq_size(sccb); |
| 210 | 185 | if (sclp_cmd_early(SCLP_CMDW_WRITE_EVENT_DATA, sccb)) |
| 211 | 186 | return -EIO; |
| @@ -214,10 +189,8 @@ static long __init sclp_hsa_size_init(void) · 2 unmodified lines | ||
| 214 | 189 | return 0; |
| 215 | 190 | } |
| 216 | 191 | |
| 217 | −static long __init sclp_hsa_copy_wait(void) | |
| 192 | +static long __init sclp_hsa_copy_wait(struct sccb_header *sccb) | |
| 218 | 193 | { |
| 219 | − struct sccb_header *sccb = (void *) &sccb_early; | |
| 220 | − | |
| 221 | 194 | memset(sccb, 0, PAGE_SIZE); |
| 222 | 195 | sccb->length = PAGE_SIZE; |
| 223 | 196 | if (sclp_cmd_early(SCLP_CMDW_READ_EVENT_DATA, sccb)) |
| @@ -230,34 +203,62 @@ unsigned long sclp_get_hsa_size(void) · 6 unmodified lines | ||
| 230 | 203 | return sclp_hsa_size; |
| 231 | 204 | } |
| 232 | 205 | |
| 233 | −static void __init sclp_hsa_size_detect(void) | |
| 206 | +static void __init sclp_hsa_size_detect(void *sccb) | |
| 234 | 207 | { |
| 235 | 208 | long size; |
| 236 | 209 | |
| 237 | 210 | /* First try synchronous interface (LPAR) */ |
| 238 | − if (sclp_set_event_mask(0, 0x40000010)) | |
| 211 | + if (sclp_set_event_mask(sccb, 0, 0x40000010)) | |
| 239 | 212 | return; |
| 240 | − size = sclp_hsa_size_init(); | |
| 213 | + size = sclp_hsa_size_init(sccb); | |
| 241 | 214 | if (size < 0) |
| 242 | 215 | return; |
| 243 | 216 | if (size != 0) |
| 244 | 217 | goto out; |
| 245 | 218 | /* Then try asynchronous interface (z/VM) */ |
| 246 | − if (sclp_set_event_mask(0x00000010, 0x40000010)) | |
| 219 | + if (sclp_set_event_mask(sccb, 0x00000010, 0x40000010)) | |
| 247 | 220 | return; |
| 248 | − size = sclp_hsa_size_init(); | |
| 221 | + size = sclp_hsa_size_init(sccb); | |
| 249 | 222 | if (size < 0) |
| 250 | 223 | return; |
| 251 | − size = sclp_hsa_copy_wait(); | |
| 224 | + size = sclp_hsa_copy_wait(sccb); | |
| 252 | 225 | if (size < 0) |
| 253 | 226 | return; |
| 254 | 227 | out: |
| 255 | 228 | sclp_hsa_size = size; |
| 256 | 229 | } |
| 257 | 230 | |
| 231 | +static unsigned int __init sclp_con_check_linemode(struct init_sccb *sccb) | |
| 232 | +{ | |
| 233 | + if (!(sccb->sclp_send_mask & (EVTYP_OPCMD_MASK | EVTYP_PMSGCMD_MASK))) | |
| 234 | + return 0; | |
| 235 | + if (!(sccb->sclp_receive_mask & (EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK))) | |
| 236 | + return 0; | |
| 237 | + return 1; | |
| 238 | +} | |
| 239 | + | |
| 240 | +static void __init sclp_console_detect(struct init_sccb *sccb) | |
| 241 | +{ | |
| 242 | + if (sccb->header.response_code != 0x20) | |
| 243 | + return; | |
| 244 | + | |
| 245 | + if (sccb->sclp_send_mask & EVTYP_VT220MSG_MASK) | |
| 246 | + sclp_con_has_vt220 = 1; | |
| 247 | + | |
| 248 | + if (sclp_con_check_linemode(sccb)) | |
| 249 | + sclp_con_has_linemode = 1; | |
| 250 | +} | |
| 251 | + | |
| 258 | 252 | void __init sclp_early_detect(void) |
| 259 | 253 | { |
| 260 | − sclp_facilities_detect(); | |
| 261 | − sclp_hsa_size_detect(); | |
| 262 | − sclp_set_event_mask(0, 0); | |
| 254 | + void *sccb = &sccb_early; | |
| 255 | + | |
| 256 | + sclp_facilities_detect(sccb); | |
| 257 | + sclp_hsa_size_detect(sccb); | |
| 258 | + | |
| 259 | + /* Turn off SCLP event notifications. Also save remote masks in the | |
| 260 | + * sccb. These are sufficient to detect sclp console capabilities. | |
| 261 | + */ | |
| 262 | + sclp_set_event_mask(sccb, 0, 0); | |
| 263 | + sclp_console_detect(sccb); | |
| 263 | 264 | } |
| @@ -125,10 +125,7 @@ static void tty3270_resize_work(struct work_struct *work); · 124 unmodified lines | ||
| 125 | 125 | */ |
| 126 | 126 | static void tty3270_set_timer(struct tty3270 *tp, int expires) |
| 127 | 127 | { |
| 128 | − if (expires == 0) | |
| 129 | − del_timer(&tp->timer); | |
| 130 | − else | |
| 131 | − mod_timer(&tp->timer, jiffies + expires); | |
| 128 | + mod_timer(&tp->timer, jiffies + expires); | |
| 132 | 129 | } |
| 133 | 130 | |
| 134 | 131 | /* |
| @@ -744,7 +741,6 @@ tty3270_free_view(struct tty3270 *tp) · 609 unmodified lines | ||
| 744 | 741 | { |
| 745 | 742 | int pages; |
| 746 | 743 | |
| 747 | − del_timer_sync(&tp->timer); | |
| 748 | 744 | kbd_free(tp->kbd); |
| 749 | 745 | raw3270_request_free(tp->kreset); |
| 750 | 746 | raw3270_request_free(tp->read); |
| @@ -877,6 +873,7 @@ tty3270_free(struct raw3270_view *view) · 126 unmodified lines | ||
| 877 | 873 | { |
| 878 | 874 | struct tty3270 *tp = container_of(view, struct tty3270, view); |
| 879 | 875 | |
| 876 | + del_timer_sync(&tp->timer); | |
| 880 | 877 | tty3270_free_screen(tp->screen, tp->view.rows); |
| 881 | 878 | tty3270_free_view(tp); |
| 882 | 879 | } |
| @@ -260,16 +260,16 @@ static int blacklist_parse_proc_parameters(char *buf) · 259 unmodified lines | ||
| 260 | 260 | |
| 261 | 261 | parm = strsep(&buf, " "); |
| 262 | 262 | |
| 263 | − if (strcmp("free", parm) == 0) | |
| 263 | + if (strcmp("free", parm) == 0) { | |
| 264 | 264 | rc = blacklist_parse_parameters(buf, free, 0); |
| 265 | − else if (strcmp("add", parm) == 0) | |
| 265 | + css_schedule_eval_all_unreg(0); | |
| 266 | + } else if (strcmp("add", parm) == 0) | |
| 266 | 267 | rc = blacklist_parse_parameters(buf, add, 0); |
| 267 | 268 | else if (strcmp("purge", parm) == 0) |
| 268 | 269 | return ccw_purge_blacklisted(); |
| 269 | 270 | else |
| 270 | 271 | return -EINVAL; |
| 271 | 272 | |
| 272 | − css_schedule_reprobe(); | |
| 273 | 273 | |
| 274 | 274 | return rc; |
| 275 | 275 | } |
| @@ -128,14 +128,14 @@ static ssize_t ccwgroup_online_store(struct device *dev, · 127 unmodified lines | ||
| 128 | 128 | const char *buf, size_t count) |
| 129 | 129 | { |
| 130 | 130 | struct ccwgroup_device *gdev = to_ccwgroupdev(dev); |
| 131 | − struct ccwgroup_driver *gdrv = to_ccwgroupdrv(dev->driver); | |
| 132 | 131 | unsigned long value; |
| 133 | 132 | int ret; |
| 134 | 133 | |
| 135 | − if (!dev->driver) | |
| 136 | − return -EINVAL; | |
| 137 | − if (!try_module_get(gdrv->driver.owner)) | |
| 138 | − return -EINVAL; | |
| 134 | + device_lock(dev); | |
| 135 | + if (!dev->driver) { | |
| 136 | + ret = -EINVAL; | |
| 137 | + goto out; | |
| 138 | + } | |
| 139 | 139 | |
| 140 | 140 | ret = kstrtoul(buf, 0, &value); |
| 141 | 141 | if (ret) |
| @@ -148,7 +148,7 @@ static ssize_t ccwgroup_online_store(struct device *dev, · 6 unmodified lines | ||
| 148 | 148 | else |
| 149 | 149 | ret = -EINVAL; |
| 150 | 150 | out: |
| 151 | − module_put(gdrv->driver.owner); | |
| 151 | + device_unlock(dev); | |
| 152 | 152 | return (ret == 0) ? count : ret; |
| 153 | 153 | } |
| 154 | 154 | |
| @@ -55,6 +55,7 @@ int chsc_error_from_response(int response) · 54 unmodified lines | ||
| 55 | 55 | case 0x0004: |
| 56 | 56 | return -EOPNOTSUPP; |
| 57 | 57 | case 0x000b: |
| 58 | + case 0x0107: /* "Channel busy" for the op 0x003d */ | |
| 58 | 59 | return -EBUSY; |
| 59 | 60 | case 0x0100: |
| 60 | 61 | case 0x0102: |
| @@ -237,26 +238,6 @@ void chsc_chp_offline(struct chp_id chpid) · 176 unmodified lines | ||
| 237 | 238 | for_each_subchannel_staged(s390_subchannel_remove_chpid, NULL, &link); |
| 238 | 239 | } |
| 239 | 240 | |
| 240 | −static int s390_process_res_acc_new_sch(struct subchannel_id schid, void *data) | |
| 241 | −{ | |
| 242 | − struct schib schib; | |
| 243 | − /* | |
| 244 | − * We don't know the device yet, but since a path | |
| 245 | − * may be available now to the device we'll have | |
| 246 | − * to do recognition again. | |
| 247 | − * Since we don't have any idea about which chpid | |
| 248 | − * that beast may be on we'll have to do a stsch | |
| 249 | − * on all devices, grr... | |
| 250 | − */ | |
| 251 | − if (stsch_err(schid, &schib)) | |
| 252 | − /* We're through */ | |
| 253 | − return -ENXIO; | |
| 254 | − | |
| 255 | − /* Put it on the slow path. */ | |
| 256 | − css_schedule_eval(schid); | |
| 257 | − return 0; | |
| 258 | −} | |
| 259 | − | |
| 260 | 241 | static int __s390_process_res_acc(struct subchannel *sch, void *data) |
| 261 | 242 | { |
| 262 | 243 | spin_lock_irq(sch->lock); |
| @@ -287,8 +268,8 @@ static void s390_process_res_acc(struct chp_link *link) · 24 unmodified lines | ||
| 287 | 268 | * The more information we have (info), the less scanning |
| 288 | 269 | * will we have to do. |
| 289 | 270 | */ |
| 290 | − for_each_subchannel_staged(__s390_process_res_acc, | |
| 291 | − s390_process_res_acc_new_sch, link); | |
| 271 | + for_each_subchannel_staged(__s390_process_res_acc, NULL, link); | |
| 272 | + css_schedule_reprobe(); | |
| 292 | 273 | } |
| 293 | 274 | |
| 294 | 275 | static int |
| @@ -663,19 +644,6 @@ static int s390_subchannel_vary_chpid_on(struct subchannel *sch, void *data) · 368 unmodified lines | ||
| 663 | 644 | return 0; |
| 664 | 645 | } |
| 665 | 646 | |
| 666 | −static int | |
| 667 | −__s390_vary_chpid_on(struct subchannel_id schid, void *data) | |
| 668 | −{ | |
| 669 | − struct schib schib; | |
| 670 | − | |
| 671 | − if (stsch_err(schid, &schib)) | |
| 672 | − /* We're through */ | |
| 673 | − return -ENXIO; | |
| 674 | − /* Put it on the slow path. */ | |
| 675 | − css_schedule_eval(schid); | |
| 676 | − return 0; | |
| 677 | −} | |
| 678 | − | |
| 679 | 647 | /** |
| 680 | 648 | * chsc_chp_vary - propagate channel-path vary operation to subchannels |
| 681 | 649 | * @chpid: channl-path ID |
| @@ -694,7 +662,8 @@ int chsc_chp_vary(struct chp_id chpid, int on) · 12 unmodified lines | ||
| 694 | 662 | /* Try to update the channel path description. */ |
| 695 | 663 | chp_update_desc(chp); |
| 696 | 664 | for_each_subchannel_staged(s390_subchannel_vary_chpid_on, |
| 697 | − __s390_vary_chpid_on, &chpid); | |
| 665 | + NULL, &chpid); | |
| 666 | + css_schedule_reprobe(); | |
| 698 | 667 | } else |
| 699 | 668 | for_each_subchannel_staged(s390_subchannel_vary_chpid_off, |
| 700 | 669 | NULL, &chpid); |
| @@ -1234,3 +1203,35 @@ out: · 533 unmodified lines | ||
| 1234 | 1203 | return ret; |
| 1235 | 1204 | } |
| 1236 | 1205 | EXPORT_SYMBOL_GPL(chsc_scm_info); |
| 1206 | + | |
| 1207 | +/** | |
| 1208 | + * chsc_pnso_brinfo() - Perform Network-Subchannel Operation, Bridge Info. | |
| 1209 | + * @schid: id of the subchannel on which PNSO is performed | |
| 1210 | + * @brinfo_area: request and response block for the operation | |
| 1211 | + * @resume_token: resume token for multiblock response | |
| 1212 | + * @cnc: Boolean change-notification control | |
| 1213 | + * | |
| 1214 | + * brinfo_area must be allocated by the caller with get_zeroed_page(GFP_KERNEL) | |
| 1215 | + * | |
| 1216 | + * Returns 0 on success. | |
| 1217 | + */ | |
| 1218 | +int chsc_pnso_brinfo(struct subchannel_id schid, | |
| 1219 | + struct chsc_pnso_area *brinfo_area, | |
| 1220 | + struct chsc_brinfo_resume_token resume_token, | |
| 1221 | + int cnc) | |
| 1222 | +{ | |
| 1223 | + memset(brinfo_area, 0, sizeof(*brinfo_area)); | |
| 1224 | + brinfo_area->request.length = 0x0030; | |
| 1225 | + brinfo_area->request.code = 0x003d; /* network-subchannel operation */ | |
| 1226 | + brinfo_area->m = schid.m; | |
| 1227 | + brinfo_area->ssid = schid.ssid; | |
| 1228 | + brinfo_area->sch = schid.sch_no; | |
| 1229 | + brinfo_area->cssid = schid.cssid; | |
| 1230 | + brinfo_area->oc = 0; /* Store-network-bridging-information list */ | |
| 1231 | + brinfo_area->resume_token = resume_token; | |
| 1232 | + brinfo_area->n = (cnc != 0); | |
| 1233 | + if (chsc(brinfo_area)) | |
| 1234 | + return -EIO; | |
| 1235 | + return chsc_error_from_response(brinfo_area->response.code); | |
| 1236 | +} | |
| 1237 | +EXPORT_SYMBOL_GPL(chsc_pnso_brinfo); | |
| @@ -61,7 +61,9 @@ struct css_chsc_char { · 60 unmodified lines | ||
| 61 | 61 | u32 : 20; |
| 62 | 62 | u32 scssc : 1; /* bit 107 */ |
| 63 | 63 | u32 scsscf : 1; /* bit 108 */ |
| 64 | − u32 : 19; | |
| 64 | + u32:7; | |
| 65 | + u32 pnso:1; /* bit 116 */ | |
| 66 | + u32:11; | |
| 65 | 67 | }__attribute__((packed)); |
| 66 | 68 | |
| 67 | 69 | extern struct css_chsc_char css_chsc_characteristics; |
| @@ -188,6 +190,53 @@ struct chsc_scm_info { · 120 unmodified lines | ||
| 188 | 190 | |
| 189 | 191 | int chsc_scm_info(struct chsc_scm_info *scm_area, u64 token); |
| 190 | 192 | |
| 193 | +struct chsc_brinfo_resume_token { | |
| 194 | + u64 t1; | |
| 195 | + u64 t2; | |
| 196 | +} __packed; | |
| 197 | + | |
| 198 | +struct chsc_brinfo_naihdr { | |
| 199 | + struct chsc_brinfo_resume_token resume_token; | |
| 200 | + u32:32; | |
| 201 | + u32 instance; | |
| 202 | + u32:24; | |
| 203 | + u8 naids; | |
| 204 | + u32 reserved[3]; | |
| 205 | +} __packed; | |
| 206 | + | |
| 207 | +struct chsc_pnso_area { | |
| 208 | + struct chsc_header request; | |
| 209 | + u8:2; | |
| 210 | + u8 m:1; | |
| 211 | + u8:5; | |
| 212 | + u8:2; | |
| 213 | + u8 ssid:2; | |
| 214 | + u8 fmt:4; | |
| 215 | + u16 sch; | |
| 216 | + u8:8; | |
| 217 | + u8 cssid; | |
| 218 | + u16:16; | |
| 219 | + u8 oc; | |
| 220 | + u32:24; | |
| 221 | + struct chsc_brinfo_resume_token resume_token; | |
| 222 | + u32 n:1; | |
| 223 | + u32:31; | |
| 224 | + u32 reserved[3]; | |
| 225 | + struct chsc_header response; | |
| 226 | + u32:32; | |
| 227 | + struct chsc_brinfo_naihdr naihdr; | |
| 228 | + union { | |
| 229 | + struct qdio_brinfo_entry_l3_ipv6 l3_ipv6[0]; | |
| 230 | + struct qdio_brinfo_entry_l3_ipv4 l3_ipv4[0]; | |
| 231 | + struct qdio_brinfo_entry_l2 l2[0]; | |
| 232 | + } entries; | |
| 233 | +} __packed; | |
| 234 | + | |
| 235 | +int chsc_pnso_brinfo(struct subchannel_id schid, | |
| 236 | + struct chsc_pnso_area *brinfo_area, | |
| 237 | + struct chsc_brinfo_resume_token resume_token, | |
| 238 | + int cnc); | |
| 239 | + | |
| 191 | 240 | #ifdef CONFIG_SCM_BUS |
| 192 | 241 | int scm_update_information(void); |
| 193 | 242 | int scm_process_availability_information(void); |
| @@ -69,7 +69,8 @@ static int call_fn_known_sch(struct device *dev, void *data) · 68 unmodified lines | ||
| 69 | 69 | struct cb_data *cb = data; |
| 70 | 70 | int rc = 0; |
| 71 | 71 | |
| 72 | − idset_sch_del(cb->set, sch->schid); | |
| 72 | + if (cb->set) | |
| 73 | + idset_sch_del(cb->set, sch->schid); | |
| 73 | 74 | if (cb->fn_known_sch) |
| 74 | 75 | rc = cb->fn_known_sch(sch, cb->data); |
| 75 | 76 | return rc; |
| @@ -115,6 +116,13 @@ int for_each_subchannel_staged(int (*fn_known)(struct subchannel *, void *), · 39 unmodified lines | ||
| 115 | 116 | cb.fn_known_sch = fn_known; |
| 116 | 117 | cb.fn_unknown_sch = fn_unknown; |
| 117 | 118 | |
| 119 | + if (fn_known && !fn_unknown) { | |
| 120 | + /* Skip idset allocation in case of known-only loop. */ | |
| 121 | + cb.set = NULL; | |
| 122 | + return bus_for_each_dev(&css_bus_type, NULL, &cb, | |
| 123 | + call_fn_known_sch); | |
| 124 | + } | |
| 125 | + | |
| 118 | 126 | cb.set = idset_sch_new(); |
| 119 | 127 | if (!cb.set) |
| 120 | 128 | /* fall back to brute force scanning in case of oom */ |
| @@ -553,6 +561,9 @@ static int slow_eval_unknown_fn(struct subchannel_id schid, void *data) · 432 unmodified lines | ||
| 553 | 561 | default: |
| 554 | 562 | rc = 0; |
| 555 | 563 | } |
| 564 | + /* Allow scheduling here since the containing loop might | |
| 565 | + * take a while. */ | |
| 566 | + cond_resched(); | |
| 556 | 567 | } |
| 557 | 568 | return rc; |
| 558 | 569 | } |
| @@ -572,7 +583,7 @@ static void css_slow_path_func(struct work_struct *unused) · 13 unmodified lines | ||
| 572 | 583 | spin_unlock_irqrestore(&slow_subchannel_lock, flags); |
| 573 | 584 | } |
| 574 | 585 | |
| 575 | −static DECLARE_WORK(slow_path_work, css_slow_path_func); | |
| 586 | +static DECLARE_DELAYED_WORK(slow_path_work, css_slow_path_func); | |
| 576 | 587 | struct workqueue_struct *cio_work_q; |
| 577 | 588 | |
| 578 | 589 | void css_schedule_eval(struct subchannel_id schid) |
| @@ -582,7 +593,7 @@ void css_schedule_eval(struct subchannel_id schid) · 3 unmodified lines | ||
| 582 | 593 | spin_lock_irqsave(&slow_subchannel_lock, flags); |
| 583 | 594 | idset_sch_add(slow_subchannel_set, schid); |
| 584 | 595 | atomic_set(&css_eval_scheduled, 1); |
| 585 | − queue_work(cio_work_q, &slow_path_work); | |
| 596 | + queue_delayed_work(cio_work_q, &slow_path_work, 0); | |
| 586 | 597 | spin_unlock_irqrestore(&slow_subchannel_lock, flags); |
| 587 | 598 | } |
| 588 | 599 | |
| @@ -593,7 +604,7 @@ void css_schedule_eval_all(void) · 4 unmodified lines | ||
| 593 | 604 | spin_lock_irqsave(&slow_subchannel_lock, flags); |
| 594 | 605 | idset_fill(slow_subchannel_set); |
| 595 | 606 | atomic_set(&css_eval_scheduled, 1); |
| 596 | − queue_work(cio_work_q, &slow_path_work); | |
| 607 | + queue_delayed_work(cio_work_q, &slow_path_work, 0); | |
| 597 | 608 | spin_unlock_irqrestore(&slow_subchannel_lock, flags); |
| 598 | 609 | } |
| 599 | 610 | |
| @@ -606,7 +617,7 @@ static int __unset_registered(struct device *dev, void *data) · 6 unmodified lines | ||
| 606 | 617 | return 0; |
| 607 | 618 | } |
| 608 | 619 | |
| 609 | −static void css_schedule_eval_all_unreg(void) | |
| 620 | +void css_schedule_eval_all_unreg(unsigned long delay) | |
| 610 | 621 | { |
| 611 | 622 | unsigned long flags; |
| 612 | 623 | struct idset *unreg_set; |
| @@ -624,7 +635,7 @@ static void css_schedule_eval_all_unreg(void) · 11 unmodified lines | ||
| 624 | 635 | spin_lock_irqsave(&slow_subchannel_lock, flags); |
| 625 | 636 | idset_add_set(slow_subchannel_set, unreg_set); |
| 626 | 637 | atomic_set(&css_eval_scheduled, 1); |
| 627 | − queue_work(cio_work_q, &slow_path_work); | |
| 638 | + queue_delayed_work(cio_work_q, &slow_path_work, delay); | |
| 628 | 639 | spin_unlock_irqrestore(&slow_subchannel_lock, flags); |
| 629 | 640 | idset_free(unreg_set); |
| 630 | 641 | } |
| @@ -637,7 +648,8 @@ void css_wait_for_slow_path(void) · 6 unmodified lines | ||
| 637 | 648 | /* Schedule reprobing of all unregistered subchannels. */ |
| 638 | 649 | void css_schedule_reprobe(void) |
| 639 | 650 | { |
| 640 | − css_schedule_eval_all_unreg(); | |
| 651 | + /* Schedule with a delay to allow merging of subsequent calls. */ | |
| 652 | + css_schedule_eval_all_unreg(1 * HZ); | |
| 641 | 653 | } |
| 642 | 654 | EXPORT_SYMBOL_GPL(css_schedule_reprobe); |
| 643 | 655 | |
| @@ -133,6 +133,7 @@ extern struct channel_subsystem *channel_subsystems[]; · 132 unmodified lines | ||
| 133 | 133 | /* Helper functions to build lists for the slow path. */ |
| 134 | 134 | void css_schedule_eval(struct subchannel_id schid); |
| 135 | 135 | void css_schedule_eval_all(void); |
| 136 | +void css_schedule_eval_all_unreg(unsigned long delay); | |
| 136 | 137 | int css_complete_work(void); |
| 137 | 138 | |
| 138 | 139 | int sch_is_pseudo_sch(struct subchannel *); |
| @@ -333,9 +333,9 @@ int ccw_device_set_offline(struct ccw_device *cdev) · 332 unmodified lines | ||
| 333 | 333 | if (ret != 0) |
| 334 | 334 | return ret; |
| 335 | 335 | } |
| 336 | − cdev->online = 0; | |
| 337 | 336 | spin_lock_irq(cdev->ccwlock); |
| 338 | 337 | sch = to_subchannel(cdev->dev.parent); |
| 338 | + cdev->online = 0; | |
| 339 | 339 | /* Wait until a final state or DISCONNECTED is reached */ |
| 340 | 340 | while (!dev_fsm_final_state(cdev) && |
| 341 | 341 | cdev->private->state != DEV_STATE_DISCONNECTED) { |
| @@ -446,7 +446,10 @@ int ccw_device_set_online(struct ccw_device *cdev) · 104 unmodified lines | ||
| 446 | 446 | ret = cdev->drv->set_online(cdev); |
| 447 | 447 | if (ret) |
| 448 | 448 | goto rollback; |
| 449 | + | |
| 450 | + spin_lock_irq(cdev->ccwlock); | |
| 449 | 451 | cdev->online = 1; |
| 452 | + spin_unlock_irq(cdev->ccwlock); | |
| 450 | 453 | return 0; |
| 451 | 454 | |
| 452 | 455 | rollback: |
| @@ -546,17 +549,12 @@ static ssize_t online_store (struct device *dev, struct device_attribute *attr, · 93 unmodified lines | ||
| 546 | 549 | if (!dev_fsm_final_state(cdev) && |
| 547 | 550 | cdev->private->state != DEV_STATE_DISCONNECTED) { |
| 548 | 551 | ret = -EAGAIN; |
| 549 | − goto out_onoff; | |
| 552 | + goto out; | |
| 550 | 553 | } |
| 551 | 554 | /* Prevent conflict between pending work and on-/offline processing.*/ |
| 552 | 555 | if (work_pending(&cdev->private->todo_work)) { |
| 553 | 556 | ret = -EAGAIN; |
| 554 | − goto out_onoff; | |
| 555 | − } | |
| 556 | − | |
| 557 | − if (cdev->drv && !try_module_get(cdev->drv->driver.owner)) { | |
| 558 | − ret = -EINVAL; | |
| 559 | − goto out_onoff; | |
| 557 | + goto out; | |
| 560 | 558 | } |
| 561 | 559 | if (!strncmp(buf, "force\n", count)) { |
| 562 | 560 | force = 1; |
| @@ -568,6 +566,8 @@ static ssize_t online_store (struct device *dev, struct device_attribute *attr, · 5 unmodified lines | ||
| 568 | 566 | } |
| 569 | 567 | if (ret) |
| 570 | 568 | goto out; |
| 569 | + | |
| 570 | + device_lock(dev); | |
| 571 | 571 | switch (i) { |
| 572 | 572 | case 0: |
| 573 | 573 | ret = online_store_handle_offline(cdev); |
| @@ -578,10 +578,9 @@ static ssize_t online_store (struct device *dev, struct device_attribute *attr, · 4 unmodified lines | ||
| 578 | 578 | default: |
| 579 | 579 | ret = -EINVAL; |
| 580 | 580 | } |
| 581 | + device_unlock(dev); | |
| 582 | + | |
| 581 | 583 | out: |
| 582 | − if (cdev->drv) | |
| 583 | − module_put(cdev->drv->driver.owner); | |
| 584 | −out_onoff: | |
| 585 | 584 | atomic_set(&cdev->private->onoff, 0); |
| 586 | 585 | return (ret < 0) ? ret : count; |
| 587 | 586 | } |
| @@ -1745,8 +1744,7 @@ ccw_device_probe (struct device *dev) · 1157 unmodified lines | ||
| 1745 | 1744 | return 0; |
| 1746 | 1745 | } |
| 1747 | 1746 | |
| 1748 | −static int | |
| 1749 | −ccw_device_remove (struct device *dev) | |
| 1747 | +static int ccw_device_remove(struct device *dev) | |
| 1750 | 1748 | { |
| 1751 | 1749 | struct ccw_device *cdev = to_ccwdev(dev); |
| 1752 | 1750 | struct ccw_driver *cdrv = cdev->drv; |
| @@ -1754,9 +1752,10 @@ ccw_device_remove (struct device *dev) · 1 unmodified line | ||
| 1754 | 1752 | |
| 1755 | 1753 | if (cdrv->remove) |
| 1756 | 1754 | cdrv->remove(cdev); |
| 1755 | + | |
| 1756 | + spin_lock_irq(cdev->ccwlock); | |
| 1757 | 1757 | if (cdev->online) { |
| 1758 | 1758 | cdev->online = 0; |
| 1759 | − spin_lock_irq(cdev->ccwlock); | |
| 1760 | 1759 | ret = ccw_device_offline(cdev); |
| 1761 | 1760 | spin_unlock_irq(cdev->ccwlock); |
| 1762 | 1761 | if (ret == 0) |
| @@ -1769,10 +1768,12 @@ ccw_device_remove (struct device *dev) · 6 unmodified lines | ||
| 1769 | 1768 | cdev->private->dev_id.devno); |
| 1770 | 1769 | /* Give up reference obtained in ccw_device_set_online(). */ |
| 1771 | 1770 | put_device(&cdev->dev); |
| 1771 | + spin_lock_irq(cdev->ccwlock); | |
| 1772 | 1772 | } |
| 1773 | 1773 | ccw_device_set_timeout(cdev, 0); |
| 1774 | 1774 | cdev->drv = NULL; |
| 1775 | 1775 | cdev->private->int_class = IRQIO_CIO; |
| 1776 | + spin_unlock_irq(cdev->ccwlock); | |
| 1776 | 1777 | return 0; |
| 1777 | 1778 | } |
| 1778 | 1779 | |
| @@ -1752,6 +1752,97 @@ int qdio_stop_irq(struct ccw_device *cdev, int nr) · 1751 unmodified lines | ||
| 1752 | 1752 | } |
| 1753 | 1753 | EXPORT_SYMBOL(qdio_stop_irq); |
| 1754 | 1754 | |
| 1755 | +/** | |
| 1756 | + * qdio_pnso_brinfo() - perform network subchannel op #0 - bridge info. | |
| 1757 | + * @schid: Subchannel ID. | |
| 1758 | + * @cnc: Boolean Change-Notification Control | |
| 1759 | + * @response: Response code will be stored at this address | |
| 1760 | + * @cb: Callback function will be executed for each element | |
| 1761 | + * of the address list | |
| 1762 | + * @priv: Pointer passed from the caller to qdio_pnso_brinfo() | |
| 1763 | + * @type: Type of the address entry passed to the callback | |
| 1764 | + * @entry: Entry containg the address of the specified type | |
| 1765 | + * @priv: Pointer to pass to the callback function. | |
| 1766 | + * | |
| 1767 | + * Performs "Store-network-bridging-information list" operation and calls | |
| 1768 | + * the callback function for every entry in the list. If "change- | |
| 1769 | + * notification-control" is set, further changes in the address list | |
| 1770 | + * will be reported via the IPA command. | |
| 1771 | + */ | |
| 1772 | +int qdio_pnso_brinfo(struct subchannel_id schid, | |
| 1773 | + int cnc, u16 *response, | |
| 1774 | + void (*cb)(void *priv, enum qdio_brinfo_entry_type type, | |
| 1775 | + void *entry), | |
| 1776 | + void *priv) | |
| 1777 | +{ | |
| 1778 | + struct chsc_pnso_area *rr; | |
| 1779 | + int rc; | |
| 1780 | + u32 prev_instance = 0; | |
| 1781 | + int isfirstblock = 1; | |
| 1782 | + int i, size, elems; | |
| 1783 | + | |
| 1784 | + rr = (struct chsc_pnso_area *)get_zeroed_page(GFP_KERNEL); | |
| 1785 | + if (rr == NULL) | |
| 1786 | + return -ENOMEM; | |
| 1787 | + do { | |
| 1788 | + /* on the first iteration, naihdr.resume_token will be zero */ | |
| 1789 | + rc = chsc_pnso_brinfo(schid, rr, rr->naihdr.resume_token, cnc); | |
| 1790 | + if (rc != 0 && rc != -EBUSY) | |
| 1791 | + goto out; | |
| 1792 | + if (rr->response.code != 1) { | |
| 1793 | + rc = -EIO; | |
| 1794 | + continue; | |
| 1795 | + } else | |
| 1796 | + rc = 0; | |
| 1797 | + | |
| 1798 | + if (cb == NULL) | |
| 1799 | + continue; | |
| 1800 | + | |
| 1801 | + size = rr->naihdr.naids; | |
| 1802 | + elems = (rr->response.length - | |
| 1803 | + sizeof(struct chsc_header) - | |
| 1804 | + sizeof(struct chsc_brinfo_naihdr)) / | |
| 1805 | + size; | |
| 1806 | + | |
| 1807 | + if (!isfirstblock && (rr->naihdr.instance != prev_instance)) { | |
| 1808 | + /* Inform the caller that they need to scrap */ | |
| 1809 | + /* the data that was already reported via cb */ | |
| 1810 | + rc = -EAGAIN; | |
| 1811 | + break; | |
| 1812 | + } | |
| 1813 | + isfirstblock = 0; | |
| 1814 | + prev_instance = rr->naihdr.instance; | |
| 1815 | + for (i = 0; i < elems; i++) | |
| 1816 | + switch (size) { | |
| 1817 | + case sizeof(struct qdio_brinfo_entry_l3_ipv6): | |
| 1818 | + (*cb)(priv, l3_ipv6_addr, | |
| 1819 | + &rr->entries.l3_ipv6[i]); | |
| 1820 | + break; | |
| 1821 | + case sizeof(struct qdio_brinfo_entry_l3_ipv4): | |
| 1822 | + (*cb)(priv, l3_ipv4_addr, | |
| 1823 | + &rr->entries.l3_ipv4[i]); | |
| 1824 | + break; | |
| 1825 | + case sizeof(struct qdio_brinfo_entry_l2): | |
| 1826 | + (*cb)(priv, l2_addr_lnid, | |
| 1827 | + &rr->entries.l2[i]); | |
| 1828 | + break; | |
| 1829 | + default: | |
| 1830 | + WARN_ON_ONCE(1); | |
| 1831 | + rc = -EIO; | |
| 1832 | + goto out; | |
| 1833 | + } | |
| 1834 | + } while (rr->response.code == 0x0107 || /* channel busy */ | |
| 1835 | + (rr->response.code == 1 && /* list stored */ | |
| 1836 | + /* resume token is non-zero => list incomplete */ | |
| 1837 | + (rr->naihdr.resume_token.t1 || rr->naihdr.resume_token.t2))); | |
| 1838 | + (*response) = rr->response.code; | |
| 1839 | + | |
| 1840 | +out: | |
| 1841 | + free_page((unsigned long)rr); | |
| 1842 | + return rc; | |
| 1843 | +} | |
| 1844 | +EXPORT_SYMBOL_GPL(qdio_pnso_brinfo); | |
| 1845 | + | |
| 1755 | 1846 | static int __init init_QDIO(void) |
| 1756 | 1847 | { |
| 1757 | 1848 | int rc; |
| @@ -591,7 +591,13 @@ static int ap_init_queue(ap_qid_t qid) · 590 unmodified lines | ||
| 591 | 591 | if (rc != -ENODEV && rc != -EBUSY) |
| 592 | 592 | break; |
| 593 | 593 | if (i < AP_MAX_RESET - 1) { |
| 594 | − udelay(5); | |
| 594 | + /* Time we are waiting until we give up (0.7sec * 90). | |
| 595 | + * Since the actual request (in progress) will not | |
| 596 | + * interrupted immediately for the reset command, | |
| 597 | + * we have to be patient. In worst case we have to | |
| 598 | + * wait 60sec + reset time (some msec). | |
| 599 | + */ | |
| 600 | + schedule_timeout(AP_RESET_TIMEOUT); | |
| 595 | 601 | status = ap_test_queue(qid, &dummy, &dummy); |
| 596 | 602 | } |
| 597 | 603 | } |
| @@ -992,6 +998,28 @@ static ssize_t ap_domain_show(struct bus_type *bus, char *buf) · 394 unmodified lines | ||
| 992 | 998 | |
| 993 | 999 | static BUS_ATTR(ap_domain, 0444, ap_domain_show, NULL); |
| 994 | 1000 | |
| 1001 | +static ssize_t ap_control_domain_mask_show(struct bus_type *bus, char *buf) | |
| 1002 | +{ | |
| 1003 | + if (ap_configuration != NULL) { /* QCI not supported */ | |
| 1004 | + if (test_facility(76)) { /* format 1 - 256 bit domain field */ | |
| 1005 | + return snprintf(buf, PAGE_SIZE, | |
| 1006 | + "0x%08x%08x%08x%08x%08x%08x%08x%08x\n", | |
| 1007 | + ap_configuration->adm[0], ap_configuration->adm[1], | |
| 1008 | + ap_configuration->adm[2], ap_configuration->adm[3], | |
| 1009 | + ap_configuration->adm[4], ap_configuration->adm[5], | |
| 1010 | + ap_configuration->adm[6], ap_configuration->adm[7]); | |
| 1011 | + } else { /* format 0 - 16 bit domain field */ | |
| 1012 | + return snprintf(buf, PAGE_SIZE, "%08x%08x\n", | |
| 1013 | + ap_configuration->adm[0], ap_configuration->adm[1]); | |
| 1014 | + } | |
| 1015 | + } else { | |
| 1016 | + return snprintf(buf, PAGE_SIZE, "not supported\n"); | |
| 1017 | + } | |
| 1018 | +} | |
| 1019 | + | |
| 1020 | +static BUS_ATTR(ap_control_domain_mask, 0444, | |
| 1021 | + ap_control_domain_mask_show, NULL); | |
| 1022 | + | |
| 995 | 1023 | static ssize_t ap_config_time_show(struct bus_type *bus, char *buf) |
| 996 | 1024 | { |
| 997 | 1025 | return snprintf(buf, PAGE_SIZE, "%d\n", ap_config_time); |
| @@ -1077,6 +1105,7 @@ static BUS_ATTR(poll_timeout, 0644, poll_timeout_show, poll_timeout_store); · 79 unmodified lines | ||
| 1077 | 1105 | |
| 1078 | 1106 | static struct bus_attribute *const ap_bus_attrs[] = { |
| 1079 | 1107 | &bus_attr_ap_domain, |
| 1108 | + &bus_attr_ap_control_domain_mask, | |
| 1080 | 1109 | &bus_attr_config_time, |
| 1081 | 1110 | &bus_attr_poll_thread, |
| 1082 | 1111 | &bus_attr_ap_interrupts, |
| @@ -33,7 +33,7 @@ · 32 unmodified lines | ||
| 33 | 33 | #define AP_DEVICES 64 /* Number of AP devices. */ |
| 34 | 34 | #define AP_DOMAINS 16 /* Number of AP domains. */ |
| 35 | 35 | #define AP_MAX_RESET 90 /* Maximum number of resets. */ |
| 36 | −#define AP_RESET_TIMEOUT (HZ/2) /* Time in ticks for reset timeouts. */ | |
| 36 | +#define AP_RESET_TIMEOUT (HZ*0.7) /* Time in ticks for reset timeouts. */ | |
| 37 | 37 | #define AP_CONFIG_TIME 30 /* Time in seconds between AP bus rescans. */ |
| 38 | 38 | #define AP_POLL_TIME 1 /* Time in ticks between receive polls. */ |
| 39 | 39 | |
| @@ -125,6 +125,8 @@ static inline int ap_test_bit(unsigned int *ptr, unsigned int nr) · 85 unmodified lines | ||
| 125 | 125 | #define AP_FUNC_CRT4K 2 |
| 126 | 126 | #define AP_FUNC_COPRO 3 |
| 127 | 127 | #define AP_FUNC_ACCEL 4 |
| 128 | +#define AP_FUNC_EP11 5 | |
| 129 | +#define AP_FUNC_APXA 6 | |
| 128 | 130 | |
| 129 | 131 | /* |
| 130 | 132 | * AP reset flag states |
| @@ -44,6 +44,8 @@ · 43 unmodified lines | ||
| 44 | 44 | #include "zcrypt_debug.h" |
| 45 | 45 | #include "zcrypt_api.h" |
| 46 | 46 | |
| 47 | +#include "zcrypt_msgtype6.h" | |
| 48 | + | |
| 47 | 49 | /* |
| 48 | 50 | * Module description. |
| 49 | 51 | */ |
| @@ -554,9 +556,9 @@ static long zcrypt_send_cprb(struct ica_xcRB *xcRB) · 504 unmodified lines | ||
| 554 | 556 | spin_lock_bh(&zcrypt_device_lock); |
| 555 | 557 | list_for_each_entry(zdev, &zcrypt_device_list, list) { |
| 556 | 558 | if (!zdev->online || !zdev->ops->send_cprb || |
| 557 | − (xcRB->user_defined != AUTOSELECT && | |
| 558 | − AP_QID_DEVICE(zdev->ap_dev->qid) != xcRB->user_defined) | |
| 559 | − ) | |
| 559 | + (zdev->ops->variant == MSGTYPE06_VARIANT_EP11) || | |
| 560 | + (xcRB->user_defined != AUTOSELECT && | |
| 561 | + AP_QID_DEVICE(zdev->ap_dev->qid) != xcRB->user_defined)) | |
| 560 | 562 | continue; |
| 561 | 563 | zcrypt_device_get(zdev); |
| 562 | 564 | get_device(&zdev->ap_dev->device); |
| @@ -581,6 +583,90 @@ static long zcrypt_send_cprb(struct ica_xcRB *xcRB) · 18 unmodified lines | ||
| 581 | 583 | return -ENODEV; |
| 582 | 584 | } |
| 583 | 585 | |
| 586 | +struct ep11_target_dev_list { | |
| 587 | + unsigned short targets_num; | |
| 588 | + struct ep11_target_dev *targets; | |
| 589 | +}; | |
| 590 | + | |
| 591 | +static bool is_desired_ep11dev(unsigned int dev_qid, | |
| 592 | + struct ep11_target_dev_list dev_list) | |
| 593 | +{ | |
| 594 | + int n; | |
| 595 | + | |
| 596 | + for (n = 0; n < dev_list.targets_num; n++, dev_list.targets++) { | |
| 597 | + if ((AP_QID_DEVICE(dev_qid) == dev_list.targets->ap_id) && | |
| 598 | + (AP_QID_QUEUE(dev_qid) == dev_list.targets->dom_id)) { | |
| 599 | + return true; | |
| 600 | + } | |
| 601 | + } | |
| 602 | + return false; | |
| 603 | +} | |
| 604 | + | |
| 605 | +static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb) | |
| 606 | +{ | |
| 607 | + struct zcrypt_device *zdev; | |
| 608 | + bool autoselect = false; | |
| 609 | + int rc; | |
| 610 | + struct ep11_target_dev_list ep11_dev_list = { | |
| 611 | + .targets_num = 0x00, | |
| 612 | + .targets = NULL, | |
| 613 | + }; | |
| 614 | + | |
| 615 | + ep11_dev_list.targets_num = (unsigned short) xcrb->targets_num; | |
| 616 | + | |
| 617 | + /* empty list indicates autoselect (all available targets) */ | |
| 618 | + if (ep11_dev_list.targets_num == 0) | |
| 619 | + autoselect = true; | |
| 620 | + else { | |
| 621 | + ep11_dev_list.targets = kcalloc((unsigned short) | |
| 622 | + xcrb->targets_num, | |
| 623 | + sizeof(struct ep11_target_dev), | |
| 624 | + GFP_KERNEL); | |
| 625 | + if (!ep11_dev_list.targets) | |
| 626 | + return -ENOMEM; | |
| 627 | + | |
| 628 | + if (copy_from_user(ep11_dev_list.targets, | |
| 629 | + (struct ep11_target_dev *)xcrb->targets, | |
| 630 | + xcrb->targets_num * | |
| 631 | + sizeof(struct ep11_target_dev))) | |
| 632 | + return -EFAULT; | |
| 633 | + } | |
| 634 | + | |
| 635 | + spin_lock_bh(&zcrypt_device_lock); | |
| 636 | + list_for_each_entry(zdev, &zcrypt_device_list, list) { | |
| 637 | + /* check if device is eligible */ | |
| 638 | + if (!zdev->online || | |
| 639 | + zdev->ops->variant != MSGTYPE06_VARIANT_EP11) | |
| 640 | + continue; | |
| 641 | + | |
| 642 | + /* check if device is selected as valid target */ | |
| 643 | + if (!is_desired_ep11dev(zdev->ap_dev->qid, ep11_dev_list) && | |
| 644 | + !autoselect) | |
| 645 | + continue; | |
| 646 | + | |
| 647 | + zcrypt_device_get(zdev); | |
| 648 | + get_device(&zdev->ap_dev->device); | |
| 649 | + zdev->request_count++; | |
| 650 | + __zcrypt_decrease_preference(zdev); | |
| 651 | + if (try_module_get(zdev->ap_dev->drv->driver.owner)) { | |
| 652 | + spin_unlock_bh(&zcrypt_device_lock); | |
| 653 | + rc = zdev->ops->send_ep11_cprb(zdev, xcrb); | |
| 654 | + spin_lock_bh(&zcrypt_device_lock); | |
| 655 | + module_put(zdev->ap_dev->drv->driver.owner); | |
| 656 | + } else { | |
| 657 | + rc = -EAGAIN; | |
| 658 | + } | |
| 659 | + zdev->request_count--; | |
| 660 | + __zcrypt_increase_preference(zdev); | |
| 661 | + put_device(&zdev->ap_dev->device); | |
| 662 | + zcrypt_device_put(zdev); | |
| 663 | + spin_unlock_bh(&zcrypt_device_lock); | |
| 664 | + return rc; | |
| 665 | + } | |
| 666 | + spin_unlock_bh(&zcrypt_device_lock); | |
| 667 | + return -ENODEV; | |
| 668 | +} | |
| 669 | + | |
| 584 | 670 | static long zcrypt_rng(char *buffer) |
| 585 | 671 | { |
| 586 | 672 | struct zcrypt_device *zdev; |
| @@ -784,6 +870,23 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd, · 197 unmodified lines | ||
| 784 | 870 | return -EFAULT; |
| 785 | 871 | return rc; |
| 786 | 872 | } |
| 873 | + case ZSENDEP11CPRB: { | |
| 874 | + struct ep11_urb __user *uxcrb = (void __user *)arg; | |
| 875 | + struct ep11_urb xcrb; | |
| 876 | + if (copy_from_user(&xcrb, uxcrb, sizeof(xcrb))) | |
| 877 | + return -EFAULT; | |
| 878 | + do { | |
| 879 | + rc = zcrypt_send_ep11_cprb(&xcrb); | |
| 880 | + } while (rc == -EAGAIN); | |
| 881 | + /* on failure: retry once again after a requested rescan */ | |
| 882 | + if ((rc == -ENODEV) && (zcrypt_process_rescan())) | |
| 883 | + do { | |
| 884 | + rc = zcrypt_send_ep11_cprb(&xcrb); | |
| 885 | + } while (rc == -EAGAIN); | |
| 886 | + if (copy_to_user(uxcrb, &xcrb, sizeof(xcrb))) | |
| 887 | + return -EFAULT; | |
| 888 | + return rc; | |
| 889 | + } | |
| 787 | 890 | case Z90STAT_STATUS_MASK: { |
| 788 | 891 | char status[AP_DEVICES]; |
| 789 | 892 | zcrypt_status_mask(status); |
| @@ -74,6 +74,7 @@ struct ica_z90_status { · 73 unmodified lines | ||
| 74 | 74 | #define ZCRYPT_CEX2A 6 |
| 75 | 75 | #define ZCRYPT_CEX3C 7 |
| 76 | 76 | #define ZCRYPT_CEX3A 8 |
| 77 | +#define ZCRYPT_CEX4 10 | |
| 77 | 78 | |
| 78 | 79 | /** |
| 79 | 80 | * Large random numbers are pulled in 4096 byte chunks from the crypto cards |
| @@ -89,6 +90,7 @@ struct zcrypt_ops { · 9 unmodified lines | ||
| 89 | 90 | long (*rsa_modexpo_crt)(struct zcrypt_device *, |
| 90 | 91 | struct ica_rsa_modexpo_crt *); |
| 91 | 92 | long (*send_cprb)(struct zcrypt_device *, struct ica_xcRB *); |
| 93 | + long (*send_ep11_cprb)(struct zcrypt_device *, struct ep11_urb *); | |
| 92 | 94 | long (*rng)(struct zcrypt_device *, char *); |
| 93 | 95 | struct list_head list; /* zcrypt ops list. */ |
| 94 | 96 | struct module *owner; |
| @@ -30,7 +30,12 @@ · 29 unmodified lines | ||
| 30 | 30 | #define CEX4A_MAX_MESSAGE_SIZE MSGTYPE50_CRB3_MAX_MSG_SIZE |
| 31 | 31 | #define CEX4C_MAX_MESSAGE_SIZE MSGTYPE06_MAX_MSG_SIZE |
| 32 | 32 | |
| 33 | −#define CEX4_CLEANUP_TIME (15*HZ) | |
| 33 | +/* Waiting time for requests to be processed. | |
| 34 | + * Currently there are some types of request which are not deterministic. | |
| 35 | + * But the maximum time limit managed by the stomper code is set to 60sec. | |
| 36 | + * Hence we have to wait at least that time period. | |
| 37 | + */ | |
| 38 | +#define CEX4_CLEANUP_TIME (61*HZ) | |
| 34 | 39 | |
| 35 | 40 | static struct ap_device_id zcrypt_cex4_ids[] = { |
| 36 | 41 | { AP_DEVICE(AP_DEVICE_TYPE_CEX4) }, |
| @@ -101,6 +106,19 @@ static int zcrypt_cex4_probe(struct ap_device *ap_dev) · 64 unmodified lines | ||
| 101 | 106 | zdev->speed_rating = CEX4C_SPEED_RATING; |
| 102 | 107 | zdev->ops = zcrypt_msgtype_request(MSGTYPE06_NAME, |
| 103 | 108 | MSGTYPE06_VARIANT_DEFAULT); |
| 109 | + } else if (ap_test_bit(&ap_dev->functions, AP_FUNC_EP11)) { | |
| 110 | + zdev = zcrypt_device_alloc(CEX4C_MAX_MESSAGE_SIZE); | |
| 111 | + if (!zdev) | |
| 112 | + return -ENOMEM; | |
| 113 | + zdev->type_string = "CEX4P"; | |
| 114 | + zdev->user_space_type = ZCRYPT_CEX4; | |
| 115 | + zdev->min_mod_size = CEX4C_MIN_MOD_SIZE; | |
| 116 | + zdev->max_mod_size = CEX4C_MAX_MOD_SIZE; | |
| 117 | + zdev->max_exp_bit_length = CEX4C_MAX_MOD_SIZE; | |
| 118 | + zdev->short_crt = 0; | |
| 119 | + zdev->speed_rating = CEX4C_SPEED_RATING; | |
| 120 | + zdev->ops = zcrypt_msgtype_request(MSGTYPE06_NAME, | |
| 121 | + MSGTYPE06_VARIANT_EP11); | |
| 104 | 122 | } |
| 105 | 123 | break; |
| 106 | 124 | } |
| @@ -106,15 +106,15 @@ static inline int convert_error(struct zcrypt_device *zdev, · 105 unmodified lines | ||
| 106 | 106 | // REP88_ERROR_MESSAGE_TYPE // '20' CEX2A |
| 107 | 107 | /* |
| 108 | 108 | * To sent a message of the wrong type is a bug in the |
| 109 | − * device driver. Warn about it, disable the device | |
| 109 | + * device driver. Send error msg, disable the device | |
| 110 | 110 | * and then repeat the request. |
| 111 | 111 | */ |
| 112 | − WARN_ON(1); | |
| 113 | 112 | atomic_set(&zcrypt_rescan_req, 1); |
| 114 | 113 | zdev->online = 0; |
| 114 | + pr_err("Cryptographic device %x failed and was set offline\n", | |
| 115 | + zdev->ap_dev->qid); | |
| 115 | 116 | ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%drc%d", |
| 116 | − zdev->ap_dev->qid, | |
| 117 | − zdev->online, ehdr->reply_code); | |
| 117 | + zdev->ap_dev->qid, zdev->online, ehdr->reply_code); | |
| 118 | 118 | return -EAGAIN; |
| 119 | 119 | case REP82_ERROR_TRANSPORT_FAIL: |
| 120 | 120 | case REP82_ERROR_MACHINE_FAILURE: |
| @@ -122,15 +122,17 @@ static inline int convert_error(struct zcrypt_device *zdev, · 1 unmodified line | ||
| 122 | 122 | /* If a card fails disable it and repeat the request. */ |
| 123 | 123 | atomic_set(&zcrypt_rescan_req, 1); |
| 124 | 124 | zdev->online = 0; |
| 125 | + pr_err("Cryptographic device %x failed and was set offline\n", | |
| 126 | + zdev->ap_dev->qid); | |
| 125 | 127 | ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%drc%d", |
| 126 | − zdev->ap_dev->qid, | |
| 127 | − zdev->online, ehdr->reply_code); | |
| 128 | + zdev->ap_dev->qid, zdev->online, ehdr->reply_code); | |
| 128 | 129 | return -EAGAIN; |
| 129 | 130 | default: |
| 130 | 131 | zdev->online = 0; |
| 132 | + pr_err("Cryptographic device %x failed and was set offline\n", | |
| 133 | + zdev->ap_dev->qid); | |
| 131 | 134 | ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%drc%d", |
| 132 | − zdev->ap_dev->qid, | |
| 133 | − zdev->online, ehdr->reply_code); | |
| 135 | + zdev->ap_dev->qid, zdev->online, ehdr->reply_code); | |
| 134 | 136 | return -EAGAIN; /* repeat the request on a different device. */ |
| 135 | 137 | } |
| 136 | 138 | } |
| @@ -25,6 +25,9 @@ · 24 unmodified lines | ||
| 25 | 25 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| 26 | 26 | */ |
| 27 | 27 | |
| 28 | +#define KMSG_COMPONENT "zcrypt" | |
| 29 | +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | |
| 30 | + | |
| 28 | 31 | #include <linux/module.h> |
| 29 | 32 | #include <linux/slab.h> |
| 30 | 33 | #include <linux/init.h> |
| @@ -332,6 +335,11 @@ static int convert_type80(struct zcrypt_device *zdev, · 301 unmodified lines | ||
| 332 | 335 | if (t80h->len < sizeof(*t80h) + outputdatalength) { |
| 333 | 336 | /* The result is too short, the CEX2A card may not do that.. */ |
| 334 | 337 | zdev->online = 0; |
| 338 | + pr_err("Cryptographic device %x failed and was set offline\n", | |
| 339 | + zdev->ap_dev->qid); | |
| 340 | + ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%drc%d", | |
| 341 | + zdev->ap_dev->qid, zdev->online, t80h->code); | |
| 342 | + | |
| 335 | 343 | return -EAGAIN; /* repeat the request on a different device. */ |
| 336 | 344 | } |
| 337 | 345 | if (zdev->user_space_type == ZCRYPT_CEX2A) |
| @@ -359,6 +367,10 @@ static int convert_response(struct zcrypt_device *zdev, · 21 unmodified lines | ||
| 359 | 367 | outputdata, outputdatalength); |
| 360 | 368 | default: /* Unknown response type, this should NEVER EVER happen */ |
| 361 | 369 | zdev->online = 0; |
| 370 | + pr_err("Cryptographic device %x failed and was set offline\n", | |
| 371 | + zdev->ap_dev->qid); | |
| 372 | + ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%dfail", | |
| 373 | + zdev->ap_dev->qid, zdev->online); | |
| 362 | 374 | return -EAGAIN; /* repeat the request on a different device. */ |
| 363 | 375 | } |
| 364 | 376 | } |
| @@ -25,6 +25,9 @@ · 24 unmodified lines | ||
| 25 | 25 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| 26 | 26 | */ |
| 27 | 27 | |
| 28 | +#define KMSG_COMPONENT "zcrypt" | |
| 29 | +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | |
| 30 | + | |
| 28 | 31 | #include <linux/module.h> |
| 29 | 32 | #include <linux/init.h> |
| 30 | 33 | #include <linux/err.h> |
| @@ -50,6 +53,7 @@ struct response_type { · 19 unmodified lines | ||
| 50 | 53 | }; |
| 51 | 54 | #define PCIXCC_RESPONSE_TYPE_ICA 0 |
| 52 | 55 | #define PCIXCC_RESPONSE_TYPE_XCRB 1 |
| 56 | +#define PCIXCC_RESPONSE_TYPE_EP11 2 | |
| 53 | 57 | |
| 54 | 58 | MODULE_AUTHOR("IBM Corporation"); |
| 55 | 59 | MODULE_DESCRIPTION("Cryptographic Coprocessor (message type 6), " \ |
| @@ -358,6 +362,91 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev, · 302 unmodified lines | ||
| 358 | 362 | return 0; |
| 359 | 363 | } |
| 360 | 364 | |
| 365 | +static int xcrb_msg_to_type6_ep11cprb_msgx(struct zcrypt_device *zdev, | |
| 366 | + struct ap_message *ap_msg, | |
| 367 | + struct ep11_urb *xcRB) | |
| 368 | +{ | |
| 369 | + unsigned int lfmt; | |
| 370 | + | |
| 371 | + static struct type6_hdr static_type6_ep11_hdr = { | |
| 372 | + .type = 0x06, | |
| 373 | + .rqid = {0x00, 0x01}, | |
| 374 | + .function_code = {0x00, 0x00}, | |
| 375 | + .agent_id[0] = 0x58, /* {'X'} */ | |
| 376 | + .agent_id[1] = 0x43, /* {'C'} */ | |
| 377 | + .offset1 = 0x00000058, | |
| 378 | + }; | |
| 379 | + | |
| 380 | + struct { | |
| 381 | + struct type6_hdr hdr; | |
| 382 | + struct ep11_cprb cprbx; | |
| 383 | + unsigned char pld_tag; /* fixed value 0x30 */ | |
| 384 | + unsigned char pld_lenfmt; /* payload length format */ | |
| 385 | + } __packed * msg = ap_msg->message; | |
| 386 | + | |
| 387 | + struct pld_hdr { | |
| 388 | + unsigned char func_tag; /* fixed value 0x4 */ | |
| 389 | + unsigned char func_len; /* fixed value 0x4 */ | |
| 390 | + unsigned int func_val; /* function ID */ | |
| 391 | + unsigned char dom_tag; /* fixed value 0x4 */ | |
| 392 | + unsigned char dom_len; /* fixed value 0x4 */ | |
| 393 | + unsigned int dom_val; /* domain id */ | |
| 394 | + } __packed * payload_hdr; | |
| 395 | + | |
| 396 | + /* length checks */ | |
| 397 | + ap_msg->length = sizeof(struct type6_hdr) + xcRB->req_len; | |
| 398 | + if (CEIL4(xcRB->req_len) > MSGTYPE06_MAX_MSG_SIZE - | |
| 399 | + (sizeof(struct type6_hdr))) | |
| 400 | + return -EINVAL; | |
| 401 | + | |
| 402 | + if (CEIL4(xcRB->resp_len) > MSGTYPE06_MAX_MSG_SIZE - | |
| 403 | + (sizeof(struct type86_fmt2_msg))) | |
| 404 | + return -EINVAL; | |
| 405 | + | |
| 406 | + /* prepare type6 header */ | |
| 407 | + msg->hdr = static_type6_ep11_hdr; | |
| 408 | + msg->hdr.ToCardLen1 = xcRB->req_len; | |
| 409 | + msg->hdr.FromCardLen1 = xcRB->resp_len; | |
| 410 | + | |
| 411 | + /* Import CPRB data from the ioctl input parameter */ | |
| 412 | + if (copy_from_user(&(msg->cprbx.cprb_len), | |
| 413 | + (char *)xcRB->req, xcRB->req_len)) { | |
| 414 | + return -EFAULT; | |
| 415 | + } | |
| 416 | + | |
| 417 | + /* | |
| 418 | + The target domain field within the cprb body/payload block will be | |
| 419 | + replaced by the usage domain for non-management commands only. | |
| 420 | + Therefore we check the first bit of the 'flags' parameter for | |
| 421 | + management command indication. | |
| 422 | + 0 - non management command | |
| 423 | + 1 - management command | |
| 424 | + */ | |
| 425 | + if (!((msg->cprbx.flags & 0x80) == 0x80)) { | |
| 426 | + msg->cprbx.target_id = (unsigned int) | |
| 427 | + AP_QID_QUEUE(zdev->ap_dev->qid); | |
| 428 | + | |
| 429 | + if ((msg->pld_lenfmt & 0x80) == 0x80) { /*ext.len.fmt 2 or 3*/ | |
| 430 | + switch (msg->pld_lenfmt & 0x03) { | |
| 431 | + case 1: | |
| 432 | + lfmt = 2; | |
| 433 | + break; | |
| 434 | + case 2: | |
| 435 | + lfmt = 3; | |
| 436 | + break; | |
| 437 | + default: | |
| 438 | + return -EINVAL; | |
| 439 | + } | |
| 440 | + } else { | |
| 441 | + lfmt = 1; /* length format #1 */ | |
| 442 | + } | |
| 443 | + payload_hdr = (struct pld_hdr *)((&(msg->pld_lenfmt))+lfmt); | |
| 444 | + payload_hdr->dom_val = (unsigned int) | |
| 445 | + AP_QID_QUEUE(zdev->ap_dev->qid); | |
| 446 | + } | |
| 447 | + return 0; | |
| 448 | +} | |
| 449 | + | |
| 361 | 450 | /** |
| 362 | 451 | * Copy results from a type 86 ICA reply message back to user space. |
| 363 | 452 | * |
| @@ -377,6 +466,12 @@ struct type86x_reply { · 13 unmodified lines | ||
| 377 | 466 | char text[0]; |
| 378 | 467 | } __packed; |
| 379 | 468 | |
| 469 | +struct type86_ep11_reply { | |
| 470 | + struct type86_hdr hdr; | |
| 471 | + struct type86_fmt2_ext fmt2; | |
| 472 | + struct ep11_cprb cprbx; | |
| 473 | +} __packed; | |
| 474 | + | |
| 380 | 475 | static int convert_type86_ica(struct zcrypt_device *zdev, |
| 381 | 476 | struct ap_message *reply, |
| 382 | 477 | char __user *outputdata, |
| @@ -440,6 +535,11 @@ static int convert_type86_ica(struct zcrypt_device *zdev, · 57 unmodified lines | ||
| 440 | 535 | if (service_rc == 8 && service_rs == 72) |
| 441 | 536 | return -EINVAL; |
| 442 | 537 | zdev->online = 0; |
| 538 | + pr_err("Cryptographic device %x failed and was set offline\n", | |
| 539 | + zdev->ap_dev->qid); | |
| 540 | + ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%drc%d", | |
| 541 | + zdev->ap_dev->qid, zdev->online, | |
| 542 | + msg->hdr.reply_code); | |
| 443 | 543 | return -EAGAIN; /* repeat the request on a different device. */ |
| 444 | 544 | } |
| 445 | 545 | data = msg->text; |
| @@ -503,6 +603,33 @@ static int convert_type86_xcrb(struct zcrypt_device *zdev, · 57 unmodified lines | ||
| 503 | 603 | return 0; |
| 504 | 604 | } |
| 505 | 605 | |
| 606 | +/** | |
| 607 | + * Copy results from a type 86 EP11 XCRB reply message back to user space. | |
| 608 | + * | |
| 609 | + * @zdev: crypto device pointer | |
| 610 | + * @reply: reply AP message. | |
| 611 | + * @xcRB: pointer to EP11 user request block | |
| 612 | + * | |
| 613 | + * Returns 0 on success or -EINVAL, -EFAULT, -EAGAIN in case of an error. | |
| 614 | + */ | |
| 615 | +static int convert_type86_ep11_xcrb(struct zcrypt_device *zdev, | |
| 616 | + struct ap_message *reply, | |
| 617 | + struct ep11_urb *xcRB) | |
| 618 | +{ | |
| 619 | + struct type86_fmt2_msg *msg = reply->message; | |
| 620 | + char *data = reply->message; | |
| 621 | + | |
| 622 | + if (xcRB->resp_len < msg->fmt2.count1) | |
| 623 | + return -EINVAL; | |
| 624 | + | |
| 625 | + /* Copy response CPRB to user */ | |
| 626 | + if (copy_to_user((char *)xcRB->resp, | |
| 627 | + data + msg->fmt2.offset1, msg->fmt2.count1)) | |
| 628 | + return -EFAULT; | |
| 629 | + xcRB->resp_len = msg->fmt2.count1; | |
| 630 | + return 0; | |
| 631 | +} | |
| 632 | + | |
| 506 | 633 | static int convert_type86_rng(struct zcrypt_device *zdev, |
| 507 | 634 | struct ap_message *reply, |
| 508 | 635 | char *buffer) |
| @@ -551,6 +678,10 @@ static int convert_response_ica(struct zcrypt_device *zdev, · 42 unmodified lines | ||
| 551 | 678 | * response */ |
| 552 | 679 | default: /* Unknown response type, this should NEVER EVER happen */ |
| 553 | 680 | zdev->online = 0; |
| 681 | + pr_err("Cryptographic device %x failed and was set offline\n", | |
| 682 | + zdev->ap_dev->qid); | |
| 683 | + ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%dfail", | |
| 684 | + zdev->ap_dev->qid, zdev->online); | |
| 554 | 685 | return -EAGAIN; /* repeat the request on a different device. */ |
| 555 | 686 | } |
| 556 | 687 | } |
| @@ -579,10 +710,40 @@ static int convert_response_xcrb(struct zcrypt_device *zdev, · 22 unmodified lines | ||
| 579 | 710 | default: /* Unknown response type, this should NEVER EVER happen */ |
| 580 | 711 | xcRB->status = 0x0008044DL; /* HDD_InvalidParm */ |
| 581 | 712 | zdev->online = 0; |
| 713 | + pr_err("Cryptographic device %x failed and was set offline\n", | |
| 714 | + zdev->ap_dev->qid); | |
| 715 | + ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%dfail", | |
| 716 | + zdev->ap_dev->qid, zdev->online); | |
| 582 | 717 | return -EAGAIN; /* repeat the request on a different device. */ |
| 583 | 718 | } |
| 584 | 719 | } |
| 585 | 720 | |
| 721 | +static int convert_response_ep11_xcrb(struct zcrypt_device *zdev, | |
| 722 | + struct ap_message *reply, struct ep11_urb *xcRB) | |
| 723 | +{ | |
| 724 | + struct type86_ep11_reply *msg = reply->message; | |
| 725 | + | |
| 726 | + /* Response type byte is the second byte in the response. */ | |
| 727 | + switch (((unsigned char *)reply->message)[1]) { | |
| 728 | + case TYPE82_RSP_CODE: | |
| 729 | + case TYPE87_RSP_CODE: | |
| 730 | + return convert_error(zdev, reply); | |
| 731 | + case TYPE86_RSP_CODE: | |
| 732 | + if (msg->hdr.reply_code) | |
| 733 | + return convert_error(zdev, reply); | |
| 734 | + if (msg->cprbx.cprb_ver_id == 0x04) | |
| 735 | + return convert_type86_ep11_xcrb(zdev, reply, xcRB); | |
| 736 | + /* Fall through, no break, incorrect cprb version is an unknown resp.*/ | |
| 737 | + default: /* Unknown response type, this should NEVER EVER happen */ | |
| 738 | + zdev->online = 0; | |
| 739 | + pr_err("Cryptographic device %x failed and was set offline\n", | |
| 740 | + zdev->ap_dev->qid); | |
| 741 | + ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%dfail", | |
| 742 | + zdev->ap_dev->qid, zdev->online); | |
| 743 | + return -EAGAIN; /* repeat the request on a different device. */ | |
| 744 | + } | |
| 745 | +} | |
| 746 | + | |
| 586 | 747 | static int convert_response_rng(struct zcrypt_device *zdev, |
| 587 | 748 | struct ap_message *reply, |
| 588 | 749 | char *data) |
| @@ -602,6 +763,10 @@ static int convert_response_rng(struct zcrypt_device *zdev, · 13 unmodified lines | ||
| 602 | 763 | * response */ |
| 603 | 764 | default: /* Unknown response type, this should NEVER EVER happen */ |
| 604 | 765 | zdev->online = 0; |
| 766 | + pr_err("Cryptographic device %x failed and was set offline\n", | |
| 767 | + zdev->ap_dev->qid); | |
| 768 | + ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%dfail", | |
| 769 | + zdev->ap_dev->qid, zdev->online); | |
| 605 | 770 | return -EAGAIN; /* repeat the request on a different device. */ |
| 606 | 771 | } |
| 607 | 772 | } |
| @@ -657,6 +822,51 @@ out: · 49 unmodified lines | ||
| 657 | 822 | complete(&(resp_type->work)); |
| 658 | 823 | } |
| 659 | 824 | |
| 825 | +/** | |
| 826 | + * This function is called from the AP bus code after a crypto request | |
| 827 | + * "msg" has finished with the reply message "reply". | |
| 828 | + * It is called from tasklet context. | |
| 829 | + * @ap_dev: pointer to the AP device | |
| 830 | + * @msg: pointer to the AP message | |
| 831 | + * @reply: pointer to the AP reply message | |
| 832 | + */ | |
| 833 | +static void zcrypt_msgtype6_receive_ep11(struct ap_device *ap_dev, | |
| 834 | + struct ap_message *msg, | |
| 835 | + struct ap_message *reply) | |
| 836 | +{ | |
| 837 | + static struct error_hdr error_reply = { | |
| 838 | + .type = TYPE82_RSP_CODE, | |
| 839 | + .reply_code = REP82_ERROR_MACHINE_FAILURE, | |
| 840 | + }; | |
| 841 | + struct response_type *resp_type = | |
| 842 | + (struct response_type *)msg->private; | |
| 843 | + struct type86_ep11_reply *t86r; | |
| 844 | + int length; | |
| 845 | + | |
| 846 | + /* Copy the reply message to the request message buffer. */ | |
| 847 | + if (IS_ERR(reply)) { | |
| 848 | + memcpy(msg->message, &error_reply, sizeof(error_reply)); | |
| 849 | + goto out; | |
| 850 | + } | |
| 851 | + t86r = reply->message; | |
| 852 | + if (t86r->hdr.type == TYPE86_RSP_CODE && | |
| 853 | + t86r->cprbx.cprb_ver_id == 0x04) { | |
| 854 | + switch (resp_type->type) { | |
| 855 | + case PCIXCC_RESPONSE_TYPE_EP11: | |
| 856 | + length = t86r->fmt2.offset1 + t86r->fmt2.count1; | |
| 857 | + length = min(MSGTYPE06_MAX_MSG_SIZE, length); | |
| 858 | + memcpy(msg->message, reply->message, length); | |
| 859 | + break; | |
| 860 | + default: | |
| 861 | + memcpy(msg->message, &error_reply, sizeof(error_reply)); | |
| 862 | + } | |
| 863 | + } else { | |
| 864 | + memcpy(msg->message, reply->message, sizeof(error_reply)); | |
| 865 | + } | |
| 866 | +out: | |
| 867 | + complete(&(resp_type->work)); | |
| 868 | +} | |
| 869 | + | |
| 660 | 870 | static atomic_t zcrypt_step = ATOMIC_INIT(0); |
| 661 | 871 | |
| 662 | 872 | /** |
| @@ -781,6 +991,46 @@ out_free: · 118 unmodified lines | ||
| 781 | 991 | return rc; |
| 782 | 992 | } |
| 783 | 993 | |
| 994 | +/** | |
| 995 | + * The request distributor calls this function if it picked the CEX4P | |
| 996 | + * device to handle a send_ep11_cprb request. | |
| 997 | + * @zdev: pointer to zcrypt_device structure that identifies the | |
| 998 | + * CEX4P device to the request distributor | |
| 999 | + * @xcRB: pointer to the ep11 user request block | |
| 1000 | + */ | |
| 1001 | +static long zcrypt_msgtype6_send_ep11_cprb(struct zcrypt_device *zdev, | |
| 1002 | + struct ep11_urb *xcrb) | |
| 1003 | +{ | |
| 1004 | + struct ap_message ap_msg; | |
| 1005 | + struct response_type resp_type = { | |
| 1006 | + .type = PCIXCC_RESPONSE_TYPE_EP11, | |
| 1007 | + }; | |
| 1008 | + int rc; | |
| 1009 | + | |
| 1010 | + ap_init_message(&ap_msg); | |
| 1011 | + ap_msg.message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL); | |
| 1012 | + if (!ap_msg.message) | |
| 1013 | + return -ENOMEM; | |
| 1014 | + ap_msg.receive = zcrypt_msgtype6_receive_ep11; | |
| 1015 | + ap_msg.psmid = (((unsigned long long) current->pid) << 32) + | |
| 1016 | + atomic_inc_return(&zcrypt_step); | |
| 1017 | + ap_msg.private = &resp_type; | |
| 1018 | + rc = xcrb_msg_to_type6_ep11cprb_msgx(zdev, &ap_msg, xcrb); | |
| 1019 | + if (rc) | |
| 1020 | + goto out_free; | |
| 1021 | + init_completion(&resp_type.work); | |
| 1022 | + ap_queue_message(zdev->ap_dev, &ap_msg); | |
| 1023 | + rc = wait_for_completion_interruptible(&resp_type.work); | |
| 1024 | + if (rc == 0) | |
| 1025 | + rc = convert_response_ep11_xcrb(zdev, &ap_msg, xcrb); | |
| 1026 | + else /* Signal pending. */ | |
| 1027 | + ap_cancel_message(zdev->ap_dev, &ap_msg); | |
| 1028 | + | |
| 1029 | +out_free: | |
| 1030 | + kzfree(ap_msg.message); | |
| 1031 | + return rc; | |
| 1032 | +} | |
| 1033 | + | |
| 784 | 1034 | /** |
| 785 | 1035 | * The request distributor calls this function if it picked the PCIXCC/CEX2C |
| 786 | 1036 | * device to generate random data. |
| @@ -839,10 +1089,19 @@ static struct zcrypt_ops zcrypt_msgtype6_ops = { · 52 unmodified lines | ||
| 839 | 1089 | .rng = zcrypt_msgtype6_rng, |
| 840 | 1090 | }; |
| 841 | 1091 | |
| 1092 | +static struct zcrypt_ops zcrypt_msgtype6_ep11_ops = { | |
| 1093 | + .owner = THIS_MODULE, | |
| 1094 | + .variant = MSGTYPE06_VARIANT_EP11, | |
| 1095 | + .rsa_modexpo = NULL, | |
| 1096 | + .rsa_modexpo_crt = NULL, | |
| 1097 | + .send_ep11_cprb = zcrypt_msgtype6_send_ep11_cprb, | |
| 1098 | +}; | |
| 1099 | + | |
| 842 | 1100 | int __init zcrypt_msgtype6_init(void) |
| 843 | 1101 | { |
| 844 | 1102 | zcrypt_msgtype_register(&zcrypt_msgtype6_norng_ops); |
| 845 | 1103 | zcrypt_msgtype_register(&zcrypt_msgtype6_ops); |
| 1104 | + zcrypt_msgtype_register(&zcrypt_msgtype6_ep11_ops); | |
| 846 | 1105 | return 0; |
| 847 | 1106 | } |
| 848 | 1107 | |
| @@ -850,6 +1109,7 @@ void __exit zcrypt_msgtype6_exit(void) · 1 unmodified line | ||
| 850 | 1109 | { |
| 851 | 1110 | zcrypt_msgtype_unregister(&zcrypt_msgtype6_norng_ops); |
| 852 | 1111 | zcrypt_msgtype_unregister(&zcrypt_msgtype6_ops); |
| 1112 | + zcrypt_msgtype_unregister(&zcrypt_msgtype6_ep11_ops); | |
| 853 | 1113 | } |
| 854 | 1114 | |
| 855 | 1115 | module_init(zcrypt_msgtype6_init); |
| @@ -32,6 +32,7 @@ · 31 unmodified lines | ||
| 32 | 32 | #define MSGTYPE06_NAME "zcrypt_msgtype6" |
| 33 | 33 | #define MSGTYPE06_VARIANT_DEFAULT 0 |
| 34 | 34 | #define MSGTYPE06_VARIANT_NORNG 1 |
| 35 | +#define MSGTYPE06_VARIANT_EP11 2 | |
| 35 | 36 | |
| 36 | 37 | #define MSGTYPE06_MAX_MSG_SIZE (12*1024) |
| 37 | 38 | |
| @@ -99,6 +100,7 @@ struct type86_hdr { · 61 unmodified lines | ||
| 99 | 100 | } __packed; |
| 100 | 101 | |
| 101 | 102 | #define TYPE86_RSP_CODE 0x86 |
| 103 | +#define TYPE87_RSP_CODE 0x87 | |
| 102 | 104 | #define TYPE86_FMT2 0x02 |
| 103 | 105 | |
| 104 | 106 | struct type86_fmt2_ext { |
| @@ -24,6 +24,9 @@ · 23 unmodified lines | ||
| 24 | 24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| 25 | 25 | */ |
| 26 | 26 | |
| 27 | +#define KMSG_COMPONENT "zcrypt" | |
| 28 | +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | |
| 29 | + | |
| 27 | 30 | #include <linux/module.h> |
| 28 | 31 | #include <linux/slab.h> |
| 29 | 32 | #include <linux/init.h> |
| @@ -199,6 +202,10 @@ static int convert_type84(struct zcrypt_device *zdev, · 169 unmodified lines | ||
| 199 | 202 | if (t84h->len < sizeof(*t84h) + outputdatalength) { |
| 200 | 203 | /* The result is too short, the PCICA card may not do that.. */ |
| 201 | 204 | zdev->online = 0; |
| 205 | + pr_err("Cryptographic device %x failed and was set offline\n", | |
| 206 | + zdev->ap_dev->qid); | |
| 207 | + ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%drc%d", | |
| 208 | + zdev->ap_dev->qid, zdev->online, t84h->code); | |
| 202 | 209 | return -EAGAIN; /* repeat the request on a different device. */ |
| 203 | 210 | } |
| 204 | 211 | BUG_ON(t84h->len > PCICA_MAX_RESPONSE_SIZE); |
| @@ -223,6 +230,10 @@ static int convert_response(struct zcrypt_device *zdev, · 18 unmodified lines | ||
| 223 | 230 | outputdata, outputdatalength); |
| 224 | 231 | default: /* Unknown response type, this should NEVER EVER happen */ |
| 225 | 232 | zdev->online = 0; |
| 233 | + pr_err("Cryptographic device %x failed and was set offline\n", | |
| 234 | + zdev->ap_dev->qid); | |
| 235 | + ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%dfail", | |
| 236 | + zdev->ap_dev->qid, zdev->online); | |
| 226 | 237 | return -EAGAIN; /* repeat the request on a different device. */ |
| 227 | 238 | } |
| 228 | 239 | } |
| @@ -24,6 +24,9 @@ · 23 unmodified lines | ||
| 24 | 24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| 25 | 25 | */ |
| 26 | 26 | |
| 27 | +#define KMSG_COMPONENT "zcrypt" | |
| 28 | +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | |
| 29 | + | |
| 27 | 30 | #include <linux/module.h> |
| 28 | 31 | #include <linux/init.h> |
| 29 | 32 | #include <linux/gfp.h> |
| @@ -372,6 +375,11 @@ static int convert_type86(struct zcrypt_device *zdev, · 342 unmodified lines | ||
| 372 | 375 | if (service_rc == 8 && service_rs == 72) |
| 373 | 376 | return -EINVAL; |
| 374 | 377 | zdev->online = 0; |
| 378 | + pr_err("Cryptographic device %x failed and was set offline\n", | |
| 379 | + zdev->ap_dev->qid); | |
| 380 | + ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%drc%d", | |
| 381 | + zdev->ap_dev->qid, zdev->online, | |
| 382 | + msg->hdr.reply_code); | |
| 375 | 383 | return -EAGAIN; /* repeat the request on a different device. */ |
| 376 | 384 | } |
| 377 | 385 | data = msg->text; |
| @@ -425,6 +433,10 @@ static int convert_response(struct zcrypt_device *zdev, · 47 unmodified lines | ||
| 425 | 433 | /* no break, incorrect cprb version is an unknown response */ |
| 426 | 434 | default: /* Unknown response type, this should NEVER EVER happen */ |
| 427 | 435 | zdev->online = 0; |
| 436 | + pr_err("Cryptographic device %x failed and was set offline\n", | |
| 437 | + zdev->ap_dev->qid); | |
| 438 | + ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%dfail", | |
| 439 | + zdev->ap_dev->qid, zdev->online); | |
| 428 | 440 | return -EAGAIN; /* repeat the request on a different device. */ |
| 429 | 441 | } |
| 430 | 442 | } |