| 1 | |
| 2 | |
| 3 | ** I/O Sapic Driver - PCI interrupt line support
|
| 4 | **
|
| 5 | ** (c) Copyright 1999 Grant Grundler
|
| 6 | ** (c) Copyright 1999 Hewlett-Packard Company
|
| 7 | **
|
| 8 | **
|
| 9 | ** The I/O sapic driver manages the Interrupt Redirection Table which is
|
| 10 | ** the control logic to convert PCI line based interrupts into a Message
|
| 11 | ** Signaled Interrupt (aka Transaction Based Interrupt, TBI).
|
| 12 | **
|
| 13 | ** Acronyms
|
| 14 | ** --------
|
| 15 | ** HPA Hard Physical Address (aka MMIO address)
|
| 16 | ** IRQ Interrupt ReQuest. Implies Line based interrupt.
|
| 17 | ** IRT Interrupt Routing Table (provided by PAT firmware)
|
| 18 | ** IRdT Interrupt Redirection Table. IRQ line to TXN ADDR/DATA
|
| 19 | ** table which is implemented in I/O SAPIC.
|
| 20 | ** ISR Interrupt Service Routine. aka Interrupt handler.
|
| 21 | ** MSI Message Signaled Interrupt. PCI 2.2 functionality.
|
| 22 | ** aka Transaction Based Interrupt (or TBI).
|
| 23 | ** PA Precision Architecture. HP's RISC architecture.
|
| 24 | ** RISC Reduced Instruction Set Computer.
|
| 25 | **
|
| 26 | **
|
| 27 | ** What's a Message Signalled Interrupt?
|
| 28 | ** -------------------------------------
|
| 29 | ** MSI is a write transaction which targets a processor and is similar
|
| 30 | ** to a processor write to memory or MMIO. MSIs can be generated by I/O
|
| 31 | ** devices as well as processors and require *architecture* to work.
|
| 32 | **
|
| 33 | ** PA only supports MSI. So I/O subsystems must either natively generate
|
| 34 | ** MSIs (e.g. GSC or HP-PB) or convert line based interrupts into MSIs
|
| 35 | ** (e.g. PCI and EISA). IA64 supports MSIs via a "local SAPIC" which
|
| 36 | ** acts on behalf of a processor.
|
| 37 | **
|
| 38 | ** MSI allows any I/O device to interrupt any processor. This makes
|
| 39 | ** load balancing of the interrupt processing possible on an SMP platform.
|
| 40 | ** Interrupts are also ordered WRT to DMA data. It's possible on I/O
|
| 41 | ** coherent systems to completely eliminate PIO reads from the interrupt
|
| 42 | ** path. The device and driver must be designed and implemented to
|
| 43 | ** guarantee all DMA has been issued (issues about atomicity here)
|
| 44 | ** before the MSI is issued. I/O status can then safely be read from
|
| 45 | ** DMA'd data by the ISR.
|
| 46 | **
|
| 47 | **
|
| 48 | ** PA Firmware
|
| 49 | ** -----------
|
| 50 | ** PA-RISC platforms have two fundamentally different types of firmware.
|
| 51 | ** For PCI devices, "Legacy" PDC initializes the "INTERRUPT_LINE" register
|
| 52 | ** and BARs similar to a traditional PC BIOS.
|
| 53 | ** The newer "PAT" firmware supports PDC calls which return tables.
|
| 54 | ** PAT firmware only initializes the PCI Console and Boot interface.
|
| 55 | ** With these tables, the OS can program all other PCI devices.
|
| 56 | **
|
| 57 | ** One such PAT PDC call returns the "Interrupt Routing Table" (IRT).
|
| 58 | ** The IRT maps each PCI slot's INTA-D "output" line to an I/O SAPIC
|
| 59 | ** input line. If the IRT is not available, this driver assumes
|
| 60 | ** INTERRUPT_LINE register has been programmed by firmware. The latter
|
| 61 | ** case also means online addition of PCI cards can NOT be supported
|
| 62 | ** even if HW support is present.
|
| 63 | **
|
| 64 | ** All platforms with PAT firmware to date (Oct 1999) use one Interrupt
|
| 65 | ** Routing Table for the entire platform.
|
| 66 | **
|
| 67 | ** Where's the iosapic?
|
| 68 | ** --------------------
|
| 69 | ** I/O sapic is part of the "Core Electronics Complex". And on HP platforms
|
| 70 | ** it's integrated as part of the PCI bus adapter, "lba". So no bus walk
|
| 71 | ** will discover I/O Sapic. I/O Sapic driver learns about each device
|
| 72 | ** when lba driver advertises the presence of the I/O sapic by calling
|
| 73 | ** iosapic_register().
|
| 74 | **
|
| 75 | **
|
| 76 | ** IRQ handling notes
|
| 77 | ** ------------------
|
| 78 | ** The IO-SAPIC can indicate to the CPU which interrupt was asserted.
|
| 79 | ** So, unlike the GSC-ASIC and Dino, we allocate one CPU interrupt per
|
| 80 | ** IO-SAPIC interrupt and call the device driver's handler directly.
|
| 81 | ** The IO-SAPIC driver hijacks the CPU interrupt handler so it can
|
| 82 | ** issue the End Of Interrupt command to the IO-SAPIC.
|
| 83 | **
|
| 84 | ** Overview of exported iosapic functions
|
| 85 | ** --------------------------------------
|
| 86 | ** (caveat: code isn't finished yet - this is just the plan)
|
| 87 | **
|
| 88 | ** iosapic_init:
|
| 89 | ** o initialize globals (lock, etc)
|
| 90 | ** o try to read IRT. Presence of IRT determines if this is
|
| 91 | ** a PAT platform or not.
|
| 92 | **
|
| 93 | ** iosapic_register():
|
| 94 | ** o create iosapic_info instance data structure
|
| 95 | ** o allocate vector_info array for this iosapic
|
| 96 | ** o initialize vector_info - read corresponding IRdT?
|
| 97 | **
|
| 98 | ** iosapic_xlate_pin: (only called by fixup_irq for PAT platform)
|
| 99 | ** o intr_pin = read cfg (INTERRUPT_PIN);
|
| 100 | ** o if (device under PCI-PCI bridge)
|
| 101 | ** translate slot/pin
|
| 102 | **
|
| 103 | ** iosapic_fixup_irq:
|
| 104 | ** o if PAT platform (IRT present)
|
| 105 | ** intr_pin = iosapic_xlate_pin(isi,pcidev):
|
| 106 | ** intr_line = find IRT entry(isi, PCI_SLOT(pcidev), intr_pin)
|
| 107 | ** save IRT entry into vector_info later
|
| 108 | ** write cfg INTERRUPT_LINE (with intr_line)?
|
| 109 | ** else
|
| 110 | ** intr_line = pcidev->irq
|
| 111 | ** IRT pointer = NULL
|
| 112 | ** endif
|
| 113 | ** o locate vector_info (needs: isi, intr_line)
|
| 114 | ** o allocate processor "irq" and get txn_addr/data
|
| 115 | ** o request_irq(processor_irq, iosapic_interrupt, vector_info,...)
|
| 116 | **
|
| 117 | ** iosapic_enable_irq:
|
| 118 | ** o clear any pending IRQ on that line
|
| 119 | ** o enable IRdT - call enable_irq(vector[line]->processor_irq)
|
| 120 | ** o write EOI in case line is already asserted.
|
| 121 | **
|
| 122 | ** iosapic_disable_irq:
|
| 123 | ** o disable IRdT - call disable_irq(vector[line]->processor_irq)
|
| 124 |
|
| 125 |
|
| 126 | #include <linux/pci.h>
|
| 127 |
|
| 128 | #include <asm/pdc.h>
|
| 129 | #include <asm/pdcpat.h>
|
| 130 | #ifdef CONFIG_SUPERIO
|
| 131 | #include <asm/superio.h>
|
| 132 | #endif
|
| 133 |
|
| 134 | #include <asm/ropes.h>
|
| 135 | #include "iosapic_private.h"
|
| 136 |
|
| 137 | #define MODULE_NAME "iosapic"
|
| 138 |
|
| 139 |
|
| 140 | #undef PCI_BRIDGE_FUNCS
|
| 141 | #undef DEBUG_IOSAPIC
|
| 142 | #undef DEBUG_IOSAPIC_IRT
|
| 143 |
|
| 144 |
|
| 145 | #ifdef DEBUG_IOSAPIC
|
| 146 | #define DBG(x...) printk(x)
|
| 147 | #else
|
| 148 | #define DBG(x...)
|
| 149 | #endif
|
| 150 |
|
| 151 | #ifdef DEBUG_IOSAPIC_IRT
|
| 152 | #define DBG_IRT(x...) printk(x)
|
| 153 | #else
|
| 154 | #define DBG_IRT(x...)
|
| 155 | #endif
|
| 156 |
|
| 157 | #ifdef CONFIG_64BIT
|
| 158 | #define COMPARE_IRTE_ADDR(irte, hpa) ((irte)->dest_iosapic_addr == (hpa))
|
| 159 | #else
|
| 160 | #define COMPARE_IRTE_ADDR(irte, hpa) \
|
| 161 | ((irte)->dest_iosapic_addr == ((hpa) | 0xffffffff00000000ULL))
|
| 162 | #endif
|
| 163 |
|
| 164 | #define IOSAPIC_REG_SELECT 0x00
|
| 165 | #define IOSAPIC_REG_WINDOW 0x10
|
| 166 | #define IOSAPIC_REG_EOI 0x40
|
| 167 |
|
| 168 | #define IOSAPIC_REG_VERSION 0x1
|
| 169 |
|
| 170 | #define IOSAPIC_IRDT_ENTRY(idx) (0x10+(idx)*2)
|
| 171 | #define IOSAPIC_IRDT_ENTRY_HI(idx) (0x11+(idx)*2)
|
| 172 |
|
| 173 | static inline unsigned int iosapic_read(void __iomem *iosapic, unsigned int reg)
|
| 174 | {
|
| 175 | writel(reg, iosapic + IOSAPIC_REG_SELECT);
|
| 176 | return readl(iosapic + IOSAPIC_REG_WINDOW);
|
| 177 | }
|
| 178 |
|
| 179 | static inline void iosapic_write(void __iomem *iosapic, unsigned int reg, u32 val)
|
| 180 | {
|
| 181 | writel(reg, iosapic + IOSAPIC_REG_SELECT);
|
| 182 | writel(val, iosapic + IOSAPIC_REG_WINDOW);
|
| 183 | }
|
| 184 |
|
| 185 | #define IOSAPIC_VERSION_MASK 0x000000ff
|
| 186 | #define IOSAPIC_VERSION(ver) ((int) (ver & IOSAPIC_VERSION_MASK))
|
| 187 |
|
| 188 | #define IOSAPIC_MAX_ENTRY_MASK 0x00ff0000
|
| 189 | #define IOSAPIC_MAX_ENTRY_SHIFT 0x10
|
| 190 | #define IOSAPIC_IRDT_MAX_ENTRY(ver) \
|
| 191 | (int) (((ver) & IOSAPIC_MAX_ENTRY_MASK) >> IOSAPIC_MAX_ENTRY_SHIFT)
|
| 192 |
|
| 193 |
|
| 194 | #define IOSAPIC_IRDT_ENABLE 0x10000
|
| 195 | #define IOSAPIC_IRDT_PO_LOW 0x02000
|
| 196 | #define IOSAPIC_IRDT_LEVEL_TRIG 0x08000
|
| 197 | #define IOSAPIC_IRDT_MODE_LPRI 0x00100
|
| 198 |
|
| 199 |
|
| 200 | #define IOSAPIC_IRDT_ID_EID_SHIFT 0x10
|
| 201 |
|
| 202 |
|
| 203 | static DEFINE_SPINLOCK(iosapic_lock);
|
| 204 |
|
| 205 | static inline void iosapic_eoi(__le32 __iomem *addr, __le32 data)
|
| 206 | {
|
| 207 | __raw_writel((__force u32)data, addr);
|
| 208 | }
|
| 209 |
|
| 210 | |
| 211 | ** REVISIT: future platforms may have more than one IRT.
|
| 212 | ** If so, the following three fields form a structure which
|
| 213 | ** then be linked into a list. Names are chosen to make searching
|
| 214 | ** for them easy - not necessarily accurate (eg "cell").
|
| 215 | **
|
| 216 | ** Alternative: iosapic_info could point to the IRT it's in.
|
| 217 | ** iosapic_register() could search a list of IRT's.
|
| 218 |
|
| 219 | static struct irt_entry *irt_cell;
|
| 220 | static size_t irt_num_entry;
|
| 221 |
|
| 222 | static struct irt_entry *iosapic_alloc_irt(int num_entries)
|
| 223 | {
|
| 224 | return kzalloc_objs(struct irt_entry, num_entries);
|
| 225 | }
|
| 226 |
|
| 227 | |
| 228 | * iosapic_load_irt - Fill in the interrupt routing table
|
| 229 | * @cell_num: The cell number of the CPU we're currently executing on
|
| 230 | * @irt: The address to place the new IRT at
|
| 231 | * @return The number of entries found
|
| 232 | *
|
| 233 | * The "Get PCI INT Routing Table Size" option returns the number of
|
| 234 | * entries in the PCI interrupt routing table for the cell specified
|
| 235 | * in the cell_number argument. The cell number must be for a cell
|
| 236 | * within the caller's protection domain.
|
| 237 | *
|
| 238 | * The "Get PCI INT Routing Table" option returns, for the cell
|
| 239 | * specified in the cell_number argument, the PCI interrupt routing
|
| 240 | * table in the caller allocated memory pointed to by mem_addr.
|
| 241 | * We assume the IRT only contains entries for I/O SAPIC and
|
| 242 | * calculate the size based on the size of I/O sapic entries.
|
| 243 | *
|
| 244 | * The PCI interrupt routing table entry format is derived from the
|
| 245 | * IA64 SAL Specification 2.4. The PCI interrupt routing table defines
|
| 246 | * the routing of PCI interrupt signals between the PCI device output
|
| 247 | * "pins" and the IO SAPICs' input "lines" (including core I/O PCI
|
| 248 | * devices). This table does NOT include information for devices/slots
|
| 249 | * behind PCI to PCI bridges. See PCI to PCI Bridge Architecture Spec.
|
| 250 | * for the architected method of routing of IRQ's behind PPB's.
|
| 251 |
|
| 252 |
|
| 253 |
|
| 254 | static int __init
|
| 255 | iosapic_load_irt(unsigned long cell_num, struct irt_entry **irt)
|
| 256 | {
|
| 257 | long status;
|
| 258 | struct irt_entry *table;
|
| 259 | unsigned long num_entries = 0UL;
|
| 260 |
|
| 261 | BUG_ON(!irt);
|
| 262 |
|
| 263 | if (is_pdc_pat()) {
|
| 264 |
|
| 265 | status = pdc_pat_get_irt_size(&num_entries, cell_num);
|
| 266 | DBG("calling get_irt_size (cell %ld) ", cell_num);
|
| 267 | DBG("returned %ld, entries: %lu\n", status, num_entries);
|
| 268 |
|
| 269 | BUG_ON(status != PDC_OK);
|
| 270 | BUG_ON(num_entries == 0);
|
| 271 |
|
| 272 | |
| 273 | ** allocate memory for interrupt routing table
|
| 274 | ** This interface isn't really right. We are assuming
|
| 275 | ** the contents of the table are exclusively
|
| 276 | ** for I/O sapic devices.
|
| 277 |
|
| 278 | table = iosapic_alloc_irt(num_entries);
|
| 279 | if (table == NULL) {
|
| 280 | printk(KERN_WARNING MODULE_NAME ": read_irt : can "
|
| 281 | "not alloc mem for IRT\n");
|
| 282 | return 0;
|
| 283 | }
|
| 284 |
|
| 285 |
|
| 286 | status = pdc_pat_get_irt(table, cell_num);
|
| 287 | DBG("pdc_pat_get_irt: %ld\n", status);
|
| 288 | WARN_ON(status != PDC_OK);
|
| 289 | } else {
|
| 290 | |
| 291 | ** C3000/J5000 (and similar) platforms with Sprockets PDC
|
| 292 | ** will return exactly one IRT for all iosapics.
|
| 293 | ** So if we have one, don't need to get it again.
|
| 294 |
|
| 295 | if (irt_cell)
|
| 296 | return 0;
|
| 297 |
|
| 298 |
|
| 299 | status = pdc_pci_irt_size(&num_entries, 0);
|
| 300 | DBG("pdc_pci_irt_size: %ld\n", status);
|
| 301 |
|
| 302 | if (status != PDC_OK) {
|
| 303 |
|
| 304 | return 0;
|
| 305 | }
|
| 306 |
|
| 307 | BUG_ON(num_entries == 0);
|
| 308 |
|
| 309 | table = iosapic_alloc_irt(num_entries);
|
| 310 | if (!table) {
|
| 311 | printk(KERN_WARNING MODULE_NAME ": read_irt : can "
|
| 312 | "not alloc mem for IRT\n");
|
| 313 | return 0;
|
| 314 | }
|
| 315 |
|
| 316 |
|
| 317 | status = pdc_pci_irt(num_entries, 0, table);
|
| 318 | BUG_ON(status != PDC_OK);
|
| 319 | }
|
| 320 |
|
| 321 |
|
| 322 | *irt = table;
|
| 323 |
|
| 324 | #ifdef DEBUG_IOSAPIC_IRT
|
| 325 | {
|
| 326 | struct irt_entry *p = table;
|
| 327 | int i;
|
| 328 |
|
| 329 | printk(MODULE_NAME " Interrupt Routing Table (cell %ld)\n", cell_num);
|
| 330 | printk(MODULE_NAME " start = 0x%px num_entries %ld entry_size %d\n",
|
| 331 | table,
|
| 332 | num_entries,
|
| 333 | (int) sizeof(struct irt_entry));
|
| 334 |
|
| 335 | for (i = 0 ; i < num_entries ; i++, p++) {
|
| 336 | printk(MODULE_NAME " %02x %02x %02x %02x %02x %02x %02x %02x %08x%08x\n",
|
| 337 | p->entry_type, p->entry_length, p->interrupt_type,
|
| 338 | p->polarity_trigger, p->src_bus_irq_devno, p->src_bus_id,
|
| 339 | p->src_seg_id, p->dest_iosapic_intin,
|
| 340 | ((u32 *) p)[2],
|
| 341 | ((u32 *) p)[3]
|
| 342 | );
|
| 343 | }
|
| 344 | }
|
| 345 | #endif
|
| 346 |
|
| 347 | return num_entries;
|
| 348 | }
|
| 349 |
|
| 350 |
|
| 351 | static int __init iosapic_init(void)
|
| 352 | {
|
| 353 | unsigned long cell = 0;
|
| 354 |
|
| 355 | #ifdef __LP64__
|
| 356 | if (is_pdc_pat()) {
|
| 357 | int status;
|
| 358 | struct pdc_pat_cell_num cell_info;
|
| 359 |
|
| 360 | status = pdc_pat_cell_get_number(&cell_info);
|
| 361 | if (status == PDC_OK) {
|
| 362 | cell = cell_info.cell_num;
|
| 363 | }
|
| 364 | }
|
| 365 | #endif
|
| 366 |
|
| 367 |
|
| 368 | irt_num_entry = iosapic_load_irt(cell, &irt_cell);
|
| 369 | if (irt_num_entry == 0)
|
| 370 | irt_cell = NULL;
|
| 371 |
|
| 372 | return 0;
|
| 373 | }
|
| 374 | arch_initcall(iosapic_init);
|
| 375 |
|
| 376 |
|
| 377 | |
| 378 | ** Return the IRT entry in case we need to look something else up.
|
| 379 |
|
| 380 | static struct irt_entry *
|
| 381 | irt_find_irqline(struct iosapic_info *isi, u8 slot, u8 intr_pin)
|
| 382 | {
|
| 383 | struct irt_entry *i = irt_cell;
|
| 384 | int cnt;
|
| 385 | u8 irq_devno = (slot << IRT_DEV_SHIFT) | (intr_pin-1);
|
| 386 |
|
| 387 | DBG_IRT("irt_find_irqline() SLOT %d pin %d\n", slot, intr_pin);
|
| 388 |
|
| 389 | for (cnt=0; cnt < irt_num_entry; cnt++, i++) {
|
| 390 |
|
| 391 | |
| 392 | ** Validate: entry_type, entry_length, interrupt_type
|
| 393 | **
|
| 394 | ** Difference between validate vs compare is the former
|
| 395 | ** should print debug info and is not expected to "fail"
|
| 396 | ** on current platforms.
|
| 397 |
|
| 398 | if (i->entry_type != IRT_IOSAPIC_TYPE) {
|
| 399 | DBG_IRT(KERN_WARNING MODULE_NAME ":find_irqline(0x%p): skipping entry %d type %d\n", i, cnt, i->entry_type);
|
| 400 | continue;
|
| 401 | }
|
| 402 |
|
| 403 | if (i->entry_length != IRT_IOSAPIC_LENGTH) {
|
| 404 | DBG_IRT(KERN_WARNING MODULE_NAME ":find_irqline(0x%p): skipping entry %d length %d\n", i, cnt, i->entry_length);
|
| 405 | continue;
|
| 406 | }
|
| 407 |
|
| 408 | if (i->interrupt_type != IRT_VECTORED_INTR) {
|
| 409 | DBG_IRT(KERN_WARNING MODULE_NAME ":find_irqline(0x%p): skipping entry %d interrupt_type %d\n", i, cnt, i->interrupt_type);
|
| 410 | continue;
|
| 411 | }
|
| 412 |
|
| 413 | if (!COMPARE_IRTE_ADDR(i, isi->isi_hpa))
|
| 414 | continue;
|
| 415 |
|
| 416 | if ((i->src_bus_irq_devno & IRT_IRQ_DEVNO_MASK) != irq_devno)
|
| 417 | continue;
|
| 418 |
|
| 419 | |
| 420 | ** Ignore: src_bus_id and rc_seg_id correlate with
|
| 421 | ** iosapic_info->isi_hpa on HP platforms.
|
| 422 | ** If needed, pass in "PFA" (aka config space addr)
|
| 423 | ** instead of slot.
|
| 424 |
|
| 425 |
|
| 426 |
|
| 427 | return i;
|
| 428 | }
|
| 429 |
|
| 430 | printk(KERN_WARNING MODULE_NAME ": 0x%lx : no IRT entry for slot %d, pin %d\n",
|
| 431 | isi->isi_hpa, slot, intr_pin);
|
| 432 | return NULL;
|
| 433 | }
|
| 434 |
|
| 435 |
|
| 436 | |
| 437 | ** xlate_pin() supports the skewing of IRQ lines done by subsidiary bridges.
|
| 438 | ** Legacy PDC already does this translation for us and stores it in INTR_LINE.
|
| 439 | **
|
| 440 | ** PAT PDC needs to basically do what legacy PDC does:
|
| 441 | ** o read PIN
|
| 442 | ** o adjust PIN in case device is "behind" a PPB
|
| 443 | ** (eg 4-port 100BT and SCSI/LAN "Combo Card")
|
| 444 | ** o convert slot/pin to I/O SAPIC input line.
|
| 445 | **
|
| 446 | ** HP platforms only support:
|
| 447 | ** o one level of skewing for any number of PPBs
|
| 448 | ** o only support PCI-PCI Bridges.
|
| 449 |
|
| 450 | static struct irt_entry *
|
| 451 | iosapic_xlate_pin(struct iosapic_info *isi, struct pci_dev *pcidev)
|
| 452 | {
|
| 453 | u8 intr_pin, intr_slot;
|
| 454 |
|
| 455 | pci_read_config_byte(pcidev, PCI_INTERRUPT_PIN, &intr_pin);
|
| 456 |
|
| 457 | DBG_IRT("iosapic_xlate_pin(%s) SLOT %d pin %d\n",
|
| 458 | pci_name(pcidev), PCI_SLOT(pcidev->devfn), intr_pin);
|
| 459 |
|
| 460 | if (intr_pin == 0) {
|
| 461 |
|
| 462 | return NULL;
|
| 463 | }
|
| 464 |
|
| 465 |
|
| 466 | if (pcidev->bus->parent) {
|
| 467 | |
| 468 | ** can lookup in the IRT.
|
| 469 |
|
| 470 | #ifdef PCI_BRIDGE_FUNCS
|
| 471 | |
| 472 | ** Proposal #1:
|
| 473 | **
|
| 474 | ** call implementation specific translation function
|
| 475 | ** This is architecturally "cleaner". HP-UX doesn't
|
| 476 | ** support other secondary bus types (eg. E/ISA) directly.
|
| 477 | ** May be needed for other processor (eg IA64) architectures
|
| 478 | ** or by some ambitous soul who wants to watch TV.
|
| 479 |
|
| 480 | if (pci_bridge_funcs->xlate_intr_line) {
|
| 481 | intr_pin = pci_bridge_funcs->xlate_intr_line(pcidev);
|
| 482 | }
|
| 483 | #else
|
| 484 | struct pci_bus *p = pcidev->bus;
|
| 485 | |
| 486 | ** Proposal #2:
|
| 487 | ** The "pin" is skewed ((pin + dev - 1) % 4).
|
| 488 | **
|
| 489 | ** This isn't very clean since I/O SAPIC must assume:
|
| 490 | ** - all platforms only have PCI busses.
|
| 491 | ** - only PCI-PCI bridge (eg not PCI-EISA, PCI-PCMCIA)
|
| 492 | ** - IRQ routing is only skewed once regardless of
|
| 493 | ** the number of PPB's between iosapic and device.
|
| 494 | ** (Bit3 expansion chassis follows this rule)
|
| 495 | **
|
| 496 | ** Advantage is it's really easy to implement.
|
| 497 |
|
| 498 | intr_pin = pci_swizzle_interrupt_pin(pcidev, intr_pin);
|
| 499 | #endif
|
| 500 |
|
| 501 | |
| 502 | * Locate the host slot of the PPB.
|
| 503 |
|
| 504 | while (p->parent->parent)
|
| 505 | p = p->parent;
|
| 506 |
|
| 507 | intr_slot = PCI_SLOT(p->self->devfn);
|
| 508 | } else {
|
| 509 | intr_slot = PCI_SLOT(pcidev->devfn);
|
| 510 | }
|
| 511 | DBG_IRT("iosapic_xlate_pin: bus %lld slot %d pin %d\n",
|
| 512 | pcidev->bus->busn_res.start, intr_slot, intr_pin);
|
| 513 |
|
| 514 | return irt_find_irqline(isi, intr_slot, intr_pin);
|
| 515 | }
|
| 516 |
|
| 517 | static void iosapic_rd_irt_entry(struct vector_info *vi , u32 *dp0, u32 *dp1)
|
| 518 | {
|
| 519 | struct iosapic_info *isp = vi->iosapic;
|
| 520 | u8 idx = vi->irqline;
|
| 521 |
|
| 522 | *dp0 = iosapic_read(isp->addr, IOSAPIC_IRDT_ENTRY(idx));
|
| 523 | *dp1 = iosapic_read(isp->addr, IOSAPIC_IRDT_ENTRY_HI(idx));
|
| 524 | }
|
| 525 |
|
| 526 |
|
| 527 | static void iosapic_wr_irt_entry(struct vector_info *vi, u32 dp0, u32 dp1)
|
| 528 | {
|
| 529 | struct iosapic_info *isp = vi->iosapic;
|
| 530 |
|
| 531 | DBG_IRT("iosapic_wr_irt_entry(): irq %d hpa %lx 0x%x 0x%x\n",
|
| 532 | vi->irqline, isp->isi_hpa, dp0, dp1);
|
| 533 |
|
| 534 | iosapic_write(isp->addr, IOSAPIC_IRDT_ENTRY(vi->irqline), dp0);
|
| 535 |
|
| 536 |
|
| 537 | dp0 = readl(isp->addr+IOSAPIC_REG_WINDOW);
|
| 538 |
|
| 539 | iosapic_write(isp->addr, IOSAPIC_IRDT_ENTRY_HI(vi->irqline), dp1);
|
| 540 |
|
| 541 |
|
| 542 | dp1 = readl(isp->addr+IOSAPIC_REG_WINDOW);
|
| 543 | }
|
| 544 |
|
| 545 | |
| 546 | ** set_irt prepares the data (dp0, dp1) according to the vector_info
|
| 547 | ** and target cpu (id_eid). dp0/dp1 are then used to program I/O SAPIC
|
| 548 | ** IRdT for the given "vector" (aka IRQ line).
|
| 549 |
|
| 550 | static void
|
| 551 | iosapic_set_irt_data( struct vector_info *vi, u32 *dp0, u32 *dp1)
|
| 552 | {
|
| 553 | u32 mode = 0;
|
| 554 | struct irt_entry *p = vi->irte;
|
| 555 |
|
| 556 | if ((p->polarity_trigger & IRT_PO_MASK) == IRT_ACTIVE_LO)
|
| 557 | mode |= IOSAPIC_IRDT_PO_LOW;
|
| 558 |
|
| 559 | if (((p->polarity_trigger >> IRT_EL_SHIFT) & IRT_EL_MASK) == IRT_LEVEL_TRIG)
|
| 560 | mode |= IOSAPIC_IRDT_LEVEL_TRIG;
|
| 561 |
|
| 562 | |
| 563 | ** IA64 REVISIT
|
| 564 | ** PA doesn't support EXTINT or LPRIO bits.
|
| 565 |
|
| 566 |
|
| 567 | *dp0 = mode | (u32) vi->txn_data;
|
| 568 |
|
| 569 | |
| 570 | ** Extracting id_eid isn't a real clean way of getting it.
|
| 571 | ** But the encoding is the same for both PA and IA64 platforms.
|
| 572 |
|
| 573 | if (is_pdc_pat()) {
|
| 574 | |
| 575 | ** PAT PDC just hands it to us "right".
|
| 576 | ** txn_addr comes from cpu_data[x].txn_addr.
|
| 577 |
|
| 578 | *dp1 = (u32) (vi->txn_addr);
|
| 579 | } else {
|
| 580 | |
| 581 | ** eg if base_addr == 0xfffa0000),
|
| 582 | ** we want to get 0xa0ff0000.
|
| 583 | **
|
| 584 | ** eid 0x0ff00000 -> 0x00ff0000
|
| 585 | ** id 0x000ff000 -> 0xff000000
|
| 586 |
|
| 587 | *dp1 = (((u32)vi->txn_addr & 0x0ff00000) >> 4) |
|
| 588 | (((u32)vi->txn_addr & 0x000ff000) << 12);
|
| 589 | }
|
| 590 | DBG_IRT("iosapic_set_irt_data(): 0x%x 0x%x\n", *dp0, *dp1);
|
| 591 | }
|
| 592 |
|
| 593 |
|
| 594 | static void iosapic_mask_irq(struct irq_data *d)
|
| 595 | {
|
| 596 | unsigned long flags;
|
| 597 | struct vector_info *vi = irq_data_get_irq_chip_data(d);
|
| 598 | u32 d0, d1;
|
| 599 |
|
| 600 | spin_lock_irqsave(&iosapic_lock, flags);
|
| 601 | iosapic_rd_irt_entry(vi, &d0, &d1);
|
| 602 | d0 |= IOSAPIC_IRDT_ENABLE;
|
| 603 | iosapic_wr_irt_entry(vi, d0, d1);
|
| 604 | spin_unlock_irqrestore(&iosapic_lock, flags);
|
| 605 | }
|
| 606 |
|
| 607 | static void iosapic_unmask_irq(struct irq_data *d)
|
| 608 | {
|
| 609 | struct vector_info *vi = irq_data_get_irq_chip_data(d);
|
| 610 | u32 d0, d1;
|
| 611 |
|
| 612 |
|
| 613 | WARN_ON(vi->txn_irq == 0);
|
| 614 |
|
| 615 | iosapic_set_irt_data(vi, &d0, &d1);
|
| 616 | iosapic_wr_irt_entry(vi, d0, d1);
|
| 617 |
|
| 618 | #ifdef DEBUG_IOSAPIC_IRT
|
| 619 | {
|
| 620 | u32 *t = (u32 *) ((ulong) vi->eoi_addr & ~0xffUL);
|
| 621 | printk("iosapic_enable_irq(): regs %p", vi->eoi_addr);
|
| 622 | for ( ; t < vi->eoi_addr; t++)
|
| 623 | printk(" %x", readl(t));
|
| 624 | printk("\n");
|
| 625 | }
|
| 626 |
|
| 627 | printk("iosapic_enable_irq(): sel ");
|
| 628 | {
|
| 629 | struct iosapic_info *isp = vi->iosapic;
|
| 630 |
|
| 631 | for (d0=0x10; d0<0x1e; d0++) {
|
| 632 | d1 = iosapic_read(isp->addr, d0);
|
| 633 | printk(" %x", d1);
|
| 634 | }
|
| 635 | }
|
| 636 | printk("\n");
|
| 637 | #endif
|
| 638 |
|
| 639 | |
| 640 | * Issuing I/O SAPIC an EOI causes an interrupt IFF IRQ line is
|
| 641 | * asserted. IRQ generally should not be asserted when a driver
|
| 642 | * enables their IRQ. It can lead to "interesting" race conditions
|
| 643 | * in the driver initialization sequence.
|
| 644 |
|
| 645 | DBG(KERN_DEBUG "enable_irq(%d): eoi(%p, 0x%x)\n", d->irq,
|
| 646 | vi->eoi_addr, vi->eoi_data);
|
| 647 | iosapic_eoi(vi->eoi_addr, vi->eoi_data);
|
| 648 | }
|
| 649 |
|
| 650 | static void iosapic_eoi_irq(struct irq_data *d)
|
| 651 | {
|
| 652 | struct vector_info *vi = irq_data_get_irq_chip_data(d);
|
| 653 |
|
| 654 | iosapic_eoi(vi->eoi_addr, vi->eoi_data);
|
| 655 | cpu_eoi_irq(d);
|
| 656 | }
|
| 657 |
|
| 658 | #ifdef CONFIG_SMP
|
| 659 | static int iosapic_set_affinity_irq(struct irq_data *d,
|
| 660 | const struct cpumask *dest, bool force)
|
| 661 | {
|
| 662 | struct vector_info *vi = irq_data_get_irq_chip_data(d);
|
| 663 | u32 d0, d1, dummy_d0;
|
| 664 | unsigned long flags;
|
| 665 | int dest_cpu;
|
| 666 |
|
| 667 | dest_cpu = cpu_check_affinity(d, dest);
|
| 668 | if (dest_cpu < 0)
|
| 669 | return -1;
|
| 670 |
|
| 671 | irq_data_update_affinity(d, cpumask_of(dest_cpu));
|
| 672 | vi->txn_addr = txn_affinity_addr(d->irq, dest_cpu);
|
| 673 |
|
| 674 | spin_lock_irqsave(&iosapic_lock, flags);
|
| 675 | |
| 676 | * entry
|
| 677 | iosapic_rd_irt_entry(vi, &d0, &d1);
|
| 678 | iosapic_set_irt_data(vi, &dummy_d0, &d1);
|
| 679 | iosapic_wr_irt_entry(vi, d0, d1);
|
| 680 | spin_unlock_irqrestore(&iosapic_lock, flags);
|
| 681 |
|
| 682 | return 0;
|
| 683 | }
|
| 684 | #endif
|
| 685 |
|
| 686 | static struct irq_chip iosapic_interrupt_type = {
|
| 687 | .name = "IO-SAPIC-level",
|
| 688 | .irq_unmask = iosapic_unmask_irq,
|
| 689 | .irq_mask = iosapic_mask_irq,
|
| 690 | .irq_ack = cpu_ack_irq,
|
| 691 | .irq_eoi = iosapic_eoi_irq,
|
| 692 | #ifdef CONFIG_SMP
|
| 693 | .irq_set_affinity = iosapic_set_affinity_irq,
|
| 694 | #endif
|
| 695 | };
|
| 696 |
|
| 697 | int iosapic_fixup_irq(void *isi_obj, struct pci_dev *pcidev)
|
| 698 | {
|
| 699 | struct iosapic_info *isi = isi_obj;
|
| 700 | struct irt_entry *irte = NULL;
|
| 701 | struct vector_info *vi;
|
| 702 | int isi_line;
|
| 703 |
|
| 704 | if (!isi) {
|
| 705 | printk(KERN_WARNING MODULE_NAME ": hpa not registered for %s\n",
|
| 706 | pci_name(pcidev));
|
| 707 | return -1;
|
| 708 | }
|
| 709 |
|
| 710 | #ifdef CONFIG_SUPERIO
|
| 711 | |
| 712 | * HACK ALERT! (non-compliant PCI device support)
|
| 713 | *
|
| 714 | * All SuckyIO interrupts are routed through the PIC's on function 1.
|
| 715 | * But SuckyIO OHCI USB controller gets an IRT entry anyway because
|
| 716 | * it advertises INT D for INT_PIN. Use that IRT entry to get the
|
| 717 | * SuckyIO interrupt routing for PICs on function 1 (*BLEECCHH*).
|
| 718 |
|
| 719 | if (is_superio_device(pcidev)) {
|
| 720 |
|
| 721 | pcidev->irq = superio_fixup_irq(pcidev);
|
| 722 |
|
| 723 |
|
| 724 | if (PCI_FUNC(pcidev->devfn) != SUPERIO_USB_FN)
|
| 725 | return pcidev->irq;
|
| 726 | }
|
| 727 | #endif
|
| 728 |
|
| 729 |
|
| 730 | irte = iosapic_xlate_pin(isi, pcidev);
|
| 731 | if (!irte) {
|
| 732 | printk("iosapic: no IRTE for %s (IRQ not connected?)\n",
|
| 733 | pci_name(pcidev));
|
| 734 | return -1;
|
| 735 | }
|
| 736 | DBG_IRT("iosapic_fixup_irq(): irte %px %02x %02x %02x %02x %02x %02x %02x %04llx\n",
|
| 737 | irte,
|
| 738 | irte->entry_type,
|
| 739 | irte->entry_length,
|
| 740 | irte->polarity_trigger,
|
| 741 | irte->src_bus_irq_devno,
|
| 742 | irte->src_bus_id,
|
| 743 | irte->src_seg_id,
|
| 744 | irte->dest_iosapic_intin,
|
| 745 | irte->dest_iosapic_addr);
|
| 746 | isi_line = irte->dest_iosapic_intin;
|
| 747 |
|
| 748 |
|
| 749 | vi = isi->isi_vector + isi_line;
|
| 750 | DBG_IRT("iosapic_fixup_irq: line %d vi 0x%px\n", isi_line, vi);
|
| 751 |
|
| 752 |
|
| 753 | if (vi->irte)
|
| 754 | goto out;
|
| 755 |
|
| 756 | vi->irte = irte;
|
| 757 |
|
| 758 | |
| 759 | * Allocate processor IRQ
|
| 760 | *
|
| 761 | * XXX/FIXME The txn_alloc_irq() code and related code should be
|
| 762 | * moved to enable_irq(). That way we only allocate processor IRQ
|
| 763 | * bits for devices that actually have drivers claiming them.
|
| 764 | * Right now we assign an IRQ to every PCI device present,
|
| 765 | * regardless of whether it's used or not.
|
| 766 |
|
| 767 | vi->txn_irq = txn_alloc_irq(8);
|
| 768 |
|
| 769 | if (vi->txn_irq < 0)
|
| 770 | panic("I/O sapic: couldn't get TXN IRQ\n");
|
| 771 |
|
| 772 |
|
| 773 | vi->txn_addr = txn_alloc_addr(vi->txn_irq);
|
| 774 | vi->txn_data = txn_alloc_data(vi->txn_irq);
|
| 775 | DBG_IRT("iosapic_fixup_irq() TXN: 0x%lx 0x%x\n",
|
| 776 | vi->txn_addr, vi->txn_data);
|
| 777 |
|
| 778 | vi->eoi_addr = isi->addr + IOSAPIC_REG_EOI;
|
| 779 | vi->eoi_data = cpu_to_le32(vi->txn_data);
|
| 780 |
|
| 781 | cpu_claim_irq(vi->txn_irq, &iosapic_interrupt_type, vi);
|
| 782 |
|
| 783 | out:
|
| 784 | pcidev->irq = vi->txn_irq;
|
| 785 |
|
| 786 | DBG_IRT("iosapic_fixup_irq() %d:%d %x %x line %d irq %d\n",
|
| 787 | PCI_SLOT(pcidev->devfn), PCI_FUNC(pcidev->devfn),
|
| 788 | pcidev->vendor, pcidev->device, isi_line, pcidev->irq);
|
| 789 |
|
| 790 | return pcidev->irq;
|
| 791 | }
|
| 792 |
|
| 793 | static struct iosapic_info *iosapic_list;
|
| 794 |
|
| 795 | #ifdef CONFIG_64BIT
|
| 796 | int iosapic_serial_irq(struct parisc_device *dev)
|
| 797 | {
|
| 798 | struct iosapic_info *isi;
|
| 799 | struct irt_entry *irte;
|
| 800 | struct vector_info *vi;
|
| 801 | int cnt;
|
| 802 | int intin;
|
| 803 |
|
| 804 | intin = (dev->mod_info >> 24) & 15;
|
| 805 |
|
| 806 |
|
| 807 | for (cnt = 0; cnt < irt_num_entry; cnt++) {
|
| 808 | irte = &irt_cell[cnt];
|
| 809 | if (COMPARE_IRTE_ADDR(irte, dev->mod0) &&
|
| 810 | irte->dest_iosapic_intin == intin)
|
| 811 | break;
|
| 812 | }
|
| 813 | if (cnt >= irt_num_entry)
|
| 814 | return 0;
|
| 815 |
|
| 816 | DBG_IRT("iosapic_serial_irq(): irte %p %x %x %x %x %x %x %x %x\n",
|
| 817 | irte,
|
| 818 | irte->entry_type,
|
| 819 | irte->entry_length,
|
| 820 | irte->polarity_trigger,
|
| 821 | irte->src_bus_irq_devno,
|
| 822 | irte->src_bus_id,
|
| 823 | irte->src_seg_id,
|
| 824 | irte->dest_iosapic_intin,
|
| 825 | (u32) irte->dest_iosapic_addr);
|
| 826 |
|
| 827 |
|
| 828 | for (isi = iosapic_list; isi; isi = isi->isi_next)
|
| 829 | if (isi->isi_hpa == dev->mod0)
|
| 830 | break;
|
| 831 | if (!isi)
|
| 832 | return 0;
|
| 833 |
|
| 834 |
|
| 835 | vi = isi->isi_vector + intin;
|
| 836 | DBG_IRT("iosapic_serial_irq: line %d vi 0x%p\n", intin, vi);
|
| 837 |
|
| 838 |
|
| 839 | if (vi->irte)
|
| 840 | goto out;
|
| 841 |
|
| 842 | vi->irte = irte;
|
| 843 |
|
| 844 | |
| 845 | * Allocate processor IRQ
|
| 846 | *
|
| 847 | * XXX/FIXME The txn_alloc_irq() code and related code should be
|
| 848 | * moved to enable_irq(). That way we only allocate processor IRQ
|
| 849 | * bits for devices that actually have drivers claiming them.
|
| 850 | * Right now we assign an IRQ to every PCI device present,
|
| 851 | * regardless of whether it's used or not.
|
| 852 |
|
| 853 | vi->txn_irq = txn_alloc_irq(8);
|
| 854 |
|
| 855 | if (vi->txn_irq < 0)
|
| 856 | panic("I/O sapic: couldn't get TXN IRQ\n");
|
| 857 |
|
| 858 |
|
| 859 | vi->txn_addr = txn_alloc_addr(vi->txn_irq);
|
| 860 | vi->txn_data = txn_alloc_data(vi->txn_irq);
|
| 861 |
|
| 862 | vi->eoi_addr = isi->addr + IOSAPIC_REG_EOI;
|
| 863 | vi->eoi_data = cpu_to_le32(vi->txn_data);
|
| 864 |
|
| 865 | cpu_claim_irq(vi->txn_irq, &iosapic_interrupt_type, vi);
|
| 866 |
|
| 867 | out:
|
| 868 |
|
| 869 | return vi->txn_irq;
|
| 870 | }
|
| 871 | EXPORT_SYMBOL(iosapic_serial_irq);
|
| 872 | #endif
|
| 873 |
|
| 874 |
|
| 875 | |
| 876 | ** squirrel away the I/O Sapic Version
|
| 877 |
|
| 878 | static unsigned int
|
| 879 | iosapic_rd_version(struct iosapic_info *isi)
|
| 880 | {
|
| 881 | return iosapic_read(isi->addr, IOSAPIC_REG_VERSION);
|
| 882 | }
|
| 883 |
|
| 884 |
|
| 885 | |
| 886 | ** iosapic_register() is called by "drivers" with an integrated I/O SAPIC.
|
| 887 | ** Caller must be certain they have an I/O SAPIC and know its MMIO address.
|
| 888 | **
|
| 889 | ** o allocate iosapic_info and add it to the list
|
| 890 | ** o read iosapic version and squirrel that away
|
| 891 | ** o read size of IRdT.
|
| 892 | ** o allocate and initialize isi_vector[]
|
| 893 | ** o allocate irq region
|
| 894 |
|
| 895 | void *iosapic_register(unsigned long hpa, void __iomem *vaddr)
|
| 896 | {
|
| 897 | struct iosapic_info *isi = NULL;
|
| 898 | struct irt_entry *irte = irt_cell;
|
| 899 | struct vector_info *vip;
|
| 900 | int cnt;
|
| 901 |
|
| 902 | |
| 903 | * Astro based platforms can only support PCI OLARD if they implement
|
| 904 | * PAT PDC. Legacy PDC omits LBAs with no PCI devices from the IRT.
|
| 905 | * Search the IRT and ignore iosapic's which aren't in the IRT.
|
| 906 |
|
| 907 | for (cnt=0; cnt < irt_num_entry; cnt++, irte++) {
|
| 908 | WARN_ON(IRT_IOSAPIC_TYPE != irte->entry_type);
|
| 909 | if (COMPARE_IRTE_ADDR(irte, hpa))
|
| 910 | break;
|
| 911 | }
|
| 912 |
|
| 913 | if (cnt >= irt_num_entry) {
|
| 914 | DBG("iosapic_register() ignoring 0x%lx (NOT FOUND)\n", hpa);
|
| 915 | return NULL;
|
| 916 | }
|
| 917 |
|
| 918 | isi = kzalloc_obj(struct iosapic_info);
|
| 919 | if (!isi) {
|
| 920 | BUG();
|
| 921 | return NULL;
|
| 922 | }
|
| 923 |
|
| 924 | isi->addr = vaddr;
|
| 925 | isi->isi_hpa = hpa;
|
| 926 | isi->isi_version = iosapic_rd_version(isi);
|
| 927 | isi->isi_num_vectors = IOSAPIC_IRDT_MAX_ENTRY(isi->isi_version) + 1;
|
| 928 | DBG_IRT("iosapic_register: num vectors = %d\n", isi->isi_num_vectors);
|
| 929 |
|
| 930 | vip = isi->isi_vector = kzalloc_objs(struct vector_info,
|
| 931 | isi->isi_num_vectors);
|
| 932 | if (vip == NULL) {
|
| 933 | kfree(isi);
|
| 934 | return NULL;
|
| 935 | }
|
| 936 |
|
| 937 | for (cnt=0; cnt < isi->isi_num_vectors; cnt++, vip++) {
|
| 938 | vip->irqline = (unsigned char) cnt;
|
| 939 | vip->iosapic = isi;
|
| 940 | }
|
| 941 | isi->isi_next = iosapic_list;
|
| 942 | iosapic_list = isi;
|
| 943 | return isi;
|
| 944 | }
|
| 945 |
|
| 946 |
|
| 947 | #ifdef DEBUG_IOSAPIC
|
| 948 |
|
| 949 | static void
|
| 950 | iosapic_prt_irt(void *irt, long num_entry)
|
| 951 | {
|
| 952 | unsigned int i, *irp = (unsigned int *) irt;
|
| 953 |
|
| 954 |
|
| 955 | printk(KERN_DEBUG MODULE_NAME ": Interrupt Routing Table (%lx entries)\n", num_entry);
|
| 956 |
|
| 957 | for (i=0; i<num_entry; i++, irp += 4) {
|
| 958 | printk(KERN_DEBUG "%p : %2d %.8x %.8x %.8x %.8x\n",
|
| 959 | irp, i, irp[0], irp[1], irp[2], irp[3]);
|
| 960 | }
|
| 961 | }
|
| 962 |
|
| 963 |
|
| 964 | static void
|
| 965 | iosapic_prt_vi(struct vector_info *vi)
|
| 966 | {
|
| 967 | printk(KERN_DEBUG MODULE_NAME ": vector_info[%d] is at %p\n", vi->irqline, vi);
|
| 968 | printk(KERN_DEBUG "\t\tstatus: %.4x\n", vi->status);
|
| 969 | printk(KERN_DEBUG "\t\ttxn_irq: %d\n", vi->txn_irq);
|
| 970 | printk(KERN_DEBUG "\t\ttxn_addr: %lx\n", vi->txn_addr);
|
| 971 | printk(KERN_DEBUG "\t\ttxn_data: %lx\n", vi->txn_data);
|
| 972 | printk(KERN_DEBUG "\t\teoi_addr: %p\n", vi->eoi_addr);
|
| 973 | printk(KERN_DEBUG "\t\teoi_data: %x\n", vi->eoi_data);
|
| 974 | }
|
| 975 |
|
| 976 |
|
| 977 | static void
|
| 978 | iosapic_prt_isi(struct iosapic_info *isi)
|
| 979 | {
|
| 980 | printk(KERN_DEBUG MODULE_NAME ": io_sapic_info at %p\n", isi);
|
| 981 | printk(KERN_DEBUG "\t\tisi_hpa: %lx\n", isi->isi_hpa);
|
| 982 | printk(KERN_DEBUG "\t\tisi_status: %x\n", isi->isi_status);
|
| 983 | printk(KERN_DEBUG "\t\tisi_version: %x\n", isi->isi_version);
|
| 984 | printk(KERN_DEBUG "\t\tisi_vector: %p\n", isi->isi_vector);
|
| 985 | }
|
| 986 | #endif
|