Update ia64 patch to 2.5.69-030521, throwing away the parts included
[linux-flexiantxendom0-3.2.10.git] / arch / ia64 / sn / io / sn2 / shub_intr.c
1 /* $Id: shub_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-2003 Silicon Graphics, Inc.  All Rights Reserved.
8  */
9
10 #include <linux/types.h>
11 #include <linux/slab.h>
12 #include <asm/sn/types.h>
13 #include <asm/sn/sgi.h>
14 #include <asm/sn/driver.h>
15 #include <asm/sn/iograph.h>
16 #include <asm/param.h>
17 #include <asm/sn/pio.h>
18 #include <asm/sn/xtalk/xwidget.h>
19 #include <asm/sn/io.h>
20 #include <asm/sn/sn_private.h>
21 #include <asm/sn/addrs.h>
22 #include <asm/sn/invent.h>
23 #include <asm/sn/hcl.h>
24 #include <asm/sn/hcl_util.h>
25 #include <asm/sn/intr.h>
26 #include <asm/sn/xtalk/xtalkaddrs.h>
27 #include <asm/sn/klconfig.h>
28 #include <asm/sn/sn2/shub_mmr.h>
29 #include <asm/sn/sn_cpuid.h>
30
31 /* ARGSUSED */
32 void
33 hub_intr_init(vertex_hdl_t hubv)
34 {
35 }
36
37 xwidgetnum_t
38 hub_widget_id(nasid_t nasid)
39 {
40         hubii_wcr_t     ii_wcr; /* the control status register */
41         
42         ii_wcr.wcr_reg_value = REMOTE_HUB_L(nasid,IIO_WCR);
43         
44         return ii_wcr.wcr_fields_s.wcr_widget_id;
45 }
46
47 static hub_intr_t
48 do_hub_intr_alloc(vertex_hdl_t dev,
49                 device_desc_t dev_desc,
50                 vertex_hdl_t owner_dev,
51                 int uncond_nothread)
52 {
53         cpuid_t         cpu = 0;
54         int             vector;
55         hub_intr_t      intr_hdl;
56         cnodeid_t       cnode;
57         int             cpuphys, slice;
58         int             nasid;
59         iopaddr_t       xtalk_addr;
60         struct xtalk_intr_s     *xtalk_info;
61         xwidget_info_t  xwidget_info;
62         ilvl_t          intr_swlevel = 0;
63
64         cpu = intr_heuristic(dev, dev_desc, -1, 0, owner_dev, NULL, &vector);
65
66         if (cpu == CPU_NONE) {
67                 printk("Unable to allocate interrupt for 0x%p\n", (void *)owner_dev);
68                 return(0);
69         }
70
71         cpuphys = cpu_physical_id(cpu);
72         slice = cpu_physical_id_to_slice(cpuphys);
73         nasid = cpu_physical_id_to_nasid(cpuphys);
74         cnode = cpuid_to_cnodeid(cpu);
75
76         if (slice) {
77                 xtalk_addr = SH_II_INT1 | ((unsigned long)nasid << 36) | (1UL << 47);
78         } else {
79                 xtalk_addr = SH_II_INT0 | ((unsigned long)nasid << 36) | (1UL << 47);
80         }
81
82         intr_hdl = snia_kmem_alloc_node(sizeof(struct hub_intr_s), KM_NOSLEEP, cnode);
83         ASSERT_ALWAYS(intr_hdl);
84
85         xtalk_info = &intr_hdl->i_xtalk_info;
86         xtalk_info->xi_dev = dev;
87         xtalk_info->xi_vector = vector;
88         xtalk_info->xi_addr = xtalk_addr;
89
90         xwidget_info = xwidget_info_get(dev);
91         if (xwidget_info) {
92                 xtalk_info->xi_target = xwidget_info_masterid_get(xwidget_info);
93         }
94
95         intr_hdl->i_swlevel = intr_swlevel;
96         intr_hdl->i_cpuid = cpu;
97         intr_hdl->i_bit = vector;
98         intr_hdl->i_flags |= HUB_INTR_IS_ALLOCED;
99
100         return(intr_hdl);
101 }
102
103 hub_intr_t
104 hub_intr_alloc(vertex_hdl_t dev,
105                 device_desc_t dev_desc,
106                 vertex_hdl_t owner_dev)
107 {
108         return(do_hub_intr_alloc(dev, dev_desc, owner_dev, 0));
109 }
110
111 hub_intr_t
112 hub_intr_alloc_nothd(vertex_hdl_t dev,
113                 device_desc_t dev_desc,
114                 vertex_hdl_t owner_dev)
115 {
116         return(do_hub_intr_alloc(dev, dev_desc, owner_dev, 1));
117 }
118
119 void
120 hub_intr_free(hub_intr_t intr_hdl)
121 {
122         cpuid_t         cpu = intr_hdl->i_cpuid;
123         int             vector = intr_hdl->i_bit;
124         xtalk_intr_t    xtalk_info;
125
126         if (intr_hdl->i_flags & HUB_INTR_IS_CONNECTED) {
127                 xtalk_info = &intr_hdl->i_xtalk_info;
128                 xtalk_info->xi_dev = 0;
129                 xtalk_info->xi_vector = 0;
130                 xtalk_info->xi_addr = 0;
131                 hub_intr_disconnect(intr_hdl);
132         }
133
134         if (intr_hdl->i_flags & HUB_INTR_IS_ALLOCED) {
135                 kfree(intr_hdl);
136         }
137         intr_unreserve_level(cpu, vector);
138 }
139
140 int
141 hub_intr_connect(hub_intr_t intr_hdl,
142                 intr_func_t intr_func,          /* xtalk intr handler */
143                 void *intr_arg,                 /* arg to intr handler */
144                 xtalk_intr_setfunc_t setfunc,
145                 void *setfunc_arg)
146 {
147         int             rv;
148         cpuid_t         cpu = intr_hdl->i_cpuid;
149         int             vector = intr_hdl->i_bit;
150
151         ASSERT(intr_hdl->i_flags & HUB_INTR_IS_ALLOCED);
152
153         rv = intr_connect_level(cpu, vector, intr_hdl->i_swlevel, NULL);
154         if (rv < 0) {
155                 return rv;
156         }
157
158         intr_hdl->i_xtalk_info.xi_setfunc = setfunc;
159         intr_hdl->i_xtalk_info.xi_sfarg = setfunc_arg;
160
161         if (setfunc) {
162                 (*setfunc)((xtalk_intr_t)intr_hdl);
163         }
164
165         intr_hdl->i_flags |= HUB_INTR_IS_CONNECTED;
166
167         return 0;
168 }
169
170 /*
171  * Disassociate handler with the specified interrupt.
172  */
173 void
174 hub_intr_disconnect(hub_intr_t intr_hdl)
175 {
176         /*REFERENCED*/
177         int rv;
178         cpuid_t cpu = intr_hdl->i_cpuid;
179         int bit = intr_hdl->i_bit;
180         xtalk_intr_setfunc_t setfunc;
181
182         setfunc = intr_hdl->i_xtalk_info.xi_setfunc;
183
184         /* TBD: send disconnected interrupts somewhere harmless */
185         if (setfunc) (*setfunc)((xtalk_intr_t)intr_hdl);
186
187         rv = intr_disconnect_level(cpu, bit);
188         ASSERT(rv == 0);
189         intr_hdl->i_flags &= ~HUB_INTR_IS_CONNECTED;
190 }