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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /* $Id: hub_intr.c,v 1.1 2002/02/28 17:31:25 marcelo Exp $
  2.  *
  3.  * This file is subject to the terms and conditions of the GNU General Public
  4.  * License.  See the file "COPYING" in the main directory of this archive
  5.  * for more details.
  6.  *
  7.  * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
  8.  */
  9. #include <linux/types.h>
  10. #include <linux/slab.h>
  11. #include <asm/sn/types.h>
  12. #include <asm/sn/sgi.h>
  13. #include <asm/sn/driver.h>
  14. #include <asm/sn/iograph.h>
  15. #include <asm/param.h>
  16. #include <asm/sn/pio.h>
  17. #include <asm/sn/xtalk/xwidget.h>
  18. #include <asm/sn/io.h>
  19. #include <asm/sn/sn_private.h>
  20. #include <asm/sn/addrs.h>
  21. #include <asm/sn/invent.h>
  22. #include <asm/sn/hcl.h>
  23. #include <asm/sn/hcl_util.h>
  24. #include <asm/sn/intr.h>
  25. #include <asm/sn/xtalk/xtalkaddrs.h>
  26. #include <asm/sn/klconfig.h>
  27. #include <asm/sn/sn_cpuid.h>
  28. extern xtalk_provider_t hub_provider;
  29. /* ARGSUSED */
  30. void
  31. hub_intr_init(devfs_handle_t hubv)
  32. {
  33. }
  34. /*
  35.  * hub_device_desc_update
  36.  * Update the passed in device descriptor with the actual the
  37.  *  target cpu number and interrupt priority level.
  38.  * NOTE : These might be the same as the ones passed in thru
  39.  * the descriptor.
  40.  */
  41. static void
  42. hub_device_desc_update(device_desc_t  dev_desc, 
  43.        ilvl_t  intr_swlevel,
  44.        cpuid_t cpu)
  45. {
  46. }
  47. int allocate_my_bit = INTRCONNECT_ANYBIT;
  48. /*
  49.  * Allocate resources required for an interrupt as specified in dev_desc.
  50.  * Returns a hub interrupt handle on success, or 0 on failure.
  51.  */
  52. static hub_intr_t
  53. do_hub_intr_alloc(devfs_handle_t dev, /* which crosstalk device */
  54.   device_desc_t dev_desc, /* device descriptor */
  55.   devfs_handle_t owner_dev, /* owner of this interrupt, if known */
  56.   int uncond_nothread) /* unconditionally non-threaded */
  57. {
  58. cpuid_t cpu = (cpuid_t)0; /* cpu to receive interrupt */
  59.         int cpupicked = 0;
  60. int bit; /* interrupt vector */
  61. /*REFERENCED*/
  62. int intr_resflags = 0;
  63. hub_intr_t intr_hdl;
  64. cnodeid_t nodeid; /* node to receive interrupt */
  65. /*REFERENCED*/
  66. nasid_t nasid; /* nasid to receive interrupt */
  67. struct xtalk_intr_s *xtalk_info;
  68. iopaddr_t xtalk_addr; /* xtalk addr on hub to set intr */
  69. xwidget_info_t xwidget_info; /* standard crosstalk widget info handle */
  70. char *intr_name = NULL;
  71. ilvl_t intr_swlevel = (ilvl_t)0;
  72. extern int default_intr_pri;
  73. extern void synergy_intr_alloc(int, int);
  74. if (dev_desc) {
  75. if (dev_desc->flags & D_INTR_ISERR) {
  76. intr_resflags = II_ERRORINT;
  77. } else if (!uncond_nothread && !(dev_desc->flags & D_INTR_NOTHREAD)) {
  78. intr_resflags = II_THREADED;
  79. } else {
  80. /* Neither an error nor a thread. */
  81. intr_resflags = 0;
  82. }
  83. } else {
  84. intr_swlevel = default_intr_pri;
  85. if (!uncond_nothread)
  86. intr_resflags = II_THREADED;
  87. }
  88. /* XXX - Need to determine if the interrupt should be threaded. */
  89. /* If the cpu has not been picked already then choose a candidate 
  90.  * interrupt target and reserve the interrupt bit 
  91.  */
  92. if (!cpupicked) {
  93. cpu = intr_heuristic(dev,dev_desc,allocate_my_bit,
  94.      intr_resflags,owner_dev,
  95.      intr_name,&bit);
  96. }
  97. /* At this point we SHOULD have a valid cpu */
  98. if (cpu == CPU_NONE) {
  99. #if defined(SUPPORT_PRINTING_V_FORMAT)
  100. printk(KERN_WARNING  "%v hub_intr_alloc could not allocate interruptn",
  101. owner_dev);
  102. #else
  103. printk(KERN_WARNING  "%p hub_intr_alloc could not allocate interruptn",
  104. (void *)owner_dev);
  105. #endif
  106. return(0);
  107. }
  108. /* If the cpu has been picked already (due to the bridge data 
  109.  * corruption bug) then try to reserve an interrupt bit .
  110.  */
  111. if (cpupicked) {
  112. bit = intr_reserve_level(cpu, allocate_my_bit, 
  113.  intr_resflags, 
  114.  owner_dev, intr_name);
  115. if (bit < 0) {
  116. #if defined(SUPPORT_PRINTING_V_FORMAT)
  117. printk(KERN_WARNING  "Could not reserve an interrupt bit for cpu "
  118. " %d and dev %vn",
  119. cpu,owner_dev);
  120. #else
  121. printk(KERN_WARNING  "Could not reserve an interrupt bit for cpu "
  122. " %d and dev %pn",
  123. (int)cpu, (void *)owner_dev);
  124. #endif
  125. return(0);
  126. }
  127. }
  128. nodeid = cpuid_to_cnodeid(cpu);
  129. nasid = cpuid_to_nasid(cpu);
  130. xtalk_addr = HUBREG_AS_XTALKADDR(nasid, PIREG(PI_INT_PEND_MOD, cpuid_to_subnode(cpu)));
  131. /*
  132.  * Allocate an interrupt handle, and fill it in.  There are two
  133.  * pieces to an interrupt handle: the piece needed by generic
  134.  * xtalk code which is used by crosstalk device drivers, and
  135.  * the piece needed by low-level IP27 hardware code.
  136.  */
  137. intr_hdl = snia_kmem_alloc_node(sizeof(struct hub_intr_s), KM_NOSLEEP, nodeid);
  138. ASSERT_ALWAYS(intr_hdl);
  139. /* 
  140.  * Fill in xtalk information for generic xtalk interfaces that
  141.  * operate on xtalk_intr_hdl's.
  142.  */
  143. xtalk_info = &intr_hdl->i_xtalk_info;
  144. xtalk_info->xi_dev = dev;
  145. xtalk_info->xi_vector = bit;
  146. xtalk_info->xi_addr = xtalk_addr;
  147. /*
  148.  * Regardless of which CPU we ultimately interrupt, a given crosstalk
  149.  * widget always handles interrupts (and PIO and DMA) through its 
  150.  * designated "master" crosstalk provider.
  151.  */
  152. xwidget_info = xwidget_info_get(dev);
  153. if (xwidget_info)
  154. xtalk_info->xi_target = xwidget_info_masterid_get(xwidget_info);
  155. /* Fill in low level hub information for hub_* interrupt interface */
  156. intr_hdl->i_swlevel = intr_swlevel;
  157. intr_hdl->i_cpuid = cpu;
  158. intr_hdl->i_bit = bit;
  159. intr_hdl->i_flags = HUB_INTR_IS_ALLOCED;
  160. /* Store the actual interrupt priority level & interrupt target
  161.  * cpu back in the device descriptor.
  162.  */
  163. hub_device_desc_update(dev_desc, intr_swlevel, cpu);
  164. synergy_intr_alloc((int)bit, (int)cpu);
  165. return(intr_hdl);
  166. }
  167. /*
  168.  * Allocate resources required for an interrupt as specified in dev_desc.
  169.  * Returns a hub interrupt handle on success, or 0 on failure.
  170.  */
  171. hub_intr_t
  172. hub_intr_alloc( devfs_handle_t dev, /* which crosstalk device */
  173. device_desc_t dev_desc, /* device descriptor */
  174. devfs_handle_t owner_dev) /* owner of this interrupt, if known */
  175. {
  176. return(do_hub_intr_alloc(dev, dev_desc, owner_dev, 0));
  177. }
  178. /*
  179.  * Allocate resources required for an interrupt as specified in dev_desc.
  180.  * Uncondtionally request non-threaded, regardless of what the device
  181.  * descriptor might say.
  182.  * Returns a hub interrupt handle on success, or 0 on failure.
  183.  */
  184. hub_intr_t
  185. hub_intr_alloc_nothd(devfs_handle_t dev, /* which crosstalk device */
  186. device_desc_t dev_desc, /* device descriptor */
  187. devfs_handle_t owner_dev) /* owner of this interrupt, if known */
  188. {
  189. return(do_hub_intr_alloc(dev, dev_desc, owner_dev, 1));
  190. }
  191. /*
  192.  * Free resources consumed by intr_alloc.
  193.  */
  194. void
  195. hub_intr_free(hub_intr_t intr_hdl)
  196. {
  197. cpuid_t cpu = intr_hdl->i_cpuid;
  198. int bit = intr_hdl->i_bit;
  199. xtalk_intr_t xtalk_info;
  200. if (intr_hdl->i_flags & HUB_INTR_IS_CONNECTED) {
  201. /* Setting the following fields in the xtalk interrupt info
  202.    * clears the interrupt target register in the xtalk user
  203.    */
  204. xtalk_info = &intr_hdl->i_xtalk_info;
  205. xtalk_info->xi_dev = NODEV;
  206. xtalk_info->xi_vector = 0;
  207. xtalk_info->xi_addr = 0;
  208. hub_intr_disconnect(intr_hdl);
  209. }
  210. if (intr_hdl->i_flags & HUB_INTR_IS_ALLOCED)
  211. kfree(intr_hdl);
  212. intr_unreserve_level(cpu, bit);
  213. }
  214. /*
  215.  * Associate resources allocated with a previous hub_intr_alloc call with the
  216.  * described handler, arg, name, etc.
  217.  */
  218. /*ARGSUSED*/
  219. int
  220. hub_intr_connect( hub_intr_t intr_hdl, /* xtalk intr resource handle */
  221. xtalk_intr_setfunc_t setfunc, /* func to set intr hw */
  222. void *setfunc_arg) /* arg to setfunc */
  223. {
  224. int rv;
  225. cpuid_t cpu = intr_hdl->i_cpuid;
  226. int bit = intr_hdl->i_bit;
  227. extern int synergy_intr_connect(int, int);
  228. ASSERT(intr_hdl->i_flags & HUB_INTR_IS_ALLOCED);
  229. rv = intr_connect_level(cpu, bit, intr_hdl->i_swlevel, NULL);
  230. if (rv < 0)
  231. return(rv);
  232. intr_hdl->i_xtalk_info.xi_setfunc = setfunc;
  233. intr_hdl->i_xtalk_info.xi_sfarg = setfunc_arg;
  234. if (setfunc) (*setfunc)((xtalk_intr_t)intr_hdl);
  235. intr_hdl->i_flags |= HUB_INTR_IS_CONNECTED;
  236. return(synergy_intr_connect((int)bit, (int)cpu));
  237. }
  238. /*
  239.  * Disassociate handler with the specified interrupt.
  240.  */
  241. void
  242. hub_intr_disconnect(hub_intr_t intr_hdl)
  243. {
  244. /*REFERENCED*/
  245. int rv;
  246. cpuid_t cpu = intr_hdl->i_cpuid;
  247. int bit = intr_hdl->i_bit;
  248. xtalk_intr_setfunc_t setfunc;
  249. setfunc = intr_hdl->i_xtalk_info.xi_setfunc;
  250. /* TBD: send disconnected interrupts somewhere harmless */
  251. if (setfunc) (*setfunc)((xtalk_intr_t)intr_hdl);
  252. rv = intr_disconnect_level(cpu, bit);
  253. ASSERT(rv == 0);
  254. intr_hdl->i_flags &= ~HUB_INTR_IS_CONNECTED;
  255. }
  256. /*
  257.  * Return a hwgraph vertex that represents the CPU currently
  258.  * targeted by an interrupt.
  259.  */
  260. devfs_handle_t
  261. hub_intr_cpu_get(hub_intr_t intr_hdl)
  262. {
  263. cpuid_t cpuid = intr_hdl->i_cpuid;
  264. ASSERT(cpuid != CPU_NONE);
  265. return(cpuid_to_vertex(cpuid));
  266. }