The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/cfi/cfi_dev.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2007, Juniper Networks, Inc.
    3  * Copyright (c) 2012-2013, SRI International
    4  * All rights reserved.
    5  *
    6  * Portions of this software were developed by SRI International and the
    7  * University of Cambridge Computer Laboratory under DARPA/AFRL contract
    8  * (FA8750-10-C-0237) ("CTSRD"), as part of the DARPA CRASH research
    9  * programme.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  * 3. Neither the name of the author nor the names of any co-contributors
   20  *    may be used to endorse or promote products derived from this software
   21  *    without specific prior written permission.
   22  *
   23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   24  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   25  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   26  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   30  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   31  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   33  * SUCH DAMAGE.
   34  */
   35 
   36 #include <sys/cdefs.h>
   37 __FBSDID("$FreeBSD: releng/10.3/sys/dev/cfi/cfi_dev.c 255207 2013-09-04 17:19:21Z brooks $");
   38 
   39 #include "opt_cfi.h"
   40 
   41 #include <sys/param.h>
   42 #include <sys/systm.h>
   43 #include <sys/bus.h>
   44 #include <sys/conf.h>
   45 #include <sys/ioccom.h>
   46 #include <sys/kernel.h>
   47 #include <sys/malloc.h>   
   48 #include <sys/proc.h>
   49 #include <sys/sysctl.h>
   50 #include <sys/types.h>
   51 #include <sys/uio.h>
   52 
   53 #include <sys/cfictl.h>
   54 
   55 #include <machine/atomic.h>
   56 #include <machine/bus.h>
   57 
   58 #include <dev/cfi/cfi_var.h>
   59 
   60 static d_open_t cfi_devopen;
   61 static d_close_t cfi_devclose;
   62 static d_read_t cfi_devread;
   63 static d_write_t cfi_devwrite;
   64 static d_ioctl_t cfi_devioctl;
   65 
   66 struct cdevsw cfi_cdevsw = {
   67         .d_version      =       D_VERSION,
   68         .d_flags        =       0,
   69         .d_name         =       cfi_driver_name,
   70         .d_open         =       cfi_devopen,
   71         .d_close        =       cfi_devclose,
   72         .d_read         =       cfi_devread,
   73         .d_write        =       cfi_devwrite,
   74         .d_ioctl        =       cfi_devioctl,
   75 };
   76 
   77 /*
   78  * Begin writing into a new block/sector.  We read the sector into
   79  * memory and keep updating that, until we move into another sector
   80  * or the process stops writing. At that time we write the whole
   81  * sector to flash (see cfi_block_finish).  To avoid unneeded erase
   82  * cycles, keep a pristine copy of the sector on hand.
   83  */
   84 int
   85 cfi_block_start(struct cfi_softc *sc, u_int ofs)
   86 {
   87         union {
   88                 uint8_t         *x8;
   89                 uint16_t        *x16;
   90                 uint32_t        *x32;
   91         } ptr;
   92         u_int rofs, rsz;
   93         uint32_t val;
   94         int r;
   95 
   96         rofs = 0;
   97         for (r = 0; r < sc->sc_regions; r++) {
   98                 rsz = sc->sc_region[r].r_blocks * sc->sc_region[r].r_blksz;
   99                 if (ofs < rofs + rsz)
  100                         break;
  101                 rofs += rsz;
  102         }
  103         if (r == sc->sc_regions)
  104                 return (EFAULT);
  105 
  106         sc->sc_wrbufsz = sc->sc_region[r].r_blksz;
  107         sc->sc_wrbuf = malloc(sc->sc_wrbufsz, M_TEMP, M_WAITOK);
  108         sc->sc_wrofs = ofs - (ofs - rofs) % sc->sc_wrbufsz;
  109 
  110         /* Read the block from flash for byte-serving. */
  111         ptr.x8 = sc->sc_wrbuf;
  112         for (r = 0; r < sc->sc_wrbufsz; r += sc->sc_width) {
  113                 val = cfi_read_raw(sc, sc->sc_wrofs + r);
  114                 switch (sc->sc_width) {
  115                 case 1:
  116                         *(ptr.x8)++ = val;
  117                         break;
  118                 case 2:
  119                         *(ptr.x16)++ = val;
  120                         break;
  121                 case 4:
  122                         *(ptr.x32)++ = val;
  123                         break;
  124                 }
  125         }
  126         sc->sc_wrbufcpy = malloc(sc->sc_wrbufsz, M_TEMP, M_WAITOK);
  127         memcpy(sc->sc_wrbufcpy, sc->sc_wrbuf, sc->sc_wrbufsz);
  128         sc->sc_writing = 1;
  129         return (0);
  130 }
  131 
  132 /*
  133  * Finish updating the current block/sector by writing the compound
  134  * set of changes to the flash.
  135  */
  136 int
  137 cfi_block_finish(struct cfi_softc *sc)
  138 {
  139         int error;
  140 
  141         error = cfi_write_block(sc);
  142         free(sc->sc_wrbuf, M_TEMP);
  143         free(sc->sc_wrbufcpy, M_TEMP);
  144         sc->sc_wrbuf = NULL;
  145         sc->sc_wrbufsz = 0;
  146         sc->sc_wrofs = 0;
  147         sc->sc_writing = 0;
  148         return (error);
  149 }
  150 
  151 static int
  152 cfi_devopen(struct cdev *dev, int oflags, int devtype, struct thread *td)
  153 {
  154         struct cfi_softc *sc;
  155 
  156         sc = dev->si_drv1;
  157         /* We allow only 1 open. */
  158         if (!atomic_cmpset_acq_ptr((uintptr_t *)&sc->sc_opened,
  159             (uintptr_t)NULL, (uintptr_t)td->td_proc))
  160                 return (EBUSY);
  161         return (0);
  162 }
  163 
  164 static int
  165 cfi_devclose(struct cdev *dev, int fflag, int devtype, struct thread *td)
  166 {
  167         struct cfi_softc *sc;
  168         int error;
  169 
  170         sc = dev->si_drv1;
  171         /* Sanity. Not really necessary. */
  172         if (sc->sc_opened != td->td_proc)
  173                 return (ENXIO);
  174 
  175         error = (sc->sc_writing) ? cfi_block_finish(sc) : 0;
  176         sc->sc_opened = NULL;
  177         return (error);
  178 }
  179 
  180 static int
  181 cfi_devread(struct cdev *dev, struct uio *uio, int ioflag)
  182 {
  183         union {
  184                 uint8_t         x8[4];
  185                 uint16_t        x16[2];
  186                 uint32_t        x32[1];
  187         } buf;
  188         struct cfi_softc *sc;
  189         u_int ofs;
  190         uint32_t val;
  191         int error;
  192 
  193         sc = dev->si_drv1;
  194 
  195         error = (sc->sc_writing) ? cfi_block_finish(sc) : 0;
  196         if (!error)
  197                 error = (uio->uio_offset > sc->sc_size) ? EIO : 0;
  198 
  199         while (error == 0 && uio->uio_resid > 0 &&
  200             uio->uio_offset < sc->sc_size) {
  201                 ofs = uio->uio_offset;
  202                 val = cfi_read_raw(sc, ofs);
  203                 switch (sc->sc_width) {
  204                 case 1:
  205                         buf.x8[0] = val;
  206                         break;
  207                 case 2:
  208                         buf.x16[0] = val;
  209                         break;
  210                 case 4:
  211                         buf.x32[0] = val;
  212                         break;
  213                 }
  214                 ofs &= sc->sc_width - 1;
  215                 error = uiomove(buf.x8 + ofs,
  216                     MIN(uio->uio_resid, sc->sc_width - ofs), uio);
  217         }
  218         return (error);
  219 }
  220 
  221 static int
  222 cfi_devwrite(struct cdev *dev, struct uio *uio, int ioflag)
  223 {
  224         struct cfi_softc *sc;
  225         u_int ofs, top;
  226         int error;
  227 
  228         sc = dev->si_drv1;
  229 
  230         error = (uio->uio_offset > sc->sc_size) ? EIO : 0;
  231         while (error == 0 && uio->uio_resid > 0 &&
  232             uio->uio_offset < sc->sc_size) {
  233                 ofs = uio->uio_offset;
  234 
  235                 /*
  236                  * Finish the current block if we're about to write
  237                  * to a different block.
  238                  */
  239                 if (sc->sc_writing) {
  240                         top = sc->sc_wrofs + sc->sc_wrbufsz;
  241                         if (ofs < sc->sc_wrofs || ofs >= top)
  242                                 cfi_block_finish(sc);
  243                 }
  244 
  245                 /* Start writing to a (new) block if applicable. */
  246                 if (!sc->sc_writing) {
  247                         error = cfi_block_start(sc, uio->uio_offset);
  248                         if (error)
  249                                 break;
  250                 }
  251 
  252                 top = sc->sc_wrofs + sc->sc_wrbufsz;
  253                 error = uiomove(sc->sc_wrbuf + ofs - sc->sc_wrofs,
  254                     MIN(top - ofs, uio->uio_resid), uio);
  255         }
  256         return (error);
  257 }
  258 
  259 static int
  260 cfi_devioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
  261     struct thread *td)
  262 {
  263         struct cfi_softc *sc;
  264         struct cfiocqry *rq;
  265         int error;
  266         u_char val;
  267 
  268         sc = dev->si_drv1;
  269         error = 0;
  270 
  271         switch (cmd) {
  272         case CFIOCQRY:
  273                 if (sc->sc_writing) {
  274                         error = cfi_block_finish(sc);
  275                         if (error)
  276                                 break;
  277                 }
  278                 rq = (struct cfiocqry *)data;
  279                 if (rq->offset >= sc->sc_size / sc->sc_width)
  280                         return (ESPIPE);
  281                 if (rq->offset + rq->count > sc->sc_size / sc->sc_width)
  282                         return (ENOSPC);
  283 
  284                 while (!error && rq->count--) {
  285                         val = cfi_read_qry(sc, rq->offset++);
  286                         error = copyout(&val, rq->buffer++, 1);
  287                 }
  288                 break;
  289 #ifdef CFI_SUPPORT_STRATAFLASH
  290         case CFIOCGFACTORYPR:
  291                 error = cfi_intel_get_factory_pr(sc, (uint64_t *)data);
  292                 break;
  293         case CFIOCGOEMPR:
  294                 error = cfi_intel_get_oem_pr(sc, (uint64_t *)data);
  295                 break;
  296         case CFIOCSOEMPR:
  297                 error = cfi_intel_set_oem_pr(sc, *(uint64_t *)data);
  298                 break;
  299         case CFIOCGPLR:
  300                 error = cfi_intel_get_plr(sc, (uint32_t *)data);
  301                 break;
  302         case CFIOCSPLR:
  303                 error = cfi_intel_set_plr(sc);
  304                 break;
  305 #endif /* CFI_SUPPORT_STRATAFLASH */
  306         default:
  307                 error = ENOIOCTL;
  308                 break;
  309         }
  310         return (error);
  311 }

Cache object: 335ff6be04c356e308d5ec16361ce749


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.