103479763SNathan Whitehorn /*- 271e3c308SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 371e3c308SPedro F. Giffuni * 403479763SNathan Whitehorn * Copyright 2010 Nathan Whitehorn 503479763SNathan Whitehorn * 603479763SNathan Whitehorn * Redistribution and use in source and binary forms, with or without 703479763SNathan Whitehorn * modification, are permitted provided that the following conditions 803479763SNathan Whitehorn * are met: 903479763SNathan Whitehorn * 1. Redistributions of source code must retain the above copyright 1003479763SNathan Whitehorn * notice, this list of conditions and the following disclaimer. 1103479763SNathan Whitehorn * 2. Redistributions in binary form must reproduce the above copyright 1203479763SNathan Whitehorn * notice, this list of conditions and the following disclaimer in the 1303479763SNathan Whitehorn * documentation and/or other materials provided with the distribution. 1403479763SNathan Whitehorn * 1503479763SNathan Whitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1603479763SNathan Whitehorn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1703479763SNathan Whitehorn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1803479763SNathan Whitehorn * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1903479763SNathan Whitehorn * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 2003479763SNathan Whitehorn * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 2103479763SNathan Whitehorn * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 2203479763SNathan Whitehorn * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 2303479763SNathan Whitehorn * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2403479763SNathan Whitehorn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2503479763SNathan Whitehorn * SUCH DAMAGE. 2603479763SNathan Whitehorn * 2703479763SNathan Whitehorn * $FreeBSD$ 2803479763SNathan Whitehorn */ 2903479763SNathan Whitehorn 3003479763SNathan Whitehorn #include <sys/param.h> 3103479763SNathan Whitehorn #include <sys/systm.h> 3203479763SNathan Whitehorn #include <sys/module.h> 3303479763SNathan Whitehorn #include <sys/bus.h> 3403479763SNathan Whitehorn #include <sys/conf.h> 3503479763SNathan Whitehorn #include <sys/kernel.h> 3603479763SNathan Whitehorn #include <sys/malloc.h> 3703479763SNathan Whitehorn 3803479763SNathan Whitehorn #include <vm/vm.h> 3903479763SNathan Whitehorn #include <vm/pmap.h> 4003479763SNathan Whitehorn 4103479763SNathan Whitehorn #include <machine/bus.h> 4203479763SNathan Whitehorn #include <machine/intr_machdep.h> 4303479763SNathan Whitehorn #include <machine/md_var.h> 4403479763SNathan Whitehorn #include <machine/platform.h> 4503479763SNathan Whitehorn 4603479763SNathan Whitehorn #include "ps3-hvcall.h" 4703479763SNathan Whitehorn #include "pic_if.h" 4803479763SNathan Whitehorn 4903479763SNathan Whitehorn static void ps3pic_identify(driver_t *driver, device_t parent); 5003479763SNathan Whitehorn static int ps3pic_probe(device_t); 5103479763SNathan Whitehorn static int ps3pic_attach(device_t); 5203479763SNathan Whitehorn 5303479763SNathan Whitehorn static void ps3pic_dispatch(device_t, struct trapframe *); 5456505ec0SJustin Hibbits static void ps3pic_enable(device_t, u_int, u_int, void **); 5556505ec0SJustin Hibbits static void ps3pic_eoi(device_t, u_int, void *); 5603479763SNathan Whitehorn static void ps3pic_ipi(device_t, u_int); 5756505ec0SJustin Hibbits static void ps3pic_mask(device_t, u_int, void *); 5856505ec0SJustin Hibbits static void ps3pic_unmask(device_t, u_int, void *); 5903479763SNathan Whitehorn 6003479763SNathan Whitehorn struct ps3pic_softc { 61f574af0dSNathan Whitehorn volatile uint64_t *bitmap_thread0; 62f574af0dSNathan Whitehorn volatile uint64_t *mask_thread0; 63f574af0dSNathan Whitehorn volatile uint64_t *bitmap_thread1; 64f574af0dSNathan Whitehorn volatile uint64_t *mask_thread1; 6503479763SNathan Whitehorn 6603479763SNathan Whitehorn uint64_t sc_ipi_outlet[2]; 67f7952747SNathan Whitehorn uint64_t sc_ipi_virq; 6803479763SNathan Whitehorn int sc_vector[64]; 6903479763SNathan Whitehorn }; 7003479763SNathan Whitehorn 7103479763SNathan Whitehorn static device_method_t ps3pic_methods[] = { 7203479763SNathan Whitehorn /* Device interface */ 7303479763SNathan Whitehorn DEVMETHOD(device_identify, ps3pic_identify), 7403479763SNathan Whitehorn DEVMETHOD(device_probe, ps3pic_probe), 7503479763SNathan Whitehorn DEVMETHOD(device_attach, ps3pic_attach), 7603479763SNathan Whitehorn 7703479763SNathan Whitehorn /* PIC interface */ 7803479763SNathan Whitehorn DEVMETHOD(pic_dispatch, ps3pic_dispatch), 7903479763SNathan Whitehorn DEVMETHOD(pic_enable, ps3pic_enable), 8003479763SNathan Whitehorn DEVMETHOD(pic_eoi, ps3pic_eoi), 8103479763SNathan Whitehorn DEVMETHOD(pic_ipi, ps3pic_ipi), 8203479763SNathan Whitehorn DEVMETHOD(pic_mask, ps3pic_mask), 8303479763SNathan Whitehorn DEVMETHOD(pic_unmask, ps3pic_unmask), 8403479763SNathan Whitehorn 8503479763SNathan Whitehorn { 0, 0 }, 8603479763SNathan Whitehorn }; 8703479763SNathan Whitehorn 8803479763SNathan Whitehorn static driver_t ps3pic_driver = { 8903479763SNathan Whitehorn "ps3pic", 9003479763SNathan Whitehorn ps3pic_methods, 9103479763SNathan Whitehorn sizeof(struct ps3pic_softc) 9203479763SNathan Whitehorn }; 9303479763SNathan Whitehorn 94*c331b0e4SJohn Baldwin DRIVER_MODULE(ps3pic, nexus, ps3pic_driver, 0, 0); 9503479763SNathan Whitehorn 9603479763SNathan Whitehorn static MALLOC_DEFINE(M_PS3PIC, "ps3pic", "PS3 PIC"); 9703479763SNathan Whitehorn 9803479763SNathan Whitehorn static void 9903479763SNathan Whitehorn ps3pic_identify(driver_t *driver, device_t parent) 10003479763SNathan Whitehorn { 10103479763SNathan Whitehorn if (strcmp(installed_platform(), "ps3") != 0) 10203479763SNathan Whitehorn return; 10303479763SNathan Whitehorn 10403479763SNathan Whitehorn if (device_find_child(parent, "ps3pic", -1) == NULL) 10503479763SNathan Whitehorn BUS_ADD_CHILD(parent, 0, "ps3pic", 0); 10603479763SNathan Whitehorn } 10703479763SNathan Whitehorn 10803479763SNathan Whitehorn static int 10903479763SNathan Whitehorn ps3pic_probe(device_t dev) 11003479763SNathan Whitehorn { 11103479763SNathan Whitehorn device_set_desc(dev, "Playstation 3 interrupt controller"); 11203479763SNathan Whitehorn return (BUS_PROBE_NOWILDCARD); 11303479763SNathan Whitehorn } 11403479763SNathan Whitehorn 11503479763SNathan Whitehorn static int 11603479763SNathan Whitehorn ps3pic_attach(device_t dev) 11703479763SNathan Whitehorn { 11803479763SNathan Whitehorn struct ps3pic_softc *sc; 11903479763SNathan Whitehorn uint64_t ppe; 12003479763SNathan Whitehorn int thread; 12103479763SNathan Whitehorn 12203479763SNathan Whitehorn sc = device_get_softc(dev); 12303479763SNathan Whitehorn 12403479763SNathan Whitehorn sc->bitmap_thread0 = contigmalloc(128 /* 512 bits * 2 */, M_PS3PIC, 12503479763SNathan Whitehorn M_NOWAIT | M_ZERO, 0, BUS_SPACE_MAXADDR, 64 /* alignment */, 12603479763SNathan Whitehorn PAGE_SIZE /* boundary */); 12703479763SNathan Whitehorn sc->mask_thread0 = sc->bitmap_thread0 + 4; 12803479763SNathan Whitehorn sc->bitmap_thread1 = sc->bitmap_thread0 + 8; 12903479763SNathan Whitehorn sc->mask_thread1 = sc->bitmap_thread0 + 12; 13003479763SNathan Whitehorn 13103479763SNathan Whitehorn lv1_get_logical_ppe_id(&ppe); 13203479763SNathan Whitehorn thread = 32 - fls(mfctrl()); 13303479763SNathan Whitehorn lv1_configure_irq_state_bitmap(ppe, thread, 13403479763SNathan Whitehorn vtophys(sc->bitmap_thread0)); 135f7952747SNathan Whitehorn 136f7952747SNathan Whitehorn sc->sc_ipi_virq = 63; 137f7952747SNathan Whitehorn 13803479763SNathan Whitehorn #ifdef SMP 13903479763SNathan Whitehorn lv1_configure_irq_state_bitmap(ppe, !thread, 14003479763SNathan Whitehorn vtophys(sc->bitmap_thread1)); 14103479763SNathan Whitehorn 14203479763SNathan Whitehorn /* Map both IPIs to the same VIRQ to avoid changes in intr_machdep */ 14303479763SNathan Whitehorn lv1_construct_event_receive_port(&sc->sc_ipi_outlet[0]); 144f7952747SNathan Whitehorn lv1_connect_irq_plug_ext(ppe, thread, sc->sc_ipi_virq, 14503479763SNathan Whitehorn sc->sc_ipi_outlet[0], 0); 14603479763SNathan Whitehorn lv1_construct_event_receive_port(&sc->sc_ipi_outlet[1]); 147f7952747SNathan Whitehorn lv1_connect_irq_plug_ext(ppe, !thread, sc->sc_ipi_virq, 14803479763SNathan Whitehorn sc->sc_ipi_outlet[1], 0); 14903479763SNathan Whitehorn #endif 15003479763SNathan Whitehorn 151f7952747SNathan Whitehorn powerpc_register_pic(dev, 0, sc->sc_ipi_virq, 1, FALSE); 15203479763SNathan Whitehorn return (0); 15303479763SNathan Whitehorn } 15403479763SNathan Whitehorn 15503479763SNathan Whitehorn /* 15603479763SNathan Whitehorn * PIC I/F methods. 15703479763SNathan Whitehorn */ 15803479763SNathan Whitehorn 15903479763SNathan Whitehorn static void 16003479763SNathan Whitehorn ps3pic_dispatch(device_t dev, struct trapframe *tf) 16103479763SNathan Whitehorn { 16203479763SNathan Whitehorn uint64_t bitmap, mask; 16303479763SNathan Whitehorn int irq; 16403479763SNathan Whitehorn struct ps3pic_softc *sc; 16503479763SNathan Whitehorn 16603479763SNathan Whitehorn sc = device_get_softc(dev); 16703479763SNathan Whitehorn 16803479763SNathan Whitehorn if (PCPU_GET(cpuid) == 0) { 1690c50edffSNathan Whitehorn bitmap = atomic_readandclear_64(&sc->bitmap_thread0[0]); 17003479763SNathan Whitehorn mask = sc->mask_thread0[0]; 17103479763SNathan Whitehorn } else { 1720c50edffSNathan Whitehorn bitmap = atomic_readandclear_64(&sc->bitmap_thread1[0]); 17303479763SNathan Whitehorn mask = sc->mask_thread1[0]; 17403479763SNathan Whitehorn } 1750c50edffSNathan Whitehorn powerpc_sync(); 17603479763SNathan Whitehorn 17703479763SNathan Whitehorn while ((irq = ffsl(bitmap & mask) - 1) != -1) { 17803479763SNathan Whitehorn bitmap &= ~(1UL << irq); 17903479763SNathan Whitehorn powerpc_dispatch_intr(sc->sc_vector[63 - irq], tf); 18003479763SNathan Whitehorn } 18103479763SNathan Whitehorn } 18203479763SNathan Whitehorn 18303479763SNathan Whitehorn static void 18456505ec0SJustin Hibbits ps3pic_enable(device_t dev, u_int irq, u_int vector, void **priv) 18503479763SNathan Whitehorn { 18603479763SNathan Whitehorn struct ps3pic_softc *sc; 18703479763SNathan Whitehorn 18803479763SNathan Whitehorn sc = device_get_softc(dev); 18903479763SNathan Whitehorn sc->sc_vector[irq] = vector; 19003479763SNathan Whitehorn 19156505ec0SJustin Hibbits ps3pic_unmask(dev, irq, priv); 19203479763SNathan Whitehorn } 19303479763SNathan Whitehorn 19403479763SNathan Whitehorn static void 19556505ec0SJustin Hibbits ps3pic_eoi(device_t dev, u_int irq, void *priv) 19603479763SNathan Whitehorn { 19703479763SNathan Whitehorn uint64_t ppe; 19803479763SNathan Whitehorn int thread; 19903479763SNathan Whitehorn 20003479763SNathan Whitehorn lv1_get_logical_ppe_id(&ppe); 20103479763SNathan Whitehorn thread = 32 - fls(mfctrl()); 20203479763SNathan Whitehorn 20303479763SNathan Whitehorn lv1_end_of_interrupt_ext(ppe, thread, irq); 20403479763SNathan Whitehorn } 20503479763SNathan Whitehorn 20603479763SNathan Whitehorn static void 20703479763SNathan Whitehorn ps3pic_ipi(device_t dev, u_int cpu) 20803479763SNathan Whitehorn { 20903479763SNathan Whitehorn struct ps3pic_softc *sc; 21003479763SNathan Whitehorn sc = device_get_softc(dev); 21103479763SNathan Whitehorn 21203479763SNathan Whitehorn lv1_send_event_locally(sc->sc_ipi_outlet[cpu]); 21303479763SNathan Whitehorn } 21403479763SNathan Whitehorn 21503479763SNathan Whitehorn static void 21656505ec0SJustin Hibbits ps3pic_mask(device_t dev, u_int irq, void *priv) 21703479763SNathan Whitehorn { 21803479763SNathan Whitehorn struct ps3pic_softc *sc; 21903479763SNathan Whitehorn uint64_t ppe; 22003479763SNathan Whitehorn 22103479763SNathan Whitehorn sc = device_get_softc(dev); 22203479763SNathan Whitehorn 22303479763SNathan Whitehorn /* Do not mask IPIs! */ 224f7952747SNathan Whitehorn if (irq == sc->sc_ipi_virq) 22503479763SNathan Whitehorn return; 22603479763SNathan Whitehorn 227f574af0dSNathan Whitehorn atomic_clear_64(&sc->mask_thread0[0], 1UL << (63 - irq)); 228f574af0dSNathan Whitehorn atomic_clear_64(&sc->mask_thread1[0], 1UL << (63 - irq)); 22903479763SNathan Whitehorn 23003479763SNathan Whitehorn lv1_get_logical_ppe_id(&ppe); 23103479763SNathan Whitehorn lv1_did_update_interrupt_mask(ppe, 0); 23203479763SNathan Whitehorn lv1_did_update_interrupt_mask(ppe, 1); 23303479763SNathan Whitehorn } 23403479763SNathan Whitehorn 23503479763SNathan Whitehorn static void 23656505ec0SJustin Hibbits ps3pic_unmask(device_t dev, u_int irq, void *priv) 23703479763SNathan Whitehorn { 23803479763SNathan Whitehorn struct ps3pic_softc *sc; 23903479763SNathan Whitehorn uint64_t ppe; 24003479763SNathan Whitehorn 24103479763SNathan Whitehorn sc = device_get_softc(dev); 242f574af0dSNathan Whitehorn atomic_set_64(&sc->mask_thread0[0], 1UL << (63 - irq)); 243f574af0dSNathan Whitehorn atomic_set_64(&sc->mask_thread1[0], 1UL << (63 - irq)); 24403479763SNathan Whitehorn 24503479763SNathan Whitehorn lv1_get_logical_ppe_id(&ppe); 24603479763SNathan Whitehorn lv1_did_update_interrupt_mask(ppe, 0); 24703479763SNathan Whitehorn lv1_did_update_interrupt_mask(ppe, 1); 24803479763SNathan Whitehorn } 249