18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/arch/alpha/kernel/sys_mikasa.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 1995 David A Rusling 68c2ecf20Sopenharmony_ci * Copyright (C) 1996 Jay A Estabrook 78c2ecf20Sopenharmony_ci * Copyright (C) 1998, 1999 Richard Henderson 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Code supporting the MIKASA (AlphaServer 1000). 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/kernel.h> 138c2ecf20Sopenharmony_ci#include <linux/types.h> 148c2ecf20Sopenharmony_ci#include <linux/mm.h> 158c2ecf20Sopenharmony_ci#include <linux/sched.h> 168c2ecf20Sopenharmony_ci#include <linux/pci.h> 178c2ecf20Sopenharmony_ci#include <linux/init.h> 188c2ecf20Sopenharmony_ci#include <linux/bitops.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include <asm/ptrace.h> 218c2ecf20Sopenharmony_ci#include <asm/mce.h> 228c2ecf20Sopenharmony_ci#include <asm/dma.h> 238c2ecf20Sopenharmony_ci#include <asm/irq.h> 248c2ecf20Sopenharmony_ci#include <asm/mmu_context.h> 258c2ecf20Sopenharmony_ci#include <asm/io.h> 268c2ecf20Sopenharmony_ci#include <asm/core_apecs.h> 278c2ecf20Sopenharmony_ci#include <asm/core_cia.h> 288c2ecf20Sopenharmony_ci#include <asm/tlbflush.h> 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#include "proto.h" 318c2ecf20Sopenharmony_ci#include "irq_impl.h" 328c2ecf20Sopenharmony_ci#include "pci_impl.h" 338c2ecf20Sopenharmony_ci#include "machvec_impl.h" 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci/* Note mask bit is true for ENABLED irqs. */ 378c2ecf20Sopenharmony_cistatic int cached_irq_mask; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic inline void 408c2ecf20Sopenharmony_cimikasa_update_irq_hw(int mask) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci outw(mask, 0x536); 438c2ecf20Sopenharmony_ci} 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic inline void 468c2ecf20Sopenharmony_cimikasa_enable_irq(struct irq_data *d) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci mikasa_update_irq_hw(cached_irq_mask |= 1 << (d->irq - 16)); 498c2ecf20Sopenharmony_ci} 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic void 528c2ecf20Sopenharmony_cimikasa_disable_irq(struct irq_data *d) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci mikasa_update_irq_hw(cached_irq_mask &= ~(1 << (d->irq - 16))); 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic struct irq_chip mikasa_irq_type = { 588c2ecf20Sopenharmony_ci .name = "MIKASA", 598c2ecf20Sopenharmony_ci .irq_unmask = mikasa_enable_irq, 608c2ecf20Sopenharmony_ci .irq_mask = mikasa_disable_irq, 618c2ecf20Sopenharmony_ci .irq_mask_ack = mikasa_disable_irq, 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic void 658c2ecf20Sopenharmony_cimikasa_device_interrupt(unsigned long vector) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci unsigned long pld; 688c2ecf20Sopenharmony_ci unsigned int i; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci /* Read the interrupt summary registers */ 718c2ecf20Sopenharmony_ci pld = (((~inw(0x534) & 0x0000ffffUL) << 16) 728c2ecf20Sopenharmony_ci | (((unsigned long) inb(0xa0)) << 8) 738c2ecf20Sopenharmony_ci | inb(0x20)); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci /* 768c2ecf20Sopenharmony_ci * Now for every possible bit set, work through them and call 778c2ecf20Sopenharmony_ci * the appropriate interrupt handler. 788c2ecf20Sopenharmony_ci */ 798c2ecf20Sopenharmony_ci while (pld) { 808c2ecf20Sopenharmony_ci i = ffz(~pld); 818c2ecf20Sopenharmony_ci pld &= pld - 1; /* clear least bit set */ 828c2ecf20Sopenharmony_ci if (i < 16) { 838c2ecf20Sopenharmony_ci isa_device_interrupt(vector); 848c2ecf20Sopenharmony_ci } else { 858c2ecf20Sopenharmony_ci handle_irq(i); 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci } 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic void __init 918c2ecf20Sopenharmony_cimikasa_init_irq(void) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci long i; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci if (alpha_using_srm) 968c2ecf20Sopenharmony_ci alpha_mv.device_interrupt = srm_device_interrupt; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci mikasa_update_irq_hw(0); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci for (i = 16; i < 32; ++i) { 1018c2ecf20Sopenharmony_ci irq_set_chip_and_handler(i, &mikasa_irq_type, 1028c2ecf20Sopenharmony_ci handle_level_irq); 1038c2ecf20Sopenharmony_ci irq_set_status_flags(i, IRQ_LEVEL); 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci init_i8259a_irqs(); 1078c2ecf20Sopenharmony_ci common_init_isa_dma(); 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci/* 1128c2ecf20Sopenharmony_ci * PCI Fixup configuration. 1138c2ecf20Sopenharmony_ci * 1148c2ecf20Sopenharmony_ci * Summary @ 0x536: 1158c2ecf20Sopenharmony_ci * Bit Meaning 1168c2ecf20Sopenharmony_ci * 0 Interrupt Line A from slot 0 1178c2ecf20Sopenharmony_ci * 1 Interrupt Line B from slot 0 1188c2ecf20Sopenharmony_ci * 2 Interrupt Line C from slot 0 1198c2ecf20Sopenharmony_ci * 3 Interrupt Line D from slot 0 1208c2ecf20Sopenharmony_ci * 4 Interrupt Line A from slot 1 1218c2ecf20Sopenharmony_ci * 5 Interrupt line B from slot 1 1228c2ecf20Sopenharmony_ci * 6 Interrupt Line C from slot 1 1238c2ecf20Sopenharmony_ci * 7 Interrupt Line D from slot 1 1248c2ecf20Sopenharmony_ci * 8 Interrupt Line A from slot 2 1258c2ecf20Sopenharmony_ci * 9 Interrupt Line B from slot 2 1268c2ecf20Sopenharmony_ci *10 Interrupt Line C from slot 2 1278c2ecf20Sopenharmony_ci *11 Interrupt Line D from slot 2 1288c2ecf20Sopenharmony_ci *12 NCR 810 SCSI 1298c2ecf20Sopenharmony_ci *13 Power Supply Fail 1308c2ecf20Sopenharmony_ci *14 Temperature Warn 1318c2ecf20Sopenharmony_ci *15 Reserved 1328c2ecf20Sopenharmony_ci * 1338c2ecf20Sopenharmony_ci * The device to slot mapping looks like: 1348c2ecf20Sopenharmony_ci * 1358c2ecf20Sopenharmony_ci * Slot Device 1368c2ecf20Sopenharmony_ci * 6 NCR SCSI controller 1378c2ecf20Sopenharmony_ci * 7 Intel PCI-EISA bridge chip 1388c2ecf20Sopenharmony_ci * 11 PCI on board slot 0 1398c2ecf20Sopenharmony_ci * 12 PCI on board slot 1 1408c2ecf20Sopenharmony_ci * 13 PCI on board slot 2 1418c2ecf20Sopenharmony_ci * 1428c2ecf20Sopenharmony_ci * 1438c2ecf20Sopenharmony_ci * This two layered interrupt approach means that we allocate IRQ 16 and 1448c2ecf20Sopenharmony_ci * above for PCI interrupts. The IRQ relates to which bit the interrupt 1458c2ecf20Sopenharmony_ci * comes in on. This makes interrupt processing much easier. 1468c2ecf20Sopenharmony_ci */ 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic int 1498c2ecf20Sopenharmony_cimikasa_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci static char irq_tab[8][5] = { 1528c2ecf20Sopenharmony_ci /*INT INTA INTB INTC INTD */ 1538c2ecf20Sopenharmony_ci {16+12, 16+12, 16+12, 16+12, 16+12}, /* IdSel 17, SCSI */ 1548c2ecf20Sopenharmony_ci { -1, -1, -1, -1, -1}, /* IdSel 18, PCEB */ 1558c2ecf20Sopenharmony_ci { -1, -1, -1, -1, -1}, /* IdSel 19, ???? */ 1568c2ecf20Sopenharmony_ci { -1, -1, -1, -1, -1}, /* IdSel 20, ???? */ 1578c2ecf20Sopenharmony_ci { -1, -1, -1, -1, -1}, /* IdSel 21, ???? */ 1588c2ecf20Sopenharmony_ci { 16+0, 16+0, 16+1, 16+2, 16+3}, /* IdSel 22, slot 0 */ 1598c2ecf20Sopenharmony_ci { 16+4, 16+4, 16+5, 16+6, 16+7}, /* IdSel 23, slot 1 */ 1608c2ecf20Sopenharmony_ci { 16+8, 16+8, 16+9, 16+10, 16+11}, /* IdSel 24, slot 2 */ 1618c2ecf20Sopenharmony_ci }; 1628c2ecf20Sopenharmony_ci const long min_idsel = 6, max_idsel = 13, irqs_per_slot = 5; 1638c2ecf20Sopenharmony_ci return COMMON_TABLE_LOOKUP; 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci#if defined(CONFIG_ALPHA_GENERIC) || !defined(CONFIG_ALPHA_PRIMO) 1688c2ecf20Sopenharmony_cistatic void 1698c2ecf20Sopenharmony_cimikasa_apecs_machine_check(unsigned long vector, unsigned long la_ptr) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci#define MCHK_NO_DEVSEL 0x205U 1728c2ecf20Sopenharmony_ci#define MCHK_NO_TABT 0x204U 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci struct el_common *mchk_header; 1758c2ecf20Sopenharmony_ci unsigned int code; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci mchk_header = (struct el_common *)la_ptr; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci /* Clear the error before any reporting. */ 1808c2ecf20Sopenharmony_ci mb(); 1818c2ecf20Sopenharmony_ci mb(); /* magic */ 1828c2ecf20Sopenharmony_ci draina(); 1838c2ecf20Sopenharmony_ci apecs_pci_clr_err(); 1848c2ecf20Sopenharmony_ci wrmces(0x7); 1858c2ecf20Sopenharmony_ci mb(); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci code = mchk_header->code; 1888c2ecf20Sopenharmony_ci process_mcheck_info(vector, la_ptr, "MIKASA APECS", 1898c2ecf20Sopenharmony_ci (mcheck_expected(0) 1908c2ecf20Sopenharmony_ci && (code == MCHK_NO_DEVSEL 1918c2ecf20Sopenharmony_ci || code == MCHK_NO_TABT))); 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci#endif 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci/* 1978c2ecf20Sopenharmony_ci * The System Vector 1988c2ecf20Sopenharmony_ci */ 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci#if defined(CONFIG_ALPHA_GENERIC) || !defined(CONFIG_ALPHA_PRIMO) 2018c2ecf20Sopenharmony_cistruct alpha_machine_vector mikasa_mv __initmv = { 2028c2ecf20Sopenharmony_ci .vector_name = "Mikasa", 2038c2ecf20Sopenharmony_ci DO_EV4_MMU, 2048c2ecf20Sopenharmony_ci DO_DEFAULT_RTC, 2058c2ecf20Sopenharmony_ci DO_APECS_IO, 2068c2ecf20Sopenharmony_ci .machine_check = mikasa_apecs_machine_check, 2078c2ecf20Sopenharmony_ci .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, 2088c2ecf20Sopenharmony_ci .min_io_address = DEFAULT_IO_BASE, 2098c2ecf20Sopenharmony_ci .min_mem_address = APECS_AND_LCA_DEFAULT_MEM_BASE, 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci .nr_irqs = 32, 2128c2ecf20Sopenharmony_ci .device_interrupt = mikasa_device_interrupt, 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci .init_arch = apecs_init_arch, 2158c2ecf20Sopenharmony_ci .init_irq = mikasa_init_irq, 2168c2ecf20Sopenharmony_ci .init_rtc = common_init_rtc, 2178c2ecf20Sopenharmony_ci .init_pci = common_init_pci, 2188c2ecf20Sopenharmony_ci .pci_map_irq = mikasa_map_irq, 2198c2ecf20Sopenharmony_ci .pci_swizzle = common_swizzle, 2208c2ecf20Sopenharmony_ci}; 2218c2ecf20Sopenharmony_ciALIAS_MV(mikasa) 2228c2ecf20Sopenharmony_ci#endif 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_PRIMO) 2258c2ecf20Sopenharmony_cistruct alpha_machine_vector mikasa_primo_mv __initmv = { 2268c2ecf20Sopenharmony_ci .vector_name = "Mikasa-Primo", 2278c2ecf20Sopenharmony_ci DO_EV5_MMU, 2288c2ecf20Sopenharmony_ci DO_DEFAULT_RTC, 2298c2ecf20Sopenharmony_ci DO_CIA_IO, 2308c2ecf20Sopenharmony_ci .machine_check = cia_machine_check, 2318c2ecf20Sopenharmony_ci .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, 2328c2ecf20Sopenharmony_ci .min_io_address = DEFAULT_IO_BASE, 2338c2ecf20Sopenharmony_ci .min_mem_address = CIA_DEFAULT_MEM_BASE, 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci .nr_irqs = 32, 2368c2ecf20Sopenharmony_ci .device_interrupt = mikasa_device_interrupt, 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci .init_arch = cia_init_arch, 2398c2ecf20Sopenharmony_ci .init_irq = mikasa_init_irq, 2408c2ecf20Sopenharmony_ci .init_rtc = common_init_rtc, 2418c2ecf20Sopenharmony_ci .init_pci = cia_init_pci, 2428c2ecf20Sopenharmony_ci .kill_arch = cia_kill_arch, 2438c2ecf20Sopenharmony_ci .pci_map_irq = mikasa_map_irq, 2448c2ecf20Sopenharmony_ci .pci_swizzle = common_swizzle, 2458c2ecf20Sopenharmony_ci}; 2468c2ecf20Sopenharmony_ciALIAS_MV(mikasa_primo) 2478c2ecf20Sopenharmony_ci#endif 248