synergy.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:10k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * SN1 Platform specific synergy Support
  3.  *
  4.  * Copyright (C) 2000 Silicon Graphics, Inc.
  5.  * Copyright (C) 2000 Alan Mayer (ajm@sgi.com)
  6.  */
  7. #include <linux/config.h>
  8. #include <linux/kernel.h>
  9. #include <linux/sched.h>
  10. #include <linux/mm.h>
  11. #include <linux/spinlock.h>
  12. #include <linux/proc_fs.h>
  13. #include <asm/ptrace.h>
  14. #include <linux/devfs_fs_kernel.h>
  15. #include <asm/smp.h>
  16. #include <asm/sn/sn_cpuid.h>
  17. #include <asm/sn/sn1/bedrock.h>
  18. #include <asm/sn/intr.h>
  19. #include <asm/sn/addrs.h>
  20. #include <asm/sn/synergy.h>
  21. int bit_pos_to_irq(int bit);
  22. void setclear_mask_b(int irq, int cpuid, int set);
  23. void setclear_mask_a(int irq, int cpuid, int set);
  24. void * kmalloc(size_t size, int flags);
  25. void
  26. synergy_intr_alloc(int bit, int cpuid) {
  27. return;
  28. }
  29. int
  30. synergy_intr_connect(int bit, 
  31. int cpuid)
  32. {
  33. int irq;
  34. unsigned is_b;
  35. irq = bit_pos_to_irq(bit);
  36. is_b = (cpuid_to_slice(cpuid)) & 1;
  37. if (is_b) {
  38. setclear_mask_b(irq,cpuid,1);
  39. setclear_mask_a(irq,cpuid, 0);
  40. } else {
  41. setclear_mask_a(irq, cpuid, 1);
  42. setclear_mask_b(irq, cpuid, 0);
  43. }
  44. return 0;
  45. }
  46. void
  47. setclear_mask_a(int irq, int cpuid, int set)
  48. {
  49. int synergy;
  50. int nasid;
  51. int reg_num;
  52. unsigned long mask;
  53. unsigned long addr;
  54. unsigned long reg;
  55. unsigned long val;
  56. int my_cnode, my_synergy;
  57. int target_cnode, target_synergy;
  58.         /*
  59.          * Perform some idiot checks ..
  60.          */
  61.         if ( (irq < 0) || (irq > 255) ||
  62.                 (cpuid < 0) || (cpuid > 512) ) {
  63.                 printk("clear_mask_a: Invalid parameter irq %d cpuid %dn", irq, cpuid);
  64. return;
  65. }
  66. target_cnode = cpuid_to_cnodeid(cpuid);
  67. target_synergy = cpuid_to_synergy(cpuid);
  68. my_cnode = cpuid_to_cnodeid(smp_processor_id());
  69. my_synergy = cpuid_to_synergy(smp_processor_id());
  70. reg_num = irq / 64;
  71. mask = 1;
  72. mask <<= (irq % 64);
  73. switch (reg_num) {
  74. case 0: 
  75. reg = VEC_MASK0A;
  76. addr = VEC_MASK0A_ADDR;
  77. break;
  78. case 1: 
  79. reg = VEC_MASK1A;
  80. addr = VEC_MASK1A_ADDR;
  81. break;
  82. case 2: 
  83. reg = VEC_MASK2A;
  84. addr = VEC_MASK2A_ADDR;
  85. break;
  86. case 3: 
  87. reg = VEC_MASK3A;
  88. addr = VEC_MASK3A_ADDR;
  89. break;
  90. default:
  91. reg = addr = 0;
  92. break;
  93. }
  94. if (my_cnode == target_cnode && my_synergy == target_synergy) {
  95. // local synergy
  96. val = READ_LOCAL_SYNERGY_REG(addr);
  97. if (set) {
  98. val |= mask;
  99. } else {
  100. val &= ~mask;
  101. }
  102. WRITE_LOCAL_SYNERGY_REG(addr, val);
  103. val = READ_LOCAL_SYNERGY_REG(addr);
  104. } else { /* remote synergy */
  105. synergy = cpuid_to_synergy(cpuid);
  106. nasid = cpuid_to_nasid(cpuid);
  107. val = REMOTE_SYNERGY_LOAD(nasid, synergy, reg);
  108. if (set) {
  109. val |= mask;
  110. } else {
  111. val &= ~mask;
  112. }
  113. REMOTE_SYNERGY_STORE(nasid, synergy, reg, val);
  114. }
  115. }
  116. void
  117. setclear_mask_b(int irq, int cpuid, int set)
  118. {
  119. int synergy;
  120. int nasid;
  121. int reg_num;
  122. unsigned long mask;
  123. unsigned long addr;
  124. unsigned long reg;
  125. unsigned long val;
  126. int my_cnode, my_synergy;
  127. int target_cnode, target_synergy;
  128. /*
  129.  * Perform some idiot checks ..
  130.  */
  131. if ( (irq < 0) || (irq > 255) ||
  132. (cpuid < 0) || (cpuid > 512) ) {
  133. printk("clear_mask_b: Invalid parameter irq %d cpuid %dn", irq, cpuid);
  134. return;
  135. }
  136. target_cnode = cpuid_to_cnodeid(cpuid);
  137. target_synergy = cpuid_to_synergy(cpuid);
  138. my_cnode = cpuid_to_cnodeid(smp_processor_id());
  139. my_synergy = cpuid_to_synergy(smp_processor_id());
  140. reg_num = irq / 64;
  141. mask = 1;
  142. mask <<= (irq % 64);
  143. switch (reg_num) {
  144. case 0: 
  145. reg = VEC_MASK0B;
  146. addr = VEC_MASK0B_ADDR;
  147. break;
  148. case 1: 
  149. reg = VEC_MASK1B;
  150. addr = VEC_MASK1B_ADDR;
  151. break;
  152. case 2: 
  153. reg = VEC_MASK2B;
  154. addr = VEC_MASK2B_ADDR;
  155. break;
  156. case 3: 
  157. reg = VEC_MASK3B;
  158. addr = VEC_MASK3B_ADDR;
  159. break;
  160. default:
  161. reg = addr = 0;
  162. break;
  163. }
  164. if (my_cnode == target_cnode && my_synergy == target_synergy) {
  165. // local synergy
  166. val = READ_LOCAL_SYNERGY_REG(addr);
  167. if (set) {
  168. val |= mask;
  169. } else {
  170. val &= ~mask;
  171. }
  172. WRITE_LOCAL_SYNERGY_REG(addr, val);
  173. val = READ_LOCAL_SYNERGY_REG(addr);
  174. } else { /* remote synergy */
  175. synergy = cpuid_to_synergy(cpuid);
  176. nasid = cpuid_to_nasid(cpuid);
  177. val = REMOTE_SYNERGY_LOAD(nasid, synergy, reg);
  178. if (set) {
  179. val |= mask;
  180. } else {
  181. val &= ~mask;
  182. }
  183. REMOTE_SYNERGY_STORE(nasid, synergy, reg, val);
  184. }
  185. }
  186. #if defined(CONFIG_IA64_SGI_SYNERGY_PERF)
  187. /*
  188.  * Synergy perf registers. Multiplexed via timer_interrupt
  189.  */
  190. static struct proc_dir_entry *synergy_perf_proc = NULL;
  191. /*
  192.  * read handler for /proc/synergy
  193.  */
  194. static int
  195. synergy_perf_read_proc (char *page, char **start, off_t off,
  196.                                  int count, int *eof, void *data)
  197. {
  198. cnodeid_t       cnode;
  199. nodepda_t       *npdap;
  200. synergy_perf_t *p;
  201. int len = 0;
  202. len += sprintf(page+len, "# cnode module slot event synergy-A synergy-Bn");
  203. /* walk the event list for each node */
  204. for (cnode=0; cnode < numnodes; cnode++) {
  205. npdap = NODEPDA(cnode);
  206. if (npdap->synergy_perf_enabled == 0) {
  207. len += sprintf(page+len, "# DISABLEDn");
  208. break;
  209. }
  210. spin_lock_irq(&npdap->synergy_perf_lock);
  211. for (p = npdap->synergy_perf_first; p;) {
  212. uint64_t cnt_a=0, cnt_b=0;
  213. if (p->intervals > 0) {
  214. cnt_a = p->counts[0] * npdap->synergy_active_intervals / p->intervals;
  215. cnt_b = p->counts[1] * npdap->synergy_active_intervals / p->intervals;
  216. }
  217. len += sprintf(page+len, "%d %d %d %12lx %lu %lun",
  218. (int)cnode, (int)npdap->module_id, (int)npdap->slotdesc,
  219. p->modesel, cnt_a, cnt_b);
  220. p = p->next;
  221. if (p == npdap->synergy_perf_first)
  222. break;
  223. }
  224. spin_unlock_irq(&npdap->synergy_perf_lock);
  225. }
  226. if (len <= off+count) *eof = 1;
  227. *start = page + off;
  228. len -= off;
  229. if (len>count) len = count;
  230. if (len<0) len = 0;
  231. return len;
  232. }
  233. static int
  234. synergy_perf_append(uint64_t modesel)
  235. {
  236. int cnode;
  237. nodepda_t       *npdap;
  238. synergy_perf_t *p;
  239. int err = 0;
  240. /* bit 45 is enable */
  241. modesel |= (1UL << 45);
  242. for (cnode=0; cnode < numnodes; cnode++) {
  243. /* for each node, insert a new synergy_perf entry */
  244. if ((npdap = NODEPDA(cnode)) == NULL) {
  245. printk("synergy_perf_append: cnode=%d NODEPDA(cnode)==NULL, nodepda=%pn", cnode, nodepda);
  246. continue;
  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 (p == NULL)
  251. err = -ENOMEM;
  252. else {
  253. memset(p, 0, sizeof(synergy_perf_t));
  254. p->modesel = modesel;
  255. if (npdap->synergy_perf_data == NULL) {
  256. /* circular list */
  257. p->next = p;
  258. npdap->synergy_perf_data = p;
  259. npdap->synergy_perf_first = p;
  260. }
  261. else {
  262. /*
  263.  * Jumble up the insertion order so we get better sampling.
  264.  * Once the list is complete, "first" stays the same so the
  265.  * reporting order is consistent.
  266.  */
  267. p->next = npdap->synergy_perf_first->next;
  268. npdap->synergy_perf_first->next = p;
  269. npdap->synergy_perf_first = p->next;
  270. }
  271. }
  272. }
  273. return err;
  274. }
  275. static int
  276. synergy_perf_write_proc (struct file *file, const char *buffer,
  277.                                 unsigned long count, void *data)
  278. {
  279. int cnode;
  280. nodepda_t       *npdap;
  281. uint64_t modesel;
  282. char cmd[64];
  283. extern long atoi(char *);
  284.     
  285. if (count == sizeof(uint64_t)) {
  286.     if (copy_from_user(&modesel, buffer, sizeof(uint64_t)))
  287.     return -EFAULT;
  288.     synergy_perf_append(modesel);
  289. }
  290. else {
  291.     if (copy_from_user(cmd, buffer, count < sizeof(cmd) ? count : sizeof(cmd)))
  292.     return -EFAULT;
  293.     if (strncmp(cmd, "enable", 6) == 0) {
  294. /* enable counting */
  295. for (cnode=0; cnode < numnodes; cnode++) {
  296. npdap = NODEPDA(cnode);
  297. npdap->synergy_perf_enabled = 1;
  298. }
  299. printk("NOTICE: synergy perf counting enabledn");
  300.     }
  301.     else
  302.     if (strncmp(cmd, "disable", 7) == 0) {
  303. /* disable counting */
  304. for (cnode=0; cnode < numnodes; cnode++) {
  305. npdap = NODEPDA(cnode);
  306. npdap->synergy_perf_enabled = 0;
  307. }
  308. printk("NOTICE: synergy perf counting disabledn");
  309.     }
  310.     else
  311.     if (strncmp(cmd, "frequency", 9) == 0) {
  312. /* set the update frequency (timer-interrupts per update) */
  313. int freq;
  314. if (count < 12)
  315. return -EINVAL;
  316. freq = atoi(cmd + 10);
  317. if (freq <= 0 || freq > 100)
  318. return -EINVAL;
  319. for (cnode=0; cnode < numnodes; cnode++) {
  320. npdap = NODEPDA(cnode);
  321. npdap->synergy_perf_freq = (uint64_t)freq;
  322. }
  323. printk("NOTICE: synergy perf freq set to %dn", freq);
  324.     }
  325.     else
  326. return -EINVAL;
  327. }
  328. return count;
  329. }
  330. void
  331. synergy_perf_update(int cpu)
  332. {
  333. nasid_t nasid;
  334. cnodeid_t       cnode = cpuid_to_cnodeid(cpu);
  335. struct nodepda_s *npdap;
  336. extern struct nodepda_s *nodepda;
  337. if (nodepda == NULL || (npdap=NODEPDA(cnode)) == NULL || npdap->synergy_perf_enabled == 0 ||
  338. npdap->synergy_perf_data == NULL) {
  339. /* I/O not initialized, or not enabled, or no events to monitor */
  340. return;
  341. }
  342. if (npdap->synergy_inactive_intervals++ % npdap->synergy_perf_freq != 0) {
  343. /* don't multiplex on every timer interrupt */
  344. return;
  345. }
  346. /*
  347.  * Read registers for last interval and increment counters.
  348.  * Hold the per-node synergy_perf_lock so concurrent readers get
  349.  * consistent values.
  350.  */
  351. spin_lock_irq(&npdap->synergy_perf_lock);
  352. nasid = cpuid_to_nasid(cpu);
  353. npdap->synergy_active_intervals++;
  354. npdap->synergy_perf_data->intervals++;
  355. npdap->synergy_perf_data->counts[0] += 0xffffffffffUL &
  356. REMOTE_SYNERGY_LOAD(nasid, 0, PERF_CNTR0_A);
  357. npdap->synergy_perf_data->counts[1] += 0xffffffffffUL &
  358. REMOTE_SYNERGY_LOAD(nasid, 1, PERF_CNTR0_B);
  359. /* skip to next in circular list */
  360. npdap->synergy_perf_data = npdap->synergy_perf_data->next;
  361. spin_unlock_irq(&npdap->synergy_perf_lock);
  362. /* set the counter 0 selection modes for both A and B */
  363. REMOTE_SYNERGY_STORE(nasid, 0, PERF_CNTL0_A, npdap->synergy_perf_data->modesel);
  364. REMOTE_SYNERGY_STORE(nasid, 1, PERF_CNTL0_B, npdap->synergy_perf_data->modesel);
  365. /* and reset the counter registers to zero */
  366. REMOTE_SYNERGY_STORE(nasid, 0, PERF_CNTR0_A, 0UL);
  367. REMOTE_SYNERGY_STORE(nasid, 1, PERF_CNTR0_B, 0UL);
  368. }
  369. void
  370. synergy_perf_init(void)
  371. {
  372.         if ((synergy_perf_proc = create_proc_entry("synergy", 0644, NULL)) != NULL) {
  373.                 synergy_perf_proc->read_proc = synergy_perf_read_proc;
  374.                 synergy_perf_proc->write_proc = synergy_perf_write_proc;
  375.                 printk("markgw: synergy_perf_init()n");
  376.         }
  377. }
  378. #endif /* CONFIG_IA64_SGI_SYNERGY_PERF */