perf.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:22k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

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