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/bhnd/nvram/bhnd_nvram_iores.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) 2016 Landon Fuller <landonf@FreeBSD.org>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer,
   10  *    without modification.
   11  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
   12  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
   13  *    redistribution must be conditioned upon including a substantially
   14  *    similar Disclaimer requirement for further binary redistribution.
   15  *
   16  * NO WARRANTY
   17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   19  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
   20  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
   21  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
   22  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
   25  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
   27  * THE POSSIBILITY OF SUCH DAMAGES.
   28  */
   29 
   30 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD$");
   32 
   33 #include <sys/param.h>
   34 #include <sys/bus.h>
   35 #include <sys/malloc.h>
   36 #include <sys/rman.h>
   37 
   38 #include <machine/bus.h>
   39 
   40 #include <dev/bhnd/bhnd.h>
   41 
   42 #include "bhnd_nvram_private.h"
   43 
   44 #include "bhnd_nvram_io.h"
   45 #include "bhnd_nvram_iovar.h"
   46 
   47 /**
   48  * BHND resource-backed NVRAM I/O context.
   49  */
   50 struct bhnd_nvram_iores {
   51         struct bhnd_nvram_io     io;            /**< common I/O instance state */
   52         struct bhnd_resource    *res;           /**< backing resource (borrowed ref) */
   53         size_t                   offset;        /**< offset within res */
   54         size_t                   size;          /**< size relative to the base offset */
   55         u_int                    bus_width;     /**< data type byte width to be used
   56                                                      when performing bus operations
   57                                                      on res. (1, 2, or 4 bytes) */
   58 };
   59 
   60 BHND_NVRAM_IOPS_DEFN(iores);
   61 
   62 /**
   63  * Allocate and return a new I/O context backed by a borrowed reference to @p r.
   64  *
   65  * The caller is responsible for deallocating the returned I/O context via
   66  * bhnd_nvram_io_free().
   67  * 
   68  * @param       r               The resource to be mapped by the returned I/O
   69  *                              context.
   70  * @param       offset          Offset 
   71  * @param       bus_width       The required I/O width (1, 2, or 4 bytes) to be
   72  *                              used when reading from @p r.
   73  * 
   74  * @retval      bhnd_nvram_io   success.
   75  * @retval      NULL            if allocation fails, or an invalid argument
   76  *                              is supplied.
   77  */
   78 struct bhnd_nvram_io *
   79 bhnd_nvram_iores_new(struct bhnd_resource *r, bus_size_t offset,
   80     bus_size_t size, u_int bus_width)
   81 {
   82         struct bhnd_nvram_iores *iores;
   83         rman_res_t               r_start, r_size;
   84 
   85         /* Verify the bus width */
   86         switch (bus_width) {
   87         case 1:
   88         case 2:
   89         case 4:
   90                 /* valid */
   91                 break;
   92         default:
   93                 BHND_NV_LOG("invalid bus width %u\n", bus_width);
   94                 return (NULL);
   95         }
   96 
   97         /* offset/size must not exceed our internal size_t representation,
   98          * or our bus_size_t usage (note that BUS_SPACE_MAXSIZE may be less
   99          * than 2^(sizeof(bus_size_t) * 32). */
  100         if (size > SIZE_MAX || offset > SIZE_MAX) {
  101                 BHND_NV_LOG("offset %#jx+%#jx exceeds SIZE_MAX\n",
  102                     (uintmax_t)offset, (uintmax_t)offset);
  103                 return (NULL);
  104         }
  105 
  106         if (size > BUS_SPACE_MAXSIZE || offset > BUS_SPACE_MAXSIZE)
  107         {
  108                 BHND_NV_LOG("offset %#jx+%#jx exceeds BUS_SPACE_MAXSIZE\n",
  109                     (uintmax_t)offset, (uintmax_t)offset);
  110                 return (NULL);
  111         }
  112 
  113         /* offset/size fall within the resource's mapped range */
  114         r_size = rman_get_size(r->res);
  115         r_start = rman_get_start(r->res);
  116         if (r_size < offset || r_size < size || r_size - size < offset)
  117                 return (NULL);
  118 
  119         /* offset/size must be bus_width aligned  */
  120         if ((r_start + offset) % bus_width != 0) {
  121                 BHND_NV_LOG("base address %#jx+%#jx not aligned to bus width "
  122                     "%u\n", (uintmax_t)r_start, (uintmax_t)offset, bus_width);
  123                 return (NULL);
  124         }
  125 
  126         if (size % bus_width != 0) {
  127                 BHND_NV_LOG("size %#jx not aligned to bus width %u\n",
  128                     (uintmax_t)size, bus_width);
  129                 return (NULL);
  130         }
  131 
  132         /* Allocate and return the I/O context */
  133         iores = malloc(sizeof(*iores), M_BHND_NVRAM, M_WAITOK);
  134         iores->io.iops = &bhnd_nvram_iores_ops;
  135         iores->res = r;
  136         iores->offset = offset;
  137         iores->size = size;
  138         iores->bus_width = bus_width;
  139 
  140         return (&iores->io);
  141 }
  142 
  143 static void
  144 bhnd_nvram_iores_free(struct bhnd_nvram_io *io)
  145 {
  146         free(io, M_BHND_NVRAM);
  147 }
  148 
  149 static size_t
  150 bhnd_nvram_iores_getsize(struct bhnd_nvram_io *io)
  151 {
  152         struct bhnd_nvram_iores *iores = (struct bhnd_nvram_iores *)io;
  153         return (iores->size);
  154 }
  155 
  156 static int
  157 bhnd_nvram_iores_setsize(struct bhnd_nvram_io *io, size_t size)
  158 {
  159         /* unsupported */
  160         return (ENODEV);
  161 }
  162 
  163 static int
  164 bhnd_nvram_iores_read_ptr(struct bhnd_nvram_io *io, size_t offset,
  165     const void **ptr, size_t nbytes, size_t *navail)
  166 {
  167         /* unsupported */
  168         return (ENODEV);
  169 }
  170 
  171 static int
  172 bhnd_nvram_iores_write_ptr(struct bhnd_nvram_io *io, size_t offset,
  173     void **ptr, size_t nbytes, size_t *navail)
  174 {
  175         /* unsupported */
  176         return (ENODEV);
  177 }
  178 
  179 /**
  180  * Validate @p offset and @p nbytes:
  181  * 
  182  * - Verify that @p offset is mapped by the backing resource.
  183  * - If less than @p nbytes are available at @p offset, write the actual number
  184  *   of bytes available to @p nbytes.
  185  * - Verify that @p offset + @p nbytes are correctly aligned.
  186  */
  187 static int
  188 bhnd_nvram_iores_validate_req(struct bhnd_nvram_iores *iores, size_t offset,
  189     size_t *nbytes)
  190 {
  191         /* Verify offset falls within the resource range */
  192         if (offset > iores->size)
  193                 return (ENXIO);
  194 
  195         /* Check for eof */
  196         if (offset == iores->size) {
  197                 *nbytes = 0;
  198                 return (0);
  199         }
  200 
  201         /* Verify offset alignment */
  202         if (offset % iores->bus_width != 0)
  203                 return (EFAULT);
  204 
  205         /* Limit nbytes to available range and verify size alignment */
  206         *nbytes = ummin(*nbytes, iores->size - offset);
  207         if (*nbytes < iores->bus_width && *nbytes % iores->bus_width != 0)
  208                 return (EFAULT);
  209 
  210         return (0);
  211 }
  212 
  213 static int
  214 bhnd_nvram_iores_read(struct bhnd_nvram_io *io, size_t offset, void *buffer,
  215     size_t nbytes)
  216 {
  217         struct bhnd_nvram_iores *iores;
  218         bus_size_t               r_offset;
  219         size_t                   navail;
  220         int                      error;
  221 
  222         iores = (struct bhnd_nvram_iores *)io;
  223 
  224         /* Validate the request and determine the actual number of readable
  225          * bytes */
  226         navail = nbytes;
  227         if ((error = bhnd_nvram_iores_validate_req(iores, offset, &navail)))
  228                 return (error);
  229 
  230         /* At least nbytes must be readable */
  231         if (navail < nbytes)
  232                 return (ENXIO);
  233 
  234         /* Handle zero length read */
  235         if (nbytes == 0)
  236                 return (0);
  237 
  238         /* Determine actual resource offset and perform the read */
  239         r_offset = iores->offset + offset;
  240         switch (iores->bus_width) {
  241         case 1:
  242                 bhnd_bus_read_region_stream_1(iores->res, r_offset, buffer,
  243                     nbytes);
  244                 break;
  245         case 2:
  246                 bhnd_bus_read_region_stream_2(iores->res, r_offset, buffer,
  247                     nbytes / 2);
  248                 break;
  249         case 4:
  250                 bhnd_bus_read_region_stream_4(iores->res, r_offset, buffer,
  251                     nbytes / 4);
  252                 break;
  253         default:
  254                 panic("unreachable!");
  255         }
  256 
  257         return (0);
  258 }
  259 
  260 static int
  261 bhnd_nvram_iores_write(struct bhnd_nvram_io *io, size_t offset,
  262     void *buffer, size_t nbytes)
  263 {
  264         struct bhnd_nvram_iores *iores;
  265         size_t                   navail;
  266         bus_size_t               r_offset;
  267         int                      error;
  268 
  269         iores = (struct bhnd_nvram_iores *)io;
  270 
  271         /* Validate the request and determine the actual number of writable
  272          * bytes */
  273         navail = nbytes;
  274         if ((error = bhnd_nvram_iores_validate_req(iores, offset, &navail)))
  275                 return (error);
  276 
  277         /* At least nbytes must be writable */
  278         if (navail < nbytes)
  279                 return (ENXIO);
  280 
  281         /* Determine actual resource offset and perform the write */
  282         r_offset = iores->offset + offset;
  283         switch (iores->bus_width) {
  284         case 1:
  285                 bhnd_bus_write_region_stream_1(iores->res, r_offset, buffer,
  286                     nbytes);
  287                 break;
  288         case 2:
  289                 bhnd_bus_write_region_stream_2(iores->res, r_offset, buffer,
  290                     nbytes / 2);
  291                 break;
  292         case 4:
  293                 bhnd_bus_write_region_stream_4(iores->res, r_offset, buffer,
  294                     nbytes / 4);
  295                 break;
  296         default:
  297                 panic("unreachable!");
  298         }
  299 
  300         return (0);
  301 }

Cache object: d62f64b330e802ea3068e0fe627f999b


[ 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.