1/* 2 * Parisc performance counters 3 * Copyright (C) 2001 Randolph Chung <tausq@debian.org> 4 * 5 * This code is derived, with permission, from HP/UX sources. 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 as published by 9 * the Free Software Foundation; either version 2, or (at your option) 10 * any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 */ 21 22/* 23 * Edited comment from original sources: 24 * 25 * This driver programs the PCX-U/PCX-W performance counters 26 * on the PA-RISC 2.0 chips. The driver keeps all images now 27 * internally to the kernel to hopefully eliminate the possiblity 28 * of a bad image halting the CPU. Also, there are different 29 * images for the PCX-W and later chips vs the PCX-U chips. 30 * 31 * Only 1 process is allowed to access the driver at any time, 32 * so the only protection that is needed is at open and close. 33 * A variable "perf_enabled" is used to hold the state of the 34 * driver. The spinlock "perf_lock" is used to protect the 35 * modification of the state during open/close operations so 36 * multiple processes don't get into the driver simultaneously. 37 * 38 * This driver accesses the processor directly vs going through 39 * the PDC INTRIGUE calls. This is done to eliminate bugs introduced 40 * in various PDC revisions. The code is much more maintainable 41 * and reliable this way vs having to debug on every version of PDC 42 * on every box. 43 */ 44 45#include <linux/capability.h> 46#include <linux/init.h> 47#include <linux/proc_fs.h> 48#include <linux/miscdevice.h> 49#include <linux/spinlock.h> 50 51#include <asm/uaccess.h> 52#include <asm/perf.h> 53#include <asm/parisc-device.h> 54#include <asm/processor.h> 55#include <asm/runway.h> 56#include <asm/io.h> /* for __raw_read() */ 57 58#include "perf_images.h" 59 60#define MAX_RDR_WORDS 24 61#define PERF_VERSION 2 /* derived from hpux's PI v2 interface */ 62 63/* definition of RDR regs */ 64struct rdr_tbl_ent { 65 uint16_t width; 66 uint8_t num_words; 67 uint8_t write_control; 68}; 69 70static int perf_processor_interface __read_mostly = UNKNOWN_INTF; 71static int perf_enabled __read_mostly; 72static spinlock_t perf_lock; 73struct parisc_device *cpu_device __read_mostly; 74 75/* RDRs to write for PCX-W */ 76static const int perf_rdrs_W[] = 77 { 0, 1, 4, 5, 6, 15, 16, 17, 18, 20, 21, 22, 23, 24, 25, -1 }; 78 79/* RDRs to write for PCX-U */ 80static const int perf_rdrs_U[] = 81 { 0, 1, 4, 5, 6, 7, 16, 17, 18, 20, 21, 22, 23, 24, 25, -1 }; 82 83/* RDR register descriptions for PCX-W */ 84static const struct rdr_tbl_ent perf_rdr_tbl_W[] = { 85 { 19, 1, 8 }, /* RDR 0 */ 86 { 16, 1, 16 }, /* RDR 1 */ 87 { 72, 2, 0 }, /* RDR 2 */ 88 { 81, 2, 0 }, /* RDR 3 */ 89 { 328, 6, 0 }, /* RDR 4 */ 90 { 160, 3, 0 }, /* RDR 5 */ 91 { 336, 6, 0 }, /* RDR 6 */ 92 { 164, 3, 0 }, /* RDR 7 */ 93 { 0, 0, 0 }, /* RDR 8 */ 94 { 35, 1, 0 }, /* RDR 9 */ 95 { 6, 1, 0 }, /* RDR 10 */ 96 { 18, 1, 0 }, /* RDR 11 */ 97 { 13, 1, 0 }, /* RDR 12 */ 98 { 8, 1, 0 }, /* RDR 13 */ 99 { 8, 1, 0 }, /* RDR 14 */ 100 { 8, 1, 0 }, /* RDR 15 */ 101 { 1530, 24, 0 }, /* RDR 16 */ 102 { 16, 1, 0 }, /* RDR 17 */ 103 { 4, 1, 0 }, /* RDR 18 */ 104 { 0, 0, 0 }, /* RDR 19 */ 105 { 152, 3, 24 }, /* RDR 20 */ 106 { 152, 3, 24 }, /* RDR 21 */ 107 { 233, 4, 48 }, /* RDR 22 */ 108 { 233, 4, 48 }, /* RDR 23 */ 109 { 71, 2, 0 }, /* RDR 24 */ 110 { 71, 2, 0 }, /* RDR 25 */ 111 { 11, 1, 0 }, /* RDR 26 */ 112 { 18, 1, 0 }, /* RDR 27 */ 113 { 128, 2, 0 }, /* RDR 28 */ 114 { 0, 0, 0 }, /* RDR 29 */ 115 { 16, 1, 0 }, /* RDR 30 */ 116 { 16, 1, 0 }, /* RDR 31 */ 117}; 118 119/* RDR register descriptions for PCX-U */ 120static const struct rdr_tbl_ent perf_rdr_tbl_U[] = { 121 { 19, 1, 8 }, /* RDR 0 */ 122 { 32, 1, 16 }, /* RDR 1 */ 123 { 20, 1, 0 }, /* RDR 2 */ 124 { 0, 0, 0 }, /* RDR 3 */ 125 { 344, 6, 0 }, /* RDR 4 */ 126 { 176, 3, 0 }, /* RDR 5 */ 127 { 336, 6, 0 }, /* RDR 6 */ 128 { 0, 0, 0 }, /* RDR 7 */ 129 { 0, 0, 0 }, /* RDR 8 */ 130 { 0, 0, 0 }, /* RDR 9 */ 131 { 28, 1, 0 }, /* RDR 10 */ 132 { 33, 1, 0 }, /* RDR 11 */ 133 { 0, 0, 0 }, /* RDR 12 */ 134 { 230, 4, 0 }, /* RDR 13 */ 135 { 32, 1, 0 }, /* RDR 14 */ 136 { 128, 2, 0 }, /* RDR 15 */ 137 { 1494, 24, 0 }, /* RDR 16 */ 138 { 18, 1, 0 }, /* RDR 17 */ 139 { 4, 1, 0 }, /* RDR 18 */ 140 { 0, 0, 0 }, /* RDR 19 */ 141 { 158, 3, 24 }, /* RDR 20 */ 142 { 158, 3, 24 }, /* RDR 21 */ 143 { 194, 4, 48 }, /* RDR 22 */ 144 { 194, 4, 48 }, /* RDR 23 */ 145 { 71, 2, 0 }, /* RDR 24 */ 146 { 71, 2, 0 }, /* RDR 25 */ 147 { 28, 1, 0 }, /* RDR 26 */ 148 { 33, 1, 0 }, /* RDR 27 */ 149 { 88, 2, 0 }, /* RDR 28 */ 150 { 32, 1, 0 }, /* RDR 29 */ 151 { 24, 1, 0 }, /* RDR 30 */ 152 { 16, 1, 0 }, /* RDR 31 */ 153}; 154 155/* 156 * A non-zero write_control in the above tables is a byte offset into 157 * this array. 158 */ 159static const uint64_t perf_bitmasks[] = { 160 0x0000000000000000ul, /* first dbl word must be zero */ 161 0xfdffe00000000000ul, /* RDR0 bitmask */ 162 0x003f000000000000ul, /* RDR1 bitmask */ 163 0x00fffffffffffffful, /* RDR20-RDR21 bitmask (152 bits) */ 164 0xfffffffffffffffful, 165 0xfffffffc00000000ul, 166 0xfffffffffffffffful, /* RDR22-RDR23 bitmask (233 bits) */ 167 0xfffffffffffffffful, 168 0xfffffffffffffffcul, 169 0xff00000000000000ul 170}; 171 172/* 173 * Write control bitmasks for Pa-8700 processor given 174 * some things have changed slightly. 175 */ 176static const uint64_t perf_bitmasks_piranha[] = { 177 0x0000000000000000ul, /* first dbl word must be zero */ 178 0xfdffe00000000000ul, /* RDR0 bitmask */ 179 0x003f000000000000ul, /* RDR1 bitmask */ 180 0x00fffffffffffffful, /* RDR20-RDR21 bitmask (158 bits) */ 181 0xfffffffffffffffful, 182 0xfffffffc00000000ul, 183 0xfffffffffffffffful, /* RDR22-RDR23 bitmask (210 bits) */ 184 0xfffffffffffffffful, 185 0xfffffffffffffffful, 186 0xfffc000000000000ul 187}; 188 189static const uint64_t *bitmask_array; /* array of bitmasks to use */ 190 191/****************************************************************************** 192 * Function Prototypes 193 *****************************************************************************/ 194static int perf_config(uint32_t *image_ptr); 195static int perf_release(struct inode *inode, struct file *file); 196static int perf_open(struct inode *inode, struct file *file); 197static ssize_t perf_read(struct file *file, char __user *buf, size_t cnt, loff_t *ppos); 198static ssize_t perf_write(struct file *file, const char __user *buf, size_t count, 199 loff_t *ppos); 200static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg); 201static void perf_start_counters(void); 202static int perf_stop_counters(uint32_t *raddr); 203static const struct rdr_tbl_ent * perf_rdr_get_entry(uint32_t rdr_num); 204static int perf_rdr_read_ubuf(uint32_t rdr_num, uint64_t *buffer); 205static int perf_rdr_clear(uint32_t rdr_num); 206static int perf_write_image(uint64_t *memaddr); 207static void perf_rdr_write(uint32_t rdr_num, uint64_t *buffer); 208 209/* External Assembly Routines */ 210extern uint64_t perf_rdr_shift_in_W (uint32_t rdr_num, uint16_t width); 211extern uint64_t perf_rdr_shift_in_U (uint32_t rdr_num, uint16_t width); 212extern void perf_rdr_shift_out_W (uint32_t rdr_num, uint64_t buffer); 213extern void perf_rdr_shift_out_U (uint32_t rdr_num, uint64_t buffer); 214extern void perf_intrigue_enable_perf_counters (void); 215extern void perf_intrigue_disable_perf_counters (void); 216 217/****************************************************************************** 218 * Function Definitions 219 *****************************************************************************/ 220 221 222/* 223 * configure: 224 * 225 * Configure the cpu with a given data image. First turn off the counters, 226 * then download the image, then turn the counters back on. 227 */ 228static int perf_config(uint32_t *image_ptr) 229{ 230 long error; 231 uint32_t raddr[4]; 232 233 /* Stop the counters*/ 234 error = perf_stop_counters(raddr); 235 if (error != 0) { 236 printk("perf_config: perf_stop_counters = %ld\n", error); 237 return -EINVAL; 238 } 239 240printk("Preparing to write image\n"); 241 /* Write the image to the chip */ 242 error = perf_write_image((uint64_t *)image_ptr); 243 if (error != 0) { 244 printk("perf_config: DOWNLOAD = %ld\n", error); 245 return -EINVAL; 246 } 247 248printk("Preparing to start counters\n"); 249 250 /* Start the counters */ 251 perf_start_counters(); 252 253 return sizeof(uint32_t); 254} 255 256/* 257 * Open the device and initialize all of its memory. The device is only 258 * opened once, but can be "queried" by multiple processes that know its 259 * file descriptor. 260 */ 261static int perf_open(struct inode *inode, struct file *file) 262{ 263 spin_lock(&perf_lock); 264 if (perf_enabled) { 265 spin_unlock(&perf_lock); 266 return -EBUSY; 267 } 268 perf_enabled = 1; 269 spin_unlock(&perf_lock); 270 271 return 0; 272} 273 274/* 275 * Close the device. 276 */ 277static int perf_release(struct inode *inode, struct file *file) 278{ 279 spin_lock(&perf_lock); 280 perf_enabled = 0; 281 spin_unlock(&perf_lock); 282 283 return 0; 284} 285 286/* 287 * Read does nothing for this driver 288 */ 289static ssize_t perf_read(struct file *file, char __user *buf, size_t cnt, loff_t *ppos) 290{ 291 return 0; 292} 293 294/* 295 * write: 296 * 297 * This routine downloads the image to the chip. It must be 298 * called on the processor that the download should happen 299 * on. 300 */ 301static ssize_t perf_write(struct file *file, const char __user *buf, size_t count, 302 loff_t *ppos) 303{ 304 int err; 305 size_t image_size; 306 uint32_t image_type; 307 uint32_t interface_type; 308 uint32_t test; 309 310 if (perf_processor_interface == ONYX_INTF) 311 image_size = PCXU_IMAGE_SIZE; 312 else if (perf_processor_interface == CUDA_INTF) 313 image_size = PCXW_IMAGE_SIZE; 314 else 315 return -EFAULT; 316 317 if (!capable(CAP_SYS_ADMIN)) 318 return -EACCES; 319 320 if (count != sizeof(uint32_t)) 321 return -EIO; 322 323 if ((err = copy_from_user(&image_type, buf, sizeof(uint32_t))) != 0) 324 return err; 325 326 /* Get the interface type and test type */ 327 interface_type = (image_type >> 16) & 0xffff; 328 test = (image_type & 0xffff); 329 330 /* Make sure everything makes sense */ 331 332 /* First check the machine type is correct for 333 the requested image */ 334 if (((perf_processor_interface == CUDA_INTF) && 335 (interface_type != CUDA_INTF)) || 336 ((perf_processor_interface == ONYX_INTF) && 337 (interface_type != ONYX_INTF))) 338 return -EINVAL; 339 340 /* Next check to make sure the requested image 341 is valid */ 342 if (((interface_type == CUDA_INTF) && 343 (test >= MAX_CUDA_IMAGES)) || 344 ((interface_type == ONYX_INTF) && 345 (test >= MAX_ONYX_IMAGES))) 346 return -EINVAL; 347 348 /* Copy the image into the processor */ 349 if (interface_type == CUDA_INTF) 350 return perf_config(cuda_images[test]); 351 else 352 return perf_config(onyx_images[test]); 353 354 return count; 355} 356 357/* 358 * Patch the images that need to know the IVA addresses. 359 */ 360static void perf_patch_images(void) 361{ 362} 363 364 365/* 366 * ioctl routine 367 * All routines effect the processor that they are executed on. Thus you 368 * must be running on the processor that you wish to change. 369 */ 370 371static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 372{ 373 long error_start; 374 uint32_t raddr[4]; 375 int error = 0; 376 377 switch (cmd) { 378 379 case PA_PERF_ON: 380 /* Start the counters */ 381 perf_start_counters(); 382 break; 383 384 case PA_PERF_OFF: 385 error_start = perf_stop_counters(raddr); 386 if (error_start != 0) { 387 printk(KERN_ERR "perf_off: perf_stop_counters = %ld\n", error_start); 388 error = -EFAULT; 389 break; 390 } 391 392 /* copy out the Counters */ 393 if (copy_to_user((void __user *)arg, raddr, 394 sizeof (raddr)) != 0) { 395 error = -EFAULT; 396 break; 397 } 398 break; 399 400 case PA_PERF_VERSION: 401 /* Return the version # */ 402 error = put_user(PERF_VERSION, (int *)arg); 403 break; 404 405 default: 406 error = -ENOTTY; 407 } 408 409 return error; 410} 411 412static const struct file_operations perf_fops = { 413 .llseek = no_llseek, 414 .read = perf_read, 415 .write = perf_write, 416 .unlocked_ioctl = perf_ioctl, 417 .compat_ioctl = perf_ioctl, 418 .open = perf_open, 419 .release = perf_release 420}; 421 422static struct miscdevice perf_dev = { 423 MISC_DYNAMIC_MINOR, 424 PA_PERF_DEV, 425 &perf_fops 426}; 427 428/* 429 * Initialize the module 430 */ 431static int __init perf_init(void) 432{ 433 int ret; 434 435 /* Determine correct processor interface to use */ 436 bitmask_array = perf_bitmasks; 437 438 if (boot_cpu_data.cpu_type == pcxu || 439 boot_cpu_data.cpu_type == pcxu_) { 440 perf_processor_interface = ONYX_INTF; 441 } else if (boot_cpu_data.cpu_type == pcxw || 442 boot_cpu_data.cpu_type == pcxw_ || 443 boot_cpu_data.cpu_type == pcxw2 || 444 boot_cpu_data.cpu_type == mako || 445 boot_cpu_data.cpu_type == mako2) { 446 perf_processor_interface = CUDA_INTF; 447 if (boot_cpu_data.cpu_type == pcxw2 || 448 boot_cpu_data.cpu_type == mako || 449 boot_cpu_data.cpu_type == mako2) 450 bitmask_array = perf_bitmasks_piranha; 451 } else { 452 perf_processor_interface = UNKNOWN_INTF; 453 printk("Performance monitoring counters not supported on this processor\n"); 454 return -ENODEV; 455 } 456 457 ret = misc_register(&perf_dev); 458 if (ret) { 459 printk(KERN_ERR "Performance monitoring counters: " 460 "cannot register misc device.\n"); 461 return ret; 462 } 463 464 /* Patch the images to match the system */ 465 perf_patch_images(); 466 467 spin_lock_init(&perf_lock); 468 469 /* TODO: this only lets us access the first cpu.. what to do for SMP? */ 470 cpu_device = cpu_data[0].dev; 471 printk("Performance monitoring counters enabled for %s\n", 472 cpu_data[0].dev->name); 473 474 return 0; 475} 476 477/* 478 * perf_start_counters(void) 479 * 480 * Start the counters. 481 */ 482static void perf_start_counters(void) 483{ 484 /* Enable performance monitor counters */ 485 perf_intrigue_enable_perf_counters(); 486} 487 488/* 489 * perf_stop_counters 490 * 491 * Stop the performance counters and save counts 492 * in a per_processor array. 493 */ 494static int perf_stop_counters(uint32_t *raddr) 495{ 496 uint64_t userbuf[MAX_RDR_WORDS]; 497 498 /* Disable performance counters */ 499 perf_intrigue_disable_perf_counters(); 500 501 if (perf_processor_interface == ONYX_INTF) { 502 uint64_t tmp64; 503 /* 504 * Read the counters 505 */ 506 if (!perf_rdr_read_ubuf(16, userbuf)) 507 return -13; 508 509 /* Counter0 is bits 1398 to 1429 */ 510 tmp64 = (userbuf[21] << 22) & 0x00000000ffc00000; 511 tmp64 |= (userbuf[22] >> 42) & 0x00000000003fffff; 512 /* OR sticky0 (bit 1430) to counter0 bit 32 */ 513 tmp64 |= (userbuf[22] >> 10) & 0x0000000080000000; 514 raddr[0] = (uint32_t)tmp64; 515 516 /* Counter1 is bits 1431 to 1462 */ 517 tmp64 = (userbuf[22] >> 9) & 0x00000000ffffffff; 518 /* OR sticky1 (bit 1463) to counter1 bit 32 */ 519 tmp64 |= (userbuf[22] << 23) & 0x0000000080000000; 520 raddr[1] = (uint32_t)tmp64; 521 522 /* Counter2 is bits 1464 to 1495 */ 523 tmp64 = (userbuf[22] << 24) & 0x00000000ff000000; 524 tmp64 |= (userbuf[23] >> 40) & 0x0000000000ffffff; 525 /* OR sticky2 (bit 1496) to counter2 bit 32 */ 526 tmp64 |= (userbuf[23] >> 8) & 0x0000000080000000; 527 raddr[2] = (uint32_t)tmp64; 528 529 /* Counter3 is bits 1497 to 1528 */ 530 tmp64 = (userbuf[23] >> 7) & 0x00000000ffffffff; 531 /* OR sticky3 (bit 1529) to counter3 bit 32 */ 532 tmp64 |= (userbuf[23] << 25) & 0x0000000080000000; 533 raddr[3] = (uint32_t)tmp64; 534 535 /* 536 * Zero out the counters 537 */ 538 539 /* 540 * The counters and sticky-bits comprise the last 132 bits 541 * (1398 - 1529) of RDR16 on a U chip. We'll zero these 542 * out the easy way: zero out last 10 bits of dword 21, 543 * all of dword 22 and 58 bits (plus 6 don't care bits) of 544 * dword 23. 545 */ 546 userbuf[21] &= 0xfffffffffffffc00ul; /* 0 to last 10 bits */ 547 userbuf[22] = 0; 548 userbuf[23] = 0; 549 550 /* 551 * Write back the zeroed bytes + the image given 552 * the read was destructive. 553 */ 554 perf_rdr_write(16, userbuf); 555 } else { 556 557 /* 558 * Read RDR-15 which contains the counters and sticky bits 559 */ 560 if (!perf_rdr_read_ubuf(15, userbuf)) { 561 return -13; 562 } 563 564 /* 565 * Clear out the counters 566 */ 567 perf_rdr_clear(15); 568 569 /* 570 * Copy the counters 571 */ 572 raddr[0] = (uint32_t)((userbuf[0] >> 32) & 0x00000000ffffffffUL); 573 raddr[1] = (uint32_t)(userbuf[0] & 0x00000000ffffffffUL); 574 raddr[2] = (uint32_t)((userbuf[1] >> 32) & 0x00000000ffffffffUL); 575 raddr[3] = (uint32_t)(userbuf[1] & 0x00000000ffffffffUL); 576 } 577 578 return 0; 579} 580 581/* 582 * perf_rdr_get_entry 583 * 584 * Retrieve a pointer to the description of what this 585 * RDR contains. 586 */ 587static const struct rdr_tbl_ent * perf_rdr_get_entry(uint32_t rdr_num) 588{ 589 if (perf_processor_interface == ONYX_INTF) { 590 return &perf_rdr_tbl_U[rdr_num]; 591 } else { 592 return &perf_rdr_tbl_W[rdr_num]; 593 } 594} 595 596/* 597 * perf_rdr_read_ubuf 598 * 599 * Read the RDR value into the buffer specified. 600 */ 601static int perf_rdr_read_ubuf(uint32_t rdr_num, uint64_t *buffer) 602{ 603 uint64_t data, data_mask = 0; 604 uint32_t width, xbits, i; 605 const struct rdr_tbl_ent *tentry; 606 607 tentry = perf_rdr_get_entry(rdr_num); 608 if ((width = tentry->width) == 0) 609 return 0; 610 611 /* Clear out buffer */ 612 i = tentry->num_words; 613 while (i--) { 614 buffer[i] = 0; 615 } 616 617 /* Check for bits an even number of 64 */ 618 if ((xbits = width & 0x03f) != 0) { 619 data_mask = 1; 620 data_mask <<= (64 - xbits); 621 data_mask--; 622 } 623 624 /* Grab all of the data */ 625 i = tentry->num_words; 626 while (i--) { 627 628 if (perf_processor_interface == ONYX_INTF) { 629 data = perf_rdr_shift_in_U(rdr_num, width); 630 } else { 631 data = perf_rdr_shift_in_W(rdr_num, width); 632 } 633 if (xbits) { 634 buffer[i] |= (data << (64 - xbits)); 635 if (i) { 636 buffer[i-1] |= ((data >> xbits) & data_mask); 637 } 638 } else { 639 buffer[i] = data; 640 } 641 } 642 643 return 1; 644} 645 646/* 647 * perf_rdr_clear 648 * 649 * Zero out the given RDR register 650 */ 651static int perf_rdr_clear(uint32_t rdr_num) 652{ 653 const struct rdr_tbl_ent *tentry; 654 int32_t i; 655 656 tentry = perf_rdr_get_entry(rdr_num); 657 658 if (tentry->width == 0) { 659 return -1; 660 } 661 662 i = tentry->num_words; 663 while (i--) { 664 if (perf_processor_interface == ONYX_INTF) { 665 perf_rdr_shift_out_U(rdr_num, 0UL); 666 } else { 667 perf_rdr_shift_out_W(rdr_num, 0UL); 668 } 669 } 670 671 return 0; 672} 673 674 675/* 676 * perf_write_image 677 * 678 * Write the given image out to the processor 679 */ 680static int perf_write_image(uint64_t *memaddr) 681{ 682 uint64_t buffer[MAX_RDR_WORDS]; 683 uint64_t *bptr; 684 uint32_t dwords; 685 const uint32_t *intrigue_rdr; 686 const uint64_t *intrigue_bitmask; 687 uint64_t tmp64; 688 void __iomem *runway; 689 const struct rdr_tbl_ent *tentry; 690 int i; 691 692 /* Clear out counters */ 693 if (perf_processor_interface == ONYX_INTF) { 694 695 perf_rdr_clear(16); 696 697 /* Toggle performance monitor */ 698 perf_intrigue_enable_perf_counters(); 699 perf_intrigue_disable_perf_counters(); 700 701 intrigue_rdr = perf_rdrs_U; 702 } else { 703 perf_rdr_clear(15); 704 intrigue_rdr = perf_rdrs_W; 705 } 706 707 /* Write all RDRs */ 708 while (*intrigue_rdr != -1) { 709 tentry = perf_rdr_get_entry(*intrigue_rdr); 710 perf_rdr_read_ubuf(*intrigue_rdr, buffer); 711 bptr = &buffer[0]; 712 dwords = tentry->num_words; 713 if (tentry->write_control) { 714 intrigue_bitmask = &bitmask_array[tentry->write_control >> 3]; 715 while (dwords--) { 716 tmp64 = *intrigue_bitmask & *memaddr++; 717 tmp64 |= (~(*intrigue_bitmask++)) & *bptr; 718 *bptr++ = tmp64; 719 } 720 } else { 721 while (dwords--) { 722 *bptr++ = *memaddr++; 723 } 724 } 725 726 perf_rdr_write(*intrigue_rdr, buffer); 727 intrigue_rdr++; 728 } 729 730 /* 731 * Now copy out the Runway stuff which is not in RDRs 732 */ 733 734 if (cpu_device == NULL) 735 { 736 printk(KERN_ERR "write_image: cpu_device not yet initialized!\n"); 737 return -1; 738 } 739 740 runway = ioremap_nocache(cpu_device->hpa.start, 4096); 741 742 /* Merge intrigue bits into Runway STATUS 0 */ 743 tmp64 = __raw_readq(runway + RUNWAY_STATUS) & 0xffecfffffffffffful; 744 __raw_writeq(tmp64 | (*memaddr++ & 0x0013000000000000ul), 745 runway + RUNWAY_STATUS); 746 747 /* Write RUNWAY DEBUG registers */ 748 for (i = 0; i < 8; i++) { 749 __raw_writeq(*memaddr++, runway + RUNWAY_DEBUG); 750 } 751 752 return 0; 753} 754 755/* 756 * perf_rdr_write 757 * 758 * Write the given RDR register with the contents 759 * of the given buffer. 760 */ 761static void perf_rdr_write(uint32_t rdr_num, uint64_t *buffer) 762{ 763 const struct rdr_tbl_ent *tentry; 764 int32_t i; 765 766printk("perf_rdr_write\n"); 767 tentry = perf_rdr_get_entry(rdr_num); 768 if (tentry->width == 0) { return; } 769 770 i = tentry->num_words; 771 while (i--) { 772 if (perf_processor_interface == ONYX_INTF) { 773 perf_rdr_shift_out_U(rdr_num, buffer[i]); 774 } else { 775 perf_rdr_shift_out_W(rdr_num, buffer[i]); 776 } 777 } 778printk("perf_rdr_write done\n"); 779} 780 781module_init(perf_init); 782