Home | History | Annotate | Line # | Download | only in dev
      1 /* $NetBSD: xp.c,v 1.8 2023/01/15 05:08:33 tsutsui Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2016 Izumi Tsutsui.  All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  */
     26 
     27 /*
     28  * LUNA's Hitachi HD647180 "XP" I/O processor driver
     29  */
     30 
     31 #include <sys/cdefs.h>
     32 __KERNEL_RCSID(0, "$NetBSD: xp.c,v 1.8 2023/01/15 05:08:33 tsutsui Exp $");
     33 
     34 #include <sys/param.h>
     35 #include <sys/systm.h>
     36 #include <sys/conf.h>
     37 #include <sys/device.h>
     38 #include <sys/fcntl.h>
     39 #include <sys/ioctl.h>
     40 #include <sys/kmem.h>
     41 #include <sys/mman.h>
     42 #include <sys/errno.h>
     43 
     44 #include <uvm/uvm_extern.h>
     45 
     46 #include <machine/autoconf.h>
     47 #include <machine/board.h>
     48 #include <machine/xpio.h>
     49 
     50 #include <luna68k/dev/xpbusvar.h>
     51 
     52 #include "ioconf.h"
     53 #include "xplx/xplxdefs.h"
     54 
     55 struct xp_softc {
     56 	device_t	sc_dev;
     57 
     58 	vaddr_t		sc_shm_base;
     59 	vsize_t		sc_shm_size;
     60 	vaddr_t		sc_tas;
     61 
     62 	bool		sc_isopen;
     63 	int		sc_flags;
     64 };
     65 
     66 static int xp_match(device_t, cfdata_t, void *);
     67 static void xp_attach(device_t, device_t, void *);
     68 
     69 static dev_type_open(xp_open);
     70 static dev_type_close(xp_close);
     71 static dev_type_read(xp_read);
     72 static dev_type_write(xp_write);
     73 static dev_type_ioctl(xp_ioctl);
     74 static dev_type_mmap(xp_mmap);
     75 
     76 const struct cdevsw xp_cdevsw = {
     77 	.d_open     = xp_open,
     78 	.d_close    = xp_close,
     79 	.d_read     = xp_read,
     80 	.d_write    = xp_write,
     81 	.d_ioctl    = xp_ioctl,
     82 	.d_stop     = nostop,
     83 	.d_tty      = notty,
     84 	.d_poll     = nopoll,
     85 	.d_mmap     = xp_mmap,
     86 	.d_kqfilter = nokqfilter,
     87 	.d_discard  = nodiscard,
     88 	.d_flag     = 0
     89 };
     90 
     91 CFATTACH_DECL_NEW(xp, sizeof(struct xp_softc),
     92     xp_match, xp_attach, NULL, NULL);
     93 
     94 /* #define XP_DEBUG */
     95 
     96 #ifdef XP_DEBUG
     97 #define XP_DEBUG_ALL	0xff
     98 uint32_t xp_debug = 0;
     99 #define DPRINTF(x, y)	if (xp_debug & (x)) printf y
    100 #else
    101 #define DPRINTF(x, y)	/* nothing */
    102 #endif
    103 
    104 static bool xp_matched;
    105 
    106 static int
    107 xp_match(device_t parent, cfdata_t cf, void *aux)
    108 {
    109 	struct xpbus_attach_args *xa = aux;
    110 
    111 	/* only one XP processor */
    112 	if (xp_matched)
    113 		return 0;
    114 
    115 	if (strcmp(xa->xa_name, xp_cd.cd_name))
    116 		return 0;
    117 
    118 	xp_matched = true;
    119 	return 1;
    120 }
    121 
    122 static void
    123 xp_attach(device_t parent, device_t self, void *aux)
    124 {
    125 	struct xp_softc *sc = device_private(self);
    126 
    127 	sc->sc_dev = self;
    128 
    129 	aprint_normal(": HD647180X I/O processor\n");
    130 
    131 	sc->sc_shm_base = XP_SHM_BASE;
    132 	sc->sc_shm_size = XP_SHM_SIZE;
    133 	sc->sc_tas      = XP_TAS_ADDR;
    134 }
    135 
    136 static int
    137 xp_open(dev_t dev, int flags, int devtype, struct lwp *l)
    138 {
    139 	struct xp_softc *sc;
    140 	int unit;
    141 	u_int a;
    142 
    143 	DPRINTF(XP_DEBUG_ALL, ("%s\n", __func__));
    144 
    145 	unit = minor(dev);
    146 	sc = device_lookup_private(&xp_cd, unit);
    147 	if (sc == NULL)
    148 		return ENXIO;
    149 	if (sc->sc_isopen)
    150 		return EBUSY;
    151 
    152 	if ((flags & FWRITE) != 0) {
    153 		/* exclusive if write */
    154 		a = xp_acquire(DEVID_XPBUS, XP_ACQ_EXCL);
    155 		if (a == 0)
    156 			return EBUSY;
    157 		if (a != (1 << DEVID_XPBUS)) {
    158 			xp_release(DEVID_XPBUS);
    159 			return EBUSY;
    160 		}
    161 	} else {
    162 		a = xp_acquire(DEVID_XPBUS, 0);
    163 		if (a == 0)
    164 			return EBUSY;
    165 	}
    166 
    167 	sc->sc_isopen = true;
    168 	sc->sc_flags = flags;
    169 
    170 	return 0;
    171 }
    172 
    173 static int
    174 xp_close(dev_t dev, int flags, int mode, struct lwp *l)
    175 {
    176 	struct xp_softc *sc;
    177 	int unit;
    178 
    179 	DPRINTF(XP_DEBUG_ALL, ("%s\n", __func__));
    180 
    181 	unit = minor(dev);
    182 	sc = device_lookup_private(&xp_cd, unit);
    183 
    184 	xp_release(DEVID_XPBUS);
    185 
    186 	sc->sc_isopen = false;
    187 
    188 	return 0;
    189 }
    190 
    191 static int
    192 xp_ioctl(dev_t dev, u_long cmd, void *addr, int flags, struct lwp *l)
    193 {
    194 	struct xp_softc *sc;
    195 	int unit, error;
    196 	struct xp_download *downld;
    197 	uint8_t *loadbuf;
    198 	size_t loadsize;
    199 
    200 	DPRINTF(XP_DEBUG_ALL, ("%s\n", __func__));
    201 
    202 	unit = minor(dev);
    203 	sc = device_lookup_private(&xp_cd, unit);
    204 
    205 	switch (cmd) {
    206 	case XPIOCDOWNLD:
    207 		if ((sc->sc_flags & FWRITE) == 0) {
    208 			return EACCES;
    209 		}
    210 		downld = addr;
    211 		loadsize = downld->size;
    212 		if (loadsize == 0 || loadsize > sc->sc_shm_size) {
    213 			return EINVAL;
    214 		}
    215 
    216 		loadbuf = kmem_alloc(loadsize, KM_SLEEP);
    217 		error = copyin(downld->data, loadbuf, loadsize);
    218 		if (error == 0) {
    219 			xp_set_shm_dirty();
    220 			xp_cpu_reset_hold();
    221 			delay(100);
    222 			memcpy((void *)sc->sc_shm_base, loadbuf, loadsize);
    223 			delay(100);
    224 			xp_cpu_reset_release();
    225 		} else {
    226 			DPRINTF(XP_DEBUG_ALL, ("%s: ioctl failed (err =  %d)\n",
    227 			    __func__, error));
    228 		}
    229 
    230 		kmem_free(loadbuf, loadsize);
    231 		return error;
    232 
    233 	default:
    234 		return ENOTTY;
    235 	}
    236 
    237 	panic("%s: cmd (%ld) is not handled", device_xname(sc->sc_dev), cmd);
    238 }
    239 
    240 static paddr_t
    241 xp_mmap(dev_t dev, off_t offset, int prot)
    242 {
    243 	struct xp_softc *sc;
    244 	int unit;
    245 	paddr_t pa;
    246 
    247 	pa = -1;
    248 
    249 	unit = minor(dev);
    250 	sc = device_lookup_private(&xp_cd, unit);
    251 
    252 	if (offset >= 0 &&
    253 	    offset < sc->sc_shm_size) {
    254 		pa = m68k_btop(m68k_trunc_page(sc->sc_shm_base) + offset);
    255 	}
    256 
    257 	if ((prot & PROT_WRITE) != 0)
    258 		xp_set_shm_dirty();
    259 
    260 	return pa;
    261 }
    262 
    263 static int
    264 xp_read(dev_t dev, struct uio *uio, int flags)
    265 {
    266 
    267 	return ENODEV;
    268 }
    269 
    270 static int
    271 xp_write(dev_t dev, struct uio *uio, int flags)
    272 {
    273 
    274 	return ENODEV;
    275 }
    276