xref: /linux-6.15/arch/alpha/kernel/sys_rawhide.c (revision e31cf2f4)
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