freebsd-src/sys/dev/dpaa2/dpaa2_console.c
Warner Losh fdafd315ad sys: Automated cleanup of cdefs and other formatting
Apply the following automated changes to try to eliminate
no-longer-needed sys/cdefs.h includes as well as now-empty
blank lines in a row.

Remove /^#if.*\n#endif.*\n#include\s+<sys/cdefs.h>.*\n/
Remove /\n+#include\s+<sys/cdefs.h>.*\n+#if.*\n#endif.*\n+/
Remove /\n+#if.*\n#endif.*\n+/
Remove /^#if.*\n#endif.*\n/
Remove /\n+#include\s+<sys/cdefs.h>\n#include\s+<sys/types.h>/
Remove /\n+#include\s+<sys/cdefs.h>\n#include\s+<sys/param.h>/
Remove /\n+#include\s+<sys/cdefs.h>\n#include\s+<sys/capsicum.h>/

Sponsored by:		Netflix
2023-11-26 22:24:00 -07:00

581 lines
14 KiB
C

/*-
* SPDX-License-Identifier: BSD-3-Clause AND BSD-2-Clause
*/
/*
* // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
*
* Freescale DPAA2 Platforms Console Driver
*
* Copyright 2015-2016 Freescale Semiconductor Inc.
* Copyright 2018 NXP
*
* git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/drivers/soc/fsl/dpaa2-console.c#8120bd469f5525da229953c1197f2b826c0109f4
*/
/*
* Copyright (c) 2022-2023 Bjoern A. Zeeb
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Some docs are in:
* - https://www.nxp.com.cn/docs/en/application-note/AN13329.pdf
* - DPAA2UM
* - git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/drivers/soc/fsl/dpaa2-console.c
*/
#include "opt_platform.h"
#ifdef __notyet__
#include "opt_acpi.h"
#endif
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/conf.h>
#include <sys/fcntl.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/rman.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <machine/bus.h>
#include <machine/resource.h>
#ifdef FDT
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
#endif
/* Table 6-1. MC Memory Map */
#define MC_REG_MCFBA 0x20
#define MC_REG_MCFBALR_OFF 0x00
#define MC_REG_MCFBALR_MASK 0xe0000000
#define MC_REG_MCFBAHR_OFF 0x04
#define MC_REG_MCFBAHR_MASK 0x0001ffff
/* Firmware Consoles. */
#define MC_BUFFER_OFFSET 0x01000000
#define MC_BUFFER_SIZE (1024 * 1024 * 16)
#define MC_OFFSET_DELTA MC_BUFFER_OFFSET
#define AIOP_BUFFER_OFFSET 0x06000000
#define AIOP_BUFFER_SIZE (1024 * 1024 * 16)
#define AIOP_OFFSET_DELTA 0
/* MC and AIOP Magic words */
#define MAGIC_MC 0x4d430100
#define MAGIC_AIOP 0X41494f50
#define LOG_HEADER_FLAG_BUFFER_WRAPAROUND \
0x80000000
#define LAST_BYTE(a) \
((a) & ~(LOG_HEADER_FLAG_BUFFER_WRAPAROUND))
struct dpaa2_cons_dev {
struct cdev *cdev;
struct mtx mtx;
size_t offset;
uint32_t magic;
uint32_t hdr_magic;
uint32_t hdr_eobyte;
uint32_t hdr_start;
uint32_t hdr_len;
uoff_t start;
uoff_t end;
uoff_t eod;
uoff_t cur;
bus_space_tag_t bst;
bus_space_handle_t bsh;
vm_size_t size;
};
struct dpaa2_cons_softc {
struct resource *res;
bus_space_tag_t bst;
uint64_t mcfba;
struct dpaa2_cons_dev mc_cd;
struct dpaa2_cons_dev aiop_cd;
};
struct dpaa2_cons_hdr {
uint32_t magic;
uint32_t _reserved;
uint32_t start;
uint32_t len;
uint32_t eobyte;
};
#define DPAA2_MC_READ_4(_sc, _r) bus_read_4((_sc)->res, (_r))
/* Management interface */
static d_open_t dpaa2_cons_open;
static d_close_t dpaa2_cons_close;
static d_read_t dpaa2_cons_read;
static struct cdevsw dpaa2_mc_cons_cdevsw = {
.d_version = D_VERSION,
.d_flags = 0,
.d_open = dpaa2_cons_open,
.d_close = dpaa2_cons_close,
.d_read = dpaa2_cons_read,
.d_name = "fsl_mc_console",
};
static struct cdevsw dpaa2_aiop_cons_cdevsw = {
.d_version = D_VERSION,
.d_flags = 0,
.d_open = dpaa2_cons_open,
.d_close = dpaa2_cons_close,
.d_read = dpaa2_cons_read,
.d_name = "fsl_aiop_console",
};
static size_t
dpaa2_cons_read_bs(struct dpaa2_cons_dev *cd, size_t offset, void *dst, size_t len)
{
size_t count, l;
uint8_t *p;
count = 0;
p = dst;
l = offset % 8;
if (l != 0) {
bus_space_read_region_1(cd->bst, cd->bsh, offset + count, p + count, l);
count += l;
len -= l;
}
l = len / 8;
if (l != 0) {
bus_space_read_region_8(cd->bst, cd->bsh, offset + count, (uint64_t *)(p + count), l);
l *= 8;
count += l;
len -= l;
}
l = len / 4;
if (l != 0) {
bus_space_read_region_4(cd->bst, cd->bsh, offset + count, (uint32_t *)(p + count), l);
l *= 4;
count += l;
len -= l;
}
l = len / 2;
if (l != 0) {
bus_space_read_region_2(cd->bst, cd->bsh, offset + count, (uint16_t *)(p + count), l);
l *= 2;
count += l;
len -= l;
}
if (len != 0) {
bus_space_read_region_1(cd->bst, cd->bsh, offset + count, p + count, len);
count += len;
}
return (count);
}
static int
dpaa2_cons_open(struct cdev *cdev, int flags, int fmt, struct thread *td)
{
struct dpaa2_cons_dev *cd;
struct dpaa2_cons_hdr hdr;
size_t rlen __diagused;
uint32_t wrapped;
if (flags & FWRITE)
return (EACCES);
cd = cdev->si_drv1;
if (cd->size == 0)
return (ENODEV);
mtx_lock(&cd->mtx);
rlen = dpaa2_cons_read_bs(cd, 0, &hdr, sizeof(hdr));
KASSERT(rlen == sizeof(hdr), ("%s:%d: rlen %zu != count %zu, cdev %p "
"cd %p\n", __func__, __LINE__, rlen, sizeof(hdr), cdev, cd));
cd->hdr_magic = hdr.magic;
if (cd->hdr_magic != cd->magic) {
mtx_unlock(&cd->mtx);
return (ENODEV);
}
cd->hdr_eobyte = hdr.eobyte;
cd->hdr_start = hdr.start;
cd->hdr_len = hdr.len;
cd->start = cd->hdr_start - cd->offset;
cd->end = cd->start + cd->hdr_len;
wrapped = cd->hdr_eobyte & LOG_HEADER_FLAG_BUFFER_WRAPAROUND;
cd->eod = cd->start + LAST_BYTE(cd->hdr_eobyte);
if (wrapped && cd->eod != cd->end)
cd->cur = cd->eod + 1;
else
cd->cur = cd->start;
mtx_unlock(&cd->mtx);
return (0);
}
static int
dpaa2_cons_close(struct cdev *cdev, int flags, int fmt, struct thread *td)
{
struct dpaa2_cons_dev *cd;
cd = cdev->si_drv1;
mtx_lock(&cd->mtx);
cd->hdr_magic = cd->hdr_eobyte = cd->hdr_start = cd->hdr_len = 0;
cd->start = cd->end = 0;
mtx_unlock(&cd->mtx);
return (0);
}
static int
dpaa2_cons_read(struct cdev *cdev, struct uio *uio, int flag)
{
char buf[128];
struct dpaa2_cons_dev *cd;
size_t len, size, count;
size_t rlen __diagused;
int error;
cd = cdev->si_drv1;
mtx_lock(&cd->mtx);
if (cd->cur == cd->eod) {
mtx_unlock(&cd->mtx);
return (0);
} else if (cd->cur > cd->eod) {
len = (cd->end - cd->cur) + (cd->eod - cd->start);
} else {
len = cd->eod - cd->cur;
}
size = cd->end - cd->cur;
if (len > size) {
/* dump cur [size] */
while (uio->uio_resid > 0) {
count = imin(sizeof(buf), uio->uio_resid);
if (count > size)
count = size;
rlen = dpaa2_cons_read_bs(cd, cd->cur, buf, count);
KASSERT(rlen == count, ("%s:%d: rlen %zu != count %zu, "
"cdev %p cd %p\n", __func__, __LINE__, rlen, count,
cdev, cd));
cd->cur += count;
len -= count;
size -= count;
mtx_unlock(&cd->mtx);
error = uiomove(buf, count, uio);
if (error != 0 || uio->uio_resid == 0)
return (error);
mtx_lock(&cd->mtx);
}
cd->cur = cd->start;
}
/* dump cur [len] */
while (len > 0 && uio->uio_resid > 0) {
count = imin(sizeof(buf), uio->uio_resid);
if (count > len)
count = len;
rlen = dpaa2_cons_read_bs(cd, cd->cur, buf, count);
KASSERT(rlen == count, ("%s:%d: rlen %zu != count %zu, cdev %p "
"cd %p\n", __func__, __LINE__, rlen, count, cdev, cd));
cd->cur += count;
len -= count;
mtx_unlock(&cd->mtx);
error = uiomove(buf, count, uio);
if (error != 0 || uio->uio_resid == 0)
return (error);
mtx_lock(&cd->mtx);
}
mtx_unlock(&cd->mtx);
return (0);
}
static int
dpaa2_cons_create_dev(device_t dev, bus_addr_t pa, size_t size,
size_t offset, uint32_t magic, struct cdevsw *devsw,
struct dpaa2_cons_dev *cd)
{
struct dpaa2_cons_softc *sc;
struct dpaa2_cons_hdr hdr;
struct make_dev_args md_args;
size_t len;
int error;
sc = device_get_softc(dev);
error = bus_space_map(sc->bst, pa, size, 0, &cd->bsh);
if (error != 0) {
device_printf(dev, "%s: failed to map bus space %#jx/%zu: %d\n",
__func__, (uintmax_t)pa, size, error);
return (error);
}
cd->bst = sc->bst;
cd->size = size;
len = dpaa2_cons_read_bs(cd, 0, &hdr, sizeof(hdr));
if (len != sizeof(hdr)) {
device_printf(dev, "%s: failed to read hdr for %#jx/%zu: %d\n",
__func__, (uintmax_t)pa, size, error);
bus_space_unmap(cd->bst, cd->bsh, cd->size);
cd->size = 0;
return (EIO);
}
/* This checks probably needs to be removed one day? */
if (hdr.magic != magic) {
if (bootverbose)
device_printf(dev, "%s: magic wrong for %#jx/%zu: "
"%#010x != %#010x, no console?\n", __func__,
(uintmax_t)pa, size, hdr.magic, magic);
bus_space_unmap(cd->bst, cd->bsh, cd->size);
cd->size = 0;
return (ENOENT);
}
if (hdr.start - offset > size) {
device_printf(dev, "%s: range wrong for %#jx/%zu: %u - %zu > %zu\n",
__func__, (uintmax_t)pa, size, hdr.start, offset, size);
bus_space_unmap(cd->bst, cd->bsh, cd->size);
cd->size = 0;
return (ERANGE);
}
cd->offset = offset;
cd->magic = magic;
mtx_init(&cd->mtx, "dpaa2 cons", NULL, MTX_DEF);
make_dev_args_init(&md_args);
md_args.mda_devsw = devsw;
md_args.mda_uid = 0;
md_args.mda_gid = 69;
md_args.mda_mode = S_IRUSR | S_IRGRP;
md_args.mda_unit = 0;
md_args.mda_si_drv1 = cd;
error = make_dev_s(&md_args, &cd->cdev, "%s", devsw->d_name);
if (error != 0) {
device_printf(dev, "%s: make_dev_s failed for %#jx/%zu: %d\n",
__func__, (uintmax_t)pa, size, error);
mtx_destroy(&cd->mtx);
bus_space_unmap(cd->bst, cd->bsh, cd->size);
cd->size = 0;
return (error);
}
if (bootverbose)
device_printf(dev, "dpaa2 console %s at pa %#jx size %#010zx "
"(%zu) offset %zu, hdr: magic %#010x start %#010x len "
"%#010x eobyte %#010x\n", devsw->d_name, (uintmax_t)pa,
size, size, offset, hdr.magic, hdr.start, hdr.len, hdr.eobyte);
return (0);
}
static int
dpaa2_cons_attach_common(device_t dev)
{
struct dpaa2_cons_softc *sc;
sc = device_get_softc(dev);
dpaa2_cons_create_dev(dev, (bus_addr_t)(sc->mcfba + MC_BUFFER_OFFSET),
MC_BUFFER_SIZE, MC_OFFSET_DELTA, MAGIC_MC,
&dpaa2_mc_cons_cdevsw, &sc->mc_cd);
dpaa2_cons_create_dev(dev, (bus_addr_t)(sc->mcfba + AIOP_BUFFER_OFFSET),
AIOP_BUFFER_SIZE, AIOP_OFFSET_DELTA, MAGIC_AIOP,
&dpaa2_aiop_cons_cdevsw, &sc->aiop_cd);
return (0);
}
static void
dpaa2_cons_detach_common(struct dpaa2_cons_dev *cd)
{
bus_space_unmap(cd->bst, cd->bsh, cd->size);
mtx_destroy(&cd->mtx);
}
static int
dpaa2_cons_detach(device_t dev)
{
struct dpaa2_cons_softc *sc;
sc = device_get_softc(dev);
if (sc->aiop_cd.cdev != NULL)
destroy_dev(sc->aiop_cd.cdev);
if (sc->mc_cd.cdev != NULL)
destroy_dev(sc->mc_cd.cdev);
if (sc->aiop_cd.size != 0)
dpaa2_cons_detach_common(&sc->aiop_cd);
if (sc->mc_cd.size != 0)
dpaa2_cons_detach_common(&sc->mc_cd);
if (sc->res != NULL)
bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(sc->res),
sc->res);
return (0);
}
#ifdef __notyet__
#ifdef ACPI
static int
dpaa2_cons_acpi_probe(device_t dev)
{
if (!ofw_bus_status_okay(dev))
return (ENXIO);
device_set_desc(dev, "DPAA2 Console Driver");
return (BUS_PROBE_DEFAULT);
}
static int
dpaa2_cons_acpi_attach(device_t dev)
{
struct dpaa2_cons_softc *sc;
uint32_t val;
int error, rid;
sc = device_get_softc(dev);
rid = 0;
sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
if (sc->res == NULL) {
device_printf(dev, "Could not allocate memory\n");
return (ENXIO);
}
sc->bst = rman_get_bustag(sc->res);
val = DPAA2_MC_READ_4(sc, MC_REG_MCFBALR_OFF);
val &= MC_REG_MCFBALR_MASK;
sc->mcfba |= val;
val = DPAA2_MC_READ_4(sc, MC_REG_MCFBAHR_OFF);
val &= MC_REG_MCFBAHR_MASK;
sc->mcfba |= ((uint64_t)val << 32);
error = dpaa2_cons_attach_common(dev);
return (error);
}
static device_method_t dpaa2_cons_acpi_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, dpaa2_cons_acpi_probe),
DEVMETHOD(device_attach, dpaa2_cons_acpi_attach),
DEVMETHOD(device_detach, dpaa2_cons_detach),
DEVMETHOD_END
};
DEFINE_CLASS_0(dpaa2_cons_acpi, dpaa2_cons_acpi_driver, dpaa2_cons_acpi_methods,
sizeof(struct dpaa2_cons_softc));
DRIVER_MODULE(dpaa2_cons_acpi, simplebus, dpaa2_cons_acpi_driver, 0, 0);
MODULE_DEPEND(dpaa2_cons_acpi, dpaa2_mc, 1, 1, 1);
#endif
#endif /* 0 */
#ifdef FDT
static struct ofw_compat_data compat_data[] = {
{ "fsl,dpaa2-console", 1 },
{ NULL, 0 }
};
static int
dpaa2_cons_fdt_probe(device_t dev)
{
if (!ofw_bus_status_okay(dev))
return (ENXIO);
if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
return (ENXIO);
device_set_desc(dev, "DPAA2 Console Driver");
return (BUS_PROBE_DEFAULT);
}
static int
dpaa2_cons_fdt_attach(device_t dev)
{
struct dpaa2_cons_softc *sc;
uint32_t val;
int error, rid;
sc = device_get_softc(dev);
rid = 0;
sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
if (sc->res == NULL) {
device_printf(dev, "Could not allocate memory\n");
return (ENXIO);
}
sc->bst = rman_get_bustag(sc->res);
val = DPAA2_MC_READ_4(sc, MC_REG_MCFBALR_OFF);
val &= MC_REG_MCFBALR_MASK;
sc->mcfba |= val;
val = DPAA2_MC_READ_4(sc, MC_REG_MCFBAHR_OFF);
val &= MC_REG_MCFBAHR_MASK;
sc->mcfba |= ((uint64_t)val << 32);
error = dpaa2_cons_attach_common(dev);
return (error);
}
static device_method_t dpaa2_cons_fdt_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, dpaa2_cons_fdt_probe),
DEVMETHOD(device_attach, dpaa2_cons_fdt_attach),
DEVMETHOD(device_detach, dpaa2_cons_detach),
DEVMETHOD_END
};
DEFINE_CLASS_0(dpaa2_cons_fdt, dpaa2_cons_fdt_driver, dpaa2_cons_fdt_methods,
sizeof(struct dpaa2_cons_softc));
DRIVER_MODULE(dpaa2_cons_fdt, simplebus, dpaa2_cons_fdt_driver, 0, 0);
#endif