11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** I/O Sapic Driver - PCI interrupt line support 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** (c) Copyright 1999 Grant Grundler 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** (c) Copyright 1999 Hewlett-Packard Company 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** This program is free software; you can redistribute it and/or modify 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** it under the terms of the GNU General Public License as published by 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** the Free Software Foundation; either version 2 of the License, or 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** (at your option) any later version. 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** The I/O sapic driver manages the Interrupt Redirection Table which is 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** the control logic to convert PCI line based interrupts into a Message 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** Signaled Interrupt (aka Transaction Based Interrupt, TBI). 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** Acronyms 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** -------- 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** HPA Hard Physical Address (aka MMIO address) 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** IRQ Interrupt ReQuest. Implies Line based interrupt. 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** IRT Interrupt Routing Table (provided by PAT firmware) 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** IRdT Interrupt Redirection Table. IRQ line to TXN ADDR/DATA 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** table which is implemented in I/O SAPIC. 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** ISR Interrupt Service Routine. aka Interrupt handler. 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** MSI Message Signaled Interrupt. PCI 2.2 functionality. 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** aka Transaction Based Interrupt (or TBI). 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** PA Precision Architecture. HP's RISC architecture. 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** RISC Reduced Instruction Set Computer. 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** What's a Message Signalled Interrupt? 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** ------------------------------------- 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** MSI is a write transaction which targets a processor and is similar 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** to a processor write to memory or MMIO. MSIs can be generated by I/O 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** devices as well as processors and require *architecture* to work. 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** PA only supports MSI. So I/O subsystems must either natively generate 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** MSIs (e.g. GSC or HP-PB) or convert line based interrupts into MSIs 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** (e.g. PCI and EISA). IA64 supports MSIs via a "local SAPIC" which 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** acts on behalf of a processor. 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** MSI allows any I/O device to interrupt any processor. This makes 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** load balancing of the interrupt processing possible on an SMP platform. 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** Interrupts are also ordered WRT to DMA data. It's possible on I/O 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** coherent systems to completely eliminate PIO reads from the interrupt 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** path. The device and driver must be designed and implemented to 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** guarantee all DMA has been issued (issues about atomicity here) 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** before the MSI is issued. I/O status can then safely be read from 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** DMA'd data by the ISR. 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** PA Firmware 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** ----------- 530779bf2d2ecc4d9b1e9437ae659f50e6776a7666Matt LaPlante** PA-RISC platforms have two fundamentally different types of firmware. 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** For PCI devices, "Legacy" PDC initializes the "INTERRUPT_LINE" register 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** and BARs similar to a traditional PC BIOS. 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** The newer "PAT" firmware supports PDC calls which return tables. 570779bf2d2ecc4d9b1e9437ae659f50e6776a7666Matt LaPlante** PAT firmware only initializes the PCI Console and Boot interface. 580779bf2d2ecc4d9b1e9437ae659f50e6776a7666Matt LaPlante** With these tables, the OS can program all other PCI devices. 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** One such PAT PDC call returns the "Interrupt Routing Table" (IRT). 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** The IRT maps each PCI slot's INTA-D "output" line to an I/O SAPIC 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** input line. If the IRT is not available, this driver assumes 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** INTERRUPT_LINE register has been programmed by firmware. The latter 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** case also means online addition of PCI cards can NOT be supported 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** even if HW support is present. 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** All platforms with PAT firmware to date (Oct 1999) use one Interrupt 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** Routing Table for the entire platform. 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** Where's the iosapic? 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** -------------------- 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** I/O sapic is part of the "Core Electronics Complex". And on HP platforms 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** it's integrated as part of the PCI bus adapter, "lba". So no bus walk 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** will discover I/O Sapic. I/O Sapic driver learns about each device 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** when lba driver advertises the presence of the I/O sapic by calling 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** iosapic_register(). 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** IRQ handling notes 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** ------------------ 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** The IO-SAPIC can indicate to the CPU which interrupt was asserted. 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** So, unlike the GSC-ASIC and Dino, we allocate one CPU interrupt per 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** IO-SAPIC interrupt and call the device driver's handler directly. 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** The IO-SAPIC driver hijacks the CPU interrupt handler so it can 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** issue the End Of Interrupt command to the IO-SAPIC. 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** Overview of exported iosapic functions 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** -------------------------------------- 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** (caveat: code isn't finished yet - this is just the plan) 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** iosapic_init: 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** o initialize globals (lock, etc) 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** o try to read IRT. Presence of IRT determines if this is 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** a PAT platform or not. 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** iosapic_register(): 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** o create iosapic_info instance data structure 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** o allocate vector_info array for this iosapic 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** o initialize vector_info - read corresponding IRdT? 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** iosapic_xlate_pin: (only called by fixup_irq for PAT platform) 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** o intr_pin = read cfg (INTERRUPT_PIN); 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** o if (device under PCI-PCI bridge) 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** translate slot/pin 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** iosapic_fixup_irq: 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** o if PAT platform (IRT present) 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** intr_pin = iosapic_xlate_pin(isi,pcidev): 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** intr_line = find IRT entry(isi, PCI_SLOT(pcidev), intr_pin) 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** save IRT entry into vector_info later 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** write cfg INTERRUPT_LINE (with intr_line)? 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** else 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** intr_line = pcidev->irq 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** IRT pointer = NULL 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** endif 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** o locate vector_info (needs: isi, intr_line) 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** o allocate processor "irq" and get txn_addr/data 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** o request_irq(processor_irq, iosapic_interrupt, vector_info,...) 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** iosapic_enable_irq: 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** o clear any pending IRQ on that line 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** o enable IRdT - call enable_irq(vector[line]->processor_irq) 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** o write EOI in case line is already asserted. 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** iosapic_disable_irq: 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** o disable IRdT - call disable_irq(vector[line]->processor_irq) 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/ 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* FIXME: determine which include files are really needed */ 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h> 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h> 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h> 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h> 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/byteorder.h> /* get in-line asm for swab */ 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/pdc.h> 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/pdcpat.h> 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/page.h> 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> /* read/write functions */ 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SUPERIO 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/superio.h> 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1481790cf9111f61d360d861901b97eba4de3b5414cKyle McMartin#include <asm/ropes.h> 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "./iosapic_private.h" 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MODULE_NAME "iosapic" 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* "local" compile flags */ 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef PCI_BRIDGE_FUNCS 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef DEBUG_IOSAPIC 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef DEBUG_IOSAPIC_IRT 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG_IOSAPIC 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DBG(x...) printk(x) 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else /* DEBUG_IOSAPIC */ 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DBG(x...) 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* DEBUG_IOSAPIC */ 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG_IOSAPIC_IRT 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DBG_IRT(x...) printk(x) 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DBG_IRT(x...) 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_64BIT 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define COMPARE_IRTE_ADDR(irte, hpa) ((irte)->dest_iosapic_addr == (hpa)) 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define COMPARE_IRTE_ADDR(irte, hpa) \ 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((irte)->dest_iosapic_addr == ((hpa) | 0xffffffff00000000ULL)) 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IOSAPIC_REG_SELECT 0x00 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IOSAPIC_REG_WINDOW 0x10 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IOSAPIC_REG_EOI 0x40 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IOSAPIC_REG_VERSION 0x1 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IOSAPIC_IRDT_ENTRY(idx) (0x10+(idx)*2) 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IOSAPIC_IRDT_ENTRY_HI(idx) (0x11+(idx)*2) 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline unsigned int iosapic_read(void __iomem *iosapic, unsigned int reg) 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(reg, iosapic + IOSAPIC_REG_SELECT); 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return readl(iosapic + IOSAPIC_REG_WINDOW); 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void iosapic_write(void __iomem *iosapic, unsigned int reg, u32 val) 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(reg, iosapic + IOSAPIC_REG_SELECT); 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(val, iosapic + IOSAPIC_REG_WINDOW); 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IOSAPIC_VERSION_MASK 0x000000ff 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IOSAPIC_VERSION(ver) ((int) (ver & IOSAPIC_VERSION_MASK)) 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IOSAPIC_MAX_ENTRY_MASK 0x00ff0000 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IOSAPIC_MAX_ENTRY_SHIFT 0x10 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IOSAPIC_IRDT_MAX_ENTRY(ver) \ 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (int) (((ver) & IOSAPIC_MAX_ENTRY_MASK) >> IOSAPIC_MAX_ENTRY_SHIFT) 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* bits in the "low" I/O Sapic IRdT entry */ 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IOSAPIC_IRDT_ENABLE 0x10000 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IOSAPIC_IRDT_PO_LOW 0x02000 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IOSAPIC_IRDT_LEVEL_TRIG 0x08000 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IOSAPIC_IRDT_MODE_LPRI 0x00100 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* bits in the "high" I/O Sapic IRdT entry */ 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IOSAPIC_IRDT_ID_EID_SHIFT 0x10 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 217a9f6a0dd54efea2a5d57a27e6c232f9197c25154Ingo Molnarstatic DEFINE_SPINLOCK(iosapic_lock); 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void iosapic_eoi(void __iomem *addr, unsigned int data) 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __raw_writel(data, addr); 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** REVISIT: future platforms may have more than one IRT. 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** If so, the following three fields form a structure which 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** then be linked into a list. Names are chosen to make searching 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** for them easy - not necessarily accurate (eg "cell"). 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** Alternative: iosapic_info could point to the IRT it's in. 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** iosapic_register() could search a list of IRT's. 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/ 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct irt_entry *irt_cell; 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic size_t irt_num_entry; 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct irt_entry *iosapic_alloc_irt(int num_entries) 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long a; 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The IRT needs to be 8-byte aligned for the PDC call. 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Normally kmalloc would guarantee larger alignment, but 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if CONFIG_DEBUG_SLAB is enabled, then we can get only 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4-byte alignment on 32-bit kernels 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds a = (unsigned long)kmalloc(sizeof(struct irt_entry) * num_entries + 8, GFP_KERNEL); 2463aa0862ce7c120e035bc2aa25997fd000d964d6eGrant Grundler a = (a + 7UL) & ~7UL; 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (struct irt_entry *)a; 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * iosapic_load_irt - Fill in the interrupt routing table 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @cell_num: The cell number of the CPU we're currently executing on 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @irt: The address to place the new IRT at 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @return The number of entries found 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The "Get PCI INT Routing Table Size" option returns the number of 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * entries in the PCI interrupt routing table for the cell specified 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in the cell_number argument. The cell number must be for a cell 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * within the caller's protection domain. 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The "Get PCI INT Routing Table" option returns, for the cell 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * specified in the cell_number argument, the PCI interrupt routing 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * table in the caller allocated memory pointed to by mem_addr. 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We assume the IRT only contains entries for I/O SAPIC and 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * calculate the size based on the size of I/O sapic entries. 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The PCI interrupt routing table entry format is derived from the 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * IA64 SAL Specification 2.4. The PCI interrupt routing table defines 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the routing of PCI interrupt signals between the PCI device output 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * "pins" and the IO SAPICs' input "lines" (including core I/O PCI 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * devices). This table does NOT include information for devices/slots 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * behind PCI to PCI bridges. See PCI to PCI Bridge Architecture Spec. 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for the architected method of routing of IRQ's behind PPB's. 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsiosapic_load_irt(unsigned long cell_num, struct irt_entry **irt) 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds long status; /* PDC return value status */ 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct irt_entry *table; /* start of interrupt routing tbl */ 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long num_entries = 0UL; 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(!irt); 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (is_pdc_pat()) { 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Use pat pdc routine to get interrupt routing table size */ 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG("calling get_irt_size (cell %ld)\n", cell_num); 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = pdc_pat_get_irt_size(&num_entries, cell_num); 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG("get_irt_size: %ld\n", status); 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(status != PDC_OK); 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(num_entries == 0); 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** allocate memory for interrupt routing table 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** This interface isn't really right. We are assuming 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** the contents of the table are exclusively 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** for I/O sapic devices. 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds table = iosapic_alloc_irt(num_entries); 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (table == NULL) { 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING MODULE_NAME ": read_irt : can " 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "not alloc mem for IRT\n"); 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* get PCI INT routing table */ 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = pdc_pat_get_irt(table, cell_num); 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG("pdc_pat_get_irt: %ld\n", status); 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds WARN_ON(status != PDC_OK); 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** C3000/J5000 (and similar) platforms with Sprockets PDC 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** will return exactly one IRT for all iosapics. 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** So if we have one, don't need to get it again. 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (irt_cell) 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Should be using the Elroy's HPA, but it's ignored anyway */ 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = pdc_pci_irt_size(&num_entries, 0); 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG("pdc_pci_irt_size: %ld\n", status); 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status != PDC_OK) { 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Not a "legacy" system with I/O SAPIC either */ 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(num_entries == 0); 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds table = iosapic_alloc_irt(num_entries); 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!table) { 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING MODULE_NAME ": read_irt : can " 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "not alloc mem for IRT\n"); 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* HPA ignored by this call too. */ 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = pdc_pci_irt(num_entries, 0, table); 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(status != PDC_OK); 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* return interrupt table address */ 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *irt = table; 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG_IOSAPIC_IRT 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct irt_entry *p = table; 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(MODULE_NAME " Interrupt Routing Table (cell %ld)\n", cell_num); 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(MODULE_NAME " start = 0x%p num_entries %ld entry_size %d\n", 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds table, 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds num_entries, 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (int) sizeof(struct irt_entry)); 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0 ; i < num_entries ; i++, p++) { 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(MODULE_NAME " %02x %02x %02x %02x %02x %02x %02x %02x %08x%08x\n", 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p->entry_type, p->entry_length, p->interrupt_type, 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p->polarity_trigger, p->src_bus_irq_devno, p->src_bus_id, 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p->src_seg_id, p->dest_iosapic_intin, 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((u32 *) p)[2], 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((u32 *) p)[3] 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ); 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* DEBUG_IOSAPIC_IRT */ 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return num_entries; 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid __init iosapic_init(void) 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long cell = 0; 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG("iosapic_init()\n"); 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef __LP64__ 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (is_pdc_pat()) { 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int status; 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pdc_pat_cell_num cell_info; 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = pdc_pat_cell_get_number(&cell_info); 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status == PDC_OK) { 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cell = cell_info.cell_num; 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* get interrupt routing table for this cell */ 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irt_num_entry = iosapic_load_irt(cell, &irt_cell); 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (irt_num_entry == 0) 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irt_cell = NULL; /* old PDC w/o iosapic */ 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** Return the IRT entry in case we need to look something else up. 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/ 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct irt_entry * 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsirt_find_irqline(struct iosapic_info *isi, u8 slot, u8 intr_pin) 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct irt_entry *i = irt_cell; 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cnt; /* track how many entries we've looked at */ 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 irq_devno = (slot << IRT_DEV_SHIFT) | (intr_pin-1); 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG_IRT("irt_find_irqline() SLOT %d pin %d\n", slot, intr_pin); 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (cnt=0; cnt < irt_num_entry; cnt++, i++) { 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** Validate: entry_type, entry_length, interrupt_type 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** Difference between validate vs compare is the former 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** should print debug info and is not expected to "fail" 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** on current platforms. 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i->entry_type != IRT_IOSAPIC_TYPE) { 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG_IRT(KERN_WARNING MODULE_NAME ":find_irqline(0x%p): skipping entry %d type %d\n", i, cnt, i->entry_type); 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i->entry_length != IRT_IOSAPIC_LENGTH) { 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG_IRT(KERN_WARNING MODULE_NAME ":find_irqline(0x%p): skipping entry %d length %d\n", i, cnt, i->entry_length); 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i->interrupt_type != IRT_VECTORED_INTR) { 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG_IRT(KERN_WARNING MODULE_NAME ":find_irqline(0x%p): skipping entry %d interrupt_type %d\n", i, cnt, i->interrupt_type); 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!COMPARE_IRTE_ADDR(i, isi->isi_hpa)) 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((i->src_bus_irq_devno & IRT_IRQ_DEVNO_MASK) != irq_devno) 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** Ignore: src_bus_id and rc_seg_id correlate with 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** iosapic_info->isi_hpa on HP platforms. 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** If needed, pass in "PFA" (aka config space addr) 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** instead of slot. 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Found it! */ 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return i; 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING MODULE_NAME ": 0x%lx : no IRT entry for slot %d, pin %d\n", 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds isi->isi_hpa, slot, intr_pin); 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** xlate_pin() supports the skewing of IRQ lines done by subsidiary bridges. 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** Legacy PDC already does this translation for us and stores it in INTR_LINE. 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** PAT PDC needs to basically do what legacy PDC does: 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** o read PIN 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** o adjust PIN in case device is "behind" a PPB 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** (eg 4-port 100BT and SCSI/LAN "Combo Card") 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** o convert slot/pin to I/O SAPIC input line. 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** HP platforms only support: 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** o one level of skewing for any number of PPBs 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** o only support PCI-PCI Bridges. 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/ 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct irt_entry * 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsiosapic_xlate_pin(struct iosapic_info *isi, struct pci_dev *pcidev) 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 intr_pin, intr_slot; 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_read_config_byte(pcidev, PCI_INTERRUPT_PIN, &intr_pin); 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG_IRT("iosapic_xlate_pin(%s) SLOT %d pin %d\n", 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcidev->slot_name, PCI_SLOT(pcidev->devfn), intr_pin); 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (intr_pin == 0) { 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The device does NOT support/use IRQ lines. */ 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Check if pcidev behind a PPB */ 4899785d646c10b0707412516ffe56b71b9eb18861fGrant Grundler if (pcidev->bus->parent) { 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Convert pcidev INTR_PIN into something we 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** can lookup in the IRT. 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef PCI_BRIDGE_FUNCS 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** Proposal #1: 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** call implementation specific translation function 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** This is architecturally "cleaner". HP-UX doesn't 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** support other secondary bus types (eg. E/ISA) directly. 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** May be needed for other processor (eg IA64) architectures 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** or by some ambitous soul who wants to watch TV. 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pci_bridge_funcs->xlate_intr_line) { 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds intr_pin = pci_bridge_funcs->xlate_intr_line(pcidev); 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else /* PCI_BRIDGE_FUNCS */ 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pci_bus *p = pcidev->bus; 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** Proposal #2: 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** The "pin" is skewed ((pin + dev - 1) % 4). 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** This isn't very clean since I/O SAPIC must assume: 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** - all platforms only have PCI busses. 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** - only PCI-PCI bridge (eg not PCI-EISA, PCI-PCMCIA) 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** - IRQ routing is only skewed once regardless of 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** the number of PPB's between iosapic and device. 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** (Bit3 expansion chassis follows this rule) 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** Advantage is it's really easy to implement. 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 521f0e88af855cbc5012f2e796f42686969b82d79d4Bjorn Helgaas intr_pin = pci_swizzle_interrupt_pin(pcidev, intr_pin); 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* PCI_BRIDGE_FUNCS */ 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5259785d646c10b0707412516ffe56b71b9eb18861fGrant Grundler * Locate the host slot of the PPB. 5269785d646c10b0707412516ffe56b71b9eb18861fGrant Grundler */ 5279785d646c10b0707412516ffe56b71b9eb18861fGrant Grundler while (p->parent->parent) 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p = p->parent; 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds intr_slot = PCI_SLOT(p->self->devfn); 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds intr_slot = PCI_SLOT(pcidev->devfn); 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG_IRT("iosapic_xlate_pin: bus %d slot %d pin %d\n", 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcidev->bus->secondary, intr_slot, intr_pin); 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return irt_find_irqline(isi, intr_slot, intr_pin); 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void iosapic_rd_irt_entry(struct vector_info *vi , u32 *dp0, u32 *dp1) 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct iosapic_info *isp = vi->iosapic; 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 idx = vi->irqline; 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *dp0 = iosapic_read(isp->addr, IOSAPIC_IRDT_ENTRY(idx)); 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *dp1 = iosapic_read(isp->addr, IOSAPIC_IRDT_ENTRY_HI(idx)); 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void iosapic_wr_irt_entry(struct vector_info *vi, u32 dp0, u32 dp1) 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct iosapic_info *isp = vi->iosapic; 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG_IRT("iosapic_wr_irt_entry(): irq %d hpa %lx 0x%x 0x%x\n", 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vi->irqline, isp->isi_hpa, dp0, dp1); 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iosapic_write(isp->addr, IOSAPIC_IRDT_ENTRY(vi->irqline), dp0); 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Read the window register to flush the writes down to HW */ 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dp0 = readl(isp->addr+IOSAPIC_REG_WINDOW); 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iosapic_write(isp->addr, IOSAPIC_IRDT_ENTRY_HI(vi->irqline), dp1); 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Read the window register to flush the writes down to HW */ 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dp1 = readl(isp->addr+IOSAPIC_REG_WINDOW); 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** set_irt prepares the data (dp0, dp1) according to the vector_info 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** and target cpu (id_eid). dp0/dp1 are then used to program I/O SAPIC 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** IRdT for the given "vector" (aka IRQ line). 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/ 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsiosapic_set_irt_data( struct vector_info *vi, u32 *dp0, u32 *dp1) 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 mode = 0; 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct irt_entry *p = vi->irte; 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((p->polarity_trigger & IRT_PO_MASK) == IRT_ACTIVE_LO) 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mode |= IOSAPIC_IRDT_PO_LOW; 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (((p->polarity_trigger >> IRT_EL_SHIFT) & IRT_EL_MASK) == IRT_LEVEL_TRIG) 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mode |= IOSAPIC_IRDT_LEVEL_TRIG; 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** IA64 REVISIT 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** PA doesn't support EXTINT or LPRIO bits. 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *dp0 = mode | (u32) vi->txn_data; 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** Extracting id_eid isn't a real clean way of getting it. 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** But the encoding is the same for both PA and IA64 platforms. 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (is_pdc_pat()) { 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** PAT PDC just hands it to us "right". 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** txn_addr comes from cpu_data[x].txn_addr. 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *dp1 = (u32) (vi->txn_addr); 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** eg if base_addr == 0xfffa0000), 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** we want to get 0xa0ff0000. 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** eid 0x0ff00000 -> 0x00ff0000 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** id 0x000ff000 -> 0xff000000 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *dp1 = (((u32)vi->txn_addr & 0x0ff00000) >> 4) | 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (((u32)vi->txn_addr & 0x000ff000) << 12); 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG_IRT("iosapic_set_irt_data(): 0x%x 0x%x\n", *dp0, *dp1); 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6174c4231ea2f794d73bbb50b8d84e00c66a012a607Thomas Gleixnerstatic void iosapic_mask_irq(struct irq_data *d) 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 6204c4231ea2f794d73bbb50b8d84e00c66a012a607Thomas Gleixner struct vector_info *vi = irq_data_get_irq_chip_data(d); 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 d0, d1; 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&iosapic_lock, flags); 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iosapic_rd_irt_entry(vi, &d0, &d1); 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds d0 |= IOSAPIC_IRDT_ENABLE; 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iosapic_wr_irt_entry(vi, d0, d1); 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&iosapic_lock, flags); 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6304c4231ea2f794d73bbb50b8d84e00c66a012a607Thomas Gleixnerstatic void iosapic_unmask_irq(struct irq_data *d) 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6324c4231ea2f794d73bbb50b8d84e00c66a012a607Thomas Gleixner struct vector_info *vi = irq_data_get_irq_chip_data(d); 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 d0, d1; 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* data is initialized by fixup_irq */ 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds WARN_ON(vi->txn_irq == 0); 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iosapic_set_irt_data(vi, &d0, &d1); 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iosapic_wr_irt_entry(vi, d0, d1); 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG_IOSAPIC_IRT 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 *t = (u32 *) ((ulong) vi->eoi_addr & ~0xffUL); 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("iosapic_enable_irq(): regs %p", vi->eoi_addr); 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for ( ; t < vi->eoi_addr; t++) 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(" %x", readl(t)); 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("\n"); 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsprintk("iosapic_enable_irq(): sel "); 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct iosapic_info *isp = vi->iosapic; 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (d0=0x10; d0<0x1e; d0++) { 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds d1 = iosapic_read(isp->addr, d0); 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(" %x", d1); 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsprintk("\n"); 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Issuing I/O SAPIC an EOI causes an interrupt IFF IRQ line is 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * asserted. IRQ generally should not be asserted when a driver 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * enables their IRQ. It can lead to "interesting" race conditions 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in the driver initialization sequence. 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6684c4231ea2f794d73bbb50b8d84e00c66a012a607Thomas Gleixner DBG(KERN_DEBUG "enable_irq(%d): eoi(%p, 0x%x)\n", d->irq, 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vi->eoi_addr, vi->eoi_data); 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iosapic_eoi(vi->eoi_addr, vi->eoi_data); 67151890613f2bfa70453a5cc22c91c63946dd311cdJames Bottomley} 67251890613f2bfa70453a5cc22c91c63946dd311cdJames Bottomley 6734c4231ea2f794d73bbb50b8d84e00c66a012a607Thomas Gleixnerstatic void iosapic_eoi_irq(struct irq_data *d) 67451890613f2bfa70453a5cc22c91c63946dd311cdJames Bottomley{ 6754c4231ea2f794d73bbb50b8d84e00c66a012a607Thomas Gleixner struct vector_info *vi = irq_data_get_irq_chip_data(d); 67651890613f2bfa70453a5cc22c91c63946dd311cdJames Bottomley 67751890613f2bfa70453a5cc22c91c63946dd311cdJames Bottomley iosapic_eoi(vi->eoi_addr, vi->eoi_data); 6784c4231ea2f794d73bbb50b8d84e00c66a012a607Thomas Gleixner cpu_eoi_irq(d); 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 681c2ab64d09815cc4d48347ee3679658f197455a2aJames Bottomley#ifdef CONFIG_SMP 6824c4231ea2f794d73bbb50b8d84e00c66a012a607Thomas Gleixnerstatic int iosapic_set_affinity_irq(struct irq_data *d, 6834c4231ea2f794d73bbb50b8d84e00c66a012a607Thomas Gleixner const struct cpumask *dest, bool force) 684c2ab64d09815cc4d48347ee3679658f197455a2aJames Bottomley{ 6854c4231ea2f794d73bbb50b8d84e00c66a012a607Thomas Gleixner struct vector_info *vi = irq_data_get_irq_chip_data(d); 686c2ab64d09815cc4d48347ee3679658f197455a2aJames Bottomley u32 d0, d1, dummy_d0; 687c2ab64d09815cc4d48347ee3679658f197455a2aJames Bottomley unsigned long flags; 6888b6649c575e0d8312f62fe643ae43558892da2e1Kyle McMartin int dest_cpu; 689c2ab64d09815cc4d48347ee3679658f197455a2aJames Bottomley 6904c4231ea2f794d73bbb50b8d84e00c66a012a607Thomas Gleixner dest_cpu = cpu_check_affinity(d, dest); 6918b6649c575e0d8312f62fe643ae43558892da2e1Kyle McMartin if (dest_cpu < 0) 692d5dedd4507d307eb3f35f21b6e16f336fdc0d82aYinghai Lu return -1; 693c2ab64d09815cc4d48347ee3679658f197455a2aJames Bottomley 6944c4231ea2f794d73bbb50b8d84e00c66a012a607Thomas Gleixner cpumask_copy(d->affinity, cpumask_of(dest_cpu)); 6954c4231ea2f794d73bbb50b8d84e00c66a012a607Thomas Gleixner vi->txn_addr = txn_affinity_addr(d->irq, dest_cpu); 696c2ab64d09815cc4d48347ee3679658f197455a2aJames Bottomley 697c2ab64d09815cc4d48347ee3679658f197455a2aJames Bottomley spin_lock_irqsave(&iosapic_lock, flags); 698c2ab64d09815cc4d48347ee3679658f197455a2aJames Bottomley /* d1 contains the destination CPU, so only want to set that 699c2ab64d09815cc4d48347ee3679658f197455a2aJames Bottomley * entry */ 700c2ab64d09815cc4d48347ee3679658f197455a2aJames Bottomley iosapic_rd_irt_entry(vi, &d0, &d1); 701c2ab64d09815cc4d48347ee3679658f197455a2aJames Bottomley iosapic_set_irt_data(vi, &dummy_d0, &d1); 702c2ab64d09815cc4d48347ee3679658f197455a2aJames Bottomley iosapic_wr_irt_entry(vi, d0, d1); 703c2ab64d09815cc4d48347ee3679658f197455a2aJames Bottomley spin_unlock_irqrestore(&iosapic_lock, flags); 704d5dedd4507d307eb3f35f21b6e16f336fdc0d82aYinghai Lu 705d5dedd4507d307eb3f35f21b6e16f336fdc0d82aYinghai Lu return 0; 706c2ab64d09815cc4d48347ee3679658f197455a2aJames Bottomley} 707c2ab64d09815cc4d48347ee3679658f197455a2aJames Bottomley#endif 708c2ab64d09815cc4d48347ee3679658f197455a2aJames Bottomley 709dfe07565021959f0f646e9e775810c1bfbe0f6d6Thomas Gleixnerstatic struct irq_chip iosapic_interrupt_type = { 7104c4231ea2f794d73bbb50b8d84e00c66a012a607Thomas Gleixner .name = "IO-SAPIC-level", 7114c4231ea2f794d73bbb50b8d84e00c66a012a607Thomas Gleixner .irq_unmask = iosapic_unmask_irq, 7124c4231ea2f794d73bbb50b8d84e00c66a012a607Thomas Gleixner .irq_mask = iosapic_mask_irq, 7134c4231ea2f794d73bbb50b8d84e00c66a012a607Thomas Gleixner .irq_ack = cpu_ack_irq, 7144c4231ea2f794d73bbb50b8d84e00c66a012a607Thomas Gleixner .irq_eoi = iosapic_eoi_irq, 715c2ab64d09815cc4d48347ee3679658f197455a2aJames Bottomley#ifdef CONFIG_SMP 7164c4231ea2f794d73bbb50b8d84e00c66a012a607Thomas Gleixner .irq_set_affinity = iosapic_set_affinity_irq, 717c2ab64d09815cc4d48347ee3679658f197455a2aJames Bottomley#endif 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint iosapic_fixup_irq(void *isi_obj, struct pci_dev *pcidev) 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct iosapic_info *isi = isi_obj; 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct irt_entry *irte = NULL; /* only used if PAT PDC */ 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct vector_info *vi; 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int isi_line; /* line used by device */ 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!isi) { 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING MODULE_NAME ": hpa not registered for %s\n", 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_name(pcidev)); 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SUPERIO 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * HACK ALERT! (non-compliant PCI device support) 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * All SuckyIO interrupts are routed through the PIC's on function 1. 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * But SuckyIO OHCI USB controller gets an IRT entry anyway because 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it advertises INT D for INT_PIN. Use that IRT entry to get the 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SuckyIO interrupt routing for PICs on function 1 (*BLEECCHH*). 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (is_superio_device(pcidev)) { 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We must call superio_fixup_irq() to register the pdev */ 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcidev->irq = superio_fixup_irq(pcidev); 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Don't return if need to program the IOSAPIC's IRT... */ 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (PCI_FUNC(pcidev->devfn) != SUPERIO_USB_FN) 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return pcidev->irq; 7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_SUPERIO */ 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* lookup IRT entry for isi/slot/pin set */ 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irte = iosapic_xlate_pin(isi, pcidev); 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!irte) { 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("iosapic: no IRTE for %s (IRQ not connected?)\n", 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_name(pcidev)); 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG_IRT("iosapic_fixup_irq(): irte %p %x %x %x %x %x %x %x %x\n", 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irte, 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irte->entry_type, 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irte->entry_length, 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irte->polarity_trigger, 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irte->src_bus_irq_devno, 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irte->src_bus_id, 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irte->src_seg_id, 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irte->dest_iosapic_intin, 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (u32) irte->dest_iosapic_addr); 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds isi_line = irte->dest_iosapic_intin; 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* get vector info for this input line */ 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vi = isi->isi_vector + isi_line; 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG_IRT("iosapic_fixup_irq: line %d vi 0x%p\n", isi_line, vi); 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If this IRQ line has already been setup, skip it */ 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (vi->irte) 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vi->irte = irte; 7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Allocate processor IRQ 7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * XXX/FIXME The txn_alloc_irq() code and related code should be 7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * moved to enable_irq(). That way we only allocate processor IRQ 7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bits for devices that actually have drivers claiming them. 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Right now we assign an IRQ to every PCI device present, 7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * regardless of whether it's used or not. 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vi->txn_irq = txn_alloc_irq(8); 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (vi->txn_irq < 0) 7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds panic("I/O sapic: couldn't get TXN IRQ\n"); 7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* enable_irq() will use txn_* to program IRdT */ 7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vi->txn_addr = txn_alloc_addr(vi->txn_irq); 7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vi->txn_data = txn_alloc_data(vi->txn_irq); 7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vi->eoi_addr = isi->addr + IOSAPIC_REG_EOI; 8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vi->eoi_data = cpu_to_le32(vi->txn_data); 8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cpu_claim_irq(vi->txn_irq, &iosapic_interrupt_type, vi); 8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out: 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcidev->irq = vi->txn_irq; 8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG_IRT("iosapic_fixup_irq() %d:%d %x %x line %d irq %d\n", 8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PCI_SLOT(pcidev->devfn), PCI_FUNC(pcidev->devfn), 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcidev->vendor, pcidev->device, isi_line, pcidev->irq); 8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return pcidev->irq; 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** squirrel away the I/O Sapic Version 8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/ 8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsiosapic_rd_version(struct iosapic_info *isi) 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return iosapic_read(isi->addr, IOSAPIC_REG_VERSION); 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** iosapic_register() is called by "drivers" with an integrated I/O SAPIC. 8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** Caller must be certain they have an I/O SAPIC and know its MMIO address. 8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** 8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** o allocate iosapic_info and add it to the list 8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** o read iosapic version and squirrel that away 8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** o read size of IRdT. 8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** o allocate and initialize isi_vector[] 8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** o allocate irq region 8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/ 8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid *iosapic_register(unsigned long hpa) 8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct iosapic_info *isi = NULL; 8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct irt_entry *irte = irt_cell; 8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct vector_info *vip; 8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cnt; /* track how many entries we've looked at */ 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Astro based platforms can only support PCI OLARD if they implement 8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PAT PDC. Legacy PDC omits LBAs with no PCI devices from the IRT. 8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Search the IRT and ignore iosapic's which aren't in the IRT. 8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (cnt=0; cnt < irt_num_entry; cnt++, irte++) { 8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds WARN_ON(IRT_IOSAPIC_TYPE != irte->entry_type); 8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (COMPARE_IRTE_ADDR(irte, hpa)) 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cnt >= irt_num_entry) { 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG("iosapic_register() ignoring 0x%lx (NOT FOUND)\n", hpa); 8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8585cbded585d129d0226cb48ac4202b253c781be26Robert P. J. Day isi = kzalloc(sizeof(struct iosapic_info), GFP_KERNEL); 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!isi) { 8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG(); 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8645076c15862644edb91d2e3436b2fa3e07b28385dHelge Deller isi->addr = ioremap_nocache(hpa, 4096); 8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds isi->isi_hpa = hpa; 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds isi->isi_version = iosapic_rd_version(isi); 8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds isi->isi_num_vectors = IOSAPIC_IRDT_MAX_ENTRY(isi->isi_version) + 1; 8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 869f8301041d7bdca3197d718518242eeba0c75352fJoe Perches vip = isi->isi_vector = kcalloc(isi->isi_num_vectors, 870f8301041d7bdca3197d718518242eeba0c75352fJoe Perches sizeof(struct vector_info), GFP_KERNEL); 8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (vip == NULL) { 8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(isi); 8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (cnt=0; cnt < isi->isi_num_vectors; cnt++, vip++) { 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vip->irqline = (unsigned char) cnt; 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vip->iosapic = isi; 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return isi; 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG_IOSAPIC 8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsiosapic_prt_irt(void *irt, long num_entry) 8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int i, *irp = (unsigned int *) irt; 8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG MODULE_NAME ": Interrupt Routing Table (%lx entries)\n", num_entry); 8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i=0; i<num_entry; i++, irp += 4) { 8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG "%p : %2d %.8x %.8x %.8x %.8x\n", 8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irp, i, irp[0], irp[1], irp[2], irp[3]); 8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsiosapic_prt_vi(struct vector_info *vi) 9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG MODULE_NAME ": vector_info[%d] is at %p\n", vi->irqline, vi); 9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG "\t\tstatus: %.4x\n", vi->status); 9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG "\t\ttxn_irq: %d\n", vi->txn_irq); 9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG "\t\ttxn_addr: %lx\n", vi->txn_addr); 9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG "\t\ttxn_data: %lx\n", vi->txn_data); 9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG "\t\teoi_addr: %p\n", vi->eoi_addr); 9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG "\t\teoi_data: %x\n", vi->eoi_data); 9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsiosapic_prt_isi(struct iosapic_info *isi) 9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG MODULE_NAME ": io_sapic_info at %p\n", isi); 9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG "\t\tisi_hpa: %lx\n", isi->isi_hpa); 9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG "\t\tisi_status: %x\n", isi->isi_status); 9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG "\t\tisi_version: %x\n", isi->isi_version); 9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG "\t\tisi_vector: %p\n", isi->isi_vector); 9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* DEBUG_IOSAPIC */ 924