1/* 2 * Platform dependent support for SGI SN1 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 35#include <linux/config.h> 36#include <linux/init.h> 37#include <linux/sched.h> 38#include <asm/current.h> 39#include <linux/irq.h> 40#include <linux/interrupt.h> 41#include <asm/page.h> 42#include <asm/pgtable.h> 43#include <asm/sn/sgi.h> 44#include <asm/sn/iograph.h> 45#include <asm/sn/invent.h> 46#include <linux/devfs_fs_kernel.h> 47#include <asm/sn/hcl.h> 48#include <asm/sn/types.h> 49#include <asm/sn/pci/bridge.h> 50#include <asm/sn/pci/pciio.h> 51#include <asm/sn/pci/pciio_private.h> 52#ifdef ajmtestintr 53#include <asm/sn/pci/pcibr.h> 54#include <asm/sn/pci/pcibr_private.h> 55#endif /* ajmtestintr */ 56#include <asm/sn/sn_cpuid.h> 57#include <asm/sn/io.h> 58#include <asm/sn/intr.h> 59#include <asm/sn/addrs.h> 60#include <asm/sn/driver.h> 61#include <asm/sn/arch.h> 62 63int irq_to_bit_pos(int irq); 64 65 66 67static unsigned int 68sn_startup_irq(unsigned int irq) 69{ 70 return(0); 71} 72 73static void 74sn_shutdown_irq(unsigned int irq) 75{ 76} 77 78static void 79sn_disable_irq(unsigned int irq) 80{ 81} 82 83static void 84sn_enable_irq(unsigned int irq) 85{ 86} 87 88static void 89sn_ack_irq(unsigned int irq) 90{ 91#ifdef CONFIG_IA64_SGI_SN1 92 int bit = -1; 93 unsigned long long intpend_val; 94 int subnode; 95#endif 96#ifdef CONFIG_IA64_SGI_SN2 97 unsigned long event_occurred, mask = 0; 98#endif 99 int nasid; 100 101 irq = irq & 0xff; 102 nasid = smp_physical_node_id(); 103#ifdef CONFIG_IA64_SGI_SN1 104 subnode = cpuid_to_subnode(smp_processor_id()); 105 if (irq == SGI_UART_IRQ) { 106 intpend_val = REMOTE_HUB_PI_L(nasid, subnode, PI_INT_PEND0); 107 if (intpend_val & (1L<<GFX_INTR_A) ) { 108 bit = GFX_INTR_A; 109 REMOTE_HUB_PI_CLR_INTR(nasid, subnode, bit); 110 } 111 if ( intpend_val & (1L<<GFX_INTR_B) ) { 112 bit = GFX_INTR_B; 113 REMOTE_HUB_PI_CLR_INTR(nasid, subnode, bit); 114 } 115 if (intpend_val & (1L<<PG_MIG_INTR) ) { 116 bit = PG_MIG_INTR; 117 REMOTE_HUB_PI_CLR_INTR(nasid, subnode, bit); 118 } 119 if (intpend_val & (1L<<CC_PEND_A)) { 120 bit = CC_PEND_A; 121 REMOTE_HUB_PI_CLR_INTR(nasid, subnode, bit); 122 } 123 if (intpend_val & (1L<<CC_PEND_B)) { 124 bit = CC_PEND_B; 125 REMOTE_HUB_PI_CLR_INTR(nasid, subnode, bit); 126 } 127 return; 128 } 129 bit = irq_to_bit_pos(irq); 130 REMOTE_HUB_PI_CLR_INTR(nasid, subnode, bit); 131#endif 132 133#ifdef CONFIG_IA64_SGI_SN2 134 event_occurred = HUB_L( (unsigned long *)GLOBAL_MMR_ADDR(nasid,SH_EVENT_OCCURRED) ); 135 if (event_occurred & SH_EVENT_OCCURRED_UART_INT_MASK) { 136 mask |= (1 << SH_EVENT_OCCURRED_UART_INT_SHFT); 137 } 138 if (event_occurred & SH_EVENT_OCCURRED_IPI_INT_MASK) { 139 mask |= (1 << SH_EVENT_OCCURRED_IPI_INT_SHFT); 140 } 141 if (event_occurred & SH_EVENT_OCCURRED_II_INT0_MASK) { 142 mask |= (1 << SH_EVENT_OCCURRED_II_INT0_SHFT); 143 } 144 if (event_occurred & SH_EVENT_OCCURRED_II_INT1_MASK) { 145 mask |= (1 << SH_EVENT_OCCURRED_II_INT1_SHFT); 146 } 147 HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_EVENT_OCCURRED_ALIAS), mask ); 148#endif 149} 150 151static void 152sn_end_irq(unsigned int irq) 153{ 154#ifdef CONFIG_IA64_SGI_SN1 155 unsigned long long intpend_val, mask = 0x70L; 156 int subnode; 157#endif 158 int nasid; 159#ifdef CONFIG_IA64_SGI_SN2 160 unsigned long event_occurred; 161#endif 162 163 irq = irq & 0xff; 164#ifdef CONFIG_IA64_SGI_SN1 165 if (irq == SGI_UART_IRQ) { 166 nasid = smp_physical_node_id(); 167 subnode = cpuid_to_subnode(smp_processor_id()); 168 intpend_val = REMOTE_HUB_PI_L(nasid, subnode, PI_INT_PEND0); 169 if (intpend_val & mask) { 170 platform_send_ipi(smp_processor_id(), SGI_UART_IRQ, IA64_IPI_DM_INT, 0); 171 } 172 } 173#endif 174#ifdef CONFIG_IA64_SGI_SN2 175 if (irq == SGI_UART_VECTOR) { 176 nasid = smp_physical_node_id(); 177 event_occurred = HUB_L( (unsigned long *)GLOBAL_MMR_ADDR(nasid,SH_EVENT_OCCURRED) ); 178 // If the UART bit is set here, we may have received an interrupt from the 179 // UART that the driver missed. To make sure, we IPI ourselves to force us 180 // to look again. 181 if (event_occurred & SH_EVENT_OCCURRED_UART_INT_MASK) { 182 platform_send_ipi(smp_processor_id(), SGI_UART_VECTOR, IA64_IPI_DM_INT, 0); 183 } 184 } 185#endif 186 187} 188 189static void 190sn_set_affinity_irq(unsigned int irq, unsigned long mask) 191{ 192} 193 194 195struct hw_interrupt_type irq_type_iosapic_level = { 196 "SN hub", 197 sn_startup_irq, 198 sn_shutdown_irq, 199 sn_enable_irq, 200 sn_disable_irq, 201 sn_ack_irq, 202 sn_end_irq, 203 sn_set_affinity_irq 204}; 205 206 207#define irq_type_sn irq_type_iosapic_level 208struct irq_desc *_sn_irq_desc[NR_CPUS]; 209 210struct irq_desc * 211sn_irq_desc(unsigned int irq) { 212 int cpu = irq >> 8; 213 214 irq = irq & 0xff; 215 216 return(_sn_irq_desc[cpu] + irq); 217} 218 219u8 220sn_irq_to_vector(u8 irq) { 221 return(irq & 0xff); 222} 223 224unsigned int 225sn_local_vector_to_irq(u8 vector) { 226 return (CPU_VECTOR_TO_IRQ(smp_processor_id(), vector)); 227} 228 229int 230sn_valid_irq(u8 irq) { 231 232 return( ((irq & 0xff) < NR_IRQS) && ((irq >> 8) < NR_CPUS) ); 233} 234 235void *kmalloc(size_t, int); 236 237void 238sn_irq_init (void) 239{ 240 int i; 241 irq_desc_t *base_desc = _irq_desc; 242 243 for (i=IA64_FIRST_DEVICE_VECTOR; i<NR_IRQS; i++) { 244 if (base_desc[i].handler == &no_irq_type) { 245 base_desc[i].handler = &irq_type_sn; 246 } 247 } 248} 249 250void 251sn_init_irq_desc(void) { 252 int i; 253 irq_desc_t *base_desc = _irq_desc, *p; 254 255 for (i=0; i < NR_CPUS; i++) { 256 p = page_address(alloc_pages_node(local_cnodeid(), GFP_KERNEL, 257 get_order(sizeof(struct irq_desc) * NR_IRQS) ) ); 258 ASSERT(p); 259 memcpy(p, base_desc, sizeof(struct irq_desc) * NR_IRQS); 260 _sn_irq_desc[i] = p; 261 } 262} 263 264 265#if !defined(CONFIG_IA64_SGI_SN) 266void 267sn_pci_fixup(void) 268{ 269} 270#endif 271 272int 273bit_pos_to_irq(int bit) { 274#define BIT_TO_IRQ 64 275 if (bit > 118) bit = 118; 276 277#ifdef CONFIG_IA64_SGI_SN1 278 if (bit >= GFX_INTR_A && bit <= CC_PEND_B) { 279 return SGI_UART_IRQ; 280 } 281#endif 282 283 return bit + BIT_TO_IRQ; 284} 285 286int 287irq_to_bit_pos(int irq) { 288#define IRQ_TO_BIT 64 289 int bit = irq - IRQ_TO_BIT; 290 291 return bit; 292} 293 294#ifdef ajmtestintr 295 296#include <linux/timer.h> 297struct timer_list intr_test_timer; 298int intr_test_icount[NR_IRQS]; 299struct intr_test_reg_struct { 300 pcibr_soft_t pcibr_soft; 301 int slot; 302}; 303struct intr_test_reg_struct intr_test_registered[NR_IRQS]; 304 305void 306intr_test_handle_timer(unsigned long data) { 307 int i; 308 bridge_t *bridge; 309 310 for (i=0;i<NR_IRQS;i++) { 311 if (intr_test_registered[i].pcibr_soft) { 312 pcibr_soft_t pcibr_soft = intr_test_registered[i].pcibr_soft; 313 xtalk_intr_t intr = pcibr_soft->bs_intr[intr_test_registered[i].slot].bsi_xtalk_intr; 314 /* send interrupt */ 315 bridge = pcibr_soft->bs_base; 316 bridge->b_force_always[intr_test_registered[i].slot].intr = 1; 317 } 318 } 319 del_timer(&intr_test_timer); 320 intr_test_timer.expires = jiffies + HZ/100; 321 add_timer(&intr_test_timer); 322} 323 324void 325intr_test_set_timer(void) { 326 intr_test_timer.expires = jiffies + HZ/100; 327 intr_test_timer.function = intr_test_handle_timer; 328 add_timer(&intr_test_timer); 329} 330 331void 332intr_test_register_irq(int irq, pcibr_soft_t pcibr_soft, int slot) { 333 irq = irq & 0xff; 334 intr_test_registered[irq].pcibr_soft = pcibr_soft; 335 intr_test_registered[irq].slot = slot; 336} 337 338void 339intr_test_handle_intr(int irq, void *junk, struct pt_regs *morejunk) { 340 intr_test_icount[irq]++; 341 printk("RECEIVED %d INTERRUPTS ON IRQ %d\n",intr_test_icount[irq], irq); 342} 343#endif /* ajmtestintr */ 344