11.1Sjmcneill/* $NetBSD: pic_pi.c,v 1.1 2026/01/09 22:54:29 jmcneill Exp $ */ 21.1Sjmcneill 31.1Sjmcneill/*- 41.1Sjmcneill * Copyright (c) 2024-2025 Jared McNeill <jmcneill@invisible.ca> 51.1Sjmcneill * All rights reserved. 61.1Sjmcneill * 71.1Sjmcneill * Redistribution and use in source and binary forms, with or without 81.1Sjmcneill * modification, are permitted provided that the following conditions 91.1Sjmcneill * are met: 101.1Sjmcneill * 1. Redistributions of source code must retain the above copyright 111.1Sjmcneill * notice, this list of conditions and the following disclaimer. 121.1Sjmcneill * 2. Redistributions in binary form must reproduce the above copyright 131.1Sjmcneill * notice, this list of conditions and the following disclaimer in the 141.1Sjmcneill * documentation and/or other materials provided with the distribution. 151.1Sjmcneill * 161.1Sjmcneill * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 171.1Sjmcneill * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 181.1Sjmcneill * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 191.1Sjmcneill * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 201.1Sjmcneill * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 211.1Sjmcneill * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 221.1Sjmcneill * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 231.1Sjmcneill * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 241.1Sjmcneill * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 251.1Sjmcneill * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 261.1Sjmcneill * POSSIBILITY OF SUCH DAMAGE. 271.1Sjmcneill */ 281.1Sjmcneill 291.1Sjmcneill/* 301.1Sjmcneill * Processor interface interrupt controller. Top level controller for all 311.1Sjmcneill * EXT interrupts. 321.1Sjmcneill */ 331.1Sjmcneill 341.1Sjmcneill#include <sys/cdefs.h> 351.1Sjmcneill__KERNEL_RCSID(0, "$NetBSD: pic_pi.c,v 1.1 2026/01/09 22:54:29 jmcneill Exp $"); 361.1Sjmcneill 371.1Sjmcneill#include "opt_multiprocessor.h" 381.1Sjmcneill 391.1Sjmcneill#include <sys/param.h> 401.1Sjmcneill#include <sys/intr.h> 411.1Sjmcneill#include <sys/systm.h> 421.1Sjmcneill#include <sys/bus.h> 431.1Sjmcneill#include <sys/bitops.h> 441.1Sjmcneill#include <sys/cpu.h> 451.1Sjmcneill#include <powerpc/include/spr.h> 461.1Sjmcneill#include <powerpc/include/oea/spr.h> 471.1Sjmcneill#include <machine/pio.h> 481.1Sjmcneill#include <machine/intr.h> 491.1Sjmcneill#include <arch/powerpc/pic/picvar.h> 501.1Sjmcneill#include <arch/powerpc/pic/ipivar.h> 511.1Sjmcneill#include <machine/wii.h> 521.1Sjmcneill#include <machine/wiiu.h> 531.1Sjmcneill 541.1Sjmcneill#include "pic_pi.h" 551.1Sjmcneill 561.1Sjmcneillstruct pic_state { 571.1Sjmcneill uint32_t irqmask; 581.1Sjmcneill uint32_t actmask; 591.1Sjmcneill uint32_t intsr; 601.1Sjmcneill uint32_t intmr; 611.1Sjmcneill} __aligned(32); 621.1Sjmcneill 631.1Sjmcneillstatic struct pic_state pic_s[CPU_MAXNUM]; 641.1Sjmcneill 651.1Sjmcneill#define WR4(reg, val) out32(reg, val) 661.1Sjmcneill#define RD4(reg) in32(reg) 671.1Sjmcneill 681.1Sjmcneill#ifdef MULTIPROCESSOR 691.1Sjmcneillextern struct ipi_ops ipiops; 701.1Sjmcneill 711.1Sjmcneill#define IRQ_IS_IPI(_irq) \ 721.1Sjmcneill ((_irq) >= WIIU_PI_IRQ_MB_CPU(0) && (_irq) <= WIIU_PI_IRQ_MB_CPU(2)) 731.1Sjmcneill#endif 741.1Sjmcneill 751.1Sjmcneillstatic u_int 761.1Sjmcneillpi_irq_affinity(int irq) 771.1Sjmcneill{ 781.1Sjmcneill#ifdef MULTIPROCESSOR 791.1Sjmcneill if (wiiu_native && IRQ_IS_IPI(irq)) { 801.1Sjmcneill return irq - WIIU_PI_IRQ_MB_CPU(0); 811.1Sjmcneill } 821.1Sjmcneill#endif 831.1Sjmcneill return 0; 841.1Sjmcneill} 851.1Sjmcneill 861.1Sjmcneillstatic void 871.1Sjmcneillpi_enable_irq(struct pic_ops *pic, int irq, int type) 881.1Sjmcneill{ 891.1Sjmcneill const u_int cpu_num = pi_irq_affinity(irq); 901.1Sjmcneill 911.1Sjmcneill pic_s[cpu_num].irqmask |= __BIT(irq); 921.1Sjmcneill WR4(pic_s[cpu_num].intmr, pic_s[cpu_num].irqmask & ~pic_s[cpu_num].actmask); 931.1Sjmcneill} 941.1Sjmcneill 951.1Sjmcneillstatic void 961.1Sjmcneillpi_disable_irq(struct pic_ops *pic, int irq) 971.1Sjmcneill{ 981.1Sjmcneill const u_int cpu_num = pi_irq_affinity(irq); 991.1Sjmcneill 1001.1Sjmcneill pic_s[cpu_num].irqmask &= ~__BIT(irq); 1011.1Sjmcneill WR4(pic_s[cpu_num].intmr, pic_s[cpu_num].irqmask & ~pic_s[cpu_num].actmask); 1021.1Sjmcneill} 1031.1Sjmcneill 1041.1Sjmcneill#ifdef MULTIPROCESSOR 1051.1Sjmcneillstatic void 1061.1Sjmcneillpi_ipi_ack(const u_int cpu_num, register_t spr) 1071.1Sjmcneill{ 1081.1Sjmcneill do { 1091.1Sjmcneill mtspr(SPR_SCR, spr & ~SPR_SCR_IPI_PEND(cpu_num)); 1101.1Sjmcneill spr = mfspr(SPR_SCR); 1111.1Sjmcneill } while ((spr & SPR_SCR_IPI_PEND(cpu_num)) != 0); 1121.1Sjmcneill} 1131.1Sjmcneill#endif 1141.1Sjmcneill 1151.1Sjmcneillstatic int 1161.1Sjmcneillpi_get_irq(struct pic_ops *pic, int mode) 1171.1Sjmcneill{ 1181.1Sjmcneill const u_int cpu_num = cpu_number(); 1191.1Sjmcneill uint32_t raw, pend; 1201.1Sjmcneill int irq; 1211.1Sjmcneill 1221.1Sjmcneill#ifdef MULTIPROCESSOR 1231.1Sjmcneill if (wiiu_native) { 1241.1Sjmcneill register_t spr = mfspr(SPR_SCR); 1251.1Sjmcneill 1261.1Sjmcneill if ((spr & SPR_SCR_IPI_PEND(cpu_num)) != 0) { 1271.1Sjmcneill pi_ipi_ack(cpu_num, spr); 1281.1Sjmcneill return WIIU_PI_IRQ_MB_CPU(cpu_num); 1291.1Sjmcneill } 1301.1Sjmcneill } 1311.1Sjmcneill#endif 1321.1Sjmcneill 1331.1Sjmcneill raw = RD4(pic_s[cpu_num].intsr); 1341.1Sjmcneill pend = raw & pic_s[cpu_num].irqmask; 1351.1Sjmcneill if (pend == 0) { 1361.1Sjmcneill return 255; 1371.1Sjmcneill } 1381.1Sjmcneill irq = ffs32(pend) - 1; 1391.1Sjmcneill 1401.1Sjmcneill pic_s[cpu_num].actmask |= __BIT(irq); 1411.1Sjmcneill WR4(pic_s[cpu_num].intmr, pic_s[cpu_num].irqmask & ~pic_s[cpu_num].actmask); 1421.1Sjmcneill 1431.1Sjmcneill return irq; 1441.1Sjmcneill} 1451.1Sjmcneill 1461.1Sjmcneillstatic void 1471.1Sjmcneillpi_ack_irq(struct pic_ops *pic, int irq) 1481.1Sjmcneill{ 1491.1Sjmcneill const u_int cpu_num = cpu_number(); 1501.1Sjmcneill 1511.1Sjmcneill pic_s[cpu_num].actmask &= ~__BIT(irq); 1521.1Sjmcneill WR4(pic_s[cpu_num].intmr, pic_s[cpu_num].irqmask & ~pic_s[cpu_num].actmask); 1531.1Sjmcneill WR4(pic_s[cpu_num].intsr, __BIT(irq)); 1541.1Sjmcneill} 1551.1Sjmcneill 1561.1Sjmcneillstatic struct pic_ops pic = { 1571.1Sjmcneill .pic_name = "pi", 1581.1Sjmcneill .pic_numintrs = 32, 1591.1Sjmcneill .pic_cookie = NULL, 1601.1Sjmcneill .pic_enable_irq = pi_enable_irq, 1611.1Sjmcneill .pic_reenable_irq = pi_enable_irq, 1621.1Sjmcneill .pic_disable_irq = pi_disable_irq, 1631.1Sjmcneill .pic_get_irq = pi_get_irq, 1641.1Sjmcneill .pic_ack_irq = pi_ack_irq, 1651.1Sjmcneill .pic_establish_irq = dummy_pic_establish_intr, 1661.1Sjmcneill}; 1671.1Sjmcneill 1681.1Sjmcneillvoid 1691.1Sjmcneillpi_init_intr(void) 1701.1Sjmcneill{ 1711.1Sjmcneill u_int cpu_num; 1721.1Sjmcneill 1731.1Sjmcneill for (cpu_num = 0; cpu_num < uimin(3, CPU_MAXNUM); cpu_num++) { 1741.1Sjmcneill pic_s[cpu_num].irqmask = 0; 1751.1Sjmcneill pic_s[cpu_num].actmask = 0; 1761.1Sjmcneill if (wiiu_native) { 1771.1Sjmcneill pic_s[cpu_num].intmr = WIIU_PI_INTMSK(cpu_num); 1781.1Sjmcneill pic_s[cpu_num].intsr = WIIU_PI_INTSR(cpu_num); 1791.1Sjmcneill } else { 1801.1Sjmcneill pic_s[cpu_num].intmr = PI_INTMR; 1811.1Sjmcneill pic_s[cpu_num].intsr = PI_INTSR; 1821.1Sjmcneill } 1831.1Sjmcneill 1841.1Sjmcneill /* Mask and clear all interrupts. */ 1851.1Sjmcneill WR4(pic_s[cpu_num].intmr, 0); 1861.1Sjmcneill WR4(pic_s[cpu_num].intsr, ~0U); 1871.1Sjmcneill } 1881.1Sjmcneill 1891.1Sjmcneill pic_add(&pic); 1901.1Sjmcneill} 191