Home | History | Annotate | Line # | Download | only in dev
cbus.c revision 1.2.18.1
      1  1.2.18.1  martin /*	$NetBSD: cbus.c,v 1.2.18.1 2020/04/13 08:04:08 martin Exp $	*/
      2       1.1   palle /*	$OpenBSD: cbus.c,v 1.15 2015/09/27 11:29:20 kettenis Exp $	*/
      3       1.1   palle /*
      4       1.1   palle  * Copyright (c) 2008 Mark Kettenis
      5       1.1   palle  *
      6       1.1   palle  * Permission to use, copy, modify, and distribute this software for any
      7       1.1   palle  * purpose with or without fee is hereby granted, provided that the above
      8       1.1   palle  * copyright notice and this permission notice appear in all copies.
      9       1.1   palle  *
     10       1.1   palle  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     11       1.1   palle  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     12       1.1   palle  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     13       1.1   palle  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     14       1.1   palle  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     15       1.1   palle  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     16       1.1   palle  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     17       1.1   palle  */
     18       1.1   palle 
     19       1.1   palle #include <sys/param.h>
     20       1.1   palle #include <sys/device.h>
     21       1.1   palle #include <sys/malloc.h>
     22       1.1   palle #include <sys/systm.h>
     23       1.1   palle 
     24       1.1   palle #include <machine/autoconf.h>
     25       1.1   palle #include <machine/hypervisor.h>
     26       1.1   palle #include <machine/openfirm.h>
     27       1.1   palle #include <machine/mdesc.h>
     28       1.1   palle 
     29       1.1   palle #include <sparc64/dev/cbusvar.h>
     30       1.1   palle #include <sparc64/dev/vbusvar.h>
     31       1.1   palle 
     32       1.1   palle #include <sparc64/dev/iommureg.h>
     33       1.1   palle 
     34       1.1   palle #ifdef DEBUG
     35       1.1   palle #define CBUSDB_AC               0x01
     36       1.1   palle #define CBUSDB_INTR             0x02
     37       1.2   palle int cbus_debug = 0x00;
     38       1.1   palle #define DPRINTF(l, s)   do { if (cbus_debug & l) printf s; } while (0)
     39       1.1   palle #else
     40       1.1   palle #define DPRINTF(l, s)
     41       1.1   palle #endif
     42       1.1   palle 
     43       1.1   palle struct cbus_softc {
     44       1.1   palle 	device_t		sc_dv;
     45       1.1   palle 	bus_space_tag_t		sc_bustag;
     46       1.1   palle 	bus_dma_tag_t		sc_dmatag;
     47       1.1   palle 
     48       1.1   palle 	uint64_t		sc_devhandle;
     49       1.1   palle 
     50       1.1   palle 	/* Machine description. */
     51       1.1   palle 	int			sc_idx;
     52       1.1   palle };
     53       1.1   palle 
     54       1.1   palle int	cbus_match(device_t, cfdata_t, void *);
     55       1.1   palle void	cbus_attach(device_t, device_t, void *);
     56       1.1   palle int	cbus_print(void *, const char *);
     57       1.1   palle 
     58       1.1   palle CFATTACH_DECL_NEW(cbus, sizeof(struct cbus_softc),
     59       1.1   palle     cbus_match, cbus_attach, NULL, NULL);
     60       1.1   palle 
     61       1.1   palle 
     62       1.1   palle void *cbus_intr_establish(bus_space_tag_t, int, int,
     63       1.1   palle     int (*)(void *), void *, void (*)(void));
     64       1.1   palle void cbus_intr_ack(struct intrhand *);
     65       1.1   palle bus_space_tag_t cbus_alloc_bus_tag(struct cbus_softc *, bus_space_tag_t);
     66       1.1   palle 
     67       1.1   palle int cbus_get_channel_endpoint(struct cbus_softc *,
     68       1.1   palle 			      struct cbus_attach_args *);
     69       1.1   palle 
     70       1.1   palle int
     71       1.1   palle cbus_match(device_t parent, cfdata_t match, void *aux)
     72       1.1   palle {
     73       1.1   palle 	struct vbus_attach_args *va = aux;
     74       1.1   palle 
     75       1.1   palle 	if (strcmp(va->va_name, "channel-devices") == 0)
     76       1.1   palle 		return (1);
     77       1.1   palle 
     78       1.1   palle 	return (0);
     79       1.1   palle }
     80       1.1   palle 
     81       1.1   palle void
     82       1.1   palle cbus_attach(device_t parent, device_t self, void *aux)
     83       1.1   palle {
     84       1.1   palle         struct cbus_softc *sc = device_private(self);
     85       1.1   palle 	struct vbus_attach_args *va = aux;
     86       1.1   palle 	int node;
     87       1.1   palle 	int reg;
     88       1.1   palle 
     89       1.1   palle 	sc->sc_bustag = cbus_alloc_bus_tag(sc, va->va_bustag);
     90       1.1   palle 	sc->sc_dmatag = va->va_dmatag;
     91       1.1   palle 
     92       1.1   palle 	if (OF_getprop(va->va_node, "reg", &reg, sizeof(reg)) != sizeof(reg))
     93       1.1   palle 		return;
     94       1.1   palle 	sc->sc_devhandle = reg;
     95       1.1   palle 
     96       1.1   palle 	printf("\n");
     97       1.1   palle 
     98       1.1   palle 	sc->sc_idx = mdesc_find(va->va_name, va->va_reg[0]);
     99       1.1   palle 	if (sc->sc_idx == -1) {
    100       1.1   palle 	  DPRINTF(CBUSDB_AC, ("cbus_attach() - no idx\n"));
    101       1.1   palle 	  return;
    102       1.1   palle 	}
    103       1.1   palle 
    104       1.1   palle 	for (node = OF_child(va->va_node); node; node = OF_peer(node)) {
    105       1.1   palle 		struct cbus_attach_args ca;
    106       1.1   palle 		char buf[32];
    107       1.1   palle 
    108       1.1   palle 		bzero(&ca, sizeof(ca));
    109       1.1   palle 		ca.ca_node = node;
    110       1.1   palle 		if (OF_getprop(node, "name", buf, sizeof(buf)) <= 0)
    111       1.1   palle 			continue;
    112       1.1   palle 		DPRINTF(CBUSDB_AC, ("cbus_attach() - buf %s\n", buf));
    113       1.1   palle 		ca.ca_name = buf;
    114       1.1   palle 		ca.ca_bustag = sc->sc_bustag;
    115       1.1   palle 		ca.ca_dmatag = sc->sc_dmatag;
    116       1.1   palle 		prom_getprop(node, "reg", sizeof(*ca.ca_reg),
    117       1.1   palle 			     &ca.ca_nreg, (void **)&ca.ca_reg);
    118       1.1   palle 		int rc = cbus_get_channel_endpoint(sc, &ca);
    119       1.1   palle 		DPRINTF(CBUSDB_AC, ("cbus_attach() - cbus_get_channel_endpoint() %d\n", rc));
    120       1.1   palle 		if ( rc != 0) {
    121       1.1   palle 		  continue;
    122       1.1   palle 		}
    123       1.1   palle 
    124       1.1   palle 		config_found(self, &ca, cbus_print);
    125       1.1   palle 
    126       1.1   palle 	}
    127       1.1   palle }
    128       1.1   palle 
    129       1.1   palle int
    130       1.1   palle cbus_print(void *aux, const char *name)
    131       1.1   palle {
    132       1.1   palle 	struct cbus_attach_args *ca = aux;
    133       1.1   palle 	DPRINTF(CBUSDB_AC, ("cbus_print() name %s\n", name));
    134       1.1   palle 
    135       1.1   palle 	if (name)
    136       1.1   palle 		printf("\"%s\" at %s", ca->ca_name, name);
    137       1.1   palle 	if (ca->ca_id != -1)
    138       1.1   palle 	  printf(" chan 0x%llx", (long long unsigned int)ca->ca_id);
    139       1.1   palle 	return (UNCONF);
    140       1.1   palle }
    141       1.1   palle 
    142       1.1   palle int
    143       1.1   palle cbus_intr_setstate(bus_space_tag_t t, uint64_t devino, uint64_t state)
    144       1.1   palle {
    145       1.1   palle 	struct cbus_softc *sc = t->cookie;
    146       1.1   palle 	uint64_t devhandle = sc->sc_devhandle;
    147       1.1   palle 	int err;
    148       1.1   palle 
    149       1.1   palle 	err = hv_vintr_setstate(devhandle, devino, state);
    150       1.1   palle 	if (err != H_EOK)
    151       1.1   palle 		return (-1);
    152       1.1   palle 
    153       1.1   palle 	return (0);
    154       1.1   palle }
    155       1.1   palle 
    156       1.1   palle int
    157       1.1   palle cbus_intr_setenabled(bus_space_tag_t t, uint64_t devino, uint64_t enabled)
    158       1.1   palle {
    159       1.1   palle 	struct cbus_softc *sc = t->cookie;
    160       1.1   palle 	uint64_t devhandle = sc->sc_devhandle;
    161       1.1   palle 	int err;
    162       1.1   palle 
    163       1.1   palle 	err = hv_vintr_setenabled(devhandle, devino, enabled);
    164       1.1   palle 	if (err != H_EOK)
    165       1.1   palle 		return (-1);
    166       1.1   palle 
    167       1.1   palle 	return (0);
    168       1.1   palle }
    169       1.1   palle 
    170       1.1   palle void *
    171       1.1   palle cbus_intr_establish(bus_space_tag_t t, int ihandle, int level,
    172       1.1   palle 	int (*handler)(void *), void *arg, void (*fastvec)(void) /* ignored */)
    173       1.1   palle {
    174       1.1   palle 	struct cbus_softc *sc = t->cookie;
    175       1.1   palle 	uint64_t devhandle = sc->sc_devhandle;
    176       1.1   palle 	uint64_t devino = ihandle;
    177       1.1   palle 	struct intrhand *ih;
    178       1.1   palle 	int ino;
    179       1.1   palle 	int err;
    180       1.1   palle 
    181       1.1   palle 	ino = INTINO(ihandle);
    182       1.1   palle 
    183       1.1   palle 	DPRINTF(CBUSDB_INTR, ("cbus_intr_establish(): ino 0x%x\n", ino));
    184       1.1   palle 
    185       1.1   palle 	ih = intrhand_alloc();
    186       1.1   palle 
    187       1.1   palle 	ih->ih_ivec = ihandle;
    188       1.1   palle 	ih->ih_fun = handler;
    189       1.1   palle 	ih->ih_arg = arg;
    190       1.1   palle 	ih->ih_pil = level;
    191       1.1   palle 	ih->ih_number = ino;
    192       1.1   palle 	ih->ih_bus = t;
    193       1.1   palle 
    194       1.1   palle 	err = hv_vintr_setenabled(devhandle, devino, INTR_DISABLED);
    195       1.1   palle 	if (err != H_EOK) {
    196       1.1   palle 		printf("hv_vintr_setenabled: %d\n", err);
    197       1.1   palle 		return (NULL);
    198       1.1   palle 	}
    199       1.1   palle 
    200       1.1   palle 	err = hv_vintr_setcookie(devhandle, devino, (vaddr_t)ih);
    201       1.1   palle 	if (err != H_EOK) {
    202       1.1   palle 		printf("hv_vintr_setcookie: %d\n", err);
    203       1.1   palle 		return (NULL);
    204       1.1   palle 	}
    205       1.1   palle 
    206       1.1   palle 	ih->ih_ack = cbus_intr_ack;
    207       1.1   palle 
    208       1.1   palle 	err = hv_vintr_settarget(devhandle, devino, cpus->ci_cpuid);
    209       1.1   palle 	if (err != H_EOK) {
    210       1.1   palle 		printf("hv_vintr_settarget: %d\n", err);
    211       1.1   palle 		return (NULL);
    212       1.1   palle 	}
    213       1.1   palle 
    214       1.1   palle 	/* Clear pending interrupts. */
    215       1.1   palle 	err = hv_vintr_setstate(devhandle, devino, INTR_IDLE);
    216       1.1   palle 	if (err != H_EOK) {
    217       1.1   palle 		printf("hv_vintr_setstate: %d\n", err);
    218       1.1   palle 		return (NULL);
    219       1.1   palle 	}
    220       1.1   palle 
    221       1.1   palle 	return (ih);
    222       1.1   palle }
    223       1.1   palle 
    224       1.1   palle void
    225       1.1   palle cbus_intr_ack(struct intrhand *ih)
    226       1.1   palle {
    227       1.1   palle 	DPRINTF(CBUSDB_INTR, ("cbus_intr_ack()\n"));
    228       1.1   palle 	bus_space_tag_t t = ih->ih_bus;
    229       1.1   palle 	struct cbus_softc *sc = t->cookie;
    230       1.1   palle 	uint64_t devhandle = sc->sc_devhandle;
    231       1.1   palle 	uint64_t devino = ih->ih_number;
    232       1.1   palle 
    233       1.1   palle 	hv_vintr_setstate(devhandle, devino, INTR_IDLE);
    234       1.1   palle }
    235       1.1   palle 
    236       1.1   palle bus_space_tag_t
    237       1.1   palle cbus_alloc_bus_tag(struct cbus_softc *sc, bus_space_tag_t parent)
    238       1.1   palle {
    239       1.1   palle 	struct sparc_bus_space_tag *bt;
    240       1.1   palle 
    241  1.2.18.1  martin 	bt = malloc(sizeof(*bt), M_DEVBUF, M_WAITOK | M_ZERO);
    242       1.1   palle 	bt->cookie = sc;
    243       1.1   palle 	bt->parent = parent;
    244       1.1   palle 	bt->sparc_bus_map = parent->sparc_bus_map;
    245       1.1   palle 	bt->sparc_intr_establish = cbus_intr_establish;
    246       1.1   palle 
    247       1.1   palle 	return (bt);
    248       1.1   palle }
    249       1.1   palle 
    250       1.1   palle int
    251       1.1   palle cbus_get_channel_endpoint(struct cbus_softc *sc, struct cbus_attach_args *ca)
    252       1.1   palle {
    253       1.1   palle 	struct md_header *hdr;
    254       1.1   palle 	struct md_element *elem;
    255       1.1   palle 	const char *name_blk;
    256       1.1   palle 	const char *str;
    257       1.1   palle 	int idx;
    258       1.1   palle 	int arc;
    259       1.1   palle 
    260       1.1   palle 	idx = mdesc_find_child(sc->sc_idx, ca->ca_name, ca->ca_reg[0]);
    261       1.1   palle 	if (idx == -1) {
    262       1.1   palle 	  DPRINTF(CBUSDB_AC, ("cbus_get_channel_endpoint() - mdesc_find_child() failed\n"));
    263       1.1   palle 	  return (ENOENT);
    264       1.1   palle 	}
    265       1.1   palle 	DPRINTF(CBUSDB_AC, ("cbus_get_channel_endpoint() - idx %d\n", idx));
    266       1.1   palle 
    267       1.1   palle 	hdr = (struct md_header *)mdesc;
    268       1.1   palle 	elem = (struct md_element *)(mdesc + sizeof(struct md_header));
    269       1.1   palle 	name_blk = (char *)mdesc + sizeof(struct md_header) + hdr->node_blk_sz;
    270       1.1   palle 
    271       1.1   palle 	ca->ca_idx = idx;
    272       1.1   palle 
    273       1.1   palle 	ca->ca_id = -1;
    274       1.1   palle 	ca->ca_tx_ino = -1;
    275       1.1   palle 	ca->ca_rx_ino = -1;
    276       1.1   palle 
    277       1.1   palle 	if (strcmp(ca->ca_name, "disk") != 0 &&
    278       1.1   palle 	    strcmp(ca->ca_name, "network") != 0) {
    279       1.1   palle 	  DPRINTF(CBUSDB_AC, ("cbus_get_channel_endpoint() - neither disk nor network\n"));
    280       1.1   palle 	  return (0);
    281       1.1   palle 	}
    282       1.1   palle 
    283       1.1   palle 	for (; elem[idx].tag != 'E'; idx++) {
    284       1.1   palle 		str = name_blk + elem[idx].name_offset;
    285       1.1   palle 		if (elem[idx].tag != 'a' || strcmp(str, "fwd") != 0)
    286       1.1   palle 			continue;
    287       1.1   palle 
    288       1.1   palle 		arc = elem[idx].d.val;
    289       1.1   palle 		str = name_blk + elem[arc].name_offset;
    290       1.1   palle 		DPRINTF(CBUSDB_AC, ("cbus_get_channel_endpoint() - str %s\n", str));
    291       1.1   palle 		if (strcmp(str, "virtual-device-port") == 0) {
    292       1.1   palle 			idx = arc;
    293       1.1   palle 			DPRINTF(CBUSDB_AC, ("cbus_get_channel_endpoint() - idx %d\n", idx));
    294       1.1   palle 			continue;
    295       1.1   palle 		}
    296       1.1   palle 
    297       1.1   palle 		if (strcmp(str, "channel-endpoint") == 0) {
    298       1.1   palle 			ca->ca_id = mdesc_get_prop_val(arc, "id");
    299       1.1   palle 			ca->ca_tx_ino = mdesc_get_prop_val(arc, "tx-ino");
    300       1.1   palle 			ca->ca_rx_ino = mdesc_get_prop_val(arc, "rx-ino");
    301       1.1   palle 			DPRINTF(CBUSDB_AC, ("cbus_get_channel_endpoint() "
    302       1.1   palle 					    "- tx-ino %lu rx-ino %lu\n",
    303       1.1   palle 					    ca->ca_tx_ino, ca->ca_rx_ino));
    304       1.1   palle 			return (0);
    305       1.1   palle 		}
    306       1.1   palle 	}
    307       1.1   palle 
    308       1.1   palle 	DPRINTF(CBUSDB_AC, ("cbus_get_channel_endpoint() - exit\n"));
    309       1.1   palle 
    310       1.1   palle 	return (0);
    311       1.1   palle }
    312