ps3pic.c revision 223463
158314Sache/*- 221308Sache * Copyright 2010 Nathan Whitehorn 321308Sache * 421308Sache * Redistribution and use in source and binary forms, with or without 521308Sache * modification, are permitted provided that the following conditions 621308Sache * are met: 721308Sache * 1. Redistributions of source code must retain the above copyright 821308Sache * notice, this list of conditions and the following disclaimer. 921308Sache * 2. Redistributions in binary form must reproduce the above copyright 1021308Sache * notice, this list of conditions and the following disclaimer in the 1158314Sache * documentation and/or other materials provided with the distribution. 1221308Sache * 1321308Sache * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1421308Sache * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1521308Sache * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1621308Sache * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1721308Sache * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 1821308Sache * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 1921308Sache * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 2021308Sache * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 2121308Sache * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2258314Sache * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2321308Sache * SUCH DAMAGE. 2421308Sache * 2521308Sache * $FreeBSD: head/sys/powerpc/ps3/ps3pic.c 223463 2011-06-23 04:35:45Z nwhitehorn $ 2621308Sache */ 2721308Sache 2821308Sache#include <sys/param.h> 2921308Sache#include <sys/systm.h> 3021308Sache#include <sys/module.h> 3121308Sache#include <sys/bus.h> 3221308Sache#include <sys/conf.h> 3321308Sache#include <sys/kernel.h> 3421308Sache#include <sys/malloc.h> 3526497Sache 3626497Sache#include <vm/vm.h> 3721308Sache#include <vm/pmap.h> 3821308Sache 3921308Sache#include <machine/bus.h> 4021308Sache#include <machine/intr_machdep.h> 4121308Sache#include <machine/md_var.h> 4221308Sache#include <machine/platform.h> 4326497Sache 4421308Sache#include "ps3-hvcall.h" 4521308Sache#include "pic_if.h" 4621308Sache 4721308Sachestatic void ps3pic_identify(driver_t *driver, device_t parent); 4821308Sachestatic int ps3pic_probe(device_t); 4921308Sachestatic int ps3pic_attach(device_t); 5021308Sache 5121308Sachestatic void ps3pic_dispatch(device_t, struct trapframe *); 5221308Sachestatic void ps3pic_enable(device_t, u_int, u_int); 5321308Sachestatic void ps3pic_eoi(device_t, u_int); 5421308Sachestatic void ps3pic_ipi(device_t, u_int); 5558314Sachestatic void ps3pic_mask(device_t, u_int); 5658314Sachestatic void ps3pic_unmask(device_t, u_int); 5758314Sache 5821308Sachestruct ps3pic_softc { 5921308Sache volatile uint64_t *bitmap_thread0; 6021308Sache volatile uint64_t *mask_thread0; 6121308Sache volatile uint64_t *bitmap_thread1; 6258314Sache volatile uint64_t *mask_thread1; 6358314Sache 6435486Sache uint64_t sc_ipi_outlet[2]; 6521308Sache int sc_vector[64]; 6658314Sache}; 6758314Sache 6858314Sachestatic device_method_t ps3pic_methods[] = { 6958314Sache /* Device interface */ 7058314Sache DEVMETHOD(device_identify, ps3pic_identify), 7121308Sache DEVMETHOD(device_probe, ps3pic_probe), 7221308Sache DEVMETHOD(device_attach, ps3pic_attach), 7358314Sache 7421308Sache /* PIC interface */ 7521308Sache DEVMETHOD(pic_dispatch, ps3pic_dispatch), 7621308Sache DEVMETHOD(pic_enable, ps3pic_enable), 7721308Sache DEVMETHOD(pic_eoi, ps3pic_eoi), 7821308Sache DEVMETHOD(pic_ipi, ps3pic_ipi), 7921308Sache DEVMETHOD(pic_mask, ps3pic_mask), 8021308Sache DEVMETHOD(pic_unmask, ps3pic_unmask), 8121308Sache 8221308Sache { 0, 0 }, 8321308Sache}; 8421308Sache 8521308Sachestatic driver_t ps3pic_driver = { 8621308Sache "ps3pic", 8721308Sache ps3pic_methods, 8821308Sache sizeof(struct ps3pic_softc) 8921308Sache}; 9021308Sache 9121308Sachestatic devclass_t ps3pic_devclass; 9221308Sache 9321308SacheDRIVER_MODULE(ps3pic, nexus, ps3pic_driver, ps3pic_devclass, 0, 0); 9421308Sache 9521308Sachestatic MALLOC_DEFINE(M_PS3PIC, "ps3pic", "PS3 PIC"); 9621308Sache 9721308Sachestatic void 9821308Sacheps3pic_identify(driver_t *driver, device_t parent) 9921308Sache{ 10021308Sache if (strcmp(installed_platform(), "ps3") != 0) 10121308Sache return; 10221308Sache 10321308Sache if (device_find_child(parent, "ps3pic", -1) == NULL) 10421308Sache BUS_ADD_CHILD(parent, 0, "ps3pic", 0); 10521308Sache} 10621308Sache 10721308Sachestatic int 10821308Sacheps3pic_probe(device_t dev) 10921308Sache{ 11021308Sache device_set_desc(dev, "Playstation 3 interrupt controller"); 11121308Sache return (BUS_PROBE_NOWILDCARD); 11221308Sache} 11321308Sache 11421308Sachestatic int 11521308Sacheps3pic_attach(device_t dev) 11621308Sache{ 11721308Sache struct ps3pic_softc *sc; 11821308Sache uint64_t ppe; 11921308Sache int thread; 12021308Sache 12121308Sache sc = device_get_softc(dev); 12221308Sache 12321308Sache sc->bitmap_thread0 = contigmalloc(128 /* 512 bits * 2 */, M_PS3PIC, 12421308Sache M_NOWAIT | M_ZERO, 0, BUS_SPACE_MAXADDR, 64 /* alignment */, 12521308Sache PAGE_SIZE /* boundary */); 12621308Sache sc->mask_thread0 = sc->bitmap_thread0 + 4; 12721308Sache sc->bitmap_thread1 = sc->bitmap_thread0 + 8; 12821308Sache sc->mask_thread1 = sc->bitmap_thread0 + 12; 12921308Sache 13021308Sache lv1_get_logical_ppe_id(&ppe); 13121308Sache thread = 32 - fls(mfctrl()); 13221308Sache lv1_configure_irq_state_bitmap(ppe, thread, 13321308Sache vtophys(sc->bitmap_thread0)); 13421308Sache#ifdef SMP 13521308Sache lv1_configure_irq_state_bitmap(ppe, !thread, 13621308Sache vtophys(sc->bitmap_thread1)); 13721308Sache 13821308Sache /* Map both IPIs to the same VIRQ to avoid changes in intr_machdep */ 13921308Sache lv1_construct_event_receive_port(&sc->sc_ipi_outlet[0]); 14021308Sache lv1_connect_irq_plug_ext(ppe, thread, sc->sc_ipi_outlet[0], 14121308Sache sc->sc_ipi_outlet[0], 0); 14221308Sache lv1_construct_event_receive_port(&sc->sc_ipi_outlet[1]); 14321308Sache lv1_connect_irq_plug_ext(ppe, !thread, sc->sc_ipi_outlet[0], 14421308Sache sc->sc_ipi_outlet[1], 0); 14521308Sache#endif 14621308Sache 14721308Sache powerpc_register_pic(dev, 0, sc->sc_ipi_outlet[0], 1, FALSE); 14821308Sache return (0); 14921308Sache} 15021308Sache 15121308Sache/* 15221308Sache * PIC I/F methods. 15321308Sache */ 15421308Sache 15521308Sachestatic void 15621308Sacheps3pic_dispatch(device_t dev, struct trapframe *tf) 15721308Sache{ 15821308Sache uint64_t bitmap, mask; 15921308Sache int irq; 16021308Sache struct ps3pic_softc *sc; 16121308Sache 16221308Sache sc = device_get_softc(dev); 16321308Sache 16421308Sache if (PCPU_GET(cpuid) == 0) { 16521308Sache bitmap = sc->bitmap_thread0[0]; 16658314Sache mask = sc->mask_thread0[0]; 16721308Sache } else { 16821308Sache bitmap = sc->bitmap_thread1[0]; 16921308Sache mask = sc->mask_thread1[0]; 17021308Sache } 17121308Sache 17221308Sache while ((irq = ffsl(bitmap & mask) - 1) != -1) { 17321308Sache bitmap &= ~(1UL << irq); 17421308Sache powerpc_dispatch_intr(sc->sc_vector[63 - irq], tf); 17521308Sache } 17621308Sache} 17721308Sache 17821308Sachestatic void 17921308Sacheps3pic_enable(device_t dev, u_int irq, u_int vector) 18021308Sache{ 18121308Sache struct ps3pic_softc *sc; 18221308Sache 18321308Sache sc = device_get_softc(dev); 18421308Sache sc->sc_vector[irq] = vector; 18521308Sache 18621308Sache ps3pic_unmask(dev, irq); 18721308Sache} 18821308Sache 18921308Sachestatic void 19021308Sacheps3pic_eoi(device_t dev, u_int irq) 19121308Sache{ 19221308Sache uint64_t ppe; 19321308Sache int thread; 19421308Sache 19521308Sache lv1_get_logical_ppe_id(&ppe); 19621308Sache thread = 32 - fls(mfctrl()); 19721308Sache 19821308Sache lv1_end_of_interrupt_ext(ppe, thread, irq); 19921308Sache} 20021308Sache 20121308Sachestatic void 20221308Sacheps3pic_ipi(device_t dev, u_int cpu) 20321308Sache{ 20421308Sache struct ps3pic_softc *sc; 20521308Sache sc = device_get_softc(dev); 20621308Sache 20721308Sache lv1_send_event_locally(sc->sc_ipi_outlet[cpu]); 20821308Sache} 20921308Sache 21021308Sachestatic void 21121308Sacheps3pic_mask(device_t dev, u_int irq) 21221308Sache{ 21321308Sache struct ps3pic_softc *sc; 21421308Sache uint64_t ppe; 21521308Sache 21621308Sache sc = device_get_softc(dev); 21721308Sache 21821308Sache /* Do not mask IPIs! */ 21921308Sache if (irq == sc->sc_ipi_outlet[0]) 22021308Sache return; 22121308Sache 22221308Sache atomic_clear_64(&sc->mask_thread0[0], 1UL << (63 - irq)); 22321308Sache atomic_clear_64(&sc->mask_thread1[0], 1UL << (63 - irq)); 22421308Sache 22521308Sache lv1_get_logical_ppe_id(&ppe); 22658314Sache lv1_did_update_interrupt_mask(ppe, 0); 22758314Sache lv1_did_update_interrupt_mask(ppe, 1); 22858314Sache} 22958314Sache 23058314Sachestatic void 23158314Sacheps3pic_unmask(device_t dev, u_int irq) 23258314Sache{ 23358314Sache struct ps3pic_softc *sc; 23458314Sache uint64_t ppe; 23558314Sache 23658314Sache sc = device_get_softc(dev); 23758314Sache atomic_set_64(&sc->mask_thread0[0], 1UL << (63 - irq)); 23821308Sache atomic_set_64(&sc->mask_thread1[0], 1UL << (63 - irq)); 23921308Sache 24021308Sache lv1_get_logical_ppe_id(&ppe); 24121308Sache lv1_did_update_interrupt_mask(ppe, 0); 24221308Sache lv1_did_update_interrupt_mask(ppe, 1); 24321308Sache} 24421308Sache