| .. | .. |
|---|
| 202 | 202 | } |
|---|
| 203 | 203 | |
|---|
| 204 | 204 | /* |
|---|
| 205 | | - * Use IBS for precise event sampling: |
|---|
| 205 | + * core pmu config -> IBS config |
|---|
| 206 | 206 | * |
|---|
| 207 | 207 | * perf record -a -e cpu-cycles:p ... # use ibs op counting cycle count |
|---|
| 208 | 208 | * perf record -a -e r076:p ... # same as -e cpu-cycles:p |
|---|
| .. | .. |
|---|
| 211 | 211 | * IbsOpCntCtl (bit 19) of IBS Execution Control Register (IbsOpCtl, |
|---|
| 212 | 212 | * MSRC001_1033) is used to select either cycle or micro-ops counting |
|---|
| 213 | 213 | * mode. |
|---|
| 214 | | - * |
|---|
| 215 | | - * The rip of IBS samples has skid 0. Thus, IBS supports precise |
|---|
| 216 | | - * levels 1 and 2 and the PERF_EFLAGS_EXACT is set. In rare cases the |
|---|
| 217 | | - * rip is invalid when IBS was not able to record the rip correctly. |
|---|
| 218 | | - * We clear PERF_EFLAGS_EXACT and take the rip from pt_regs then. |
|---|
| 219 | | - * |
|---|
| 220 | 214 | */ |
|---|
| 221 | | -static int perf_ibs_precise_event(struct perf_event *event, u64 *config) |
|---|
| 215 | +static int core_pmu_ibs_config(struct perf_event *event, u64 *config) |
|---|
| 222 | 216 | { |
|---|
| 223 | | - switch (event->attr.precise_ip) { |
|---|
| 224 | | - case 0: |
|---|
| 225 | | - return -ENOENT; |
|---|
| 226 | | - case 1: |
|---|
| 227 | | - case 2: |
|---|
| 228 | | - break; |
|---|
| 229 | | - default: |
|---|
| 230 | | - return -EOPNOTSUPP; |
|---|
| 231 | | - } |
|---|
| 232 | | - |
|---|
| 233 | 217 | switch (event->attr.type) { |
|---|
| 234 | 218 | case PERF_TYPE_HARDWARE: |
|---|
| 235 | 219 | switch (event->attr.config) { |
|---|
| .. | .. |
|---|
| 255 | 239 | return -EOPNOTSUPP; |
|---|
| 256 | 240 | } |
|---|
| 257 | 241 | |
|---|
| 242 | +/* |
|---|
| 243 | + * The rip of IBS samples has skid 0. Thus, IBS supports precise |
|---|
| 244 | + * levels 1 and 2 and the PERF_EFLAGS_EXACT is set. In rare cases the |
|---|
| 245 | + * rip is invalid when IBS was not able to record the rip correctly. |
|---|
| 246 | + * We clear PERF_EFLAGS_EXACT and take the rip from pt_regs then. |
|---|
| 247 | + */ |
|---|
| 248 | +int forward_event_to_ibs(struct perf_event *event) |
|---|
| 249 | +{ |
|---|
| 250 | + u64 config = 0; |
|---|
| 251 | + |
|---|
| 252 | + if (!event->attr.precise_ip || event->attr.precise_ip > 2) |
|---|
| 253 | + return -EOPNOTSUPP; |
|---|
| 254 | + |
|---|
| 255 | + if (!core_pmu_ibs_config(event, &config)) { |
|---|
| 256 | + event->attr.type = perf_ibs_op.pmu.type; |
|---|
| 257 | + event->attr.config = config; |
|---|
| 258 | + } |
|---|
| 259 | + return -ENOENT; |
|---|
| 260 | +} |
|---|
| 261 | + |
|---|
| 258 | 262 | static int perf_ibs_init(struct perf_event *event) |
|---|
| 259 | 263 | { |
|---|
| 260 | 264 | struct hw_perf_event *hwc = &event->hw; |
|---|
| 261 | 265 | struct perf_ibs *perf_ibs; |
|---|
| 262 | 266 | u64 max_cnt, config; |
|---|
| 263 | | - int ret; |
|---|
| 264 | 267 | |
|---|
| 265 | 268 | perf_ibs = get_ibs_pmu(event->attr.type); |
|---|
| 266 | | - if (perf_ibs) { |
|---|
| 267 | | - config = event->attr.config; |
|---|
| 268 | | - } else { |
|---|
| 269 | | - perf_ibs = &perf_ibs_op; |
|---|
| 270 | | - ret = perf_ibs_precise_event(event, &config); |
|---|
| 271 | | - if (ret) |
|---|
| 272 | | - return ret; |
|---|
| 273 | | - } |
|---|
| 269 | + if (!perf_ibs) |
|---|
| 270 | + return -ENOENT; |
|---|
| 271 | + |
|---|
| 272 | + config = event->attr.config; |
|---|
| 274 | 273 | |
|---|
| 275 | 274 | if (event->pmu != &perf_ibs->pmu) |
|---|
| 276 | 275 | return -ENOENT; |
|---|