code:
// SPDX-License-Identifier: GPL-2.0
/*
 *	linux/arch/alpha/kernel/err_marvel.c
 *
 *	Copyright (C) 2001 Jeff Wiedemeier (Compaq Computer Corporation)
 *
 */

#include <linux/init.h>
#include <linux/pci.h>
#include <linux/sched.h>

#include <asm/io.h>
#include <asm/console.h>
#include <asm/core_marvel.h>
#include <asm/hwrpb.h>
#include <asm/smp.h>
#include <asm/err_common.h>
#include <asm/err_ev7.h>

#include "err_impl.h"
#include "proto.h"

static void
marvel_print_680_frame(struct ev7_lf_subpackets *lf_subpackets)
{
#ifdef CONFIG_VERBOSE_MCHECK
	struct ev7_pal_environmental_subpacket *env;
	struct { int type; char *name; } ev_packets[] = {
		{ EL_TYPE__PAL__ENV__AMBIENT_TEMPERATURE,
		  "Ambient Temperature" },
		{ EL_TYPE__PAL__ENV__AIRMOVER_FAN,
		  "AirMover / Fan" },
		{ EL_TYPE__PAL__ENV__VOLTAGE,
		  "Voltage" },
		{ EL_TYPE__PAL__ENV__INTRUSION,
		  "Intrusion" },
		{ EL_TYPE__PAL__ENV__POWER_SUPPLY,
		  "Power Supply" },
		{ EL_TYPE__PAL__ENV__LAN,
		  "LAN" },
		{ EL_TYPE__PAL__ENV__HOT_PLUG,
		  "Hot Plug" },
		{ 0, NULL }
	};
	int i;

	for (i = 0; ev_packets[i].type != 0; i++) {
		env = lf_subpackets->env[ev7_lf_env_index(ev_packets[i].type)];
		if (!env)
			continue;

		printk("%s**%s event (cabinet %d, drawer %d)\n",
		       err_print_prefix,
		       ev_packets[i].name,
		       env->cabinet,
		       env->drawer);
		printk("%s   Module Type: 0x%x - Unit ID 0x%x - "
		       "Condition 0x%x\n",
		       err_print_prefix,
		       env->module_type,
		       env->unit_id,
		       env->condition);
	}
#endif /* CONFIG_VERBOSE_MCHECK */
}

static int
marvel_process_680_frame(struct ev7_lf_subpackets *lf_subpackets, int print)
{
	int status = MCHK_DISPOSITION_UNKNOWN_ERROR;
	int i;

	for (i = ev7_lf_env_index(EL_TYPE__PAL__ENV__AMBIENT_TEMPERATURE);
	     i <= ev7_lf_env_index(EL_TYPE__PAL__ENV__HOT_PLUG);
	     i++) {
		if (lf_subpackets->env[i])
			status = MCHK_DISPOSITION_REPORT;
	}

	if (print)
		marvel_print_680_frame(lf_subpackets);

	return status;
}

#ifdef CONFIG_VERBOSE_MCHECK

static void
marvel_print_err_cyc(u64 err_cyc)
{
	static char *packet_desc[] = {
		"No Error",
		"UNKNOWN",
		"1 cycle (1 or 2 flit packet)",
		"2 cycles (3 flit packet)",
		"9 cycles (18 flit packet)",
		"10 cycles (19 flit packet)",
		"UNKNOWN",
		"UNKNOWN",
		"UNKNOWN"
	};

#define IO7__ERR_CYC__ODD_FLT	(1UL <<  0)
#define IO7__ERR_CYC__EVN_FLT	(1UL <<  1)
#define IO7__ERR_CYC__PACKET__S	(6)
#define IO7__ERR_CYC__PACKET__M	(0x7)
#define IO7__ERR_CYC__LOC	(1UL <<  5)
#define IO7__ERR_CYC__CYCLE__S	(2)
#define IO7__ERR_CYC__CYCLE__M	(0x7)

	printk("%s        Packet In Error: %s\n"
	       "%s        Error in %s, cycle %lld%s%s\n",
	       err_print_prefix,
	       packet_desc[EXTRACT(err_cyc, IO7__ERR_CYC__PACKET)],
	       err_print_prefix,
	       (err_cyc & IO7__ERR_CYC__LOC) ? "DATA" : "HEADER",
	       EXTRACT(err_cyc, IO7__ERR_CYC__CYCLE),
	       (err_cyc & IO7__ERR_CYC__ODD_FLT) ? " [ODD Flit]": "",
	       (err_cyc & IO7__ERR_CYC__EVN_FLT) ? " [Even Flit]": "");
}

static void
marvel_print_po7_crrct_sym(u64 crrct_sym)
{
#define IO7__PO7_CRRCT_SYM__SYN__S	(0)
#define IO7__PO7_CRRCT_SYM__SYN__M	(0x7f)
#define IO7__PO7_CRRCT_SYM__ERR_CYC__S	(7)   /* ERR_CYC + ODD_FLT + EVN_FLT */
#define IO7__PO7_CRRCT_SYM__ERR_CYC__M	(0x1ff)

	printk("%s      Correctable Error Symptoms:\n"
	       "%s        Syndrome: 0x%llx\n",
	       err_print_prefix,
	       err_print_prefix, EXTRACT(crrct_sym, IO7__PO7_CRRCT_SYM__SYN));
	marvel_print_err_cyc(EXTRACT(crrct_sym, IO7__PO7_CRRCT_SYM__ERR_CYC));
}

static void
marvel_print_po7_uncrr_sym(u64 uncrr_sym, u64 valid_mask)
{
	static char *clk_names[] = { "_h[0]", "_h[1]", "_n[0]", "_n[1]" };
	static char *clk_decode[] = {
		"No Error",
		"One extra rising edge",
		"Two extra rising edges",
		"Lost one clock"
	};
	static char *port_names[] = { "Port 0", 	"Port 1",
				      "Port 2", 	"Port 3",
				      "Unknown Port",	"Unknown Port",
				      "Unknown Port",	"Port 7" };
	int scratch, i;

#define IO7__PO7_UNCRR_SYM__SYN__S	    (0)
#define IO7__PO7_UNCRR_SYM__SYN__M	    (0x7f)
#define IO7__PO7_UNCRR_SYM__ERR_CYC__S	    (7)      /* ERR_CYC + ODD_FLT... */
#define IO7__PO7_UNCRR_SYM__ERR_CYC__M	    (0x1ff)  /* ... + EVN_FLT        */
#define IO7__PO7_UNCRR_SYM__CLK__S	    (16)
#define IO7__PO7_UNCRR_SYM__CLK__M	    (0xff)
#define IO7__PO7_UNCRR_SYM__CDT_OVF_TO__REQ (1UL << 24)
#define IO7__PO7_UNCRR_SYM__CDT_OVF_TO__RIO (1UL << 25)
#define IO7__PO7_UNCRR_SYM__CDT_OVF_TO__WIO (1UL << 26)
#define IO7__PO7_UNCRR_SYM__CDT_OVF_TO__BLK (1UL << 27)
#define IO7__PO7_UNCRR_SYM__CDT_OVF_TO__NBK (1UL << 28)
#define IO7__PO7_UNCRR_SYM__OVF__READIO	    (1UL << 29)
#define IO7__PO7_UNCRR_SYM__OVF__WRITEIO    (1UL << 30)
#define IO7__PO7_UNCRR_SYM__OVF__FWD        (1UL << 31)
#define IO7__PO7_UNCRR_SYM__VICTIM_SP__S    (32)
#define IO7__PO7_UNCRR_SYM__VICTIM_SP__M    (0xff)
#define IO7__PO7_UNCRR_SYM__DETECT_SP__S    (40)
#define IO7__PO7_UNCRR_SYM__DETECT_SP__M    (0xff)
#define IO7__PO7_UNCRR_SYM__STRV_VTR__S     (48)
#define IO7__PO7_UNCRR_SYM__STRV_VTR__M     (0x3ff)

#define IO7__STRV_VTR__LSI__INTX__S	    (0)
#define IO7__STRV_VTR__LSI__INTX__M	    (0x3)
#define IO7__STRV_VTR__LSI__SLOT__S	    (2)
#define IO7__STRV_VTR__LSI__SLOT__M	    (0x7)
#define IO7__STRV_VTR__LSI__BUS__S	    (5)
#define IO7__STRV_VTR__LSI__BUS__M	    (0x3)
#define IO7__STRV_VTR__MSI__INTNUM__S	    (0)
#define IO7__STRV_VTR__MSI__INTNUM__M	    (0x1ff)
#define IO7__STRV_VTR__IS_MSI		    (1UL << 9)

	printk("%s      Uncorrectable Error Symptoms:\n", err_print_prefix);
	uncrr_sym &= valid_mask;

	if (EXTRACT(valid_mask, IO7__PO7_UNCRR_SYM__SYN))
		printk("%s        Syndrome: 0x%llx\n",
		       err_print_prefix,
		       EXTRACT(uncrr_sym, IO7__PO7_UNCRR_SYM__SYN));

	if (EXTRACT(valid_mask, IO7__PO7_UNCRR_SYM__ERR_CYC))
		marvel_print_err_cyc(EXTRACT(uncrr_sym,
					     IO7__PO7_UNCRR_SYM__ERR_CYC));

	scratch = EXTRACT(uncrr_sym, IO7__PO7_UNCRR_SYM__CLK);
	for (i = 0; i < 4; i++, scratch >>= 2) {
		if (scratch & 0x3)
			printk("%s        Clock %s: %s\n",
			       err_print_prefix,
			       clk_names[i], clk_decode[scratch & 0x3]);
	}

	if (uncrr_sym & IO7__PO7_UNCRR_SYM__CDT_OVF_TO__REQ)
		printk("%s       REQ Credit Timeout or Overflow\n",
		       err_print_prefix);
	if (uncrr_sym & IO7__PO7_UNCRR_SYM__CDT_OVF_TO__RIO)
		printk("%s       RIO Credit Timeout or Overflow\n",
		       err_print_prefix);
	if (uncrr_sym & IO7__PO7_UNCRR_SYM__CDT_OVF_TO__WIO)
		printk("%s       WIO Credit Timeout or Overflow\n",
		       err_print_prefix);
	if (uncrr_sym & IO7__PO7_UNCRR_SYM__CDT_OVF_TO__BLK)
		printk("%s       BLK Credit Timeout or Overflow\n",
		       err_print_prefix);
	if (uncrr_sym & IO7__PO7_UNCRR_SYM__CDT_OVF_TO__NBK)
		printk("%s       NBK Credit Timeout or Overflow\n",
		       err_print_prefix);

	if (uncrr_sym & IO7__PO7_UNCRR_SYM__OVF__READIO)
		printk("%s       Read I/O Buffer Overflow\n",
		       err_print_prefix);
	if (uncrr_sym & IO7__PO7_UNCRR_SYM__OVF__WRITEIO)
		printk("%s       Write I/O Buffer Overflow\n",
		       err_print_prefix);
	if (uncrr_sym & IO7__PO7_UNCRR_SYM__OVF__FWD)
		printk("%s       FWD Buffer Overflow\n",
		       err_print_prefix);

	if ((scratch = EXTRACT(uncrr_sym, IO7__PO7_UNCRR_SYM__VICTIM_SP))) {
		int lost = scratch & (1UL << 4);
		scratch &= ~lost;
		for (i = 0; i < 8; i++, scratch >>= 1) {
			if (!(scratch & 1))
				continue;
			printk("%s        Error Response sent to %s",
			       err_print_prefix, port_names[i]);
		}
		if (lost)
			printk("%s        Lost Error sent somewhere else\n",
			       err_print_prefix);
	}

	if ((scratch = EXTRACT(uncrr_sym, IO7__PO7_UNCRR_SYM__DETECT_SP))) {
		for (i = 0; i < 8; i++, scratch >>= 1) {
			if (!(scratch & 1))
				continue;
			printk("%s        Error Reported by %s",
			       err_print_prefix, port_names[i]);
		}
	}

	if (EXTRACT(valid_mask, IO7__PO7_UNCRR_SYM__STRV_VTR)) {
		char starvation_message[80];

		scratch = EXTRACT(uncrr_sym, IO7__PO7_UNCRR_SYM__STRV_VTR);
		if (scratch & IO7__STRV_VTR__IS_MSI)
			sprintf(starvation_message,
				"MSI Interrupt 0x%x",
				EXTRACT(scratch, IO7__STRV_VTR__MSI__INTNUM));
		else
			sprintf(starvation_message,
				"LSI INT%c for Bus:Slot (%d:%d)\n",
				'A' + EXTRACT(scratch,
					      IO7__STRV_VTR__LSI__INTX),
				EXTRACT(scratch, IO7__STRV_VTR__LSI__BUS),
				EXTRACT(scratch, IO7__STRV_VTR__LSI__SLOT));

		printk("%s        Starvation Int Trigger By: %s\n",
		       err_print_prefix, starvation_message);
	}
}

static void
marvel_print_po7_ugbge_sym(u64 ugbge_sym)
{
	char opcode_str[10];

#define IO7__PO7_UGBGE_SYM__UPH_PKT_OFF__S	(6)
#define IO7__PO7_UGBGE_SYM__UPH_PKT_OFF__M	(0xfffffffful)
#define IO7__PO7_UGBGE_SYM__UPH_OPCODE__S	(40)
#define IO7__PO7_UGBGE_SYM__UPH_OPCODE__M	(0xff)
#define IO7__PO7_UGBGE_SYM__UPH_SRC_PORT__S	(48)
#define IO7__PO7_UGBGE_SYM__UPH_SRC_PORT__M	(0xf)
#define IO7__PO7_UGBGE_SYM__UPH_DEST_PID__S	(52)
#define IO7__PO7_UGBGE_SYM__UPH_DEST_PID__M	(0x7ff)
#define IO7__PO7_UGBGE_SYM__VALID		(1UL << 63)

	if (!(ugbge_sym & IO7__PO7_UGBGE_SYM__VALID))
		return;

	switch(EXTRACT(ugbge_sym, IO7__PO7_UGBGE_SYM__UPH_OPCODE)) {
	case 0x51:
		sprintf(opcode_str, "Wr32");
		break;
	case 0x50:
		sprintf(opcode_str, "WrQW");
		break;
	case 0x54:
		sprintf(opcode_str, "WrIPR");
		break;
	case 0xD8:
		sprintf(opcode_str, "Victim");
		break;
	case 0xC5:
		sprintf(opcode_str, "BlkIO");
		break;
	default:
		sprintf(opcode_str, "0x%llx\n",
			EXTRACT(ugbge_sym, IO7__PO7_UGBGE_SYM__UPH_OPCODE));
		break;
	}

	printk("%s      Up Hose Garbage Symptom:\n"
	       "%s        Source Port: %lld - Dest PID: %lld - OpCode: %s\n",
	       err_print_prefix,
	       err_print_prefix,
	       EXTRACT(ugbge_sym, IO7__PO7_UGBGE_SYM__UPH_SRC_PORT),
	       EXTRACT(ugbge_sym, IO7__PO7_UGBGE_SYM__UPH_DEST_PID),
	       opcode_str);

	if (0xC5 != EXTRACT(ugbge_sym, IO7__PO7_UGBGE_SYM__UPH_OPCODE))
		printk("%s        Packet Offset 0x%08llx\n",
		       err_print_prefix,
		       EXTRACT(ugbge_sym, IO7__PO7_UGBGE_SYM__UPH_PKT_OFF));
}

static void
marvel_print_po7_err_sum(struct ev7_pal_io_subpacket *io)
{
	u64	uncrr_sym_valid = 0;

#define IO7__PO7_ERRSUM__CR_SBE		(1UL << 32)
#define IO7__PO7_ERRSUM__CR_SBE2	(1UL << 33)
#define IO7__PO7_ERRSUM__CR_PIO_WBYTE	(1UL << 34)
#define IO7__PO7_ERRSUM__CR_CSR_NXM	(1UL << 35)
#define IO7__PO7_ERRSUM__CR_RPID_ACV	(1UL << 36)
#define IO7__PO7_ERRSUM__CR_RSP_NXM	(1UL << 37)
#define IO7__PO7_ERRSUM__CR_ERR_RESP	(1UL << 38)
#define IO7__PO7_ERRSUM__CR_CLK_DERR	(1UL << 39)
#define IO7__PO7_ERRSUM__CR_DAT_DBE	(1UL << 40)
#define IO7__PO7_ERRSUM__CR_DAT_GRBG	(1UL << 41)
#define IO7__PO7_ERRSUM__MAF_TO		(1UL << 42)
#define IO7__PO7_ERRSUM__UGBGE		(1UL << 43)
#define IO7__PO7_ERRSUM__UN_MAF_LOST	(1UL << 44)
#define IO7__PO7_ERRSUM__UN_PKT_OVF	(1UL << 45)
#define IO7__PO7_ERRSUM__UN_CDT_OVF	(1UL << 46)
#define IO7__PO7_ERRSUM__UN_DEALLOC	(1UL << 47)
#define IO7__PO7_ERRSUM__BH_CDT_TO	(1UL << 51)
#define IO7__PO7_ERRSUM__BH_CLK_HDR	(1UL << 52)
#define IO7__PO7_ERRSUM__BH_DBE_HDR	(1UL << 53)
#define IO7__PO7_ERRSUM__BH_GBG_HDR	(1UL << 54)
#define IO7__PO7_ERRSUM__BH_BAD_CMD	(1UL << 55)
#define IO7__PO7_ERRSUM__HLT_INT	(1UL << 56)
#define IO7__PO7_ERRSUM__HP_INT		(1UL << 57)
#define IO7__PO7_ERRSUM__CRD_INT	(1UL << 58)
#define IO7__PO7_ERRSUM__STV_INT	(1UL << 59)
#define IO7__PO7_ERRSUM__HRD_INT	(1UL << 60)
#define IO7__PO7_ERRSUM__BH_SUM		(1UL << 61)
#define IO7__PO7_ERRSUM__ERR_LST	(1UL << 62)
#define IO7__PO7_ERRSUM__ERR_VALID	(1UL << 63)

#define IO7__PO7_ERRSUM__ERR_MASK	(IO7__PO7_ERRSUM__ERR_VALID |	\
					 IO7__PO7_ERRSUM__CR_SBE)

	/*
	 * Single bit errors aren't covered by ERR_VALID.
	 */
	if (io->po7_error_sum & IO7__PO7_ERRSUM__CR_SBE) {
		printk("%s    %sSingle Bit Error(s) detected/corrected\n",
		       err_print_prefix,
		       (io->po7_error_sum & IO7__PO7_ERRSUM__CR_SBE2)
		       ? "Multiple " : "");
		marvel_print_po7_crrct_sym(io->po7_crrct_sym);
	}

	/*
	 * Neither are the interrupt status bits
	 */
	if (io->po7_error_sum & IO7__PO7_ERRSUM__HLT_INT)
		printk("%s    Halt Interrupt posted", err_print_prefix);
	if (io->po7_error_sum & IO7__PO7_ERRSUM__HP_INT) {
		printk("%s    Hot Plug Event Interrupt posted",
		       err_print_prefix);
		uncrr_sym_valid |= GEN_MASK(IO7__PO7_UNCRR_SYM__DETECT_SP);
	}
	if (io->po7_error_sum & IO7__PO7_ERRSUM__CRD_INT)
		printk("%s    Correctable Error Interrupt posted",
		       err_print_prefix);
	if (io->po7_error_sum & IO7__PO7_ERRSUM__STV_INT) {
		printk("%s    Starvation Interrupt posted", err_print_prefix);
		uncrr_sym_valid |= GEN_MASK(IO7__PO7_UNCRR_SYM__STRV_VTR);
	}
	if (io->po7_error_sum & IO7__PO7_ERRSUM__HRD_INT) {
		printk("%s    Hard Error Interrupt posted", err_print_prefix);
		uncrr_sym_valid |= GEN_MASK(IO7__PO7_UNCRR_SYM__DETECT_SP);
	}

	/*
	 * Everything else is valid only with ERR_VALID, so skip to the end
	 * (uncrr_sym check) unless ERR_VALID is set.
	 */
	if (!(io->po7_error_sum & IO7__PO7_ERRSUM__ERR_VALID))
		goto check_uncrr_sym;

	/*
	 * Since ERR_VALID is set, VICTIM_SP in uncrr_sym is valid.
	 * For bits [29:0] to also be valid, the following bits must
	 * not be set:
	 *	CR_PIO_WBYTE	CR_CSR_NXM	CR_RSP_NXM
	 *	CR_ERR_RESP	MAF_TO
	 */
	uncrr_sym_valid |= GEN_MASK(IO7__PO7_UNCRR_SYM__VICTIM_SP);
	if (!(io->po7_error_sum & (IO7__PO7_ERRSUM__CR_PIO_WBYTE |
				   IO7__PO7_ERRSUM__CR_CSR_NXM |
				   IO7__PO7_ERRSUM__CR_RSP_NXM |
				   IO7__PO7_ERRSUM__CR_ERR_RESP |
				   IO7__PO7_ERRSUM__MAF_TO)))
		uncrr_sym_valid |= 0x3ffffffful;

	if (io->po7_error_sum & IO7__PO7_ERRSUM__CR_PIO_WBYTE)
		printk("%s    Write byte into IO7 CSR\n", err_print_prefix);
	if (io->po7_error_sum & IO7__PO7_ERRSUM__CR_CSR_NXM)
		printk("%s    PIO to non-existent CSR\n", err_print_prefix);
	if (io->po7_error_sum & IO7__PO7_ERRSUM__CR_RPID_ACV)
		printk("%s    Bus Requester PID (Access Violation)\n",
		       err_print_prefix);
	if (io->po7_error_sum & IO7__PO7_ERRSUM__CR_RSP_NXM)
		printk("%s    Received NXM response from EV7\n",
		       err_print_prefix);
	if (io->po7_error_sum & IO7__PO7_ERRSUM__CR_ERR_RESP)
		printk("%s    Received ERROR RESPONSE\n", err_print_prefix);
	if (io->po7_error_sum & IO7__PO7_ERRSUM__CR_CLK_DERR)
		printk("%s    Clock error on data flit\n", err_print_prefix);
	if (io->po7_error_sum & IO7__PO7_ERRSUM__CR_DAT_DBE)
		printk("%s    Double Bit Error Data Error Detected\n",
		       err_print_prefix);
	if (io->po7_error_sum & IO7__PO7_ERRSUM__CR_DAT_GRBG)
		printk("%s    Garbage Encoding Detected on the data\n",
		       err_print_prefix);
	if (io->po7_error_sum & IO7__PO7_ERRSUM__UGBGE) {
		printk("%s    Garbage Encoding sent up hose\n",
		       err_print_prefix);
		marvel_print_po7_ugbge_sym(io->po7_ugbge_sym);
	}
	if (io->po7_error_sum & IO7__PO7_ERRSUM__UN_MAF_LOST)
		printk("%s    Orphan response (unexpected response)\n",
		       err_print_prefix);
	if (io->po7_error_sum & IO7__PO7_ERRSUM__UN_PKT_OVF)
		printk("%s    Down hose packet overflow\n", err_print_prefix);
	if (io->po7_error_sum & IO7__PO7_ERRSUM__UN_CDT_OVF)
		printk("%s    Down hose credit overflow\n", err_print_prefix);
	if (io->po7_error_sum & IO7__PO7_ERRSUM__UN_DEALLOC)
		printk("%s    Unexpected or bad dealloc field\n",
		       err_print_prefix);

	/*
	 * The black hole events.
	 */
	if (io->po7_error_sum & IO7__PO7_ERRSUM__MAF_TO)
		printk("%s    BLACK HOLE: Timeout for all responses\n",
		       err_print_prefix);
	if (io->po7_error_sum & IO7__PO7_ERRSUM__BH_CDT_TO)
		printk("%s    BLACK HOLE: Credit Timeout\n", err_print_prefix);
	if (io->po7_error_sum & IO7__PO7_ERRSUM__BH_CLK_HDR)
		printk("%s    BLACK HOLE: Clock check on header\n",
		       err_print_prefix);
	if (io->po7_error_sum & IO7__PO7_ERRSUM__BH_DBE_HDR)
		printk("%s    BLACK HOLE: Uncorrectable Error on header\n",
		       err_print_prefix);
	if (io->po7_error_sum & IO7__PO7_ERRSUM__BH_GBG_HDR)
		printk("%s    BLACK HOLE: Garbage on header\n",
		       err_print_prefix);
	if (io->po7_error_sum & IO7__PO7_ERRSUM__BH_BAD_CMD)
		printk("%s    BLACK HOLE: Bad EV7 command\n",
		       err_print_prefix);

	if (io->po7_error_sum & IO7__PO7_ERRSUM__ERR_LST)
		printk("%s    Lost Error\n", err_print_prefix);

	printk("%s    Failing Packet:\n"
	       "%s      Cycle 1: %016llx\n"
	       "%s      Cycle 2: %016llx\n",
	       err_print_prefix,
	       err_print_prefix, io->po7_err_pkt0,
	       err_print_prefix, io->po7_err_pkt1);
	/*
	 * If there are any valid bits in UNCRR sym for this err,
	 * print UNCRR_SYM as well.
	 */
check_uncrr_sym:
	if (uncrr_sym_valid)
		marvel_print_po7_uncrr_sym(io->po7_uncrr_sym, uncrr_sym_valid);
}

static void
marvel_print_pox_tlb_err(u64 tlb_err)
{
	static char *tlb_errors[] = {
		"No Error",
		"North Port Signaled Error fetching TLB entry",
		"PTE invalid or UCC or GBG error on this entry",
		"Address did not hit any DMA window"
	};

#define IO7__POX_TLBERR__ERR_VALID		(1UL << 63)
#define IO7__POX_TLBERR__ERRCODE__S		(0)
#define IO7__POX_TLBERR__ERRCODE__M		(0x3)
#define IO7__POX_TLBERR__ERR_TLB_PTR__S		(3)
#define IO7__POX_TLBERR__ERR_TLB_PTR__M		(0x7)
#define IO7__POX_TLBERR__FADDR__S		(6)
#define IO7__POX_TLBERR__FADDR__M		(0x3fffffffffful)

	if (!(tlb_err & IO7__POX_TLBERR__ERR_VALID))
		return;

	printk("%s      TLB Error on index 0x%llx:\n"
	       "%s        - %s\n"
	       "%s        - Addr: 0x%016llx\n",
	       err_print_prefix,
	       EXTRACT(tlb_err, IO7__POX_TLBERR__ERR_TLB_PTR),
	       err_print_prefix,
	       tlb_errors[EXTRACT(tlb_err, IO7__POX_TLBERR__ERRCODE)],
	       err_print_prefix,
	       EXTRACT(tlb_err, IO7__POX_TLBERR__FADDR) << 6);
}

static  void
marvel_print_pox_spl_cmplt(u64 spl_cmplt)
{
	char message[80];

#define IO7__POX_SPLCMPLT__MESSAGE__S		(0)
#define IO7__POX_SPLCMPLT__MESSAGE__M		(0x0fffffffful)
#define IO7__POX_SPLCMPLT__SOURCE_BUS__S	(40)
#define IO7__POX_SPLCMPLT__SOURCE_BUS__M	(0xfful)
#define IO7__POX_SPLCMPLT__SOURCE_DEV__S	(35)
#define IO7__POX_SPLCMPLT__SOURCE_DEV__M	(0x1ful)
#define IO7__POX_SPLCMPLT__SOURCE_FUNC__S	(32)
#define IO7__POX_SPLCMPLT__SOURCE_FUNC__M	(0x07ul)

#define IO7__POX_SPLCMPLT__MSG_CLASS__S		(28)
#define IO7__POX_SPLCMPLT__MSG_CLASS__M		(0xf)
#define IO7__POX_SPLCMPLT__MSG_INDEX__S		(20)
#define IO7__POX_SPLCMPLT__MSG_INDEX__M		(0xff)
#define IO7__POX_SPLCMPLT__MSG_CLASSINDEX__S	(20)
#define IO7__POX_SPLCMPLT__MSG_CLASSINDEX__M    (0xfff)
#define IO7__POX_SPLCMPLT__REM_LOWER_ADDR__S	(12)
#define IO7__POX_SPLCMPLT__REM_LOWER_ADDR__M	(0x7f)
#define IO7__POX_SPLCMPLT__REM_BYTE_COUNT__S	(0)
#define IO7__POX_SPLCMPLT__REM_BYTE_COUNT__M	(0xfff)

	printk("%s      Split Completion Error:\n"
	       "%s         Source (Bus:Dev:Func): %lld:%lld:%lld\n",
	       err_print_prefix,
	       err_print_prefix,
	       EXTRACT(spl_cmplt, IO7__POX_SPLCMPLT__SOURCE_BUS),
	       EXTRACT(spl_cmplt, IO7__POX_SPLCMPLT__SOURCE_DEV),
	       EXTRACT(spl_cmplt, IO7__POX_SPLCMPLT__SOURCE_FUNC));

	switch(EXTRACT(spl_cmplt, IO7__POX_SPLCMPLT__MSG_CLASSINDEX)) {
	case 0x000:
		sprintf(message, "Normal completion");
		break;
	case 0x100:
		sprintf(message, "Bridge - Master Abort");
		break;
	case 0x101:
		sprintf(message, "Bridge - Target Abort");
		break;
	case 0x102:
		sprintf(message, "Bridge - Uncorrectable Write Data Error");
		break;
	case 0x200:
		sprintf(message, "Byte Count Out of Range");
		break;
	case 0x201:
		sprintf(message, "Uncorrectable Split Write Data Error");
		break;
	default:
		sprintf(message, "%08llx\n",
			EXTRACT(spl_cmplt, IO7__POX_SPLCMPLT__MESSAGE));
		break;
	}
	printk("%s	   Message: %s\n", err_print_prefix, message);
}

static void
marvel_print_pox_trans_sum(u64 trans_sum)
{
	static const char * const pcix_cmd[] = {
		"Interrupt Acknowledge",
		"Special Cycle",
		"I/O Read",
		"I/O Write",
		"Reserved",
		"Reserved / Device ID Message",
		"Memory Read",
		"Memory Write",
		"Reserved / Alias to Memory Read Block",
		"Reserved / Alias to Memory Write Block",
		"Configuration Read",
		"Configuration Write",
		"Memory Read Multiple / Split Completion",
		"Dual Address Cycle",
		"Memory Read Line / Memory Read Block",
		"Memory Write and Invalidate / Memory Write Block"
	};

#define IO7__POX_TRANSUM__PCI_ADDR__S		(0)
#define IO7__POX_TRANSUM__PCI_ADDR__M		(0x3fffffffffffful)
#define IO7__POX_TRANSUM__DAC			(1UL << 50)
#define IO7__POX_TRANSUM__PCIX_MASTER_SLOT__S	(52)
#define IO7__POX_TRANSUM__PCIX_MASTER_SLOT__M	(0xf)
#define IO7__POX_TRANSUM__PCIX_CMD__S		(56)
#define IO7__POX_TRANSUM__PCIX_CMD__M		(0xf)
#define IO7__POX_TRANSUM__ERR_VALID		(1UL << 63)

	if (!(trans_sum & IO7__POX_TRANSUM__ERR_VALID))
		return;

	printk("%s      Transaction Summary:\n"
	       "%s        Command: 0x%llx - %s\n"
	       "%s        Address: 0x%016llx%s\n"
	       "%s        PCI-X Master Slot: 0x%llx\n",
	       err_print_prefix,
	       err_print_prefix,
	       EXTRACT(trans_sum, IO7__POX_TRANSUM__PCIX_CMD),
	       pcix_cmd[EXTRACT(trans_sum, IO7__POX_TRANSUM__PCIX_CMD)],
	       err_print_prefix,
	       EXTRACT(trans_sum, IO7__POX_TRANSUM__PCI_ADDR),
	       (trans_sum & IO7__POX_TRANSUM__DAC) ? " (DAC)" : "",
	       err_print_prefix,
	       EXTRACT(trans_sum, IO7__POX_TRANSUM__PCIX_MASTER_SLOT));
}

static void
marvel_print_pox_err(u64 err_sum, struct ev7_pal_io_one_port *port)
{
#define IO7__POX_ERRSUM__AGP_REQQ_OVFL    (1UL <<  4)
#define IO7__POX_ERRSUM__AGP_SYNC_ERR     (1UL <<  5)
#define IO7__POX_ERRSUM__MRETRY_TO        (1UL <<  6)
#define IO7__POX_ERRSUM__PCIX_UX_SPL      (1UL <<  7)
#define IO7__POX_ERRSUM__PCIX_SPLIT_TO    (1UL <<  8)
#define IO7__POX_ERRSUM__PCIX_DISCARD_SPL (1UL <<  9)
#define IO7__POX_ERRSUM__DMA_RD_TO        (1UL << 10)
#define IO7__POX_ERRSUM__CSR_NXM_RD       (1UL << 11)
#define IO7__POX_ERRSUM__CSR_NXM_WR       (1UL << 12)
#define IO7__POX_ERRSUM__DMA_TO           (1UL << 13)
#define IO7__POX_ERRSUM__ALL_MABORTS      (1UL << 14)
#define IO7__POX_ERRSUM__MABORT		  (1UL << 15)
#define IO7__POX_ERRSUM__MABORT_MASK	  (IO7__POX_ERRSUM__ALL_MABORTS|\
					   IO7__POX_ERRSUM__MABORT)
#define IO7__POX_ERRSUM__PT_TABORT        (1UL << 16)
#define IO7__POX_ERRSUM__PM_TABORT        (1UL << 17)
#define IO7__POX_ERRSUM__TABORT_MASK      (IO7__POX_ERRSUM__PT_TABORT | \
                                           IO7__POX_ERRSUM__PM_TABORT)
#define IO7__POX_ERRSUM__SERR             (1UL << 18)
#define IO7__POX_ERRSUM__ADDRERR_STB      (1UL << 19)
#define IO7__POX_ERRSUM__DETECTED_SERR    (1UL << 20)
#define IO7__POX_ERRSUM__PERR             (1UL << 21)
#define IO7__POX_ERRSUM__DATAERR_STB_NIOW (1UL << 22)
#define IO7__POX_ERRSUM__DETECTED_PERR    (1UL << 23)
#define IO7__POX_ERRSUM__PM_PERR          (1UL << 24)
#define IO7__POX_ERRSUM__PT_SCERROR       (1UL << 26)
#define IO7__POX_ERRSUM__HUNG_BUS         (1UL << 28)
#define IO7__POX_ERRSUM__UPE_ERROR__S     (51)
#define IO7__POX_ERRSUM__UPE_ERROR__M     (0xffUL)
#define IO7__POX_ERRSUM__UPE_ERROR        GEN_MASK(IO7__POX_ERRSUM__UPE_ERROR)
#define IO7__POX_ERRSUM__TLB_ERR          (1UL << 59)
#define IO7__POX_ERRSUM__ERR_VALID        (1UL << 63)

#define IO7__POX_ERRSUM__TRANS_SUM__MASK  (IO7__POX_ERRSUM__MRETRY_TO |       \
					   IO7__POX_ERRSUM__PCIX_UX_SPL |     \
					   IO7__POX_ERRSUM__PCIX_SPLIT_TO |   \
					   IO7__POX_ERRSUM__DMA_TO |          \
					   IO7__POX_ERRSUM__MABORT_MASK |     \
					   IO7__POX_ERRSUM__TABORT_MASK |     \
					   IO7__POX_ERRSUM__SERR |            \
					   IO7__POX_ERRSUM__ADDRERR_STB |     \
					   IO7__POX_ERRSUM__PERR |            \
					   IO7__POX_ERRSUM__DATAERR_STB_NIOW |\
					   IO7__POX_ERRSUM__DETECTED_PERR |   \
					   IO7__POX_ERRSUM__PM_PERR |         \
					   IO7__POX_ERRSUM__PT_SCERROR |      \
					   IO7__POX_ERRSUM__UPE_ERROR)

	if (!(err_sum & IO7__POX_ERRSUM__ERR_VALID))
		return;

	/*
	 * First the transaction summary errors
	 */
	if (err_sum & IO7__POX_ERRSUM__MRETRY_TO)
		printk("%s    IO7 Master Retry Timeout expired\n",
		       err_print_prefix);
	if (err_sum & IO7__POX_ERRSUM__PCIX_UX_SPL)
		printk("%s    Unexpected Split Completion\n",
		       err_print_prefix);
	if (err_sum & IO7__POX_ERRSUM__PCIX_SPLIT_TO)
		printk("%s    IO7 Split Completion Timeout expired\n",
		       err_print_prefix);
	if (err_sum & IO7__POX_ERRSUM__DMA_TO)
		printk("%s    Hung bus during DMA transaction\n",
		       err_print_prefix);
	if (err_sum & IO7__POX_ERRSUM__MABORT_MASK)
		printk("%s    Master Abort\n", err_print_prefix);
	if (err_sum & IO7__POX_ERRSUM__PT_TABORT)
		printk("%s    IO7 Asserted Target Abort\n", err_print_prefix);
	if (err_sum & IO7__POX_ERRSUM__PM_TABORT)
		printk("%s    IO7 Received Target Abort\n", err_print_prefix);
	if (err_sum & IO7__POX_ERRSUM__ADDRERR_STB) {
		printk("%s    Address or PCI-X Attribute Parity Error\n",
		       err_print_prefix);
		if (err_sum & IO7__POX_ERRSUM__SERR)
			printk("%s     IO7 Asserted SERR\n", err_print_prefix);
	}
	if (err_sum & IO7__POX_ERRSUM__PERR) {
		if (err_sum & IO7__POX_ERRSUM__DATAERR_STB_NIOW)
			printk("%s    IO7 Detected Data Parity Error\n",
			       err_print_prefix);
		else
			printk("%s    Split Completion Response with "
			       "Parity Error\n", err_print_prefix);
	}
	if (err_sum & IO7__POX_ERRSUM__DETECTED_PERR)
		printk("%s    PERR detected\n", err_print_prefix);
	if (err_sum & IO7__POX_ERRSUM__PM_PERR)
		printk("%s    PERR while IO7 is master\n", err_print_prefix);
	if (err_sum & IO7__POX_ERRSUM__PT_SCERROR) {
		printk("%s    IO7 Received Split Completion Error message\n",
		       err_print_prefix);
		marvel_print_pox_spl_cmplt(port->pox_spl_cmplt);
	}
	if (err_sum & IO7__POX_ERRSUM__UPE_ERROR) {
		unsigned int upe_error = EXTRACT(err_sum,
						 IO7__POX_ERRSUM__UPE_ERROR);
		int i;
		static char *upe_errors[] = {
			"Parity Error on MSI write data",
			"MSI read (MSI window is write only",
			"TLB - Invalid WR transaction",
			"TLB - Invalid RD transaction",
			"DMA - WR error (see north port)",
			"DMA - RD error (see north port)",
			"PPR - WR error (see north port)",
			"PPR - RD error (see north port)"
		};

		printk("%s    UPE Error:\n", err_print_prefix);
		for (i = 0; i < 8; i++) {
			if (upe_error & (1 << i))
				printk("%s      %s\n", err_print_prefix,
				       upe_errors[i]);
		}
	}

	/*
	 * POx_TRANS_SUM, if appropriate.
	 */
	if (err_sum & IO7__POX_ERRSUM__TRANS_SUM__MASK)
		marvel_print_pox_trans_sum(port->pox_trans_sum);

	/*
	 * Then TLB_ERR.
	 */
	if (err_sum & IO7__POX_ERRSUM__TLB_ERR) {
		printk("%s    TLB ERROR\n", err_print_prefix);
		marvel_print_pox_tlb_err(port->pox_tlb_err);
	}

	/*
	 * And the single bit status errors.
	 */
	if (err_sum & IO7__POX_ERRSUM__AGP_REQQ_OVFL)
		printk("%s    AGP Request Queue Overflow\n", err_print_prefix);
	if (err_sum & IO7__POX_ERRSUM__AGP_SYNC_ERR)
		printk("%s    AGP Sync Error\n", err_print_prefix);
	if (err_sum & IO7__POX_ERRSUM__PCIX_DISCARD_SPL)
		printk("%s    Discarded split completion\n", err_print_prefix);
	if (err_sum & IO7__POX_ERRSUM__DMA_RD_TO)
		printk("%s    DMA Read Timeout\n", err_print_prefix);
	if (err_sum & IO7__POX_ERRSUM__CSR_NXM_RD)
		printk("%s    CSR NXM READ\n", err_print_prefix);
	if (err_sum & IO7__POX_ERRSUM__CSR_NXM_WR)
		printk("%s    CSR NXM WRITE\n", err_print_prefix);
	if (err_sum & IO7__POX_ERRSUM__DETECTED_SERR)
		printk("%s    SERR detected\n", err_print_prefix);
	if (err_sum & IO7__POX_ERRSUM__HUNG_BUS)
		printk("%s    HUNG BUS detected\n", err_print_prefix);
}

#endif /* CONFIG_VERBOSE_MCHECK */

static struct ev7_pal_io_subpacket *
marvel_find_io7_with_error(struct ev7_lf_subpackets *lf_subpackets)
{
	struct ev7_pal_io_subpacket *io = lf_subpackets->io;
	struct io7 *io7;
	int i;

	/*
	 * Caller must provide the packet to fill
	 */
	if (!io)
		return NULL;

	/*
	 * Fill the subpacket with the console's standard fill pattern
	 */
	memset(io, 0x55, sizeof(*io));

	for (io7 = NULL; NULL != (io7 = marvel_next_io7(io7)); ) {
		unsigned long err_sum = 0;

		err_sum |= io7->csrs->PO7_ERROR_SUM.csr;
		for (i = 0; i < IO7_NUM_PORTS; i++) {
			if (!io7->ports[i].enabled)
				continue;
			err_sum |= io7->ports[i].csrs->POx_ERR_SUM.csr;
		}

		/*
		 * Is there at least one error?
		 */
		if (err_sum & (1UL << 63))
			break;
	}

	/*
	 * Did we find an IO7 with an error?
	 */
	if (!io7)
		return NULL;

	/*
	 * We have an IO7 with an error.
	 *
	 * Fill in the IO subpacket.
	 */
	io->io_asic_rev   = io7->csrs->IO_ASIC_REV.csr;
	io->io_sys_rev    = io7->csrs->IO_SYS_REV.csr;
	io->io7_uph       = io7->csrs->IO7_UPH.csr;
	io->hpi_ctl       = io7->csrs->HPI_CTL.csr;
	io->crd_ctl       = io7->csrs->CRD_CTL.csr;
	io->hei_ctl       = io7->csrs->HEI_CTL.csr;
	io->po7_error_sum = io7->csrs->PO7_ERROR_SUM.csr;
	io->po7_uncrr_sym = io7->csrs->PO7_UNCRR_SYM.csr;
	io->po7_crrct_sym = io7->csrs->PO7_CRRCT_SYM.csr;
	io->po7_ugbge_sym = io7->csrs->PO7_UGBGE_SYM.csr;
	io->po7_err_pkt0  = io7->csrs->PO7_ERR_PKT[0].csr;
	io->po7_err_pkt1  = io7->csrs->PO7_ERR_PKT[1].csr;

	for (i = 0; i < IO7_NUM_PORTS; i++) {
		io7_ioport_csrs *csrs = io7->ports[i].csrs;

		if (!io7->ports[i].enabled)
			continue;

		io->ports[i].pox_err_sum   = csrs->POx_ERR_SUM.csr;
		io->ports[i].pox_tlb_err   = csrs->POx_TLB_ERR.csr;
		io->ports[i].pox_spl_cmplt = csrs->POx_SPL_COMPLT.csr;
		io->ports[i].pox_trans_sum = csrs->POx_TRANS_SUM.csr;
		io->ports[i].pox_first_err = csrs->POx_FIRST_ERR.csr;
		io->ports[i].pox_mult_err  = csrs->POx_MULT_ERR.csr;
		io->ports[i].pox_dm_source = csrs->POx_DM_SOURCE.csr;
		io->ports[i].pox_dm_dest   = csrs->POx_DM_DEST.csr;
		io->ports[i].pox_dm_size   = csrs->POx_DM_SIZE.csr;
		io->ports[i].pox_dm_ctrl   = csrs->POx_DM_CTRL.csr;

		/*
		 * Ack this port's errors, if any. POx_ERR_SUM must be last.
		 *
		 * Most of the error registers get cleared and unlocked when
		 * the associated bits in POx_ERR_SUM are cleared (by writing
		 * 1). POx_TLB_ERR is an exception and must be explicitly
		 * cleared.
		 */
		csrs->POx_TLB_ERR.csr = io->ports[i].pox_tlb_err;
		csrs->POx_ERR_SUM.csr =	io->ports[i].pox_err_sum;
		mb();
		csrs->POx_ERR_SUM.csr;
	}

	/*
	 * Ack any port 7 error(s).
	 */
	io7->csrs->PO7_ERROR_SUM.csr = io->po7_error_sum;
	mb();
	io7->csrs->PO7_ERROR_SUM.csr;

	/*
	 * Correct the io7_pid.
	 */
	lf_subpackets->io_pid = io7->pe;

	return io;
}

static int
marvel_process_io_error(struct ev7_lf_subpackets *lf_subpackets, int print)
{
	int status = MCHK_DISPOSITION_UNKNOWN_ERROR;

#ifdef CONFIG_VERBOSE_MCHECK
	struct ev7_pal_io_subpacket *io = lf_subpackets->io;
	int i;
#endif /* CONFIG_VERBOSE_MCHECK */

#define MARVEL_IO_ERR_VALID(x)  ((x) & (1UL << 63))

	if (!lf_subpackets->logout || !lf_subpackets->io)
		return status;

	/*
	 * The PALcode only builds an IO subpacket if there is a
	 * locally connected IO7. In the cases of
	 *	1) a uniprocessor kernel
	 *	2) an mp kernel before the local secondary has called in
	 * error interrupts are all directed to the primary processor.
	 * In that case, we may not have an IO subpacket at all and, event
	 * if we do, it may not be the right now.
	 *
	 * If the RBOX indicates an I/O error interrupt, make sure we have
	 * the correct IO7 information. If we don't have an IO subpacket
	 * or it's the wrong one, try to find the right one.
	 *
	 * RBOX I/O error interrupts are indicated by RBOX_INT<29> and
	 * RBOX_INT<10>.
	 */
	if ((lf_subpackets->io->po7_error_sum & (1UL << 32)) ||
	    ((lf_subpackets->io->po7_error_sum        |
	      lf_subpackets->io->ports[0].pox_err_sum |
	      lf_subpackets->io->ports[1].pox_err_sum |
	      lf_subpackets->io->ports[2].pox_err_sum |
	      lf_subpackets->io->ports[3].pox_err_sum) & (1UL << 63))) {
		/*
		 * Either we have no IO subpacket or no error is
		 * indicated in the one we do have. Try find the
		 * one with the error.
		 */
		if (!marvel_find_io7_with_error(lf_subpackets))
			return status;
	}

	/*
	 * We have an IO7 indicating an error - we're going to report it
	 */
	status = MCHK_DISPOSITION_REPORT;

#ifdef CONFIG_VERBOSE_MCHECK

	if (!print)
		return status;

	printk("%s*Error occurred on IO7 at PID %u\n",
	       err_print_prefix, lf_subpackets->io_pid);

	/*
	 * Check port 7 first
	 */
	if (lf_subpackets->io->po7_error_sum & IO7__PO7_ERRSUM__ERR_MASK) {
		marvel_print_po7_err_sum(io);

#if 0
		printk("%s  PORT 7 ERROR:\n"
		       "%s    PO7_ERROR_SUM: %016llx\n"
		       "%s    PO7_UNCRR_SYM: %016llx\n"
		       "%s    PO7_CRRCT_SYM: %016llx\n"
		       "%s    PO7_UGBGE_SYM: %016llx\n"
		       "%s    PO7_ERR_PKT0:  %016llx\n"
		       "%s    PO7_ERR_PKT1:  %016llx\n",
		       err_print_prefix,
		       err_print_prefix, io->po7_error_sum,
		       err_print_prefix, io->po7_uncrr_sym,
		       err_print_prefix, io->po7_crrct_sym,
		       err_print_prefix, io->po7_ugbge_sym,
		       err_print_prefix, io->po7_err_pkt0,
		       err_print_prefix, io->po7_err_pkt1);
#endif
	}

	/*
	 * Then loop through the ports
	 */
	for (i = 0; i < IO7_NUM_PORTS; i++) {
		if (!MARVEL_IO_ERR_VALID(io->ports[i].pox_err_sum))
			continue;

		printk("%s  PID %u PORT %d POx_ERR_SUM: %016llx\n",
		       err_print_prefix,
		       lf_subpackets->io_pid, i, io->ports[i].pox_err_sum);
		marvel_print_pox_err(io->ports[i].pox_err_sum, &io->ports[i]);

		printk("%s  [ POx_FIRST_ERR: %016llx ]\n",
		       err_print_prefix, io->ports[i].pox_first_err);
		marvel_print_pox_err(io->ports[i].pox_first_err,
				     &io->ports[i]);

	}

#endif /* CONFIG_VERBOSE_MCHECK */

	return status;
}

static int
marvel_process_logout_frame(struct ev7_lf_subpackets *lf_subpackets, int print)
{
	int status = MCHK_DISPOSITION_UNKNOWN_ERROR;

	/*
	 * I/O error?
	 */
#define EV7__RBOX_INT__IO_ERROR__MASK 0x20000400ul
	if (lf_subpackets->logout &&
	    (lf_subpackets->logout->rbox_int & 0x20000400ul))
		status = marvel_process_io_error(lf_subpackets, print);

	/*
	 * Probing behind PCI-X bridges can cause machine checks on
	 * Marvel when the probe is handled by the bridge as a split
	 * completion transaction. The symptom is an ERROR_RESPONSE
	 * to a CONFIG address. Since these errors will happen in
	 * normal operation, dismiss them.
	 *
	 * Dismiss if:
	 *	C_STAT		= 0x14 		(Error Response)
	 *	C_STS<3>	= 0    		(C_ADDR valid)
	 *	C_ADDR<42>	= 1    		(I/O)
	 *	C_ADDR<31:22>	= 111110xxb	(PCI Config space)
	 */
	if (lf_subpackets->ev7 &&
	    (lf_subpackets->ev7->c_stat == 0x14) &&
	    !(lf_subpackets->ev7->c_sts & 0x8) &&
	    ((lf_subpackets->ev7->c_addr & 0x400ff000000ul)
	     == 0x400fe000000ul))
		status = MCHK_DISPOSITION_DISMISS;

	return status;
}

void
marvel_machine_check(unsigned long vector, unsigned long la_ptr)
{
	struct el_subpacket *el_ptr = (struct el_subpacket *)la_ptr;
	int (*process_frame)(struct ev7_lf_subpackets *, int) = NULL;
	struct ev7_lf_subpackets subpacket_collection = { NULL, };
	struct ev7_pal_io_subpacket scratch_io_packet = { 0, };
	struct ev7_lf_subpackets *lf_subpackets = NULL;
	int disposition = MCHK_DISPOSITION_UNKNOWN_ERROR;
	char *saved_err_prefix = err_print_prefix;
	char *error_type = NULL;

	/*
	 * Sync the processor
	 */
	mb();
	draina();

	switch(vector) {
	case SCB_Q_SYSEVENT:
		process_frame = marvel_process_680_frame;
		error_type = "System Event";
		break;

	case SCB_Q_SYSMCHK:
		process_frame = marvel_process_logout_frame;
		error_type = "System Uncorrectable Error";
		break;

	case SCB_Q_SYSERR:
		process_frame = marvel_process_logout_frame;
		error_type = "System Correctable Error";
		break;

	default:
		/* Don't know it - pass it up.  */
		ev7_machine_check(vector, la_ptr);
		return;
	}

	/*
	 * A system event or error has occurred, handle it here.
	 *
	 * Any errors in the logout frame have already been cleared by the
	 * PALcode, so just parse it.
	 */
	err_print_prefix = KERN_CRIT;

	/*
	 * Parse the logout frame without printing first. If the only error(s)
	 * found are classified as "dismissable", then just dismiss them and
	 * don't print any message
	 */
	lf_subpackets =
		ev7_collect_logout_frame_subpackets(el_ptr,
						    &subpacket_collection);
	if (process_frame && lf_subpackets && lf_subpackets->logout) {
		/*
		 * We might not have the correct (or any) I/O subpacket.
		 * [ See marvel_process_io_error() for explanation. ]
		 * If we don't have one, point the io subpacket in
		 * lf_subpackets at scratch_io_packet so that
		 * marvel_find_io7_with_error() will have someplace to
		 * store the info.
		 */
		if (!lf_subpackets->io)
			lf_subpackets->io = &scratch_io_packet;

		/*
		 * Default io_pid to the processor reporting the error
		 * [this will get changed in marvel_find_io7_with_error()
		 * if a different one is needed]
		 */
		lf_subpackets->io_pid = lf_subpackets->logout->whami;

		/*
		 * Evaluate the frames.
		 */
		disposition = process_frame(lf_subpackets, 0);
	}
	switch(disposition) {
	case MCHK_DISPOSITION_DISMISS:
		/* Nothing to do. */
		break;

	case MCHK_DISPOSITION_REPORT:
		/* Recognized error, report it. */
		printk("%s*%s (Vector 0x%x) reported on CPU %d\n",
		       err_print_prefix, error_type,
		       (unsigned int)vector, (int)smp_processor_id());
		el_print_timestamp(&lf_subpackets->logout->timestamp);
		process_frame(lf_subpackets, 1);
		break;

	default:
		/* Unknown - dump the annotated subpackets. */
		printk("%s*%s (Vector 0x%x) reported on CPU %d\n",
		       err_print_prefix, error_type,
		       (unsigned int)vector, (int)smp_processor_id());
		el_process_subpacket(el_ptr);
		break;

	}

	err_print_prefix = saved_err_prefix;

        /* Release the logout frame.  */
	wrmces(0x7);
	mb();
}

void __init
marvel_register_error_handlers(void)
{
	ev7_register_error_handlers();
}


code:
// SPDX-License-Identifier: GPL-2.0
/*
 *	linux/arch/alpha/kernel/err_titan.c
 *
 *	Copyright (C) 2000 Jeff Wiedemeier (Compaq Computer Corporation)
 *
 *	Error handling code supporting TITAN systems
 */

#include <linux/init.h>
#include <linux/pci.h>
#include <linux/sched.h>

#include <asm/io.h>
#include <asm/core_titan.h>
#include <asm/hwrpb.h>
#include <asm/smp.h>
#include <asm/err_common.h>
#include <asm/err_ev6.h>
#include <asm/irq_regs.h>

#include "err_impl.h"
#include "proto.h"

static int
titan_parse_c_misc(u64 c_misc, int print)
{
#ifdef CONFIG_VERBOSE_MCHECK
	char *src;
	int nxs = 0;
#endif
	int status = MCHK_DISPOSITION_REPORT;

#define TITAN__CCHIP_MISC__NXM		(1UL << 28)
#define TITAN__CCHIP_MISC__NXS__S	(29)
#define TITAN__CCHIP_MISC__NXS__M	(0x7)

	if (!(c_misc & TITAN__CCHIP_MISC__NXM))
		return MCHK_DISPOSITION_UNKNOWN_ERROR;

#ifdef CONFIG_VERBOSE_MCHECK
	if (!print)
		return status;

	nxs = EXTRACT(c_misc, TITAN__CCHIP_MISC__NXS);
	switch(nxs) {
	case 0:	/* CPU 0 */
	case 1:	/* CPU 1 */
	case 2:	/* CPU 2 */
	case 3:	/* CPU 3 */
		src = "CPU";
		/* num is already the CPU number */
		break;
	case 4:	/* Pchip 0 */
	case 5:	/* Pchip 1 */
		src = "Pchip";
		nxs -= 4;
		break;
	default:/* reserved */
		src = "Unknown, NXS =";
		/* leave num untouched */
		break;
	}

	printk("%s    Non-existent memory access from: %s %d\n",
	       err_print_prefix, src, nxs);
#endif /* CONFIG_VERBOSE_MCHECK */

	return status;
}

static int
titan_parse_p_serror(int which, u64 serror, int print)
{
	int status = MCHK_DISPOSITION_REPORT;

#ifdef CONFIG_VERBOSE_MCHECK
	static const char * const serror_src[] = {
		"GPCI", "APCI", "AGP HP", "AGP LP"
	};
	static const char * const serror_cmd[] = {
		"DMA Read", "DMA RMW", "SGTE Read", "Reserved"
	};
#endif /* CONFIG_VERBOSE_MCHECK */

#define TITAN__PCHIP_SERROR__LOST_UECC	(1UL << 0)
#define TITAN__PCHIP_SERROR__UECC	(1UL << 1)
#define TITAN__PCHIP_SERROR__CRE	(1UL << 2)
#define TITAN__PCHIP_SERROR__NXIO	(1UL << 3)
#define TITAN__PCHIP_SERROR__LOST_CRE	(1UL << 4)
#define TITAN__PCHIP_SERROR__ECCMASK	(TITAN__PCHIP_SERROR__UECC |	  \
					 TITAN__PCHIP_SERROR__CRE)
#define TITAN__PCHIP_SERROR__ERRMASK	(TITAN__PCHIP_SERROR__LOST_UECC | \
					 TITAN__PCHIP_SERROR__UECC |	  \
					 TITAN__PCHIP_SERROR__CRE |	  \
					 TITAN__PCHIP_SERROR__NXIO |	  \
					 TITAN__PCHIP_SERROR__LOST_CRE)
#define TITAN__PCHIP_SERROR__SRC__S	(52)
#define TITAN__PCHIP_SERROR__SRC__M	(0x3)
#define TITAN__PCHIP_SERROR__CMD__S	(54)
#define TITAN__PCHIP_SERROR__CMD__M	(0x3)
#define TITAN__PCHIP_SERROR__SYN__S	(56)
#define TITAN__PCHIP_SERROR__SYN__M	(0xff)
#define TITAN__PCHIP_SERROR__ADDR__S	(15)
#define TITAN__PCHIP_SERROR__ADDR__M	(0xffffffffUL)

	if (!(serror & TITAN__PCHIP_SERROR__ERRMASK))
		return MCHK_DISPOSITION_UNKNOWN_ERROR;

#ifdef CONFIG_VERBOSE_MCHECK
	if (!print)
		return status;

	printk("%s  PChip %d SERROR: %016llx\n",
	       err_print_prefix, which, serror);
	if (serror & TITAN__PCHIP_SERROR__ECCMASK) {
		printk("%s    %sorrectable ECC Error:\n"
		       "      Source: %-6s  Command: %-8s  Syndrome: 0x%08x\n"
		       "      Address: 0x%llx\n",
		       err_print_prefix,
		       (serror & TITAN__PCHIP_SERROR__UECC) ? "Unc" : "C",
		       serror_src[EXTRACT(serror, TITAN__PCHIP_SERROR__SRC)],
		       serror_cmd[EXTRACT(serror, TITAN__PCHIP_SERROR__CMD)],
		       (unsigned)EXTRACT(serror, TITAN__PCHIP_SERROR__SYN),
		       EXTRACT(serror, TITAN__PCHIP_SERROR__ADDR));
	}
	if (serror & TITAN__PCHIP_SERROR__NXIO)
		printk("%s    Non Existent I/O Error\n", err_print_prefix);
	if (serror & TITAN__PCHIP_SERROR__LOST_UECC)
		printk("%s    Lost Uncorrectable ECC Error\n",
		       err_print_prefix);
	if (serror & TITAN__PCHIP_SERROR__LOST_CRE)
		printk("%s    Lost Correctable ECC Error\n", err_print_prefix);
#endif /* CONFIG_VERBOSE_MCHECK */

	return status;
}

static int
titan_parse_p_perror(int which, int port, u64 perror, int print)
{
	int cmd;
	unsigned long addr;
	int status = MCHK_DISPOSITION_REPORT;

#ifdef CONFIG_VERBOSE_MCHECK
	static const char * const perror_cmd[] = {
		"Interrupt Acknowledge", "Special Cycle",
		"I/O Read",		"I/O Write",
		"Reserved",		"Reserved",
		"Memory Read",		"Memory Write",
		"Reserved",		"Reserved",
		"Configuration Read",	"Configuration Write",
		"Memory Read Multiple",	"Dual Address Cycle",
		"Memory Read Line",	"Memory Write and Invalidate"
	};
#endif /* CONFIG_VERBOSE_MCHECK */

#define TITAN__PCHIP_PERROR__LOST	(1UL << 0)
#define TITAN__PCHIP_PERROR__SERR	(1UL << 1)
#define TITAN__PCHIP_PERROR__PERR	(1UL << 2)
#define TITAN__PCHIP_PERROR__DCRTO	(1UL << 3)
#define TITAN__PCHIP_PERROR__SGE	(1UL << 4)
#define TITAN__PCHIP_PERROR__APE	(1UL << 5)
#define TITAN__PCHIP_PERROR__TA		(1UL << 6)
#define TITAN__PCHIP_PERROR__DPE	(1UL << 7)
#define TITAN__PCHIP_PERROR__NDS	(1UL << 8)
#define TITAN__PCHIP_PERROR__IPTPR	(1UL << 9)
#define TITAN__PCHIP_PERROR__IPTPW	(1UL << 10)
#define TITAN__PCHIP_PERROR__ERRMASK	(TITAN__PCHIP_PERROR__LOST |	\
					 TITAN__PCHIP_PERROR__SERR |	\
					 TITAN__PCHIP_PERROR__PERR |	\
					 TITAN__PCHIP_PERROR__DCRTO |	\
					 TITAN__PCHIP_PERROR__SGE |	\
					 TITAN__PCHIP_PERROR__APE |	\
					 TITAN__PCHIP_PERROR__TA |	\
					 TITAN__PCHIP_PERROR__DPE |	\
					 TITAN__PCHIP_PERROR__NDS |	\
					 TITAN__PCHIP_PERROR__IPTPR |	\
					 TITAN__PCHIP_PERROR__IPTPW)
#define TITAN__PCHIP_PERROR__DAC	(1UL << 47)
#define TITAN__PCHIP_PERROR__MWIN	(1UL << 48)
#define TITAN__PCHIP_PERROR__CMD__S	(52)
#define TITAN__PCHIP_PERROR__CMD__M	(0x0f)
#define TITAN__PCHIP_PERROR__ADDR__S	(14)
#define TITAN__PCHIP_PERROR__ADDR__M	(0x1fffffffful)

	if (!(perror & TITAN__PCHIP_PERROR__ERRMASK))
		return MCHK_DISPOSITION_UNKNOWN_ERROR;

	cmd = EXTRACT(perror, TITAN__PCHIP_PERROR__CMD);
	addr = EXTRACT(perror, TITAN__PCHIP_PERROR__ADDR) << 2;

	/*
	 * Initializing the BIOS on a video card on a bus without
	 * a south bridge (subtractive decode agent) can result in
	 * master aborts as the BIOS probes the capabilities of the
	 * card. XFree86 does such initialization. If the error
	 * is a master abort (No DevSel as PCI Master) and the command
	 * is an I/O read or write below the address where we start
	 * assigning PCI I/O spaces (SRM uses 0x1000), then mark the
	 * error as dismissable so starting XFree86 doesn't result
	 * in a series of uncorrectable errors being reported. Also
	 * dismiss master aborts to VGA frame buffer space
	 * (0xA0000 - 0xC0000) and legacy BIOS space (0xC0000 - 0x100000)
	 * for the same reason.
	 *
	 * Also mark the error dismissible if it looks like the right
	 * error but only the Lost bit is set. Since the BIOS initialization
	 * can cause multiple master aborts and the error interrupt can
	 * be handled on a different CPU than the BIOS code is run on,
	 * it is possible for a second master abort to occur between the
	 * time the PALcode reads PERROR and the time it writes PERROR
	 * to acknowledge the error. If this timing happens, a second
	 * error will be signalled after the first, and if no additional
	 * errors occur, will look like a Lost error with no additional
	 * errors on the same transaction as the previous error.
	 */
	if (((perror & TITAN__PCHIP_PERROR__NDS) ||
	     ((perror & TITAN__PCHIP_PERROR__ERRMASK) ==
	      TITAN__PCHIP_PERROR__LOST)) &&
	    ((((cmd & 0xE) == 2) && (addr < 0x1000)) ||
	     (((cmd & 0xE) == 6) && (addr >= 0xA0000) && (addr < 0x100000)))) {
		status = MCHK_DISPOSITION_DISMISS;
	}

#ifdef CONFIG_VERBOSE_MCHECK
	if (!print)
		return status;

	printk("%s  PChip %d %cPERROR: %016llx\n",
	       err_print_prefix, which,
	       port ? 'A' : 'G', perror);
	if (perror & TITAN__PCHIP_PERROR__IPTPW)
		printk("%s    Invalid Peer-to-Peer Write\n", err_print_prefix);
	if (perror & TITAN__PCHIP_PERROR__IPTPR)
		printk("%s    Invalid Peer-to-Peer Read\n", err_print_prefix);
	if (perror & TITAN__PCHIP_PERROR__NDS)
		printk("%s    No DEVSEL as PCI Master [Master Abort]\n",
		       err_print_prefix);
	if (perror & TITAN__PCHIP_PERROR__DPE)
		printk("%s    Data Parity Error\n", err_print_prefix);
	if (perror & TITAN__PCHIP_PERROR__TA)
		printk("%s    Target Abort\n", err_print_prefix);
	if (perror & TITAN__PCHIP_PERROR__APE)
		printk("%s    Address Parity Error\n", err_print_prefix);
	if (perror & TITAN__PCHIP_PERROR__SGE)
		printk("%s    Scatter-Gather Error, Invalid PTE\n",
		       err_print_prefix);
	if (perror & TITAN__PCHIP_PERROR__DCRTO)
		printk("%s    Delayed-Completion Retry Timeout\n",
		       err_print_prefix);
	if (perror & TITAN__PCHIP_PERROR__PERR)
		printk("%s    PERR Asserted\n", err_print_prefix);
	if (perror & TITAN__PCHIP_PERROR__SERR)
		printk("%s    SERR Asserted\n", err_print_prefix);
	if (perror & TITAN__PCHIP_PERROR__LOST)
		printk("%s    Lost Error\n", err_print_prefix);
	printk("%s      Command: 0x%x - %s\n"
		 "      Address: 0x%lx\n",
	       err_print_prefix,
	       cmd, perror_cmd[cmd],
	       addr);
	if (perror & TITAN__PCHIP_PERROR__DAC)
		printk("%s      Dual Address Cycle\n", err_print_prefix);
	if (perror & TITAN__PCHIP_PERROR__MWIN)
		printk("%s      Hit in Monster Window\n", err_print_prefix);
#endif /* CONFIG_VERBOSE_MCHECK */

	return status;
}

static int
titan_parse_p_agperror(int which, u64 agperror, int print)
{
	int status = MCHK_DISPOSITION_REPORT;
#ifdef CONFIG_VERBOSE_MCHECK
	int cmd, len;
	unsigned long addr;

	static const char * const agperror_cmd[] = {
		"Read (low-priority)",	"Read (high-priority)",
		"Write (low-priority)",	"Write (high-priority)",
		"Reserved",		"Reserved",
		"Flush",		"Fence"
	};
#endif /* CONFIG_VERBOSE_MCHECK */

#define TITAN__PCHIP_AGPERROR__LOST	(1UL << 0)
#define TITAN__PCHIP_AGPERROR__LPQFULL	(1UL << 1)
#define TITAN__PCHIP_AGPERROR__HPQFULL	(1UL << 2)
#define TITAN__PCHIP_AGPERROR__RESCMD	(1UL << 3)
#define TITAN__PCHIP_AGPERROR__IPTE	(1UL << 4)
#define TITAN__PCHIP_AGPERROR__PTP	(1UL << 5)
#define TITAN__PCHIP_AGPERROR__NOWINDOW	(1UL << 6)
#define TITAN__PCHIP_AGPERROR__ERRMASK	(TITAN__PCHIP_AGPERROR__LOST |    \
					 TITAN__PCHIP_AGPERROR__LPQFULL | \
					 TITAN__PCHIP_AGPERROR__HPQFULL | \
					 TITAN__PCHIP_AGPERROR__RESCMD |  \
					 TITAN__PCHIP_AGPERROR__IPTE |    \
					 TITAN__PCHIP_AGPERROR__PTP |     \
					 TITAN__PCHIP_AGPERROR__NOWINDOW)
#define TITAN__PCHIP_AGPERROR__DAC	(1UL << 48)
#define TITAN__PCHIP_AGPERROR__MWIN	(1UL << 49)
#define TITAN__PCHIP_AGPERROR__FENCE	(1UL << 59)
#define TITAN__PCHIP_AGPERROR__CMD__S	(50)
#define TITAN__PCHIP_AGPERROR__CMD__M	(0x07)
#define TITAN__PCHIP_AGPERROR__ADDR__S	(15)
#define TITAN__PCHIP_AGPERROR__ADDR__M  (0xffffffffUL)
#define TITAN__PCHIP_AGPERROR__LEN__S	(53)
#define TITAN__PCHIP_AGPERROR__LEN__M	(0x3f)

	if (!(agperror & TITAN__PCHIP_AGPERROR__ERRMASK))
		return MCHK_DISPOSITION_UNKNOWN_ERROR;

#ifdef CONFIG_VERBOSE_MCHECK
	if (!print)
		return status;

	cmd = EXTRACT(agperror, TITAN__PCHIP_AGPERROR__CMD);
	addr = EXTRACT(agperror, TITAN__PCHIP_AGPERROR__ADDR) << 3;
	len = EXTRACT(agperror, TITAN__PCHIP_AGPERROR__LEN);

	printk("%s  PChip %d AGPERROR: %016llx\n", err_print_prefix,
	       which, agperror);
	if (agperror & TITAN__PCHIP_AGPERROR__NOWINDOW)
		printk("%s    No Window\n", err_print_prefix);
	if (agperror & TITAN__PCHIP_AGPERROR__PTP)
		printk("%s    Peer-to-Peer set\n", err_print_prefix);
	if (agperror & TITAN__PCHIP_AGPERROR__IPTE)
		printk("%s    Invalid PTE\n", err_print_prefix);
	if (agperror & TITAN__PCHIP_AGPERROR__RESCMD)
		printk("%s    Reserved Command\n", err_print_prefix);
	if (agperror & TITAN__PCHIP_AGPERROR__HPQFULL)
		printk("%s    HP Transaction Received while Queue Full\n",
		       err_print_prefix);
	if (agperror & TITAN__PCHIP_AGPERROR__LPQFULL)
		printk("%s    LP Transaction Received while Queue Full\n",
		       err_print_prefix);
	if (agperror & TITAN__PCHIP_AGPERROR__LOST)
		printk("%s    Lost Error\n", err_print_prefix);
	printk("%s      Command: 0x%x - %s, %d Quadwords%s\n"
		 "      Address: 0x%lx\n",
	       err_print_prefix, cmd, agperror_cmd[cmd], len,
	       (agperror & TITAN__PCHIP_AGPERROR__FENCE) ? ", FENCE" : "",
	       addr);
	if (agperror & TITAN__PCHIP_AGPERROR__DAC)
		printk("%s      Dual Address Cycle\n", err_print_prefix);
	if (agperror & TITAN__PCHIP_AGPERROR__MWIN)
		printk("%s      Hit in Monster Window\n", err_print_prefix);
#endif /* CONFIG_VERBOSE_MCHECK */

	return status;
}

static int
titan_parse_p_chip(int which, u64 serror, u64 gperror,
		   u64 aperror, u64 agperror, int print)
{
	int status = MCHK_DISPOSITION_UNKNOWN_ERROR;
	status |= titan_parse_p_serror(which, serror, print);
	status |= titan_parse_p_perror(which, 0, gperror, print);
	status |= titan_parse_p_perror(which, 1, aperror, print);
	status |= titan_parse_p_agperror(which, agperror, print);
	return status;
}

int
titan_process_logout_frame(struct el_common *mchk_header, int print)
{
	struct el_TITAN_sysdata_mcheck *tmchk =
		(struct el_TITAN_sysdata_mcheck *)
		((unsigned long)mchk_header + mchk_header->sys_offset);
	int status = MCHK_DISPOSITION_UNKNOWN_ERROR;

	status |= titan_parse_c_misc(tmchk->c_misc, print);
	status |= titan_parse_p_chip(0, tmchk->p0_serror, tmchk->p0_gperror,
				     tmchk->p0_aperror, tmchk->p0_agperror,
				     print);
	status |= titan_parse_p_chip(1, tmchk->p1_serror, tmchk->p1_gperror,
				     tmchk->p1_aperror, tmchk->p1_agperror,
				     print);

	return status;
}

void
titan_machine_check(unsigned long vector, unsigned long la_ptr)
{
	struct el_common *mchk_header = (struct el_common *)la_ptr;
	struct el_TITAN_sysdata_mcheck *tmchk =
		(struct el_TITAN_sysdata_mcheck *)
		((unsigned long)mchk_header + mchk_header->sys_offset);
	u64 irqmask;

	/*
	 * Mask of Titan interrupt sources which are reported as machine checks
	 *
	 * 63 - CChip Error
	 * 62 - PChip 0 H_Error
	 * 61 - PChip 1 H_Error
	 * 60 - PChip 0 C_Error
	 * 59 - PChip 1 C_Error
	 */
#define TITAN_MCHECK_INTERRUPT_MASK	0xF800000000000000UL

	/*
	 * Sync the processor
	 */
	mb();
	draina();

	/*
	 * Only handle system errors here
	 */
	if ((vector != SCB_Q_SYSMCHK) && (vector != SCB_Q_SYSERR)) {
		ev6_machine_check(vector, la_ptr);
		return;
	}

	/*
	 * It's a system error, handle it here
	 *
	 * The PALcode has already cleared the error, so just parse it
	 */

	/*
	 * Parse the logout frame without printing first. If the only error(s)
	 * found are classified as "dismissable", then just dismiss them and
	 * don't print any message
	 */
	if (titan_process_logout_frame(mchk_header, 0) !=
	    MCHK_DISPOSITION_DISMISS) {
		char *saved_err_prefix = err_print_prefix;
		err_print_prefix = KERN_CRIT;

		/*
		 * Either a nondismissable error was detected or no
		 * recognized error was detected  in the logout frame
		 * -- report the error in either case
		 */
		printk("%s"
		       "*System %s Error (Vector 0x%x) reported on CPU %d:\n",
		       err_print_prefix,
		       (vector == SCB_Q_SYSERR)?"Correctable":"Uncorrectable",
		       (unsigned int)vector, (int)smp_processor_id());

#ifdef CONFIG_VERBOSE_MCHECK
		titan_process_logout_frame(mchk_header, alpha_verbose_mcheck);
		if (alpha_verbose_mcheck)
			dik_show_regs(get_irq_regs(), NULL);
#endif /* CONFIG_VERBOSE_MCHECK */

		err_print_prefix = saved_err_prefix;

		/*
		 * Convert any pending interrupts which report as system
		 * machine checks to interrupts
		 */
		irqmask = tmchk->c_dirx & TITAN_MCHECK_INTERRUPT_MASK;
		titan_dispatch_irqs(irqmask);
	}

	/*
	 * Release the logout frame
	 */
	wrmces(0x7);
	mb();
}

/*
 * Subpacket Annotations
 */
static char *el_titan_pchip0_extended_annotation[] = {
	"Subpacket Header", 	"P0_SCTL",	"P0_SERREN",
	"P0_APCTL",		"P0_APERREN",	"P0_AGPERREN",
	"P0_ASPRST",		"P0_AWSBA0",	"P0_AWSBA1",
	"P0_AWSBA2",		"P0_AWSBA3",	"P0_AWSM0",
	"P0_AWSM1",		"P0_AWSM2",	"P0_AWSM3",
	"P0_ATBA0",		"P0_ATBA1",	"P0_ATBA2",
	"P0_ATBA3",		"P0_GPCTL",	"P0_GPERREN",
	"P0_GSPRST",		"P0_GWSBA0",	"P0_GWSBA1",
	"P0_GWSBA2",		"P0_GWSBA3",	"P0_GWSM0",
	"P0_GWSM1",		"P0_GWSM2",	"P0_GWSM3",
	"P0_GTBA0",		"P0_GTBA1",	"P0_GTBA2",
	"P0_GTBA3",		NULL
};
static char *el_titan_pchip1_extended_annotation[] = {
	"Subpacket Header", 	"P1_SCTL",	"P1_SERREN",
	"P1_APCTL",		"P1_APERREN",	"P1_AGPERREN",
	"P1_ASPRST",		"P1_AWSBA0",	"P1_AWSBA1",
	"P1_AWSBA2",		"P1_AWSBA3",	"P1_AWSM0",
	"P1_AWSM1",		"P1_AWSM2",	"P1_AWSM3",
	"P1_ATBA0",		"P1_ATBA1",	"P1_ATBA2",
	"P1_ATBA3",		"P1_GPCTL",	"P1_GPERREN",
	"P1_GSPRST",		"P1_GWSBA0",	"P1_GWSBA1",
	"P1_GWSBA2",		"P1_GWSBA3",	"P1_GWSM0",
	"P1_GWSM1",		"P1_GWSM2",	"P1_GWSM3",
	"P1_GTBA0",		"P1_GTBA1",	"P1_GTBA2",
	"P1_GTBA3",		NULL
};
static char *el_titan_memory_extended_annotation[] = {
	"Subpacket Header", 	"AAR0",		"AAR1",
	"AAR2",			"AAR3",		"P0_SCTL",
	"P0_GPCTL",		"P0_APCTL",	"P1_SCTL",
	"P1_GPCTL",		"P1_SCTL",	NULL
};

static struct el_subpacket_annotation el_titan_annotations[] = {
	SUBPACKET_ANNOTATION(EL_CLASS__REGATTA_FAMILY,
			     EL_TYPE__REGATTA__TITAN_PCHIP0_EXTENDED,
			     1,
			     "Titan PChip 0 Extended Frame",
			     el_titan_pchip0_extended_annotation),
	SUBPACKET_ANNOTATION(EL_CLASS__REGATTA_FAMILY,
			     EL_TYPE__REGATTA__TITAN_PCHIP1_EXTENDED,
			     1,
			     "Titan PChip 1 Extended Frame",
			     el_titan_pchip1_extended_annotation),
	SUBPACKET_ANNOTATION(EL_CLASS__REGATTA_FAMILY,
			     EL_TYPE__REGATTA__TITAN_MEMORY_EXTENDED,
			     1,
			     "Titan Memory Extended Frame",
			     el_titan_memory_extended_annotation),
	SUBPACKET_ANNOTATION(EL_CLASS__REGATTA_FAMILY,
			     EL_TYPE__TERMINATION__TERMINATION,
			     1,
			     "Termination Subpacket",
			     NULL)
};

static struct el_subpacket *
el_process_regatta_subpacket(struct el_subpacket *header)
{
	if (header->class != EL_CLASS__REGATTA_FAMILY) {
		printk("%s  ** Unexpected header CLASS %d TYPE %d, aborting\n",
		       err_print_prefix,
		       header->class, header->type);
		return NULL;
	}

	switch(header->type) {
	case EL_TYPE__REGATTA__PROCESSOR_ERROR_FRAME:
	case EL_TYPE__REGATTA__SYSTEM_ERROR_FRAME:
	case EL_TYPE__REGATTA__ENVIRONMENTAL_FRAME:
	case EL_TYPE__REGATTA__PROCESSOR_DBL_ERROR_HALT:
	case EL_TYPE__REGATTA__SYSTEM_DBL_ERROR_HALT:
		printk("%s  ** Occurred on CPU %d:\n",
		       err_print_prefix,
		       (int)header->by_type.regatta_frame.cpuid);
		privateer_process_logout_frame((struct el_common *)
			header->by_type.regatta_frame.data_start, 1);
		break;
	default:
		printk("%s  ** REGATTA TYPE %d SUBPACKET\n",
		       err_print_prefix, header->type);
		el_annotate_subpacket(header);
		break;
	}

	return (struct el_subpacket *)((unsigned long)header + header->length);
}

static struct el_subpacket_handler titan_subpacket_handler =
	SUBPACKET_HANDLER_INIT(EL_CLASS__REGATTA_FAMILY,
			       el_process_regatta_subpacket);

void __init
titan_register_error_handlers(void)
{
	size_t i;

	for (i = 0; i < ARRAY_SIZE (el_titan_annotations); i++)
		cdl_register_subpacket_annotation(&el_titan_annotations[i]);

	cdl_register_subpacket_handler(&titan_subpacket_handler);

	ev6_register_error_handlers();
}

/*
 * Privateer
 */

static int
privateer_process_680_frame(struct el_common *mchk_header, int print)
{
	int status = MCHK_DISPOSITION_UNKNOWN_ERROR;
#ifdef CONFIG_VERBOSE_MCHECK
	struct el_PRIVATEER_envdata_mcheck *emchk =
		(struct el_PRIVATEER_envdata_mcheck *)
		((unsigned long)mchk_header + mchk_header->sys_offset);

	/* TODO - categorize errors, for now, no error */

	if (!print)
		return status;

	/* TODO - decode instead of just dumping... */
	printk("%s  Summary Flags:         %016llx\n"
 	         "  CChip DIRx:            %016llx\n"
		 "  System Management IR:  %016llx\n"
		 "  CPU IR:                %016llx\n"
		 "  Power Supply IR:       %016llx\n"
		 "  LM78 Fault Status:     %016llx\n"
		 "  System Doors:          %016llx\n"
		 "  Temperature Warning:   %016llx\n"
		 "  Fan Control:           %016llx\n"
		 "  Fatal Power Down Code: %016llx\n",
	       err_print_prefix,
	       emchk->summary,
	       emchk->c_dirx,
	       emchk->smir,
	       emchk->cpuir,
	       emchk->psir,
	       emchk->fault,
	       emchk->sys_doors,
	       emchk->temp_warn,
	       emchk->fan_ctrl,
	       emchk->code);
#endif /* CONFIG_VERBOSE_MCHECK */

	return status;
}

int
privateer_process_logout_frame(struct el_common *mchk_header, int print)
{
	struct el_common_EV6_mcheck *ev6mchk =
		(struct el_common_EV6_mcheck *)mchk_header;
	int status = MCHK_DISPOSITION_UNKNOWN_ERROR;

	/*
	 * Machine check codes
	 */
#define PRIVATEER_MCHK__CORR_ECC		0x86	/* 630 */
#define PRIVATEER_MCHK__DC_TAG_PERR		0x9E	/* 630 */
#define PRIVATEER_MCHK__PAL_BUGCHECK		0x8E	/* 670 */
#define PRIVATEER_MCHK__OS_BUGCHECK		0x90	/* 670 */
#define PRIVATEER_MCHK__PROC_HRD_ERR		0x98	/* 670 */
#define PRIVATEER_MCHK__ISTREAM_CMOV_PRX	0xA0	/* 670 */
#define PRIVATEER_MCHK__ISTREAM_CMOV_FLT	0xA2	/* 670 */
#define PRIVATEER_MCHK__SYS_HRD_ERR		0x202	/* 660 */
#define PRIVATEER_MCHK__SYS_CORR_ERR		0x204	/* 620 */
#define PRIVATEER_MCHK__SYS_ENVIRON		0x206	/* 680 */

	switch(ev6mchk->MCHK_Code) {
	/*
	 * Vector 630 - Processor, Correctable
	 */
	case PRIVATEER_MCHK__CORR_ECC:
	case PRIVATEER_MCHK__DC_TAG_PERR:
		/*
		 * Fall through to vector 670 for processing...
		 */
	/*
	 * Vector 670 - Processor, Uncorrectable
	 */
	case PRIVATEER_MCHK__PAL_BUGCHECK:
	case PRIVATEER_MCHK__OS_BUGCHECK:
	case PRIVATEER_MCHK__PROC_HRD_ERR:
	case PRIVATEER_MCHK__ISTREAM_CMOV_PRX:
	case PRIVATEER_MCHK__ISTREAM_CMOV_FLT:
		status |= ev6_process_logout_frame(mchk_header, print);
		break;

	/*
	 * Vector 620 - System, Correctable
	 */
	case PRIVATEER_MCHK__SYS_CORR_ERR:
		/*
		 * Fall through to vector 660 for processing...
		 */
	/*
	 * Vector 660 - System, Uncorrectable
	 */
	case PRIVATEER_MCHK__SYS_HRD_ERR:
		status |= titan_process_logout_frame(mchk_header, print);
		break;

	/*
	 * Vector 680 - System, Environmental
	 */
	case PRIVATEER_MCHK__SYS_ENVIRON:	/* System, Environmental */
		status |= privateer_process_680_frame(mchk_header, print);
		break;

	/*
	 * Unknown
	 */
	default:
		status |= MCHK_DISPOSITION_REPORT;
		if (print) {
			printk("%s** Unknown Error, frame follows\n",
			       err_print_prefix);
			mchk_dump_logout_frame(mchk_header);
		}

	}

	return status;
}

void
privateer_machine_check(unsigned long vector, unsigned long la_ptr)
{
	struct el_common *mchk_header = (struct el_common *)la_ptr;
	struct el_TITAN_sysdata_mcheck *tmchk =
		(struct el_TITAN_sysdata_mcheck *)
		(la_ptr + mchk_header->sys_offset);
	u64 irqmask;
	char *saved_err_prefix = err_print_prefix;

#define PRIVATEER_680_INTERRUPT_MASK		(0xE00UL)
#define PRIVATEER_HOTPLUG_INTERRUPT_MASK	(0xE00UL)

	/*
	 * Sync the processor.
	 */
	mb();
	draina();

	/*
	 * Only handle system events here.
	 */
	if (vector != SCB_Q_SYSEVENT)
		return titan_machine_check(vector, la_ptr);

	/*
	 * Report the event - System Events should be reported even if no
	 * error is indicated since the event could indicate the return
	 * to normal status.
	 */
	err_print_prefix = KERN_CRIT;
	printk("%s*System Event (Vector 0x%x) reported on CPU %d:\n",
	       err_print_prefix,
	       (unsigned int)vector, (int)smp_processor_id());
	privateer_process_680_frame(mchk_header, 1);
	err_print_prefix = saved_err_prefix;

	/*
	 * Convert any pending interrupts which report as 680 machine
	 * checks to interrupts.
	 */
	irqmask = tmchk->c_dirx & PRIVATEER_680_INTERRUPT_MASK;

	/*
	 * Dispatch the interrupt(s).
	 */
	titan_dispatch_irqs(irqmask);

	/*
	 * Release the logout frame.
	 */
	wrmces(0x7);
	mb();
}

repo_name: angery/linux


code:
// SPDX-License-Identifier: GPL-2.0
/*
 *	linux/arch/alpha/kernel/es1888.c
 *
 * Init the built-in ES1888 sound chip (SB16 compatible)
 */

#include <linux/init.h>
#include <asm/io.h>
#include "proto.h"

void __init
es1888_init(void)
{
	/* Sequence of IO reads to init the audio controller */
	inb(0x0229);
	inb(0x0229);
	inb(0x0229);
	inb(0x022b);
	inb(0x0229);
	inb(0x022b);
	inb(0x0229);
	inb(0x0229);
	inb(0x022b);
	inb(0x0229);
	inb(0x0220); /* This sets the base address to 0x220 */

	/* Sequence to set DMA channels */
	outb(0x01, 0x0226);		/* reset */
	inb(0x0226);			/* pause */
	outb(0x00, 0x0226);		/* release reset */
	while (!(inb(0x022e) & 0x80))	/* wait for bit 7 to assert*/
		continue;
	inb(0x022a);			/* pause */
	outb(0xc6, 0x022c);		/* enable extended mode */
	inb(0x022a);			/* pause, also forces the write */
	while (inb(0x022c) & 0x80)	/* wait for bit 7 to deassert */
		continue;
	outb(0xb1, 0x022c);		/* setup for write to Interrupt CR */
	while (inb(0x022c) & 0x80)	/* wait for bit 7 to deassert */
		continue;
	outb(0x14, 0x022c);		/* set IRQ 5 */
	while (inb(0x022c) & 0x80)	/* wait for bit 7 to deassert */
		continue;
	outb(0xb2, 0x022c);		/* setup for write to DMA CR */
	while (inb(0x022c) & 0x80)	/* wait for bit 7 to deassert */
		continue;
	outb(0x18, 0x022c);		/* set DMA channel 1 */
	inb(0x022c);			/* force the write */
}


code:
// SPDX-License-Identifier: GPL-2.0
/*
 *	linux/arch/alpha/kernel/gct.c
 */

#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/errno.h>

#include <asm/hwrpb.h>
#include <asm/gct.h>

int
gct6_find_nodes(gct6_node *node, gct6_search_struct *search)
{
	gct6_search_struct *wanted;
	int status = 0;

	/* First check the magic number.  */
	if (node->magic != GCT_NODE_MAGIC) {
		printk(KERN_ERR "GCT Node MAGIC incorrect - GCT invalid\n");
		return -EINVAL;
	}

	/* Check against the search struct.  */
	for (wanted = search;
	     wanted && (wanted->type | wanted->subtype);
	     wanted++) {
		if (node->type != wanted->type)
			continue;
		if (node->subtype != wanted->subtype)
			continue;

		/* Found it -- call out.  */
		if (wanted->callout)
			wanted->callout(node);
	}

	/* Now walk the tree, siblings first.  */
	if (node->next)
		status |= gct6_find_nodes(GCT_NODE_PTR(node->next), search);

	/* Then the children.  */
	if (node->child)
		status |= gct6_find_nodes(GCT_NODE_PTR(node->child), search);

	return status;
}


code:
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * arch/alpha/kernel/head.S
 *
 * initial boot stuff.. At this point, the bootloader has already
 * switched into OSF/1 PAL-code, and loaded us at the correct address
 * (START_ADDR).  So there isn't much left for us to do: just set up
 * the kernel global pointer and jump to the kernel entry-point.
 */

#include <linux/init.h>
#include <asm/asm-offsets.h>
#include <asm/pal.h>
#include <asm/setup.h>

__HEAD
.globl _stext
	.set noreorder
	.globl	__start
	.ent	__start
_stext:
__start:
	.prologue 0
	br	$27,1f
1:	ldgp	$29,0($27)
	/* We need to get current_task_info loaded up...  */
	lda	$8,init_thread_union
	/* ... and find our stack ... */
	lda	$30,0x4000 - SIZEOF_PT_REGS($8)
	/* ... and then we can start the kernel.  */
	jsr	$26,start_kernel
	call_pal PAL_halt
	.end __start

#ifdef CONFIG_SMP
	.align 3
	.globl	__smp_callin
	.ent	__smp_callin
	/* On entry here from SRM console, the HWPCB of the per-cpu
	   slot for this processor has been loaded.  We've arranged
	   for the UNIQUE value for this process to contain the PCBB
	   of the target idle task.  */
__smp_callin:
	.prologue 1
	ldgp	$29,0($27)	# First order of business, load the GP.

	call_pal PAL_rduniq	# Grab the target PCBB.
	mov	$0,$16		# Install it.
	call_pal PAL_swpctx

	lda	$8,0x3fff	# Find "current".
	bic	$30,$8,$8

	jsr	$26,smp_callin
	call_pal PAL_halt
	.end __smp_callin
#endif /* CONFIG_SMP */

	#
	# The following two functions are needed for supporting SRM PALcode
	# on the PC164 (at least), since that PALcode manages the interrupt
	# masking, and we cannot duplicate the effort without causing problems
	#

	.align 3
	.globl	cserve_ena
	.ent	cserve_ena
cserve_ena:
	.prologue 0
	bis	$16,$16,$17
	lda	$16,52($31)
	call_pal PAL_cserve
	ret	($26)
	.end	cserve_ena

	.align 3
	.globl	cserve_dis
	.ent	cserve_dis
cserve_dis:
	.prologue 0
	bis	$16,$16,$17
	lda	$16,53($31)
	call_pal PAL_cserve
	ret	($26)
	.end	cserve_dis

	#
	# It is handy, on occasion, to make halt actually just loop.
	# Putting it here means we dont have to recompile the whole
	# kernel.
	#

	.align 3
	.globl	halt
	.ent	halt
halt:
	.prologue 0
	call_pal PAL_halt
	.end	halt


code:
// SPDX-License-Identifier: GPL-2.0
/*
 * Alpha IO and memory functions.
 */

#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/module.h>
#include <asm/io.h>

/* Out-of-line versions of the i/o routines that redirect into the
   platform-specific version.  Note that "platform-specific" may mean
   "generic", which bumps through the machine vector.  */

unsigned int
ioread8(const void __iomem *addr)
{
	unsigned int ret;
	mb();
	ret = IO_CONCAT(__IO_PREFIX,ioread8)(addr);
	mb();
	return ret;
}

unsigned int ioread16(const void __iomem *addr)
{
	unsigned int ret;
	mb();
	ret = IO_CONCAT(__IO_PREFIX,ioread16)(addr);
	mb();
	return ret;
}

unsigned int ioread32(const void __iomem *addr)
{
	unsigned int ret;
	mb();
	ret = IO_CONCAT(__IO_PREFIX,ioread32)(addr);
	mb();
	return ret;
}

u64 ioread64(const void __iomem *addr)
{
	unsigned int ret;
	mb();
	ret = IO_CONCAT(__IO_PREFIX,ioread64)(addr);
	mb();
	return ret;
}

void iowrite8(u8 b, void __iomem *addr)
{
	mb();
	IO_CONCAT(__IO_PREFIX,iowrite8)(b, addr);
}

void iowrite16(u16 b, void __iomem *addr)
{
	mb();
	IO_CONCAT(__IO_PREFIX,iowrite16)(b, addr);
}

void iowrite32(u32 b, void __iomem *addr)
{
	mb();
	IO_CONCAT(__IO_PREFIX,iowrite32)(b, addr);
}

void iowrite64(u64 b, void __iomem *addr)
{
	mb();
	IO_CONCAT(__IO_PREFIX,iowrite64)(b, addr);
}

EXPORT_SYMBOL(ioread8);
EXPORT_SYMBOL(ioread16);
EXPORT_SYMBOL(ioread32);
EXPORT_SYMBOL(ioread64);
EXPORT_SYMBOL(iowrite8);
EXPORT_SYMBOL(iowrite16);
EXPORT_SYMBOL(iowrite32);
EXPORT_SYMBOL(iowrite64);

u8 inb(unsigned long port)
{
	return ioread8(ioport_map(port, 1));
}

u16 inw(unsigned long port)
{
	return ioread16(ioport_map(port, 2));
}

u32 inl(unsigned long port)
{
	return ioread32(ioport_map(port, 4));
}

void outb(u8 b, unsigned long port)
{
	iowrite8(b, ioport_map(port, 1));
}

void outw(u16 b, unsigned long port)
{
	iowrite16(b, ioport_map(port, 2));
}

void outl(u32 b, unsigned long port)
{
	iowrite32(b, ioport_map(port, 4));
}

EXPORT_SYMBOL(inb);
EXPORT_SYMBOL(inw);
EXPORT_SYMBOL(inl);
EXPORT_SYMBOL(outb);
EXPORT_SYMBOL(outw);
EXPORT_SYMBOL(outl);

u8 __raw_readb(const volatile void __iomem *addr)
{
	return IO_CONCAT(__IO_PREFIX,readb)(addr);
}

u16 __raw_readw(const volatile void __iomem *addr)
{
	return IO_CONCAT(__IO_PREFIX,readw)(addr);
}

u32 __raw_readl(const volatile void __iomem *addr)
{
	return IO_CONCAT(__IO_PREFIX,readl)(addr);
}

u64 __raw_readq(const volatile void __iomem *addr)
{
	return IO_CONCAT(__IO_PREFIX,readq)(addr);
}

void __raw_writeb(u8 b, volatile void __iomem *addr)
{
	IO_CONCAT(__IO_PREFIX,writeb)(b, addr);
}

void __raw_writew(u16 b, volatile void __iomem *addr)
{
	IO_CONCAT(__IO_PREFIX,writew)(b, addr);
}

void __raw_writel(u32 b, volatile void __iomem *addr)
{
	IO_CONCAT(__IO_PREFIX,writel)(b, addr);
}

void __raw_writeq(u64 b, volatile void __iomem *addr)
{
	IO_CONCAT(__IO_PREFIX,writeq)(b, addr);
}

EXPORT_SYMBOL(__raw_readb);
EXPORT_SYMBOL(__raw_readw);
EXPORT_SYMBOL(__raw_readl);
EXPORT_SYMBOL(__raw_readq);
EXPORT_SYMBOL(__raw_writeb);
EXPORT_SYMBOL(__raw_writew);
EXPORT_SYMBOL(__raw_writel);
EXPORT_SYMBOL(__raw_writeq);

u8 readb(const volatile void __iomem *addr)
{
	u8 ret;
	mb();
	ret = __raw_readb(addr);
	mb();
	return ret;
}

u16 readw(const volatile void __iomem *addr)
{
	u16 ret;
	mb();
	ret = __raw_readw(addr);
	mb();
	return ret;
}

u32 readl(const volatile void __iomem *addr)
{
	u32 ret;
	mb();
	ret = __raw_readl(addr);
	mb();
	return ret;
}

u64 readq(const volatile void __iomem *addr)
{
	u64 ret;
	mb();
	ret = __raw_readq(addr);
	mb();
	return ret;
}

void writeb(u8 b, volatile void __iomem *addr)
{
	mb();
	__raw_writeb(b, addr);
}

void writew(u16 b, volatile void __iomem *addr)
{
	mb();
	__raw_writew(b, addr);
}

void writel(u32 b, volatile void __iomem *addr)
{
	mb();
	__raw_writel(b, addr);
}

void writeq(u64 b, volatile void __iomem *addr)
{
	mb();
	__raw_writeq(b, addr);
}

EXPORT_SYMBOL(readb);
EXPORT_SYMBOL(readw);
EXPORT_SYMBOL(readl);
EXPORT_SYMBOL(readq);
EXPORT_SYMBOL(writeb);
EXPORT_SYMBOL(writew);
EXPORT_SYMBOL(writel);
EXPORT_SYMBOL(writeq);

/*
 * The _relaxed functions must be ordered w.r.t. each other, but they don't
 * have to be ordered w.r.t. other memory accesses.
 */
u8 readb_relaxed(const volatile void __iomem *addr)
{
	mb();
	return __raw_readb(addr);
}

u16 readw_relaxed(const volatile void __iomem *addr)
{
	mb();
	return __raw_readw(addr);
}

u32 readl_relaxed(const volatile void __iomem *addr)
{
	mb();
	return __raw_readl(addr);
}

u64 readq_relaxed(const volatile void __iomem *addr)
{
	mb();
	return __raw_readq(addr);
}

EXPORT_SYMBOL(readb_relaxed);
EXPORT_SYMBOL(readw_relaxed);
EXPORT_SYMBOL(readl_relaxed);
EXPORT_SYMBOL(readq_relaxed);

/*
 * Read COUNT 8-bit bytes from port PORT into memory starting at SRC.
 */
void ioread8_rep(const void __iomem *port, void *dst, unsigned long count)
{
	while ((unsigned long)dst & 0x3) {
		if (!count)
			return;
		count--;
		*(unsigned char *)dst = ioread8(port);
		dst += 1;
	}

	while (count >= 4) {
		unsigned int w;
		count -= 4;
		w = ioread8(port);
		w |= ioread8(port) << 8;
		w |= ioread8(port) << 16;
		w |= ioread8(port) << 24;
		*(unsigned int *)dst = w;
		dst += 4;
	}

	while (count) {
		--count;
		*(unsigned char *)dst = ioread8(port);
		dst += 1;
	}
}

void insb(unsigned long port, void *dst, unsigned long count)
{
	ioread8_rep(ioport_map(port, 1), dst, count);
}

EXPORT_SYMBOL(ioread8_rep);
EXPORT_SYMBOL(insb);

/*
 * Read COUNT 16-bit words from port PORT into memory starting at
 * SRC.  SRC must be at least short aligned.  This is used by the
 * IDE driver to read disk sectors.  Performance is important, but
 * the interfaces seems to be slow: just using the inlined version
 * of the inw() breaks things.
 */
void ioread16_rep(const void __iomem *port, void *dst, unsigned long count)
{
	if (unlikely((unsigned long)dst & 0x3)) {
		if (!count)
			return;
		BUG_ON((unsigned long)dst & 0x1);
		count--;
		*(unsigned short *)dst = ioread16(port);
		dst += 2;
	}

	while (count >= 2) {
		unsigned int w;
		count -= 2;
		w = ioread16(port);
		w |= ioread16(port) << 16;
		*(unsigned int *)dst = w;
		dst += 4;
	}

	if (count) {
		*(unsigned short*)dst = ioread16(port);
	}
}

void insw(unsigned long port, void *dst, unsigned long count)
{
	ioread16_rep(ioport_map(port, 2), dst, count);
}

EXPORT_SYMBOL(ioread16_rep);
EXPORT_SYMBOL(insw);

/*
 * Read COUNT 32-bit words from port PORT into memory starting at
 * SRC. Now works with any alignment in SRC. Performance is important,
 * but the interfaces seems to be slow: just using the inlined version
 * of the inl() breaks things.
 */
void ioread32_rep(const void __iomem *port, void *dst, unsigned long count)
{
	if (unlikely((unsigned long)dst & 0x3)) {
		while (count--) {
			struct S { int x __attribute__((packed)); };
			((struct S *)dst)->x = ioread32(port);
			dst += 4;
		}
	} else {
		/* Buffer 32-bit aligned.  */
		while (count--) {
			*(unsigned int *)dst = ioread32(port);
			dst += 4;
		}
	}
}

void insl(unsigned long port, void *dst, unsigned long count)
{
	ioread32_rep(ioport_map(port, 4), dst, count);
}

EXPORT_SYMBOL(ioread32_rep);
EXPORT_SYMBOL(insl);

/*
 * Like insb but in the opposite direction.
 * Don't worry as much about doing aligned memory transfers:
 * doing byte reads the "slow" way isn't nearly as slow as
 * doing byte writes the slow way (no r-m-w cycle).
 */
void iowrite8_rep(void __iomem *port, const void *xsrc, unsigned long count)
{
	const unsigned char *src = xsrc;
	while (count--)
		iowrite8(*src++, port);
}

void outsb(unsigned long port, const void *src, unsigned long count)
{
	iowrite8_rep(ioport_map(port, 1), src, count);
}

EXPORT_SYMBOL(iowrite8_rep);
EXPORT_SYMBOL(outsb);

/*
 * Like insw but in the opposite direction.  This is used by the IDE
 * driver to write disk sectors.  Performance is important, but the
 * interfaces seems to be slow: just using the inlined version of the
 * outw() breaks things.
 */
void iowrite16_rep(void __iomem *port, const void *src, unsigned long count)
{
	if (unlikely((unsigned long)src & 0x3)) {
		if (!count)
			return;
		BUG_ON((unsigned long)src & 0x1);
		iowrite16(*(unsigned short *)src, port);
		src += 2;
		--count;
	}

	while (count >= 2) {
		unsigned int w;
		count -= 2;
		w = *(unsigned int *)src;
		src += 4;
		iowrite16(w >>  0, port);
		iowrite16(w >> 16, port);
	}

	if (count) {
		iowrite16(*(unsigned short *)src, port);
	}
}

void outsw(unsigned long port, const void *src, unsigned long count)
{
	iowrite16_rep(ioport_map(port, 2), src, count);
}

EXPORT_SYMBOL(iowrite16_rep);
EXPORT_SYMBOL(outsw);

/*
 * Like insl but in the opposite direction.  This is used by the IDE
 * driver to write disk sectors.  Works with any alignment in SRC.
 * Performance is important, but the interfaces seems to be slow:
 * just using the inlined version of the outl() breaks things.
 */
void iowrite32_rep(void __iomem *port, const void *src, unsigned long count)
{
	if (unlikely((unsigned long)src & 0x3)) {
		while (count--) {
			struct S { int x __attribute__((packed)); };
			iowrite32(((struct S *)src)->x, port);
			src += 4;
		}
	} else {
		/* Buffer 32-bit aligned.  */
		while (count--) {
			iowrite32(*(unsigned int *)src, port);
			src += 4;
		}
	}
}

void outsl(unsigned long port, const void *src, unsigned long count)
{
	iowrite32_rep(ioport_map(port, 4), src, count);
}

EXPORT_SYMBOL(iowrite32_rep);
EXPORT_SYMBOL(outsl);

/*
 * Copy data from IO memory space to "real" memory space.
 * This needs to be optimized.
 */
void memcpy_fromio(void *to, const volatile void __iomem *from, long count)
{
	/* Optimize co-aligned transfers.  Everything else gets handled
	   a byte at a time. */

	if (count >= 8 && ((u64)to & 7) == ((u64)from & 7)) {
		count -= 8;
		do {
			*(u64 *)to = __raw_readq(from);
			count -= 8;
			to += 8;
			from += 8;
		} while (count >= 0);
		count += 8;
	}

	if (count >= 4 && ((u64)to & 3) == ((u64)from & 3)) {
		count -= 4;
		do {
			*(u32 *)to = __raw_readl(from);
			count -= 4;
			to += 4;
			from += 4;
		} while (count >= 0);
		count += 4;
	}

	if (count >= 2 && ((u64)to & 1) == ((u64)from & 1)) {
		count -= 2;
		do {
			*(u16 *)to = __raw_readw(from);
			count -= 2;
			to += 2;
			from += 2;
		} while (count >= 0);
		count += 2;
	}

	while (count > 0) {
		*(u8 *) to = __raw_readb(from);
		count--;
		to++;
		from++;
	}
	mb();
}

EXPORT_SYMBOL(memcpy_fromio);

/*
 * Copy data from "real" memory space to IO memory space.
 * This needs to be optimized.
 */
void memcpy_toio(volatile void __iomem *to, const void *from, long count)
{
	/* Optimize co-aligned transfers.  Everything else gets handled
	   a byte at a time. */
	/* FIXME -- align FROM.  */

	if (count >= 8 && ((u64)to & 7) == ((u64)from & 7)) {
		count -= 8;
		do {
			__raw_writeq(*(const u64 *)from, to);
			count -= 8;
			to += 8;
			from += 8;
		} while (count >= 0);
		count += 8;
	}

	if (count >= 4 && ((u64)to & 3) == ((u64)from & 3)) {
		count -= 4;
		do {
			__raw_writel(*(const u32 *)from, to);
			count -= 4;
			to += 4;
			from += 4;
		} while (count >= 0);
		count += 4;
	}

	if (count >= 2 && ((u64)to & 1) == ((u64)from & 1)) {
		count -= 2;
		do {
			__raw_writew(*(const u16 *)from, to);
			count -= 2;
			to += 2;
			from += 2;
		} while (count >= 0);
		count += 2;
	}

	while (count > 0) {
		__raw_writeb(*(const u8 *) from, to);
		count--;
		to++;
		from++;
	}
	mb();
}

EXPORT_SYMBOL(memcpy_toio);

/*
 * "memset" on IO memory space.
 */
void _memset_c_io(volatile void __iomem *to, unsigned long c, long count)
{
	/* Handle any initial odd byte */
	if (count > 0 && ((u64)to & 1)) {
		__raw_writeb(c, to);
		to++;
		count--;
	}

	/* Handle any initial odd halfword */
	if (count >= 2 && ((u64)to & 2)) {
		__raw_writew(c, to);
		to += 2;
		count -= 2;
	}

	/* Handle any initial odd word */
	if (count >= 4 && ((u64)to & 4)) {
		__raw_writel(c, to);
		to += 4;
		count -= 4;
	}

	/* Handle all full-sized quadwords: we're aligned
	   (or have a small count) */
	count -= 8;
	if (count >= 0) {
		do {
			__raw_writeq(c, to);
			to += 8;
			count -= 8;
		} while (count >= 0);
	}
	count += 8;

	/* The tail is word-aligned if we still have count >= 4 */
	if (count >= 4) {
		__raw_writel(c, to);
		to += 4;
		count -= 4;
	}

	/* The tail is half-word aligned if we have count >= 2 */
	if (count >= 2) {
		__raw_writew(c, to);
		to += 2;
		count -= 2;
	}

	/* And finally, one last byte.. */
	if (count) {
		__raw_writeb(c, to);
	}
	mb();
}

EXPORT_SYMBOL(_memset_c_io);

/* A version of memcpy used by the vga console routines to move data around
   arbitrarily between screen and main memory.  */

void
scr_memcpyw(u16 *d, const u16 *s, unsigned int count)
{
	const u16 __iomem *ios = (const u16 __iomem *) s;
	u16 __iomem *iod = (u16 __iomem *) d;
	int s_isio = __is_ioaddr(s);
	int d_isio = __is_ioaddr(d);

	if (s_isio) {
		if (d_isio) {
			/* FIXME: Should handle unaligned ops and
			   operation widening.  */

			count /= 2;
			while (count--) {
				u16 tmp = __raw_readw(ios++);
				__raw_writew(tmp, iod++);
			}
		}
		else
			memcpy_fromio(d, ios, count);
	} else {
		if (d_isio)
			memcpy_toio(iod, s, count);
		else
			memcpy(d, s, count);
	}
}

EXPORT_SYMBOL(scr_memcpyw);

void __iomem *ioport_map(unsigned long port, unsigned int size)
{
	return IO_CONCAT(__IO_PREFIX,ioportmap) (port);
}

void ioport_unmap(void __iomem *addr)
{
}

EXPORT_SYMBOL(ioport_map);
EXPORT_SYMBOL(ioport_unmap);


code:
// SPDX-License-Identifier: GPL-2.0
/*
 *	linux/arch/alpha/kernel/irq.c
 *
 *	Copyright (C) 1995 Linus Torvalds
 *
 * This file contains the code used by various IRQ handling routines:
 * asking for different IRQ's should be done through these routines
 * instead of just grabbing them. Thus setups with different IRQ numbers
 * shouldn't result in any weird surprises, and installing new handlers
 * should be easier.
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/kernel_stat.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/ptrace.h>
#include <linux/interrupt.h>
#include <linux/random.h>
#include <linux/irq.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/profile.h>
#include <linux/bitops.h>

#include <asm/io.h>
#include <linux/uaccess.h>

volatile unsigned long irq_err_count;
DEFINE_PER_CPU(unsigned long, irq_pmi_count);

void ack_bad_irq(unsigned int irq)
{
	irq_err_count++;
	printk(KERN_CRIT "Unexpected IRQ trap at vector %u\n", irq);
}

#ifdef CONFIG_SMP
static char irq_user_affinity[NR_IRQS];

int irq_select_affinity(unsigned int irq)
{
	struct irq_data *data = irq_get_irq_data(irq);
	struct irq_chip *chip;
	static int last_cpu;
	int cpu = last_cpu + 1;

	if (!data)
		return 1;
	chip = irq_data_get_irq_chip(data);

	if (!chip->irq_set_affinity || irq_user_affinity[irq])
		return 1;

	while (!cpu_possible(cpu) ||
	       !cpumask_test_cpu(cpu, irq_default_affinity))
		cpu = (cpu < (NR_CPUS-1) ? cpu + 1 : 0);
	last_cpu = cpu;

	irq_data_update_affinity(data, cpumask_of(cpu));
	chip->irq_set_affinity(data, cpumask_of(cpu), false);
	return 0;
}
#endif /* CONFIG_SMP */

int arch_show_interrupts(struct seq_file *p, int prec)
{
	int j;

#ifdef CONFIG_SMP
	seq_puts(p, "IPI: ");
	for_each_online_cpu(j)
		seq_printf(p, "%10lu ", cpu_data[j].ipi_count);
	seq_putc(p, '\n');
#endif
	seq_puts(p, "PMI: ");
	for_each_online_cpu(j)
		seq_printf(p, "%10lu ", per_cpu(irq_pmi_count, j));
	seq_puts(p, "          Performance Monitoring\n");
	seq_printf(p, "ERR: %10lu\n", irq_err_count);
	return 0;
}

/*
 * handle_irq handles all normal device IRQ's (the special
 * SMP cross-CPU interrupts have their own specific
 * handlers).
 */

#define MAX_ILLEGAL_IRQS 16

void
handle_irq(int irq)
{
	/*
	 * We ack quickly, we don't want the irq controller
	 * thinking we're snobs just because some other CPU has
	 * disabled global interrupts (we have already done the
	 * INT_ACK cycles, it's too late to try to pretend to the
	 * controller that we aren't taking the interrupt).
	 *
	 * 0 return value means that this irq is already being
	 * handled by some other CPU. (or is disabled)
	 */
	static unsigned int illegal_count=0;
	struct irq_desc *desc = irq_to_desc(irq);

	if (!desc || ((unsigned) irq > ACTUAL_NR_IRQS &&
	    illegal_count < MAX_ILLEGAL_IRQS)) {
		irq_err_count++;
		illegal_count++;
		printk(KERN_CRIT "device_interrupt: invalid interrupt %d\n",
		       irq);
		return;
	}

	irq_enter();
	generic_handle_irq_desc(desc);
	irq_exit();
}


code:
// SPDX-License-Identifier: GPL-2.0
/*
 * Alpha specific irq code.
 */

#include <linux/init.h>
#include <linux/sched.h>
#include <linux/irq.h>
#include <linux/kernel_stat.h>
#include <linux/module.h>

#include <asm/machvec.h>
#include <asm/dma.h>
#include <asm/perf_event.h>
#include <asm/mce.h>

#include "proto.h"
#include "irq_impl.h"

/* Hack minimum IPL during interrupt processing for broken hardware.  */
#ifdef CONFIG_ALPHA_BROKEN_IRQ_MASK
int __min_ipl;
EXPORT_SYMBOL(__min_ipl);
#endif

/*
 * Performance counter hook.  A module can override this to
 * do something useful.
 */
static void
dummy_perf(unsigned long vector, struct pt_regs *regs)
{
	irq_err_count++;
	printk(KERN_CRIT "Performance counter interrupt!\n");
}

void (*perf_irq)(unsigned long, struct pt_regs *) = dummy_perf;
EXPORT_SYMBOL(perf_irq);

/*
 * The main interrupt entry point.
 */

asmlinkage void
do_entInt(unsigned long type, unsigned long vector,
	  unsigned long la_ptr, struct pt_regs *regs)
{
	struct pt_regs *old_regs;

	/*
	 * Disable interrupts during IRQ handling.
	 * Note that there is no matching local_irq_enable() due to
	 * severe problems with RTI at IPL0 and some MILO PALcode
	 * (namely LX164).
	 */
	local_irq_disable();
	switch (type) {
	case 0:
#ifdef CONFIG_SMP
		handle_ipi(regs);
		return;
#else
		irq_err_count++;
		printk(KERN_CRIT "Interprocessor interrupt? "
		       "You must be kidding!\n");
#endif
		break;
	case 1:
		old_regs = set_irq_regs(regs);
		handle_irq(RTC_IRQ);
		set_irq_regs(old_regs);
		return;
	case 2:
		old_regs = set_irq_regs(regs);
		alpha_mv.machine_check(vector, la_ptr);
		set_irq_regs(old_regs);
		return;
	case 3:
		old_regs = set_irq_regs(regs);
		alpha_mv.device_interrupt(vector);
		set_irq_regs(old_regs);
		return;
	case 4:
		perf_irq(la_ptr, regs);
		return;
	default:
		printk(KERN_CRIT "Hardware intr %ld %lx? Huh?\n",
		       type, vector);
	}
	printk(KERN_CRIT "PC = %016lx PS=%04lx\n", regs->pc, regs->ps);
}

void __init
common_init_isa_dma(void)
{
	outb(0, DMA1_RESET_REG);
	outb(0, DMA2_RESET_REG);
	outb(0, DMA1_CLR_MASK_REG);
	outb(0, DMA2_CLR_MASK_REG);
}

void __init
init_IRQ(void)
{
	/* Just in case the platform init_irq() causes interrupts/mchecks
	   (as is the case with RAWHIDE, at least).  */
	wrent(entInt, 0);

	alpha_mv.init_irq();
}

/*
 * machine error checks
 */
#define MCHK_K_TPERR           0x0080
#define MCHK_K_TCPERR          0x0082
#define MCHK_K_HERR            0x0084
#define MCHK_K_ECC_C           0x0086
#define MCHK_K_ECC_NC          0x0088
#define MCHK_K_OS_BUGCHECK     0x008A
#define MCHK_K_PAL_BUGCHECK    0x0090

#ifndef CONFIG_SMP
struct mcheck_info __mcheck_info;
#endif

void
process_mcheck_info(unsigned long vector, unsigned long la_ptr,
		    const char *machine, int expected)
{
	struct el_common *mchk_header;
	const char *reason;

	/*
	 * See if the machine check is due to a badaddr() and if so,
	 * ignore it.
	 */

#ifdef CONFIG_VERBOSE_MCHECK
	if (alpha_verbose_mcheck > 1) {
		printk(KERN_CRIT "%s machine check %s\n", machine,
		       expected ? "expected." : "NOT expected!!!");
	}
#endif

	if (expected) {
		int cpu = smp_processor_id();
		mcheck_expected(cpu) = 0;
		mcheck_taken(cpu) = 1;
		return;
	}

	mchk_header = (struct el_common *)la_ptr;

	printk(KERN_CRIT "%s machine check: vector=0x%lx pc=0x%lx code=0x%x\n",
	       machine, vector, get_irq_regs()->pc, mchk_header->code);

	switch (mchk_header->code) {
	/* Machine check reasons.  Defined according to PALcode sources.  */
	case 0x80: reason = "tag parity error"; break;
	case 0x82: reason = "tag control parity error"; break;
	case 0x84: reason = "generic hard error"; break;
	case 0x86: reason = "correctable ECC error"; break;
	case 0x88: reason = "uncorrectable ECC error"; break;
	case 0x8A: reason = "OS-specific PAL bugcheck"; break;
	case 0x90: reason = "callsys in kernel mode"; break;
	case 0x96: reason = "i-cache read retryable error"; break;
	case 0x98: reason = "processor detected hard error"; break;

	/* System specific (these are for Alcor, at least): */
	case 0x202: reason = "system detected hard error"; break;
	case 0x203: reason = "system detected uncorrectable ECC error"; break;
	case 0x204: reason = "SIO SERR occurred on PCI bus"; break;
	case 0x205: reason = "parity error detected by core logic"; break;
	case 0x206: reason = "SIO IOCHK occurred on ISA bus"; break;
	case 0x207: reason = "non-existent memory error"; break;
	case 0x208: reason = "MCHK_K_DCSR"; break;
	case 0x209: reason = "PCI SERR detected"; break;
	case 0x20b: reason = "PCI data parity error detected"; break;
	case 0x20d: reason = "PCI address parity error detected"; break;
	case 0x20f: reason = "PCI master abort error"; break;
	case 0x211: reason = "PCI target abort error"; break;
	case 0x213: reason = "scatter/gather PTE invalid error"; break;
	case 0x215: reason = "flash ROM write error"; break;
	case 0x217: reason = "IOA timeout detected"; break;
	case 0x219: reason = "IOCHK#, EISA add-in board parity or other catastrophic error"; break;
	case 0x21b: reason = "EISA fail-safe timer timeout"; break;
	case 0x21d: reason = "EISA bus time-out"; break;
	case 0x21f: reason = "EISA software generated NMI"; break;
	case 0x221: reason = "unexpected ev5 IRQ[3] interrupt"; break;
	default: reason = "unknown"; break;
	}

	printk(KERN_CRIT "machine check type: %s%s\n",
	       reason, mchk_header->retry ? " (retryable)" : "");

	dik_show_regs(get_irq_regs(), NULL);

#ifdef CONFIG_VERBOSE_MCHECK
	if (alpha_verbose_mcheck > 1) {
		/* Dump the logout area to give all info.  */
		unsigned long *ptr = (unsigned long *)la_ptr;
		long i;
		for (i = 0; i < mchk_header->size / sizeof(long); i += 2) {
			printk(KERN_CRIT "   +%8lx %016lx %016lx\n",
			       i*sizeof(long), ptr[i], ptr[i+1]);
		}
	}
#endif /* CONFIG_VERBOSE_MCHECK */
}

/*
 * The special RTC interrupt type.  The interrupt itself was
 * processed by PALcode, and comes in via entInt vector 1.
 */
void __init
init_rtc_irq(irq_handler_t handler)
{
	irq_set_chip_and_handler_name(RTC_IRQ, &dummy_irq_chip,
				      handle_percpu_irq, "RTC");
	if (!handler)
		handler = rtc_timer_interrupt;
	if (request_irq(RTC_IRQ, handler, 0, "timer", NULL))
		pr_err("Failed to register timer interrupt\n");
}


code:
// SPDX-License-Identifier: GPL-2.0
/*
 *      linux/arch/alpha/kernel/irq_i8259.c
 *
 * This is the 'legacy' 8259A Programmable Interrupt Controller,
 * present in the majority of PC/AT boxes.
 *
 * Started hacking from linux-2.3.30pre6/arch/i386/kernel/i8259.c.
 */

#include <linux/init.h>
#include <linux/cache.h>
#include <linux/sched.h>
#include <linux/irq.h>
#include <linux/interrupt.h>

#include <asm/io.h>

#include "proto.h"
#include "irq_impl.h"

/* Note mask bit is true for DISABLED irqs.  */
static unsigned int cached_irq_mask = 0xffff;
static DEFINE_SPINLOCK(i8259_irq_lock);

static inline void
i8259_update_irq_hw(unsigned int irq, unsigned long mask)
{
	int port = 0x21;
	if (irq & 8) mask >>= 8;
	if (irq & 8) port = 0xA1;
	outb(mask, port);
}

inline void
i8259a_enable_irq(struct irq_data *d)
{
	spin_lock(&i8259_irq_lock);
	i8259_update_irq_hw(d->irq, cached_irq_mask &= ~(1 << d->irq));
	spin_unlock(&i8259_irq_lock);
}

static inline void
__i8259a_disable_irq(unsigned int irq)
{
	i8259_update_irq_hw(irq, cached_irq_mask |= 1 << irq);
}

void
i8259a_disable_irq(struct irq_data *d)
{
	spin_lock(&i8259_irq_lock);
	__i8259a_disable_irq(d->irq);
	spin_unlock(&i8259_irq_lock);
}

void
i8259a_mask_and_ack_irq(struct irq_data *d)
{
	unsigned int irq = d->irq;

	spin_lock(&i8259_irq_lock);
	__i8259a_disable_irq(irq);

	/* Ack the interrupt making it the lowest priority.  */
	if (irq >= 8) {
		outb(0xE0 | (irq - 8), 0xa0);   /* ack the slave */
		irq = 2;
	}
	outb(0xE0 | irq, 0x20);			/* ack the master */
	spin_unlock(&i8259_irq_lock);
}

struct irq_chip i8259a_irq_type = {
	.name		= "XT-PIC",
	.irq_unmask	= i8259a_enable_irq,
	.irq_mask	= i8259a_disable_irq,
	.irq_mask_ack	= i8259a_mask_and_ack_irq,
};

void __init
init_i8259a_irqs(void)
{
	long i;

	outb(0xff, 0x21);	/* mask all of 8259A-1 */
	outb(0xff, 0xA1);	/* mask all of 8259A-2 */

	for (i = 0; i < 16; i++) {
		irq_set_chip_and_handler(i, &i8259a_irq_type, handle_level_irq);
	}

	if (request_irq(2, no_action, 0, "cascade", NULL))
		pr_err("Failed to request irq 2 (cascade)\n");
}

#if defined(CONFIG_ALPHA_GENERIC)
# define IACK_SC	alpha_mv.iack_sc
#elif defined(CONFIG_ALPHA_APECS)
# define IACK_SC	APECS_IACK_SC
#elif defined(CONFIG_ALPHA_LCA)
# define IACK_SC	LCA_IACK_SC
#elif defined(CONFIG_ALPHA_CIA)
# define IACK_SC	CIA_IACK_SC
#elif defined(CONFIG_ALPHA_PYXIS)
# define IACK_SC	PYXIS_IACK_SC
#elif defined(CONFIG_ALPHA_TITAN)
# define IACK_SC	TITAN_IACK_SC
#elif defined(CONFIG_ALPHA_TSUNAMI)
# define IACK_SC	TSUNAMI_IACK_SC
#elif defined(CONFIG_ALPHA_IRONGATE)
# define IACK_SC        IRONGATE_IACK_SC
#endif
/* Note that CONFIG_ALPHA_POLARIS is intentionally left out here, since
   sys_rx164 wants to use isa_no_iack_sc_device_interrupt for some reason.  */

#if defined(IACK_SC)
void
isa_device_interrupt(unsigned long vector)
{
	/*
	 * Generate a PCI interrupt acknowledge cycle.  The PIC will
	 * respond with the interrupt vector of the highest priority
	 * interrupt that is pending.  The PALcode sets up the
	 * interrupts vectors such that irq level L generates vector L.
	 */
	int j = *(vuip) IACK_SC;
	j &= 0xff;
	handle_irq(j);
}
#endif

#if defined(CONFIG_ALPHA_GENERIC) || !defined(IACK_SC)
void
isa_no_iack_sc_device_interrupt(unsigned long vector)
{
	unsigned long pic;

	/*
	 * It seems to me that the probability of two or more *device*
	 * interrupts occurring at almost exactly the same time is
	 * pretty low.  So why pay the price of checking for
	 * additional interrupts here if the common case can be
	 * handled so much easier?
	 */
	/*
	 *  The first read of gives you *all* interrupting lines.
	 *  Therefore, read the mask register and and out those lines
	 *  not enabled.  Note that some documentation has 21 and a1
	 *  write only.  This is not true.
	 */
	pic = inb(0x20) | (inb(0xA0) << 8);	/* read isr */
	pic &= 0xFFFB;				/* mask out cascade & hibits */

	while (pic) {
		int j = ffz(~pic);
		pic &= pic - 1;
		handle_irq(j);
	}
}
#endif


code:
/* SPDX-License-Identifier: GPL-2.0 */
/*
 *	linux/arch/alpha/kernel/irq_impl.h
 *
 *	Copyright (C) 1995 Linus Torvalds
 *	Copyright (C) 1998, 2000 Richard Henderson
 *
 * This file contains declarations and inline functions for interfacing
 * with the IRQ handling routines in irq.c.
 */

#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/profile.h>

#define RTC_IRQ    8

extern void isa_device_interrupt(unsigned long);
extern void isa_no_iack_sc_device_interrupt(unsigned long);
extern void srm_device_interrupt(unsigned long);
extern void pyxis_device_interrupt(unsigned long);

extern void init_srm_irqs(long, unsigned long);
extern void init_pyxis_irqs(unsigned long);
extern void init_rtc_irq(irq_handler_t  handler);

extern void common_init_isa_dma(void);

extern void i8259a_enable_irq(struct irq_data *d);
extern void i8259a_disable_irq(struct irq_data *d);
extern void i8259a_mask_and_ack_irq(struct irq_data *d);
extern struct irq_chip i8259a_irq_type;
extern void init_i8259a_irqs(void);

extern void handle_irq(int irq);


code:
// SPDX-License-Identifier: GPL-2.0
/*
 *	linux/arch/alpha/kernel/irq_pyxis.c
 *
 * Based on code written by David A Rusling (david.rusling@reo.mts.dec.com).
 *
 * IRQ Code common to all PYXIS core logic chips.
 */

#include <linux/init.h>
#include <linux/sched.h>
#include <linux/irq.h>

#include <asm/io.h>
#include <asm/core_cia.h>

#include "proto.h"
#include "irq_impl.h"

/* Note mask bit is true for ENABLED irqs.  */
static unsigned long cached_irq_mask;

static inline void
pyxis_update_irq_hw(unsigned long mask)
{
	*(vulp)PYXIS_INT_MASK = mask;
	mb();
	*(vulp)PYXIS_INT_MASK;
}

static inline void
pyxis_enable_irq(struct irq_data *d)
{
	pyxis_update_irq_hw(cached_irq_mask |= 1UL << (d->irq - 16));
}

static void
pyxis_disable_irq(struct irq_data *d)
{
	pyxis_update_irq_hw(cached_irq_mask &= ~(1UL << (d->irq - 16)));
}

static void
pyxis_mask_and_ack_irq(struct irq_data *d)
{
	unsigned long bit = 1UL << (d->irq - 16);
	unsigned long mask = cached_irq_mask &= ~bit;

	/* Disable the interrupt.  */
	*(vulp)PYXIS_INT_MASK = mask;
	wmb();
	/* Ack PYXIS PCI interrupt.  */
	*(vulp)PYXIS_INT_REQ = bit;
	mb();
	/* Re-read to force both writes.  */
	*(vulp)PYXIS_INT_MASK;
}

static struct irq_chip pyxis_irq_type = {
	.name		= "PYXIS",
	.irq_mask_ack	= pyxis_mask_and_ack_irq,
	.irq_mask	= pyxis_disable_irq,
	.irq_unmask	= pyxis_enable_irq,
};

void
pyxis_device_interrupt(unsigned long vector)
{
	unsigned long pld;
	unsigned int i;

	/* Read the interrupt summary register of PYXIS */
	pld = *(vulp)PYXIS_INT_REQ;
	pld &= cached_irq_mask;

	/*
	 * Now for every possible bit set, work through them and call
	 * the appropriate interrupt handler.
	 */
	while (pld) {
		i = ffz(~pld);
		pld &= pld - 1; /* clear least bit set */
		if (i == 7)
			isa_device_interrupt(vector);
		else
			handle_irq(16+i);
	}
}

void __init
init_pyxis_irqs(unsigned long ignore_mask)
{
	long i;

	*(vulp)PYXIS_INT_MASK = 0;		/* disable all */
	*(vulp)PYXIS_INT_REQ  = -1;		/* flush all */
	mb();

	/* Send -INTA pulses to clear any pending interrupts ...*/
	*(vuip) CIA_IACK_SC;

	for (i = 16; i < 48; ++i) {
		if ((ignore_mask >> i) & 1)
			continue;
		irq_set_chip_and_handler(i, &pyxis_irq_type, handle_level_irq);
		irq_set_status_flags(i, IRQ_LEVEL);
	}

	if (request_irq(16 + 7, no_action, 0, "isa-cascade", NULL))
		pr_err("Failed to register isa-cascade interrupt\n");
}


code:
// SPDX-License-Identifier: GPL-2.0
/*
 * Handle interrupts from the SRM, assuming no additional weirdness.
 */

#include <linux/init.h>
#include <linux/sched.h>
#include <linux/irq.h>

#include "proto.h"
#include "irq_impl.h"

/*
 * Is the palcode SMP safe? In other words: can we call cserve_ena/dis
 * at the same time in multiple CPUs? To be safe I added a spinlock
 * but it can be removed trivially if the palcode is robust against smp.
 */
DEFINE_SPINLOCK(srm_irq_lock);

static inline void
srm_enable_irq(struct irq_data *d)
{
	spin_lock(&srm_irq_lock);
	cserve_ena(d->irq - 16);
	spin_unlock(&srm_irq_lock);
}

static void
srm_disable_irq(struct irq_data *d)
{
	spin_lock(&srm_irq_lock);
	cserve_dis(d->irq - 16);
	spin_unlock(&srm_irq_lock);
}

/* Handle interrupts from the SRM, assuming no additional weirdness.  */
static struct irq_chip srm_irq_type = {
	.name		= "SRM",
	.irq_unmask	= srm_enable_irq,
	.irq_mask	= srm_disable_irq,
	.irq_mask_ack	= srm_disable_irq,
};

void __init
init_srm_irqs(long max, unsigned long ignore_mask)
{
	long i;

	if (NR_IRQS <= 16)
		return;
	for (i = 16; i < max; ++i) {
		if (i < 64 && ((ignore_mask >> i) & 1))
			continue;
		irq_set_chip_and_handler(i, &srm_irq_type, handle_level_irq);
		irq_set_status_flags(i, IRQ_LEVEL);
	}
}

void
srm_device_interrupt(unsigned long vector)
{
	int irq = (vector - 0x800) >> 4;
	handle_irq(irq);
}