ps3pic.c revision 217044
198937Sdes/*- 298937Sdes * Copyright 2010 Nathan Whitehorn 3106121Sdes * 4225825Sdes * Redistribution and use in source and binary forms, with or without 5255670Sdes * modification, are permitted provided that the following conditions 698937Sdes * are met: 7255670Sdes * 1. Redistributions of source code must retain the above copyright 898937Sdes * notice, this list of conditions and the following disclaimer. 998937Sdes * 2. Redistributions in binary form must reproduce the above copyright 1098937Sdes * notice, this list of conditions and the following disclaimer in the 1198937Sdes * documentation and/or other materials provided with the distribution. 1298937Sdes * 1398937Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1498937Sdes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1598937Sdes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1698937Sdes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1798937Sdes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 1898937Sdes * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 1998937Sdes * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 2098937Sdes * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 2198937Sdes * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2298937Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2398937Sdes * SUCH DAMAGE. 24255670Sdes * 25149749Sdes * $FreeBSD: head/sys/powerpc/ps3/ps3pic.c 217044 2011-01-06 04:12:29Z nwhitehorn $ 2698937Sdes */ 2798937Sdes 2898937Sdes#include <sys/param.h> 2998937Sdes#include <sys/systm.h> 3098937Sdes#include <sys/module.h> 31149749Sdes#include <sys/bus.h> 32106121Sdes#include <sys/conf.h> 33204861Sdes#include <sys/kernel.h> 3498937Sdes#include <sys/malloc.h> 3598937Sdes 3698937Sdes#include <vm/vm.h> 3798937Sdes#include <vm/pmap.h> 3898937Sdes 3998937Sdes#include <machine/bus.h> 40204861Sdes#include <machine/intr_machdep.h> 41204861Sdes#include <machine/md_var.h> 42204861Sdes#include <machine/platform.h> 4398937Sdes 4498937Sdes#include "ps3-hvcall.h" 4598937Sdes#include "pic_if.h" 4698937Sdes 4798937Sdesstatic void ps3pic_identify(driver_t *driver, device_t parent); 4898937Sdesstatic int ps3pic_probe(device_t); 4998937Sdesstatic int ps3pic_attach(device_t); 5098937Sdes 5198937Sdesstatic void ps3pic_dispatch(device_t, struct trapframe *); 5298937Sdesstatic void ps3pic_enable(device_t, u_int, u_int); 5398937Sdesstatic void ps3pic_eoi(device_t, u_int); 5498937Sdesstatic void ps3pic_ipi(device_t, u_int); 5598937Sdesstatic void ps3pic_mask(device_t, u_int); 5698937Sdesstatic void ps3pic_unmask(device_t, u_int); 5798937Sdesstatic uint32_t ps3pic_id(device_t dev); 5898937Sdes 5998937Sdesstruct ps3pic_softc { 6098937Sdes uint64_t *bitmap_thread0; 6198937Sdes uint64_t *mask_thread0; 6298937Sdes uint64_t *bitmap_thread1; 6398937Sdes uint64_t *mask_thread1; 6498937Sdes 6598937Sdes uint64_t sc_ipi_outlet[2]; 6698937Sdes int sc_vector[64]; 6798937Sdes}; 6898937Sdes 6998937Sdesstatic device_method_t ps3pic_methods[] = { 7098937Sdes /* Device interface */ 7198937Sdes DEVMETHOD(device_identify, ps3pic_identify), 7298937Sdes DEVMETHOD(device_probe, ps3pic_probe), 7398937Sdes DEVMETHOD(device_attach, ps3pic_attach), 7498937Sdes 7598937Sdes /* PIC interface */ 76204861Sdes DEVMETHOD(pic_dispatch, ps3pic_dispatch), 77255670Sdes DEVMETHOD(pic_enable, ps3pic_enable), 78255670Sdes DEVMETHOD(pic_eoi, ps3pic_eoi), 7998937Sdes DEVMETHOD(pic_id, ps3pic_id), 8098937Sdes DEVMETHOD(pic_ipi, ps3pic_ipi), 8198937Sdes DEVMETHOD(pic_mask, ps3pic_mask), 8298937Sdes DEVMETHOD(pic_unmask, ps3pic_unmask), 8398937Sdes 8498937Sdes { 0, 0 }, 8598937Sdes}; 8698937Sdes 8798937Sdesstatic driver_t ps3pic_driver = { 8898937Sdes "ps3pic", 8998937Sdes ps3pic_methods, 90149749Sdes sizeof(struct ps3pic_softc) 9198937Sdes}; 92149749Sdes 9398937Sdesstatic devclass_t ps3pic_devclass; 94149749Sdes 9598937SdesDRIVER_MODULE(ps3pic, nexus, ps3pic_driver, ps3pic_devclass, 0, 0); 9698937Sdes 9798937Sdesstatic MALLOC_DEFINE(M_PS3PIC, "ps3pic", "PS3 PIC"); 9898937Sdes 9998937Sdesstatic void 10098937Sdesps3pic_identify(driver_t *driver, device_t parent) 10198937Sdes{ 10298937Sdes if (strcmp(installed_platform(), "ps3") != 0) 10398937Sdes return; 10498937Sdes 10598937Sdes if (device_find_child(parent, "ps3pic", -1) == NULL) 106149749Sdes BUS_ADD_CHILD(parent, 0, "ps3pic", 0); 10798937Sdes} 10898937Sdes 10998937Sdesstatic int 11098937Sdesps3pic_probe(device_t dev) 11198937Sdes{ 11298937Sdes device_set_desc(dev, "Playstation 3 interrupt controller"); 11398937Sdes return (BUS_PROBE_NOWILDCARD); 11498937Sdes} 11598937Sdes 11698937Sdesstatic int 11798937Sdesps3pic_attach(device_t dev) 11898937Sdes{ 11998937Sdes struct ps3pic_softc *sc; 12098937Sdes uint64_t ppe; 12198937Sdes int thread; 12298937Sdes 12398937Sdes sc = device_get_softc(dev); 12498937Sdes 125225825Sdes sc->bitmap_thread0 = contigmalloc(128 /* 512 bits * 2 */, M_PS3PIC, 126255670Sdes M_NOWAIT | M_ZERO, 0, BUS_SPACE_MAXADDR, 64 /* alignment */, 127225825Sdes PAGE_SIZE /* boundary */); 128204861Sdes sc->mask_thread0 = sc->bitmap_thread0 + 4; 129189006Sdes sc->bitmap_thread1 = sc->bitmap_thread0 + 8; 13098937Sdes sc->mask_thread1 = sc->bitmap_thread0 + 12; 13198937Sdes 13298937Sdes lv1_get_logical_ppe_id(&ppe); 133255670Sdes thread = 32 - fls(mfctrl()); 134255670Sdes lv1_configure_irq_state_bitmap(ppe, thread, 135255670Sdes vtophys(sc->bitmap_thread0)); 136255670Sdes#ifdef SMP 13798937Sdes lv1_configure_irq_state_bitmap(ppe, !thread, 13898937Sdes vtophys(sc->bitmap_thread1)); 13998937Sdes 14098937Sdes /* Map both IPIs to the same VIRQ to avoid changes in intr_machdep */ 14198937Sdes lv1_construct_event_receive_port(&sc->sc_ipi_outlet[0]); 14298937Sdes lv1_connect_irq_plug_ext(ppe, thread, sc->sc_ipi_outlet[0], 14398937Sdes sc->sc_ipi_outlet[0], 0); 14498937Sdes lv1_construct_event_receive_port(&sc->sc_ipi_outlet[1]); 14598937Sdes lv1_connect_irq_plug_ext(ppe, !thread, sc->sc_ipi_outlet[0], 14698937Sdes sc->sc_ipi_outlet[1], 0); 14798937Sdes#endif 14898937Sdes 14998937Sdes powerpc_register_pic(dev, sc->sc_ipi_outlet[0]); 15098937Sdes root_pic = dev; /* PS3s have only one PIC */ 15198937Sdes 15298937Sdes return (0); 15398937Sdes} 15498937Sdes 15598937Sdes/* 15698937Sdes * PIC I/F methods. 15798937Sdes */ 15898937Sdes 159255670Sdesstatic void 16098937Sdesps3pic_dispatch(device_t dev, struct trapframe *tf) 16198937Sdes{ 16298937Sdes uint64_t bitmap, mask; 163255670Sdes int irq; 164255670Sdes struct ps3pic_softc *sc; 165204861Sdes 16698937Sdes sc = device_get_softc(dev); 16798937Sdes 16898937Sdes if (PCPU_GET(cpuid) == 0) { 16998937Sdes bitmap = sc->bitmap_thread0[0]; 17098937Sdes mask = sc->mask_thread0[0]; 17198937Sdes } else { 17298937Sdes bitmap = sc->bitmap_thread1[0]; 17398937Sdes mask = sc->mask_thread1[0]; 17498937Sdes } 17598937Sdes 176106121Sdes while ((irq = ffsl(bitmap & mask) - 1) != -1) { 177106121Sdes bitmap &= ~(1UL << irq); 178106121Sdes powerpc_dispatch_intr(sc->sc_vector[63 - irq], tf); 179106121Sdes } 180255670Sdes} 181255670Sdes 182106121Sdesstatic void 183255670Sdesps3pic_enable(device_t dev, u_int irq, u_int vector) 18498937Sdes{ 18598937Sdes struct ps3pic_softc *sc; 18698937Sdes 187189006Sdes sc = device_get_softc(dev); 188189006Sdes sc->sc_vector[irq] = vector; 189189006Sdes 190189006Sdes ps3pic_unmask(dev, irq); 19198937Sdes} 19298937Sdes 19398937Sdesstatic void 19498937Sdesps3pic_eoi(device_t dev, u_int irq) 19598937Sdes{ 19698937Sdes uint64_t ppe; 19798937Sdes int thread; 19898937Sdes 19998937Sdes lv1_get_logical_ppe_id(&ppe); 20098937Sdes thread = 32 - fls(mfctrl()); 20198937Sdes 20298937Sdes lv1_end_of_interrupt_ext(ppe, thread, irq); 20398937Sdes} 20498937Sdes 20598937Sdesstatic void 20698937Sdesps3pic_ipi(device_t dev, u_int cpu) 207189006Sdes{ 208189006Sdes struct ps3pic_softc *sc; 209189006Sdes sc = device_get_softc(dev); 210189006Sdes 21198937Sdes lv1_send_event_locally(sc->sc_ipi_outlet[cpu]); 21298937Sdes} 21398937Sdes 21498937Sdesstatic void 21598937Sdesps3pic_mask(device_t dev, u_int irq) 21698937Sdes{ 21798937Sdes struct ps3pic_softc *sc; 21898937Sdes uint64_t ppe; 21998937Sdes 22098937Sdes sc = device_get_softc(dev); 22198937Sdes 22298937Sdes /* Do not mask IPIs! */ 22398937Sdes if (irq == sc->sc_ipi_outlet[0]) 22498937Sdes return; 22598937Sdes 22698937Sdes sc->mask_thread0[0] &= ~(1UL << (63 - irq)); 22798937Sdes sc->mask_thread1[0] &= ~(1UL << (63 - irq)); 228255670Sdes 229255670Sdes lv1_get_logical_ppe_id(&ppe); 230255670Sdes lv1_did_update_interrupt_mask(ppe, 0); 231255670Sdes lv1_did_update_interrupt_mask(ppe, 1); 232255670Sdes} 233255670Sdes 23498937Sdesstatic void 23598937Sdesps3pic_unmask(device_t dev, u_int irq) 23698937Sdes{ 23798937Sdes struct ps3pic_softc *sc; 23898937Sdes uint64_t ppe; 23998937Sdes 24098937Sdes sc = device_get_softc(dev); 24198937Sdes sc->mask_thread0[0] |= (1UL << (63 - irq)); 24298937Sdes sc->mask_thread1[0] |= (1UL << (63 - irq)); 24398937Sdes 24498937Sdes lv1_get_logical_ppe_id(&ppe); 24598937Sdes lv1_did_update_interrupt_mask(ppe, 0); 24698937Sdes lv1_did_update_interrupt_mask(ppe, 1); 24798937Sdes} 24898937Sdes 24998937Sdesstatic uint32_t 25098937Sdesps3pic_id(device_t dev) 25198937Sdes{ 25298937Sdes return (0); 25398937Sdes} 25498937Sdes 25598937Sdes