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