Home | History | Annotate | Line # | Download | only in dev
psycho.c revision 1.4
      1 /*	$NetBSD: psycho.c,v 1.4 2000/04/08 15:15:41 mrg Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1999, 2000 Matthew R. Green
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. The name of the author may not be used to endorse or promote products
     16  *    derived from this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     23  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     25  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     26  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     28  * SUCH DAMAGE.
     29  */
     30 
     31 /*
     32  * PCI support for UltraSPARC `psycho'
     33  */
     34 
     35 #undef DEBUG
     36 #define DEBUG
     37 
     38 #ifdef DEBUG
     39 #define	PDB_PROM	0x1
     40 #define	PDB_IOMMU	0x2
     41 int psycho_debug = 0x0;
     42 #define DPRINTF(l, s)   do { if (psycho_debug & l) printf s; } while (0)
     43 #else
     44 #define DPRINTF(l, s)
     45 #endif
     46 
     47 #include <sys/param.h>
     48 #include <sys/extent.h>
     49 #include <sys/time.h>
     50 #include <sys/systm.h>
     51 #include <sys/errno.h>
     52 #include <sys/device.h>
     53 #include <sys/malloc.h>
     54 
     55 #include <vm/vm.h>
     56 #include <vm/vm_kern.h>
     57 
     58 #define _SPARC_BUS_DMA_PRIVATE
     59 #include <machine/bus.h>
     60 #include <machine/autoconf.h>
     61 
     62 #include <dev/pci/pcivar.h>
     63 #include <dev/pci/pcireg.h>
     64 
     65 #include <sparc64/dev/iommureg.h>
     66 #include <sparc64/dev/iommuvar.h>
     67 #include <sparc64/dev/psychoreg.h>
     68 #include <sparc64/dev/psychovar.h>
     69 
     70 static pci_chipset_tag_t psycho_alloc_chipset __P((struct psycho_pbm *, int,
     71 						   pci_chipset_tag_t));
     72 static void psycho_get_bus_range __P((int, int *));
     73 static void psycho_get_ranges __P((int, struct psycho_ranges **, int *));
     74 static void psycho_get_registers __P((int, struct psycho_registers **, int *));
     75 static void psycho_get_intmap __P((int, struct psycho_interrupt_map **, int *));
     76 static void psycho_get_intmapmask __P((int, struct psycho_interrupt_map_mask *));
     77 
     78 /* IOMMU support */
     79 static void psycho_iommu_init __P((struct psycho_softc *));
     80 
     81 extern struct sparc_pci_chipset _sparc_pci_chipset;
     82 
     83 /*
     84  * autoconfiguration
     85  */
     86 static	int	psycho_match __P((struct device *, struct cfdata *, void *));
     87 static	void	psycho_attach __P((struct device *, struct device *, void *));
     88 static	int	psycho_print __P((void *aux, const char *p));
     89 
     90 static	void	sabre_init __P((struct psycho_softc *, struct pcibus_attach_args *));
     91 static	void	psycho_init __P((struct psycho_softc *, struct pcibus_attach_args *));
     92 
     93 struct cfattach psycho_ca = {
     94         sizeof(struct psycho_softc), psycho_match, psycho_attach
     95 };
     96 
     97 /*
     98  * "sabre" is the UltraSPARC IIi onboard PCI interface, normally connected to
     99  * an APB (advanced PCI bridge), which was designed specifically for the IIi.
    100  * the APB appears as two "simba"'s underneath the sabre.  real devices
    101  * typically appear on the "simba"'s only.
    102  *
    103  * a pair of "psycho"s sit on the mainbus and have real devices attached to
    104  * them.  they implemented in the U2P (UPA to PCI).  these two devices share
    105  * register space and as such need to be configured together, even though the
    106  * autoconfiguration will attach them separately.
    107  *
    108  * each of these appears as two usable PCI busses, though the sabre itself
    109  * takes pci0 in this case, leaving real devices on pci1 and pci2.  there can
    110  * be multiple pairs of psycho's, however, in multi-board machines.
    111  */
    112 #define	ROM_PCI_NAME		"pci"
    113 #define ROM_SABRE_MODEL		"SUNW,sabre"
    114 #define ROM_SIMBA_MODEL		"SUNW,simba"
    115 #define ROM_PSYCHO_MODEL	"SUNW,psycho"
    116 
    117 static	int
    118 psycho_match(parent, match, aux)
    119 	struct device	*parent;
    120 	struct cfdata	*match;
    121 	void		*aux;
    122 {
    123 	struct mainbus_attach_args *ma = aux;
    124 	char *model = getpropstring(ma->ma_node, "model");
    125 
    126 	/* match on a name of "pci" and a sabre or a psycho */
    127 	if (strcmp(ma->ma_name, ROM_PCI_NAME) == 0 &&
    128 	    (strcmp(model, ROM_SABRE_MODEL) == 0 ||
    129 	     strcmp(model, ROM_PSYCHO_MODEL) == 0))
    130 		return (1);
    131 
    132 	return (0);
    133 }
    134 
    135 static	void
    136 psycho_attach(parent, self, aux)
    137 	struct device *parent, *self;
    138 	void *aux;
    139 {
    140 	struct psycho_softc *sc = (struct psycho_softc *)self;
    141 	struct pcibus_attach_args pba;
    142 	struct mainbus_attach_args *ma = aux;
    143 	char *model = getpropstring(ma->ma_node, "model");
    144 
    145 	printf("\n");
    146 
    147 	sc->sc_node = ma->ma_node;
    148 	sc->sc_bustag = ma->ma_bustag;
    149 	sc->sc_dmatag = ma->ma_dmatag;
    150 
    151 	/*
    152 	 * pull in all the information about the psycho as we can.
    153 	 */
    154 
    155 	/*
    156 	 * XXX use the prom address for the psycho registers?  we do so far.
    157 	 */
    158 	sc->sc_regs = (struct psychoreg *)(u_long)ma->ma_address[0];
    159 	sc->sc_basepaddr = (paddr_t)ma->ma_reg[0].ur_paddr;
    160 
    161 	/*
    162 	 * call the model-specific initialisation routine.
    163 	 */
    164 	if (strcmp(model, ROM_SABRE_MODEL) == 0)
    165 		sabre_init(sc, &pba);
    166 	else if (strcmp(model, ROM_PSYCHO_MODEL) == 0)
    167 		psycho_init(sc, &pba);
    168 #ifdef DIAGNOSTIC
    169 	else
    170 		panic("psycho_attach: unknown model %s?", model);
    171 #endif
    172 
    173 	/*
    174 	 * attach the pci.. note we pass PCI A tags, etc., for the sabre here.
    175 	 */
    176 	pba.pba_busname = "pci";
    177 	pba.pba_flags = sc->sc_psycho_this->pp_flags;
    178 	pba.pba_dmat = sc->sc_psycho_this->pp_dmat;
    179 	pba.pba_iot = sc->sc_psycho_this->pp_iot;
    180 	pba.pba_memt = sc->sc_psycho_this->pp_memt;
    181 
    182 	config_found(self, &pba, psycho_print);
    183 }
    184 
    185 static	int
    186 psycho_print(aux, p)
    187 	void *aux;
    188 	const char *p;
    189 {
    190 
    191 	if (p == NULL)
    192 		return (UNCONF);
    193 	return (QUIET);
    194 }
    195 
    196 /*
    197  * SUNW,sabre initialisation ..
    198  *	- get the sabre's ranges.  this are used for both simba's.
    199  *	- find the two SUNW,simba's underneath (a and b)
    200  *	- work out which simba is which via the bus-range property
    201  *	- get each simba's interrupt-map and interrupt-map-mask.
    202  *	- turn on the iommu
    203  */
    204 static void
    205 sabre_init(sc, pba)
    206 	struct psycho_softc *sc;
    207 	struct pcibus_attach_args *pba;
    208 {
    209 	struct psycho_pbm *pp;
    210 	bus_space_handle_t bh;
    211 	u_int64_t csr;
    212 	int node;
    213 	int sabre_br[2], simba_br[2];
    214 
    215 	/* who? said a voice, incredulous */
    216 	sc->sc_mode = PSYCHO_MODE_SABRE;
    217 	printf("sabre: ");
    218 
    219 	/* setup the PCI control register; there is only one for the sabre */
    220 	csr = bus_space_read_8(sc->sc_bustag, (bus_space_handle_t)(u_long)&sc->sc_regs->psy_pcictl[0].pci_csr, 0);
    221 	csr = PCICTL_SERR | PCICTL_ARB_PARK | PCICTL_ERRINTEN | PCICTL_4ENABLE;
    222 	bus_space_write_8(sc->sc_bustag, &sc->sc_regs->psy_pcictl[0].pci_csr, 0, csr);
    223 
    224 	/* allocate a pair of psycho_pbm's for our simba's */
    225 	sc->sc_sabre = malloc(sizeof *pp, M_DEVBUF, M_NOWAIT);
    226 	sc->sc_simba_a = malloc(sizeof *pp, M_DEVBUF, M_NOWAIT);
    227 	sc->sc_simba_b = malloc(sizeof *pp, M_DEVBUF, M_NOWAIT);
    228 	if (sc->sc_simba_a == NULL || sc->sc_simba_b == NULL)
    229 		panic("could not allocate simba pbm's");
    230 
    231 	memset(sc->sc_sabre, 0, sizeof *pp);
    232 	memset(sc->sc_simba_a, 0, sizeof *pp);
    233 	memset(sc->sc_simba_b, 0, sizeof *pp);
    234 
    235 	/* grab the sabre ranges; use them for both simba's */
    236 	psycho_get_ranges(sc->sc_node, &sc->sc_sabre->pp_range,
    237 	    &sc->sc_sabre->pp_nrange);
    238 	sc->sc_simba_b->pp_range = sc->sc_simba_a->pp_range =
    239 	    sc->sc_sabre->pp_range;
    240 	sc->sc_simba_b->pp_nrange = sc->sc_simba_a->pp_nrange =
    241 	    sc->sc_sabre->pp_nrange;
    242 
    243 	/* get the bus-range for the sabre.  we expect 0..2 */
    244 	psycho_get_bus_range(sc->sc_node, sabre_br);
    245 
    246 	pba->pba_bus = sabre_br[0];
    247 
    248 	printf("bus range %u to %u", sabre_br[0], sabre_br[1]);
    249 
    250 	for (node = firstchild(sc->sc_node); node; node = nextsibling(node)) {
    251 		char *name = getpropstring(node, "name");
    252 		char *model, who;
    253 
    254 		if (strcmp(name, ROM_PCI_NAME) != 0)
    255 			continue;
    256 
    257 		model = getpropstring(node, "model");
    258 		if (strcmp(model, ROM_SIMBA_MODEL) != 0)
    259 			continue;
    260 
    261 		psycho_get_bus_range(node, simba_br);
    262 
    263 		if (simba_br[0] == 1) {		/* PCI B */
    264 			pp = sc->sc_simba_b;
    265 			pp->pp_pcictl = &sc->sc_regs->psy_pcictl[1];
    266 			pp->pp_sb_diag = &sc->sc_regs->psy_strbufdiag[1];
    267 			who = 'b';
    268 		} else {			/* PCI A */
    269 			pp = sc->sc_simba_a;
    270 			pp->pp_pcictl = &sc->sc_regs->psy_pcictl[0];
    271 			pp->pp_sb_diag = &sc->sc_regs->psy_strbufdiag[0];
    272 			who = 'a';
    273 		}
    274 		/* link us in .. */
    275 		pp->pp_sc = sc;
    276 
    277 		printf("; simba %c, PCI bus %d", who, simba_br[0]);
    278 
    279 		/* grab the simba registers, interrupt map and map mask */
    280 		psycho_get_registers(node, &pp->pp_regs, &pp->pp_nregs);
    281 		psycho_get_intmap(node, &pp->pp_intmap, &pp->pp_nintmap);
    282 		psycho_get_intmapmask(node, &pp->pp_intmapmask);
    283 
    284 		/* allocate our tags */
    285 		pp->pp_memt = psycho_alloc_mem_tag(pp);
    286 		pp->pp_iot = psycho_alloc_io_tag(pp);
    287 		pp->pp_dmat = psycho_alloc_dma_tag(pp);
    288 		pp->pp_flags = (pp->pp_memt ? PCI_FLAGS_MEM_ENABLED : 0) |
    289 			       (pp->pp_iot ? PCI_FLAGS_IO_ENABLED : 0);
    290 
    291 		/* allocate a chipset for this */
    292 		pp->pp_pc = psycho_alloc_chipset(pp, node, &_sparc_pci_chipset);
    293 	}
    294 
    295 	/* setup the rest of the sabre pbm */
    296 	pp = sc->sc_sabre;
    297 	pp->pp_sc = sc;
    298 	pp->pp_memt = sc->sc_psycho_this->pp_memt;
    299 	pp->pp_iot = sc->sc_psycho_this->pp_iot;
    300 	pp->pp_dmat = sc->sc_psycho_this->pp_dmat;
    301 	pp->pp_flags = sc->sc_psycho_this->pp_flags;
    302 	pp->pp_intmap = NULL;
    303 	pp->pp_regs = NULL;
    304 	pp->pp_pcictl = sc->sc_psycho_this->pp_pcictl;
    305 	pp->pp_sb_diag = sc->sc_psycho_this->pp_sb_diag;
    306 	pba->pba_pc = psycho_alloc_chipset(pp, sc->sc_node,
    307 	    sc->sc_psycho_this->pp_pc);
    308 
    309 	printf("\n");
    310 
    311 	/* and finally start up the IOMMU ... */
    312 	psycho_iommu_init(sc);
    313 
    314 	/*
    315 	 * get us a config space tag, and punch in the physical address
    316 	 * of the PCI configuration space.  note that we use unmapped
    317 	 * access to PCI configuration space, relying on the bus space
    318 	 * macros to provide the proper ASI based on the bus tag.
    319 	 */
    320 	sc->sc_configtag = psycho_alloc_config_tag(sc->sc_simba_a);
    321 #if 0
    322 	sc->sc_configaddr = (paddr_t)sc->sc_basepaddr + 0x01000000;
    323 #else
    324 	if (bus_space_map2(sc->sc_bustag,
    325 			  PCI_CONFIG_BUS_SPACE,
    326 			  sc->sc_basepaddr + 0x01000000,
    327 			  0x0100000,
    328 			  0,
    329 			  0,
    330 			  &bh))
    331 		panic("could not map sabre PCI configuration space");
    332 	sc->sc_configaddr = (paddr_t)bh;
    333 #endif
    334 }
    335 
    336 /*
    337  * SUNW,psycho initialisation ..
    338  *	- XXX what do we do here?
    339  *
    340  * i think that an attaching psycho should here find it's partner psycho
    341  * and if they haven't been attached yet, allocate both psycho_pbm's and
    342  * fill them both in here, and when the partner attaches, there is little
    343  * to do... perhaps keep a static array of what psycho have been found so
    344  * far (or perhaps those that have not yet been finished).  .mrg.
    345  * note that the partner can be found via matching `ranges' properties.
    346  */
    347 static void
    348 psycho_init(sc, pba)
    349 	struct psycho_softc *sc;
    350 	struct pcibus_attach_args *pba;
    351 {
    352 #if 1
    353 	panic("can't do SUNW,psycho yet");
    354 #else
    355 
    356 	/*
    357 	 * OK, so the deal here is:
    358 	 *	- given our base register address, search our sibling
    359 	 *	  devices for a match.
    360 	 *	- if we find a match, we are attaching an almost
    361 	 *	  already setup PCI bus, the partner already done.
    362 	 *	- otherwise, we are doing the hard slog.
    363 	 */
    364 	for (n = 0; n < psycho_cd.cd_ndevs; n++) {
    365 		psycho_softc *osc = &psycho_cd.cd_devs[n];
    366 
    367 		/*
    368 		 * I am not myself.
    369 		 */
    370 		if (osc == sc || osc->sc_regs != sc->sc_regs)
    371 			continue;
    372 
    373 		/*
    374 		 * OK, so we found a matching regs that wasn't me,
    375 		 * so that must make me partly attached.  Finish it.
    376 		 */
    377 	}
    378 
    379 	/* Oh, dear.  OK, lets get started */
    380 
    381 	/* who? said a voice, incredulous */
    382 	sc->sc_mode = PSYCHO_MODE_PSYCHO_A;
    383 	printf("psycho: ");
    384 #endif
    385 }
    386 
    387 /*
    388  * PCI bus support
    389  */
    390 
    391 /*
    392  * allocate a PCI chipset tag and set it's cookie.
    393  */
    394 static pci_chipset_tag_t
    395 psycho_alloc_chipset(pp, node, pc)
    396 	struct psycho_pbm *pp;
    397 	int node;
    398 	pci_chipset_tag_t pc;
    399 {
    400 	pci_chipset_tag_t npc;
    401 
    402 	npc = malloc(sizeof *npc, M_DEVBUF, M_NOWAIT);
    403 	if (npc == NULL)
    404 		panic("could not allocate pci_chipset_tag_t");
    405 	memcpy(npc, pc, sizeof *pc);
    406 	npc->cookie = pp;
    407 	npc->node = node;
    408 
    409 	return (npc);
    410 }
    411 
    412 /*
    413  * grovel the OBP for various psycho properties
    414  */
    415 static void
    416 psycho_get_bus_range(node, brp)
    417 	int node;
    418 	int *brp;
    419 {
    420 	int n;
    421 
    422 	if (getprop(node, "bus-range", sizeof(*brp), &n, (void **)&brp))
    423 		panic("could not get psycho bus-range");
    424 	if (n != 2)
    425 		panic("broken psycho bus-range");
    426 	DPRINTF(PDB_PROM, ("psycho debug: got `bus-range' for node %08x: %u - %u\n", node, brp[0], brp[1]));
    427 }
    428 
    429 static void
    430 psycho_get_ranges(node, rp, np)
    431 	int node;
    432 	struct psycho_ranges **rp;
    433 	int *np;
    434 {
    435 
    436 	if (getprop(node, "ranges", sizeof(**rp), np, (void **)rp))
    437 		panic("could not get psycho ranges");
    438 	DPRINTF(PDB_PROM, ("psycho debug: got `ranges' for node %08x: %d entries\n", node, *np));
    439 }
    440 
    441 static void
    442 psycho_get_registers(node, rp, np)
    443 	int node;
    444 	struct psycho_registers **rp;
    445 	int *np;
    446 {
    447 
    448 	if (getprop(node, "reg", sizeof(**rp), np, (void **)rp))
    449 		panic("could not get psycho registers");
    450 	DPRINTF(PDB_PROM, ("psycho debug: got `reg' for node %08x: %d entries\n", node, *np));
    451 }
    452 
    453 static void
    454 psycho_get_intmap(node, imp, np)
    455 	int node;
    456 	struct psycho_interrupt_map **imp;
    457 	int *np;
    458 {
    459 
    460 	if (getprop(node, "interrupt-map", sizeof(**imp), np, (void **)imp))
    461 		panic("could not get psycho interrupt-map");
    462 	DPRINTF(PDB_PROM, ("psycho debug: got `interupt-map' for node %08x\n", node));
    463 }
    464 
    465 static void
    466 psycho_get_intmapmask(node, immp)
    467 	int node;
    468 	struct psycho_interrupt_map_mask *immp;
    469 {
    470 	int n;
    471 
    472 	if (getprop(node, "interrupt-map-mask", sizeof(*immp), &n,
    473 	    (void **)&immp))
    474 		panic("could not get psycho interrupt-map-mask");
    475 	if (n != 1)
    476 		panic("broken psycho interrupt-map-mask");
    477 	DPRINTF(PDB_PROM, ("psycho debug: got `interrupt-map-mask' for node %08x\n", node));
    478 }
    479 
    480 /*
    481  * IOMMU code
    482  */
    483 
    484 /*
    485  * initialise the IOMMU..
    486  */
    487 void
    488 psycho_iommu_init(sc)
    489 	struct psycho_softc *sc;
    490 {
    491 	char *name;
    492 
    493 	/* punch in our copies */
    494 	sc->sc_is.is_bustag = sc->sc_bustag;
    495 	sc->sc_is.is_iommu = &sc->sc_regs->psy_iommu;
    496 	sc->sc_is.is_sb = &sc->sc_regs->psy_iommu_strbuf;
    497 
    498 	/* give us a nice name.. */
    499 	name = (char *)malloc(32, M_DEVBUF, M_NOWAIT);
    500 	if (name == 0)
    501 		panic("couldn't malloc iommu name");
    502 	snprintf(name, 32, "%s dvma", sc->sc_dev.dv_xname);
    503 
    504 	/* XXX XXX XXX FIX ME tsbsize XXX XXX XXX */
    505 	iommu_init(name, &sc->sc_is, 0);
    506 }
    507