1295041Sbr/*- 2295972Sbr * Copyright (c) 2015-2016 Ruslan Bukin <br@bsdpad.com> 3295041Sbr * All rights reserved. 4295041Sbr * 5295041Sbr * Portions of this software were developed by SRI International and the 6295041Sbr * University of Cambridge Computer Laboratory under DARPA/AFRL contract 7295041Sbr * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme. 8295041Sbr * 9295041Sbr * Portions of this software were developed by the University of Cambridge 10295041Sbr * Computer Laboratory as part of the CTSRD Project, with support from the 11295041Sbr * UK Higher Education Innovation Fund (HEIF). 12295041Sbr * 13295041Sbr * Redistribution and use in source and binary forms, with or without 14295041Sbr * modification, are permitted provided that the following conditions 15295041Sbr * are met: 16295041Sbr * 1. Redistributions of source code must retain the above copyright 17295041Sbr * notice, this list of conditions and the following disclaimer. 18295041Sbr * 2. Redistributions in binary form must reproduce the above copyright 19295041Sbr * notice, this list of conditions and the following disclaimer in the 20295041Sbr * documentation and/or other materials provided with the distribution. 21295041Sbr * 22295041Sbr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23295041Sbr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24295041Sbr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25295041Sbr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26295041Sbr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27295041Sbr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28295041Sbr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29295041Sbr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30295041Sbr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31295041Sbr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32295041Sbr * SUCH DAMAGE. 33295041Sbr */ 34295041Sbr 35295041Sbr#include <sys/cdefs.h> 36295041Sbr__FBSDID("$FreeBSD: releng/11.0/sys/riscv/htif/htif_block.c 298476 2016-04-22 15:12:05Z br $"); 37295041Sbr 38295041Sbr#include <sys/param.h> 39295041Sbr#include <sys/systm.h> 40295041Sbr#include <sys/kernel.h> 41295041Sbr#include <sys/kthread.h> 42295041Sbr#include <sys/selinfo.h> 43295041Sbr#include <sys/module.h> 44295041Sbr#include <sys/lock.h> 45295041Sbr#include <sys/mutex.h> 46295041Sbr#include <sys/malloc.h> 47295041Sbr#include <sys/sysctl.h> 48295041Sbr#include <sys/uio.h> 49295041Sbr 50295041Sbr#include <sys/bio.h> 51295041Sbr#include <sys/bus.h> 52295041Sbr#include <sys/conf.h> 53295041Sbr#include <sys/disk.h> 54295041Sbr#include <geom/geom_disk.h> 55295041Sbr 56295041Sbr#include <vm/vm.h> 57295041Sbr#include <vm/pmap.h> 58295041Sbr 59295041Sbr#include <machine/md_var.h> 60295041Sbr#include <machine/bus.h> 61295041Sbr#include <machine/trap.h> 62295041Sbr#include <sys/rman.h> 63295041Sbr 64295041Sbr#include "htif.h" 65295041Sbr 66295041Sbr#define SECTOR_SIZE_SHIFT (9) 67295041Sbr#define SECTOR_SIZE (1 << SECTOR_SIZE_SHIFT) 68295041Sbr 69295041Sbr#define HTIF_BLK_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) 70295041Sbr#define HTIF_BLK_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) 71295041Sbr#define HTIF_BLK_LOCK_INIT(_sc) \ 72295041Sbr mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \ 73295041Sbr "htif_blk", MTX_DEF) 74295041Sbr#define HTIF_BLK_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx); 75295041Sbr#define HTIF_BLK_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED); 76295041Sbr#define HTIF_BLK_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED); 77295041Sbr 78295041Sbrstatic void htif_blk_task(void *arg); 79295041Sbr 80295041Sbrstatic disk_open_t htif_blk_open; 81295041Sbrstatic disk_close_t htif_blk_close; 82295041Sbrstatic disk_strategy_t htif_blk_strategy; 83295041Sbr 84295041Sbrstruct htif_blk_softc { 85295041Sbr device_t dev; 86295041Sbr struct disk *disk; 87295041Sbr struct mtx htif_io_mtx; 88295041Sbr struct mtx sc_mtx; 89295041Sbr struct proc *p; 90295041Sbr struct bio_queue_head bio_queue; 91295041Sbr int running; 92295041Sbr int intr_chan; 93295041Sbr int cmd_done; 94295041Sbr int index; 95295041Sbr uint16_t curtag; 96295041Sbr}; 97295041Sbr 98295041Sbrstruct htif_blk_request { 99295041Sbr uint64_t addr; 100295041Sbr uint64_t offset; /* offset in bytes */ 101295041Sbr uint64_t size; /* length in bytes */ 102295041Sbr uint64_t tag; 103295041Sbr}; 104295041Sbr 105295041Sbrstatic void 106295041Sbrhtif_blk_intr(void *arg, uint64_t entry) 107295041Sbr{ 108295041Sbr struct htif_blk_softc *sc; 109295041Sbr uint64_t devcmd; 110295041Sbr uint64_t data; 111295041Sbr 112295041Sbr sc = arg; 113295041Sbr 114295041Sbr devcmd = HTIF_DEV_CMD(entry); 115295041Sbr data = HTIF_DEV_DATA(entry); 116295041Sbr 117295041Sbr if (sc->curtag == data) { 118298476Sbr wmb(); 119295041Sbr sc->cmd_done = 1; 120295041Sbr wakeup(&sc->intr_chan); 121295972Sbr } else { 122295972Sbr device_printf(sc->dev, "Unexpected tag %d (should be %d)\n", 123295972Sbr data, sc->curtag); 124295041Sbr } 125295041Sbr} 126295041Sbr 127295041Sbrstatic int 128295041Sbrhtif_blk_probe(device_t dev) 129295041Sbr{ 130295041Sbr 131295041Sbr return (0); 132295041Sbr} 133295041Sbr 134295041Sbrstatic int 135295041Sbrhtif_blk_attach(device_t dev) 136295041Sbr{ 137295041Sbr struct htif_blk_softc *sc; 138295041Sbr char prefix[] = " size="; 139295041Sbr char *str; 140295041Sbr long size; 141295041Sbr 142295041Sbr sc = device_get_softc(dev); 143295041Sbr sc->dev = dev; 144295041Sbr 145295041Sbr mtx_init(&sc->htif_io_mtx, device_get_nameunit(dev), "htif_blk", MTX_DEF); 146295041Sbr HTIF_BLK_LOCK_INIT(sc); 147295041Sbr 148295041Sbr str = strstr(htif_get_id(dev), prefix); 149295041Sbr 150295041Sbr size = strtol((str + 6), NULL, 10); 151295041Sbr if (size == 0) { 152295041Sbr return (ENXIO); 153295041Sbr } 154295041Sbr 155295041Sbr sc->index = htif_get_index(dev); 156295041Sbr if (sc->index < 0) 157295041Sbr return (EINVAL); 158295041Sbr htif_setup_intr(sc->index, htif_blk_intr, sc); 159295041Sbr 160295041Sbr sc->disk = disk_alloc(); 161295041Sbr sc->disk->d_drv1 = sc; 162295041Sbr 163295041Sbr sc->disk->d_maxsize = 4096; /* Max transfer */ 164295041Sbr sc->disk->d_name = "htif_blk"; 165295041Sbr sc->disk->d_open = htif_blk_open; 166295041Sbr sc->disk->d_close = htif_blk_close; 167295041Sbr sc->disk->d_strategy = htif_blk_strategy; 168295041Sbr sc->disk->d_unit = 0; 169295041Sbr sc->disk->d_sectorsize = SECTOR_SIZE; 170295041Sbr sc->disk->d_mediasize = size; 171295041Sbr disk_create(sc->disk, DISK_VERSION); 172295041Sbr 173295041Sbr bioq_init(&sc->bio_queue); 174295041Sbr 175295041Sbr sc->running = 1; 176295041Sbr 177295041Sbr kproc_create(&htif_blk_task, sc, &sc->p, 0, 0, "%s: transfer", 178295041Sbr device_get_nameunit(dev)); 179295041Sbr 180295041Sbr return (0); 181295041Sbr} 182295041Sbr 183295041Sbrstatic int 184295041Sbrhtif_blk_open(struct disk *dp) 185295041Sbr{ 186295041Sbr 187295041Sbr return (0); 188295041Sbr} 189295041Sbr 190295041Sbrstatic int 191295041Sbrhtif_blk_close(struct disk *dp) 192295041Sbr{ 193295041Sbr 194295041Sbr return (0); 195295041Sbr} 196295041Sbr 197295041Sbrstatic void 198295041Sbrhtif_blk_task(void *arg) 199295041Sbr{ 200295041Sbr struct htif_blk_request req __aligned(HTIF_ALIGN); 201295041Sbr struct htif_blk_softc *sc; 202298476Sbr uint64_t req_paddr; 203295041Sbr struct bio *bp; 204295041Sbr uint64_t paddr; 205295041Sbr uint64_t cmd; 206295041Sbr int i; 207295041Sbr 208295041Sbr sc = (struct htif_blk_softc *)arg; 209295041Sbr 210295041Sbr while (1) { 211295041Sbr HTIF_BLK_LOCK(sc); 212295041Sbr do { 213295041Sbr bp = bioq_takefirst(&sc->bio_queue); 214295041Sbr if (bp == NULL) 215295041Sbr msleep(sc, &sc->sc_mtx, PRIBIO, "jobqueue", 0); 216295041Sbr } while (bp == NULL); 217295041Sbr HTIF_BLK_UNLOCK(sc); 218295041Sbr 219295041Sbr if (bp->bio_cmd == BIO_READ || bp->bio_cmd == BIO_WRITE) { 220295972Sbr HTIF_BLK_LOCK(sc); 221295972Sbr 222298476Sbr rmb(); 223295041Sbr req.offset = (bp->bio_pblkno * sc->disk->d_sectorsize); 224295041Sbr req.size = bp->bio_bcount; 225295041Sbr paddr = vtophys(bp->bio_data); 226295041Sbr KASSERT(paddr != 0, ("paddr is 0")); 227295041Sbr req.addr = paddr; 228298476Sbr sc->curtag++; 229295041Sbr req.tag = sc->curtag; 230295041Sbr 231295041Sbr cmd = sc->index; 232295041Sbr cmd <<= HTIF_DEV_ID_SHIFT; 233295041Sbr if (bp->bio_cmd == BIO_READ) 234295041Sbr cmd |= (HTIF_CMD_READ << HTIF_CMD_SHIFT); 235295041Sbr else 236295041Sbr cmd |= (HTIF_CMD_WRITE << HTIF_CMD_SHIFT); 237298476Sbr req_paddr = vtophys(&req); 238298476Sbr KASSERT(req_paddr != 0, ("req_paddr is 0")); 239298476Sbr cmd |= req_paddr; 240295041Sbr 241295041Sbr sc->cmd_done = 0; 242295041Sbr htif_command(cmd); 243295041Sbr 244295041Sbr /* Wait for interrupt */ 245295041Sbr i = 0; 246295041Sbr while (sc->cmd_done == 0) { 247295041Sbr msleep(&sc->intr_chan, &sc->sc_mtx, PRIBIO, "intr", hz/2); 248295041Sbr 249295041Sbr if (i++ > 2) { 250295041Sbr /* TODO: try to re-issue operation on timeout ? */ 251295041Sbr bp->bio_error = EIO; 252295041Sbr bp->bio_flags |= BIO_ERROR; 253295041Sbr disk_err(bp, "hard error", -1, 1); 254295041Sbr break; 255295041Sbr } 256295041Sbr } 257295041Sbr HTIF_BLK_UNLOCK(sc); 258295041Sbr 259295041Sbr biodone(bp); 260295041Sbr } else { 261295041Sbr printf("unknown op %d\n", bp->bio_cmd); 262295041Sbr } 263295041Sbr } 264295041Sbr} 265295041Sbr 266295041Sbrstatic void 267295041Sbrhtif_blk_strategy(struct bio *bp) 268295041Sbr{ 269295041Sbr struct htif_blk_softc *sc; 270295041Sbr 271295041Sbr sc = bp->bio_disk->d_drv1; 272295041Sbr 273295041Sbr HTIF_BLK_LOCK(sc); 274295041Sbr if (sc->running > 0) { 275295041Sbr bioq_disksort(&sc->bio_queue, bp); 276295041Sbr HTIF_BLK_UNLOCK(sc); 277295041Sbr wakeup(sc); 278295041Sbr } else { 279295041Sbr HTIF_BLK_UNLOCK(sc); 280295041Sbr biofinish(bp, NULL, ENXIO); 281295041Sbr } 282295041Sbr} 283295041Sbr 284295041Sbrstatic device_method_t htif_blk_methods[] = { 285295041Sbr DEVMETHOD(device_probe, htif_blk_probe), 286295041Sbr DEVMETHOD(device_attach, htif_blk_attach), 287295041Sbr}; 288295041Sbr 289295041Sbrstatic driver_t htif_blk_driver = { 290295041Sbr "htif_blk", 291295041Sbr htif_blk_methods, 292295041Sbr sizeof(struct htif_blk_softc) 293295041Sbr}; 294295041Sbr 295295041Sbrstatic devclass_t htif_blk_devclass; 296295041Sbr 297295041SbrDRIVER_MODULE(htif_blk, htif, htif_blk_driver, htif_blk_devclass, 0, 0); 298