1/*- 2 * Copyright (c) 2015-2016 Ruslan Bukin <br@bsdpad.com> 3 * All rights reserved. 4 * 5 * Portions of this software were developed by SRI International and the 6 * University of Cambridge Computer Laboratory under DARPA/AFRL contract 7 * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme. 8 * 9 * Portions of this software were developed by the University of Cambridge 10 * Computer Laboratory as part of the CTSRD Project, with support from the 11 * UK Higher Education Innovation Fund (HEIF). 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35#include <sys/cdefs.h> 36__FBSDID("$FreeBSD: releng/11.0/sys/riscv/htif/htif_block.c 298476 2016-04-22 15:12:05Z br $"); 37 38#include <sys/param.h> 39#include <sys/systm.h> 40#include <sys/kernel.h> 41#include <sys/kthread.h> 42#include <sys/selinfo.h> 43#include <sys/module.h> 44#include <sys/lock.h> 45#include <sys/mutex.h> 46#include <sys/malloc.h> 47#include <sys/sysctl.h> 48#include <sys/uio.h> 49 50#include <sys/bio.h> 51#include <sys/bus.h> 52#include <sys/conf.h> 53#include <sys/disk.h> 54#include <geom/geom_disk.h> 55 56#include <vm/vm.h> 57#include <vm/pmap.h> 58 59#include <machine/md_var.h> 60#include <machine/bus.h> 61#include <machine/trap.h> 62#include <sys/rman.h> 63 64#include "htif.h" 65 66#define SECTOR_SIZE_SHIFT (9) 67#define SECTOR_SIZE (1 << SECTOR_SIZE_SHIFT) 68 69#define HTIF_BLK_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) 70#define HTIF_BLK_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) 71#define HTIF_BLK_LOCK_INIT(_sc) \ 72 mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \ 73 "htif_blk", MTX_DEF) 74#define HTIF_BLK_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx); 75#define HTIF_BLK_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED); 76#define HTIF_BLK_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED); 77 78static void htif_blk_task(void *arg); 79 80static disk_open_t htif_blk_open; 81static disk_close_t htif_blk_close; 82static disk_strategy_t htif_blk_strategy; 83 84struct htif_blk_softc { 85 device_t dev; 86 struct disk *disk; 87 struct mtx htif_io_mtx; 88 struct mtx sc_mtx; 89 struct proc *p; 90 struct bio_queue_head bio_queue; 91 int running; 92 int intr_chan; 93 int cmd_done; 94 int index; 95 uint16_t curtag; 96}; 97 98struct htif_blk_request { 99 uint64_t addr; 100 uint64_t offset; /* offset in bytes */ 101 uint64_t size; /* length in bytes */ 102 uint64_t tag; 103}; 104 105static void 106htif_blk_intr(void *arg, uint64_t entry) 107{ 108 struct htif_blk_softc *sc; 109 uint64_t devcmd; 110 uint64_t data; 111 112 sc = arg; 113 114 devcmd = HTIF_DEV_CMD(entry); 115 data = HTIF_DEV_DATA(entry); 116 117 if (sc->curtag == data) { 118 wmb(); 119 sc->cmd_done = 1; 120 wakeup(&sc->intr_chan); 121 } else { 122 device_printf(sc->dev, "Unexpected tag %d (should be %d)\n", 123 data, sc->curtag); 124 } 125} 126 127static int 128htif_blk_probe(device_t dev) 129{ 130 131 return (0); 132} 133 134static int 135htif_blk_attach(device_t dev) 136{ 137 struct htif_blk_softc *sc; 138 char prefix[] = " size="; 139 char *str; 140 long size; 141 142 sc = device_get_softc(dev); 143 sc->dev = dev; 144 145 mtx_init(&sc->htif_io_mtx, device_get_nameunit(dev), "htif_blk", MTX_DEF); 146 HTIF_BLK_LOCK_INIT(sc); 147 148 str = strstr(htif_get_id(dev), prefix); 149 150 size = strtol((str + 6), NULL, 10); 151 if (size == 0) { 152 return (ENXIO); 153 } 154 155 sc->index = htif_get_index(dev); 156 if (sc->index < 0) 157 return (EINVAL); 158 htif_setup_intr(sc->index, htif_blk_intr, sc); 159 160 sc->disk = disk_alloc(); 161 sc->disk->d_drv1 = sc; 162 163 sc->disk->d_maxsize = 4096; /* Max transfer */ 164 sc->disk->d_name = "htif_blk"; 165 sc->disk->d_open = htif_blk_open; 166 sc->disk->d_close = htif_blk_close; 167 sc->disk->d_strategy = htif_blk_strategy; 168 sc->disk->d_unit = 0; 169 sc->disk->d_sectorsize = SECTOR_SIZE; 170 sc->disk->d_mediasize = size; 171 disk_create(sc->disk, DISK_VERSION); 172 173 bioq_init(&sc->bio_queue); 174 175 sc->running = 1; 176 177 kproc_create(&htif_blk_task, sc, &sc->p, 0, 0, "%s: transfer", 178 device_get_nameunit(dev)); 179 180 return (0); 181} 182 183static int 184htif_blk_open(struct disk *dp) 185{ 186 187 return (0); 188} 189 190static int 191htif_blk_close(struct disk *dp) 192{ 193 194 return (0); 195} 196 197static void 198htif_blk_task(void *arg) 199{ 200 struct htif_blk_request req __aligned(HTIF_ALIGN); 201 struct htif_blk_softc *sc; 202 uint64_t req_paddr; 203 struct bio *bp; 204 uint64_t paddr; 205 uint64_t cmd; 206 int i; 207 208 sc = (struct htif_blk_softc *)arg; 209 210 while (1) { 211 HTIF_BLK_LOCK(sc); 212 do { 213 bp = bioq_takefirst(&sc->bio_queue); 214 if (bp == NULL) 215 msleep(sc, &sc->sc_mtx, PRIBIO, "jobqueue", 0); 216 } while (bp == NULL); 217 HTIF_BLK_UNLOCK(sc); 218 219 if (bp->bio_cmd == BIO_READ || bp->bio_cmd == BIO_WRITE) { 220 HTIF_BLK_LOCK(sc); 221 222 rmb(); 223 req.offset = (bp->bio_pblkno * sc->disk->d_sectorsize); 224 req.size = bp->bio_bcount; 225 paddr = vtophys(bp->bio_data); 226 KASSERT(paddr != 0, ("paddr is 0")); 227 req.addr = paddr; 228 sc->curtag++; 229 req.tag = sc->curtag; 230 231 cmd = sc->index; 232 cmd <<= HTIF_DEV_ID_SHIFT; 233 if (bp->bio_cmd == BIO_READ) 234 cmd |= (HTIF_CMD_READ << HTIF_CMD_SHIFT); 235 else 236 cmd |= (HTIF_CMD_WRITE << HTIF_CMD_SHIFT); 237 req_paddr = vtophys(&req); 238 KASSERT(req_paddr != 0, ("req_paddr is 0")); 239 cmd |= req_paddr; 240 241 sc->cmd_done = 0; 242 htif_command(cmd); 243 244 /* Wait for interrupt */ 245 i = 0; 246 while (sc->cmd_done == 0) { 247 msleep(&sc->intr_chan, &sc->sc_mtx, PRIBIO, "intr", hz/2); 248 249 if (i++ > 2) { 250 /* TODO: try to re-issue operation on timeout ? */ 251 bp->bio_error = EIO; 252 bp->bio_flags |= BIO_ERROR; 253 disk_err(bp, "hard error", -1, 1); 254 break; 255 } 256 } 257 HTIF_BLK_UNLOCK(sc); 258 259 biodone(bp); 260 } else { 261 printf("unknown op %d\n", bp->bio_cmd); 262 } 263 } 264} 265 266static void 267htif_blk_strategy(struct bio *bp) 268{ 269 struct htif_blk_softc *sc; 270 271 sc = bp->bio_disk->d_drv1; 272 273 HTIF_BLK_LOCK(sc); 274 if (sc->running > 0) { 275 bioq_disksort(&sc->bio_queue, bp); 276 HTIF_BLK_UNLOCK(sc); 277 wakeup(sc); 278 } else { 279 HTIF_BLK_UNLOCK(sc); 280 biofinish(bp, NULL, ENXIO); 281 } 282} 283 284static device_method_t htif_blk_methods[] = { 285 DEVMETHOD(device_probe, htif_blk_probe), 286 DEVMETHOD(device_attach, htif_blk_attach), 287}; 288 289static driver_t htif_blk_driver = { 290 "htif_blk", 291 htif_blk_methods, 292 sizeof(struct htif_blk_softc) 293}; 294 295static devclass_t htif_blk_devclass; 296 297DRIVER_MODULE(htif_blk, htif, htif_blk_driver, htif_blk_devclass, 0, 0); 298