1 1.7 andvar /* $NetBSD: flash_io.c,v 1.7 2025/01/08 11:39:50 andvar Exp $ */ 2 1.1 ahoka 3 1.1 ahoka /*- 4 1.1 ahoka * Copyright (c) 2011 Department of Software Engineering, 5 1.1 ahoka * University of Szeged, Hungary 6 1.1 ahoka * Copyright (c) 2011 Adam Hoka <ahoka (at) NetBSD.org> 7 1.1 ahoka * All rights reserved. 8 1.1 ahoka * 9 1.1 ahoka * This code is derived from software contributed to The NetBSD Foundation 10 1.1 ahoka * by the Department of Software Engineering, University of Szeged, Hungary 11 1.1 ahoka * 12 1.1 ahoka * Redistribution and use in source and binary forms, with or without 13 1.1 ahoka * modification, are permitted provided that the following conditions 14 1.1 ahoka * are met: 15 1.1 ahoka * 1. Redistributions of source code must retain the above copyright 16 1.1 ahoka * notice, this list of conditions and the following disclaimer. 17 1.1 ahoka * 2. Redistributions in binary form must reproduce the above copyright 18 1.1 ahoka * notice, this list of conditions and the following disclaimer in the 19 1.1 ahoka * documentation and/or other materials provided with the distribution. 20 1.1 ahoka * 21 1.1 ahoka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 1.1 ahoka * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 1.1 ahoka * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 1.1 ahoka * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 1.1 ahoka * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26 1.1 ahoka * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27 1.1 ahoka * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28 1.1 ahoka * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 1.1 ahoka * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 1.1 ahoka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 1.1 ahoka * SUCH DAMAGE. 32 1.1 ahoka */ 33 1.1 ahoka 34 1.1 ahoka #include <sys/cdefs.h> 35 1.7 andvar __KERNEL_RCSID(0, "$NetBSD: flash_io.c,v 1.7 2025/01/08 11:39:50 andvar Exp $"); 36 1.1 ahoka 37 1.1 ahoka #include <sys/param.h> 38 1.1 ahoka #include <sys/buf.h> 39 1.1 ahoka #include <sys/bufq.h> 40 1.1 ahoka #include <sys/kernel.h> 41 1.1 ahoka #include <sys/kmem.h> 42 1.1 ahoka #include <sys/kthread.h> 43 1.1 ahoka #include <sys/mutex.h> 44 1.1 ahoka #include <sys/sysctl.h> 45 1.1 ahoka 46 1.1 ahoka #include <dev/flash/flash.h> 47 1.1 ahoka #include <dev/flash/flash_io.h> 48 1.1 ahoka 49 1.1 ahoka #ifdef FLASH_DEBUG 50 1.1 ahoka extern int flashdebug; 51 1.1 ahoka #endif 52 1.1 ahoka 53 1.1 ahoka int flash_cachesync_timeout = 1; 54 1.1 ahoka int flash_cachesync_nodenum; 55 1.1 ahoka 56 1.1 ahoka void flash_io_read(struct flash_io *, struct buf *); 57 1.1 ahoka void flash_io_write(struct flash_io *, struct buf *); 58 1.1 ahoka void flash_io_done(struct flash_io *, struct buf *, int); 59 1.1 ahoka int flash_io_cache_write(struct flash_io *, flash_addr_t, struct buf *); 60 1.1 ahoka void flash_io_cache_sync(struct flash_io *); 61 1.1 ahoka 62 1.1 ahoka static int 63 1.1 ahoka flash_timestamp_diff(struct bintime *bt, struct bintime *b2) 64 1.1 ahoka { 65 1.1 ahoka struct bintime b1 = *bt; 66 1.1 ahoka struct timeval tv; 67 1.1 ahoka 68 1.1 ahoka bintime_sub(&b1, b2); 69 1.1 ahoka bintime2timeval(&b1, &tv); 70 1.1 ahoka 71 1.1 ahoka return tvtohz(&tv); 72 1.1 ahoka } 73 1.1 ahoka 74 1.1 ahoka static flash_addr_t 75 1.1 ahoka flash_io_getblock(struct flash_io *fio, struct buf *bp) 76 1.1 ahoka { 77 1.1 ahoka flash_off_t block, last; 78 1.1 ahoka 79 1.1 ahoka /* get block number of first byte */ 80 1.1 ahoka block = bp->b_rawblkno * DEV_BSIZE / fio->fio_if->erasesize; 81 1.1 ahoka 82 1.1 ahoka /* block of the last bite */ 83 1.1 ahoka last = (bp->b_rawblkno * DEV_BSIZE + bp->b_resid - 1) 84 1.1 ahoka / fio->fio_if->erasesize; 85 1.1 ahoka 86 1.6 gutterid /* spans through multiple blocks, needs special handling */ 87 1.1 ahoka if (last != block) { 88 1.1 ahoka printf("0x%jx -> 0x%jx\n", 89 1.1 ahoka bp->b_rawblkno * DEV_BSIZE, 90 1.1 ahoka bp->b_rawblkno * DEV_BSIZE + bp->b_resid - 1); 91 1.1 ahoka panic("TODO: multiple block write. last: %jd, current: %jd", 92 1.1 ahoka (intmax_t )last, (intmax_t )block); 93 1.1 ahoka } 94 1.1 ahoka 95 1.1 ahoka return block; 96 1.1 ahoka } 97 1.1 ahoka 98 1.1 ahoka int 99 1.3 cliff flash_sync_thread_init(struct flash_io *fio, device_t dev, 100 1.3 cliff struct flash_interface *flash_if) 101 1.1 ahoka { 102 1.1 ahoka int error; 103 1.1 ahoka 104 1.1 ahoka FLDPRINTF(("starting flash io thread\n")); 105 1.1 ahoka 106 1.3 cliff fio->fio_dev = dev; 107 1.1 ahoka fio->fio_if = flash_if; 108 1.1 ahoka 109 1.1 ahoka fio->fio_data = kmem_alloc(fio->fio_if->erasesize, KM_SLEEP); 110 1.1 ahoka 111 1.1 ahoka mutex_init(&fio->fio_lock, MUTEX_DEFAULT, IPL_NONE); 112 1.1 ahoka cv_init(&fio->fio_cv, "flashcv"); 113 1.1 ahoka 114 1.1 ahoka error = bufq_alloc(&fio->fio_bufq, "fcfs", BUFQ_SORT_RAWBLOCK); 115 1.1 ahoka if (error) 116 1.1 ahoka goto err_bufq; 117 1.1 ahoka 118 1.1 ahoka fio->fio_exiting = false; 119 1.1 ahoka fio->fio_write_pending = false; 120 1.1 ahoka 121 1.1 ahoka /* arrange to allocate the kthread */ 122 1.4 rmind error = kthread_create(PRI_NONE, KTHREAD_MUSTJOIN | KTHREAD_MPSAFE, 123 1.1 ahoka NULL, flash_sync_thread, fio, &fio->fio_thread, "flashio"); 124 1.1 ahoka 125 1.1 ahoka if (!error) 126 1.1 ahoka return 0; 127 1.1 ahoka 128 1.1 ahoka bufq_free(fio->fio_bufq); 129 1.1 ahoka err_bufq: 130 1.1 ahoka cv_destroy(&fio->fio_cv); 131 1.1 ahoka mutex_destroy(&fio->fio_lock); 132 1.1 ahoka kmem_free(fio->fio_data, fio->fio_if->erasesize); 133 1.1 ahoka 134 1.1 ahoka return error; 135 1.1 ahoka } 136 1.1 ahoka 137 1.1 ahoka void 138 1.1 ahoka flash_sync_thread_destroy(struct flash_io *fio) 139 1.1 ahoka { 140 1.1 ahoka FLDPRINTF(("stopping flash io thread\n")); 141 1.1 ahoka 142 1.1 ahoka mutex_enter(&fio->fio_lock); 143 1.1 ahoka 144 1.1 ahoka fio->fio_exiting = true; 145 1.1 ahoka cv_broadcast(&fio->fio_cv); 146 1.1 ahoka 147 1.1 ahoka mutex_exit(&fio->fio_lock); 148 1.1 ahoka 149 1.1 ahoka kthread_join(fio->fio_thread); 150 1.1 ahoka 151 1.1 ahoka kmem_free(fio->fio_data, fio->fio_if->erasesize); 152 1.1 ahoka bufq_free(fio->fio_bufq); 153 1.1 ahoka mutex_destroy(&fio->fio_lock); 154 1.1 ahoka cv_destroy(&fio->fio_cv); 155 1.1 ahoka } 156 1.1 ahoka 157 1.1 ahoka int 158 1.1 ahoka flash_io_submit(struct flash_io *fio, struct buf *bp) 159 1.1 ahoka { 160 1.1 ahoka FLDPRINTF(("submitting job to flash io thread: %p\n", bp)); 161 1.1 ahoka 162 1.1 ahoka if (__predict_false(fio->fio_exiting)) { 163 1.1 ahoka flash_io_done(fio, bp, ENODEV); 164 1.1 ahoka return ENODEV; 165 1.1 ahoka } 166 1.1 ahoka 167 1.1 ahoka if (BUF_ISREAD(bp)) { 168 1.1 ahoka FLDPRINTF(("we have a read job\n")); 169 1.1 ahoka 170 1.1 ahoka mutex_enter(&fio->fio_lock); 171 1.1 ahoka if (fio->fio_write_pending) 172 1.1 ahoka flash_io_cache_sync(fio); 173 1.1 ahoka mutex_exit(&fio->fio_lock); 174 1.1 ahoka 175 1.1 ahoka flash_io_read(fio, bp); 176 1.1 ahoka } else { 177 1.1 ahoka FLDPRINTF(("we have a write job\n")); 178 1.1 ahoka 179 1.1 ahoka flash_io_write(fio, bp); 180 1.1 ahoka } 181 1.1 ahoka return 0; 182 1.1 ahoka } 183 1.1 ahoka 184 1.1 ahoka int 185 1.1 ahoka flash_io_cache_write(struct flash_io *fio, flash_addr_t block, struct buf *bp) 186 1.1 ahoka { 187 1.1 ahoka size_t retlen; 188 1.1 ahoka flash_addr_t base, offset; 189 1.1 ahoka int error; 190 1.1 ahoka 191 1.1 ahoka KASSERT(mutex_owned(&fio->fio_lock)); 192 1.1 ahoka KASSERT(fio->fio_if->erasesize != 0); 193 1.1 ahoka 194 1.1 ahoka base = block * fio->fio_if->erasesize; 195 1.1 ahoka offset = bp->b_rawblkno * DEV_BSIZE - base; 196 1.1 ahoka 197 1.1 ahoka FLDPRINTF(("io cache write, offset: %jd\n", (intmax_t )offset)); 198 1.1 ahoka 199 1.1 ahoka if (!fio->fio_write_pending) { 200 1.1 ahoka fio->fio_block = block; 201 1.1 ahoka /* 202 1.1 ahoka * fill the cache with data from flash, 203 1.1 ahoka * so we dont have to bother with gaps later 204 1.1 ahoka */ 205 1.1 ahoka FLDPRINTF(("filling buffer from offset %ju\n", (uintmax_t)base)); 206 1.1 ahoka error = fio->fio_if->read(fio->fio_dev, 207 1.1 ahoka base, fio->fio_if->erasesize, 208 1.1 ahoka &retlen, fio->fio_data); 209 1.1 ahoka FLDPRINTF(("cache filled\n")); 210 1.1 ahoka 211 1.1 ahoka if (error) 212 1.1 ahoka return error; 213 1.1 ahoka 214 1.1 ahoka fio->fio_write_pending = true; 215 1.1 ahoka /* save creation time for aging */ 216 1.1 ahoka binuptime(&fio->fio_creation); 217 1.1 ahoka } 218 1.1 ahoka /* copy data to cache */ 219 1.1 ahoka memcpy(fio->fio_data + offset, bp->b_data, bp->b_resid); 220 1.1 ahoka bufq_put(fio->fio_bufq, bp); 221 1.1 ahoka 222 1.1 ahoka /* update timestamp */ 223 1.1 ahoka binuptime(&fio->fio_last_write); 224 1.1 ahoka 225 1.1 ahoka return 0; 226 1.1 ahoka } 227 1.1 ahoka 228 1.1 ahoka void 229 1.1 ahoka flash_io_cache_sync(struct flash_io *fio) 230 1.1 ahoka { 231 1.1 ahoka struct flash_erase_instruction ei; 232 1.1 ahoka struct buf *bp; 233 1.1 ahoka size_t retlen; 234 1.1 ahoka flash_addr_t base; 235 1.1 ahoka int error; 236 1.1 ahoka 237 1.1 ahoka KASSERT(mutex_owned(&fio->fio_lock)); 238 1.1 ahoka 239 1.1 ahoka if (!fio->fio_write_pending) { 240 1.1 ahoka FLDPRINTF(("trying to sync with an invalid buffer\n")); 241 1.1 ahoka return; 242 1.1 ahoka } 243 1.1 ahoka 244 1.1 ahoka base = fio->fio_block * fio->fio_if->erasesize; 245 1.1 ahoka 246 1.7 andvar FLDPRINTF(("erasing block at 0x%jx\n", (uintmax_t )base)); 247 1.1 ahoka ei.ei_addr = base; 248 1.1 ahoka ei.ei_len = fio->fio_if->erasesize; 249 1.1 ahoka ei.ei_callback = NULL; 250 1.1 ahoka error = fio->fio_if->erase(fio->fio_dev, &ei); 251 1.1 ahoka 252 1.1 ahoka if (error) { 253 1.1 ahoka aprint_error_dev(fio->fio_dev, "cannot erase flash flash!\n"); 254 1.1 ahoka goto out; 255 1.1 ahoka } 256 1.1 ahoka 257 1.2 ahoka FLDPRINTF(("writing %" PRIu32 " bytes to 0x%jx\n", 258 1.1 ahoka fio->fio_if->erasesize, (uintmax_t )base)); 259 1.1 ahoka 260 1.1 ahoka error = fio->fio_if->write(fio->fio_dev, 261 1.1 ahoka base, fio->fio_if->erasesize, &retlen, fio->fio_data); 262 1.1 ahoka 263 1.1 ahoka if (error || retlen != fio->fio_if->erasesize) { 264 1.1 ahoka aprint_error_dev(fio->fio_dev, "can't sync write cache: %d\n", error); 265 1.1 ahoka goto out; 266 1.1 ahoka } 267 1.1 ahoka 268 1.1 ahoka out: 269 1.1 ahoka while ((bp = bufq_get(fio->fio_bufq)) != NULL) 270 1.1 ahoka flash_io_done(fio, bp, error); 271 1.1 ahoka 272 1.1 ahoka fio->fio_block = -1; 273 1.1 ahoka fio->fio_write_pending = false; 274 1.1 ahoka } 275 1.1 ahoka 276 1.1 ahoka void 277 1.1 ahoka flash_sync_thread(void * arg) 278 1.1 ahoka { 279 1.1 ahoka struct flash_io *fio = arg; 280 1.1 ahoka struct bintime now; 281 1.1 ahoka 282 1.1 ahoka mutex_enter(&fio->fio_lock); 283 1.1 ahoka 284 1.1 ahoka while (!fio->fio_exiting) { 285 1.1 ahoka cv_timedwait_sig(&fio->fio_cv, &fio->fio_lock, hz / 4); 286 1.1 ahoka if (!fio->fio_write_pending) { 287 1.1 ahoka continue; 288 1.1 ahoka } 289 1.1 ahoka /* see if the cache is older than 3 seconds (safety limit), 290 1.1 ahoka * or if we havent touched the cache since more than 1 ms 291 1.1 ahoka */ 292 1.1 ahoka binuptime(&now); 293 1.1 ahoka if (flash_timestamp_diff(&now, &fio->fio_last_write) > hz / 5) { 294 1.1 ahoka FLDPRINTF(("syncing write cache after timeout\n")); 295 1.1 ahoka flash_io_cache_sync(fio); 296 1.1 ahoka } else if (flash_timestamp_diff(&now, &fio->fio_creation) 297 1.1 ahoka > 3 * hz) { 298 1.1 ahoka aprint_error_dev(fio->fio_dev, 299 1.1 ahoka "syncing write cache after 3 sec timeout!\n"); 300 1.1 ahoka flash_io_cache_sync(fio); 301 1.1 ahoka } 302 1.1 ahoka } 303 1.1 ahoka 304 1.1 ahoka mutex_exit(&fio->fio_lock); 305 1.1 ahoka 306 1.1 ahoka kthread_exit(0); 307 1.1 ahoka } 308 1.1 ahoka 309 1.1 ahoka void 310 1.1 ahoka flash_io_read(struct flash_io *fio, struct buf *bp) 311 1.1 ahoka { 312 1.1 ahoka size_t retlen; 313 1.1 ahoka flash_addr_t offset; 314 1.1 ahoka int error; 315 1.1 ahoka 316 1.1 ahoka FLDPRINTF(("flash io read\n")); 317 1.1 ahoka 318 1.1 ahoka offset = bp->b_rawblkno * DEV_BSIZE; 319 1.1 ahoka 320 1.1 ahoka error = fio->fio_if->read(fio->fio_dev, offset, bp->b_resid, 321 1.1 ahoka &retlen, bp->b_data); 322 1.1 ahoka 323 1.1 ahoka flash_io_done(fio, bp, error); 324 1.1 ahoka } 325 1.1 ahoka 326 1.1 ahoka void 327 1.1 ahoka flash_io_write(struct flash_io *fio, struct buf *bp) 328 1.1 ahoka { 329 1.1 ahoka flash_addr_t block; 330 1.1 ahoka 331 1.1 ahoka FLDPRINTF(("flash io write\n")); 332 1.1 ahoka 333 1.1 ahoka block = flash_io_getblock(fio, bp); 334 1.1 ahoka FLDPRINTF(("write to block %jd\n", (intmax_t )block)); 335 1.1 ahoka 336 1.1 ahoka mutex_enter(&fio->fio_lock); 337 1.1 ahoka 338 1.1 ahoka if (fio->fio_write_pending && fio->fio_block != block) { 339 1.1 ahoka FLDPRINTF(("writing to new block, syncing caches\n")); 340 1.1 ahoka flash_io_cache_sync(fio); 341 1.1 ahoka } 342 1.1 ahoka 343 1.1 ahoka flash_io_cache_write(fio, block, bp); 344 1.1 ahoka 345 1.1 ahoka mutex_exit(&fio->fio_lock); 346 1.1 ahoka } 347 1.1 ahoka 348 1.1 ahoka void 349 1.1 ahoka flash_io_done(struct flash_io *fio, struct buf *bp, int error) 350 1.1 ahoka { 351 1.1 ahoka FLDPRINTF(("io done: %p\n", bp)); 352 1.1 ahoka 353 1.1 ahoka if (error == 0) 354 1.1 ahoka bp->b_resid = 0; 355 1.1 ahoka 356 1.1 ahoka bp->b_error = error; 357 1.1 ahoka biodone(bp); 358 1.1 ahoka } 359 1.1 ahoka 360 1.1 ahoka static int 361 1.1 ahoka sysctl_flash_verify(SYSCTLFN_ARGS) 362 1.1 ahoka { 363 1.1 ahoka int error, t; 364 1.1 ahoka struct sysctlnode node; 365 1.1 ahoka 366 1.1 ahoka node = *rnode; 367 1.1 ahoka t = *(int *)rnode->sysctl_data; 368 1.1 ahoka node.sysctl_data = &t; 369 1.1 ahoka error = sysctl_lookup(SYSCTLFN_CALL(&node)); 370 1.1 ahoka if (error || newp == NULL) 371 1.1 ahoka return error; 372 1.1 ahoka 373 1.1 ahoka if (node.sysctl_num == flash_cachesync_nodenum) { 374 1.1 ahoka if (t <= 0 || t > 60) 375 1.1 ahoka return EINVAL; 376 1.1 ahoka } else { 377 1.1 ahoka return EINVAL; 378 1.1 ahoka } 379 1.1 ahoka 380 1.1 ahoka *(int *)rnode->sysctl_data = t; 381 1.1 ahoka 382 1.1 ahoka return 0; 383 1.1 ahoka } 384 1.1 ahoka 385 1.1 ahoka SYSCTL_SETUP(sysctl_flash, "sysctl flash subtree setup") 386 1.1 ahoka { 387 1.1 ahoka int rc, flash_root_num; 388 1.1 ahoka const struct sysctlnode *node; 389 1.1 ahoka 390 1.1 ahoka if ((rc = sysctl_createv(clog, 0, NULL, &node, 391 1.1 ahoka CTLFLAG_PERMANENT, CTLTYPE_NODE, "flash", 392 1.1 ahoka SYSCTL_DESCR("FLASH driver controls"), 393 1.1 ahoka NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL)) != 0) { 394 1.1 ahoka goto error; 395 1.1 ahoka } 396 1.1 ahoka 397 1.1 ahoka flash_root_num = node->sysctl_num; 398 1.1 ahoka 399 1.1 ahoka if ((rc = sysctl_createv(clog, 0, NULL, &node, 400 1.1 ahoka CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 401 1.1 ahoka CTLTYPE_INT, "cache_sync_timeout", 402 1.1 ahoka SYSCTL_DESCR("FLASH write cache sync timeout in seconds"), 403 1.1 ahoka sysctl_flash_verify, 0, &flash_cachesync_timeout, 404 1.1 ahoka 0, CTL_HW, flash_root_num, CTL_CREATE, 405 1.1 ahoka CTL_EOL)) != 0) { 406 1.1 ahoka goto error; 407 1.1 ahoka } 408 1.1 ahoka 409 1.1 ahoka flash_cachesync_nodenum = node->sysctl_num; 410 1.1 ahoka 411 1.1 ahoka return; 412 1.1 ahoka 413 1.1 ahoka error: 414 1.1 ahoka aprint_error("%s: sysctl_createv failed (rc = %d)\n", __func__, rc); 415 1.1 ahoka } 416