1*b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * linux/arch/alpha/kernel/sys_rawhide.c
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * Copyright (C) 1995 David A Rusling
61da177e4SLinus Torvalds * Copyright (C) 1996 Jay A Estabrook
71da177e4SLinus Torvalds * Copyright (C) 1998, 1999 Richard Henderson
81da177e4SLinus Torvalds *
91da177e4SLinus Torvalds * Code supporting the RAWHIDE.
101da177e4SLinus Torvalds */
111da177e4SLinus Torvalds
121da177e4SLinus Torvalds #include <linux/kernel.h>
131da177e4SLinus Torvalds #include <linux/types.h>
141da177e4SLinus Torvalds #include <linux/mm.h>
151da177e4SLinus Torvalds #include <linux/sched.h>
161da177e4SLinus Torvalds #include <linux/pci.h>
171da177e4SLinus Torvalds #include <linux/init.h>
181da177e4SLinus Torvalds
191da177e4SLinus Torvalds #include <asm/ptrace.h>
201da177e4SLinus Torvalds #include <asm/dma.h>
211da177e4SLinus Torvalds #include <asm/irq.h>
221da177e4SLinus Torvalds #include <asm/mmu_context.h>
231da177e4SLinus Torvalds #include <asm/io.h>
241da177e4SLinus Torvalds #include <asm/core_mcpcia.h>
251da177e4SLinus Torvalds #include <asm/tlbflush.h>
261da177e4SLinus Torvalds
271da177e4SLinus Torvalds #include "proto.h"
281da177e4SLinus Torvalds #include "irq_impl.h"
291da177e4SLinus Torvalds #include "pci_impl.h"
301da177e4SLinus Torvalds #include "machvec_impl.h"
311da177e4SLinus Torvalds
321da177e4SLinus Torvalds
331da177e4SLinus Torvalds /*
341da177e4SLinus Torvalds * HACK ALERT! only the boot cpu is used for interrupts.
351da177e4SLinus Torvalds */
361da177e4SLinus Torvalds
371da177e4SLinus Torvalds
381da177e4SLinus Torvalds /* Note mask bit is true for ENABLED irqs. */
391da177e4SLinus Torvalds
401da177e4SLinus Torvalds static unsigned int hose_irq_masks[4] = {
411da177e4SLinus Torvalds 0xff0000, 0xfe0000, 0xff0000, 0xff0000
421da177e4SLinus Torvalds };
431da177e4SLinus Torvalds static unsigned int cached_irq_masks[4];
441da177e4SLinus Torvalds DEFINE_SPINLOCK(rawhide_irq_lock);
451da177e4SLinus Torvalds
461da177e4SLinus Torvalds static inline void
rawhide_update_irq_hw(int hose,int mask)471da177e4SLinus Torvalds rawhide_update_irq_hw(int hose, int mask)
481da177e4SLinus Torvalds {
491da177e4SLinus Torvalds *(vuip)MCPCIA_INT_MASK0(MCPCIA_HOSE2MID(hose)) = mask;
501da177e4SLinus Torvalds mb();
511da177e4SLinus Torvalds *(vuip)MCPCIA_INT_MASK0(MCPCIA_HOSE2MID(hose));
521da177e4SLinus Torvalds }
531da177e4SLinus Torvalds
541b75b05bSIvan Kokshaysky #define hose_exists(h) \
551b75b05bSIvan Kokshaysky (((h) < MCPCIA_MAX_HOSES) && (cached_irq_masks[(h)] != 0))
561b75b05bSIvan Kokshaysky
571da177e4SLinus Torvalds static inline void
rawhide_enable_irq(struct irq_data * d)5867436cefSThomas Gleixner rawhide_enable_irq(struct irq_data *d)
591da177e4SLinus Torvalds {
601da177e4SLinus Torvalds unsigned int mask, hose;
6167436cefSThomas Gleixner unsigned int irq = d->irq;
621da177e4SLinus Torvalds
631da177e4SLinus Torvalds irq -= 16;
641da177e4SLinus Torvalds hose = irq / 24;
651b75b05bSIvan Kokshaysky if (!hose_exists(hose)) /* if hose non-existent, exit */
661b75b05bSIvan Kokshaysky return;
671b75b05bSIvan Kokshaysky
681da177e4SLinus Torvalds irq -= hose * 24;
691da177e4SLinus Torvalds mask = 1 << irq;
701da177e4SLinus Torvalds
711da177e4SLinus Torvalds spin_lock(&rawhide_irq_lock);
721da177e4SLinus Torvalds mask |= cached_irq_masks[hose];
731da177e4SLinus Torvalds cached_irq_masks[hose] = mask;
741da177e4SLinus Torvalds rawhide_update_irq_hw(hose, mask);
751da177e4SLinus Torvalds spin_unlock(&rawhide_irq_lock);
761da177e4SLinus Torvalds }
771da177e4SLinus Torvalds
781da177e4SLinus Torvalds static void
rawhide_disable_irq(struct irq_data * d)7967436cefSThomas Gleixner rawhide_disable_irq(struct irq_data *d)
801da177e4SLinus Torvalds {
811da177e4SLinus Torvalds unsigned int mask, hose;
8267436cefSThomas Gleixner unsigned int irq = d->irq;
831da177e4SLinus Torvalds
841da177e4SLinus Torvalds irq -= 16;
851da177e4SLinus Torvalds hose = irq / 24;
861b75b05bSIvan Kokshaysky if (!hose_exists(hose)) /* if hose non-existent, exit */
871b75b05bSIvan Kokshaysky return;
881b75b05bSIvan Kokshaysky
891da177e4SLinus Torvalds irq -= hose * 24;
901da177e4SLinus Torvalds mask = ~(1 << irq) | hose_irq_masks[hose];
911da177e4SLinus Torvalds
921da177e4SLinus Torvalds spin_lock(&rawhide_irq_lock);
931da177e4SLinus Torvalds mask &= cached_irq_masks[hose];
941da177e4SLinus Torvalds cached_irq_masks[hose] = mask;
951da177e4SLinus Torvalds rawhide_update_irq_hw(hose, mask);
961da177e4SLinus Torvalds spin_unlock(&rawhide_irq_lock);
971da177e4SLinus Torvalds }
981da177e4SLinus Torvalds
991da177e4SLinus Torvalds static void
rawhide_mask_and_ack_irq(struct irq_data * d)10067436cefSThomas Gleixner rawhide_mask_and_ack_irq(struct irq_data *d)
1011da177e4SLinus Torvalds {
1021da177e4SLinus Torvalds unsigned int mask, mask1, hose;
10367436cefSThomas Gleixner unsigned int irq = d->irq;
1041da177e4SLinus Torvalds
1051da177e4SLinus Torvalds irq -= 16;
1061da177e4SLinus Torvalds hose = irq / 24;
1071b75b05bSIvan Kokshaysky if (!hose_exists(hose)) /* if hose non-existent, exit */
1081b75b05bSIvan Kokshaysky return;
1091b75b05bSIvan Kokshaysky
1101da177e4SLinus Torvalds irq -= hose * 24;
1111da177e4SLinus Torvalds mask1 = 1 << irq;
1121da177e4SLinus Torvalds mask = ~mask1 | hose_irq_masks[hose];
1131da177e4SLinus Torvalds
1141da177e4SLinus Torvalds spin_lock(&rawhide_irq_lock);
1151da177e4SLinus Torvalds
1161da177e4SLinus Torvalds mask &= cached_irq_masks[hose];
1171da177e4SLinus Torvalds cached_irq_masks[hose] = mask;
1181da177e4SLinus Torvalds rawhide_update_irq_hw(hose, mask);
1191da177e4SLinus Torvalds
1201da177e4SLinus Torvalds /* Clear the interrupt. */
1211da177e4SLinus Torvalds *(vuip)MCPCIA_INT_REQ(MCPCIA_HOSE2MID(hose)) = mask1;
1221da177e4SLinus Torvalds
1231da177e4SLinus Torvalds spin_unlock(&rawhide_irq_lock);
1241da177e4SLinus Torvalds }
1251da177e4SLinus Torvalds
12644377f62SThomas Gleixner static struct irq_chip rawhide_irq_type = {
1278ab1221cSThomas Gleixner .name = "RAWHIDE",
12867436cefSThomas Gleixner .irq_unmask = rawhide_enable_irq,
12967436cefSThomas Gleixner .irq_mask = rawhide_disable_irq,
13067436cefSThomas Gleixner .irq_mask_ack = rawhide_mask_and_ack_irq,
1311da177e4SLinus Torvalds };
1321da177e4SLinus Torvalds
1331da177e4SLinus Torvalds static void
rawhide_srm_device_interrupt(unsigned long vector)1347ca56053SAl Viro rawhide_srm_device_interrupt(unsigned long vector)
1351da177e4SLinus Torvalds {
1361da177e4SLinus Torvalds int irq;
1371da177e4SLinus Torvalds
1381da177e4SLinus Torvalds irq = (vector - 0x800) >> 4;
1391da177e4SLinus Torvalds
1401da177e4SLinus Torvalds /*
1411da177e4SLinus Torvalds * The RAWHIDE SRM console reports PCI interrupts with a vector
1421da177e4SLinus Torvalds * 0x80 *higher* than one might expect, as PCI IRQ 0 (ie bit 0)
1431da177e4SLinus Torvalds * shows up as IRQ 24, etc, etc. We adjust it down by 8 to have
1441da177e4SLinus Torvalds * it line up with the actual bit numbers from the REQ registers,
1451da177e4SLinus Torvalds * which is how we manage the interrupts/mask. Sigh...
1461da177e4SLinus Torvalds *
1471da177e4SLinus Torvalds * Also, PCI #1 interrupts are offset some more... :-(
1481da177e4SLinus Torvalds */
1491da177e4SLinus Torvalds
1501da177e4SLinus Torvalds if (irq == 52) {
1511da177e4SLinus Torvalds /* SCSI on PCI1 is special. */
1521da177e4SLinus Torvalds irq = 72;
1531da177e4SLinus Torvalds }
1541da177e4SLinus Torvalds
1551da177e4SLinus Torvalds /* Adjust by which hose it is from. */
1561da177e4SLinus Torvalds irq -= ((irq + 16) >> 2) & 0x38;
1571da177e4SLinus Torvalds
1583dbb8c62SAl Viro handle_irq(irq);
1591da177e4SLinus Torvalds }
1601da177e4SLinus Torvalds
1611da177e4SLinus Torvalds static void __init
rawhide_init_irq(void)1621da177e4SLinus Torvalds rawhide_init_irq(void)
1631da177e4SLinus Torvalds {
1641da177e4SLinus Torvalds struct pci_controller *hose;
1651da177e4SLinus Torvalds long i;
1661da177e4SLinus Torvalds
1671da177e4SLinus Torvalds mcpcia_init_hoses();
1681da177e4SLinus Torvalds
1691b75b05bSIvan Kokshaysky /* Clear them all; only hoses that exist will be non-zero. */
1701b75b05bSIvan Kokshaysky for (i = 0; i < MCPCIA_MAX_HOSES; i++) cached_irq_masks[i] = 0;
1711b75b05bSIvan Kokshaysky
1721da177e4SLinus Torvalds for (hose = hose_head; hose; hose = hose->next) {
1731da177e4SLinus Torvalds unsigned int h = hose->index;
1741da177e4SLinus Torvalds unsigned int mask = hose_irq_masks[h];
1751da177e4SLinus Torvalds
1761da177e4SLinus Torvalds cached_irq_masks[h] = mask;
1771da177e4SLinus Torvalds *(vuip)MCPCIA_INT_MASK0(MCPCIA_HOSE2MID(h)) = mask;
1781da177e4SLinus Torvalds *(vuip)MCPCIA_INT_MASK1(MCPCIA_HOSE2MID(h)) = 0;
1791da177e4SLinus Torvalds }
1801da177e4SLinus Torvalds
1811da177e4SLinus Torvalds for (i = 16; i < 128; ++i) {
182a9eb076bSThomas Gleixner irq_set_chip_and_handler(i, &rawhide_irq_type,
183a9eb076bSThomas Gleixner handle_level_irq);
18467436cefSThomas Gleixner irq_set_status_flags(i, IRQ_LEVEL);
1851da177e4SLinus Torvalds }
1861da177e4SLinus Torvalds
1871da177e4SLinus Torvalds init_i8259a_irqs();
1881da177e4SLinus Torvalds common_init_isa_dma();
1891da177e4SLinus Torvalds }
1901da177e4SLinus Torvalds
1911da177e4SLinus Torvalds /*
1921da177e4SLinus Torvalds * PCI Fixup configuration.
1931da177e4SLinus Torvalds *
1941da177e4SLinus Torvalds * Summary @ MCPCIA_PCI0_INT_REQ:
1951da177e4SLinus Torvalds * Bit Meaning
1961da177e4SLinus Torvalds * 0 Interrupt Line A from slot 2 PCI0
1971da177e4SLinus Torvalds * 1 Interrupt Line B from slot 2 PCI0
1981da177e4SLinus Torvalds * 2 Interrupt Line C from slot 2 PCI0
1991da177e4SLinus Torvalds * 3 Interrupt Line D from slot 2 PCI0
2001da177e4SLinus Torvalds * 4 Interrupt Line A from slot 3 PCI0
2011da177e4SLinus Torvalds * 5 Interrupt Line B from slot 3 PCI0
2021da177e4SLinus Torvalds * 6 Interrupt Line C from slot 3 PCI0
2031da177e4SLinus Torvalds * 7 Interrupt Line D from slot 3 PCI0
2041da177e4SLinus Torvalds * 8 Interrupt Line A from slot 4 PCI0
2051da177e4SLinus Torvalds * 9 Interrupt Line B from slot 4 PCI0
2061da177e4SLinus Torvalds * 10 Interrupt Line C from slot 4 PCI0
2071da177e4SLinus Torvalds * 11 Interrupt Line D from slot 4 PCI0
2081da177e4SLinus Torvalds * 12 Interrupt Line A from slot 5 PCI0
2091da177e4SLinus Torvalds * 13 Interrupt Line B from slot 5 PCI0
2101da177e4SLinus Torvalds * 14 Interrupt Line C from slot 5 PCI0
2111da177e4SLinus Torvalds * 15 Interrupt Line D from slot 5 PCI0
2121da177e4SLinus Torvalds * 16 EISA interrupt (PCI 0) or SCSI interrupt (PCI 1)
2131da177e4SLinus Torvalds * 17-23 NA
2141da177e4SLinus Torvalds *
2151da177e4SLinus Torvalds * IdSel
2161da177e4SLinus Torvalds * 1 EISA bridge (PCI bus 0 only)
2171da177e4SLinus Torvalds * 2 PCI option slot 2
2181da177e4SLinus Torvalds * 3 PCI option slot 3
2191da177e4SLinus Torvalds * 4 PCI option slot 4
2201da177e4SLinus Torvalds * 5 PCI option slot 5
2211da177e4SLinus Torvalds *
2221da177e4SLinus Torvalds */
2231da177e4SLinus Torvalds
224814eae59SLorenzo Pieralisi static int
rawhide_map_irq(const struct pci_dev * dev,u8 slot,u8 pin)225d5341942SRalf Baechle rawhide_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
2261da177e4SLinus Torvalds {
227814eae59SLorenzo Pieralisi static char irq_tab[5][5] = {
2281da177e4SLinus Torvalds /*INT INTA INTB INTC INTD */
2291da177e4SLinus Torvalds { 16+16, 16+16, 16+16, 16+16, 16+16}, /* IdSel 1 SCSI PCI 1 */
2301da177e4SLinus Torvalds { 16+ 0, 16+ 0, 16+ 1, 16+ 2, 16+ 3}, /* IdSel 2 slot 2 */
2311da177e4SLinus Torvalds { 16+ 4, 16+ 4, 16+ 5, 16+ 6, 16+ 7}, /* IdSel 3 slot 3 */
2321da177e4SLinus Torvalds { 16+ 8, 16+ 8, 16+ 9, 16+10, 16+11}, /* IdSel 4 slot 4 */
2331da177e4SLinus Torvalds { 16+12, 16+12, 16+13, 16+14, 16+15} /* IdSel 5 slot 5 */
2341da177e4SLinus Torvalds };
2351da177e4SLinus Torvalds const long min_idsel = 1, max_idsel = 5, irqs_per_slot = 5;
2361da177e4SLinus Torvalds
2371da177e4SLinus Torvalds struct pci_controller *hose = dev->sysdata;
2381da177e4SLinus Torvalds int irq = COMMON_TABLE_LOOKUP;
2391da177e4SLinus Torvalds if (irq >= 0)
2401da177e4SLinus Torvalds irq += 24 * hose->index;
2411da177e4SLinus Torvalds return irq;
2421da177e4SLinus Torvalds }
2431da177e4SLinus Torvalds
2441da177e4SLinus Torvalds
2451da177e4SLinus Torvalds /*
2461da177e4SLinus Torvalds * The System Vector
2471da177e4SLinus Torvalds */
2481da177e4SLinus Torvalds
2491da177e4SLinus Torvalds struct alpha_machine_vector rawhide_mv __initmv = {
2501da177e4SLinus Torvalds .vector_name = "Rawhide",
2511da177e4SLinus Torvalds DO_EV5_MMU,
2521da177e4SLinus Torvalds DO_DEFAULT_RTC,
2531da177e4SLinus Torvalds DO_MCPCIA_IO,
2541da177e4SLinus Torvalds .machine_check = mcpcia_machine_check,
2551da177e4SLinus Torvalds .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS,
2561da177e4SLinus Torvalds .min_io_address = DEFAULT_IO_BASE,
2571da177e4SLinus Torvalds .min_mem_address = MCPCIA_DEFAULT_MEM_BASE,
2581da177e4SLinus Torvalds .pci_dac_offset = MCPCIA_DAC_OFFSET,
2591da177e4SLinus Torvalds
2601da177e4SLinus Torvalds .nr_irqs = 128,
2611da177e4SLinus Torvalds .device_interrupt = rawhide_srm_device_interrupt,
2621da177e4SLinus Torvalds
2631da177e4SLinus Torvalds .init_arch = mcpcia_init_arch,
2641da177e4SLinus Torvalds .init_irq = rawhide_init_irq,
2651da177e4SLinus Torvalds .init_rtc = common_init_rtc,
2661da177e4SLinus Torvalds .init_pci = common_init_pci,
2671da177e4SLinus Torvalds .kill_arch = NULL,
2681da177e4SLinus Torvalds .pci_map_irq = rawhide_map_irq,
2691da177e4SLinus Torvalds .pci_swizzle = common_swizzle,
2701da177e4SLinus Torvalds };
2711da177e4SLinus Torvalds ALIAS_MV(rawhide)
272