Path: blob/main/sys/dev/bhnd/nvram/bhnd_nvram_iores.c
39536 views
/*-1* Copyright (c) 2016 Landon Fuller <[email protected]>2* All rights reserved.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer,9* without modification.10* 2. Redistributions in binary form must reproduce at minimum a disclaimer11* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any12* redistribution must be conditioned upon including a substantially13* similar Disclaimer requirement for further binary redistribution.14*15* NO WARRANTY16* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS17* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT18* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY19* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL20* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,21* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF22* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS23* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER24* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)25* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF26* THE POSSIBILITY OF SUCH DAMAGES.27*/2829#include <sys/param.h>30#include <sys/bus.h>31#include <sys/malloc.h>32#include <sys/rman.h>3334#include <machine/bus.h>3536#include <dev/bhnd/bhnd.h>3738#include "bhnd_nvram_private.h"3940#include "bhnd_nvram_io.h"41#include "bhnd_nvram_iovar.h"4243/**44* BHND resource-backed NVRAM I/O context.45*/46struct bhnd_nvram_iores {47struct bhnd_nvram_io io; /**< common I/O instance state */48struct bhnd_resource *res; /**< backing resource (borrowed ref) */49size_t offset; /**< offset within res */50size_t size; /**< size relative to the base offset */51u_int bus_width; /**< data type byte width to be used52when performing bus operations53on res. (1, 2, or 4 bytes) */54};5556BHND_NVRAM_IOPS_DEFN(iores);5758/**59* Allocate and return a new I/O context backed by a borrowed reference to @p r.60*61* The caller is responsible for deallocating the returned I/O context via62* bhnd_nvram_io_free().63*64* @param r The resource to be mapped by the returned I/O65* context.66* @param offset Offset67* @param bus_width The required I/O width (1, 2, or 4 bytes) to be68* used when reading from @p r.69*70* @retval bhnd_nvram_io success.71* @retval NULL if allocation fails, or an invalid argument72* is supplied.73*/74struct bhnd_nvram_io *75bhnd_nvram_iores_new(struct bhnd_resource *r, bus_size_t offset,76bus_size_t size, u_int bus_width)77{78struct bhnd_nvram_iores *iores;79rman_res_t r_start, r_size;8081/* Verify the bus width */82switch (bus_width) {83case 1:84case 2:85case 4:86/* valid */87break;88default:89BHND_NV_LOG("invalid bus width %u\n", bus_width);90return (NULL);91}9293/* offset/size must not exceed our internal size_t representation,94* or our bus_size_t usage (note that BUS_SPACE_MAXSIZE may be less95* than 2^(sizeof(bus_size_t) * 32). */96if (size > SIZE_MAX || offset > SIZE_MAX) {97BHND_NV_LOG("offset %#jx+%#jx exceeds SIZE_MAX\n",98(uintmax_t)offset, (uintmax_t)offset);99return (NULL);100}101102if (size > BUS_SPACE_MAXSIZE || offset > BUS_SPACE_MAXSIZE)103{104BHND_NV_LOG("offset %#jx+%#jx exceeds BUS_SPACE_MAXSIZE\n",105(uintmax_t)offset, (uintmax_t)offset);106return (NULL);107}108109/* offset/size fall within the resource's mapped range */110r_size = rman_get_size(r->res);111r_start = rman_get_start(r->res);112if (r_size < offset || r_size < size || r_size - size < offset)113return (NULL);114115/* offset/size must be bus_width aligned */116if ((r_start + offset) % bus_width != 0) {117BHND_NV_LOG("base address %#jx+%#jx not aligned to bus width "118"%u\n", (uintmax_t)r_start, (uintmax_t)offset, bus_width);119return (NULL);120}121122if (size % bus_width != 0) {123BHND_NV_LOG("size %#jx not aligned to bus width %u\n",124(uintmax_t)size, bus_width);125return (NULL);126}127128/* Allocate and return the I/O context */129iores = malloc(sizeof(*iores), M_BHND_NVRAM, M_WAITOK);130iores->io.iops = &bhnd_nvram_iores_ops;131iores->res = r;132iores->offset = offset;133iores->size = size;134iores->bus_width = bus_width;135136return (&iores->io);137}138139static void140bhnd_nvram_iores_free(struct bhnd_nvram_io *io)141{142free(io, M_BHND_NVRAM);143}144145static size_t146bhnd_nvram_iores_getsize(struct bhnd_nvram_io *io)147{148struct bhnd_nvram_iores *iores = (struct bhnd_nvram_iores *)io;149return (iores->size);150}151152static int153bhnd_nvram_iores_setsize(struct bhnd_nvram_io *io, size_t size)154{155/* unsupported */156return (ENODEV);157}158159static int160bhnd_nvram_iores_read_ptr(struct bhnd_nvram_io *io, size_t offset,161const void **ptr, size_t nbytes, size_t *navail)162{163/* unsupported */164return (ENODEV);165}166167static int168bhnd_nvram_iores_write_ptr(struct bhnd_nvram_io *io, size_t offset,169void **ptr, size_t nbytes, size_t *navail)170{171/* unsupported */172return (ENODEV);173}174175/**176* Validate @p offset and @p nbytes:177*178* - Verify that @p offset is mapped by the backing resource.179* - If less than @p nbytes are available at @p offset, write the actual number180* of bytes available to @p nbytes.181* - Verify that @p offset + @p nbytes are correctly aligned.182*/183static int184bhnd_nvram_iores_validate_req(struct bhnd_nvram_iores *iores, size_t offset,185size_t *nbytes)186{187/* Verify offset falls within the resource range */188if (offset > iores->size)189return (ENXIO);190191/* Check for eof */192if (offset == iores->size) {193*nbytes = 0;194return (0);195}196197/* Verify offset alignment */198if (offset % iores->bus_width != 0)199return (EFAULT);200201/* Limit nbytes to available range and verify size alignment */202*nbytes = ummin(*nbytes, iores->size - offset);203if (*nbytes < iores->bus_width && *nbytes % iores->bus_width != 0)204return (EFAULT);205206return (0);207}208209static int210bhnd_nvram_iores_read(struct bhnd_nvram_io *io, size_t offset, void *buffer,211size_t nbytes)212{213struct bhnd_nvram_iores *iores;214bus_size_t r_offset;215size_t navail;216int error;217218iores = (struct bhnd_nvram_iores *)io;219220/* Validate the request and determine the actual number of readable221* bytes */222navail = nbytes;223if ((error = bhnd_nvram_iores_validate_req(iores, offset, &navail)))224return (error);225226/* At least nbytes must be readable */227if (navail < nbytes)228return (ENXIO);229230/* Handle zero length read */231if (nbytes == 0)232return (0);233234/* Determine actual resource offset and perform the read */235r_offset = iores->offset + offset;236switch (iores->bus_width) {237case 1:238bhnd_bus_read_region_stream_1(iores->res, r_offset, buffer,239nbytes);240break;241case 2:242bhnd_bus_read_region_stream_2(iores->res, r_offset, buffer,243nbytes / 2);244break;245case 4:246bhnd_bus_read_region_stream_4(iores->res, r_offset, buffer,247nbytes / 4);248break;249default:250panic("unreachable!");251}252253return (0);254}255256static int257bhnd_nvram_iores_write(struct bhnd_nvram_io *io, size_t offset,258void *buffer, size_t nbytes)259{260struct bhnd_nvram_iores *iores;261size_t navail;262bus_size_t r_offset;263int error;264265iores = (struct bhnd_nvram_iores *)io;266267/* Validate the request and determine the actual number of writable268* bytes */269navail = nbytes;270if ((error = bhnd_nvram_iores_validate_req(iores, offset, &navail)))271return (error);272273/* At least nbytes must be writable */274if (navail < nbytes)275return (ENXIO);276277/* Determine actual resource offset and perform the write */278r_offset = iores->offset + offset;279switch (iores->bus_width) {280case 1:281bhnd_bus_write_region_stream_1(iores->res, r_offset, buffer,282nbytes);283break;284case 2:285bhnd_bus_write_region_stream_2(iores->res, r_offset, buffer,286nbytes / 2);287break;288case 4:289bhnd_bus_write_region_stream_4(iores->res, r_offset, buffer,290nbytes / 4);291break;292default:293panic("unreachable!");294}295296return (0);297}298299300