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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * SN1 Platform specific synergy Support
  3.  *
  4.  * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved.
  5.  * 
  6.  * This program is free software; you can redistribute it and/or modify it 
  7.  * under the terms of version 2 of the GNU General Public License 
  8.  * as published by the Free Software Foundation.
  9.  * 
  10.  * This program is distributed in the hope that it would be useful, but 
  11.  * WITHOUT ANY WARRANTY; without even the implied warranty of 
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
  13.  * 
  14.  * Further, this software is distributed without any warranty that it is 
  15.  * free of the rightful claim of any third person regarding infringement 
  16.  * or the like.  Any license provided herein, whether implied or 
  17.  * otherwise, applies only to this software file.  Patent licenses, if 
  18.  * any, provided herein do not apply to combinations of this program with 
  19.  * other software, or any other product whatsoever.
  20.  * 
  21.  * You should have received a copy of the GNU General Public 
  22.  * License along with this program; if not, write the Free Software 
  23.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
  24.  * 
  25.  * Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, 
  26.  * Mountain View, CA  94043, or:
  27.  * 
  28.  * http://www.sgi.com 
  29.  * 
  30.  * For further information regarding this notice, see: 
  31.  * 
  32.  * http://oss.sgi.com/projects/GenInfo/NoticeExplan
  33.  */
  34. #include <linux/kernel.h>
  35. #include <linux/sched.h>
  36. #include <linux/mm.h>
  37. #include <linux/spinlock.h>
  38. #include <linux/proc_fs.h>
  39. #include <asm/ptrace.h>
  40. #include <linux/devfs_fs_kernel.h>
  41. #include <asm/smp.h>
  42. #include <asm/sn/sn_cpuid.h>
  43. #include <asm/sn/sn1/bedrock.h>
  44. #include <asm/sn/intr.h>
  45. #include <asm/sn/addrs.h>
  46. #include <asm/sn/nodepda.h>
  47. #include <asm/sn/sn1/synergy.h>
  48. #include <asm/sn/sndrv.h>
  49. int bit_pos_to_irq(int bit);
  50. void setclear_mask_b(int irq, int cpuid, int set);
  51. void setclear_mask_a(int irq, int cpuid, int set);
  52. void * kmalloc(size_t size, int flags);
  53. static int synergy_perf_initialized = 0;
  54. void
  55. synergy_intr_alloc(int bit, int cpuid) {
  56. return;
  57. }
  58. int
  59. synergy_intr_connect(int bit, 
  60. int cpuid)
  61. {
  62. int irq;
  63. unsigned is_b;
  64. irq = bit_pos_to_irq(bit);
  65. is_b = (cpuid_to_slice(cpuid)) & 1;
  66. if (is_b) {
  67. setclear_mask_b(irq,cpuid,1);
  68. setclear_mask_a(irq,cpuid, 0);
  69. } else {
  70. setclear_mask_a(irq, cpuid, 1);
  71. setclear_mask_b(irq, cpuid, 0);
  72. }
  73. return 0;
  74. }
  75. void
  76. setclear_mask_a(int irq, int cpuid, int set)
  77. {
  78. int synergy;
  79. int nasid;
  80. int reg_num;
  81. unsigned long mask;
  82. unsigned long addr;
  83. unsigned long reg;
  84. unsigned long val;
  85. int my_cnode, my_synergy;
  86. int target_cnode, target_synergy;
  87.         /*
  88.          * Perform some idiot checks ..
  89.          */
  90.         if ( (irq < 0) || (irq > 255) ||
  91.                 (cpuid < 0) || (cpuid > 512) ) {
  92.                 printk("clear_mask_a: Invalid parameter irq %d cpuid %dn", irq, cpuid);
  93. return;
  94. }
  95. target_cnode = cpuid_to_cnodeid(cpuid);
  96. target_synergy = cpuid_to_synergy(cpuid);
  97. my_cnode = cpuid_to_cnodeid(smp_processor_id());
  98. my_synergy = cpuid_to_synergy(smp_processor_id());
  99. reg_num = irq / 64;
  100. mask = 1;
  101. mask <<= (irq % 64);
  102. switch (reg_num) {
  103. case 0: 
  104. reg = VEC_MASK0A;
  105. addr = VEC_MASK0A_ADDR;
  106. break;
  107. case 1: 
  108. reg = VEC_MASK1A;
  109. addr = VEC_MASK1A_ADDR;
  110. break;
  111. case 2: 
  112. reg = VEC_MASK2A;
  113. addr = VEC_MASK2A_ADDR;
  114. break;
  115. case 3: 
  116. reg = VEC_MASK3A;
  117. addr = VEC_MASK3A_ADDR;
  118. break;
  119. default:
  120. reg = addr = 0;
  121. break;
  122. }
  123. if (my_cnode == target_cnode && my_synergy == target_synergy) {
  124. // local synergy
  125. val = READ_LOCAL_SYNERGY_REG(addr);
  126. if (set) {
  127. val |= mask;
  128. } else {
  129. val &= ~mask;
  130. }
  131. WRITE_LOCAL_SYNERGY_REG(addr, val);
  132. val = READ_LOCAL_SYNERGY_REG(addr);
  133. } else { /* remote synergy */
  134. synergy = cpuid_to_synergy(cpuid);
  135. nasid = cpuid_to_nasid(cpuid);
  136. val = REMOTE_SYNERGY_LOAD(nasid, synergy, reg);
  137. if (set) {
  138. val |= mask;
  139. } else {
  140. val &= ~mask;
  141. }
  142. REMOTE_SYNERGY_STORE(nasid, synergy, reg, val);
  143. }
  144. }
  145. void
  146. setclear_mask_b(int irq, int cpuid, int set)
  147. {
  148. int synergy;
  149. int nasid;
  150. int reg_num;
  151. unsigned long mask;
  152. unsigned long addr;
  153. unsigned long reg;
  154. unsigned long val;
  155. int my_cnode, my_synergy;
  156. int target_cnode, target_synergy;
  157. /*
  158.  * Perform some idiot checks ..
  159.  */
  160. if ( (irq < 0) || (irq > 255) ||
  161. (cpuid < 0) || (cpuid > 512) ) {
  162. printk("clear_mask_b: Invalid parameter irq %d cpuid %dn", irq, cpuid);
  163. return;
  164. }
  165. target_cnode = cpuid_to_cnodeid(cpuid);
  166. target_synergy = cpuid_to_synergy(cpuid);
  167. my_cnode = cpuid_to_cnodeid(smp_processor_id());
  168. my_synergy = cpuid_to_synergy(smp_processor_id());
  169. reg_num = irq / 64;
  170. mask = 1;
  171. mask <<= (irq % 64);
  172. switch (reg_num) {
  173. case 0: 
  174. reg = VEC_MASK0B;
  175. addr = VEC_MASK0B_ADDR;
  176. break;
  177. case 1: 
  178. reg = VEC_MASK1B;
  179. addr = VEC_MASK1B_ADDR;
  180. break;
  181. case 2: 
  182. reg = VEC_MASK2B;
  183. addr = VEC_MASK2B_ADDR;
  184. break;
  185. case 3: 
  186. reg = VEC_MASK3B;
  187. addr = VEC_MASK3B_ADDR;
  188. break;
  189. default:
  190. reg = addr = 0;
  191. break;
  192. }
  193. if (my_cnode == target_cnode && my_synergy == target_synergy) {
  194. // local synergy
  195. val = READ_LOCAL_SYNERGY_REG(addr);
  196. if (set) {
  197. val |= mask;
  198. } else {
  199. val &= ~mask;
  200. }
  201. WRITE_LOCAL_SYNERGY_REG(addr, val);
  202. val = READ_LOCAL_SYNERGY_REG(addr);
  203. } else { /* remote synergy */
  204. synergy = cpuid_to_synergy(cpuid);
  205. nasid = cpuid_to_nasid(cpuid);
  206. val = REMOTE_SYNERGY_LOAD(nasid, synergy, reg);
  207. if (set) {
  208. val |= mask;
  209. } else {
  210. val &= ~mask;
  211. }
  212. REMOTE_SYNERGY_STORE(nasid, synergy, reg, val);
  213. }
  214. }
  215. /*
  216.  * Synergy perf stats. Multiplexed via timer_interrupt.
  217.  */
  218. static int
  219. synergy_perf_append(uint64_t modesel)
  220. {
  221. int cnode;
  222. nodepda_t       *npdap;
  223. synergy_perf_t *p;
  224. int checked = 0;
  225. int err = 0;
  226. /* bit 45 is enable */
  227. modesel |= (1UL << 45);
  228. for (cnode=0; cnode < numnodes; cnode++) {
  229. /* for each node, insert a new synergy_perf entry */
  230. if ((npdap = NODEPDA(cnode)) == NULL) {
  231. printk("synergy_perf_append: cnode=%d NODEPDA(cnode)==NULL, nodepda=%pn", cnode, (void *)nodepda);
  232. continue;
  233. }
  234. if (npdap->synergy_perf_enabled) {
  235. /* user must disable counting to append new events */
  236. err = -EBUSY;
  237. break;
  238. }
  239. if (!checked && npdap->synergy_perf_data != NULL) {
  240. checked = 1;
  241. for (p = npdap->synergy_perf_first; ;) {
  242. if (p->modesel == modesel)
  243. return 0; /* event already registered */
  244. if ((p = p->next) == npdap->synergy_perf_first)
  245. break;
  246. }
  247. }
  248. /* XX use kmem_alloc_node() when it is implemented */
  249. p = (synergy_perf_t *)kmalloc(sizeof(synergy_perf_t), GFP_KERNEL);
  250. if ((((uint64_t)p) & 7UL) != 0)
  251. BUG(); /* bad alignment */
  252. if (p == NULL) {
  253. err = -ENOMEM;
  254. break;
  255. }
  256. else {
  257. memset(p, 0, sizeof(synergy_perf_t));
  258. p->modesel = modesel;
  259. spin_lock_irq(&npdap->synergy_perf_lock);
  260. if (npdap->synergy_perf_data == NULL) {
  261. /* circular list */
  262. p->next = p;
  263. npdap->synergy_perf_first = p;
  264. npdap->synergy_perf_data = p;
  265. }
  266. else {
  267. p->next = npdap->synergy_perf_data->next;
  268. npdap->synergy_perf_data->next = p;
  269. }
  270. spin_unlock_irq(&npdap->synergy_perf_lock);
  271. }
  272. }
  273. return err;
  274. }
  275. static void
  276. synergy_perf_set_freq(int freq)
  277. {
  278. int cnode;
  279. nodepda_t *npdap;
  280. for (cnode=0; cnode < numnodes; cnode++) {
  281. if ((npdap = NODEPDA(cnode)) != NULL)
  282. npdap->synergy_perf_freq = freq;
  283. }
  284. }
  285. static void
  286. synergy_perf_set_enable(int enable)
  287. {
  288. int cnode;
  289. nodepda_t *npdap;
  290. for (cnode=0; cnode < numnodes; cnode++) {
  291. if ((npdap = NODEPDA(cnode)) != NULL)
  292. npdap->synergy_perf_enabled = enable;
  293. }
  294. printk("NOTICE: synergy perf counting %sabled on all nodesn", enable ? "en" : "dis");
  295. }
  296. static int
  297. synergy_perf_size(nodepda_t *npdap)
  298. {
  299. synergy_perf_t *p;
  300. int n;
  301. if (npdap->synergy_perf_enabled == 0) {
  302. /* no stats to return */
  303. return 0;
  304. }
  305. spin_lock_irq(&npdap->synergy_perf_lock);
  306. for (n=0, p = npdap->synergy_perf_first; p;) {
  307. n++;
  308. p = p->next;
  309. if (p == npdap->synergy_perf_first)
  310. break;
  311. }
  312. spin_unlock_irq(&npdap->synergy_perf_lock);
  313. /* bytes == n pairs of {event,counter} */
  314. return n * 2 * sizeof(uint64_t);
  315. }
  316. static int
  317. synergy_perf_ioctl(struct inode *inode, struct file *file,
  318.         unsigned int cmd, unsigned long arg)
  319. {
  320. int             cnode;
  321. nodepda_t       *npdap;
  322. synergy_perf_t *p;
  323. int intarg;
  324. int fsb;
  325. uint64_t longarg;
  326. uint64_t *stats;
  327. int n;
  328. devfs_handle_t d;
  329. arbitrary_info_t info;
  330. if ((d = devfs_get_handle_from_inode(inode)) == NULL)
  331. return -ENODEV;
  332. info = hwgraph_fastinfo_get(d);
  333. cnode = SYNERGY_PERF_INFO_CNODE(info);
  334. fsb = SYNERGY_PERF_INFO_FSB(info);
  335. npdap = NODEPDA(cnode);
  336. switch (cmd) {
  337. case SNDRV_GET_SYNERGY_VERSION:
  338. /* return int, version of data structure for SNDRV_GET_SYNERGYINFO */
  339. intarg = 1; /* version 1 */
  340. if (copy_to_user((void *)arg, &intarg, sizeof(intarg)))
  341.     return -EFAULT;
  342. break;
  343. case SNDRV_GET_INFOSIZE:
  344. /* return int, sizeof buf needed for SYNERGY_PERF_GET_STATS */
  345. intarg = synergy_perf_size(npdap);
  346. if (copy_to_user((void *)arg, &intarg, sizeof(intarg)))
  347.     return -EFAULT;
  348. break;
  349. case SNDRV_GET_SYNERGYINFO:
  350. /* return array of event/value pairs, this node only */
  351. if ((intarg = synergy_perf_size(npdap)) <= 0)
  352. return -ENODATA;
  353. if ((stats = (uint64_t *)kmalloc(intarg, GFP_KERNEL)) == NULL)
  354. return -ENOMEM;
  355. spin_lock_irq(&npdap->synergy_perf_lock);
  356. for (n=0, p = npdap->synergy_perf_first; p;) {
  357. stats[n++] = p->modesel;
  358. if (p->intervals > 0)
  359.     stats[n++] = p->counts[fsb] * p->total_intervals / p->intervals;
  360. else
  361.     stats[n++] = 0;
  362. p = p->next;
  363. if (p == npdap->synergy_perf_first)
  364. break;
  365. }
  366. spin_unlock_irq(&npdap->synergy_perf_lock);
  367. if (copy_to_user((void *)arg, stats, intarg)) {
  368.     kfree(stats);
  369.     return -EFAULT;
  370. }
  371. kfree(stats);
  372. break;
  373. case SNDRV_SYNERGY_APPEND:
  374. /* reads 64bit event, append synergy perf event to all nodes  */
  375. if (copy_from_user(&longarg, (void *)arg, sizeof(longarg)))
  376.     return -EFAULT;
  377. return synergy_perf_append(longarg);
  378. break;
  379. case SNDRV_GET_SYNERGY_STATUS:
  380. /* return int, 1 if enabled else 0 */
  381. intarg = npdap->synergy_perf_enabled;
  382. if (copy_to_user((void *)arg, &intarg, sizeof(intarg)))
  383.     return -EFAULT;
  384. break;
  385. case SNDRV_SYNERGY_ENABLE:
  386. /* read int, if true enable counting else disable */
  387. if (copy_from_user(&intarg, (void *)arg, sizeof(intarg)))
  388.     return -EFAULT;
  389. synergy_perf_set_enable(intarg);
  390. break;
  391. case SNDRV_SYNERGY_FREQ:
  392. /* read int, set jiffies per update */ 
  393. if (copy_from_user(&intarg, (void *)arg, sizeof(intarg)))
  394.     return -EFAULT;
  395. if (intarg < 0 || intarg >= HZ)
  396. return -EINVAL;
  397. synergy_perf_set_freq(intarg);
  398. break;
  399. default:
  400. printk("Warning: invalid ioctl %d on synergy mon for cnode=%d fsb=%dn", cmd, cnode, fsb);
  401. return -EINVAL;
  402. }
  403. return(0);
  404. }
  405. struct file_operations synergy_mon_fops = {
  406.         ioctl: synergy_perf_ioctl,
  407. };
  408. void
  409. synergy_perf_update(int cpu)
  410. {
  411. nasid_t nasid;
  412. cnodeid_t       cnode;
  413. struct nodepda_s *npdap;
  414. /*
  415.  * synergy_perf_initialized is set by synergy_perf_init()
  416.  * which is called last thing by sn_mp_setup(), i.e. well
  417.  * after nodepda has been initialized.
  418.  */
  419. if (!synergy_perf_initialized)
  420. return;
  421. cnode = cpuid_to_cnodeid(cpu);
  422. npdap = NODEPDA(cnode);
  423. if (npdap == NULL || cnode < 0 || cnode >= numnodes)
  424. /* this should not happen: still in early io init */
  425. return;
  426. #if 0
  427. /* use this to check nodepda initialization */
  428. if (((uint64_t)npdap) & 0x7) {
  429. printk("nERROR on cpu %d : cnode=%d, npdap == %p, not alignedn", cpu, cnode, npdap);
  430. BUG();
  431. }
  432. #endif
  433. if (npdap->synergy_perf_enabled == 0 || npdap->synergy_perf_data == NULL) {
  434. /* Not enabled, or no events to monitor */
  435. return;
  436. }
  437. if (npdap->synergy_inactive_intervals++ % npdap->synergy_perf_freq != 0) {
  438. /* don't multiplex on every timer interrupt */
  439. return;
  440. }
  441. /*
  442.  * Read registers for last interval and increment counters.
  443.  * Hold the per-node synergy_perf_lock so concurrent readers get
  444.  * consistent values.
  445.  */
  446. spin_lock_irq(&npdap->synergy_perf_lock);
  447. nasid = cpuid_to_nasid(cpu);
  448. npdap->synergy_active_intervals++;
  449. npdap->synergy_perf_data->intervals++;
  450. npdap->synergy_perf_data->total_intervals = npdap->synergy_active_intervals;
  451. npdap->synergy_perf_data->counts[0] += 0xffffffffffUL &
  452. REMOTE_SYNERGY_LOAD(nasid, 0, PERF_CNTR0_A);
  453. npdap->synergy_perf_data->counts[1] += 0xffffffffffUL &
  454. REMOTE_SYNERGY_LOAD(nasid, 1, PERF_CNTR0_B);
  455. /* skip to next in circular list */
  456. npdap->synergy_perf_data = npdap->synergy_perf_data->next;
  457. spin_unlock_irq(&npdap->synergy_perf_lock);
  458. /* set the counter 0 selection modes for both A and B */
  459. REMOTE_SYNERGY_STORE(nasid, 0, PERF_CNTL0_A, npdap->synergy_perf_data->modesel);
  460. REMOTE_SYNERGY_STORE(nasid, 1, PERF_CNTL0_B, npdap->synergy_perf_data->modesel);
  461. /* and reset the counter registers to zero */
  462. REMOTE_SYNERGY_STORE(nasid, 0, PERF_CNTR0_A, 0UL);
  463. REMOTE_SYNERGY_STORE(nasid, 1, PERF_CNTR0_B, 0UL);
  464. }
  465. void
  466. synergy_perf_init(void)
  467. {
  468. printk("synergy_perf_init(), counting is initially disabledn");
  469. synergy_perf_initialized++;
  470. }