2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
6 * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. All Rights Reserved.
9 #include <linux/types.h>
10 #include <linux/slab.h>
11 #include <linux/interrupt.h>
14 #include <asm/hw_irq.h>
15 #include <asm/sn/sgi.h>
16 #include <asm/sn/iograph.h>
17 #include <asm/sn/hcl.h>
18 #include <asm/sn/labelcl.h>
19 #include <asm/sn/io.h>
20 #include <asm/sn/sn_private.h>
21 #include <asm/sn/klconfig.h>
22 #include <asm/sn/sn_cpuid.h>
23 #include <asm/sn/pci/pciio.h>
24 #include <asm/sn/pci/pcibr.h>
25 #include <asm/sn/xtalk/xtalk.h>
26 #include <asm/sn/pci/pcibr_private.h>
27 #include <asm/sn/intr.h>
28 #include <asm/sn/sn2/shub_mmr_t.h>
29 #include <asm/sn/sn2/shubio.h>
31 #include <asm/sn/sn_sal.h>
32 #include <asm/sn/sn2/shub_mmr.h>
33 #include <asm/sn/pda.h>
35 extern irqpda_t *irqpdaindr;
36 extern cnodeid_t master_node_get(vertex_hdl_t vhdl);
37 extern nasid_t master_nasid;
39 /* Initialize some shub registers for interrupts, both IO and error. */
40 void intr_init_vecblk(cnodeid_t node)
42 int nasid = cnodeid_to_nasid(node);
43 sh_ii_int0_config_u_t ii_int_config;
47 sh_ii_int0_enable_u_t ii_int_enable;
48 sh_int_node_id_config_u_t node_id_config;
49 sh_local_int5_config_u_t local5_config;
50 sh_local_int5_enable_u_t local5_enable;
52 if (is_headless_node(node) ) {
53 struct ia64_sal_retval ret_stuff;
56 /* retarget all interrupts on this node to the master node. */
57 node_id_config.sh_int_node_id_config_regval = 0;
58 node_id_config.sh_int_node_id_config_s.node_id = master_nasid;
59 node_id_config.sh_int_node_id_config_s.id_sel = 1;
60 HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_INT_NODE_ID_CONFIG),
61 node_id_config.sh_int_node_id_config_regval);
62 cnode = nasid_to_cnodeid(master_nasid);
63 lnodepda = NODEPDA(cnode);
64 cpu = lnodepda->node_first_cpu;
65 cpu = cpu_physical_id(cpu);
66 SAL_CALL(ret_stuff, SN_SAL_REGISTER_CE, nasid, cpu, master_nasid,0,0,0,0);
67 if (ret_stuff.status < 0)
68 printk("%s: SN_SAL_REGISTER_CE SAL_CALL failed\n",__FUNCTION__);
70 lnodepda = NODEPDA(node);
71 cpu = lnodepda->node_first_cpu;
72 cpu = cpu_physical_id(cpu);
75 /* Get the physical id's of the cpu's on this node. */
76 cpu0 = nasid_slice_to_cpu_physical_id(nasid, 0);
77 cpu1 = nasid_slice_to_cpu_physical_id(nasid, 2);
79 HUB_S( (unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_PI_ERROR_MASK), 0);
80 HUB_S( (unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_PI_CRBP_ERROR_MASK), 0);
82 /* Config and enable UART interrupt, all nodes. */
83 local5_config.sh_local_int5_config_regval = 0;
84 local5_config.sh_local_int5_config_s.idx = SGI_UART_VECTOR;
85 local5_config.sh_local_int5_config_s.pid = cpu;
86 HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT5_CONFIG),
87 local5_config.sh_local_int5_config_regval);
89 local5_enable.sh_local_int5_enable_regval = 0;
90 local5_enable.sh_local_int5_enable_s.uart_int = 1;
91 HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT5_ENABLE),
92 local5_enable.sh_local_int5_enable_regval);
95 /* The II_INT_CONFIG register for cpu 0. */
96 ii_int_config.sh_ii_int0_config_regval = 0;
97 ii_int_config.sh_ii_int0_config_s.type = 0;
98 ii_int_config.sh_ii_int0_config_s.agt = 0;
99 ii_int_config.sh_ii_int0_config_s.pid = cpu0;
100 ii_int_config.sh_ii_int0_config_s.base = 0;
102 HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_II_INT0_CONFIG),
103 ii_int_config.sh_ii_int0_config_regval);
106 /* The II_INT_CONFIG register for cpu 1. */
107 ii_int_config.sh_ii_int0_config_regval = 0;
108 ii_int_config.sh_ii_int0_config_s.type = 0;
109 ii_int_config.sh_ii_int0_config_s.agt = 0;
110 ii_int_config.sh_ii_int0_config_s.pid = cpu1;
111 ii_int_config.sh_ii_int0_config_s.base = 0;
113 HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_II_INT1_CONFIG),
114 ii_int_config.sh_ii_int0_config_regval);
117 /* Enable interrupts for II_INT0 and 1. */
118 ii_int_enable.sh_ii_int0_enable_regval = 0;
119 ii_int_enable.sh_ii_int0_enable_s.ii_enable = 1;
121 HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_II_INT0_ENABLE),
122 ii_int_enable.sh_ii_int0_enable_regval);
123 HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_II_INT1_ENABLE),
124 ii_int_enable.sh_ii_int0_enable_regval);
127 static int intr_reserve_level(cpuid_t cpu, int bit)
129 irqpda_t *irqs = irqpdaindr;
134 for (i = IA64_SN2_FIRST_DEVICE_VECTOR; i <= IA64_SN2_LAST_DEVICE_VECTOR; i++) {
135 if (irqs->irq_flags[i] == 0) {
142 if (bit < 0) { /* ran out of irqs. Have to share. This will be rare. */
144 for (i=IA64_SN2_FIRST_DEVICE_VECTOR; i < IA64_SN2_LAST_DEVICE_VECTOR; i++) {
145 /* Share with the same device class */
146 /* XXX: gross layering violation.. */
147 if (irqpdaindr->curr->vendor == irqpdaindr->device_dev[i]->vendor &&
148 irqpdaindr->curr->device == irqpdaindr->device_dev[i]->device &&
149 irqpdaindr->share_count[i] < min_shared) {
150 min_shared = irqpdaindr->share_count[i];
156 if (bit < 0) { /* didn't find a matching device, just pick one. This will be */
157 /* exceptionally rare. */
158 for (i=IA64_SN2_FIRST_DEVICE_VECTOR; i < IA64_SN2_LAST_DEVICE_VECTOR; i++) {
159 if (irqpdaindr->share_count[i] < min_shared) {
160 min_shared = irqpdaindr->share_count[i];
165 irqpdaindr->share_count[bit]++;
168 if (!(irqs->irq_flags[bit] & SN2_IRQ_SHARED)) {
169 if (irqs->irq_flags[bit] & SN2_IRQ_RESERVED)
171 irqs->num_irq_used++;
174 irqs->irq_flags[bit] |= SN2_IRQ_RESERVED;
178 void intr_unreserve_level(cpuid_t cpu,
181 irqpda_t *irqs = irqpdaindr;
183 if (irqs->irq_flags[bit] & SN2_IRQ_RESERVED) {
184 irqs->num_irq_used--;
185 irqs->irq_flags[bit] &= ~SN2_IRQ_RESERVED;
189 int intr_connect_level(cpuid_t cpu, int bit)
191 irqpda_t *irqs = irqpdaindr;
193 if (!(irqs->irq_flags[bit] & SN2_IRQ_SHARED) &&
194 (irqs->irq_flags[bit] & SN2_IRQ_CONNECTED))
197 irqs->irq_flags[bit] |= SN2_IRQ_CONNECTED;
201 int intr_disconnect_level(cpuid_t cpu, int bit)
203 irqpda_t *irqs = irqpdaindr;
205 if (!(irqs->irq_flags[bit] & SN2_IRQ_CONNECTED))
207 irqs->irq_flags[bit] &= ~SN2_IRQ_CONNECTED;
212 * Choose a cpu on this node.
214 * We choose the one with the least number of int's assigned to it.
216 static cpuid_t intr_cpu_choose_from_node(cnodeid_t cnode)
218 cpuid_t cpu, best_cpu = CPU_NONE;
219 int slice, min_count = 1000;
221 for (slice = CPUS_PER_NODE - 1; slice >= 0; slice--) {
224 cpu = cnode_slice_to_cpuid(cnode, slice);
227 if (!cpu_online(cpu))
230 intrs = pdacpu(cpu)->sn_num_irqs;
232 if (min_count > intrs) {
235 if (enable_shub_wars_1_1()) {
237 * Rather than finding the best cpu, always
238 * return the first cpu. This forces all
239 * interrupts to the same cpu
245 pdacpu(best_cpu)->sn_num_irqs++;
250 * We couldn't put it on the closest node. Try to find another one.
251 * Do a stupid round-robin assignment of the node.
253 static cpuid_t intr_cpu_choose_node(void)
255 static cnodeid_t last_node = -1; /* XXX: racy */
256 cnodeid_t candidate_node;
259 if (last_node >= numnodes)
262 for (candidate_node = last_node + 1; candidate_node != last_node;
264 if (candidate_node == numnodes)
266 cpuid = intr_cpu_choose_from_node(candidate_node);
267 if (cpuid != CPU_NONE)
275 * Find the node to assign for this interrupt.
277 * SN2 + pcibr addressing limitation:
278 * Due to this limitation, all interrupts from a given bridge must
279 * go to the name node. The interrupt must also be targetted for
280 * the same processor. This limitation does not exist on PIC.
281 * But, the processor limitation will stay. The limitation will be
282 * similar to the bedrock/xbridge limit regarding PI's
284 cpuid_t intr_heuristic(vertex_hdl_t dev, int req_bit, int *resp_bit)
287 vertex_hdl_t pconn_vhdl;
288 pcibr_soft_t pcibr_soft;
291 /* XXX: gross layering violation.. */
292 if (hwgraph_edge_get(dev, EDGE_LBL_PCI, &pconn_vhdl) == GRAPH_SUCCESS) {
293 pcibr_soft = pcibr_soft_get(pconn_vhdl);
294 if (pcibr_soft && pcibr_soft->bsi_err_intr) {
296 * The cpu was chosen already when we assigned
297 * the error interrupt.
299 cpuid = ((hub_intr_t)pcibr_soft->bsi_err_intr)->i_cpuid;
305 * Need to choose one. Try the controlling c-brick first.
307 cpuid = intr_cpu_choose_from_node(master_node_get(dev));
308 if (cpuid == CPU_NONE)
309 cpuid = intr_cpu_choose_node();
312 if (cpuid != CPU_NONE) {
313 bit = intr_reserve_level(cpuid, req_bit);
320 printk("Cannot target interrupt to target cpu (%ld).\n", cpuid);