Remove SOC FPGA drivers

The drivers have been disconnected from the build since the removal of
the SOCFPGA kernel configs.

Reviewed by:	manu, imp, andrew
Sponsored by:	AFRL, DARPA
Differential Revision:	https://reviews.freebsd.org/D47885
This commit is contained in:
John Baldwin 2024-12-06 17:38:52 -05:00
parent e248e08a15
commit 8f7835acc6
57 changed files with 8 additions and 13332 deletions

View file

@ -51,6 +51,14 @@
# xargs -n1 | sort | uniq -d;
# done
# 2024xxxx: Remove Altera DE4 drivers
OLD_FILES+=usr/share/man/man4/altera_atse.4.gz
OLD_FILES+=usr/share/man/man4/altera_avgen.4.gz
OLD_FILES+=usr/share/man/man4/altera_jtag_uart.4.gz
OLD_FILES+=usr/share/man/man4/altera_sdcard.4.gz
OLD_FILES+=usr/share/man/man4/altera_sdcardc.4.gz
OLD_FILES+=usr/share/man/man4/atse.4.gz
# 20241124: library and tests of OpenBSD dc
OLD_FILES+=usr/share/misc/bc.library
OLD_FILES+=usr/tests/usr.bin/dc/Kyuafile

View file

@ -38,10 +38,6 @@ MAN= aac.4 \
alc.4 \
ale.4 \
alpm.4 \
altera_atse.4 \
altera_avgen.4 \
altera_jtag_uart.4 \
altera_sdcard.4 \
altq.4 \
amdpm.4 \
${_amdsbwd.4} \
@ -651,8 +647,6 @@ MLINKS+=age.4 if_age.4
MLINKS+=agp.4 agpgart.4
MLINKS+=alc.4 if_alc.4
MLINKS+=ale.4 if_ale.4
MLINKS+=altera_atse.4 atse.4
MLINKS+=altera_sdcard.4 altera_sdcardc.4
MLINKS+=altq.4 ALTQ.4
MLINKS+=ath.4 if_ath.4
MLINKS+=aue.4 if_aue.4

View file

@ -1,117 +0,0 @@
.\"-
.\" Copyright (c) 2013-2014 SRI International
.\" All rights reserved.
.\"
.\" This software was developed by SRI International and the University of
.\" Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
.\" ("CTSRD"), as part of the DARPA CRASH research programme.
.\"
.\" 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.
.\"
.Dd May 21, 2014
.Dt ALTERA_ATSE 4
.Os
.Sh NAME
.Nm atse
.Nd driver for the Altera Triple-Speed Ethernet MegaCore
.Sh SYNOPSIS
.Cd "device atse"
.Cd "options ATSE_CFI_HACK"
.Pp
In
.Pa /boot/device.hints :
.Cd hint.atse.0.at="nexus0"
.Cd hint.atse.0.maddr=0x7f007000
.Cd hint.atse.0.msize=0x540
.Cd hint.atse.0.rc_irq=1
.Cd hint.atse.0.rx_maddr=0x7f007500
.Cd hint.atse.0.rx_msize=0x8
.Cd hint.atse.0.rxc_maddr=0x7f007520
.Cd hint.atse.0.rxc_msize=0x20
.Cd hint.atse.0.tx_irq=2
.Cd hint.atse.0.tx_maddr=0x7f007400
.Cd hint.atse.0.tx_msize=0x8
.Cd hint.atse.0.txc_maddr=0x7f007420
.Cd hint.atse.0.txc_msize=0x20
.Cd hint.e1000phy.0.at="miibus0"
.Cd hint.e1000phy.0.phyno=0
.Sh DESCRIPTION
The
.Nm
device driver provides support for the Altera Triple-Speed Ethernet
MegaCore.
.Sh HARDWARE
The current version of the
.Nm
driver supports the Ethernet MegaCore as described in version 11.1 of
Altera's documentation when the device is configured with internal FIFOs.
.Sh MAC SELECTION
The default MAC address for each
.Nm
interface is derived from a value stored in
.Xr cfi 4
flash.
The value is managed by the
.Xr atsectl 8
utility.
.Pp
Only a single MAC address may be stored in flash.
If the address begins with the Altera prefix 00:07:ed and ends in 00 then
up to 16 addresses will be derived from it by adding the unit number of
the interface to the stored address.
For other prefixes, the address will be assigned to atse0 and random
addresses will be used for other interfaces.
If the stored address is invalid, for example all zero's, multicast, or the
default address shipped on all DE4 boards (00:07:ed:ff:ed:15) then a random
address is generated when the device is attached.
.Sh SEE ALSO
.Xr miibus 4 ,
.Xr netintro 4 ,
.Xr ifconfig 8
.Rs
.%T Triple-Speed Ethernet MegaCore Function User Guide
.%D November 2011
.%I Altera Corporation
.Re
.Sh HISTORY
The
.Nm
device driver first appeared in
.Fx 10.0 .
.Sh AUTHORS
The
.Nm
device driver and this manual page were
developed by SRI International and the University of Cambridge Computer
Laboratory under DARPA/AFRL contract
.Pq FA8750-10-C-0237
.Pq Do CTSRD Dc ,
as part of the DARPA CRASH research programme.
This device driver was written by
.An Bjoern A. Zeeb .
.Sh BUGS
The
.Nm
driver only supports a single configuration of the MegaCore as installed
on the Terasic Technologies Altera DE4 Development and Education Board.
.Pp
Only gigabit Ethernet speeds are currently supported.

View file

@ -1,153 +0,0 @@
.\"-
.\" Copyright (c) 2012 Robert N. M. Watson
.\" All rights reserved.
.\"
.\" This software was developed by SRI International and the University of
.\" Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
.\" ("CTSRD"), as part of the DARPA CRASH research programme.
.\"
.\" 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.
.\"
.Dd August 18, 2012
.Dt ALTERA_AVGEN 4
.Os
.Sh NAME
.Nm altera_avgen
.Nd driver for generic Altera Avalon-bus-attached, memory-mapped devices
.Sh SYNOPSIS
.Cd "device altera_avgen"
.Pp
In
.Pa /boot/device.hints :
.Cd hint.altera_avgen.0.at="nexus0"
.Cd hint.altera_avgen.0.maddr=0x7f00a000
.Cd hint.altera_avgen.0.msize=20
.Cd hint.altera_avgen.0.width=4
.Cd hint.altera_avgen.0.fileio="rw"
.Cd hint.altera_avgen.0.devname="berirom"
.Sh DESCRIPTION
The
.Nm
device driver provides generic support for memory-mapped devices on the
Altera Avalon bus.
.Pa device.hints
entries configure the address, size, I/O disposition, and
.Pa /dev
device node name that will be used.
The
.Xr open 2 ,
.Xr read 2 ,
.Xr write 2 ,
and
.Xr mmap 2
system calls (and variations) may be used on
.Nm
device nodes, subject to constraints imposed using
.Pa device.hints
entries.
Although reading and writing mapped memory is supported,
.Nm
does not currently support directing device interrupts to userspace.
.Pp
A number of
.Pa device.hints
sub-fields are available to configure
.Nm
device instances:
.Bl -tag -width devunit
.It maddr
base physical address of the memory region to export; must be aligned to
.Li width
.It msize
length of the memory region export; must be aligned to
.Li width
.It width
Granularity at which
.Xr read 2
and
.Xr write 2
operations will be performed.
Larger requests will be broken down into
.Li width -sized
operations; smaller requests will be rejected.
I/O operations must be aligned to
.Li width .
.It fileio
allowed file descriptor operations;
.Li r
authorizes
.Xr read 2 ;
.Li w
authorizes
.Xr write 2 .
.It mmapio
allowed
.Xr mmap 2
permissions;
.Li w
authorizes
.Dv PROT_WRITE ;
.Li r
authorizes
.Dv PROT_READ ;
.Li x
authorizes
.Dv PROT_EXEC .
.It devname
specifies a device name relative to
.Pa /dev .
.It devunit
specifies a device unit number; no unit number is used if this is unspecified.
.El
.Sh SEE ALSO
.Xr mmap 2 ,
.Xr open 2 ,
.Xr read 2 ,
.Xr write 2
.Sh HISTORY
The
.Nm
device driver first appeared in
.Fx 10.0 .
.Sh AUTHORS
The
.Nm
device driver and this manual page were
developed by SRI International and the University of Cambridge Computer
Laboratory under DARPA/AFRL contract
.Pq FA8750-10-C-0237
.Pq Do CTSRD Dc ,
as part of the DARPA CRASH research programme.
This device driver was written by
.An Robert N. M. Watson .
.Sh BUGS
.Nm
is intended to support the writing of userspace device drivers; however, it
does not permit directing interrupts to userspace, only memory-mapped I/O.
.Pp
.Nm
supports only a
.Li nexus
bus attachment, which is appropriate for system-on-chip busses such as
Altera's Avalon bus.
If the target device is off of another bus type, then additional bus
attachments will be required.

View file

@ -1,119 +0,0 @@
.\"-
.\" Copyright (c) 2012 Robert N. M. Watson
.\" All rights reserved.
.\"
.\" This software was developed by SRI International and the University of
.\" Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
.\" ("CTSRD"), as part of the DARPA CRASH research programme.
.\"
.\" 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.
.\"
.Dd August 18, 2012
.Dt ALTERA_JTAG_UART 4
.Os
.Sh NAME
.Nm altera_jtag_uart
.Nd driver for the Altera JTAG UART Core
.Sh SYNOPSIS
.Cd "device altera_jtag_uart"
.Pp
In
.Pa /boot/device.hints :
.Cd hint.altera_jtag_uart.0.at="nexus0"
.Cd hint.altera_jtag_uart.0.maddr=0x7f000000
.Cd hint.altera_jtag_uart.0.msize=0x40
.Cd hint.altera_jtag_uart.0.irq=0
.Cd hint.altera_jtag_uart.1.at="nexus0"
.Cd hint.altera_jtag_uart.1.maddr=0x7f001000
.Cd hint.altera_jtag_uart.1.msize=0x40
.Sh DESCRIPTION
The
.Nm
device driver provides support for the Altera JTAG UART core, which allows
multiple UART-like streams to be carried over JTAG.
.Nm
allows JTAG UART streams to be attached to both the low-level console
interface, used for direct kernel input and output, and the
.Xr tty 4
layer, to be used with
.Xr ttys 5
and
.Xr login 1 .
Sequential Altera JTAG UART devices will appear as
.Li ttyu0 ,
.Li ttyu1 ,
etc.
.Sh HARDWARE
Altera JTAG UART devices can be connected to using Altera's
.Pa nios2-terminal
program, with the instance selected using the
.Li --instance
argument on the management host.
.Nm
supports JTAG UART cores with or without interrupt lines connected; if the
.Li irq
portion of the
.Pa device.hints
entry is omitted, the driver will poll rather than configure interrupts.
.Sh SEE ALSO
.Xr login 1 ,
.Xr tty 4 ,
.Xr ttys 5
.Rs
.%T Altera Embedded Peripherals IP User Guide
.%D June 2011
.%I Altera Corporation
.%U http://www.altera.com/literature/ug/ug_embedded_ip.pdf
.Re
.Sh HISTORY
The
.Nm
device driver first appeared in
.Fx 10.0 .
.Sh AUTHORS
The
.Nm
device driver and this manual page were
developed by SRI International and the University of Cambridge Computer
Laboratory under DARPA/AFRL contract
.Pq FA8750-10-C-0237
.Pq Do CTSRD Dc ,
as part of the DARPA CRASH research programme.
This device driver was written by
.An Robert N. M. Watson .
.Sh BUGS
.Nm
must dynamically poll to detect when JTAG is present, in order to disable flow
control in the event that there is no receiving endpoint.
Otherwise, the boot may hang waiting for the JTAG client to be attached, and
user processes attached to JTAG UART devices might block indefinitely.
However, there is no way to flush the output buffer once JTAG is detected to
have disappeared; this means that a small amount of stale output data will
remain in the output buffer, being displayed by
.Li nios2-terminal
when it is connected.
Loss of JTAG will not generate a hang-up event, as that is rarely the desired
behaviour.
.Pp
.Li nios2-terminal
does not place the client-side TTY in raw mode, and so by default will not
pass all control characters through to the UART.

View file

@ -1,116 +0,0 @@
.\"-
.\" Copyright (c) 2012 Robert N. M. Watson
.\" All rights reserved.
.\"
.\" This software was developed by SRI International and the University of
.\" Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
.\" ("CTSRD"), as part of the DARPA CRASH research programme.
.\"
.\" 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.
.\"
.Dd August 18, 2012
.Dt ALTERA_SDCARD 4
.Os
.Sh NAME
.Nm altera_sdcard
.Nd driver for the Altera University Program Secure Data Card IP Core
.Sh SYNOPSIS
.Cd "device altera_sdcard"
.Pp
In
.Pa /boot/device.hints :
.Cd hint.altera_sdcardc.0.at="nexus0"
.Cd hint.altera_sdcardc.0.maddr=0x7f008000
.Cd hint.altera_sdcardc.0.msize=0x400
.Sh DESCRIPTION
The
.Nm
device driver provides support for the Altera University Program Secure Data
Card (SD Card) IP Core device.
A controller device,
.Li altera_sdcardcX ,
will be attached during boot.
Inserted disks are presented as
.Xr disk 9
devices,
.Li altera_sdcardX ,
corresponding to the controller number.
.Sh HARDWARE
The current version of the
.Nm
driver supports the SD Card IP core as described in the August 2011 version of
Altera's documentation.
The core supports only cards up to 2G (CSD 0); larger cards, or cards using
newer CSD versions, will not be detected.
The IP core has two key limitations: a lack of interrupt support, requiring
timer-driven polling to detect I/O completion, and support for only single
512-byte block read and write operations at a time.
The combined effect of those two limits is that the system clock rate,
.Dv HZ ,
must be set to at least 200 in order to accomplish the maximum 100KB/s data
rate supported by the IP core.
.Sh SEE ALSO
.Xr disk 9
.Rs
.%T Altera University Program Secure Data Card IP Core
.%D August 2011
.%I Altera Corporation - University Program
.%U ftp://ftp.altera.com/up/pub/Altera_Material/11.0/University_Program_IP_Cores/Memory/SD_Card_Interface_for_SoPC_Builder.pdf
.Re
.Sh HISTORY
The
.Nm
device driver first appeared in
.Fx 10.0 .
.Sh AUTHORS
The
.Nm
device driver and this manual page were
developed by SRI International and the University of Cambridge Computer
Laboratory under DARPA/AFRL contract
.Pq FA8750-10-C-0237
.Pq Do CTSRD Dc ,
as part of the DARPA CRASH research programme.
This device driver was written by
.An Robert N. M. Watson .
.Sh BUGS
.Nm
contains a number of work-arounds for IP core bugs.
Perhaps most critically,
.Nm
ignores the CRC error bit returned in the RR1 register, which appears to be
unexpectedly set by the IP core.
.Pp
.Nm
uses fixed polling intervals are used for card insertion/removal and
I/O completion detection; an adaptive strategy might improve performance by
reducing the latency to detecting completed I/O.
However, in our experiments, using polling rates greater than 200 times a
second did not improve performance.
.Pp
.Nm
supports only a
.Li nexus
bus attachment, which is appropriate for system-on-chip busses such as
Altera's Avalon bus.
If the IP core is configured off of another bus type, then additional bus
attachments will be required.

View file

@ -1,18 +0,0 @@
arm/altera/socfpga/socfpga_common.c standard
arm/altera/socfpga/socfpga_machdep.c standard
arm/altera/socfpga/socfpga_manager.c standard
arm/altera/socfpga/socfpga_rstmgr.c standard
arm/altera/socfpga/socfpga_mp.c optional smp
dev/mmc/host/dwmmc_altera.c optional dwmmc
# Arria 10
arm/altera/socfpga/socfpga_a10_manager.c standard
# BERI specific
dev/beri/beri_ring.c optional beri_ring
dev/beri/beri_mem.c optional beri_mem
dev/beri/virtio/virtio.c optional beri_vtblk | vtbe
dev/beri/virtio/virtio_block.c optional beri_vtblk
dev/beri/virtio/network/if_vtbe.c optional vtbe

View file

@ -1,437 +0,0 @@
/*-
* Copyright (c) 2017 Ruslan Bukin <br@bsdpad.com>
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
* ("CTSRD"), as part of the DARPA CRASH research programme.
*
* 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.
*/
/*
* Intel Arria 10 FPGA Manager.
* Chapter 4, Arria 10 Hard Processor System Technical Reference Manual.
* Chapter A, FPGA Reconfiguration.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/malloc.h>
#include <sys/rman.h>
#include <sys/timeet.h>
#include <sys/timetc.h>
#include <sys/conf.h>
#include <sys/uio.h>
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
#include <machine/cpu.h>
#include <machine/intr.h>
#include <arm/altera/socfpga/socfpga_common.h>
#define FPGAMGR_DCLKCNT 0x8 /* DCLK Count Register */
#define FPGAMGR_DCLKSTAT 0xC /* DCLK Status Register */
#define FPGAMGR_GPO 0x10 /* General-Purpose Output Register */
#define FPGAMGR_GPI 0x14 /* General-Purpose Input Register */
#define FPGAMGR_MISCI 0x18 /* Miscellaneous Input Register */
#define IMGCFG_CTRL_00 0x70
#define S2F_CONDONE_OE (1 << 24)
#define S2F_NSTATUS_OE (1 << 16)
#define CTRL_00_NCONFIG (1 << 8)
#define CTRL_00_NENABLE_CONDONE (1 << 2)
#define CTRL_00_NENABLE_NSTATUS (1 << 1)
#define CTRL_00_NENABLE_NCONFIG (1 << 0)
#define IMGCFG_CTRL_01 0x74
#define CTRL_01_S2F_NCE (1 << 24)
#define CTRL_01_S2F_PR_REQUEST (1 << 16)
#define CTRL_01_S2F_NENABLE_CONFIG (1 << 0)
#define IMGCFG_CTRL_02 0x78
#define CTRL_02_CDRATIO_S 16
#define CTRL_02_CDRATIO_M (0x3 << CTRL_02_CDRATIO_S)
#define CTRL_02_CFGWIDTH_16 (0 << 24)
#define CTRL_02_CFGWIDTH_32 (1 << 24)
#define CTRL_02_EN_CFG_DATA (1 << 8)
#define CTRL_02_EN_CFG_CTRL (1 << 0)
#define IMGCFG_STAT 0x80
#define F2S_PR_ERROR (1 << 11)
#define F2S_PR_DONE (1 << 10)
#define F2S_PR_READY (1 << 9)
#define F2S_MSEL_S 16
#define F2S_MSEL_M (0x7 << F2S_MSEL_S)
#define MSEL_PASSIVE_FAST 0
#define MSEL_PASSIVE_SLOW 1
#define F2S_NCONFIG_PIN (1 << 12)
#define F2S_CONDONE_OE (1 << 7)
#define F2S_NSTATUS_PIN (1 << 4)
#define F2S_CONDONE_PIN (1 << 6)
#define F2S_USERMODE (1 << 2)
struct fpgamgr_a10_softc {
struct resource *res[2];
bus_space_tag_t bst_data;
bus_space_handle_t bsh_data;
struct cdev *mgr_cdev;
device_t dev;
};
static struct resource_spec fpgamgr_a10_spec[] = {
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
{ SYS_RES_MEMORY, 1, RF_ACTIVE },
{ -1, 0 }
};
static int
fpga_wait_dclk_pulses(struct fpgamgr_a10_softc *sc, int npulses)
{
int tout;
/* Clear done bit, if any */
if (READ4(sc, FPGAMGR_DCLKSTAT) != 0)
WRITE4(sc, FPGAMGR_DCLKSTAT, 0x1);
/* Request DCLK pulses */
WRITE4(sc, FPGAMGR_DCLKCNT, npulses);
/* Wait finish */
tout = 1000;
while (tout > 0) {
if (READ4(sc, FPGAMGR_DCLKSTAT) == 1) {
WRITE4(sc, FPGAMGR_DCLKSTAT, 0x1);
break;
}
tout--;
DELAY(10);
}
if (tout == 0) {
device_printf(sc->dev,
"Error: dclkpulses wait timeout\n");
return (1);
}
return (0);
}
static int
fpga_open(struct cdev *dev, int flags __unused,
int fmt __unused, struct thread *td __unused)
{
struct fpgamgr_a10_softc *sc;
int tout;
int msel;
int reg;
sc = dev->si_drv1;
/* Step 1 */
reg = READ4(sc, IMGCFG_STAT);
if ((reg & F2S_USERMODE) == 0) {
device_printf(sc->dev, "Error: invalid mode\n");
return (ENXIO);
};
/* Step 2 */
reg = READ4(sc, IMGCFG_STAT);
msel = (reg & F2S_MSEL_M) >> F2S_MSEL_S;
if ((msel != MSEL_PASSIVE_FAST) && \
(msel != MSEL_PASSIVE_SLOW)) {
device_printf(sc->dev,
"Error: invalid msel %d\n", msel);
return (ENXIO);
};
/*
* Step 3.
* TODO: add support for compressed, encrypted images.
*/
reg = READ4(sc, IMGCFG_CTRL_02);
reg &= ~(CTRL_02_CDRATIO_M);
WRITE4(sc, IMGCFG_CTRL_02, reg);
reg = READ4(sc, IMGCFG_CTRL_02);
reg &= ~CTRL_02_CFGWIDTH_32;
WRITE4(sc, IMGCFG_CTRL_02, reg);
/* Step 4. a */
reg = READ4(sc, IMGCFG_CTRL_01);
reg &= ~CTRL_01_S2F_PR_REQUEST;
WRITE4(sc, IMGCFG_CTRL_01, reg);
reg = READ4(sc, IMGCFG_CTRL_00);
reg |= CTRL_00_NCONFIG;
WRITE4(sc, IMGCFG_CTRL_00, reg);
/* b */
reg = READ4(sc, IMGCFG_CTRL_01);
reg &= ~CTRL_01_S2F_NCE;
WRITE4(sc, IMGCFG_CTRL_01, reg);
/* c */
reg = READ4(sc, IMGCFG_CTRL_02);
reg |= CTRL_02_EN_CFG_CTRL;
WRITE4(sc, IMGCFG_CTRL_02, reg);
/* d */
reg = READ4(sc, IMGCFG_CTRL_00);
reg &= ~S2F_CONDONE_OE;
reg &= ~S2F_NSTATUS_OE;
reg |= CTRL_00_NCONFIG;
reg |= CTRL_00_NENABLE_NSTATUS;
reg |= CTRL_00_NENABLE_CONDONE;
reg &= ~CTRL_00_NENABLE_NCONFIG;
WRITE4(sc, IMGCFG_CTRL_00, reg);
/* Step 5 */
reg = READ4(sc, IMGCFG_CTRL_01);
reg &= ~CTRL_01_S2F_NENABLE_CONFIG;
WRITE4(sc, IMGCFG_CTRL_01, reg);
/* Step 6 */
fpga_wait_dclk_pulses(sc, 0x100);
/* Step 7. a */
reg = READ4(sc, IMGCFG_CTRL_01);
reg |= CTRL_01_S2F_PR_REQUEST;
WRITE4(sc, IMGCFG_CTRL_01, reg);
/* b, c */
fpga_wait_dclk_pulses(sc, 0x7ff);
/* Step 8 */
tout = 10;
while (tout--) {
reg = READ4(sc, IMGCFG_STAT);
if (reg & F2S_PR_ERROR) {
device_printf(sc->dev,
"Error: PR failed on open.\n");
return (ENXIO);
}
if (reg & F2S_PR_READY) {
break;
}
}
if (tout == 0) {
device_printf(sc->dev,
"Error: Timeout waiting PR ready bit.\n");
return (ENXIO);
}
return (0);
}
static int
fpga_close(struct cdev *dev, int flags __unused,
int fmt __unused, struct thread *td __unused)
{
struct fpgamgr_a10_softc *sc;
int tout;
int reg;
sc = dev->si_drv1;
/* Step 10 */
tout = 10;
while (tout--) {
reg = READ4(sc, IMGCFG_STAT);
if (reg & F2S_PR_ERROR) {
device_printf(sc->dev,
"Error: PR failed.\n");
return (ENXIO);
}
if (reg & F2S_PR_DONE) {
break;
}
}
/* Step 11 */
reg = READ4(sc, IMGCFG_CTRL_01);
reg &= ~CTRL_01_S2F_PR_REQUEST;
WRITE4(sc, IMGCFG_CTRL_01, reg);
/* Step 12, 13 */
fpga_wait_dclk_pulses(sc, 0x100);
/* Step 14 */
reg = READ4(sc, IMGCFG_CTRL_02);
reg &= ~CTRL_02_EN_CFG_CTRL;
WRITE4(sc, IMGCFG_CTRL_02, reg);
/* Step 15 */
reg = READ4(sc, IMGCFG_CTRL_01);
reg |= CTRL_01_S2F_NCE;
WRITE4(sc, IMGCFG_CTRL_01, reg);
/* Step 16 */
reg = READ4(sc, IMGCFG_CTRL_01);
reg |= CTRL_01_S2F_NENABLE_CONFIG;
WRITE4(sc, IMGCFG_CTRL_01, reg);
/* Step 17 */
reg = READ4(sc, IMGCFG_STAT);
if ((reg & F2S_USERMODE) == 0) {
device_printf(sc->dev,
"Error: invalid mode\n");
return (ENXIO);
};
if ((reg & F2S_CONDONE_PIN) == 0) {
device_printf(sc->dev,
"Error: configuration not done\n");
return (ENXIO);
};
if ((reg & F2S_NSTATUS_PIN) == 0) {
device_printf(sc->dev,
"Error: nstatus pin\n");
return (ENXIO);
};
return (0);
}
static int
fpga_write(struct cdev *dev, struct uio *uio, int ioflag)
{
struct fpgamgr_a10_softc *sc;
uint32_t buffer;
sc = dev->si_drv1;
/*
* Step 9.
* Device supports 4-byte writes only.
*/
while (uio->uio_resid >= 4) {
uiomove(&buffer, 4, uio);
bus_space_write_4(sc->bst_data, sc->bsh_data,
0x0, buffer);
}
switch (uio->uio_resid) {
case 3:
uiomove(&buffer, 3, uio);
buffer &= 0xffffff;
bus_space_write_4(sc->bst_data, sc->bsh_data,
0x0, buffer);
break;
case 2:
uiomove(&buffer, 2, uio);
buffer &= 0xffff;
bus_space_write_4(sc->bst_data, sc->bsh_data,
0x0, buffer);
break;
case 1:
uiomove(&buffer, 1, uio);
buffer &= 0xff;
bus_space_write_4(sc->bst_data, sc->bsh_data,
0x0, buffer);
break;
default:
break;
};
return (0);
}
static int
fpga_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags,
struct thread *td)
{
return (0);
}
static struct cdevsw fpga_cdevsw = {
.d_version = D_VERSION,
.d_open = fpga_open,
.d_close = fpga_close,
.d_write = fpga_write,
.d_ioctl = fpga_ioctl,
.d_name = "FPGA Manager",
};
static int
fpgamgr_a10_probe(device_t dev)
{
if (!ofw_bus_status_okay(dev))
return (ENXIO);
if (!ofw_bus_is_compatible(dev, "altr,socfpga-a10-fpga-mgr"))
return (ENXIO);
device_set_desc(dev, "Arria 10 FPGA Manager");
return (BUS_PROBE_DEFAULT);
}
static int
fpgamgr_a10_attach(device_t dev)
{
struct fpgamgr_a10_softc *sc;
sc = device_get_softc(dev);
sc->dev = dev;
if (bus_alloc_resources(dev, fpgamgr_a10_spec, sc->res)) {
device_printf(dev, "Could not allocate resources.\n");
return (ENXIO);
}
/* Memory interface */
sc->bst_data = rman_get_bustag(sc->res[1]);
sc->bsh_data = rman_get_bushandle(sc->res[1]);
sc->mgr_cdev = make_dev(&fpga_cdevsw, 0, UID_ROOT, GID_WHEEL,
0600, "fpga%d", device_get_unit(sc->dev));
if (sc->mgr_cdev == NULL) {
device_printf(dev, "Failed to create character device.\n");
return (ENXIO);
}
sc->mgr_cdev->si_drv1 = sc;
return (0);
}
static device_method_t fpgamgr_a10_methods[] = {
DEVMETHOD(device_probe, fpgamgr_a10_probe),
DEVMETHOD(device_attach, fpgamgr_a10_attach),
{ 0, 0 }
};
static driver_t fpgamgr_a10_driver = {
"fpgamgr_a10",
fpgamgr_a10_methods,
sizeof(struct fpgamgr_a10_softc),
};
DRIVER_MODULE(fpgamgr_a10, simplebus, fpgamgr_a10_driver, 0, 0);

View file

@ -1,41 +0,0 @@
/*-
* Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com>
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
* ("CTSRD"), as part of the DARPA CRASH research programme.
*
* 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.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <dev/ofw/openfirm.h>
#include <machine/bus.h>
#include <machine/fdt.h>
#include <arm/altera/socfpga/socfpga_rstmgr.h>

View file

@ -1,36 +0,0 @@
/*-
* Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com>
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
* ("CTSRD"), as part of the DARPA CRASH research programme.
*
* 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.
*/
#define READ4(_sc, _reg) bus_read_4((_sc)->res[0], _reg)
#define READ2(_sc, _reg) bus_read_2((_sc)->res[0], _reg)
#define READ1(_sc, _reg) bus_read_1((_sc)->res[0], _reg)
#define WRITE4(_sc, _reg, _val) bus_write_4((_sc)->res[0], _reg, _val)
#define WRITE2(_sc, _reg, _val) bus_write_2((_sc)->res[0], _reg, _val)
#define WRITE1(_sc, _reg, _val) bus_write_1((_sc)->res[0], _reg, _val)

View file

@ -1,52 +0,0 @@
/*-
* Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com>
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
* ("CTSRD"), as part of the DARPA CRASH research programme.
*
* 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.
*/
#define L3REGS_REMAP 0x0 /* Remap */
#define REMAP_LWHPS2FPGA (1 << 4)
#define REMAP_HPS2FPGA (1 << 3)
#define REMAP_MPUZERO (1 << 0)
#define L3REGS_L4MAIN 0x8 /* L4 main peripherals security */
#define L3REGS_L4SP 0xC /* L4 SP Peripherals Security */
#define L3REGS_L4MP 0x10 /* L4 MP Peripherals Security */
#define L3REGS_L4OSC1 0x14 /* L4 OSC1 Peripherals Security */
#define L3REGS_L4SPIM 0x18 /* L4 SPIM Peripherals Security */
#define L3REGS_STM 0x1C /* STM Peripheral Security */
#define L3REGS_LWHPS2FPGAREGS 0x20 /* LWHPS2FPGA AXI Bridge Security */
#define L3REGS_USB1 0x28 /* USB1 Peripheral Security */
#define L3REGS_NANDDATA 0x2C /* NAND Flash Controller Data Sec */
#define L3REGS_USB0 0x80 /* USB0 Peripheral Security */
#define L3REGS_NANDREGS 0x84 /* NAND Flash Controller Security */
#define L3REGS_QSPIDATA 0x88 /* QSPI Flash Controller Data Sec */
#define L3REGS_FPGAMGRDATA 0x8C /* FPGA Manager Data Peripheral Sec */
#define L3REGS_HPS2FPGAREGS 0x90 /* HPS2FPGA AXI Bridge Perip. Sec */
#define L3REGS_ACP 0x94 /* MPU ACP Peripheral Security */
#define L3REGS_ROM 0x98 /* ROM Peripheral Security */
#define L3REGS_OCRAM 0x9C /* On-chip RAM Peripheral Security */
#define L3REGS_SDRDATA 0xA0 /* SDRAM Data Peripheral Security */

View file

@ -1,173 +0,0 @@
/*-
* Copyright (c) 2014-2017 Ruslan Bukin <br@bsdpad.com>
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
* ("CTSRD"), as part of the DARPA CRASH research programme.
*
* 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.
*/
#include "opt_platform.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/devmap.h>
#include <vm/vm.h>
#include <dev/ofw/openfirm.h>
#include <machine/armreg.h>
#include <machine/bus.h>
#include <machine/fdt.h>
#include <machine/machdep.h>
#include <machine/platform.h>
#include <machine/platformvar.h>
#include <arm/altera/socfpga/socfpga_mp.h>
#include <arm/altera/socfpga/socfpga_rstmgr.h>
#include "platform_if.h"
#if defined(SOC_ALTERA_CYCLONE5)
static int
socfpga_devmap_init(platform_t plat)
{
/* UART */
devmap_add_entry(0xffc00000, 0x100000);
/*
* USB OTG
*
* We use static device map for USB due to some bug in the Altera
* which throws Translation Fault (P) exception on high load.
* It might be caused due to some power save options being turned
* on or something else.
*/
devmap_add_entry(0xffb00000, 0x100000);
/* dwmmc */
devmap_add_entry(0xff700000, 0x100000);
/* scu */
devmap_add_entry(0xfff00000, 0x100000);
/* FPGA memory window, 256MB */
devmap_add_entry(0xd0000000, 0x10000000);
return (0);
}
#endif
#if defined(SOC_ALTERA_ARRIA10)
static int
socfpga_a10_devmap_init(platform_t plat)
{
/* UART */
devmap_add_entry(0xffc00000, 0x100000);
/* USB OTG */
devmap_add_entry(0xffb00000, 0x100000);
/* dwmmc */
devmap_add_entry(0xff800000, 0x100000);
/* scu */
devmap_add_entry(0xfff00000, 0x100000);
return (0);
}
#endif
static void
_socfpga_cpu_reset(bus_size_t reg)
{
uint32_t paddr;
bus_addr_t vaddr;
phandle_t node;
if (rstmgr_warmreset(reg) == 0)
goto end;
node = OF_finddevice("/soc/rstmgr");
if (node == -1)
goto end;
if ((OF_getencprop(node, "reg", &paddr, sizeof(paddr))) > 0) {
if (bus_space_map(fdtbus_bs_tag, paddr, 0x8, 0, &vaddr) == 0) {
bus_space_write_4(fdtbus_bs_tag, vaddr,
reg, CTRL_SWWARMRSTREQ);
}
}
end:
while (1);
}
#if defined(SOC_ALTERA_CYCLONE5)
static void
socfpga_cpu_reset(platform_t plat)
{
_socfpga_cpu_reset(RSTMGR_CTRL);
}
#endif
#if defined(SOC_ALTERA_ARRIA10)
static void
socfpga_a10_cpu_reset(platform_t plat)
{
_socfpga_cpu_reset(RSTMGR_A10_CTRL);
}
#endif
#if defined(SOC_ALTERA_CYCLONE5)
static platform_method_t socfpga_methods[] = {
PLATFORMMETHOD(platform_devmap_init, socfpga_devmap_init),
PLATFORMMETHOD(platform_cpu_reset, socfpga_cpu_reset),
#ifdef SMP
PLATFORMMETHOD(platform_mp_setmaxid, socfpga_mp_setmaxid),
PLATFORMMETHOD(platform_mp_start_ap, socfpga_mp_start_ap),
#endif
PLATFORMMETHOD_END,
};
FDT_PLATFORM_DEF(socfpga, "socfpga", 0, "altr,socfpga-cyclone5", 200);
#endif
#if defined(SOC_ALTERA_ARRIA10)
static platform_method_t socfpga_a10_methods[] = {
PLATFORMMETHOD(platform_devmap_init, socfpga_a10_devmap_init),
PLATFORMMETHOD(platform_cpu_reset, socfpga_a10_cpu_reset),
#ifdef SMP
PLATFORMMETHOD(platform_mp_setmaxid, socfpga_mp_setmaxid),
PLATFORMMETHOD(platform_mp_start_ap, socfpga_a10_mp_start_ap),
#endif
PLATFORMMETHOD_END,
};
FDT_PLATFORM_DEF(socfpga_a10, "socfpga", 0, "altr,socfpga-arria10", 200);
#endif

View file

@ -1,426 +0,0 @@
/*-
* Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com>
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
* ("CTSRD"), as part of the DARPA CRASH research programme.
*
* 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.
*/
/*
* Altera FPGA Manager.
* Chapter 4, Cyclone V Device Handbook (CV-5V2 2014.07.22)
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/malloc.h>
#include <sys/rman.h>
#include <sys/timeet.h>
#include <sys/timetc.h>
#include <sys/conf.h>
#include <sys/uio.h>
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
#include <machine/cpu.h>
#include <machine/intr.h>
#include <arm/altera/socfpga/socfpga_common.h>
/* FPGA Manager Module Registers */
#define FPGAMGR_STAT 0x0 /* Status Register */
#define STAT_MSEL_MASK 0x1f
#define STAT_MSEL_SHIFT 3
#define STAT_MODE_SHIFT 0
#define STAT_MODE_MASK 0x7
#define FPGAMGR_CTRL 0x4 /* Control Register */
#define CTRL_AXICFGEN (1 << 8)
#define CTRL_CDRATIO_MASK 0x3
#define CTRL_CDRATIO_SHIFT 6
#define CTRL_CFGWDTH_MASK 1
#define CTRL_CFGWDTH_SHIFT 9
#define CTRL_NCONFIGPULL (1 << 2)
#define CTRL_NCE (1 << 1)
#define CTRL_EN (1 << 0)
#define FPGAMGR_DCLKCNT 0x8 /* DCLK Count Register */
#define FPGAMGR_DCLKSTAT 0xC /* DCLK Status Register */
#define FPGAMGR_GPO 0x10 /* General-Purpose Output Register */
#define FPGAMGR_GPI 0x14 /* General-Purpose Input Register */
#define FPGAMGR_MISCI 0x18 /* Miscellaneous Input Register */
/* Configuration Monitor (MON) Registers */
#define GPIO_INTEN 0x830 /* Interrupt Enable Register */
#define GPIO_INTMASK 0x834 /* Interrupt Mask Register */
#define GPIO_INTTYPE_LEVEL 0x838 /* Interrupt Level Register */
#define GPIO_INT_POLARITY 0x83C /* Interrupt Polarity Register */
#define GPIO_INTSTATUS 0x840 /* Interrupt Status Register */
#define GPIO_RAW_INTSTATUS 0x844 /* Raw Interrupt Status Register */
#define GPIO_PORTA_EOI 0x84C /* Clear Interrupt Register */
#define PORTA_EOI_NS (1 << 0)
#define GPIO_EXT_PORTA 0x850 /* External Port A Register */
#define EXT_PORTA_CDP (1 << 10) /* Configuration done */
#define GPIO_LS_SYNC 0x860 /* Synchronization Level Register */
#define GPIO_VER_ID_CODE 0x86C /* GPIO Version Register */
#define GPIO_CONFIG_REG2 0x870 /* Configuration Register 2 */
#define GPIO_CONFIG_REG1 0x874 /* Configuration Register 1 */
#define MSEL_PP16_FAST_NOAES_NODC 0x0
#define MSEL_PP16_FAST_AES_NODC 0x1
#define MSEL_PP16_FAST_AESOPT_DC 0x2
#define MSEL_PP16_SLOW_NOAES_NODC 0x4
#define MSEL_PP16_SLOW_AES_NODC 0x5
#define MSEL_PP16_SLOW_AESOPT_DC 0x6
#define MSEL_PP32_FAST_NOAES_NODC 0x8
#define MSEL_PP32_FAST_AES_NODC 0x9
#define MSEL_PP32_FAST_AESOPT_DC 0xa
#define MSEL_PP32_SLOW_NOAES_NODC 0xc
#define MSEL_PP32_SLOW_AES_NODC 0xd
#define MSEL_PP32_SLOW_AESOPT_DC 0xe
#define CFGWDTH_16 0
#define CFGWDTH_32 1
#define CDRATIO_1 0
#define CDRATIO_2 1
#define CDRATIO_4 2
#define CDRATIO_8 3
#define FPGAMGR_MODE_POWEROFF 0x0
#define FPGAMGR_MODE_RESET 0x1
#define FPGAMGR_MODE_CONFIG 0x2
#define FPGAMGR_MODE_INIT 0x3
#define FPGAMGR_MODE_USER 0x4
struct cfgmgr_mode {
int msel;
int cfgwdth;
int cdratio;
};
static struct cfgmgr_mode cfgmgr_modes[] = {
{ MSEL_PP16_FAST_NOAES_NODC, CFGWDTH_16, CDRATIO_1 },
{ MSEL_PP16_FAST_AES_NODC, CFGWDTH_16, CDRATIO_2 },
{ MSEL_PP16_FAST_AESOPT_DC, CFGWDTH_16, CDRATIO_4 },
{ MSEL_PP16_SLOW_NOAES_NODC, CFGWDTH_16, CDRATIO_1 },
{ MSEL_PP16_SLOW_AES_NODC, CFGWDTH_16, CDRATIO_2 },
{ MSEL_PP16_SLOW_AESOPT_DC, CFGWDTH_16, CDRATIO_4 },
{ MSEL_PP32_FAST_NOAES_NODC, CFGWDTH_32, CDRATIO_1 },
{ MSEL_PP32_FAST_AES_NODC, CFGWDTH_32, CDRATIO_4 },
{ MSEL_PP32_FAST_AESOPT_DC, CFGWDTH_32, CDRATIO_8 },
{ MSEL_PP32_SLOW_NOAES_NODC, CFGWDTH_32, CDRATIO_1 },
{ MSEL_PP32_SLOW_AES_NODC, CFGWDTH_32, CDRATIO_4 },
{ MSEL_PP32_SLOW_AESOPT_DC, CFGWDTH_32, CDRATIO_8 },
{ -1, -1, -1 },
};
struct fpgamgr_softc {
struct resource *res[3];
bus_space_tag_t bst_data;
bus_space_handle_t bsh_data;
struct cdev *mgr_cdev;
device_t dev;
};
static struct resource_spec fpgamgr_spec[] = {
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
{ SYS_RES_MEMORY, 1, RF_ACTIVE },
{ SYS_RES_IRQ, 0, RF_ACTIVE },
{ -1, 0 }
};
static int
fpgamgr_state_get(struct fpgamgr_softc *sc)
{
int reg;
reg = READ4(sc, FPGAMGR_STAT);
reg >>= STAT_MODE_SHIFT;
reg &= STAT_MODE_MASK;
return reg;
}
static int
fpgamgr_state_wait(struct fpgamgr_softc *sc, int state)
{
int tout;
tout = 1000;
while (tout > 0) {
if (fpgamgr_state_get(sc) == state)
break;
tout--;
DELAY(10);
}
if (tout == 0) {
return (1);
}
return (0);
}
static int
fpga_open(struct cdev *dev, int flags __unused,
int fmt __unused, struct thread *td __unused)
{
struct fpgamgr_softc *sc;
struct cfgmgr_mode *mode;
int msel;
int reg;
int i;
sc = dev->si_drv1;
msel = READ4(sc, FPGAMGR_STAT);
msel >>= STAT_MSEL_SHIFT;
msel &= STAT_MSEL_MASK;
mode = NULL;
for (i = 0; cfgmgr_modes[i].msel != -1; i++) {
if (msel == cfgmgr_modes[i].msel) {
mode = &cfgmgr_modes[i];
break;
}
}
if (mode == NULL) {
device_printf(sc->dev, "Can't configure: unknown mode\n");
return (ENXIO);
}
reg = READ4(sc, FPGAMGR_CTRL);
reg &= ~(CTRL_CDRATIO_MASK << CTRL_CDRATIO_SHIFT);
reg |= (mode->cdratio << CTRL_CDRATIO_SHIFT);
reg &= ~(CTRL_CFGWDTH_MASK << CTRL_CFGWDTH_SHIFT);
reg |= (mode->cfgwdth << CTRL_CFGWDTH_SHIFT);
reg &= ~(CTRL_NCE);
WRITE4(sc, FPGAMGR_CTRL, reg);
/* Enable configuration */
reg = READ4(sc, FPGAMGR_CTRL);
reg |= (CTRL_EN);
WRITE4(sc, FPGAMGR_CTRL, reg);
/* Reset FPGA */
reg = READ4(sc, FPGAMGR_CTRL);
reg |= (CTRL_NCONFIGPULL);
WRITE4(sc, FPGAMGR_CTRL, reg);
/* Wait reset state */
if (fpgamgr_state_wait(sc, FPGAMGR_MODE_RESET)) {
device_printf(sc->dev, "Can't get RESET state\n");
return (ENXIO);
}
/* Release from reset */
reg = READ4(sc, FPGAMGR_CTRL);
reg &= ~(CTRL_NCONFIGPULL);
WRITE4(sc, FPGAMGR_CTRL, reg);
if (fpgamgr_state_wait(sc, FPGAMGR_MODE_CONFIG)) {
device_printf(sc->dev, "Can't get CONFIG state\n");
return (ENXIO);
}
/* Clear nSTATUS edge interrupt */
WRITE4(sc, GPIO_PORTA_EOI, PORTA_EOI_NS);
/* Enter configuration state */
reg = READ4(sc, FPGAMGR_CTRL);
reg |= (CTRL_AXICFGEN);
WRITE4(sc, FPGAMGR_CTRL, reg);
return (0);
}
static int
fpga_wait_dclk_pulses(struct fpgamgr_softc *sc, int npulses)
{
int tout;
/* Clear done bit, if any */
if (READ4(sc, FPGAMGR_DCLKSTAT) != 0)
WRITE4(sc, FPGAMGR_DCLKSTAT, 0x1);
/* Request DCLK pulses */
WRITE4(sc, FPGAMGR_DCLKCNT, npulses);
/* Wait finish */
tout = 1000;
while (tout > 0) {
if (READ4(sc, FPGAMGR_DCLKSTAT) == 1) {
WRITE4(sc, FPGAMGR_DCLKSTAT, 0x1);
break;
}
tout--;
DELAY(10);
}
if (tout == 0) {
return (1);
}
return (0);
}
static int
fpga_close(struct cdev *dev, int flags __unused,
int fmt __unused, struct thread *td __unused)
{
struct fpgamgr_softc *sc;
int reg;
sc = dev->si_drv1;
reg = READ4(sc, GPIO_EXT_PORTA);
if ((reg & EXT_PORTA_CDP) == 0) {
device_printf(sc->dev, "Err: configuration failed\n");
return (ENXIO);
}
/* Exit configuration state */
reg = READ4(sc, FPGAMGR_CTRL);
reg &= ~(CTRL_AXICFGEN);
WRITE4(sc, FPGAMGR_CTRL, reg);
/* Wait dclk pulses */
if (fpga_wait_dclk_pulses(sc, 4)) {
device_printf(sc->dev, "Can't proceed 4 dclk pulses\n");
return (ENXIO);
}
if (fpgamgr_state_wait(sc, FPGAMGR_MODE_USER)) {
device_printf(sc->dev, "Can't get USER mode\n");
return (ENXIO);
}
/* Disable configuration */
reg = READ4(sc, FPGAMGR_CTRL);
reg &= ~(CTRL_EN);
WRITE4(sc, FPGAMGR_CTRL, reg);
return (0);
}
static int
fpga_write(struct cdev *dev, struct uio *uio, int ioflag)
{
struct fpgamgr_softc *sc;
int buffer;
sc = dev->si_drv1;
/*
* Device supports 4-byte copy only.
* TODO: add padding for <4 bytes.
*/
while (uio->uio_resid > 0) {
uiomove(&buffer, 4, uio);
bus_space_write_4(sc->bst_data, sc->bsh_data,
0x0, buffer);
}
return (0);
}
static int
fpga_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags,
struct thread *td)
{
return (0);
}
static struct cdevsw fpga_cdevsw = {
.d_version = D_VERSION,
.d_open = fpga_open,
.d_close = fpga_close,
.d_write = fpga_write,
.d_ioctl = fpga_ioctl,
.d_name = "FPGA Manager",
};
static int
fpgamgr_probe(device_t dev)
{
if (!ofw_bus_status_okay(dev))
return (ENXIO);
if (!ofw_bus_is_compatible(dev, "altr,socfpga-fpga-mgr"))
return (ENXIO);
device_set_desc(dev, "FPGA Manager");
return (BUS_PROBE_DEFAULT);
}
static int
fpgamgr_attach(device_t dev)
{
struct fpgamgr_softc *sc;
sc = device_get_softc(dev);
sc->dev = dev;
if (bus_alloc_resources(dev, fpgamgr_spec, sc->res)) {
device_printf(dev, "could not allocate resources\n");
return (ENXIO);
}
/* Memory interface */
sc->bst_data = rman_get_bustag(sc->res[1]);
sc->bsh_data = rman_get_bushandle(sc->res[1]);
sc->mgr_cdev = make_dev(&fpga_cdevsw, 0, UID_ROOT, GID_WHEEL,
0600, "fpga%d", device_get_unit(sc->dev));
if (sc->mgr_cdev == NULL) {
device_printf(dev, "Failed to create character device.\n");
return (ENXIO);
}
sc->mgr_cdev->si_drv1 = sc;
return (0);
}
static device_method_t fpgamgr_methods[] = {
DEVMETHOD(device_probe, fpgamgr_probe),
DEVMETHOD(device_attach, fpgamgr_attach),
{ 0, 0 }
};
static driver_t fpgamgr_driver = {
"fpgamgr",
fpgamgr_methods,
sizeof(struct fpgamgr_softc),
};
DRIVER_MODULE(fpgamgr, simplebus, fpgamgr_driver, 0, 0);

View file

@ -1,230 +0,0 @@
/*-
* Copyright (c) 2014-2017 Ruslan Bukin <br@bsdpad.com>
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
* ("CTSRD"), as part of the DARPA CRASH research programme.
*
* 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.
*/
#include "opt_platform.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/smp.h>
#include <vm/vm.h>
#include <vm/pmap.h>
#include <machine/cpu.h>
#include <machine/smp.h>
#include <machine/fdt.h>
#include <machine/intr.h>
#include <machine/platformvar.h>
#include <arm/altera/socfpga/socfpga_mp.h>
#include <arm/altera/socfpga/socfpga_rstmgr.h>
#define SCU_PHYSBASE 0xFFFEC000
#define SCU_PHYSBASE_A10 0xFFFFC000
#define SCU_SIZE 0x100
#define SCU_CONTROL_REG 0x00
#define SCU_CONTROL_ENABLE (1 << 0)
#define SCU_CONFIG_REG 0x04
#define SCU_CONFIG_REG_NCPU_MASK 0x03
#define SCU_CPUPOWER_REG 0x08
#define SCU_INV_TAGS_REG 0x0c
#define SCU_DIAG_CONTROL 0x30
#define SCU_DIAG_DISABLE_MIGBIT (1 << 0)
#define SCU_FILTER_START_REG 0x40
#define SCU_FILTER_END_REG 0x44
#define SCU_SECURE_ACCESS_REG 0x50
#define SCU_NONSECURE_ACCESS_REG 0x54
#define RSTMGR_PHYSBASE 0xFFD05000
#define RSTMGR_SIZE 0x100
#define RAM_PHYSBASE 0x0
#define RAM_SIZE 0x1000
#define SOCFPGA_ARRIA10 1
#define SOCFPGA_CYCLONE5 2
extern char *mpentry_addr;
static void socfpga_trampoline(void);
static void
socfpga_trampoline(void)
{
__asm __volatile(
"ldr pc, 1f\n"
".globl mpentry_addr\n"
"mpentry_addr:\n"
"1: .space 4\n");
}
void
socfpga_mp_setmaxid(platform_t plat)
{
int hwcpu, ncpu;
/* If we've already set this don't bother to do it again. */
if (mp_ncpus != 0)
return;
hwcpu = 2;
ncpu = hwcpu;
TUNABLE_INT_FETCH("hw.ncpu", &ncpu);
if (ncpu < 1 || ncpu > hwcpu)
ncpu = hwcpu;
mp_ncpus = ncpu;
mp_maxid = ncpu - 1;
}
static void
_socfpga_mp_start_ap(uint32_t platid)
{
bus_space_handle_t scu, rst, ram;
int reg;
switch (platid) {
#if defined(SOC_ALTERA_ARRIA10)
case SOCFPGA_ARRIA10:
if (bus_space_map(fdtbus_bs_tag, SCU_PHYSBASE_A10,
SCU_SIZE, 0, &scu) != 0)
panic("Couldn't map the SCU\n");
break;
#endif
#if defined(SOC_ALTERA_CYCLONE5)
case SOCFPGA_CYCLONE5:
if (bus_space_map(fdtbus_bs_tag, SCU_PHYSBASE,
SCU_SIZE, 0, &scu) != 0)
panic("Couldn't map the SCU\n");
break;
#endif
default:
panic("Unknown platform id %d\n", platid);
}
if (bus_space_map(fdtbus_bs_tag, RSTMGR_PHYSBASE,
RSTMGR_SIZE, 0, &rst) != 0)
panic("Couldn't map the reset manager (RSTMGR)\n");
if (bus_space_map(fdtbus_bs_tag, RAM_PHYSBASE,
RAM_SIZE, 0, &ram) != 0)
panic("Couldn't map the first physram page\n");
/* Invalidate SCU cache tags */
bus_space_write_4(fdtbus_bs_tag, scu,
SCU_INV_TAGS_REG, 0x0000ffff);
/*
* Erratum ARM/MP: 764369 (problems with cache maintenance).
* Setting the "disable-migratory bit" in the undocumented SCU
* Diagnostic Control Register helps work around the problem.
*/
reg = bus_space_read_4(fdtbus_bs_tag, scu, SCU_DIAG_CONTROL);
reg |= (SCU_DIAG_DISABLE_MIGBIT);
bus_space_write_4(fdtbus_bs_tag, scu, SCU_DIAG_CONTROL, reg);
/* Put CPU1 to reset state */
switch (platid) {
#if defined(SOC_ALTERA_ARRIA10)
case SOCFPGA_ARRIA10:
bus_space_write_4(fdtbus_bs_tag, rst,
RSTMGR_A10_MPUMODRST, MPUMODRST_CPU1);
break;
#endif
#if defined(SOC_ALTERA_CYCLONE5)
case SOCFPGA_CYCLONE5:
bus_space_write_4(fdtbus_bs_tag, rst,
RSTMGR_MPUMODRST, MPUMODRST_CPU1);
break;
#endif
default:
panic("Unknown platform id %d\n", platid);
}
/* Enable the SCU, then clean the cache on this core */
reg = bus_space_read_4(fdtbus_bs_tag, scu, SCU_CONTROL_REG);
reg |= (SCU_CONTROL_ENABLE);
bus_space_write_4(fdtbus_bs_tag, scu, SCU_CONTROL_REG, reg);
/* Set up trampoline code */
mpentry_addr = (char *)pmap_kextract((vm_offset_t)mpentry);
bus_space_write_region_4(fdtbus_bs_tag, ram, 0,
(uint32_t *)&socfpga_trampoline, 8);
dcache_wbinv_poc_all();
/* Put CPU1 out from reset */
switch (platid) {
#if defined(SOC_ALTERA_ARRIA10)
case SOCFPGA_ARRIA10:
bus_space_write_4(fdtbus_bs_tag, rst,
RSTMGR_A10_MPUMODRST, 0);
break;
#endif
#if defined(SOC_ALTERA_CYCLONE5)
case SOCFPGA_CYCLONE5:
bus_space_write_4(fdtbus_bs_tag, rst,
RSTMGR_MPUMODRST, 0);
break;
#endif
default:
panic("Unknown platform id %d\n", platid);
}
dsb();
sev();
bus_space_unmap(fdtbus_bs_tag, scu, SCU_SIZE);
bus_space_unmap(fdtbus_bs_tag, rst, RSTMGR_SIZE);
bus_space_unmap(fdtbus_bs_tag, ram, RAM_SIZE);
}
#if defined(SOC_ALTERA_ARRIA10)
void
socfpga_a10_mp_start_ap(platform_t plat)
{
_socfpga_mp_start_ap(SOCFPGA_ARRIA10);
}
#endif
#if defined(SOC_ALTERA_CYCLONE5)
void
socfpga_mp_start_ap(platform_t plat)
{
_socfpga_mp_start_ap(SOCFPGA_CYCLONE5);
}
#endif

View file

@ -1,33 +0,0 @@
/*-
* Copyright (c) 2017 Andrew Turner <andrew@FreeBSD.org>
* All rights reserved.
*
* 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 ``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 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.
*/
#ifndef _SOCFPGA_MP_H_
#define _SOCFPGA_MP_H_
void socfpga_mp_setmaxid(platform_t);
void socfpga_mp_start_ap(platform_t);
void socfpga_a10_mp_start_ap(platform_t);
#endif /* _SOCFPGA_MP_H_ */

View file

@ -1,255 +0,0 @@
/*-
* Copyright (c) 2014-2017 Ruslan Bukin <br@bsdpad.com>
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
* ("CTSRD"), as part of the DARPA CRASH research programme.
*
* 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.
*/
/*
* SOCFPGA Reset Manager.
* Chapter 3, Cyclone V Device Handbook (CV-5V2 2014.07.22)
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/malloc.h>
#include <sys/rman.h>
#include <sys/timeet.h>
#include <sys/timetc.h>
#include <sys/sysctl.h>
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
#include <machine/fdt.h>
#include <machine/cpu.h>
#include <machine/intr.h>
#include <arm/altera/socfpga/socfpga_common.h>
#include <arm/altera/socfpga/socfpga_rstmgr.h>
#include <arm/altera/socfpga/socfpga_l3regs.h>
struct rstmgr_softc {
struct resource *res[1];
bus_space_tag_t bst;
bus_space_handle_t bsh;
device_t dev;
};
struct rstmgr_softc *rstmgr_sc;
static struct resource_spec rstmgr_spec[] = {
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
{ -1, 0 }
};
enum {
RSTMGR_SYSCTL_FPGA2HPS,
RSTMGR_SYSCTL_LWHPS2FPGA,
RSTMGR_SYSCTL_HPS2FPGA
};
static int
l3remap(struct rstmgr_softc *sc, int remap, int enable)
{
uint32_t paddr;
bus_addr_t vaddr;
phandle_t node;
int reg;
/*
* Control whether bridge is visible to L3 masters or not.
* Register is write-only.
*/
reg = REMAP_MPUZERO;
if (enable)
reg |= (remap);
else
reg &= ~(remap);
node = OF_finddevice("l3regs");
if (node == -1) {
device_printf(sc->dev, "Can't find l3regs node\n");
return (1);
}
if ((OF_getencprop(node, "reg", &paddr, sizeof(paddr))) > 0) {
if (bus_space_map(fdtbus_bs_tag, paddr, 0x4, 0, &vaddr) == 0) {
bus_space_write_4(fdtbus_bs_tag, vaddr,
L3REGS_REMAP, reg);
return (0);
}
}
return (1);
}
static int
rstmgr_sysctl(SYSCTL_HANDLER_ARGS)
{
struct rstmgr_softc *sc;
int enable;
int remap;
int err;
int reg;
int bit;
sc = arg1;
switch (arg2) {
case RSTMGR_SYSCTL_FPGA2HPS:
bit = BRGMODRST_FPGA2HPS;
remap = 0;
break;
case RSTMGR_SYSCTL_LWHPS2FPGA:
bit = BRGMODRST_LWHPS2FPGA;
remap = REMAP_LWHPS2FPGA;
break;
case RSTMGR_SYSCTL_HPS2FPGA:
bit = BRGMODRST_HPS2FPGA;
remap = REMAP_HPS2FPGA;
break;
default:
return (1);
}
reg = READ4(sc, RSTMGR_BRGMODRST);
enable = reg & bit ? 0 : 1;
err = sysctl_handle_int(oidp, &enable, 0, req);
if (err || !req->newptr)
return (err);
if (enable == 1)
reg &= ~(bit);
else if (enable == 0)
reg |= (bit);
else
return (EINVAL);
WRITE4(sc, RSTMGR_BRGMODRST, reg);
l3remap(sc, remap, enable);
return (0);
}
int
rstmgr_warmreset(uint32_t reg)
{
struct rstmgr_softc *sc;
sc = rstmgr_sc;
if (sc == NULL)
return (1);
/* Request warm reset */
WRITE4(sc, reg, CTRL_SWWARMRSTREQ);
return (0);
}
static int
rstmgr_add_sysctl(struct rstmgr_softc *sc)
{
struct sysctl_oid_list *children;
struct sysctl_ctx_list *ctx;
ctx = device_get_sysctl_ctx(sc->dev);
children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev));
SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "fpga2hps",
CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
sc, RSTMGR_SYSCTL_FPGA2HPS,
rstmgr_sysctl, "I", "Enable fpga2hps bridge");
SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "lwhps2fpga",
CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
sc, RSTMGR_SYSCTL_LWHPS2FPGA,
rstmgr_sysctl, "I", "Enable lwhps2fpga bridge");
SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "hps2fpga",
CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
sc, RSTMGR_SYSCTL_HPS2FPGA,
rstmgr_sysctl, "I", "Enable hps2fpga bridge");
return (0);
}
static int
rstmgr_probe(device_t dev)
{
if (!ofw_bus_status_okay(dev))
return (ENXIO);
if (!ofw_bus_is_compatible(dev, "altr,rst-mgr"))
return (ENXIO);
device_set_desc(dev, "Reset Manager");
return (BUS_PROBE_DEFAULT);
}
static int
rstmgr_attach(device_t dev)
{
struct rstmgr_softc *sc;
sc = device_get_softc(dev);
sc->dev = dev;
if (bus_alloc_resources(dev, rstmgr_spec, sc->res)) {
device_printf(dev, "could not allocate resources\n");
return (ENXIO);
}
/* Memory interface */
sc->bst = rman_get_bustag(sc->res[0]);
sc->bsh = rman_get_bushandle(sc->res[0]);
rstmgr_sc = sc;
rstmgr_add_sysctl(sc);
return (0);
}
static device_method_t rstmgr_methods[] = {
DEVMETHOD(device_probe, rstmgr_probe),
DEVMETHOD(device_attach, rstmgr_attach),
{ 0, 0 }
};
static driver_t rstmgr_driver = {
"rstmgr",
rstmgr_methods,
sizeof(struct rstmgr_softc),
};
DRIVER_MODULE(rstmgr, simplebus, rstmgr_driver, 0, 0);

View file

@ -1,48 +0,0 @@
/*-
* Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com>
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
* ("CTSRD"), as part of the DARPA CRASH research programme.
*
* 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.
*/
#define RSTMGR_STAT 0x0 /* Status */
#define RSTMGR_CTRL 0x4 /* Control */
#define CTRL_SWWARMRSTREQ (1 << 1) /* Trigger warm reset */
#define RSTMGR_COUNTS 0x8 /* Reset Cycles Count */
#define RSTMGR_MPUMODRST 0x10 /* MPU Module Reset */
#define MPUMODRST_CPU1 (1 << 1)
#define RSTMGR_PERMODRST 0x14 /* Peripheral Module Reset */
#define RSTMGR_PER2MODRST 0x18 /* Peripheral 2 Module Reset */
#define RSTMGR_BRGMODRST 0x1C /* Bridge Module Reset */
#define BRGMODRST_FPGA2HPS (1 << 2)
#define BRGMODRST_LWHPS2FPGA (1 << 1)
#define BRGMODRST_HPS2FPGA (1 << 0)
#define RSTMGR_MISCMODRST 0x20 /* Miscellaneous Module Reset */
#define RSTMGR_A10_CTRL 0xC /* Control */
#define RSTMGR_A10_MPUMODRST 0x20 /* MPU Module Reset */
int rstmgr_warmreset(uint32_t reg);

View file

@ -1,6 +0,0 @@
cpu CPU_CORTEXA
machine arm armv7
makeoptions CONF_CFLAGS="-march=armv7a"
files "../altera/socfpga/files.socfpga"

View file

@ -856,18 +856,6 @@ contrib/alpine-hal/eth/al_hal_eth_main.c optional al_eth \
dev/alc/if_alc.c optional alc pci
dev/ale/if_ale.c optional ale pci
dev/alpm/alpm.c optional alpm pci
dev/altera/avgen/altera_avgen.c optional altera_avgen
dev/altera/avgen/altera_avgen_fdt.c optional altera_avgen fdt
dev/altera/avgen/altera_avgen_nexus.c optional altera_avgen
dev/altera/msgdma/msgdma.c optional altera_msgdma xdma
dev/altera/sdcard/altera_sdcard.c optional altera_sdcard
dev/altera/sdcard/altera_sdcard_disk.c optional altera_sdcard
dev/altera/sdcard/altera_sdcard_io.c optional altera_sdcard
dev/altera/sdcard/altera_sdcard_fdt.c optional altera_sdcard fdt
dev/altera/sdcard/altera_sdcard_nexus.c optional altera_sdcard
dev/altera/softdma/softdma.c optional altera_softdma xdma fdt
dev/altera/pio/pio.c optional altera_pio
dev/altera/pio/pio_if.m optional altera_pio
dev/amdpm/amdpm.c optional amdpm pci | nfpm pci
dev/amdsmb/amdsmb.c optional amdsmb pci
#

View file

@ -71,7 +71,6 @@ TSLOGSIZE opt_global.h
# Miscellaneous options.
ALQ
ALTERA_SDCARD_FAST_SIM opt_altera_sdcard.h
ATSE_CFI_HACK opt_cfi.h
AUDIT opt_global.h
BOOTHOWTO opt_global.h
@ -838,12 +837,6 @@ AH_INTERRUPT_DEBUGGING opt_ah.h
# XXX do not use this for AR9130
AH_AR5416_INTERRUPT_MITIGATION opt_ah.h
# options for the Altera mSGDMA driver (altera_msgdma)
ALTERA_MSGDMA_DESC_STD opt_altera_msgdma.h
ALTERA_MSGDMA_DESC_EXT opt_altera_msgdma.h
ALTERA_MSGDMA_DESC_PF_STD opt_altera_msgdma.h
ALTERA_MSGDMA_DESC_PF_EXT opt_altera_msgdma.h
# options for the Broadcom BCM43xx driver (bwi)
BWI_DEBUG opt_bwi.h
BWI_DEBUG_VERBOSE opt_bwi.h

File diff suppressed because it is too large Load diff

View file

@ -1,144 +0,0 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2013 Bjoern A. Zeeb
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-11-C-0249)
* ("MRC2"), as part of the DARPA MRC research programme.
*
* 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.
*/
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/rman.h>
#include <sys/socket.h>
#include <sys/systm.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <net/if_media.h>
#include <net/if_var.h>
#include <dev/mii/mii.h>
#include <dev/mii/miivar.h>
#include <dev/fdt/fdt_common.h>
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
#include <dev/altera/atse/if_atsereg.h>
/* "device miibus" required. See GENERIC if you get errors here. */
#include "miibus_if.h"
static int
atse_probe_fdt(device_t dev)
{
if (!ofw_bus_status_okay(dev))
return (ENXIO);
if (!ofw_bus_is_compatible(dev, "altera,atse")) {
return (ENXIO);
}
device_set_desc(dev, "Altera Triple-Speed Ethernet MegaCore");
return (BUS_PROBE_DEFAULT);
}
static int
atse_attach_fdt(device_t dev)
{
struct atse_softc *sc;
int error;
sc = device_get_softc(dev);
sc->atse_dev = dev;
sc->atse_unit = device_get_unit(dev);
/*
* FDT has the list of our resources. Given we are using multiple
* memory regions and possibly multiple interrupts, we need to attach
* them in the order specified in .dts:
* MAC, RX and RXC FIFO, TX and TXC FIFO; RX INTR, TX INTR.
*/
/* MAC: Avalon-MM, atse management register region. */
sc->atse_mem_rid = 0;
sc->atse_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
&sc->atse_mem_rid, RF_ACTIVE);
if (sc->atse_mem_res == NULL) {
device_printf(dev, "failed to map memory for ctrl region\n");
/* Cleanup. */
atse_detach_resources(dev);
return (ENXIO);
}
if (bootverbose)
device_printf(sc->atse_dev, "MAC ctrl region at mem %p-%p\n",
(void *)rman_get_start(sc->atse_mem_res),
(void *)(rman_get_start(sc->atse_mem_res) +
rman_get_size(sc->atse_mem_res)));
error = atse_attach(dev);
if (error) {
/* Cleanup. */
atse_detach_resources(dev);
return (error);
}
return (0);
}
static device_method_t atse_methods_fdt[] = {
/* Device interface */
DEVMETHOD(device_probe, atse_probe_fdt),
DEVMETHOD(device_attach, atse_attach_fdt),
DEVMETHOD(device_detach, atse_detach_dev),
/* MII interface */
DEVMETHOD(miibus_readreg, atse_miibus_readreg),
DEVMETHOD(miibus_writereg, atse_miibus_writereg),
DEVMETHOD(miibus_statchg, atse_miibus_statchg),
DEVMETHOD_END
};
static driver_t atse_driver_fdt = {
"atse",
atse_methods_fdt,
sizeof(struct atse_softc)
};
DRIVER_MODULE(atse, simplebus, atse_driver_fdt, 0, 0);
DRIVER_MODULE(miibus, atse, miibus_driver, 0, 0);

View file

@ -1,158 +0,0 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2012,2013 Bjoern A. Zeeb
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-11-C-0249)
* ("MRC2"), as part of the DARPA MRC research programme.
*
* 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.
*/
#include <sys/cdefs.h>
#include "opt_device_polling.h"
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/module.h>
#include <sys/rman.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <net/if_media.h>
#include <net/if_var.h>
#include <dev/mii/mii.h>
#include <dev/mii/miivar.h>
#include <dev/altera/atse/if_atsereg.h>
/* "device miibus" required. See GENERIC if you get errors here. */
#include "miibus_if.h"
MODULE_DEPEND(atse, ether, 1, 1, 1);
MODULE_DEPEND(atse, miibus, 1, 1, 1);
/*
* Device routines for interacting with nexus (probe, attach, detach) & helpers.
* XXX We should add suspend/resume later.
*/
static int __unused
atse_resource_int(device_t dev, const char *resname, int *v)
{
int error;
error = resource_int_value(device_get_name(dev), device_get_unit(dev),
resname, v);
if (error != 0) {
/* If it does not exist, we fail, so not ingoring ENOENT. */
device_printf(dev, "could not fetch '%s' hint\n", resname);
return (error);
}
return (0);
}
static int __unused
atse_resource_long(device_t dev, const char *resname, long *v)
{
int error;
error = resource_long_value(device_get_name(dev), device_get_unit(dev),
resname, v);
if (error != 0) {
/* If it does not exist, we fail, so not ingoring ENOENT. */
device_printf(dev, "could not fetch '%s' hint\n", resname);
return (error);
}
return (0);
}
static int
atse_probe_nexus(device_t dev)
{
device_set_desc(dev, "Altera Triple-Speed Ethernet MegaCore");
return (BUS_PROBE_NOWILDCARD);
}
static int
atse_attach_nexus(device_t dev)
{
struct atse_softc *sc;
int error;
sc = device_get_softc(dev);
sc->atse_dev = dev;
sc->atse_unit = device_get_unit(dev);
/* Avalon-MM, atse management register region. */
sc->atse_mem_rid = 0;
sc->atse_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
&sc->atse_mem_rid, RF_ACTIVE);
if (sc->atse_mem_res == NULL) {
device_printf(dev, "failed to map memory for ctrl region\n");
return (ENXIO);
}
error = atse_attach(dev);
if (error) {
/* Cleanup. */
atse_detach_resources(dev);
return (error);
}
return (0);
}
static device_method_t atse_methods_nexus[] = {
/* Device interface */
DEVMETHOD(device_probe, atse_probe_nexus),
DEVMETHOD(device_attach, atse_attach_nexus),
DEVMETHOD(device_detach, atse_detach_dev),
/* MII interface */
DEVMETHOD(miibus_readreg, atse_miibus_readreg),
DEVMETHOD(miibus_writereg, atse_miibus_writereg),
DEVMETHOD(miibus_statchg, atse_miibus_statchg),
DEVMETHOD_END
};
static driver_t atse_driver_nexus = {
"atse",
atse_methods_nexus,
sizeof(struct atse_softc)
};
DRIVER_MODULE(atse, nexus, atse_driver_nexus, 0, 0);
DRIVER_MODULE(miibus, atse, miibus_driver, 0, 0);

View file

@ -1,464 +0,0 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2012 Bjoern A. Zeeb
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-11-C-0249)
* ("MRC2"), as part of the DARPA MRC research programme.
*
* 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.
*/
#ifndef _DEV_IF_ATSEREG_H
#define _DEV_IF_ATSEREG_H
#include <dev/xdma/xdma.h>
#define ATSE_VENDOR 0x6af7
#define ATSE_DEVICE 0x00bd
/* See hints file/fdt for ctrl port and Avalon FIFO addresses. */
/* Section 3. Parameter Settings. */
/*
* This is a lot of options that affect the way things are synthesized.
* We cannot really make them all hints and most of them might be stale.
*/
/* 3-1 Core Configuration */
#if 0
static const char *atse_core_core_variation[] = {
[0] = "10/100/1000 Mbps Ethernet MAC only",
[1] = "10/100/1000 Mbps Ethernet MAC with 1000BASE-X/SGMII PCS",
[2] = "1000BASE-X/SGMII PCS only",
[3] = "1000 Mbps Small MAC",
[4] = "10/100 Mbps Small MAC",
NULL
};
static const char *atse_core_interface[] = {
[0] = "MII", /* Core variation 4. */
[1] = "GMII", /* Core variation 3. */
[2] = "RGMII", /* Core variation 0,1,3. */
[3] = "MII/GMII", /* Core variation 0,1. */
NULL
};
#endif
#define CORE_CORE_VARIATION 1 /* atse_core_core_variation[] */
#define CORE_INTERFACE 3 /* atse_core_interface[] */
#define CORE_USE_INTERNAL_FIFO 1
#define CORE_NUMBER_OF_PORTS 1 /* Internal FIFO count. */
#define CORE_USE_TRANSCEIVER_BLOCK 1 /* SGMII PCS transceiver:
* LVDS I/O. */
/* 3-2 MAC Options. */
/* Ethernet MAC Options. */
#define MAC_ENABLE_10_100_HDX_SUPPORT 0
#define MAC_ENABLE_RG_G_MII_LOOPBACK 0
#define MAC_ENABLE_SUPL_MAC_UCAST_ADDR 0 /* Supplementary MAC unicast. */
#define MAC_INCLUDE_STATISTICS_COUNTERS 0
#define MAC_STATISTICS_COUNTERS_64BIT 0
#define MAC_INCLUDE_MC_HASHTABLE 0 /* Multicast. */
#define MAC_ALIGN_PKTHDR_32BIT 1
#define MAC_ENABLE_FDX_FLOW_CTRL 0
#define MAC_ENABLE_VLAN_DETECTION 0 /* VLAN and stacked VLANs. */
#define MAC_ENABLE_MAGIC_PKT_DETECTION 0
/* MDIO Module. */
#define MAC_MDIO_INCLUDE_MDIO_MODULE 1
#define MAC_MDIO_HOST_CLOCK_DIVISOR 40 /* Not just On/Off. */
/* 3-4 FIFO Options. */
/* Width and Memory Type. */
#if 0
static char *fifo_memory_block[] = {
[0] = "M4K",
[1] = "M9K",
[2] = "M144K",
[3] = "MRAM",
[4] = "AUTO",
NULL
};
#endif
#define FIFO_MEMORY_BLOCK 4
#define FIFO_WITDH 32 /* Other: 8 bits. */
/* Depth. */
#define FIFO_DEPTH_TX 2048 /* 64 .. 64k, 2048x32bits. */
#define FIFO_DEPTH_RX 2048 /* 64 .. 64k, 2048x32bits. */
#define ATSE_TX_LIST_CNT 5 /* Certainly not bufferbloat. */
/* 3-4 PCS/Transceiver Options */
/* PCS Options. */
#define PCS_TXRX_PHY_ID 0x00000000 /* 32 bits */
#define PCS_TXRX_ENABLE_SGMII_BRIDGE 0
/* Transceiver Options. */
#define PCS_TXRX_EXP_POWER_DOWN_SIGNAL 0 /* Export power down signal. */
#define PCS_TXRX_ENABLE_DYNAMIC_RECONF 0 /* Dynamic trans. reconfig. */
#define PCS_TXRX_STARTING_CHANNEL 0 /* 0..284. */
/* -------------------------------------------------------------------------- */
/* XXX more values based on the bitmaps provided. Cleanup. */
/* See regs above. */
#define AVALON_FIFO_TX_BLOCK_DIAGRAM 0
#define AVALON_FIFO_TX_BLOCK_DIAGRAM_SHOW_SIGANLS 0
#define AVALON_FIFO_TX_PARAM_SINGLE_RESET_MODE 0
#define AVALON_FIFO_TX_BASIC_OPTS_DEPTH 16
#define AVALON_FIFO_TX_BASIC_OPTS_ALLOW_BACKPRESSURE 1
#define AVALON_FIFO_TX_BASIC_OPTS_CLOCK_SETTING "Single Clock Mode"
#define AVALON_FIFO_TX_BASIC_OPTS_FIFO_IMPL "Construct FIFO from embedded memory blocks"
#define AVALON_FIFO_TX_STATUS_PORT_CREATE_STATUS_INT_FOR_INPUT 1
#define AVALON_FIFO_TX_STATUS_PORT_CREATE_STATUS_INT_FOR_OUTPUT 0
#define AVALON_FIFO_TX_STATUS_PORT_ENABLE_IRQ_FOR_STATUS_PORT 1
#define AVALON_FIFO_TX_INPUT_TYPE "AVALONMM_WRITE"
#define AVALON_FIFO_TX_OUTPUT_TYPE "AVALONST_SOURCE"
#define AVALON_FIFO_TX_AVALON_MM_PORT_SETTINGS_DATA_WIDTH ""
#define AVALON_FIFO_TX_AVALON_ST_PORT_SETTINGS_BITS_PER_SYMBOL 8
#define AVALON_FIFO_TX_AVALON_ST_PORT_SETTINGS_SYM_PER_BEAT 4
#define AVALON_FIFO_TX_AVALON_ST_PORT_SETTINGS_ERROR_WIDTH 1
#define AVALON_FIFO_TX_AVALON_ST_PORT_SETTINGS_CHANNEL_WIDTH 0
#define AVALON_FIFO_TX_AVALON_ST_PORT_SETTINGS_ENABLE_PACKET_DATA 1
#define AVALON_FIFO_RX_BLOCK_DIAGRAM 0
#define AVALON_FIFO_RX_BLOCK_DIAGRAM_SHOW_SIGNALS 0
#define AVALON_FIFO_RX_PARAM_SINGLE_RESET_MODE 0
#define AVALON_FIFO_RX_BASIC_OPTS_DEPTH 16
#define AVALON_FIFO_RX_BASIC_OPTS_ALLOW_BACKPRESSURE 1
#define AVALON_FIFO_RX_BASIC_OPTS_CLOCK_SETTING "Single Clock Mode"
#define AVALON_FIFO_RX_BASIC_OPTS_FIFO_IMPL "Construct FIFO from embedded memory blocks"
#define AVALON_FIFO_RX_STATUS_PORT_CREATE_STATUS_INT_FOR_INPUT 1
#define AVALON_FIFO_RX_STATUS_PORT_CREATE_STATUS_INT_FOR_OUTPUT 0
#define AVALON_FIFO_RX_STATUS_PORT_ENABLE_IRQ_FOR_STATUS_PORT 1
#define AVALON_FIFO_RX_INPUT_TYPE "AVALONST_SINK"
#define AVALON_FIFO_RX_OUTPUT_TYPE "AVALONMM_READ"
#define AVALON_FIFO_RX_AVALON_MM_PORT_SETTINGS_DATA_WIDTH ""
#define AVALON_FIFO_RX_AVALON_ST_PORT_SETTINGS_BITS_PER_SYMBOL 8
#define AVALON_FIFO_RX_AVALON_ST_PORT_SETTINGS_SYM_PER_BEAT 4
#define AVALON_FIFO_RX_AVALON_ST_PORT_SETTINGS_ERROR_WIDTH 6
#define AVALON_FIFO_RX_AVALON_ST_PORT_SETTINGS_CHANNEL_WIDTH 0
#define AVALON_FIFO_RX_AVALON_ST_PORT_SETTINGS_ENABLE_PACKET_DATA 1
/* -------------------------------------------------------------------------- */
/* 5. Configuration Register Space. */
/* 5-1, MAC Configuration Register Space; Dword offsets. */
/* 0x00 - 0x17, Base Configuration. */
#define BASE_CONFIG_REV 0x00 /* ro, IP Core ver. */
#define BASE_CFG_REV_VER_MASK 0x0000FFFF
#define BASE_CFG_REV_CUST_VERSION__MASK 0xFFFF0000
#define BASE_CFG_SCRATCH 0x01 /* rw, 0 */
#define BASE_CFG_COMMAND_CONFIG 0x02 /* rw, 0 */
#define BASE_CFG_COMMAND_CONFIG_TX_ENA (1<<0) /* rw */
#define BASE_CFG_COMMAND_CONFIG_RX_ENA (1<<1) /* rw */
#define BASE_CFG_COMMAND_CONFIG_XON_GEN (1<<2) /* rw */
#define BASE_CFG_COMMAND_CONFIG_ETH_SPEED (1<<3) /* rw */
#define BASE_CFG_COMMAND_CONFIG_PROMIS_EN (1<<4) /* rw */
#define BASE_CFG_COMMAND_CONFIG_PAD_EN (1<<5) /* rw */
#define BASE_CFG_COMMAND_CONFIG_CRC_FWD (1<<6) /* rw */
#define BASE_CFG_COMMAND_CONFIG_PAUSE_FWD (1<<7) /* rw */
#define BASE_CFG_COMMAND_CONFIG_PAUSE_IGNORE (1<<8) /* rw */
#define BASE_CFG_COMMAND_CONFIG_TX_ADDR_INS (1<<9) /* rw */
#define BASE_CFG_COMMAND_CONFIG_HD_ENA (1<<10) /* rw */
#define BASE_CFG_COMMAND_CONFIG_EXCESS_COL (1<<11) /* ro */
#define BASE_CFG_COMMAND_CONFIG_LATE_COL (1<<12) /* ro */
#define BASE_CFG_COMMAND_CONFIG_SW_RESET (1<<13) /* rw */
#define BASE_CFG_COMMAND_CONFIG_MHASH_SEL (1<<14) /* rw */
#define BASE_CFG_COMMAND_CONFIG_LOOP_ENA (1<<15) /* rw */
#define BASE_CFG_COMMAND_CONFIG_TX_ADDR_SEL (1<<16|1<<17|1<<18) /* rw */
#define BASE_CFG_COMMAND_CONFIG_MAGIC_ENA (1<<19) /* rw */
#define BASE_CFG_COMMAND_CONFIG_SLEEP (1<<20) /* rw */
#define BASE_CFG_COMMAND_CONFIG_WAKEUP (1<<21) /* ro */
#define BASE_CFG_COMMAND_CONFIG_XOFF_GEN (1<<22) /* rw */
#define BASE_CFG_COMMAND_CONFIG_CNTL_FRM_ENA (1<<23) /* rw */
#define BASE_CFG_COMMAND_CONFIG_NO_LGTH_CHECK (1<<24) /* rw */
#define BASE_CFG_COMMAND_CONFIG_ENA_10 (1<<25) /* rw */
#define BASE_CFG_COMMAND_CONFIG_RX_ERR_DISC (1<<26) /* rw */
#define BASE_CFG_COMMAND_CONFIG_DISABLE_READ_TIMEOUT (1<<27) /* rw */
/* 28-30 Reserved. */ /* - */
#define BASE_CFG_COMMAND_CONFIG_CNT_RESET (1<<31) /* rw */
#define BASE_CFG_MAC_0 0x03 /* rw, 0 */
#define BASE_CFG_MAC_1 0x04 /* rw, 0 */
#define BASE_CFG_FRM_LENGTH 0x05 /* rw/ro, 1518 */
#define BASE_CFG_PAUSE_QUANT 0x06 /* rw, 0 */
#define BASE_CFG_RX_SECTION_EMPTY 0x07 /* rw/ro, 0 */
#define BASE_CFG_RX_SECTION_FULL 0x08 /* rw/ro, 0 */
#define BASE_CFG_TX_SECTION_EMPTY 0x09 /* rw/ro, 0 */
#define BASE_CFG_TX_SECTION_FULL 0x0A /* rw/ro, 0 */
#define BASE_CFG_RX_ALMOST_EMPTY 0x0B /* rw/ro, 0 */
#define BASE_CFG_RX_ALMOST_FULL 0x0C /* rw/ro, 0 */
#define BASE_CFG_TX_ALMOST_EMPTY 0x0D /* rw/ro, 0 */
#define BASE_CFG_TX_ALMOST_FULL 0x0E /* rw/ro, 0 */
#define BASE_CFG_MDIO_ADDR0 0x0F /* rw, 0 */
#define BASE_CFG_MDIO_ADDR1 0x10 /* rw, 1 */
#define BASE_CFG_HOLDOFF_QUANT 0x11 /* rw, 0xFFFF */
/* 0x12-0x16 Reserved. */ /* -, 0 */
#define BASE_CFG_TX_IPG_LENGTH 0x17 /* rw, 0 */
/* 0x18 - 0x38, Statistics Counters. */
#define STATS_A_MAC_ID_0 0x18 /* ro */
#define STATS_A_MAC_ID_1 0x19 /* ro */
#define STATS_A_FRAMES_TX_OK 0x1A /* ro */
#define STATS_A_FRAMES_RX_OK 0x1B /* ro */
#define STATS_A_FCS_ERRORS 0x1C /* ro */
#define STATS_A_ALIGNMENT_ERRORS 0x1D /* ro */
#define STATS_A_OCTETS_TX_OK 0x1E /* ro */
#define STATS_A_OCTETS_RX_OK 0x1F /* ro */
#define STATS_A_TX_PAUSE_MAX_CTRL_FRAME 0x20 /* ro */
#define STATS_A_RX_PAUSE_MAX_CTRL_FRAME 0x21 /* ro */
#define STATS_IF_IN_ERRORS 0x22 /* ro */
#define STATS_IF_OUT_ERRORS 0x23 /* ro */
#define STATS_IF_IN_UCAST_PKTS 0x24 /* ro */
#define STATS_IF_IN_MULTICAST_PKTS 0x25 /* ro */
#define STATS_IF_IN_BROADCAST_PKTS 0x26 /* ro */
#define STATS_IF_OUT_DISCARDS 0x27 /* ro */
#define STATS_IF_OUT_UCAST_PKTS 0x28 /* ro */
#define STATS_IF_OUT_MULTICAST_PKTS 0x29 /* ro */
#define STATS_IF_OUT_BROADCAST_PKTS 0x2A /* ro */
#define STATS_ETHER_STATS_DROP_EVENT 0x2B /* ro */
#define STATS_ETHER_STATS_OCTETS 0x2C /* ro */
#define STATS_ETHER_STATS_PKTS 0x2D /* ro */
#define STATS_ETHER_STATS_USIZE_PKTS 0x2E /* ro */
#define STATS_ETHER_STATS_OSIZE_PKTS 0x2F /* ro */
#define STATS_ETHER_STATS_PKTS_64_OCTETS 0x30 /* ro */
#define STATS_ETHER_STATS_PKTS_65_TO_127_OCTETS 0x31 /* ro */
#define STATS_ETHER_STATS_PKTS_128_TO_255_OCTETS 0x32 /* ro */
#define STATS_ETHER_STATS_PKTS_256_TO_511_OCTETS 0x33 /* ro */
#define STATS_ETHER_STATS_PKTS_512_TO_1023_OCTETS 0x34 /* ro */
#define STATS_ETHER_STATS_PKTS_1024_TO_1518_OCTETS 0x35 /* ro */
#define STATS_ETHER_STATS_PKTS_1519_TO_X_OCTETS 0x36 /* ro */
#define STATS_ETHER_STATS_JABBERS 0x37 /* ro */
#define STATS_ETHER_STATS_FRAGMENTS 0x38 /* ro */
/* 0x39, Reserved. */ /* - */
/* 0x3A, Transmit Command. */
#define TX_CMD_STAT 0x3A /* rw */
#define TX_CMD_STAT_OMIT_CRC (1<<17)
#define TX_CMD_STAT_TX_SHIFT16 (1<<18)
/* 0x3B, Receive Command. */
#define RX_CMD_STAT 0x3B /* rw */
#define RX_CMD_STAT_RX_SHIFT16 (1<<25)
/* 0x3C - 0x3E, Extended Statistics Counters. */
#define ESTATS_MSB_A_OCTETS_TX_OK 0x3C /* ro */
#define ESTATS_MSB_A_OCTETS_RX_OK 0x3D /* ro */
#define ESTATS_MSB_ETHER_STATS_OCTETS 0x3E /* ro */
/* 0x3F, Reserved. */
/* 0x40 - 0x7F, Multicast Hash Table. */
#define MHASH_START 0x40
#define MHASH_LEN 0x3F
/* 0x80 - 0x9F, MDIO Space 0 or PCS Function Configuration. */
#define MDIO_0_START 0x80
/* The following are offsets to the first PCS register at 0x80. */
/* See sys/dev/mii/mii.h. */
#define PCS_CONTROL 0x00 /* rw */
/* Bits 0:4, Reserved. */ /* - */
#define PCS_CONTROL_UNIDIRECTIONAL_ENABLE (1<<5) /* rw */
#define PCS_CONTROL_SPEED_SELECTION (1<<6|1<<13) /* ro */
#define PCS_CONTROL_COLLISION_TEST (1<<7) /* ro */
#define PCS_CONTROL_DUPLEX_MODE (1<<8) /* ro */
#define PCS_CONTROL_RESTART_AUTO_NEGOTIATION (1<<9) /* rw */
#define PCS_CONTROL_ISOLATE (1<<10) /* rw */
#define PCS_CONTROL_POWERDOWN (1<<11) /* rw */
#define PCS_CONTROL_AUTO_NEGOTIATION_ENABLE (1<<12) /* rw */
/* See bit 6 above. */ /* ro */
#define PCS_CONTROL_LOOPBACK (1<<14) /* rw */
#define PCS_CONTROL_RESET (1<<15) /* rw */
#define PCS_STATUS 0x01 /* ro */
#define PCS_STATUS_EXTENDED_CAPABILITY (1<<0) /* ro */
#define PCS_STATUS_JABBER_DETECT (1<<1) /* -, 0 */
#define PCS_STATUS_LINK_STATUS (1<<2) /* ro */
#define PCS_STATUS_AUTO_NEGOTIATION_ABILITY (1<<3) /* ro */
#define PCS_STATUS_REMOTE_FAULT (1<<4) /* -, 0 */
#define PCS_STATUS_AUTO_NEGOTIATION_COMPLETE (1<<5) /* ro */
#define PCS_STATUS_MF_PREAMBLE_SUPPRESSION (1<<6) /* -, 0 */
#define PCS_STATUS_UNIDIRECTIONAL_ABILITY (1<<7) /* ro */
#define PCS_STATUS_EXTENDED_STATUS (1<<8) /* -, 0 */
#define PCS_STATUS_100BASET2_HALF_DUPLEX (1<<9) /* ro */
#define PCS_STATUS_100BASET2_FULL_DUPLEX (1<<10) /* ro */
#define PCS_STATUS_10MBPS_HALF_DUPLEX (1<<11) /* ro */
#define PCS_STATUS_10MBPS_FULL_DUPLEX (1<<12) /* ro */
#define PCS_STATUS_100BASE_X_HALF_DUPLEX (1<<13) /* ro */
#define PCS_STATUS_100BASE_X_FULL_DUPLEX (1<<14) /* ro */
#define PCS_STATUS_100BASE_T4 (1<<15) /* ro */
#define PCS_PHY_IDENTIFIER_0 0x02 /* ro */
#define PCS_PHY_IDENTIFIER_1 0x03 /* ro */
#define PCS_DEV_ABILITY 0x04 /* rw */
/* 1000BASE-X */
/* Bits 0:4, Reserved. */ /* - */
#define PCS_DEV_ABILITY_1000BASE_X_FD (1<<5) /* rw */
#define PCS_DEV_ABILITY_1000BASE_X_HD (1<<6) /* rw */
#define PCS_DEV_ABILITY_1000BASE_X_PS1 (1<<7) /* rw */
#define PCS_DEV_ABILITY_1000BASE_X_PS2 (1<<8) /* rw */
/* Bits 9:11, Reserved. */ /* - */
#define PCS_DEV_ABILITY_1000BASE_X_RF1 (1<<12) /* rw */
#define PCS_DEV_ABILITY_1000BASE_X_RF2 (1<<13) /* rw */
#define PCS_DEV_ABILITY_1000BASE_X_ACK (1<<14) /* rw */
#define PCS_DEV_ABILITY_1000BASE_X_NP (1<<15) /* rw */
#define PCS_PARTNER_ABILITY 0x05 /* ro */
/* 1000BASE-X */
/* Bits 0:4, Reserved. */ /* - */
#define PCS_PARTNER_ABILITY_1000BASE_X_FD (1<<5) /* ro */
#define PCS_PARTNER_ABILITY_1000BASE_X_HD (1<<6) /* ro */
#define PCS_PARTNER_ABILITY_1000BASE_X_PS1 (1<<7) /* ro */
#define PCS_PARTNER_ABILITY_1000BASE_X_PS2 (1<<8) /* ro */
/* Bits 9:11, Reserved. */ /* - */
#define PCS_PARTNER_ABILITY_1000BASE_X_RF1 (1<<12) /* ro */
#define PCS_PARTNER_ABILITY_1000BASE_X_RF2 (1<<13) /* ro */
#define PCS_PARTNER_ABILITY_1000BASE_X_ACK (1<<14) /* ro */
#define PCS_PARTNER_ABILITY_1000BASE_X_NP (1<<15) /* ro */
/* SGMII */
/* Bits 0:9, Reserved. */ /* - */
#define PCS_PARTNER_ABILITY_SGMII_COPPER_SPEED0 (1<<10) /* ro */
#define PCS_PARTNER_ABILITY_SGMII_COPPER_SPEED1 (1<<11) /* ro */
#define PCS_PARTNER_ABILITY_SGMII_COPPER_DUPLEX_STATUS (1<<12) /* ro */
/* Bit 13, Reserved. */ /* - */
#define PCS_PARTNER_ABILITY_SGMII_ACK (1<<14) /* ro */
#define PCS_PARTNER_ABILITY_SGMII_COPPER_LINK_STATUS (1<<15) /* ro */
#define PCS_AN_EXPANSION 0x06 /* ro */
#define PCS_AN_EXPANSION_LINK_PARTNER_AUTO_NEGOTIATION_ABLE (1<<0) /* ro */
#define PCS_AN_EXPANSION_PAGE_RECEIVE (1<<1) /* ro */
#define PCS_AN_EXPANSION_NEXT_PAGE_ABLE (1<<2) /* -, 0 */
/* Bits 3:15, Reserved. */ /* - */
#define PCS_DEVICE_NEXT_PAGE 0x07 /* ro */
#define PCS_PARTNER_NEXT_PAGE 0x08 /* ro */
#define PCS_MASTER_SLAVE_CNTL 0x09 /* ro */
#define PCS_MASTER_SLAVE_STAT 0x0A /* ro */
/* 0x0B - 0x0E, Reserved */ /* - */
#define PCS_EXTENDED_STATUS 0x0F /* ro */
/* Specific Extended Registers. */
#define PCS_EXT_SCRATCH 0x10 /* rw */
#define PCS_EXT_REV 0x11 /* ro */
#define PCS_EXT_LINK_TIMER_0 0x12 /* rw */
#define PCS_EXT_LINK_TIMER_1 0x13 /* rw */
#define PCS_EXT_IF_MODE 0x14 /* rw */
#define PCS_EXT_IF_MODE_SGMII_ENA (1<<0) /* rw */
#define PCS_EXT_IF_MODE_USE_SGMII_AN (1<<1) /* rw */
#define PCS_EXT_IF_MODE_SGMII_SPEED1 (1<<2) /* rw */
#define PCS_EXT_IF_MODE_SGMII_SPEED0 (1<<3) /* rw */
#define PCS_EXT_IF_MODE_SGMII_DUPLEX (1<<4) /* rw */
/* Bits 5:15, Reserved. */ /* - */
#define PCS_EXT_DISABLE_READ_TIMEOUT 0x15 /* rw */
#define PCS_EXT_READ_TIMEOUT 0x16 /* r0 */
/* 0x17-0x1F, Reserved. */
/* 0xA0 - 0xBF, MDIO Space 1. */
#define MDIO_1_START 0xA0
#define ATSE_BMCR MDIO_1_START
/* 0xC0 - 0xC7, Supplementary Address. */
#define SUPPL_ADDR_SMAC_0_0 0xC0 /* rw */
#define SUPPL_ADDR_SMAC_0_1 0xC1 /* rw */
#define SUPPL_ADDR_SMAC_1_0 0xC2 /* rw */
#define SUPPL_ADDR_SMAC_1_1 0xC3 /* rw */
#define SUPPL_ADDR_SMAC_2_0 0xC4 /* rw */
#define SUPPL_ADDR_SMAC_2_1 0xC5 /* rw */
#define SUPPL_ADDR_SMAC_3_0 0xC6 /* rw */
#define SUPPL_ADDR_SMAC_3_1 0xC7 /* rw */
/* 0xC8 - 0xCF, Reserved; set to zero, ignore on read. */
/* 0xD7 - 0xFF, Reserved; set to zero, ignore on read. */
/* -------------------------------------------------------------------------- */
/* DE4 Intel Strata Flash Ethernet Option Bits area. */
/* XXX-BZ this is something a loader will have to handle for us. */
#define ALTERA_ETHERNET_OPTION_BITS_OFF 0x00008000
#define ALTERA_ETHERNET_OPTION_BITS_LEN 0x00007fff
/* -------------------------------------------------------------------------- */
struct atse_softc {
if_t atse_ifp;
struct resource *atse_mem_res;
device_t atse_miibus;
device_t atse_dev;
int atse_unit;
int atse_mem_rid;
int atse_phy_addr;
int atse_if_flags;
bus_addr_t atse_bmcr0;
bus_addr_t atse_bmcr1;
uint32_t atse_flags;
#define ATSE_FLAGS_LINK 0x00000001
#define ATSE_FLAGS_ERROR 0x00000002
#define ATSE_FLAGS_SOP_SEEN 0x00000004
uint8_t atse_eth_addr[ETHER_ADDR_LEN];
#define ATSE_ETH_ADDR_DEF 0x01
#define ATSE_ETH_ADDR_SUPP1 0x02
#define ATSE_ETH_ADDR_SUPP2 0x04
#define ATSE_ETH_ADDR_SUPP3 0x08
#define ATSE_ETH_ADDR_SUPP4 0x10
#define ATSE_ETH_ADDR_ALL 0x1f
int16_t atse_rx_cycles; /* POLLING */
#define RX_CYCLES_IN_INTR 5
uint32_t atse_rx_err[6];
#define ATSE_RX_ERR_FIFO_THRES_EOP 0 /* FIFO threshold reached, on EOP. */
#define ATSE_RX_ERR_ELEN 1 /* Frame/payload length not valid. */
#define ATSE_RX_ERR_CRC32 2 /* CRC-32 error. */
#define ATSE_RX_ERR_FIFO_THRES_TRUNC 3 /* FIFO thresh., truncated frame. */
#define ATSE_RX_ERR_4 4 /* ? */
#define ATSE_RX_ERR_5 5 /* / */
#define ATSE_RX_ERR_MAX 6
struct callout atse_tick;
struct mtx atse_mtx;
device_t dev;
/* xDMA */
xdma_controller_t *xdma_tx;
xdma_channel_t *xchan_tx;
void *ih_tx;
int txcount;
xdma_controller_t *xdma_rx;
xdma_channel_t *xchan_rx;
void *ih_rx;
struct buf_ring *br;
struct mtx br_mtx;
};
int atse_attach(device_t);
int atse_detach_dev(device_t);
void atse_detach_resources(device_t);
int atse_miibus_readreg(device_t, int, int);
int atse_miibus_writereg(device_t, int, int, int);
void atse_miibus_statchg(device_t);
#endif /* _DEV_IF_ATSEREG_H */

View file

@ -1,551 +0,0 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2012-2013, 2016 Robert N. M. Watson
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
* ("CTSRD"), as part of the DARPA CRASH research programme.
*
* 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.
*/
#include <sys/param.h>
#include <sys/bio.h>
#include <sys/bus.h>
#include <sys/condvar.h>
#include <sys/conf.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/rman.h>
#include <sys/stat.h>
#include <sys/systm.h>
#include <sys/uio.h>
#include <geom/geom_disk.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <vm/vm.h>
#include <dev/altera/avgen/altera_avgen.h>
/*
* Generic device driver for allowing read(), write(), and mmap() on
* memory-mapped, Avalon-attached devices. There is no actual dependence on
* Avalon, so conceivably this should just be soc_dev or similar, since many
* system-on-chip bus environments would work fine with the same code.
*/
static d_mmap_t altera_avgen_mmap;
static d_read_t altera_avgen_read;
static d_write_t altera_avgen_write;
#define ALTERA_AVGEN_DEVNAME "altera_avgen"
#define ALTERA_AVGEN_DEVNAME_FMT (ALTERA_AVGEN_DEVNAME "%d")
static struct cdevsw avg_cdevsw = {
.d_version = D_VERSION,
.d_mmap = altera_avgen_mmap,
.d_read = altera_avgen_read,
.d_write = altera_avgen_write,
.d_name = ALTERA_AVGEN_DEVNAME,
};
#define ALTERA_AVGEN_SECTORSIZE 512 /* Not configurable at this time. */
static int
altera_avgen_read(struct cdev *dev, struct uio *uio, int flag)
{
struct altera_avgen_softc *sc;
u_long offset, size;
#ifdef NOTYET
uint64_t v8;
#endif
uint32_t v4;
uint16_t v2;
uint8_t v1;
u_int width;
int error;
sc = dev->si_drv1;
if ((sc->avg_flags & ALTERA_AVALON_FLAG_READ) == 0)
return (EACCES);
width = sc->avg_width;
if (uio->uio_offset < 0 || uio->uio_offset % width != 0 ||
uio->uio_resid % width != 0)
return (ENODEV);
size = rman_get_size(sc->avg_res);
if ((uio->uio_offset + uio->uio_resid < 0) ||
(uio->uio_offset + uio->uio_resid > size))
return (ENODEV);
while (uio->uio_resid > 0) {
offset = uio->uio_offset;
if (offset + width > size)
return (ENODEV);
switch (width) {
case 1:
v1 = bus_read_1(sc->avg_res, offset);
error = uiomove(&v1, sizeof(v1), uio);
break;
case 2:
v2 = bus_read_2(sc->avg_res, offset);
error = uiomove(&v2, sizeof(v2), uio);
break;
case 4:
v4 = bus_read_4(sc->avg_res, offset);
error = uiomove(&v4, sizeof(v4), uio);
break;
#ifdef NOTYET
case 8:
v8 = bus_read_8(sc->avg_res, offset);
error = uiomove(&v8, sizeof(v8), uio);
break;
#endif
default:
panic("%s: unexpected widthment %u", __func__, width);
}
if (error)
return (error);
}
return (0);
}
static int
altera_avgen_write(struct cdev *dev, struct uio *uio, int flag)
{
struct altera_avgen_softc *sc;
u_long offset, size;
#ifdef NOTYET
uint64_t v8;
#endif
uint32_t v4;
uint16_t v2;
uint8_t v1;
u_int width;
int error;
sc = dev->si_drv1;
if ((sc->avg_flags & ALTERA_AVALON_FLAG_WRITE) == 0)
return (EACCES);
width = sc->avg_width;
if (uio->uio_offset < 0 || uio->uio_offset % width != 0 ||
uio->uio_resid % width != 0)
return (ENODEV);
size = rman_get_size(sc->avg_res);
while (uio->uio_resid > 0) {
offset = uio->uio_offset;
if (offset + width > size)
return (ENODEV);
switch (width) {
case 1:
error = uiomove(&v1, sizeof(v1), uio);
if (error)
return (error);
bus_write_1(sc->avg_res, offset, v1);
break;
case 2:
error = uiomove(&v2, sizeof(v2), uio);
if (error)
return (error);
bus_write_2(sc->avg_res, offset, v2);
break;
case 4:
error = uiomove(&v4, sizeof(v4), uio);
if (error)
return (error);
bus_write_4(sc->avg_res, offset, v4);
break;
#ifdef NOTYET
case 8:
error = uiomove(&v8, sizeof(v8), uio);
if (error)
return (error);
bus_write_8(sc->avg_res, offset, v8);
break;
#endif
default:
panic("%s: unexpected width %u", __func__, width);
}
}
return (0);
}
static int
altera_avgen_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr,
int nprot, vm_memattr_t *memattr)
{
struct altera_avgen_softc *sc;
sc = dev->si_drv1;
if (nprot & VM_PROT_READ) {
if ((sc->avg_flags & ALTERA_AVALON_FLAG_MMAP_READ) == 0)
return (EACCES);
}
if (nprot & VM_PROT_WRITE) {
if ((sc->avg_flags & ALTERA_AVALON_FLAG_MMAP_WRITE) == 0)
return (EACCES);
}
if (nprot & VM_PROT_EXECUTE) {
if ((sc->avg_flags & ALTERA_AVALON_FLAG_MMAP_EXEC) == 0)
return (EACCES);
}
if (trunc_page(offset) == offset &&
offset + PAGE_SIZE > offset &&
rman_get_size(sc->avg_res) >= offset + PAGE_SIZE) {
*paddr = rman_get_start(sc->avg_res) + offset;
*memattr = VM_MEMATTR_UNCACHEABLE;
} else
return (ENODEV);
return (0);
}
/*
* NB: We serialise block reads and writes in case the OS is generating
* concurrent I/O against the same block, in which case we want one I/O (or
* another) to win. This is not sufficient to provide atomicity for the
* sector in the presence of a fail stop -- however, we're just writing this
* to non-persistent DRAM .. right?
*/
static void
altera_avgen_disk_strategy(struct bio *bp)
{
struct altera_avgen_softc *sc;
void *data;
long bcount;
daddr_t pblkno;
int error;
sc = bp->bio_disk->d_drv1;
data = bp->bio_data;
bcount = bp->bio_bcount;
pblkno = bp->bio_pblkno;
error = 0;
/*
* Serialize block reads / writes.
*/
mtx_lock(&sc->avg_disk_mtx);
switch (bp->bio_cmd) {
case BIO_READ:
if (!(sc->avg_flags & ALTERA_AVALON_FLAG_GEOM_READ)) {
error = EROFS;
break;
}
switch (sc->avg_width) {
case 1:
bus_read_region_1(sc->avg_res,
bp->bio_pblkno * ALTERA_AVGEN_SECTORSIZE,
(uint8_t *)data, bcount);
break;
case 2:
bus_read_region_2(sc->avg_res,
bp->bio_pblkno * ALTERA_AVGEN_SECTORSIZE,
(uint16_t *)data, bcount / 2);
break;
case 4:
bus_read_region_4(sc->avg_res,
bp->bio_pblkno * ALTERA_AVGEN_SECTORSIZE,
(uint32_t *)data, bcount / 4);
break;
default:
panic("%s: unexpected width %u", __func__,
sc->avg_width);
}
break;
case BIO_WRITE:
if (!(sc->avg_flags & ALTERA_AVALON_FLAG_GEOM_WRITE)) {
biofinish(bp, NULL, EROFS);
break;
}
switch (sc->avg_width) {
case 1:
bus_write_region_1(sc->avg_res,
bp->bio_pblkno * ALTERA_AVGEN_SECTORSIZE,
(uint8_t *)data, bcount);
break;
case 2:
bus_write_region_2(sc->avg_res,
bp->bio_pblkno * ALTERA_AVGEN_SECTORSIZE,
(uint16_t *)data, bcount / 2);
break;
case 4:
bus_write_region_4(sc->avg_res,
bp->bio_pblkno * ALTERA_AVGEN_SECTORSIZE,
(uint32_t *)data, bcount / 4);
break;
default:
panic("%s: unexpected width %u", __func__,
sc->avg_width);
}
break;
default:
error = EOPNOTSUPP;
break;
}
mtx_unlock(&sc->avg_disk_mtx);
biofinish(bp, NULL, error);
}
static int
altera_avgen_process_options(struct altera_avgen_softc *sc,
const char *str_fileio, const char *str_geomio, const char *str_mmapio,
const char *str_devname, int devunit)
{
const char *cp;
device_t dev = sc->avg_dev;
/*
* Check for valid combinations of options.
*/
if (str_fileio == NULL && str_geomio == NULL && str_mmapio == NULL) {
device_printf(dev,
"at least one of %s, %s, or %s must be specified\n",
ALTERA_AVALON_STR_FILEIO, ALTERA_AVALON_STR_GEOMIO,
ALTERA_AVALON_STR_MMAPIO);
return (ENXIO);
}
/*
* Validity check: a device can either be a GEOM device (in which case
* we use GEOM to register the device node), or a special device --
* but not both as that causes a collision in /dev.
*/
if (str_geomio != NULL && (str_fileio != NULL || str_mmapio != NULL)) {
device_printf(dev,
"at most one of %s and (%s or %s) may be specified\n",
ALTERA_AVALON_STR_GEOMIO, ALTERA_AVALON_STR_FILEIO,
ALTERA_AVALON_STR_MMAPIO);
return (ENXIO);
}
/*
* Ensure that a unit is specified if a name is also specified.
*/
if (str_devname == NULL && devunit != -1) {
device_printf(dev, "%s requires %s be specified\n",
ALTERA_AVALON_STR_DEVUNIT, ALTERA_AVALON_STR_DEVNAME);
return (ENXIO);
}
/*
* Extract, digest, and save values.
*/
switch (sc->avg_width) {
case 1:
case 2:
case 4:
#ifdef NOTYET
case 8:
#endif
break;
default:
device_printf(dev, "%s unsupported value %u\n",
ALTERA_AVALON_STR_WIDTH, sc->avg_width);
return (ENXIO);
}
sc->avg_flags = 0;
if (str_fileio != NULL) {
for (cp = str_fileio; *cp != '\0'; cp++) {
switch (*cp) {
case ALTERA_AVALON_CHAR_READ:
sc->avg_flags |= ALTERA_AVALON_FLAG_READ;
break;
case ALTERA_AVALON_CHAR_WRITE:
sc->avg_flags |= ALTERA_AVALON_FLAG_WRITE;
break;
default:
device_printf(dev,
"invalid %s character %c\n",
ALTERA_AVALON_STR_FILEIO, *cp);
return (ENXIO);
}
}
}
if (str_geomio != NULL) {
for (cp = str_geomio; *cp != '\0'; cp++){
switch (*cp) {
case ALTERA_AVALON_CHAR_READ:
sc->avg_flags |= ALTERA_AVALON_FLAG_GEOM_READ;
break;
case ALTERA_AVALON_CHAR_WRITE:
sc->avg_flags |= ALTERA_AVALON_FLAG_GEOM_WRITE;
break;
default:
device_printf(dev,
"invalid %s character %c\n",
ALTERA_AVALON_STR_GEOMIO, *cp);
return (ENXIO);
}
}
}
if (str_mmapio != NULL) {
for (cp = str_mmapio; *cp != '\0'; cp++) {
switch (*cp) {
case ALTERA_AVALON_CHAR_READ:
sc->avg_flags |= ALTERA_AVALON_FLAG_MMAP_READ;
break;
case ALTERA_AVALON_CHAR_WRITE:
sc->avg_flags |=
ALTERA_AVALON_FLAG_MMAP_WRITE;
break;
case ALTERA_AVALON_CHAR_EXEC:
sc->avg_flags |= ALTERA_AVALON_FLAG_MMAP_EXEC;
break;
default:
device_printf(dev,
"invalid %s character %c\n",
ALTERA_AVALON_STR_MMAPIO, *cp);
return (ENXIO);
}
}
}
return (0);
}
int
altera_avgen_attach(struct altera_avgen_softc *sc, const char *str_fileio,
const char *str_geomio, const char *str_mmapio, const char *str_devname,
int devunit)
{
device_t dev = sc->avg_dev;
int error;
error = altera_avgen_process_options(sc, str_fileio, str_geomio,
str_mmapio, str_devname, devunit);
if (error)
return (error);
if (rman_get_size(sc->avg_res) >= PAGE_SIZE || str_mmapio != NULL) {
if (rman_get_size(sc->avg_res) % PAGE_SIZE != 0) {
device_printf(dev,
"memory region not even multiple of page size\n");
return (ENXIO);
}
if (rman_get_start(sc->avg_res) % PAGE_SIZE != 0) {
device_printf(dev, "memory region not page-aligned\n");
return (ENXIO);
}
}
/*
* If a GEOM permission is requested, then create the device via GEOM.
* Otherwise, create a special device. We checked during options
* processing that both weren't requested a once.
*/
if (str_devname != NULL) {
sc->avg_name = strdup(str_devname, M_TEMP);
devunit = sc->avg_unit;
} else
sc->avg_name = strdup(ALTERA_AVGEN_DEVNAME, M_TEMP);
if (sc->avg_flags & (ALTERA_AVALON_FLAG_GEOM_READ |
ALTERA_AVALON_FLAG_GEOM_WRITE)) {
mtx_init(&sc->avg_disk_mtx, "altera_avgen_disk", NULL,
MTX_DEF);
sc->avg_disk = disk_alloc();
sc->avg_disk->d_drv1 = sc;
sc->avg_disk->d_strategy = altera_avgen_disk_strategy;
if (devunit == -1)
devunit = 0;
sc->avg_disk->d_name = sc->avg_name;
sc->avg_disk->d_unit = devunit;
/*
* NB: As avg_res is a multiple of PAGE_SIZE, it is also a
* multiple of ALTERA_AVGEN_SECTORSIZE.
*/
sc->avg_disk->d_sectorsize = ALTERA_AVGEN_SECTORSIZE;
sc->avg_disk->d_mediasize = rman_get_size(sc->avg_res);
sc->avg_disk->d_maxsize = ALTERA_AVGEN_SECTORSIZE;
disk_create(sc->avg_disk, DISK_VERSION);
} else {
/* Device node allocation. */
if (str_devname == NULL) {
str_devname = ALTERA_AVGEN_DEVNAME_FMT;
devunit = sc->avg_unit;
}
if (devunit != -1)
sc->avg_cdev = make_dev(&avg_cdevsw, sc->avg_unit,
UID_ROOT, GID_WHEEL, S_IRUSR | S_IWUSR, "%s%d",
str_devname, devunit);
else
sc->avg_cdev = make_dev(&avg_cdevsw, sc->avg_unit,
UID_ROOT, GID_WHEEL, S_IRUSR | S_IWUSR,
"%s", str_devname);
if (sc->avg_cdev == NULL) {
device_printf(sc->avg_dev, "%s: make_dev failed\n",
__func__);
return (ENXIO);
}
/* XXXRW: Slight race between make_dev(9) and here. */
sc->avg_cdev->si_drv1 = sc;
}
return (0);
}
void
altera_avgen_detach(struct altera_avgen_softc *sc)
{
KASSERT((sc->avg_disk != NULL) || (sc->avg_cdev != NULL),
("%s: neither GEOM nor special device", __func__));
if (sc->avg_disk != NULL) {
disk_gone(sc->avg_disk);
disk_destroy(sc->avg_disk);
free(sc->avg_name, M_TEMP);
mtx_destroy(&sc->avg_disk_mtx);
} else {
destroy_dev(sc->avg_cdev);
}
}

View file

@ -1,96 +0,0 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2012, 2016 Robert N. M. Watson
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
* ("CTSRD"), as part of the DARPA CRASH research programme.
*
* 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.
*/
#ifndef _DEV_ALTERA_AVALON_H_
#define _DEV_ALTERA_AVALON_H_
struct altera_avgen_softc {
/*
* Bus-related fields.
*/
device_t avg_dev;
int avg_unit;
char *avg_name;
/*
* The device node and memory-mapped I/O region.
*/
struct cdev *avg_cdev;
struct resource *avg_res;
int avg_rid;
/*
* Access properties configured by device.hints.
*/
u_int avg_flags;
u_int avg_width;
u_int avg_sectorsize;
/*
* disk(9) state, if required for this device.
*/
struct disk *avg_disk;
struct mtx avg_disk_mtx;
};
/*
* Various flags extracted from device.hints to configure operations on the
* device.
*/
#define ALTERA_AVALON_FLAG_READ 0x01
#define ALTERA_AVALON_FLAG_WRITE 0x02
#define ALTERA_AVALON_FLAG_MMAP_READ 0x04
#define ALTERA_AVALON_FLAG_MMAP_WRITE 0x08
#define ALTERA_AVALON_FLAG_MMAP_EXEC 0x10
#define ALTERA_AVALON_FLAG_GEOM_READ 0x20
#define ALTERA_AVALON_FLAG_GEOM_WRITE 0x40
#define ALTERA_AVALON_CHAR_READ 'r'
#define ALTERA_AVALON_CHAR_WRITE 'w'
#define ALTERA_AVALON_CHAR_EXEC 'x'
#define ALTERA_AVALON_STR_WIDTH "width"
#define ALTERA_AVALON_STR_FILEIO "fileio"
#define ALTERA_AVALON_STR_GEOMIO "geomio"
#define ALTERA_AVALON_STR_MMAPIO "mmapio"
#define ALTERA_AVALON_STR_DEVNAME "devname"
#define ALTERA_AVALON_STR_DEVUNIT "devunit"
/*
* Driver setup routines from the bus attachment/teardown.
*/
int altera_avgen_attach(struct altera_avgen_softc *sc,
const char *str_fileio, const char *str_geomio,
const char *str_mmapio, const char *str_devname, int devunit);
void altera_avgen_detach(struct altera_avgen_softc *sc);
#endif /* _DEV_ALTERA_AVALON_H_ */

View file

@ -1,159 +0,0 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2012-2013, 2016 Robert N. M. Watson
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
* ("CTSRD"), as part of the DARPA CRASH research programme.
*
* 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.
*/
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/condvar.h>
#include <sys/conf.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/rman.h>
#include <sys/stat.h>
#include <sys/systm.h>
#include <sys/uio.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <vm/vm.h>
#include <dev/fdt/fdt_common.h>
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
#include <dev/altera/avgen/altera_avgen.h>
static int
altera_avgen_fdt_probe(device_t dev)
{
if (!ofw_bus_status_okay(dev))
return (ENXIO);
if (ofw_bus_is_compatible(dev, "sri-cambridge,avgen")) {
device_set_desc(dev, "Generic Altera Avalon device attachment");
return (BUS_PROBE_DEFAULT);
}
return (ENXIO);
}
static int
altera_avgen_fdt_attach(device_t dev)
{
struct altera_avgen_softc *sc;
char *str_fileio, *str_geomio, *str_mmapio;
char *str_devname;
phandle_t node;
pcell_t cell;
int devunit, error;
sc = device_get_softc(dev);
sc->avg_dev = dev;
sc->avg_unit = device_get_unit(dev);
/*
* Query driver-specific OpenFirmware properties to determine how to
* expose the device via /dev.
*/
str_fileio = NULL;
str_geomio = NULL;
str_mmapio = NULL;
str_devname = NULL;
devunit = -1;
sc->avg_width = 1;
node = ofw_bus_get_node(dev);
if (OF_getprop(node, "sri-cambridge,width", &cell, sizeof(cell)) > 0)
sc->avg_width = cell;
(void)OF_getprop_alloc(node, "sri-cambridge,fileio",
(void **)&str_fileio);
(void)OF_getprop_alloc(node, "sri-cambridge,geomio",
(void **)&str_geomio);
(void)OF_getprop_alloc(node, "sri-cambridge,mmapio",
(void **)&str_mmapio);
(void)OF_getprop_alloc(node, "sri-cambridge,devname",
(void **)&str_devname);
if (OF_getprop(node, "sri-cambridge,devunit", &cell, sizeof(cell)) > 0)
devunit = cell;
/* Memory allocation and checking. */
sc->avg_rid = 0;
sc->avg_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
&sc->avg_rid, RF_ACTIVE);
if (sc->avg_res == NULL) {
device_printf(dev, "couldn't map memory\n");
return (ENXIO);
}
error = altera_avgen_attach(sc, str_fileio, str_geomio, str_mmapio,
str_devname, devunit);
if (error != 0)
bus_release_resource(dev, SYS_RES_MEMORY, sc->avg_rid,
sc->avg_res);
if (str_fileio != NULL)
OF_prop_free(str_fileio);
if (str_geomio != NULL)
OF_prop_free(str_geomio);
if (str_mmapio != NULL)
OF_prop_free(str_mmapio);
if (str_devname != NULL)
OF_prop_free(str_devname);
return (error);
}
static int
altera_avgen_fdt_detach(device_t dev)
{
struct altera_avgen_softc *sc;
sc = device_get_softc(dev);
altera_avgen_detach(sc);
bus_release_resource(dev, SYS_RES_MEMORY, sc->avg_rid, sc->avg_res);
return (0);
}
static device_method_t altera_avgen_fdt_methods[] = {
DEVMETHOD(device_probe, altera_avgen_fdt_probe),
DEVMETHOD(device_attach, altera_avgen_fdt_attach),
DEVMETHOD(device_detach, altera_avgen_fdt_detach),
{ 0, 0 }
};
static driver_t altera_avgen_fdt_driver = {
"altera_avgen",
altera_avgen_fdt_methods,
sizeof(struct altera_avgen_softc),
};
DRIVER_MODULE(avgen, simplebus, altera_avgen_fdt_driver, 0, 0);

View file

@ -1,141 +0,0 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2012-2013, 2016 Robert N. M. Watson
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
* ("CTSRD"), as part of the DARPA CRASH research programme.
*
* 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.
*/
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/condvar.h>
#include <sys/conf.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/rman.h>
#include <sys/stat.h>
#include <sys/systm.h>
#include <sys/uio.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <vm/vm.h>
#include <dev/altera/avgen/altera_avgen.h>
static int
altera_avgen_nexus_probe(device_t dev)
{
device_set_desc(dev, "Generic Altera Avalon device attachment");
return (BUS_PROBE_NOWILDCARD);
}
static int
altera_avgen_nexus_attach(device_t dev)
{
struct altera_avgen_softc *sc;
const char *str_fileio, *str_geomio, *str_mmapio;
const char *str_devname;
int devunit, error;
sc = device_get_softc(dev);
sc->avg_dev = dev;
sc->avg_unit = device_get_unit(dev);
/*
* Query non-standard hints to find out what operations are permitted
* on the device, and whether it is cached.
*/
str_fileio = NULL;
str_geomio = NULL;
str_mmapio = NULL;
str_devname = NULL;
devunit = -1;
sc->avg_width = 1;
error = resource_int_value(device_get_name(dev), device_get_unit(dev),
ALTERA_AVALON_STR_WIDTH, &sc->avg_width);
if (error != 0 && error != ENOENT) {
device_printf(dev, "invalid %s\n", ALTERA_AVALON_STR_WIDTH);
return (error);
}
(void)resource_string_value(device_get_name(dev),
device_get_unit(dev), ALTERA_AVALON_STR_FILEIO, &str_fileio);
(void)resource_string_value(device_get_name(dev),
device_get_unit(dev), ALTERA_AVALON_STR_GEOMIO, &str_geomio);
(void)resource_string_value(device_get_name(dev),
device_get_unit(dev), ALTERA_AVALON_STR_MMAPIO, &str_mmapio);
(void)resource_string_value(device_get_name(dev),
device_get_unit(dev), ALTERA_AVALON_STR_DEVNAME, &str_devname);
(void)resource_int_value(device_get_name(dev), device_get_unit(dev),
ALTERA_AVALON_STR_DEVUNIT, &devunit);
/* Memory allocation and checking. */
sc->avg_rid = 0;
sc->avg_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
&sc->avg_rid, RF_ACTIVE);
if (sc->avg_res == NULL) {
device_printf(dev, "couldn't map memory\n");
return (ENXIO);
}
error = altera_avgen_attach(sc, str_fileio, str_geomio, str_mmapio,
str_devname, devunit);
if (error != 0)
bus_release_resource(dev, SYS_RES_MEMORY, sc->avg_rid,
sc->avg_res);
return (error);
}
static int
altera_avgen_nexus_detach(device_t dev)
{
struct altera_avgen_softc *sc;
sc = device_get_softc(dev);
altera_avgen_detach(sc);
bus_release_resource(dev, SYS_RES_MEMORY, sc->avg_rid, sc->avg_res);
return (0);
}
static device_method_t altera_avgen_nexus_methods[] = {
DEVMETHOD(device_probe, altera_avgen_nexus_probe),
DEVMETHOD(device_attach, altera_avgen_nexus_attach),
DEVMETHOD(device_detach, altera_avgen_nexus_detach),
{ 0, 0 }
};
static driver_t altera_avgen_nexus_driver = {
"altera_avgen",
altera_avgen_nexus_methods,
sizeof(struct altera_avgen_softc),
};
DRIVER_MODULE(avgen, nexus, altera_avgen_nexus_driver, 0, 0);

View file

@ -1,197 +0,0 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2011-2012 Robert N. M. Watson
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
* ("CTSRD"), as part of the DARPA CRASH research programme.
*
* 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.
*/
#ifndef _DEV_ALTERA_JTAG_UART_H_
#define _DEV_ALTERA_JTAG_UART_H_
struct altera_jtag_uart_softc {
device_t ajus_dev;
int ajus_unit;
/*
* Hardware resources.
*/
struct resource *ajus_irq_res;
int ajus_irq_rid;
void *ajus_irq_cookie;
struct resource *ajus_mem_res;
int ajus_mem_rid;
/*
* TTY resources.
*/
struct tty *ajus_ttyp;
int ajus_alt_break_state;
/*
* Driver resources.
*/
u_int ajus_flags;
struct mtx *ajus_lockp;
struct mtx ajus_lock;
struct callout ajus_io_callout;
struct callout ajus_ac_callout;
/*
* One-character buffer required because it's not possible to peek at
* the input FIFO without reading it.
*/
int ajus_buffer_valid;
int *ajus_buffer_validp;
uint8_t ajus_buffer_data;
uint8_t *ajus_buffer_datap;
int ajus_jtag_present;
int *ajus_jtag_presentp;
u_int ajus_jtag_missed;
u_int *ajus_jtag_missedp;
};
#define AJU_TTYNAME "ttyj"
/*
* Flag values for ajus_flags.
*/
#define ALTERA_JTAG_UART_FLAG_CONSOLE 0x00000001 /* Is console. */
/*
* Because tty-level use of the I/O ports completes with low-level console
* use, spinlocks must be employed here.
*/
#define AJU_CONSOLE_LOCK_INIT() do { \
mtx_init(&aju_cons_lock, "aju_cons_lock", NULL, MTX_SPIN); \
} while (0)
#define AJU_CONSOLE_LOCK() do { \
if (!kdb_active) \
mtx_lock_spin(&aju_cons_lock); \
} while (0)
#define AJU_CONSOLE_LOCK_ASSERT() { \
if (!kdb_active) \
mtx_assert(&aju_cons_lock, MA_OWNED); \
} while (0)
#define AJU_CONSOLE_UNLOCK() do { \
if (!kdb_active) \
mtx_unlock_spin(&aju_cons_lock); \
} while (0)
#define AJU_LOCK_INIT(sc) do { \
mtx_init(&(sc)->ajus_lock, "aju_lock", NULL, MTX_SPIN); \
} while (0)
#define AJU_LOCK_DESTROY(sc) do { \
mtx_destroy(&(sc)->ajus_lock); \
} while (0)
#define AJU_LOCK(sc) do { \
mtx_lock_spin((sc)->ajus_lockp); \
} while (0)
#define AJU_LOCK_ASSERT(sc) do { \
mtx_assert((sc)->ajus_lockp, MA_OWNED); \
} while (0)
#define AJU_UNLOCK(sc) do { \
mtx_unlock_spin((sc)->ajus_lockp); \
} while (0)
/*
* When a TTY-level Altera JTAG UART instance is also the low-level console,
* the TTY layer borrows the console-layer lock and buffer rather than using
* its own.
*/
extern struct mtx aju_cons_lock;
extern char aju_cons_buffer_data;
extern int aju_cons_buffer_valid;
extern int aju_cons_jtag_present;
extern u_int aju_cons_jtag_missed;
/*
* Base physical address of the JTAG UART in BERI.
*/
#define BERI_UART_BASE 0x7f000000 /* JTAG UART */
/*-
* Routines for interacting with the BERI console JTAG UART. Programming
* details from the June 2011 "Embedded Peripherals User Guide" by Altera
* Corporation, tables 6-2 (JTAG UART Core Register Map), 6-3 (Data Register
* Bits), and 6-4 (Control Register Bits).
*
* Offsets of data and control registers relative to the base. Altera
* conventions are maintained in BERI.
*/
#define ALTERA_JTAG_UART_DATA_OFF 0x00000000
#define ALTERA_JTAG_UART_CONTROL_OFF 0x00000004
/*
* Offset 0: 'data' register -- bits 31-16 (RAVAIL), 15 (RVALID),
* 14-8 (Reserved), 7-0 (DATA).
*
* DATA - One byte read or written.
* RAVAIL - Bytes available to read (excluding the current byte).
* RVALID - Whether the byte in DATA is valid.
*/
#define ALTERA_JTAG_UART_DATA_DATA 0x000000ff
#define ALTERA_JTAG_UART_DATA_RESERVED 0x00007f00
#define ALTERA_JTAG_UART_DATA_RVALID 0x00008000
#define ALTERA_JTAG_UART_DATA_RAVAIL 0xffff0000
#define ALTERA_JTAG_UART_DATA_RAVAIL_SHIFT 16
/*-
* Offset 1: 'control' register -- bits 31-16 (WSPACE), 15-11 (Reserved),
* 10 (AC), 9 (WI), 8 (RI), 7..2 (Reserved), 1 (WE), 0 (RE).
*
* RE - Enable read interrupts.
* WE - Enable write interrupts.
* RI - Read interrupt pending.
* WI - Write interrupt pending.
* AC - Activity bit; set to '1' to clear to '0'.
* WSPACE - Space available in the write FIFO.
*/
#define ALTERA_JTAG_UART_CONTROL_RE 0x00000001
#define ALTERA_JTAG_UART_CONTROL_WE 0x00000002
#define ALTERA_JTAG_UART_CONTROL_RESERVED0 0x000000fc
#define ALTERA_JTAG_UART_CONTROL_RI 0x00000100
#define ALTERA_JTAG_UART_CONTROL_WI 0x00000200
#define ALTERA_JTAG_UART_CONTROL_AC 0x00000400
#define ALTERA_JTAG_UART_CONTROL_RESERVED1 0x0000f800
#define ALTERA_JTAG_UART_CONTROL_WSPACE 0xffff0000
#define ALTERA_JTAG_UART_CONTROL_WSPACE_SHIFT 16
/*
* Driver attachment functions for Nexus.
*/
int altera_jtag_uart_attach(struct altera_jtag_uart_softc *sc);
void altera_jtag_uart_detach(struct altera_jtag_uart_softc *sc);
#endif /* _DEV_ALTERA_JTAG_UART_H_ */

View file

@ -1,331 +0,0 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2011-2012 Robert N. M. Watson
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
* ("CTSRD"), as part of the DARPA CRASH research programme.
*
* 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.
*/
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/cons.h>
#include <sys/endian.h>
#include <sys/kdb.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/reboot.h>
#include <sys/sysctl.h>
#include <sys/systm.h>
#include <sys/tty.h>
#include <ddb/ddb.h>
#include <dev/altera/jtag_uart/altera_jtag_uart.h>
static SYSCTL_NODE(_hw, OID_AUTO, altera_jtag_uart,
CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
"Altera JTAG UART configuration knobs");
/*
* One-byte buffer as we can't check whether the UART is readable without
* actually reading from it, synchronised by a spinlock; this lock also
* synchronises access to the I/O ports for non-atomic sequences. These
* symbols are public so that the TTY layer can use them when working on an
* instance of the UART that is also a low-level console.
*/
char aju_cons_buffer_data;
int aju_cons_buffer_valid;
int aju_cons_jtag_present;
u_int aju_cons_jtag_missed;
struct mtx aju_cons_lock;
/*
* Low-level console driver functions.
*/
static cn_probe_t aju_cnprobe;
static cn_init_t aju_cninit;
static cn_term_t aju_cnterm;
static cn_getc_t aju_cngetc;
static cn_putc_t aju_cnputc;
static cn_grab_t aju_cngrab;
static cn_ungrab_t aju_cnungrab;
/*
* JTAG sets the ALTERA_JTAG_UART_CONTROL_AC bit whenever it accesses the
* FIFO. This allows us to (sort of) tell when JTAG is present, so that we
* can adopt lossy, rather than blocking, behaviour when JTAG isn't there.
* When it is present, we do full flow control. This delay is how long we
* wait to see if JTAG has really disappeared when finding a full buffer and
* no AC bit set.
*/
#define ALTERA_JTAG_UART_AC_POLL_DELAY 10000
static u_int altera_jtag_uart_ac_poll_delay =
ALTERA_JTAG_UART_AC_POLL_DELAY;
SYSCTL_UINT(_hw_altera_jtag_uart, OID_AUTO, ac_poll_delay,
CTLFLAG_RW, &altera_jtag_uart_ac_poll_delay, 0,
"Maximum delay waiting for JTAG present flag when buffer is full");
/*
* I/O routines lifted from Deimos. This is not only MIPS-specific, but also
* BERI-specific, as we're hard coding the address at which we expect to
* find the Altera JTAG UART and using it unconditionally. We use these
* low-level routines so that we can perform console I/O long before newbus
* has initialised and devices have attached. The TTY layer of the driver
* knows about this, and uses the console-layer spinlock instead of the
* TTY-layer lock to avoid confusion between layers for the console UART.
*
* XXXRW: The only place this inter-layer behaviour breaks down is if the
* low-level console is used for polled read while the TTY driver is also
* looking for input. Probably we should also share buffers between layers.
*/
#define MIPS_XKPHYS_UNCACHED_BASE 0x9000000000000000
typedef uint64_t paddr_t;
typedef uint64_t vaddr_t;
static inline vaddr_t
mips_phys_to_uncached(paddr_t phys)
{
return (phys | MIPS_XKPHYS_UNCACHED_BASE);
}
static inline uint32_t
mips_ioread_uint32(vaddr_t vaddr)
{
uint32_t v;
__asm__ __volatile__ ("lw %0, 0(%1)" : "=r" (v) : "r" (vaddr));
return (v);
}
static inline void
mips_iowrite_uint32(vaddr_t vaddr, uint32_t v)
{
__asm__ __volatile__ ("sw %0, 0(%1)" : : "r" (v), "r" (vaddr));
}
/*
* Little-endian versions of 32-bit I/O routines.
*/
static inline uint32_t
mips_ioread_uint32le(vaddr_t vaddr)
{
return (le32toh(mips_ioread_uint32(vaddr)));
}
static inline void
mips_iowrite_uint32le(vaddr_t vaddr, uint32_t v)
{
mips_iowrite_uint32(vaddr, htole32(v));
}
/*
* Low-level read and write register routines; the Altera UART is little
* endian, so we byte swap 32-bit reads and writes.
*/
static inline uint32_t
aju_cons_data_read(void)
{
return (mips_ioread_uint32le(mips_phys_to_uncached(BERI_UART_BASE +
ALTERA_JTAG_UART_DATA_OFF)));
}
static inline void
aju_cons_data_write(uint32_t v)
{
mips_iowrite_uint32le(mips_phys_to_uncached(BERI_UART_BASE +
ALTERA_JTAG_UART_DATA_OFF), v);
}
static inline uint32_t
aju_cons_control_read(void)
{
return (mips_ioread_uint32le(mips_phys_to_uncached(BERI_UART_BASE +
ALTERA_JTAG_UART_CONTROL_OFF)));
}
static inline void
aju_cons_control_write(uint32_t v)
{
mips_iowrite_uint32le(mips_phys_to_uncached(BERI_UART_BASE +
ALTERA_JTAG_UART_CONTROL_OFF), v);
}
/*
* Slightly higher-level routines aware of buffering and flow control.
*/
static int
aju_cons_readable(void)
{
uint32_t v;
AJU_CONSOLE_LOCK_ASSERT();
if (aju_cons_buffer_valid)
return (1);
v = aju_cons_data_read();
if ((v & ALTERA_JTAG_UART_DATA_RVALID) != 0) {
aju_cons_buffer_valid = 1;
aju_cons_buffer_data = (v & ALTERA_JTAG_UART_DATA_DATA);
return (1);
}
return (0);
}
static void
aju_cons_write(char ch)
{
uint32_t v;
AJU_CONSOLE_LOCK_ASSERT();
/*
* The flow control logic here is somewhat subtle: we want to wait for
* write buffer space only while JTAG is present. However, we can't
* directly ask if JTAG is present -- just whether it's been seen
* since we last cleared the ALTERA_JTAG_UART_CONTROL_AC bit. As
* such, implement a polling loop in which we both wait for space and
* try to decide whether JTAG has disappeared on us. We will have to
* wait one complete polling delay to detect that JTAG has gone away,
* but otherwise shouldn't wait any further once it has gone. And we
* had to wait for buffer space anyway, if it was there.
*
* If JTAG is spotted, reset the TTY-layer miss counter so console-
* layer clearing of the bit doesn't trigger a TTY-layer
* disconnection.
*
* XXXRW: Notice the inherent race with hardware: in clearing the
* bit, we may race with hardware setting the same bit. This can
* cause real-world reliability problems due to lost output on the
* console.
*/
v = aju_cons_control_read();
if (v & ALTERA_JTAG_UART_CONTROL_AC) {
aju_cons_jtag_present = 1;
aju_cons_jtag_missed = 0;
v &= ~ALTERA_JTAG_UART_CONTROL_AC;
aju_cons_control_write(v);
}
while ((v & ALTERA_JTAG_UART_CONTROL_WSPACE) == 0) {
if (!aju_cons_jtag_present)
return;
DELAY(altera_jtag_uart_ac_poll_delay);
v = aju_cons_control_read();
if (v & ALTERA_JTAG_UART_CONTROL_AC) {
aju_cons_jtag_present = 1;
v &= ~ALTERA_JTAG_UART_CONTROL_AC;
aju_cons_control_write(v);
} else
aju_cons_jtag_present = 0;
}
aju_cons_data_write(ch);
}
static char
aju_cons_read(void)
{
AJU_CONSOLE_LOCK_ASSERT();
while (!aju_cons_readable());
aju_cons_buffer_valid = 0;
return (aju_cons_buffer_data);
}
/*
* Implementation of a FreeBSD low-level, polled console driver.
*/
static void
aju_cnprobe(struct consdev *cp)
{
sprintf(cp->cn_name, "%s%d", AJU_TTYNAME, 0);
cp->cn_pri = (boothowto & RB_SERIAL) ? CN_REMOTE : CN_NORMAL;
}
static void
aju_cninit(struct consdev *cp)
{
uint32_t v;
AJU_CONSOLE_LOCK_INIT();
AJU_CONSOLE_LOCK();
v = aju_cons_control_read();
v &= ~ALTERA_JTAG_UART_CONTROL_AC;
aju_cons_control_write(v);
AJU_CONSOLE_UNLOCK();
}
static void
aju_cnterm(struct consdev *cp)
{
}
static int
aju_cngetc(struct consdev *cp)
{
int ret;
AJU_CONSOLE_LOCK();
ret = aju_cons_read();
AJU_CONSOLE_UNLOCK();
return (ret);
}
static void
aju_cnputc(struct consdev *cp, int c)
{
AJU_CONSOLE_LOCK();
aju_cons_write(c);
AJU_CONSOLE_UNLOCK();
}
static void
aju_cngrab(struct consdev *cp)
{
}
static void
aju_cnungrab(struct consdev *cp)
{
}
CONSOLE_DRIVER(aju);

View file

@ -1,148 +0,0 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2012 Robert N. M. Watson
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
* ("CTSRD"), as part of the DARPA CRASH research programme.
*
* 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.
*/
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/condvar.h>
#include <sys/conf.h>
#include <sys/bio.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/rman.h>
#include <sys/systm.h>
#include <sys/taskqueue.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <geom/geom_disk.h>
#include <dev/altera/jtag_uart/altera_jtag_uart.h>
#include <dev/fdt/fdt_common.h>
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
/*
* FDT bus attachment for Altera JTAG UARTs.
*/
static int
altera_jtag_uart_fdt_probe(device_t dev)
{
if (!ofw_bus_status_okay(dev))
return (ENXIO);
if (ofw_bus_is_compatible(dev, "altera,jtag_uart-11_0")) {
device_set_desc(dev, "Altera JTAG UART");
return (BUS_PROBE_DEFAULT);
}
return (ENXIO);
}
static int
altera_jtag_uart_fdt_attach(device_t dev)
{
struct altera_jtag_uart_softc *sc;
int error;
error = 0;
sc = device_get_softc(dev);
sc->ajus_dev = dev;
sc->ajus_unit = device_get_unit(dev);
sc->ajus_mem_rid = 0;
sc->ajus_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
&sc->ajus_mem_rid, RF_ACTIVE);
if (sc->ajus_mem_res == NULL) {
device_printf(dev, "couldn't map memory\n");
error = ENXIO;
goto out;
}
/*
* Interrupt support is optional -- if we can't allocate an IRQ, then
* we fall back on polling.
*/
sc->ajus_irq_rid = 0;
sc->ajus_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
&sc->ajus_irq_rid, RF_ACTIVE | RF_SHAREABLE);
if (sc->ajus_irq_res == NULL)
device_printf(dev,
"IRQ unavailable; selecting polled operation\n");
error = altera_jtag_uart_attach(sc);
out:
if (error) {
if (sc->ajus_irq_res != NULL)
bus_release_resource(dev, SYS_RES_IRQ,
sc->ajus_irq_rid, sc->ajus_irq_res);
if (sc->ajus_mem_res != NULL)
bus_release_resource(dev, SYS_RES_MEMORY,
sc->ajus_mem_rid, sc->ajus_mem_res);
}
return (error);
}
static int
altera_jtag_uart_fdt_detach(device_t dev)
{
struct altera_jtag_uart_softc *sc;
sc = device_get_softc(dev);
KASSERT(sc->ajus_mem_res != NULL, ("%s: resources not allocated",
__func__));
altera_jtag_uart_detach(sc);
bus_release_resource(dev, SYS_RES_IRQ, sc->ajus_irq_rid,
sc->ajus_irq_res);
bus_release_resource(dev, SYS_RES_MEMORY, sc->ajus_mem_rid,
sc->ajus_mem_res);
return (0);
}
static device_method_t altera_jtag_uart_fdt_methods[] = {
DEVMETHOD(device_probe, altera_jtag_uart_fdt_probe),
DEVMETHOD(device_attach, altera_jtag_uart_fdt_attach),
DEVMETHOD(device_detach, altera_jtag_uart_fdt_detach),
{ 0, 0 }
};
static driver_t altera_jtag_uart_fdt_driver = {
"altera_jtag_uart",
altera_jtag_uart_fdt_methods,
sizeof(struct altera_jtag_uart_softc),
};
DRIVER_MODULE(altera_jtag_uart, simplebus, altera_jtag_uart_fdt_driver, 0, 0);

View file

@ -1,139 +0,0 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2012 Robert N. M. Watson
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
* ("CTSRD"), as part of the DARPA CRASH research programme.
*
* 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.
*/
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/condvar.h>
#include <sys/conf.h>
#include <sys/bio.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/rman.h>
#include <sys/systm.h>
#include <sys/taskqueue.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <geom/geom_disk.h>
#include <dev/altera/jtag_uart/altera_jtag_uart.h>
/*
* Nexus bus attachment for Altera JTAG UARTs. Appropriate for most Altera
* FPGA SoC-style configurations in which the IP core will be exposed to the
* processor via a memory-mapped Avalon bus.
*/
static int
altera_jtag_uart_nexus_probe(device_t dev)
{
device_set_desc(dev, "Altera JTAG UART");
return (BUS_PROBE_NOWILDCARD);
}
static int
altera_jtag_uart_nexus_attach(device_t dev)
{
struct altera_jtag_uart_softc *sc;
int error;
error = 0;
sc = device_get_softc(dev);
sc->ajus_dev = dev;
sc->ajus_unit = device_get_unit(dev);
sc->ajus_mem_rid = 0;
sc->ajus_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
&sc->ajus_mem_rid, RF_ACTIVE);
if (sc->ajus_mem_res == NULL) {
device_printf(dev, "couldn't map memory\n");
error = ENXIO;
goto out;
}
/*
* Interrupt support is optional -- if we can't allocate an IRQ, then
* we fall back on polling.
*/
sc->ajus_irq_rid = 0;
sc->ajus_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
&sc->ajus_irq_rid, RF_ACTIVE | RF_SHAREABLE);
if (sc->ajus_irq_res == NULL)
device_printf(dev,
"IRQ unavailable; selecting polled operation\n");
error = altera_jtag_uart_attach(sc);
out:
if (error) {
if (sc->ajus_irq_res != NULL)
bus_release_resource(dev, SYS_RES_IRQ,
sc->ajus_irq_rid, sc->ajus_irq_res);
if (sc->ajus_mem_res != NULL)
bus_release_resource(dev, SYS_RES_MEMORY,
sc->ajus_mem_rid, sc->ajus_mem_res);
}
return (error);
}
static int
altera_jtag_uart_nexus_detach(device_t dev)
{
struct altera_jtag_uart_softc *sc;
sc = device_get_softc(dev);
KASSERT(sc->ajus_mem_res != NULL, ("%s: resources not allocated",
__func__));
altera_jtag_uart_detach(sc);
bus_release_resource(dev, SYS_RES_IRQ, sc->ajus_irq_rid,
sc->ajus_irq_res);
bus_release_resource(dev, SYS_RES_MEMORY, sc->ajus_mem_rid,
sc->ajus_mem_res);
return (0);
}
static device_method_t altera_jtag_uart_nexus_methods[] = {
DEVMETHOD(device_probe, altera_jtag_uart_nexus_probe),
DEVMETHOD(device_attach, altera_jtag_uart_nexus_attach),
DEVMETHOD(device_detach, altera_jtag_uart_nexus_detach),
{ 0, 0 }
};
static driver_t altera_jtag_uart_nexus_driver = {
"altera_jtag_uart",
altera_jtag_uart_nexus_methods,
sizeof(struct altera_jtag_uart_softc),
};
DRIVER_MODULE(altera_jtag_uart, nexus, altera_jtag_uart_nexus_driver, 0, 0);

View file

@ -1,561 +0,0 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2011-2012, 2016 Robert N. M. Watson
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
* ("CTSRD"), as part of the DARPA CRASH research programme.
*
* 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.
*/
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/cons.h>
#include <sys/endian.h>
#include <sys/kdb.h>
#include <sys/rman.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/reboot.h>
#include <sys/sysctl.h>
#include <sys/tty.h>
#include <ddb/ddb.h>
#include <machine/atomic.h>
#include <machine/bus.h>
#include <dev/altera/jtag_uart/altera_jtag_uart.h>
/*
* If one of the Altera JTAG UARTs is currently the system console, register
* it here.
*/
static struct altera_jtag_uart_softc *aju_cons_sc;
static tsw_outwakeup_t aju_outwakeup;
static void aju_ac_callout(void *);
static void aju_io_callout(void *);
static struct ttydevsw aju_ttydevsw = {
.tsw_flags = TF_NOPREFIX,
.tsw_outwakeup = aju_outwakeup,
};
/*
* When polling for the AC bit, the number of times we have to not see it
* before assuming JTAG has disappeared on us. By default, four seconds.
*/
#define AJU_JTAG_MAXMISS 20
/*
* Polling intervals for input/output and JTAG connection events.
*/
#define AJU_IO_POLLINTERVAL (hz/100)
#define AJU_AC_POLLINTERVAL (hz/5)
/*
* Statistics on JTAG removal events when sending, for debugging purposes
* only.
*/
static u_int aju_jtag_vanished;
SYSCTL_UINT(_debug, OID_AUTO, aju_jtag_vanished, CTLFLAG_RW,
&aju_jtag_vanished, 0, "Number of times JTAG has vanished");
static u_int aju_jtag_appeared;
SYSCTL_UINT(_debug, OID_AUTO, aju_jtag_appeared, CTLFLAG_RW,
&aju_jtag_appeared, 0, "Number of times JTAG has appeared");
SYSCTL_INT(_debug, OID_AUTO, aju_cons_jtag_present, CTLFLAG_RW,
&aju_cons_jtag_present, 0, "JTAG console present flag");
SYSCTL_UINT(_debug, OID_AUTO, aju_cons_jtag_missed, CTLFLAG_RW,
&aju_cons_jtag_missed, 0, "JTAG console missed counter");
/*
* Interrupt-related statistics.
*/
static u_int aju_intr_readable_enabled;
SYSCTL_UINT(_debug, OID_AUTO, aju_intr_readable_enabled, CTLFLAG_RW,
&aju_intr_readable_enabled, 0, "Number of times read interrupt enabled");
static u_int aju_intr_writable_disabled;
SYSCTL_UINT(_debug, OID_AUTO, aju_intr_writable_disabled, CTLFLAG_RW,
&aju_intr_writable_disabled, 0,
"Number of times write interrupt disabled");
static u_int aju_intr_writable_enabled;
SYSCTL_UINT(_debug, OID_AUTO, aju_intr_writable_enabled, CTLFLAG_RW,
&aju_intr_writable_enabled, 0,
"Number of times write interrupt enabled");
static u_int aju_intr_disabled;
SYSCTL_UINT(_debug, OID_AUTO, aju_intr_disabled, CTLFLAG_RW,
&aju_intr_disabled, 0, "Number of times write interrupt disabled");
static u_int aju_intr_read_count;
SYSCTL_UINT(_debug, OID_AUTO, aju_intr_read_count, CTLFLAG_RW,
&aju_intr_read_count, 0, "Number of times read interrupt fired");
static u_int aju_intr_write_count;
SYSCTL_UINT(_debug, OID_AUTO, aju_intr_write_count, CTLFLAG_RW,
&aju_intr_write_count, 0, "Number of times write interrupt fired");
/*
* Low-level read and write register routines; the Altera UART is little
* endian, so we byte swap 32-bit reads and writes.
*/
static inline uint32_t
aju_data_read(struct altera_jtag_uart_softc *sc)
{
return (le32toh(bus_read_4(sc->ajus_mem_res,
ALTERA_JTAG_UART_DATA_OFF)));
}
static inline void
aju_data_write(struct altera_jtag_uart_softc *sc, uint32_t v)
{
bus_write_4(sc->ajus_mem_res, ALTERA_JTAG_UART_DATA_OFF, htole32(v));
}
static inline uint32_t
aju_control_read(struct altera_jtag_uart_softc *sc)
{
return (le32toh(bus_read_4(sc->ajus_mem_res,
ALTERA_JTAG_UART_CONTROL_OFF)));
}
static inline void
aju_control_write(struct altera_jtag_uart_softc *sc, uint32_t v)
{
bus_write_4(sc->ajus_mem_res, ALTERA_JTAG_UART_CONTROL_OFF,
htole32(v));
}
/*
* Slightly higher-level routines aware of buffering and flow control.
*/
static inline int
aju_writable(struct altera_jtag_uart_softc *sc)
{
return ((aju_control_read(sc) &
ALTERA_JTAG_UART_CONTROL_WSPACE) != 0);
}
static inline int
aju_readable(struct altera_jtag_uart_softc *sc)
{
uint32_t v;
AJU_LOCK_ASSERT(sc);
if (*sc->ajus_buffer_validp)
return (1);
v = aju_data_read(sc);
if ((v & ALTERA_JTAG_UART_DATA_RVALID) != 0) {
*sc->ajus_buffer_validp = 1;
*sc->ajus_buffer_datap = (v & ALTERA_JTAG_UART_DATA_DATA);
return (1);
}
return (0);
}
static char
aju_read(struct altera_jtag_uart_softc *sc)
{
AJU_LOCK_ASSERT(sc);
while (!aju_readable(sc));
*sc->ajus_buffer_validp = 0;
return (*sc->ajus_buffer_datap);
}
/*
* Routines for enabling and disabling interrupts for read and write.
*/
static void
aju_intr_readable_enable(struct altera_jtag_uart_softc *sc)
{
uint32_t v;
AJU_LOCK_ASSERT(sc);
atomic_add_int(&aju_intr_readable_enabled, 1);
v = aju_control_read(sc);
v |= ALTERA_JTAG_UART_CONTROL_RE;
aju_control_write(sc, v);
}
static void
aju_intr_writable_enable(struct altera_jtag_uart_softc *sc)
{
uint32_t v;
AJU_LOCK_ASSERT(sc);
atomic_add_int(&aju_intr_writable_enabled, 1);
v = aju_control_read(sc);
v |= ALTERA_JTAG_UART_CONTROL_WE;
aju_control_write(sc, v);
}
static void
aju_intr_writable_disable(struct altera_jtag_uart_softc *sc)
{
uint32_t v;
AJU_LOCK_ASSERT(sc);
atomic_add_int(&aju_intr_writable_disabled, 1);
v = aju_control_read(sc);
v &= ~ALTERA_JTAG_UART_CONTROL_WE;
aju_control_write(sc, v);
}
static void
aju_intr_disable(struct altera_jtag_uart_softc *sc)
{
uint32_t v;
AJU_LOCK_ASSERT(sc);
atomic_add_int(&aju_intr_disabled, 1);
v = aju_control_read(sc);
v &= ~(ALTERA_JTAG_UART_CONTROL_RE | ALTERA_JTAG_UART_CONTROL_WE);
aju_control_write(sc, v);
}
/*
* The actual work of checking for, and handling, available reads. This is
* used in both polled and interrupt-driven modes, as JTAG UARTs may be hooked
* up with, or without, IRQs allocated.
*/
static void
aju_handle_input(struct altera_jtag_uart_softc *sc, struct tty *tp)
{
int c;
tty_assert_locked(tp);
AJU_LOCK_ASSERT(sc);
while (aju_readable(sc)) {
c = aju_read(sc);
AJU_UNLOCK(sc);
#ifdef KDB
if (sc->ajus_flags & ALTERA_JTAG_UART_FLAG_CONSOLE)
kdb_alt_break(c, &sc->ajus_alt_break_state);
#endif
ttydisc_rint(tp, c, 0);
AJU_LOCK(sc);
}
AJU_UNLOCK(sc);
ttydisc_rint_done(tp);
AJU_LOCK(sc);
}
/*
* Send output to the UART until either there's none left to send, or we run
* out of room and need to await an interrupt so that we can start sending
* again.
*
* XXXRW: It would be nice to query WSPACE at the beginning and write to the
* FIFO in bugger chunks.
*/
static void
aju_handle_output(struct altera_jtag_uart_softc *sc, struct tty *tp)
{
uint32_t v;
uint8_t ch;
tty_assert_locked(tp);
AJU_LOCK_ASSERT(sc);
AJU_UNLOCK(sc);
while (ttydisc_getc_poll(tp) != 0) {
AJU_LOCK(sc);
if (*sc->ajus_jtag_presentp == 0) {
/*
* If JTAG is not present, then we will drop this
* character instead of perhaps scheduling an
* interrupt to let us know when there is buffer
* space. Otherwise we might get a write interrupt
* later even though we aren't interested in sending
* anymore. Loop to drain TTY-layer buffer.
*/
AJU_UNLOCK(sc);
if (ttydisc_getc(tp, &ch, sizeof(ch)) !=
sizeof(ch))
panic("%s: ttydisc_getc", __func__);
continue;
}
v = aju_control_read(sc);
if ((v & ALTERA_JTAG_UART_CONTROL_WSPACE) == 0) {
if (sc->ajus_irq_res != NULL &&
(v & ALTERA_JTAG_UART_CONTROL_WE) == 0)
aju_intr_writable_enable(sc);
return;
}
AJU_UNLOCK(sc);
if (ttydisc_getc(tp, &ch, sizeof(ch)) != sizeof(ch))
panic("%s: ttydisc_getc 2", __func__);
AJU_LOCK(sc);
/*
* XXXRW: There is a slight race here in which we test for
* writability, drop the lock, get the character from the tty
* layer, re-acquire the lock, and then write. It's possible
* for other code -- specifically, the low-level console -- to
* have* written in the mean time, which might mean that there
* is no longer space. The BERI memory bus will cause this
* write to block, wedging the processor until space is
* available -- which could be a while if JTAG is not
* attached!
*
* The 'easy' fix is to drop the character if WSPACE has
* become unset. Not sure what the 'hard' fix is.
*/
aju_data_write(sc, ch);
AJU_UNLOCK(sc);
}
AJU_LOCK(sc);
/*
* If interrupts are configured, and there's no data to write, but we
* had previously enabled write interrupts, disable them now.
*/
v = aju_control_read(sc);
if (sc->ajus_irq_res != NULL && (v & ALTERA_JTAG_UART_CONTROL_WE) != 0)
aju_intr_writable_disable(sc);
}
static void
aju_outwakeup(struct tty *tp)
{
struct altera_jtag_uart_softc *sc = tty_softc(tp);
tty_assert_locked(tp);
AJU_LOCK(sc);
aju_handle_output(sc, tp);
AJU_UNLOCK(sc);
}
static void
aju_io_callout(void *arg)
{
struct altera_jtag_uart_softc *sc = arg;
struct tty *tp = sc->ajus_ttyp;
tty_lock(tp);
AJU_LOCK(sc);
/*
* It would be convenient if we could share code with aju_intr() here
* by testing the control register for ALTERA_JTAG_UART_CONTROL_RI and
* ALTERA_JTAG_UART_CONTROL_WI. Unfortunately, it's not clear that
* this is supported, so do all the work to poll for both input and
* output.
*/
aju_handle_input(sc, tp);
aju_handle_output(sc, tp);
/*
* Reschedule next poll attempt. There's some argument that we should
* do adaptive polling based on the expectation of I/O: is something
* pending in the output buffer, or have we recently had input, but we
* don't.
*/
callout_reset(&sc->ajus_io_callout, AJU_IO_POLLINTERVAL,
aju_io_callout, sc);
AJU_UNLOCK(sc);
tty_unlock(tp);
}
static void
aju_ac_callout(void *arg)
{
struct altera_jtag_uart_softc *sc = arg;
struct tty *tp = sc->ajus_ttyp;
uint32_t v;
tty_lock(tp);
AJU_LOCK(sc);
v = aju_control_read(sc);
if (v & ALTERA_JTAG_UART_CONTROL_AC) {
v &= ~ALTERA_JTAG_UART_CONTROL_AC;
aju_control_write(sc, v);
if (*sc->ajus_jtag_presentp == 0) {
*sc->ajus_jtag_presentp = 1;
atomic_add_int(&aju_jtag_appeared, 1);
aju_handle_output(sc, tp);
}
/* Any hit eliminates all recent misses. */
*sc->ajus_jtag_missedp = 0;
} else if (*sc->ajus_jtag_presentp != 0) {
/*
* If we've exceeded our tolerance for misses, mark JTAG as
* disconnected and drain output. Otherwise, bump the miss
* counter.
*/
if (*sc->ajus_jtag_missedp > AJU_JTAG_MAXMISS) {
*sc->ajus_jtag_presentp = 0;
atomic_add_int(&aju_jtag_vanished, 1);
aju_handle_output(sc, tp);
} else
(*sc->ajus_jtag_missedp)++;
}
callout_reset(&sc->ajus_ac_callout, AJU_AC_POLLINTERVAL,
aju_ac_callout, sc);
AJU_UNLOCK(sc);
tty_unlock(tp);
}
static void
aju_intr(void *arg)
{
struct altera_jtag_uart_softc *sc = arg;
struct tty *tp = sc->ajus_ttyp;
uint32_t v;
tty_lock(tp);
AJU_LOCK(sc);
v = aju_control_read(sc);
if (v & ALTERA_JTAG_UART_CONTROL_RI) {
atomic_add_int(&aju_intr_read_count, 1);
aju_handle_input(sc, tp);
}
if (v & ALTERA_JTAG_UART_CONTROL_WI) {
atomic_add_int(&aju_intr_write_count, 1);
aju_handle_output(sc, tp);
}
AJU_UNLOCK(sc);
tty_unlock(tp);
}
int
altera_jtag_uart_attach(struct altera_jtag_uart_softc *sc)
{
struct tty *tp;
int error;
AJU_LOCK_INIT(sc);
/*
* XXXRW: Currently, we detect the console solely based on it using a
* reserved address, and borrow console-level locks and buffer if so.
* Is there a better way?
*/
if (rman_get_start(sc->ajus_mem_res) == BERI_UART_BASE) {
sc->ajus_lockp = &aju_cons_lock;
sc->ajus_buffer_validp = &aju_cons_buffer_valid;
sc->ajus_buffer_datap = &aju_cons_buffer_data;
sc->ajus_jtag_presentp = &aju_cons_jtag_present;
sc->ajus_jtag_missedp = &aju_cons_jtag_missed;
sc->ajus_flags |= ALTERA_JTAG_UART_FLAG_CONSOLE;
} else {
sc->ajus_lockp = &sc->ajus_lock;
sc->ajus_buffer_validp = &sc->ajus_buffer_valid;
sc->ajus_buffer_datap = &sc->ajus_buffer_data;
sc->ajus_jtag_presentp = &sc->ajus_jtag_present;
sc->ajus_jtag_missedp = &sc->ajus_jtag_missed;
}
/*
* Disable interrupts regardless of whether or not we plan to use
* them. We will register an interrupt handler now if they will be
* used, but not re-enable intil later once the remainder of the tty
* layer is properly initialised, as we're not ready for input yet.
*/
AJU_LOCK(sc);
aju_intr_disable(sc);
AJU_UNLOCK(sc);
if (sc->ajus_irq_res != NULL) {
error = bus_setup_intr(sc->ajus_dev, sc->ajus_irq_res,
INTR_ENTROPY | INTR_TYPE_TTY | INTR_MPSAFE, NULL,
aju_intr, sc, &sc->ajus_irq_cookie);
if (error) {
device_printf(sc->ajus_dev,
"could not activate interrupt\n");
AJU_LOCK_DESTROY(sc);
return (error);
}
}
tp = sc->ajus_ttyp = tty_alloc(&aju_ttydevsw, sc);
if (sc->ajus_flags & ALTERA_JTAG_UART_FLAG_CONSOLE) {
aju_cons_sc = sc;
tty_init_console(tp, 0);
}
tty_makedev(tp, NULL, "%s%d", AJU_TTYNAME, sc->ajus_unit);
/*
* If we will be using interrupts, enable them now; otherwise, start
* polling. From this point onwards, input can arrive.
*/
if (sc->ajus_irq_res != NULL) {
AJU_LOCK(sc);
aju_intr_readable_enable(sc);
AJU_UNLOCK(sc);
} else {
callout_init(&sc->ajus_io_callout, 1);
callout_reset(&sc->ajus_io_callout, AJU_IO_POLLINTERVAL,
aju_io_callout, sc);
}
callout_init(&sc->ajus_ac_callout, 1);
callout_reset(&sc->ajus_ac_callout, AJU_AC_POLLINTERVAL,
aju_ac_callout, sc);
return (0);
}
void
altera_jtag_uart_detach(struct altera_jtag_uart_softc *sc)
{
struct tty *tp = sc->ajus_ttyp;
/*
* If we're using interrupts, disable and release the interrupt
* handler now. Otherwise drain the polling timeout.
*/
if (sc->ajus_irq_res != NULL) {
AJU_LOCK(sc);
aju_intr_disable(sc);
AJU_UNLOCK(sc);
bus_teardown_intr(sc->ajus_dev, sc->ajus_irq_res,
sc->ajus_irq_cookie);
} else
callout_drain(&sc->ajus_io_callout);
callout_drain(&sc->ajus_ac_callout);
if (sc->ajus_flags & ALTERA_JTAG_UART_FLAG_CONSOLE)
aju_cons_sc = NULL;
tty_lock(tp);
tty_rel_gone(tp);
AJU_LOCK_DESTROY(sc);
}

View file

@ -1,637 +0,0 @@
/*-
* Copyright (c) 2016-2018 Ruslan Bukin <br@bsdpad.com>
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
* ("CTSRD"), as part of the DARPA CRASH research programme.
*
* 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.
*/
/* Altera mSGDMA driver. */
#include <sys/cdefs.h>
#include "opt_platform.h"
#include <sys/param.h>
#include <sys/endian.h>
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/kthread.h>
#include <sys/sglist.h>
#include <sys/module.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/resource.h>
#include <sys/rman.h>
#include <machine/bus.h>
#include <machine/fdt.h>
#include <machine/cache.h>
#ifdef FDT
#include <dev/fdt/fdt_common.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
#endif
#include <dev/xdma/xdma.h>
#include "xdma_if.h"
#include "opt_altera_msgdma.h"
#include <dev/altera/msgdma/msgdma.h>
#define MSGDMA_DEBUG
#undef MSGDMA_DEBUG
#ifdef MSGDMA_DEBUG
#define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__)
#else
#define dprintf(fmt, ...)
#endif
#define MSGDMA_NCHANNELS 1
struct msgdma_channel {
struct msgdma_softc *sc;
struct mtx mtx;
xdma_channel_t *xchan;
struct proc *p;
int used;
int index;
int idx_head;
int idx_tail;
struct msgdma_desc **descs;
bus_dma_segment_t *descs_phys;
uint32_t descs_num;
bus_dma_tag_t dma_tag;
bus_dmamap_t *dma_map;
uint32_t map_descr;
uint8_t map_err;
uint32_t descs_used_count;
};
struct msgdma_softc {
device_t dev;
struct resource *res[3];
bus_space_tag_t bst;
bus_space_handle_t bsh;
bus_space_tag_t bst_d;
bus_space_handle_t bsh_d;
void *ih;
struct msgdma_desc desc;
struct msgdma_channel channels[MSGDMA_NCHANNELS];
};
static struct resource_spec msgdma_spec[] = {
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
{ SYS_RES_MEMORY, 1, RF_ACTIVE },
{ SYS_RES_IRQ, 0, RF_ACTIVE },
{ -1, 0 }
};
#define HWTYPE_NONE 0
#define HWTYPE_STD 1
static struct ofw_compat_data compat_data[] = {
{ "altr,msgdma-16.0", HWTYPE_STD },
{ "altr,msgdma-1.0", HWTYPE_STD },
{ NULL, HWTYPE_NONE },
};
static int msgdma_probe(device_t dev);
static int msgdma_attach(device_t dev);
static int msgdma_detach(device_t dev);
static inline uint32_t
msgdma_next_desc(struct msgdma_channel *chan, uint32_t curidx)
{
return ((curidx + 1) % chan->descs_num);
}
static void
msgdma_intr(void *arg)
{
xdma_transfer_status_t status;
struct xdma_transfer_status st;
struct msgdma_desc *desc;
struct msgdma_channel *chan;
struct xdma_channel *xchan;
struct msgdma_softc *sc;
uint32_t tot_copied;
sc = arg;
chan = &sc->channels[0];
xchan = chan->xchan;
dprintf("%s(%d): status 0x%08x next_descr 0x%08x, control 0x%08x\n",
__func__, device_get_unit(sc->dev),
READ4_DESC(sc, PF_STATUS),
READ4_DESC(sc, PF_NEXT_LO),
READ4_DESC(sc, PF_CONTROL));
tot_copied = 0;
while (chan->idx_tail != chan->idx_head) {
dprintf("%s: idx_tail %d idx_head %d\n", __func__,
chan->idx_tail, chan->idx_head);
bus_dmamap_sync(chan->dma_tag, chan->dma_map[chan->idx_tail],
BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
desc = chan->descs[chan->idx_tail];
if ((le32toh(desc->control) & CONTROL_OWN) != 0) {
break;
}
tot_copied += le32toh(desc->transferred);
st.error = 0;
st.transferred = le32toh(desc->transferred);
xchan_seg_done(xchan, &st);
chan->idx_tail = msgdma_next_desc(chan, chan->idx_tail);
atomic_subtract_int(&chan->descs_used_count, 1);
}
WRITE4_DESC(sc, PF_STATUS, PF_STATUS_IRQ);
/* Finish operation */
status.error = 0;
status.transferred = tot_copied;
xdma_callback(chan->xchan, &status);
}
static int
msgdma_reset(struct msgdma_softc *sc)
{
int timeout;
dprintf("%s: read status: %x\n", __func__, READ4(sc, 0x00));
dprintf("%s: read control: %x\n", __func__, READ4(sc, 0x04));
dprintf("%s: read 1: %x\n", __func__, READ4(sc, 0x08));
dprintf("%s: read 2: %x\n", __func__, READ4(sc, 0x0C));
WRITE4(sc, DMA_CONTROL, CONTROL_RESET);
timeout = 100;
do {
if ((READ4(sc, DMA_STATUS) & STATUS_RESETTING) == 0)
break;
} while (timeout--);
dprintf("timeout %d\n", timeout);
if (timeout == 0)
return (-1);
dprintf("%s: read control after reset: %x\n",
__func__, READ4(sc, DMA_CONTROL));
return (0);
}
static int
msgdma_probe(device_t dev)
{
int hwtype;
if (!ofw_bus_status_okay(dev))
return (ENXIO);
hwtype = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
if (hwtype == HWTYPE_NONE)
return (ENXIO);
device_set_desc(dev, "Altera mSGDMA");
return (BUS_PROBE_DEFAULT);
}
static int
msgdma_attach(device_t dev)
{
struct msgdma_softc *sc;
phandle_t xref, node;
int err;
sc = device_get_softc(dev);
sc->dev = dev;
if (bus_alloc_resources(dev, msgdma_spec, sc->res)) {
device_printf(dev, "could not allocate resources for device\n");
return (ENXIO);
}
/* CSR memory interface */
sc->bst = rman_get_bustag(sc->res[0]);
sc->bsh = rman_get_bushandle(sc->res[0]);
/* Descriptor memory interface */
sc->bst_d = rman_get_bustag(sc->res[1]);
sc->bsh_d = rman_get_bushandle(sc->res[1]);
/* Setup interrupt handler */
err = bus_setup_intr(dev, sc->res[2], INTR_TYPE_MISC | INTR_MPSAFE,
NULL, msgdma_intr, sc, &sc->ih);
if (err) {
device_printf(dev, "Unable to alloc interrupt resource.\n");
return (ENXIO);
}
node = ofw_bus_get_node(dev);
xref = OF_xref_from_node(node);
OF_device_register_xref(xref, dev);
if (msgdma_reset(sc) != 0)
return (-1);
WRITE4(sc, DMA_CONTROL, CONTROL_GIEM);
return (0);
}
static int
msgdma_detach(device_t dev)
{
struct msgdma_softc *sc;
sc = device_get_softc(dev);
return (0);
}
static void
msgdma_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err)
{
struct msgdma_channel *chan;
chan = (struct msgdma_channel *)arg;
KASSERT(chan != NULL, ("xchan is NULL"));
if (err) {
chan->map_err = 1;
return;
}
chan->descs_phys[chan->map_descr].ds_addr = segs[0].ds_addr;
chan->descs_phys[chan->map_descr].ds_len = segs[0].ds_len;
dprintf("map desc %d: descs phys %lx len %ld\n",
chan->map_descr, segs[0].ds_addr, segs[0].ds_len);
}
static int
msgdma_desc_free(struct msgdma_softc *sc, struct msgdma_channel *chan)
{
struct msgdma_desc *desc;
int nsegments;
int i;
nsegments = chan->descs_num;
for (i = 0; i < nsegments; i++) {
desc = chan->descs[i];
bus_dmamap_unload(chan->dma_tag, chan->dma_map[i]);
bus_dmamem_free(chan->dma_tag, desc, chan->dma_map[i]);
}
bus_dma_tag_destroy(chan->dma_tag);
free(chan->descs, M_DEVBUF);
free(chan->dma_map, M_DEVBUF);
free(chan->descs_phys, M_DEVBUF);
return (0);
}
static int
msgdma_desc_alloc(struct msgdma_softc *sc, struct msgdma_channel *chan,
uint32_t desc_size, uint32_t align)
{
int nsegments;
int err;
int i;
nsegments = chan->descs_num;
dprintf("%s: nseg %d\n", __func__, nsegments);
err = bus_dma_tag_create(
bus_get_dma_tag(sc->dev),
align, 0, /* alignment, boundary */
BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
BUS_SPACE_MAXADDR, /* highaddr */
NULL, NULL, /* filter, filterarg */
desc_size, 1, /* maxsize, nsegments*/
desc_size, 0, /* maxsegsize, flags */
NULL, NULL, /* lockfunc, lockarg */
&chan->dma_tag);
if (err) {
device_printf(sc->dev,
"%s: Can't create bus_dma tag.\n", __func__);
return (-1);
}
/* Descriptors. */
chan->descs = malloc(nsegments * sizeof(struct msgdma_desc *),
M_DEVBUF, (M_WAITOK | M_ZERO));
chan->dma_map = malloc(nsegments * sizeof(bus_dmamap_t),
M_DEVBUF, (M_WAITOK | M_ZERO));
chan->descs_phys = malloc(nsegments * sizeof(bus_dma_segment_t),
M_DEVBUF, (M_WAITOK | M_ZERO));
/* Allocate bus_dma memory for each descriptor. */
for (i = 0; i < nsegments; i++) {
err = bus_dmamem_alloc(chan->dma_tag, (void **)&chan->descs[i],
BUS_DMA_WAITOK | BUS_DMA_ZERO, &chan->dma_map[i]);
if (err) {
device_printf(sc->dev,
"%s: Can't allocate memory for descriptors.\n",
__func__);
return (-1);
}
chan->map_err = 0;
chan->map_descr = i;
err = bus_dmamap_load(chan->dma_tag, chan->dma_map[i], chan->descs[i],
desc_size, msgdma_dmamap_cb, chan, BUS_DMA_WAITOK);
if (err) {
device_printf(sc->dev,
"%s: Can't load DMA map.\n", __func__);
return (-1);
}
if (chan->map_err != 0) {
device_printf(sc->dev,
"%s: Can't load DMA map.\n", __func__);
return (-1);
}
}
return (0);
}
static int
msgdma_channel_alloc(device_t dev, struct xdma_channel *xchan)
{
struct msgdma_channel *chan;
struct msgdma_softc *sc;
int i;
sc = device_get_softc(dev);
for (i = 0; i < MSGDMA_NCHANNELS; i++) {
chan = &sc->channels[i];
if (chan->used == 0) {
chan->xchan = xchan;
xchan->chan = (void *)chan;
if ((xchan->caps & XCHAN_CAP_IOMMU) == 0)
xchan->caps |= XCHAN_CAP_BUSDMA;
chan->index = i;
chan->sc = sc;
chan->used = 1;
chan->idx_head = 0;
chan->idx_tail = 0;
chan->descs_used_count = 0;
chan->descs_num = 1024;
return (0);
}
}
return (-1);
}
static int
msgdma_channel_free(device_t dev, struct xdma_channel *xchan)
{
struct msgdma_channel *chan;
struct msgdma_softc *sc;
sc = device_get_softc(dev);
chan = (struct msgdma_channel *)xchan->chan;
msgdma_desc_free(sc, chan);
chan->used = 0;
return (0);
}
static int
msgdma_channel_capacity(device_t dev, xdma_channel_t *xchan,
uint32_t *capacity)
{
struct msgdma_channel *chan;
uint32_t c;
chan = (struct msgdma_channel *)xchan->chan;
/* At least one descriptor must be left empty. */
c = (chan->descs_num - chan->descs_used_count - 1);
*capacity = c;
return (0);
}
static int
msgdma_channel_submit_sg(device_t dev, struct xdma_channel *xchan,
struct xdma_sglist *sg, uint32_t sg_n)
{
struct msgdma_channel *chan;
struct msgdma_desc *desc;
struct msgdma_softc *sc;
bus_addr_t src_addr_lo;
bus_addr_t dst_addr_lo;
uint32_t len;
uint32_t tmp;
int i;
sc = device_get_softc(dev);
chan = (struct msgdma_channel *)xchan->chan;
for (i = 0; i < sg_n; i++) {
src_addr_lo = sg[i].src_addr;
dst_addr_lo = sg[i].dst_addr;
len = (uint32_t)sg[i].len;
dprintf("%s: src %x dst %x len %d\n", __func__,
src_addr_lo, dst_addr_lo, len);
desc = chan->descs[chan->idx_head];
#if defined(ALTERA_MSGDMA_DESC_EXT) || defined(ALTERA_MSGDMA_DESC_PF_EXT)
desc->read_hi = htole32(src_addr_lo >> 32);
desc->write_hi = htole32(dst_addr_lo >> 32);
#endif
desc->read_lo = htole32(src_addr_lo);
desc->write_lo = htole32(dst_addr_lo);
desc->length = htole32(len);
desc->transferred = 0;
desc->status = 0;
desc->reserved = 0;
desc->control = 0;
if (sg[i].direction == XDMA_MEM_TO_DEV) {
if (sg[i].first == 1) {
desc->control |= htole32(CONTROL_GEN_SOP);
}
if (sg[i].last == 1) {
desc->control |= htole32(CONTROL_GEN_EOP);
desc->control |= htole32(CONTROL_TC_IRQ_EN |
CONTROL_ET_IRQ_EN | CONTROL_ERR_M);
}
} else {
desc->control |= htole32(CONTROL_END_ON_EOP | (1 << 13));
desc->control |= htole32(CONTROL_TC_IRQ_EN |
CONTROL_ET_IRQ_EN | CONTROL_ERR_M);
}
tmp = chan->idx_head;
atomic_add_int(&chan->descs_used_count, 1);
chan->idx_head = msgdma_next_desc(chan, chan->idx_head);
desc->control |= htole32(CONTROL_OWN | CONTROL_GO);
bus_dmamap_sync(chan->dma_tag, chan->dma_map[tmp],
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
}
return (0);
}
static int
msgdma_channel_prep_sg(device_t dev, struct xdma_channel *xchan)
{
struct msgdma_channel *chan;
struct msgdma_desc *desc;
struct msgdma_softc *sc;
uint32_t addr;
uint32_t reg;
int ret;
int i;
sc = device_get_softc(dev);
dprintf("%s(%d)\n", __func__, device_get_unit(dev));
chan = (struct msgdma_channel *)xchan->chan;
ret = msgdma_desc_alloc(sc, chan, sizeof(struct msgdma_desc), 16);
if (ret != 0) {
device_printf(sc->dev,
"%s: Can't allocate descriptors.\n", __func__);
return (-1);
}
for (i = 0; i < chan->descs_num; i++) {
desc = chan->descs[i];
if (i == (chan->descs_num - 1)) {
desc->next = htole32(chan->descs_phys[0].ds_addr);
} else {
desc->next = htole32(chan->descs_phys[i+1].ds_addr);
}
dprintf("%s(%d): desc %d vaddr %lx next paddr %x\n", __func__,
device_get_unit(dev), i, (uint64_t)desc, le32toh(desc->next));
}
addr = chan->descs_phys[0].ds_addr;
WRITE4_DESC(sc, PF_NEXT_LO, addr);
WRITE4_DESC(sc, PF_NEXT_HI, 0);
WRITE4_DESC(sc, PF_POLL_FREQ, 1000);
reg = (PF_CONTROL_GIEM | PF_CONTROL_DESC_POLL_EN);
reg |= PF_CONTROL_RUN;
WRITE4_DESC(sc, PF_CONTROL, reg);
return (0);
}
static int
msgdma_channel_control(device_t dev, xdma_channel_t *xchan, int cmd)
{
struct msgdma_channel *chan;
struct msgdma_softc *sc;
sc = device_get_softc(dev);
chan = (struct msgdma_channel *)xchan->chan;
switch (cmd) {
case XDMA_CMD_BEGIN:
case XDMA_CMD_TERMINATE:
case XDMA_CMD_PAUSE:
/* TODO: implement me */
return (-1);
}
return (0);
}
#ifdef FDT
static int
msgdma_ofw_md_data(device_t dev, pcell_t *cells, int ncells, void **ptr)
{
return (0);
}
#endif
static device_method_t msgdma_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, msgdma_probe),
DEVMETHOD(device_attach, msgdma_attach),
DEVMETHOD(device_detach, msgdma_detach),
/* xDMA Interface */
DEVMETHOD(xdma_channel_alloc, msgdma_channel_alloc),
DEVMETHOD(xdma_channel_free, msgdma_channel_free),
DEVMETHOD(xdma_channel_control, msgdma_channel_control),
/* xDMA SG Interface */
DEVMETHOD(xdma_channel_capacity, msgdma_channel_capacity),
DEVMETHOD(xdma_channel_prep_sg, msgdma_channel_prep_sg),
DEVMETHOD(xdma_channel_submit_sg, msgdma_channel_submit_sg),
#ifdef FDT
DEVMETHOD(xdma_ofw_md_data, msgdma_ofw_md_data),
#endif
DEVMETHOD_END
};
static driver_t msgdma_driver = {
"msgdma",
msgdma_methods,
sizeof(struct msgdma_softc),
};
EARLY_DRIVER_MODULE(msgdma, simplebus, msgdma_driver, 0, 0,
BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE);

View file

@ -1,148 +0,0 @@
/*-
* Copyright (c) 2017-2018 Ruslan Bukin <br@bsdpad.com>
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
* ("CTSRD"), as part of the DARPA CRASH research programme.
*
* 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.
*/
#include "opt_altera_msgdma.h"
/* Altera mSGDMA registers. */
#define DMA_STATUS 0x00
#define STATUS_RESETTING (1 << 6)
#define DMA_CONTROL 0x04
#define CONTROL_GIEM (1 << 4) /* Global Interrupt Enable Mask */
#define CONTROL_RESET (1 << 1) /* Reset Dispatcher */
/* Descriptor fields. */
#define CONTROL_GO (1 << 31) /* Commit all the descriptor info */
#define CONTROL_OWN (1 << 30) /* Owned by hardware (prefetcher-enabled only) */
#define CONTROL_EDE (1 << 24) /* Early done enable */
#define CONTROL_ERR_S 16 /* Transmit Error, Error IRQ Enable */
#define CONTROL_ERR_M (0xff << CONTROL_ERR_S)
#define CONTROL_ET_IRQ_EN (1 << 15) /* Early Termination IRQ Enable */
#define CONTROL_TC_IRQ_EN (1 << 14) /* Transfer Complete IRQ Enable */
#define CONTROL_END_ON_EOP (1 << 12) /* End on EOP */
#define CONTROL_PARK_WR (1 << 11) /* Park Writes */
#define CONTROL_PARK_RD (1 << 10) /* Park Reads */
#define CONTROL_GEN_EOP (1 << 9) /* Generate EOP */
#define CONTROL_GEN_SOP (1 << 8) /* Generate SOP */
#define CONTROL_TX_CHANNEL_S 0 /* Transmit Channel */
#define CONTROL_TX_CHANNEL_M (0xff << CONTROL_TRANSMIT_CH_S)
/* Prefetcher */
#define PF_CONTROL 0x00
#define PF_CONTROL_GIEM (1 << 3)
#define PF_CONTROL_RESET (1 << 2)
#define PF_CONTROL_DESC_POLL_EN (1 << 1)
#define PF_CONTROL_RUN (1 << 0)
#define PF_NEXT_LO 0x04
#define PF_NEXT_HI 0x08
#define PF_POLL_FREQ 0x0C
#define PF_STATUS 0x10
#define PF_STATUS_IRQ (1 << 0)
#define READ4(_sc, _reg) \
le32toh(bus_space_read_4(_sc->bst, _sc->bsh, _reg))
#define WRITE4(_sc, _reg, _val) \
bus_space_write_4(_sc->bst, _sc->bsh, _reg, htole32(_val))
#define READ4_DESC(_sc, _reg) \
le32toh(bus_space_read_4(_sc->bst_d, _sc->bsh_d, _reg))
#define WRITE4_DESC(_sc, _reg, _val) \
bus_space_write_4(_sc->bst_d, _sc->bsh_d, _reg, htole32(_val))
#if defined(ALTERA_MSGDMA_DESC_STD)
/* Standard descriptor format with prefetcher disabled. */
struct msgdma_desc {
uint32_t read_lo;
uint32_t write_lo;
uint32_t length;
uint32_t control;
};
#elif defined(ALTERA_MSGDMA_DESC_EXT)
/* Extended descriptor format with prefetcher disabled. */
struct msgdma_desc {
uint32_t read_lo;
uint32_t write_lo;
uint32_t length;
uint8_t write_burst;
uint8_t read_burst;
uint16_t seq_num;
uint16_t write_stride;
uint16_t read_stride;
uint32_t read_hi;
uint32_t write_hi;
uint32_t control;
};
#elif defined(ALTERA_MSGDMA_DESC_PF_STD)
/* Standard descriptor format with prefetcher enabled. */
struct msgdma_desc {
uint32_t read_lo;
uint32_t write_lo;
uint32_t length;
uint32_t next;
uint32_t transferred;
uint32_t status;
uint32_t reserved;
uint32_t control;
};
#elif defined(ALTERA_MSGDMA_DESC_PF_EXT)
/* Extended descriptor format with prefetcher enabled. */
struct msgdma_desc {
uint32_t read_lo;
uint32_t write_lo;
uint32_t length;
uint32_t next;
uint32_t transferred;
uint32_t status;
uint32_t reserved;
uint8_t write_burst;
uint8_t read_burst;
uint16_t seq_num;
uint16_t write_stride;
uint16_t read_stride;
uint32_t read_hi;
uint32_t write_hi;
uint32_t next_hi;
uint32_t reserved1;
uint32_t reserved2;
uint32_t reserved3;
uint32_t control;
};
#else
#error "mSGDMA descriptor format (kernel option) is not set."
#endif

View file

@ -1,208 +0,0 @@
/*-
* Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com>
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
* ("CTSRD"), as part of the DARPA CRASH research programme.
*
* 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.
*/
/*
* Altera PIO (Parallel IO) device driver
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/malloc.h>
#include <sys/rman.h>
#include <sys/timeet.h>
#include <sys/timetc.h>
#include <dev/fdt/fdt_common.h>
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
#include <machine/fdt.h>
#include <machine/cpu.h>
#include <dev/altera/pio/pio.h>
#include "pio_if.h"
#define READ4(_sc, _reg) bus_read_4((_sc)->res[0], _reg)
#define READ2(_sc, _reg) bus_read_2((_sc)->res[0], _reg)
#define READ1(_sc, _reg) bus_read_1((_sc)->res[0], _reg)
#define WRITE4(_sc, _reg, _val) bus_write_4((_sc)->res[0], _reg, _val)
#define WRITE2(_sc, _reg, _val) bus_write_2((_sc)->res[0], _reg, _val)
#define WRITE1(_sc, _reg, _val) bus_write_1((_sc)->res[0], _reg, _val)
struct pio_softc {
struct resource *res[2];
bus_space_tag_t bst;
bus_space_handle_t bsh;
device_t dev;
void *ih;
};
static struct resource_spec pio_spec[] = {
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
{ SYS_RES_IRQ, 0, RF_ACTIVE },
{ -1, 0 }
};
static int
pio_setup_irq(device_t dev, void *intr_handler, void *ih_user)
{
struct pio_softc *sc;
sc = device_get_softc(dev);
/* Setup interrupt handlers */
if (bus_setup_intr(sc->dev, sc->res[1], INTR_TYPE_BIO | INTR_MPSAFE,
NULL, intr_handler, ih_user, &sc->ih)) {
device_printf(sc->dev, "Unable to setup intr\n");
return (1);
}
return (0);
}
static int
pio_teardown_irq(device_t dev)
{
struct pio_softc *sc;
sc = device_get_softc(dev);
bus_teardown_intr(sc->dev, sc->res[1], sc->ih);
return (0);
}
static int
pio_read(device_t dev)
{
struct pio_softc *sc;
sc = device_get_softc(dev);
return (READ4(sc, PIO_DATA));
}
static int
pio_set(device_t dev, int bit, int enable)
{
struct pio_softc *sc;
sc = device_get_softc(dev);
if (enable)
WRITE4(sc, PIO_OUTSET, bit);
else
WRITE4(sc, PIO_OUTCLR, bit);
return (0);
}
static int
pio_configure(device_t dev, int dir, int mask)
{
struct pio_softc *sc;
sc = device_get_softc(dev);
WRITE4(sc, PIO_INT_MASK, mask);
WRITE4(sc, PIO_DIR, dir);
return (0);
}
static int
pio_probe(device_t dev)
{
if (!ofw_bus_status_okay(dev))
return (ENXIO);
if (!ofw_bus_is_compatible(dev, "altr,pio"))
return (ENXIO);
device_set_desc(dev, "Altera PIO");
return (BUS_PROBE_DEFAULT);
}
static int
pio_attach(device_t dev)
{
struct pio_softc *sc;
struct fdt_ic *fic;
phandle_t node;
sc = device_get_softc(dev);
sc->dev = dev;
if (bus_alloc_resources(dev, pio_spec, sc->res)) {
device_printf(dev, "could not allocate resources\n");
return (ENXIO);
}
/* Memory interface */
sc->bst = rman_get_bustag(sc->res[0]);
sc->bsh = rman_get_bushandle(sc->res[0]);
if ((node = ofw_bus_get_node(sc->dev)) == -1)
return (ENXIO);
fic = malloc(sizeof(*fic), M_DEVBUF, M_WAITOK|M_ZERO);
fic->iph = node;
fic->dev = dev;
SLIST_INSERT_HEAD(&fdt_ic_list_head, fic, fdt_ics);
return (0);
}
static device_method_t pio_methods[] = {
DEVMETHOD(device_probe, pio_probe),
DEVMETHOD(device_attach, pio_attach),
/* pio_if.m */
DEVMETHOD(pio_read, pio_read),
DEVMETHOD(pio_configure, pio_configure),
DEVMETHOD(pio_set, pio_set),
DEVMETHOD(pio_setup_irq, pio_setup_irq),
DEVMETHOD(pio_teardown_irq, pio_teardown_irq),
DEVMETHOD_END
};
static driver_t pio_driver = {
"altera_pio",
pio_methods,
sizeof(struct pio_softc),
};
DRIVER_MODULE(altera_pio, simplebus, pio_driver, 0, 0);

View file

@ -1,40 +0,0 @@
/*-
* Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com>
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
* ("CTSRD"), as part of the DARPA CRASH research programme.
*
* 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.
*/
#define PIO_DATA 0x00
#define PIO_DIR 0x04
#define PIO_OUT(n) (1 << n)
#define PIO_OUT_ALL 0xffffffff
#define PIO_INT_MASK 0x08
#define PIO_UNMASK(n) (1 << n)
#define PIO_UNMASK_ALL 0xffffffff
#define PIO_EDGECAPT 0x0c
#define PIO_OUTSET 0x10
#define PIO_OUTCLR 0x14

View file

@ -1,64 +0,0 @@
#-
# Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com>
# All rights reserved.
#
# This software was developed by SRI International and the University of
# Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
# ("CTSRD"), as part of the DARPA CRASH research programme.
#
# 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.
#
#
#include <sys/types.h>
INTERFACE pio;
#
# PIO device methods
#
METHOD int read {
device_t dev;
};
METHOD int setup_irq {
device_t dev;
void *handler;
void *ih_user;
};
METHOD int teardown_irq {
device_t dev;
};
METHOD int set {
device_t dev;
int bit;
int enable;
};
METHOD int configure {
device_t dev;
int dir;
int mask;
}

View file

@ -1,412 +0,0 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2012 Robert N. M. Watson
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
* ("CTSRD"), as part of the DARPA CRASH research programme.
*
* 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.
*/
#include <sys/cdefs.h>
#include "opt_altera_sdcard.h"
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/condvar.h>
#include <sys/conf.h>
#include <sys/bio.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/rman.h>
#include <sys/systm.h>
#include <sys/taskqueue.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <geom/geom_disk.h>
#include <dev/altera/sdcard/altera_sdcard.h>
/*
* Device driver for the Altera University Program Secure Data Card IP Core,
* as described in the similarly named SOPC Builder IP Core specification.
* This soft core is not a full SD host controller interface (SDHCI) but
* instead provides a set of memory mapped registers and memory buffer that
* mildly abstract the SD Card protocol, but without providing DMA or
* interrupts. However, it does hide the details of voltage and
* communications negotiation. This driver implements disk(9), but due to the
* lack of interrupt support, must rely on timer-driven polling to determine
* when I/Os have completed.
*
* TODO:
*
* 1. Implement DISKFLAG_CANDELETE / SD Card sector erase support.
* 2. Implement d_ident from SD Card CID serial number field.
* 3. Handle read-only SD Cards.
* 4. Tune timeouts based on real-world SD Card speeds.
*/
void
altera_sdcard_attach(struct altera_sdcard_softc *sc)
{
ALTERA_SDCARD_LOCK_INIT(sc);
ALTERA_SDCARD_CONDVAR_INIT(sc);
sc->as_disk = NULL;
bioq_init(&sc->as_bioq);
sc->as_currentbio = NULL;
sc->as_state = ALTERA_SDCARD_STATE_NOCARD;
sc->as_taskqueue = taskqueue_create("altera_sdcardc taskq", M_WAITOK,
taskqueue_thread_enqueue, &sc->as_taskqueue);
taskqueue_start_threads(&sc->as_taskqueue, 1, PI_DISK,
"altera_sdcardc%d taskqueue", sc->as_unit);
TIMEOUT_TASK_INIT(sc->as_taskqueue, &sc->as_task, 0,
altera_sdcard_task, sc);
/*
* Kick off timer-driven processing with a manual poll so that we
* synchronously detect an already-inserted SD Card during the boot or
* other driver attach point.
*/
altera_sdcard_task(sc, 1);
}
void
altera_sdcard_detach(struct altera_sdcard_softc *sc)
{
KASSERT(sc->as_taskqueue != NULL, ("%s: taskqueue not present",
__func__));
/*
* Winding down the driver on detach is a bit complex. Update the
* flags to indicate that a detach has been requested, and then wait
* for in-progress I/O to wind down before continuing.
*/
ALTERA_SDCARD_LOCK(sc);
sc->as_flags |= ALTERA_SDCARD_FLAG_DETACHREQ;
while (sc->as_state != ALTERA_SDCARD_STATE_DETACHED)
ALTERA_SDCARD_CONDVAR_WAIT(sc);
ALTERA_SDCARD_UNLOCK(sc);
/*
* Now wait for the possibly still executing taskqueue to drain. In
* principle no more events will be scheduled as we've transitioned to
* a detached state, but there might still be a request in execution.
*/
while (taskqueue_cancel_timeout(sc->as_taskqueue, &sc->as_task, NULL))
taskqueue_drain_timeout(sc->as_taskqueue, &sc->as_task);
/*
* Simulate a disk removal if one is present to deal with any pending
* or queued I/O.
*/
if (sc->as_disk != NULL)
altera_sdcard_disk_remove(sc);
KASSERT(bioq_first(&sc->as_bioq) == NULL,
("%s: non-empty bioq", __func__));
/*
* Free any remaining allocated resources.
*/
taskqueue_free(sc->as_taskqueue);
sc->as_taskqueue = NULL;
ALTERA_SDCARD_CONDVAR_DESTROY(sc);
ALTERA_SDCARD_LOCK_DESTROY(sc);
}
/*
* Set up and start the next I/O. Transition to the I/O state, but allow the
* caller to schedule the next timeout, as this may be called either from an
* initial attach context, or from the task queue, which requires different
* behaviour.
*/
static void
altera_sdcard_nextio(struct altera_sdcard_softc *sc)
{
struct bio *bp;
ALTERA_SDCARD_LOCK_ASSERT(sc);
KASSERT(sc->as_currentbio == NULL,
("%s: bio already active", __func__));
bp = bioq_takefirst(&sc->as_bioq);
if (bp == NULL)
panic("%s: bioq empty", __func__);
altera_sdcard_io_start(sc, bp);
sc->as_state = ALTERA_SDCARD_STATE_IO;
}
static void
altera_sdcard_task_nocard(struct altera_sdcard_softc *sc)
{
ALTERA_SDCARD_LOCK_ASSERT(sc);
/*
* Handle device driver detach.
*/
if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ) {
sc->as_state = ALTERA_SDCARD_STATE_DETACHED;
return;
}
/*
* If there is no card insertion, remain in NOCARD.
*/
if (!(altera_sdcard_read_asr(sc) & ALTERA_SDCARD_ASR_CARDPRESENT))
return;
/*
* Read the CSD -- it may contain values that the driver can't handle,
* either because of an unsupported version/feature, or because the
* card is misbehaving. This triggers a transition to
* ALTERA_SDCARD_STATE_BADCARD. We rely on the CSD read to print a
* banner about how the card is problematic, since it has more
* information. The bad card state allows us to print that banner
* once rather than each time we notice the card is there, and still
* bad.
*/
if (altera_sdcard_read_csd(sc) != 0) {
sc->as_state = ALTERA_SDCARD_STATE_BADCARD;
return;
}
/*
* Process card insertion and upgrade to the IDLE state.
*/
altera_sdcard_disk_insert(sc);
sc->as_state = ALTERA_SDCARD_STATE_IDLE;
}
static void
altera_sdcard_task_badcard(struct altera_sdcard_softc *sc)
{
ALTERA_SDCARD_LOCK_ASSERT(sc);
/*
* Handle device driver detach.
*/
if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ) {
sc->as_state = ALTERA_SDCARD_STATE_DETACHED;
return;
}
/*
* Handle safe card removal -- no teardown is required, just a state
* transition.
*/
if (!(altera_sdcard_read_asr(sc) & ALTERA_SDCARD_ASR_CARDPRESENT))
sc->as_state = ALTERA_SDCARD_STATE_NOCARD;
}
static void
altera_sdcard_task_idle(struct altera_sdcard_softc *sc)
{
ALTERA_SDCARD_LOCK_ASSERT(sc);
/*
* Handle device driver detach.
*/
if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ) {
sc->as_state = ALTERA_SDCARD_STATE_DETACHED;
return;
}
/*
* Handle safe card removal.
*/
if (!(altera_sdcard_read_asr(sc) & ALTERA_SDCARD_ASR_CARDPRESENT)) {
altera_sdcard_disk_remove(sc);
sc->as_state = ALTERA_SDCARD_STATE_NOCARD;
}
}
static void
altera_sdcard_task_io(struct altera_sdcard_softc *sc)
{
uint16_t asr;
ALTERA_SDCARD_LOCK_ASSERT(sc);
KASSERT(sc->as_currentbio != NULL, ("%s: no current I/O", __func__));
#ifdef ALTERA_SDCARD_FAST_SIM
recheck:
#endif
asr = altera_sdcard_read_asr(sc);
/*
* Check for unexpected card removal during an I/O.
*/
if (!(asr & ALTERA_SDCARD_ASR_CARDPRESENT)) {
altera_sdcard_disk_remove(sc);
if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ)
sc->as_state = ALTERA_SDCARD_STATE_DETACHED;
else
sc->as_state = ALTERA_SDCARD_STATE_NOCARD;
return;
}
/*
* If the I/O isn't complete, remain in the IO state without further
* action, even if DETACHREQ is in flight.
*/
if (asr & ALTERA_SDCARD_ASR_CMDINPROGRESS)
return;
/*
* Handle various forms of I/O completion, successful and otherwise.
* The I/O layer may restart the transaction if an error occurred, in
* which case remain in the IO state and reschedule.
*/
if (!altera_sdcard_io_complete(sc, asr))
return;
/*
* Now that I/O is complete, process detach requests in preference to
* starting new I/O.
*/
if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ) {
sc->as_state = ALTERA_SDCARD_STATE_DETACHED;
return;
}
/*
* Finally, either start the next I/O or transition to the IDLE state.
*/
if (bioq_first(&sc->as_bioq) != NULL) {
altera_sdcard_nextio(sc);
#ifdef ALTERA_SDCARD_FAST_SIM
goto recheck;
#endif
} else
sc->as_state = ALTERA_SDCARD_STATE_IDLE;
}
static void
altera_sdcard_task_rechedule(struct altera_sdcard_softc *sc)
{
int interval;
/*
* Reschedule based on new state. Or not, if detaching the device
* driver. Treat a bad card as though it were no card at all.
*/
switch (sc->as_state) {
case ALTERA_SDCARD_STATE_NOCARD:
case ALTERA_SDCARD_STATE_BADCARD:
interval = ALTERA_SDCARD_TIMEOUT_NOCARD;
break;
case ALTERA_SDCARD_STATE_IDLE:
interval = ALTERA_SDCARD_TIMEOUT_IDLE;
break;
case ALTERA_SDCARD_STATE_IO:
if (sc->as_flags & ALTERA_SDCARD_FLAG_IOERROR)
interval = ALTERA_SDCARD_TIMEOUT_IOERROR;
else
interval = ALTERA_SDCARD_TIMEOUT_IO;
break;
default:
panic("%s: invalid exit state %d", __func__, sc->as_state);
}
taskqueue_enqueue_timeout(sc->as_taskqueue, &sc->as_task, interval);
}
/*
* Because the Altera SD Card IP Core doesn't support interrupts, we do all
* asynchronous work from a timeout. Poll at two different rates -- an
* infrequent check for card insertion status changes, and a frequent one for
* I/O completion. The task should never start in DETACHED, as that would
* imply that a previous instance failed to cancel rather than reschedule.
*/
void
altera_sdcard_task(void *arg, int pending)
{
struct altera_sdcard_softc *sc;
sc = arg;
KASSERT(sc->as_state != ALTERA_SDCARD_STATE_DETACHED,
("%s: already in detached", __func__));
ALTERA_SDCARD_LOCK(sc);
switch (sc->as_state) {
case ALTERA_SDCARD_STATE_NOCARD:
altera_sdcard_task_nocard(sc);
break;
case ALTERA_SDCARD_STATE_BADCARD:
altera_sdcard_task_badcard(sc);
break;
case ALTERA_SDCARD_STATE_IDLE:
altera_sdcard_task_idle(sc);
break;
case ALTERA_SDCARD_STATE_IO:
altera_sdcard_task_io(sc);
break;
default:
panic("%s: invalid enter state %d", __func__, sc->as_state);
}
/*
* If we have transitioned to DETACHED, signal the detach thread and
* cancel the timeout-driven task. Otherwise reschedule on an
* appropriate timeout.
*/
if (sc->as_state == ALTERA_SDCARD_STATE_DETACHED)
ALTERA_SDCARD_CONDVAR_SIGNAL(sc);
else
altera_sdcard_task_rechedule(sc);
ALTERA_SDCARD_UNLOCK(sc);
}
void
altera_sdcard_start(struct altera_sdcard_softc *sc)
{
ALTERA_SDCARD_LOCK_ASSERT(sc);
KASSERT(sc->as_state == ALTERA_SDCARD_STATE_IDLE,
("%s: starting when not IDLE", __func__));
taskqueue_cancel_timeout(sc->as_taskqueue, &sc->as_task, NULL);
altera_sdcard_nextio(sc);
#ifdef ALTERA_SDCARD_FAST_SIM
altera_sdcard_task_io(sc);
#endif
altera_sdcard_task_rechedule(sc);
}

View file

@ -1,247 +0,0 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2012 Robert N. M. Watson
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
* ("CTSRD"), as part of the DARPA CRASH research programme.
*
* 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.
*/
#ifndef _DEV_ALTERA_SDCARD_H_
#define _DEV_ALTERA_SDCARD_H_
#define ALTERA_SDCARD_CSD_SIZE 16
struct altera_sdcard_csd {
uint8_t csd_data[ALTERA_SDCARD_CSD_SIZE];
} __aligned(2); /* CSD is read in 16-bit chunks, so align to match. */
struct altera_sdcard_softc {
device_t as_dev;
int as_unit;
struct resource *as_res;
int as_rid;
struct mtx as_lock;
struct cv as_condvar;
int as_state;
int as_flags;
struct disk *as_disk;
struct taskqueue *as_taskqueue;
struct timeout_task as_task;
/*
* Fields relating to in-progress and pending I/O, if any.
*/
struct bio_queue_head as_bioq;
struct bio *as_currentbio;
u_int as_retriesleft;
/*
* Infrequently changing fields cached from the SD Card IP Core.
*/
struct altera_sdcard_csd as_csd;
uint8_t as_csd_structure; /* CSD version. */
uint64_t as_mediasize;
};
#define ALTERA_SDCARD_LOCK(sc) mtx_lock(&(sc)->as_lock)
#define ALTERA_SDCARD_LOCK_ASSERT(sc) mtx_assert(&(sc)->as_lock, MA_OWNED)
#define ALTERA_SDCARD_LOCK_DESTROY(sc) mtx_destroy(&(sc)->as_lock)
#define ALTERA_SDCARD_LOCK_INIT(sc) mtx_init(&(sc)->as_lock, \
"altera_sdcard", NULL, MTX_DEF)
#define ALTERA_SDCARD_UNLOCK(sc) mtx_unlock(&(sc)->as_lock)
#define ALTERA_SDCARD_CONDVAR_DESTROY(sc) cv_destroy(&(sc)->as_condvar)
#define ALTERA_SDCARD_CONDVAR_INIT(sc) cv_init(&(sc)->as_condvar, \
"altera_sdcard_detach_wait")
#define ALTERA_SDCARD_CONDVAR_SIGNAL(dc) cv_signal(&(sc)->as_condvar)
#define ALTERA_SDCARD_CONDVAR_WAIT(sc) cv_wait(&(sc)->as_condvar, \
&(sc)->as_lock)
/*
* States an instance can be in at any given moment.
*/
#define ALTERA_SDCARD_STATE_NOCARD 1 /* No card inserted. */
#define ALTERA_SDCARD_STATE_BADCARD 2 /* Card bad/not supported. */
#define ALTERA_SDCARD_STATE_IDLE 3 /* Card present but idle. */
#define ALTERA_SDCARD_STATE_IO 4 /* Card in I/O currently. */
#define ALTERA_SDCARD_STATE_DETACHED 5 /* Driver is detaching. */
/*
* Different timeout intervals based on state. When just looking for a card
* status change, check twice a second. When we're actively waiting on I/O
* completion, check every millisecond.
*/
#define ALTERA_SDCARD_TIMEOUT_NOCARD (hz/2)
#define ALTERA_SDCARD_TIMEOUT_IDLE (hz/2)
#define ALTERA_SDCARD_TIMEOUT_IO (1)
#define ALTERA_SDCARD_TIMEOUT_IOERROR (hz/5)
/*
* Maximum number of retries on an I/O.
*/
#define ALTERA_SDCARD_RETRY_LIMIT 10
/*
* Driver status flags.
*/
#define ALTERA_SDCARD_FLAG_DETACHREQ 0x00000001 /* Detach requested. */
#define ALTERA_SDCARD_FLAG_IOERROR 0x00000002 /* Error in progress. */
/*
* Functions for performing low-level register and memory I/O to/from the SD
* Card IP Core. In general, only code in altera_sdcard_io.c is aware of the
* hardware interface.
*/
uint16_t altera_sdcard_read_asr(struct altera_sdcard_softc *sc);
int altera_sdcard_read_csd(struct altera_sdcard_softc *sc);
int altera_sdcard_io_complete(struct altera_sdcard_softc *sc,
uint16_t asr);
void altera_sdcard_io_start(struct altera_sdcard_softc *sc,
struct bio *bp);
/*
* Constants for interpreting the SD Card Card Specific Data (CSD) register.
*/
#define ALTERA_SDCARD_CSD_STRUCTURE_BYTE 15
#define ALTERA_SDCARD_CSD_STRUCTURE_MASK 0xc0 /* 2 bits */
#define ALTERA_SDCARD_CSD_STRUCTURE_RSHIFT 6
#define ALTERA_SDCARD_CSD_READ_BL_LEN_BYTE 10
#define ALTERA_SDCARD_CSD_READ_BL_LEN_MASK 0x0f /* 4 bits */
/*
* C_SIZE is a 12-bit field helpfully split over three differe bytes of CSD
* data. Software ease of use was not a design consideration.
*/
#define ALTERA_SDCARD_CSD_C_SIZE_BYTE0 7
#define ALTERA_SDCARD_CSD_C_SIZE_MASK0 0xc0 /* top 2 bits */
#define ALTERA_SDCARD_CSD_C_SIZE_RSHIFT0 6
#define ALTERA_SDCARD_CSD_C_SIZE_BYTE1 8
#define ALTERA_SDCARD_CSD_C_SIZE_MASK1 0xff /* 8 bits */
#define ALTERA_SDCARD_CSD_C_SIZE_LSHIFT1 2
#define ALTERA_SDCARD_CSD_C_SIZE_BYTE2 9
#define ALTERA_SDCARD_CSD_C_SIZE_MASK2 0x03 /* bottom 2 bits */
#define ALTERA_SDCARD_CSD_C_SIZE_LSHIFT2 10
#define ALTERA_SDCARD_CSD_C_SIZE_MULT_BYTE0 5
#define ALTERA_SDCARD_CSD_C_SIZE_MULT_MASK0 0x80 /* top 1 bit */
#define ALTERA_SDCARD_CSD_C_SIZE_MULT_RSHIFT0 7
#define ALTERA_SDCARD_CSD_C_SIZE_MULT_BYTE1 6
#define ALTERA_SDCARD_CSD_C_SIZE_MULT_MASK1 0x03 /* bottom 2 bits */
#define ALTERA_SDCARD_CSD_C_SIZE_MULT_LSHIFT1 1
/*
* I/O register/buffer offsets, from Table 4.1.1 in the Altera University
* Program SD Card IP Core specification.
*/
#define ALTERA_SDCARD_OFF_RXTX_BUFFER 0 /* 512-byte I/O buffer */
#define ALTERA_SDCARD_OFF_CID 512 /* 16-byte Card ID number */
#define ALTERA_SDCARD_OFF_CSD 528 /* 16-byte Card Specific Data */
#define ALTERA_SDCARD_OFF_OCR 544 /* Operating Conditions Reg */
#define ALTERA_SDCARD_OFF_SR 548 /* SD Card Status Register */
#define ALTERA_SDCARD_OFF_RCA 552 /* Relative Card Address Reg */
#define ALTERA_SDCARD_OFF_CMD_ARG 556 /* Command Argument Register */
#define ALTERA_SDCARD_OFF_CMD 560 /* Command Register */
#define ALTERA_SDCARD_OFF_ASR 564 /* Auxiliary Status Register */
#define ALTERA_SDCARD_OFF_RR1 568 /* Response R1 */
/*
* The Altera IP Core provides a 16-bit "Additional Status Register" (ASR)
* beyond those described in the SD Card specification that captures IP Core
* transaction state, such as whether the last command is in progress, the
* card has been removed, etc.
*/
#define ALTERA_SDCARD_ASR_CMDVALID 0x0001
#define ALTERA_SDCARD_ASR_CARDPRESENT 0x0002
#define ALTERA_SDCARD_ASR_CMDINPROGRESS 0x0004
#define ALTERA_SDCARD_ASR_SRVALID 0x0008
#define ALTERA_SDCARD_ASR_CMDTIMEOUT 0x0010
#define ALTERA_SDCARD_ASR_CMDDATAERROR 0x0020
/*
* The Altera IP Core claims to provide a 16-bit "Response R1" register (RR1)
* to provide more detailed error reporting when a read or write fails.
*
* XXXRW: The specification claims that this field is 16-bit, but then
* proceeds to define values as though it is 32-bit. In practice, 16-bit
* seems more likely as the register is not 32-bit aligned.
*/
#define ALTERA_SDCARD_RR1_INITPROCRUNNING 0x0100
#define ALTERA_SDCARD_RR1_ERASEINTERRUPTED 0x0200
#define ALTERA_SDCARD_RR1_ILLEGALCOMMAND 0x0400
#define ALTERA_SDCARD_RR1_COMMANDCRCFAILED 0x0800
#define ALTERA_SDCARD_RR1_ADDRESSMISALIGNED 0x1000
#define ALTERA_SDCARD_RR1_ADDRBLOCKRANGE 0x2000
/*
* Not all RR1 values are "errors" per se -- check only for the ones that are
* when performing error handling.
*/
#define ALTERA_SDCARD_RR1_ERRORMASK \
(ALTERA_SDCARD_RR1_ERASEINTERRUPTED | ALTERA_SDCARD_RR1_ILLEGALCOMMAND | \
ALTERA_SDCARD_RR1_COMMANDCRCFAILED | ALTERA_SDCARD_RR1_ADDRESSMISALIGNED |\
ALTERA_SDCARD_RR1_ADDRBLOCKRANGE)
/*
* Although SD Cards may have various sector sizes, the Altera IP Core
* requires that I/O be done in 512-byte chunks.
*/
#define ALTERA_SDCARD_SECTORSIZE 512
/*
* SD Card commands used in this driver.
*/
#define ALTERA_SDCARD_CMD_SEND_RCA 0x03 /* Retrieve card RCA. */
#define ALTERA_SDCARD_CMD_SEND_CSD 0x09 /* Retrieve CSD register. */
#define ALTERA_SDCARD_CMD_SEND_CID 0x0A /* Retrieve CID register. */
#define ALTERA_SDCARD_CMD_READ_BLOCK 0x11 /* Read block from disk. */
#define ALTERA_SDCARD_CMD_WRITE_BLOCK 0x18 /* Write block to disk. */
/*
* Functions exposed by the device driver core to newbus(9) bus attachment
* implementations.
*/
void altera_sdcard_attach(struct altera_sdcard_softc *sc);
void altera_sdcard_detach(struct altera_sdcard_softc *sc);
void altera_sdcard_task(void *arg, int pending);
/*
* Functions exposed by the device driver core to the disk(9) front-end.
*/
void altera_sdcard_start(struct altera_sdcard_softc *sc);
/*
* Functions relating to the implementation of disk(9) KPIs for the SD Card
* driver.
*/
void altera_sdcard_disk_insert(struct altera_sdcard_softc *sc);
void altera_sdcard_disk_remove(struct altera_sdcard_softc *sc);
#endif /* _DEV_ALTERA_SDCARD_H_ */

View file

@ -1,184 +0,0 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2012 Robert N. M. Watson
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
* ("CTSRD"), as part of the DARPA CRASH research programme.
*
* 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.
*/
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/condvar.h>
#include <sys/conf.h>
#include <sys/bio.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/rman.h>
#include <sys/systm.h>
#include <sys/taskqueue.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <geom/geom_disk.h>
#include <dev/altera/sdcard/altera_sdcard.h>
static int
altera_sdcard_disk_dump(void *arg, void *virtual, vm_offset_t physical,
off_t offset, size_t length)
{
panic("%s: not yet", __func__);
}
static int
altera_sdcard_disk_ioctl(struct disk *disk, u_long cmd, void *data, int fflag,
struct thread *td)
{
/* XXXRW: more here? */
return (EINVAL);
}
static void
altera_sdcard_disk_strategy(struct bio *bp)
{
struct altera_sdcard_softc *sc;
/*
* Although the SD Card doesn't need sorting, we don't want to
* introduce barriers, so use bioq_disksort().
*/
sc = bp->bio_disk->d_drv1;
ALTERA_SDCARD_LOCK(sc);
switch (sc->as_state) {
case ALTERA_SDCARD_STATE_NOCARD:
device_printf(sc->as_dev, "%s: unexpected I/O on NOCARD",
__func__);
biofinish(bp, NULL, ENXIO);
break;
case ALTERA_SDCARD_STATE_BADCARD:
device_printf(sc->as_dev, "%s: unexpected I/O on BADCARD",
__func__);
biofinish(bp, NULL, ENXIO);
break;
case ALTERA_SDCARD_STATE_DETACHED:
device_printf(sc->as_dev, "%s: unexpected I/O on DETACHED",
__func__);
biofinish(bp, NULL, ENXIO);
case ALTERA_SDCARD_STATE_IDLE:
bioq_disksort(&sc->as_bioq, bp);
altera_sdcard_start(sc);
break;
case ALTERA_SDCARD_STATE_IO:
bioq_disksort(&sc->as_bioq, bp);
break;
default:
panic("%s: invalid state %d", __func__, sc->as_state);
}
ALTERA_SDCARD_UNLOCK(sc);
}
void
altera_sdcard_disk_insert(struct altera_sdcard_softc *sc)
{
struct disk *disk;
uint64_t size;
ALTERA_SDCARD_LOCK_ASSERT(sc);
/*
* Because the disk insertion routine occupies the driver instance's
* task queue thread, and the disk(9) instance isn't hooked up yet by
* definition, the only other source of events of concern is a thread
* initiating driver detach. That thread has to issue a detach
* request and await an ACK from the taskqueue thread. It is
* therefore safe to drop the lock here.
*/
ALTERA_SDCARD_UNLOCK(sc);
disk = disk_alloc();
disk->d_drv1 = sc;
disk->d_name = "altera_sdcard";
disk->d_unit = sc->as_unit;
disk->d_strategy = altera_sdcard_disk_strategy;
disk->d_dump = altera_sdcard_disk_dump;
disk->d_ioctl = altera_sdcard_disk_ioctl;
disk->d_sectorsize = ALTERA_SDCARD_SECTORSIZE;
disk->d_mediasize = sc->as_mediasize;
disk->d_maxsize = ALTERA_SDCARD_SECTORSIZE;
sc->as_disk = disk;
disk_create(disk, DISK_VERSION);
ALTERA_SDCARD_LOCK(sc);
/*
* Print a pretty-ish card insertion string. We could stand to
* decorate this further, e.g., with card vendor information.
*/
size = sc->as_mediasize / (1000 * 1000);
device_printf(sc->as_dev, "%juM SD Card inserted\n", (uintmax_t)size);
}
void
altera_sdcard_disk_remove(struct altera_sdcard_softc *sc)
{
struct disk *disk;
ALTERA_SDCARD_LOCK_ASSERT(sc);
KASSERT(sc->as_disk != NULL, ("%s: as_disk NULL", __func__));
/*
* sc->as_state will be updated by the caller.
*
* XXXRW: Is it OK to call disk_destroy() under the mutex, or should
* we be deferring that to the calling context once it is released?
*/
disk = sc->as_disk;
disk_gone(disk);
disk_destroy(disk);
sc->as_disk = NULL;
/*
* Cancel all outstanding I/O on the SD Card.
*/
if (sc->as_currentbio != NULL) {
device_printf(sc->as_dev, "%s: SD Card removed during I/O",
__func__);
biofinish(sc->as_currentbio, NULL, ENXIO);
sc->as_currentbio = NULL;
}
bioq_flush(&sc->as_bioq, NULL, ENXIO);
device_printf(sc->as_dev, "SD Card removed\n");
}

View file

@ -1,121 +0,0 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2012 Robert N. M. Watson
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
* ("CTSRD"), as part of the DARPA CRASH research programme.
*
* 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.
*/
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/condvar.h>
#include <sys/conf.h>
#include <sys/bio.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/rman.h>
#include <sys/systm.h>
#include <sys/taskqueue.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <geom/geom_disk.h>
#include <dev/altera/sdcard/altera_sdcard.h>
#include <dev/fdt/fdt_common.h>
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
/*
* FDT bus attachment for the Altera SD Card IP core.
*/
static int
altera_sdcard_fdt_probe(device_t dev)
{
if (!ofw_bus_status_okay(dev))
return (ENXIO);
if (ofw_bus_is_compatible(dev, "altera,sdcard_11_2011")) {
device_set_desc(dev, "Altera Secure Data Card IP Core");
return (BUS_PROBE_DEFAULT);
}
return (ENXIO);
}
static int
altera_sdcard_fdt_attach(device_t dev)
{
struct altera_sdcard_softc *sc;
sc = device_get_softc(dev);
sc->as_dev = dev;
sc->as_unit = device_get_unit(dev);
sc->as_rid = 0;
sc->as_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
&sc->as_rid, RF_ACTIVE);
if (sc->as_res == NULL) {
device_printf(dev, "couldn't map memory\n");
return (ENXIO);
}
altera_sdcard_attach(sc);
return (0);
}
static int
altera_sdcard_fdt_detach(device_t dev)
{
struct altera_sdcard_softc *sc;
sc = device_get_softc(dev);
KASSERT(sc->as_res != NULL, ("%s: resources not allocated",
__func__));
altera_sdcard_detach(sc);
bus_release_resource(dev, SYS_RES_MEMORY, sc->as_rid, sc->as_res);
return (0);
}
static device_method_t altera_sdcard_fdt_methods[] = {
DEVMETHOD(device_probe, altera_sdcard_fdt_probe),
DEVMETHOD(device_attach, altera_sdcard_fdt_attach),
DEVMETHOD(device_detach, altera_sdcard_fdt_detach),
{ 0, 0 }
};
static driver_t altera_sdcard_fdt_driver = {
"altera_sdcardc",
altera_sdcard_fdt_methods,
sizeof(struct altera_sdcard_softc),
};
DRIVER_MODULE(altera_sdcard, simplebus, altera_sdcard_fdt_driver, 0, 0);

View file

@ -1,446 +0,0 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2012 Robert N. M. Watson
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
* ("CTSRD"), as part of the DARPA CRASH research programme.
*
* 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.
*/
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/condvar.h>
#include <sys/conf.h>
#include <sys/bio.h>
#include <sys/endian.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/rman.h>
#include <sys/systm.h>
#include <sys/taskqueue.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <geom/geom_disk.h>
#include <dev/altera/sdcard/altera_sdcard.h>
int altera_sdcard_ignore_crc_errors = 1;
int altera_sdcard_verify_rxtx_writes = 1;
/*
* Low-level I/O routines for the Altera SD Card University IP Core driver.
*
* XXXRW: Throughout, it is assumed that the IP Core handles multibyte
* registers as little endian, as is the case for other Altera IP cores.
* However, the specification makes no reference to endianness, so this
* assumption might not always be correct.
*/
uint16_t
altera_sdcard_read_asr(struct altera_sdcard_softc *sc)
{
return (le16toh(bus_read_2(sc->as_res, ALTERA_SDCARD_OFF_ASR)));
}
static int
altera_sdcard_process_csd0(struct altera_sdcard_softc *sc)
{
uint64_t c_size, c_size_mult, read_bl_len;
uint8_t byte0, byte1, byte2;
ALTERA_SDCARD_LOCK_ASSERT(sc);
/*-
* Compute card capacity per SD Card interface description as follows:
*
* Memory capacity = BLOCKNR * BLOCK_LEN
*
* Where:
*
* BLOCKNR = (C_SIZE + 1) * MULT
* MULT = 2^(C_SIZE_MULT+2)
* BLOCK_LEN = 2^READ_BL_LEN
*/
read_bl_len = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_READ_BL_LEN_BYTE];
read_bl_len &= ALTERA_SDCARD_CSD_READ_BL_LEN_MASK;
byte0 = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_C_SIZE_BYTE0];
byte0 &= ALTERA_SDCARD_CSD_C_SIZE_MASK0;
byte1 = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_C_SIZE_BYTE1];
byte2 = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_C_SIZE_BYTE2];
byte2 &= ALTERA_SDCARD_CSD_C_SIZE_MASK2;
c_size = (byte0 >> ALTERA_SDCARD_CSD_C_SIZE_RSHIFT0) |
(byte1 << ALTERA_SDCARD_CSD_C_SIZE_LSHIFT1) |
(byte2 << ALTERA_SDCARD_CSD_C_SIZE_LSHIFT2);
byte0 = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_C_SIZE_MULT_BYTE0];
byte0 &= ALTERA_SDCARD_CSD_C_SIZE_MULT_MASK0;
byte1 = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_C_SIZE_MULT_BYTE1];
byte1 &= ALTERA_SDCARD_CSD_C_SIZE_MULT_MASK1;
c_size_mult = (byte0 >> ALTERA_SDCARD_CSD_C_SIZE_MULT_RSHIFT0) |
(byte1 << ALTERA_SDCARD_CSD_C_SIZE_MULT_LSHIFT1);
/*
* If we're just getting back zero's, mark the card as bad, even
* though it could just mean a Very Small Disk Indeed.
*/
if (c_size == 0 && c_size_mult == 0 && read_bl_len == 0) {
device_printf(sc->as_dev, "Ignored zero-size card\n");
return (ENXIO);
}
sc->as_mediasize = (c_size + 1) * (1 << (c_size_mult + 2)) *
(1 << read_bl_len);
return (0);
}
int
altera_sdcard_read_csd(struct altera_sdcard_softc *sc)
{
uint8_t csd_structure;
int error;
ALTERA_SDCARD_LOCK_ASSERT(sc);
/*
* XXXRW: Assume for now that when the SD Card IP Core negotiates
* voltage/speed/etc, it must use the CSD register, and therefore
* populates the SD Card IP Core's cache of the register value. This
* means that we can read it without issuing further SD Card commands.
* If this assumption proves false, we will (a) get back garbage and
* (b) need to add additional states in the driver state machine in
* order to query card properties before I/O can start.
*
* XXXRW: Treating this as an array of bytes, so no byte swapping --
* is that a safe assumption?
*/
KASSERT(((uintptr_t)&sc->as_csd.csd_data) % 2 == 0,
("%s: CSD buffer unaligned", __func__));
bus_read_region_2(sc->as_res, ALTERA_SDCARD_OFF_CSD,
(uint16_t *)sc->as_csd.csd_data, sizeof(sc->as_csd) / 2);
/*
* Interpret the loaded CSD, extracting certain fields and copying
* them into the softc for easy software access.
*
* Currently, we support only CSD Version 1.0. If we detect a newer
* version, suppress card detection.
*/
csd_structure = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_STRUCTURE_BYTE];
csd_structure &= ALTERA_SDCARD_CSD_STRUCTURE_MASK;
csd_structure >>= ALTERA_SDCARD_CSD_STRUCTURE_RSHIFT;
sc->as_csd_structure = csd_structure;
/*
* Interpret the CSD field based on its version. Extract fields,
* especially mediasize.
*
* XXXRW: Desirable to support further CSD versions here.
*/
switch (sc->as_csd_structure) {
case 0:
error = altera_sdcard_process_csd0(sc);
if (error)
return (error);
break;
default:
device_printf(sc->as_dev,
"Ignored disk with unsupported CSD structure (%d)\n",
sc->as_csd_structure);
return (ENXIO);
}
return (0);
}
/*
* XXXRW: The Altera IP Core specification indicates that RR1 is a 16-bit
* register, but all bits it identifies are >16 bit. Most likely, RR1 is a
* 32-bit register?
*/
static uint16_t
altera_sdcard_read_rr1(struct altera_sdcard_softc *sc)
{
return (le16toh(bus_read_2(sc->as_res, ALTERA_SDCARD_OFF_RR1)));
}
static void
altera_sdcard_write_cmd_arg(struct altera_sdcard_softc *sc, uint32_t cmd_arg)
{
bus_write_4(sc->as_res, ALTERA_SDCARD_OFF_CMD_ARG, htole32(cmd_arg));
}
static void
altera_sdcard_write_cmd(struct altera_sdcard_softc *sc, uint16_t cmd)
{
bus_write_2(sc->as_res, ALTERA_SDCARD_OFF_CMD, htole16(cmd));
}
static void
altera_sdcard_read_rxtx_buffer(struct altera_sdcard_softc *sc, void *data,
size_t len)
{
KASSERT((uintptr_t)data % 2 == 0,
("%s: unaligned data %p", __func__, data));
KASSERT((len <= ALTERA_SDCARD_SECTORSIZE) && (len % 2 == 0),
("%s: invalid length %ju", __func__, len));
bus_read_region_2(sc->as_res, ALTERA_SDCARD_OFF_RXTX_BUFFER,
(uint16_t *)data, len / 2);
}
static void
altera_sdcard_write_rxtx_buffer(struct altera_sdcard_softc *sc, void *data,
size_t len)
{
u_int corrections, differences, i, retry_counter;
uint16_t d, v;
KASSERT((uintptr_t)data % 2 == 0,
("%s: unaligned data %p", __func__, data));
KASSERT((len <= ALTERA_SDCARD_SECTORSIZE) && (len % 2 == 0),
("%s: invalid length %ju", __func__, len));
retry_counter = 0;
do {
bus_write_region_2(sc->as_res, ALTERA_SDCARD_OFF_RXTX_BUFFER,
(uint16_t *)data, len / 2);
/*
* XXXRW: Due to a possible hardware bug, the above call to
* bus_write_region_2() might not succeed. If the workaround
* is enabled, verify each write and retry until it succeeds.
*
* XXXRW: Do we want a limit counter for retries here?
*/
recheck:
corrections = 0;
differences = 0;
if (altera_sdcard_verify_rxtx_writes) {
for (i = 0; i < ALTERA_SDCARD_SECTORSIZE; i += 2) {
v = bus_read_2(sc->as_res,
ALTERA_SDCARD_OFF_RXTX_BUFFER + i);
d = *(uint16_t *)((uint8_t *)data + i);
if (v != d) {
if (retry_counter == 0) {
bus_write_2(sc->as_res,
ALTERA_SDCARD_OFF_RXTX_BUFFER + i,
d);
v = bus_read_2(sc->as_res,
ALTERA_SDCARD_OFF_RXTX_BUFFER + i);
if (v == d) {
corrections++;
device_printf(sc->as_dev,
"%s: single word rewrite worked"
" at offset %u\n",
__func__, i);
continue;
}
}
differences++;
device_printf(sc->as_dev,
"%s: retrying write -- difference"
" %u at offset %u, retry %u\n",
__func__, differences, i,
retry_counter);
}
}
if (differences != 0) {
retry_counter++;
if (retry_counter == 1 &&
corrections == differences)
goto recheck;
}
}
} while (differences != 0);
if (retry_counter)
device_printf(sc->as_dev, "%s: succeeded after %u retries\n",
__func__, retry_counter);
}
static void
altera_sdcard_io_start_internal(struct altera_sdcard_softc *sc,
struct bio **bpp)
{
struct bio *bp;
bp = *bpp;
switch (bp->bio_cmd) {
case BIO_READ:
altera_sdcard_write_cmd_arg(sc, bp->bio_pblkno *
ALTERA_SDCARD_SECTORSIZE);
altera_sdcard_write_cmd(sc, ALTERA_SDCARD_CMD_READ_BLOCK);
break;
case BIO_WRITE:
altera_sdcard_write_rxtx_buffer(sc, bp->bio_data,
bp->bio_bcount);
altera_sdcard_write_cmd_arg(sc, bp->bio_pblkno *
ALTERA_SDCARD_SECTORSIZE);
altera_sdcard_write_cmd(sc, ALTERA_SDCARD_CMD_WRITE_BLOCK);
break;
default:
biofinish(bp, NULL, EOPNOTSUPP);
*bpp = NULL;
}
}
void
altera_sdcard_io_start(struct altera_sdcard_softc *sc, struct bio *bp)
{
ALTERA_SDCARD_LOCK_ASSERT(sc);
KASSERT(sc->as_currentbio == NULL,
("%s: bio already started", __func__));
/*
* We advertise a block size and maximum I/O size up the stack of the
* SD Card IP Core sector size. Catch any attempts to not follow the
* rules.
*/
KASSERT(bp->bio_bcount == ALTERA_SDCARD_SECTORSIZE,
("%s: I/O size not %d", __func__, ALTERA_SDCARD_SECTORSIZE));
altera_sdcard_io_start_internal(sc, &bp);
sc->as_currentbio = bp;
sc->as_retriesleft = ALTERA_SDCARD_RETRY_LIMIT;
}
/*
* Handle completed I/O. ASR is passed in to avoid reading it more than once.
* Return 1 if the I/O is actually complete (success, or retry limit
* exceeded), or 0 if not.
*/
int
altera_sdcard_io_complete(struct altera_sdcard_softc *sc, uint16_t asr)
{
struct bio *bp;
uint16_t rr1, mask;
int error;
ALTERA_SDCARD_LOCK_ASSERT(sc);
KASSERT(!(asr & ALTERA_SDCARD_ASR_CMDINPROGRESS),
("%s: still in progress", __func__));
KASSERT(asr & ALTERA_SDCARD_ASR_CARDPRESENT,
("%s: card removed", __func__));
bp = sc->as_currentbio;
/*-
* Handle I/O retries if an error is returned by the device. Various
* quirks handled in the process:
*
* 1. ALTERA_SDCARD_ASR_CMDDATAERROR is ignored for BIO_WRITE.
* 2. ALTERA_SDCARD_RR1_COMMANDCRCFAILED is optionally ignored for
* BIO_READ.
*/
error = 0;
rr1 = altera_sdcard_read_rr1(sc);
switch (bp->bio_cmd) {
case BIO_READ:
mask = ALTERA_SDCARD_RR1_ERRORMASK;
if (altera_sdcard_ignore_crc_errors)
mask &= ~ALTERA_SDCARD_RR1_COMMANDCRCFAILED;
if (asr & ALTERA_SDCARD_ASR_CMDTIMEOUT)
error = EIO;
else if ((asr & ALTERA_SDCARD_ASR_CMDDATAERROR) &&
(rr1 & mask))
error = EIO;
else
error = 0;
break;
case BIO_WRITE:
if (asr & ALTERA_SDCARD_ASR_CMDTIMEOUT)
error = EIO;
else
error = 0;
break;
default:
break;
}
if (error) {
sc->as_retriesleft--;
if (sc->as_retriesleft == 0 || bootverbose)
device_printf(sc->as_dev, "%s: %s operation block %ju "
"length %ju failed; asr 0x%08x (rr1: 0x%04x)%s\n",
__func__, bp->bio_cmd == BIO_READ ? "BIO_READ" :
(bp->bio_cmd == BIO_WRITE ? "BIO_WRITE" :
"unknown"),
bp->bio_pblkno, bp->bio_bcount, asr, rr1,
sc->as_retriesleft != 0 ? " retrying" : "");
/*
* This attempt experienced an error; possibly retry.
*/
if (sc->as_retriesleft != 0) {
sc->as_flags |= ALTERA_SDCARD_FLAG_IOERROR;
altera_sdcard_io_start_internal(sc, &bp);
return (0);
}
sc->as_flags &= ~ALTERA_SDCARD_FLAG_IOERROR;
} else {
/*
* Successful I/O completion path.
*/
if (sc->as_flags & ALTERA_SDCARD_FLAG_IOERROR) {
device_printf(sc->as_dev, "%s: %s operation block %ju"
" length %ju succeeded after %d retries\n",
__func__, bp->bio_cmd == BIO_READ ? "BIO_READ" :
(bp->bio_cmd == BIO_WRITE ? "write" : "unknown"),
bp->bio_pblkno, bp->bio_bcount,
ALTERA_SDCARD_RETRY_LIMIT - sc->as_retriesleft);
sc->as_flags &= ~ALTERA_SDCARD_FLAG_IOERROR;
}
switch (bp->bio_cmd) {
case BIO_READ:
altera_sdcard_read_rxtx_buffer(sc, bp->bio_data,
bp->bio_bcount);
break;
case BIO_WRITE:
break;
default:
panic("%s: unsupported I/O operation %d", __func__,
bp->bio_cmd);
}
bp->bio_resid = 0;
error = 0;
}
biofinish(bp, NULL, error);
sc->as_currentbio = NULL;
return (1);
}

View file

@ -1,112 +0,0 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2012 Robert N. M. Watson
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
* ("CTSRD"), as part of the DARPA CRASH research programme.
*
* 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.
*/
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/condvar.h>
#include <sys/conf.h>
#include <sys/bio.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/rman.h>
#include <sys/systm.h>
#include <sys/taskqueue.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <geom/geom_disk.h>
#include <dev/altera/sdcard/altera_sdcard.h>
/*
* Nexus bus attachment for the Altera SD Card IP core. Appropriate for most
* Altera FPGA SoC-style configurations in which the IP core will be exposed
* to the processor via a memory-mapped Avalon bus.
*/
static int
altera_sdcard_nexus_probe(device_t dev)
{
device_set_desc(dev, "Altera Secure Data Card IP Core");
return (BUS_PROBE_NOWILDCARD);
}
static int
altera_sdcard_nexus_attach(device_t dev)
{
struct altera_sdcard_softc *sc;
sc = device_get_softc(dev);
sc->as_dev = dev;
sc->as_unit = device_get_unit(dev);
sc->as_rid = 0;
sc->as_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
&sc->as_rid, RF_ACTIVE);
if (sc->as_res == NULL) {
device_printf(dev, "couldn't map memory\n");
return (ENXIO);
}
altera_sdcard_attach(sc);
return (0);
}
static int
altera_sdcard_nexus_detach(device_t dev)
{
struct altera_sdcard_softc *sc;
sc = device_get_softc(dev);
KASSERT(sc->as_res != NULL, ("%s: resources not allocated",
__func__));
altera_sdcard_detach(sc);
bus_release_resource(dev, SYS_RES_MEMORY, sc->as_rid, sc->as_res);
return (0);
}
static device_method_t altera_sdcard_nexus_methods[] = {
DEVMETHOD(device_probe, altera_sdcard_nexus_probe),
DEVMETHOD(device_attach, altera_sdcard_nexus_attach),
DEVMETHOD(device_detach, altera_sdcard_nexus_detach),
{ 0, 0 }
};
static driver_t altera_sdcard_nexus_driver = {
"altera_sdcardc",
altera_sdcard_nexus_methods,
sizeof(struct altera_sdcard_softc),
};
DRIVER_MODULE(altera_sdcard, nexus, altera_sdcard_nexus_driver, 0, 0);

View file

@ -1,98 +0,0 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2012 Bjoern A. Zeeb
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-11-C-0249)
* ("MRC2"), as part of the DARPA MRC research programme.
*
* 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.
*/
/*
* Altera, Embedded Peripherals IP, User Guide, v. 11.0, June 2011.
* UG-01085-11.0.
*/
#ifndef _A_API_H
#define _A_API_H
/* Table 16-1. Memory Map. */
#define A_ONCHIP_FIFO_MEM_CORE_DATA 0x00
#define A_ONCHIP_FIFO_MEM_CORE_METADATA 0x04
#define A_ONCHIP_FIFO_MEM_CORE_SOP (1<<0)
#define A_ONCHIP_FIFO_MEM_CORE_EOP (1<<1)
#define A_ONCHIP_FIFO_MEM_CORE_EMPTY_MASK 0x000000f7
#define A_ONCHIP_FIFO_MEM_CORE_EMPTY_SHIFT 2
/* Reserved (1<<7) */
#define A_ONCHIP_FIFO_MEM_CORE_CHANNEL_MASK 0x0000ff00
#define A_ONCHIP_FIFO_MEM_CORE_CHANNEL_SHIFT 8
#define A_ONCHIP_FIFO_MEM_CORE_ERROR_MASK 0x00ff0000
#define A_ONCHIP_FIFO_MEM_CORE_ERROR_SHIFT 16
/* Reserved 0xff000000 */
/* Table 16-3. FIFO Status Register Memory Map. */
#define A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_FILL_LEVEL 0x00
#define A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_I_STATUS 0x04
#define A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_EVENT 0x08
#define A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_INT_ENABLE 0x0c
#define A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_ALMOSTFULL 0x10
#define A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_ALMOSTEMPTY 0x14
/* Table 16-5. Status Bit Field Descriptions. */
#define A_ONCHIP_FIFO_MEM_CORE_STATUS_FULL (1<<0)
#define A_ONCHIP_FIFO_MEM_CORE_STATUS_EMPTY (1<<1)
#define A_ONCHIP_FIFO_MEM_CORE_STATUS_ALMOSTFULL (1<<2)
#define A_ONCHIP_FIFO_MEM_CORE_STATUS_ALMOSTEMPTY (1<<3)
#define A_ONCHIP_FIFO_MEM_CORE_STATUS_OVERFLOW (1<<4)
#define A_ONCHIP_FIFO_MEM_CORE_STATUS_UNDERFLOW (1<<5)
/* Table 16-6. Event Bit Field Descriptions. */
/* XXX Datasheet has incorrect bit fields. Validate. */
#define A_ONCHIP_FIFO_MEM_CORE_EVENT_FULL (1<<0)
#define A_ONCHIP_FIFO_MEM_CORE_EVENT_EMPTY (1<<1)
#define A_ONCHIP_FIFO_MEM_CORE_EVENT_ALMOSTFULL (1<<2)
#define A_ONCHIP_FIFO_MEM_CORE_EVENT_ALMOSTEMPTY (1<<3)
#define A_ONCHIP_FIFO_MEM_CORE_EVENT_OVERFLOW (1<<4)
#define A_ONCHIP_FIFO_MEM_CORE_EVENT_UNDERFLOW (1<<5)
/* Table 16-7. InterruptEnable Bit Field Descriptions. */
/* XXX Datasheet has incorrect bit fields. Validate. */
#define A_ONCHIP_FIFO_MEM_CORE_INTR_FULL (1<<0)
#define A_ONCHIP_FIFO_MEM_CORE_INTR_EMPTY (1<<1)
#define A_ONCHIP_FIFO_MEM_CORE_INTR_ALMOSTFULL (1<<2)
#define A_ONCHIP_FIFO_MEM_CORE_INTR_ALMOSTEMPTY (1<<3)
#define A_ONCHIP_FIFO_MEM_CORE_INTR_OVERFLOW (1<<4)
#define A_ONCHIP_FIFO_MEM_CORE_INTR_UNDERFLOW (1<<5)
#define A_ONCHIP_FIFO_MEM_CORE_INTR_ALL \
(A_ONCHIP_FIFO_MEM_CORE_INTR_EMPTY| \
A_ONCHIP_FIFO_MEM_CORE_INTR_FULL| \
A_ONCHIP_FIFO_MEM_CORE_INTR_ALMOSTEMPTY| \
A_ONCHIP_FIFO_MEM_CORE_INTR_ALMOSTFULL| \
A_ONCHIP_FIFO_MEM_CORE_INTR_OVERFLOW| \
A_ONCHIP_FIFO_MEM_CORE_INTR_UNDERFLOW)
#endif /* _A_API_H */
/* end */

View file

@ -1,882 +0,0 @@
/*-
* Copyright (c) 2017-2018 Ruslan Bukin <br@bsdpad.com>
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
* ("CTSRD"), as part of the DARPA CRASH research programme.
*
* 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.
*/
/* This is driver for SoftDMA device built using Altera FIFO component. */
#include <sys/cdefs.h>
#include "opt_platform.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/bus.h>
#include <sys/endian.h>
#include <sys/kernel.h>
#include <sys/kthread.h>
#include <sys/module.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/resource.h>
#include <sys/rman.h>
#include <machine/bus.h>
#ifdef FDT
#include <dev/fdt/fdt_common.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
#endif
#include <dev/altera/softdma/a_api.h>
#include <dev/xdma/xdma.h>
#include "xdma_if.h"
#define SOFTDMA_DEBUG
#undef SOFTDMA_DEBUG
#ifdef SOFTDMA_DEBUG
#define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__)
#else
#define dprintf(fmt, ...)
#endif
#define AVALON_FIFO_TX_BASIC_OPTS_DEPTH 16
#define SOFTDMA_NCHANNELS 1
#define CONTROL_GEN_SOP (1 << 0)
#define CONTROL_GEN_EOP (1 << 1)
#define CONTROL_OWN (1 << 31)
#define SOFTDMA_RX_EVENTS \
(A_ONCHIP_FIFO_MEM_CORE_INTR_FULL | \
A_ONCHIP_FIFO_MEM_CORE_INTR_OVERFLOW | \
A_ONCHIP_FIFO_MEM_CORE_INTR_UNDERFLOW)
#define SOFTDMA_TX_EVENTS \
(A_ONCHIP_FIFO_MEM_CORE_INTR_EMPTY | \
A_ONCHIP_FIFO_MEM_CORE_INTR_OVERFLOW | \
A_ONCHIP_FIFO_MEM_CORE_INTR_UNDERFLOW)
struct softdma_channel {
struct softdma_softc *sc;
struct mtx mtx;
xdma_channel_t *xchan;
struct proc *p;
int used;
int index;
int run;
uint32_t idx_tail;
uint32_t idx_head;
struct softdma_desc *descs;
uint32_t descs_num;
uint32_t descs_used_count;
};
struct softdma_desc {
uint64_t src_addr;
uint64_t dst_addr;
uint32_t len;
uint32_t access_width;
uint32_t count;
uint16_t src_incr;
uint16_t dst_incr;
uint32_t direction;
struct softdma_desc *next;
uint32_t transfered;
uint32_t status;
uint32_t reserved;
uint32_t control;
};
struct softdma_softc {
device_t dev;
struct resource *res[3];
bus_space_tag_t bst;
bus_space_handle_t bsh;
bus_space_tag_t bst_c;
bus_space_handle_t bsh_c;
void *ih;
struct softdma_channel channels[SOFTDMA_NCHANNELS];
};
static struct resource_spec softdma_spec[] = {
{ SYS_RES_MEMORY, 0, RF_ACTIVE }, /* fifo */
{ SYS_RES_MEMORY, 1, RF_ACTIVE }, /* core */
{ SYS_RES_IRQ, 0, RF_ACTIVE },
{ -1, 0 }
};
static int softdma_probe(device_t dev);
static int softdma_attach(device_t dev);
static int softdma_detach(device_t dev);
static inline uint32_t
softdma_next_desc(struct softdma_channel *chan, uint32_t curidx)
{
return ((curidx + 1) % chan->descs_num);
}
static void
softdma_mem_write(struct softdma_softc *sc, uint32_t reg, uint32_t val)
{
bus_write_4(sc->res[0], reg, htole32(val));
}
static uint32_t
softdma_mem_read(struct softdma_softc *sc, uint32_t reg)
{
uint32_t val;
val = bus_read_4(sc->res[0], reg);
return (le32toh(val));
}
static void
softdma_memc_write(struct softdma_softc *sc, uint32_t reg, uint32_t val)
{
bus_write_4(sc->res[1], reg, htole32(val));
}
static uint32_t
softdma_memc_read(struct softdma_softc *sc, uint32_t reg)
{
uint32_t val;
val = bus_read_4(sc->res[1], reg);
return (le32toh(val));
}
static uint32_t
softdma_fill_level(struct softdma_softc *sc)
{
uint32_t val;
val = softdma_memc_read(sc,
A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_FILL_LEVEL);
return (val);
}
static uint32_t
fifo_fill_level_wait(struct softdma_softc *sc)
{
uint32_t val;
do
val = softdma_fill_level(sc);
while (val == AVALON_FIFO_TX_BASIC_OPTS_DEPTH);
return (val);
}
static void
softdma_intr(void *arg)
{
struct softdma_channel *chan;
struct softdma_softc *sc;
int reg;
int err;
sc = arg;
chan = &sc->channels[0];
reg = softdma_memc_read(sc, A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_EVENT);
if (reg & (A_ONCHIP_FIFO_MEM_CORE_EVENT_OVERFLOW |
A_ONCHIP_FIFO_MEM_CORE_EVENT_UNDERFLOW)) {
/* Errors */
err = (((reg & A_ONCHIP_FIFO_MEM_CORE_ERROR_MASK) >> \
A_ONCHIP_FIFO_MEM_CORE_ERROR_SHIFT) & 0xff);
}
if (reg != 0) {
softdma_memc_write(sc,
A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_EVENT, reg);
chan->run = 1;
wakeup(chan);
}
}
static int
softdma_probe(device_t dev)
{
if (!ofw_bus_status_okay(dev))
return (ENXIO);
if (!ofw_bus_is_compatible(dev, "altr,softdma"))
return (ENXIO);
device_set_desc(dev, "SoftDMA");
return (BUS_PROBE_DEFAULT);
}
static int
softdma_attach(device_t dev)
{
struct softdma_softc *sc;
phandle_t xref, node;
int err;
sc = device_get_softc(dev);
sc->dev = dev;
if (bus_alloc_resources(dev, softdma_spec, sc->res)) {
device_printf(dev,
"could not allocate resources for device\n");
return (ENXIO);
}
/* FIFO memory interface */
sc->bst = rman_get_bustag(sc->res[0]);
sc->bsh = rman_get_bushandle(sc->res[0]);
/* FIFO control memory interface */
sc->bst_c = rman_get_bustag(sc->res[1]);
sc->bsh_c = rman_get_bushandle(sc->res[1]);
/* Setup interrupt handler */
err = bus_setup_intr(dev, sc->res[2], INTR_TYPE_MISC | INTR_MPSAFE,
NULL, softdma_intr, sc, &sc->ih);
if (err) {
device_printf(dev, "Unable to alloc interrupt resource.\n");
return (ENXIO);
}
node = ofw_bus_get_node(dev);
xref = OF_xref_from_node(node);
OF_device_register_xref(xref, dev);
return (0);
}
static int
softdma_detach(device_t dev)
{
struct softdma_softc *sc;
sc = device_get_softc(dev);
return (0);
}
static int
softdma_process_tx(struct softdma_channel *chan, struct softdma_desc *desc)
{
struct softdma_softc *sc;
uint64_t addr;
uint64_t buf;
uint32_t word;
uint32_t missing;
uint32_t reg;
int got_bits;
int len;
sc = chan->sc;
fifo_fill_level_wait(sc);
/* Set start of packet. */
if (desc->control & CONTROL_GEN_SOP)
softdma_mem_write(sc, A_ONCHIP_FIFO_MEM_CORE_METADATA,
A_ONCHIP_FIFO_MEM_CORE_SOP);
got_bits = 0;
buf = 0;
addr = desc->src_addr;
len = desc->len;
if (addr & 1) {
buf = (buf << 8) | *(uint8_t *)addr;
got_bits += 8;
addr += 1;
len -= 1;
}
if (len >= 2 && addr & 2) {
buf = (buf << 16) | *(uint16_t *)addr;
got_bits += 16;
addr += 2;
len -= 2;
}
while (len >= 4) {
buf = (buf << 32) | (uint64_t)*(uint32_t *)addr;
addr += 4;
len -= 4;
word = (uint32_t)((buf >> got_bits) & 0xffffffff);
fifo_fill_level_wait(sc);
if (len == 0 && got_bits == 0 &&
(desc->control & CONTROL_GEN_EOP) != 0)
softdma_mem_write(sc, A_ONCHIP_FIFO_MEM_CORE_METADATA,
A_ONCHIP_FIFO_MEM_CORE_EOP);
bus_write_4(sc->res[0], A_ONCHIP_FIFO_MEM_CORE_DATA, word);
}
if (len & 2) {
buf = (buf << 16) | *(uint16_t *)addr;
got_bits += 16;
addr += 2;
len -= 2;
}
if (len & 1) {
buf = (buf << 8) | *(uint8_t *)addr;
got_bits += 8;
addr += 1;
len -= 1;
}
if (got_bits >= 32) {
got_bits -= 32;
word = (uint32_t)((buf >> got_bits) & 0xffffffff);
fifo_fill_level_wait(sc);
if (len == 0 && got_bits == 0 &&
(desc->control & CONTROL_GEN_EOP) != 0)
softdma_mem_write(sc, A_ONCHIP_FIFO_MEM_CORE_METADATA,
A_ONCHIP_FIFO_MEM_CORE_EOP);
bus_write_4(sc->res[0], A_ONCHIP_FIFO_MEM_CORE_DATA, word);
}
if (got_bits) {
missing = 32 - got_bits;
got_bits /= 8;
fifo_fill_level_wait(sc);
reg = A_ONCHIP_FIFO_MEM_CORE_EOP |
((4 - got_bits) << A_ONCHIP_FIFO_MEM_CORE_EMPTY_SHIFT);
softdma_mem_write(sc, A_ONCHIP_FIFO_MEM_CORE_METADATA, reg);
word = (uint32_t)((buf << missing) & 0xffffffff);
bus_write_4(sc->res[0], A_ONCHIP_FIFO_MEM_CORE_DATA, word);
}
return (desc->len);
}
static int
softdma_process_rx(struct softdma_channel *chan, struct softdma_desc *desc)
{
uint32_t src_offs, dst_offs;
struct softdma_softc *sc;
uint32_t fill_level;
uint32_t empty;
uint32_t meta;
uint32_t data;
int sop_rcvd;
int timeout;
size_t len;
int error;
sc = chan->sc;
empty = 0;
src_offs = dst_offs = 0;
error = 0;
fill_level = softdma_fill_level(sc);
if (fill_level == 0) {
/* Nothing to receive. */
return (0);
}
len = desc->len;
sop_rcvd = 0;
while (fill_level) {
empty = 0;
data = bus_read_4(sc->res[0], A_ONCHIP_FIFO_MEM_CORE_DATA);
meta = softdma_mem_read(sc, A_ONCHIP_FIFO_MEM_CORE_METADATA);
if (meta & A_ONCHIP_FIFO_MEM_CORE_ERROR_MASK) {
error = 1;
break;
}
if ((meta & A_ONCHIP_FIFO_MEM_CORE_CHANNEL_MASK) != 0) {
error = 1;
break;
}
if (meta & A_ONCHIP_FIFO_MEM_CORE_SOP) {
sop_rcvd = 1;
}
if (meta & A_ONCHIP_FIFO_MEM_CORE_EOP) {
empty = (meta & A_ONCHIP_FIFO_MEM_CORE_EMPTY_MASK) >>
A_ONCHIP_FIFO_MEM_CORE_EMPTY_SHIFT;
}
if (sop_rcvd == 0) {
error = 1;
break;
}
if (empty == 0) {
*(uint32_t *)(desc->dst_addr + dst_offs) = data;
dst_offs += 4;
} else if (empty == 1) {
*(uint16_t *)(desc->dst_addr + dst_offs) =
((data >> 16) & 0xffff);
dst_offs += 2;
*(uint8_t *)(desc->dst_addr + dst_offs) =
((data >> 8) & 0xff);
dst_offs += 1;
} else {
panic("empty %d\n", empty);
}
if (meta & A_ONCHIP_FIFO_MEM_CORE_EOP)
break;
fill_level = softdma_fill_level(sc);
timeout = 100;
while (fill_level == 0 && timeout--)
fill_level = softdma_fill_level(sc);
if (timeout == 0) {
/* No EOP received. Broken packet. */
error = 1;
break;
}
}
if (error) {
return (-1);
}
return (dst_offs);
}
static uint32_t
softdma_process_descriptors(struct softdma_channel *chan,
xdma_transfer_status_t *status)
{
struct xdma_channel *xchan;
struct softdma_desc *desc;
struct softdma_softc *sc;
xdma_transfer_status_t st;
int ret;
sc = chan->sc;
xchan = chan->xchan;
desc = &chan->descs[chan->idx_tail];
while (desc != NULL) {
if ((desc->control & CONTROL_OWN) == 0) {
break;
}
if (desc->direction == XDMA_MEM_TO_DEV) {
ret = softdma_process_tx(chan, desc);
} else {
ret = softdma_process_rx(chan, desc);
if (ret == 0) {
/* No new data available. */
break;
}
}
/* Descriptor processed. */
desc->control = 0;
if (ret >= 0) {
st.error = 0;
st.transferred = ret;
} else {
st.error = ret;
st.transferred = 0;
}
xchan_seg_done(xchan, &st);
atomic_subtract_int(&chan->descs_used_count, 1);
if (ret >= 0) {
status->transferred += ret;
} else {
status->error = 1;
break;
}
chan->idx_tail = softdma_next_desc(chan, chan->idx_tail);
/* Process next descriptor, if any. */
desc = desc->next;
}
return (0);
}
static void
softdma_worker(void *arg)
{
xdma_transfer_status_t status;
struct softdma_channel *chan;
struct softdma_softc *sc;
chan = arg;
sc = chan->sc;
while (1) {
mtx_lock(&chan->mtx);
do {
mtx_sleep(chan, &chan->mtx, 0, "softdma_wait", hz / 2);
} while (chan->run == 0);
status.error = 0;
status.transferred = 0;
softdma_process_descriptors(chan, &status);
/* Finish operation */
chan->run = 0;
xdma_callback(chan->xchan, &status);
mtx_unlock(&chan->mtx);
}
}
static int
softdma_proc_create(struct softdma_channel *chan)
{
struct softdma_softc *sc;
sc = chan->sc;
if (chan->p != NULL) {
/* Already created */
return (0);
}
mtx_init(&chan->mtx, "SoftDMA", NULL, MTX_DEF);
if (kproc_create(softdma_worker, (void *)chan, &chan->p, 0, 0,
"softdma_worker") != 0) {
device_printf(sc->dev,
"%s: Failed to create worker thread.\n", __func__);
return (-1);
}
return (0);
}
static int
softdma_channel_alloc(device_t dev, struct xdma_channel *xchan)
{
struct softdma_channel *chan;
struct softdma_softc *sc;
int i;
sc = device_get_softc(dev);
for (i = 0; i < SOFTDMA_NCHANNELS; i++) {
chan = &sc->channels[i];
if (chan->used == 0) {
chan->xchan = xchan;
xchan->chan = (void *)chan;
xchan->caps |= XCHAN_CAP_NOSEG;
chan->index = i;
chan->idx_head = 0;
chan->idx_tail = 0;
chan->descs_used_count = 0;
chan->descs_num = 1024;
chan->sc = sc;
if (softdma_proc_create(chan) != 0) {
return (-1);
}
chan->used = 1;
return (0);
}
}
return (-1);
}
static int
softdma_channel_free(device_t dev, struct xdma_channel *xchan)
{
struct softdma_channel *chan;
struct softdma_softc *sc;
sc = device_get_softc(dev);
chan = (struct softdma_channel *)xchan->chan;
if (chan->descs != NULL) {
free(chan->descs, M_DEVBUF);
}
chan->used = 0;
return (0);
}
static int
softdma_desc_alloc(struct xdma_channel *xchan)
{
struct softdma_channel *chan;
uint32_t nsegments;
chan = (struct softdma_channel *)xchan->chan;
nsegments = chan->descs_num;
chan->descs = malloc(nsegments * sizeof(struct softdma_desc),
M_DEVBUF, (M_WAITOK | M_ZERO));
return (0);
}
static int
softdma_channel_prep_sg(device_t dev, struct xdma_channel *xchan)
{
struct softdma_channel *chan;
struct softdma_desc *desc;
struct softdma_softc *sc;
int ret;
int i;
sc = device_get_softc(dev);
chan = (struct softdma_channel *)xchan->chan;
ret = softdma_desc_alloc(xchan);
if (ret != 0) {
device_printf(sc->dev,
"%s: Can't allocate descriptors.\n", __func__);
return (-1);
}
for (i = 0; i < chan->descs_num; i++) {
desc = &chan->descs[i];
if (i == (chan->descs_num - 1)) {
desc->next = &chan->descs[0];
} else {
desc->next = &chan->descs[i+1];
}
}
return (0);
}
static int
softdma_channel_capacity(device_t dev, xdma_channel_t *xchan,
uint32_t *capacity)
{
struct softdma_channel *chan;
uint32_t c;
chan = (struct softdma_channel *)xchan->chan;
/* At least one descriptor must be left empty. */
c = (chan->descs_num - chan->descs_used_count - 1);
*capacity = c;
return (0);
}
static int
softdma_channel_submit_sg(device_t dev, struct xdma_channel *xchan,
struct xdma_sglist *sg, uint32_t sg_n)
{
struct softdma_channel *chan;
struct softdma_desc *desc;
struct softdma_softc *sc;
uint32_t enqueued;
uint32_t saved_dir;
uint32_t tmp;
uint32_t len;
int i;
sc = device_get_softc(dev);
chan = (struct softdma_channel *)xchan->chan;
enqueued = 0;
for (i = 0; i < sg_n; i++) {
len = (uint32_t)sg[i].len;
desc = &chan->descs[chan->idx_head];
desc->src_addr = sg[i].src_addr;
desc->dst_addr = sg[i].dst_addr;
if (sg[i].direction == XDMA_MEM_TO_DEV) {
desc->src_incr = 1;
desc->dst_incr = 0;
} else {
desc->src_incr = 0;
desc->dst_incr = 1;
}
desc->direction = sg[i].direction;
saved_dir = sg[i].direction;
desc->len = len;
desc->transfered = 0;
desc->status = 0;
desc->reserved = 0;
desc->control = 0;
if (sg[i].first == 1)
desc->control |= CONTROL_GEN_SOP;
if (sg[i].last == 1)
desc->control |= CONTROL_GEN_EOP;
tmp = chan->idx_head;
chan->idx_head = softdma_next_desc(chan, chan->idx_head);
atomic_add_int(&chan->descs_used_count, 1);
desc->control |= CONTROL_OWN;
enqueued += 1;
}
if (enqueued == 0)
return (0);
if (saved_dir == XDMA_MEM_TO_DEV) {
chan->run = 1;
wakeup(chan);
} else
softdma_memc_write(sc,
A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_INT_ENABLE,
SOFTDMA_RX_EVENTS);
return (0);
}
static int
softdma_channel_request(device_t dev, struct xdma_channel *xchan,
struct xdma_request *req)
{
struct softdma_channel *chan;
struct softdma_desc *desc;
struct softdma_softc *sc;
int ret;
sc = device_get_softc(dev);
chan = (struct softdma_channel *)xchan->chan;
ret = softdma_desc_alloc(xchan);
if (ret != 0) {
device_printf(sc->dev,
"%s: Can't allocate descriptors.\n", __func__);
return (-1);
}
desc = &chan->descs[0];
desc->src_addr = req->src_addr;
desc->dst_addr = req->dst_addr;
desc->len = req->block_len;
desc->src_incr = 1;
desc->dst_incr = 1;
desc->next = NULL;
return (0);
}
static int
softdma_channel_control(device_t dev, xdma_channel_t *xchan, int cmd)
{
struct softdma_channel *chan;
struct softdma_softc *sc;
sc = device_get_softc(dev);
chan = (struct softdma_channel *)xchan->chan;
switch (cmd) {
case XDMA_CMD_BEGIN:
case XDMA_CMD_TERMINATE:
case XDMA_CMD_PAUSE:
/* TODO: implement me */
return (-1);
}
return (0);
}
#ifdef FDT
static int
softdma_ofw_md_data(device_t dev, pcell_t *cells,
int ncells, void **ptr)
{
return (0);
}
#endif
static device_method_t softdma_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, softdma_probe),
DEVMETHOD(device_attach, softdma_attach),
DEVMETHOD(device_detach, softdma_detach),
/* xDMA Interface */
DEVMETHOD(xdma_channel_alloc, softdma_channel_alloc),
DEVMETHOD(xdma_channel_free, softdma_channel_free),
DEVMETHOD(xdma_channel_request, softdma_channel_request),
DEVMETHOD(xdma_channel_control, softdma_channel_control),
/* xDMA SG Interface */
DEVMETHOD(xdma_channel_prep_sg, softdma_channel_prep_sg),
DEVMETHOD(xdma_channel_submit_sg, softdma_channel_submit_sg),
DEVMETHOD(xdma_channel_capacity, softdma_channel_capacity),
#ifdef FDT
DEVMETHOD(xdma_ofw_md_data, softdma_ofw_md_data),
#endif
DEVMETHOD_END
};
static driver_t softdma_driver = {
"softdma",
softdma_methods,
sizeof(struct softdma_softc),
};
EARLY_DRIVER_MODULE(softdma, simplebus, softdma_driver, 0, 0,
BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE);

View file

@ -1,181 +0,0 @@
/*-
* Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com>
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
* ("CTSRD"), as part of the DARPA CRASH research programme.
*
* 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.
*/
/*
* BERI memory interface.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/malloc.h>
#include <sys/rman.h>
#include <sys/timeet.h>
#include <sys/timetc.h>
#include <sys/conf.h>
#include <sys/uio.h>
#include <dev/fdt/fdt_common.h>
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
#include <machine/fdt.h>
#include <machine/cpu.h>
#include <machine/intr.h>
struct beri_mem_softc {
struct resource *res[1];
struct cdev *mem_cdev;
device_t dev;
int mem_size;
int mem_start;
};
static struct resource_spec beri_mem_spec[] = {
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
{ -1, 0 }
};
static int
mem_open(struct cdev *dev, int flags __unused,
int fmt __unused, struct thread *td __unused)
{
struct beri_mem_softc *sc;
sc = dev->si_drv1;
return (0);
}
static int
mem_close(struct cdev *dev, int flags __unused,
int fmt __unused, struct thread *td __unused)
{
struct beri_mem_softc *sc;
sc = dev->si_drv1;
return (0);
}
static int
mem_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags,
struct thread *td)
{
return (0);
}
static int
mem_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, int nprot,
vm_memattr_t *memattr)
{
struct beri_mem_softc *sc;
sc = dev->si_drv1;
if (offset < sc->mem_size) {
*paddr = sc->mem_start + offset;
return (0);
}
return (EINVAL);
}
static struct cdevsw mem_cdevsw = {
.d_version = D_VERSION,
.d_open = mem_open,
.d_close = mem_close,
.d_ioctl = mem_ioctl,
.d_mmap = mem_mmap,
.d_name = "BERI memory",
};
static int
beri_mem_probe(device_t dev)
{
if (!ofw_bus_status_okay(dev))
return (ENXIO);
if (!ofw_bus_is_compatible(dev, "sri-cambridge,beri-mem"))
return (ENXIO);
device_set_desc(dev, "BERI memory");
return (BUS_PROBE_DEFAULT);
}
static int
beri_mem_attach(device_t dev)
{
struct beri_mem_softc *sc;
sc = device_get_softc(dev);
sc->dev = dev;
if (bus_alloc_resources(dev, beri_mem_spec, sc->res)) {
device_printf(dev, "could not allocate resources\n");
return (ENXIO);
}
/* Memory info */
sc->mem_size = rman_get_size(sc->res[0]);
sc->mem_start = rman_get_start(sc->res[0]);
sc->mem_cdev = make_dev(&mem_cdevsw, 0, UID_ROOT, GID_WHEEL,
0600, "beri_mem");
if (sc->mem_cdev == NULL) {
device_printf(dev, "Failed to create character device.\n");
return (ENXIO);
}
sc->mem_cdev->si_drv1 = sc;
return (0);
}
static device_method_t beri_mem_methods[] = {
DEVMETHOD(device_probe, beri_mem_probe),
DEVMETHOD(device_attach, beri_mem_attach),
{ 0, 0 }
};
static driver_t beri_mem_driver = {
"beri_mem",
beri_mem_methods,
sizeof(struct beri_mem_softc),
};
DRIVER_MODULE(beri_mem, simplebus, beri_mem_driver, 0, 0);

View file

@ -1,524 +0,0 @@
/*-
* Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com>
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
* ("CTSRD"), as part of the DARPA CRASH research programme.
*
* 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.
*/
/*
* SRI-Cambridge BERI soft processor <-> ARM core ring buffer.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/malloc.h>
#include <sys/rman.h>
#include <sys/timeet.h>
#include <sys/timetc.h>
#include <sys/conf.h>
#include <sys/uio.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/event.h>
#include <sys/selinfo.h>
#include <dev/fdt/fdt_common.h>
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
#include <machine/fdt.h>
#include <machine/cpu.h>
#include <machine/intr.h>
#define READ4(_sc, _reg) \
bus_read_4((_sc)->res[0], _reg)
#define WRITE4(_sc, _reg, _val) \
bus_write_4((_sc)->res[0], _reg, _val)
#define CDES_INT_EN (1 << 15)
#define CDES_CAUSE_MASK 0x3
#define CDES_CAUSE_SHIFT 13
#define DEVNAME_MAXLEN 256
typedef struct
{
uint16_t cdes;
uint16_t interrupt_level;
uint16_t in;
uint16_t out;
} control_reg_t;
struct beri_softc {
struct resource *res[3];
bus_space_tag_t bst;
bus_space_handle_t bsh;
struct cdev *cdev;
device_t dev;
void *read_ih;
void *write_ih;
struct selinfo beri_rsel;
struct mtx beri_mtx;
int opened;
char devname[DEVNAME_MAXLEN];
int control_read;
int control_write;
int data_read;
int data_write;
int data_size;
};
static struct resource_spec beri_spec[] = {
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
{ SYS_RES_IRQ, 0, RF_ACTIVE },
{ SYS_RES_IRQ, 1, RF_ACTIVE },
{ -1, 0 }
};
static control_reg_t
get_control_reg(struct beri_softc *sc, int dir)
{
uint32_t offset;
uint16_t dst[4];
control_reg_t c;
uint16_t *cp;
int i;
cp = (uint16_t *)&c;
offset = dir ? sc->control_write : sc->control_read;
((uint32_t *)dst)[0] = READ4(sc, offset);
((uint32_t *)dst)[1] = READ4(sc, offset + 4);
for (i = 0; i < 4; i++)
cp[i] = dst[3 - i];
return (c);
}
static void
set_control_reg(struct beri_softc *sc, int dir, control_reg_t *c)
{
uint32_t offset;
uint16_t src[4];
uint16_t *cp;
int i;
cp = (uint16_t *)c;
for (i = 0; i < 4; i++)
src[3 - i] = cp[i];
offset = dir ? sc->control_write : sc->control_read;
WRITE4(sc, offset + 0, ((uint32_t *)src)[0]);
WRITE4(sc, offset + 4, ((uint32_t *)src)[1]);
}
static int
get_stock(struct beri_softc *sc, int dir, control_reg_t *c)
{
uint32_t fill;
fill = (c->in - c->out + sc->data_size) % sc->data_size;
if (dir)
return (sc->data_size - fill - 1);
else
return (fill);
}
static void
beri_intr_write(void *arg)
{
struct beri_softc *sc;
control_reg_t c;
sc = arg;
c = get_control_reg(sc, 1);
if (c.cdes & CDES_INT_EN) {
c.cdes &= ~(CDES_INT_EN);
set_control_reg(sc, 1, &c);
}
mtx_lock(&sc->beri_mtx);
selwakeuppri(&sc->beri_rsel, PZERO + 1);
KNOTE_LOCKED(&sc->beri_rsel.si_note, 0);
mtx_unlock(&sc->beri_mtx);
}
static void
beri_intr_read(void *arg)
{
struct beri_softc *sc;
control_reg_t c;
sc = arg;
c = get_control_reg(sc, 0);
if (c.cdes & CDES_INT_EN) {
c.cdes &= ~(CDES_INT_EN);
set_control_reg(sc, 0, &c);
}
mtx_lock(&sc->beri_mtx);
selwakeuppri(&sc->beri_rsel, PZERO + 1);
KNOTE_LOCKED(&sc->beri_rsel.si_note, 0);
mtx_unlock(&sc->beri_mtx);
}
static int
beri_open(struct cdev *dev, int flags __unused,
int fmt __unused, struct thread *td __unused)
{
struct beri_softc *sc;
control_reg_t c;
sc = dev->si_drv1;
if (sc->opened)
return (1);
/* Setup interrupt handlers */
if (bus_setup_intr(sc->dev, sc->res[1], INTR_TYPE_BIO | INTR_MPSAFE,
NULL, beri_intr_read, sc, &sc->read_ih)) {
device_printf(sc->dev, "Unable to setup read intr\n");
return (1);
}
if (bus_setup_intr(sc->dev, sc->res[2], INTR_TYPE_BIO | INTR_MPSAFE,
NULL, beri_intr_write, sc, &sc->write_ih)) {
device_printf(sc->dev, "Unable to setup write intr\n");
return (1);
}
sc->opened = 1;
/* Clear write buffer */
c = get_control_reg(sc, 1);
c.in = c.out;
c.cdes = 0;
set_control_reg(sc, 1, &c);
/* Clear read buffer */
c = get_control_reg(sc, 0);
c.out = c.in;
c.cdes = 0;
set_control_reg(sc, 0, &c);
return (0);
}
static int
beri_close(struct cdev *dev, int flags __unused,
int fmt __unused, struct thread *td __unused)
{
struct beri_softc *sc;
sc = dev->si_drv1;
if (sc->opened) {
sc->opened = 0;
/* Unsetup interrupt handlers */
bus_teardown_intr(sc->dev, sc->res[1], sc->read_ih);
bus_teardown_intr(sc->dev, sc->res[2], sc->write_ih);
}
return (0);
}
static int
beri_rdwr(struct cdev *dev, struct uio *uio, int ioflag)
{
struct beri_softc *sc;
uint32_t offset;
control_reg_t c;
uint16_t *ptr;
uint8_t *dst;
int stock;
int dir;
int amount;
int count;
sc = dev->si_drv1;
dir = uio->uio_rw ? 1 : 0;
c = get_control_reg(sc, dir);
stock = get_stock(sc, dir, &c);
if (stock < uio->uio_resid) {
device_printf(sc->dev, "Err: no data/space available\n");
return (1);
}
amount = uio->uio_resid;
ptr = dir ? &c.in : &c.out;
count = (sc->data_size - *ptr);
offset = dir ? sc->data_write : sc->data_read;
dst = (uint8_t *)(sc->bsh + offset);
if (amount <= count) {
uiomove(dst + *ptr, amount, uio);
} else {
uiomove(dst + *ptr, count, uio);
uiomove(dst, (amount - count), uio);
}
*ptr = (*ptr + amount) % sc->data_size;
set_control_reg(sc, dir, &c);
return (0);
}
static int
beri_kqread(struct knote *kn, long hint)
{
struct beri_softc *sc;
control_reg_t c;
int stock;
sc = kn->kn_hook;
c = get_control_reg(sc, 0);
stock = get_stock(sc, 0, &c);
if (stock) {
kn->kn_data = stock;
return (1);
}
kn->kn_data = 0;
/* Wait at least one new byte in buffer */
c.interrupt_level = 1;
/* Enable interrupts */
c.cdes |= (CDES_INT_EN);
set_control_reg(sc, 0, &c);
return (0);
}
static int
beri_kqwrite(struct knote *kn, long hint)
{
struct beri_softc *sc;
control_reg_t c;
int stock;
sc = kn->kn_hook;
c = get_control_reg(sc, 1);
stock = get_stock(sc, 1, &c);
if (stock) {
kn->kn_data = stock;
return (1);
}
kn->kn_data = 0;
/* Wait at least one free position in buffer */
c.interrupt_level = sc->data_size - 2;
/* Enable interrupts */
c.cdes |= (CDES_INT_EN);
set_control_reg(sc, 1, &c);
return (0);
}
static void
beri_kqdetach(struct knote *kn)
{
struct beri_softc *sc;
sc = kn->kn_hook;
knlist_remove(&sc->beri_rsel.si_note, kn, 0);
}
static const struct filterops beri_read_filterops = {
.f_isfd = 1,
.f_attach = NULL,
.f_detach = beri_kqdetach,
.f_event = beri_kqread,
};
static const struct filterops beri_write_filterops = {
.f_isfd = 1,
.f_attach = NULL,
.f_detach = beri_kqdetach,
.f_event = beri_kqwrite,
};
static int
beri_kqfilter(struct cdev *dev, struct knote *kn)
{
struct beri_softc *sc;
sc = dev->si_drv1;
switch(kn->kn_filter) {
case EVFILT_READ:
kn->kn_fop = &beri_read_filterops;
break;
case EVFILT_WRITE:
kn->kn_fop = &beri_write_filterops;
break;
default:
return(EINVAL);
}
kn->kn_hook = sc;
knlist_add(&sc->beri_rsel.si_note, kn, 0);
return (0);
}
static struct cdevsw beri_cdevsw = {
.d_version = D_VERSION,
.d_open = beri_open,
.d_close = beri_close,
.d_write = beri_rdwr,
.d_read = beri_rdwr,
.d_kqfilter = beri_kqfilter,
.d_name = "beri ring buffer",
};
static int
parse_fdt(struct beri_softc *sc)
{
pcell_t dts_value[0];
phandle_t node;
int len;
if ((node = ofw_bus_get_node(sc->dev)) == -1)
return (ENXIO);
/* get device name */
if (OF_getprop(ofw_bus_get_node(sc->dev), "device_name",
&sc->devname, sizeof(sc->devname)) <= 0) {
device_printf(sc->dev, "Can't get device_name\n");
return (ENXIO);
}
if ((len = OF_getproplen(node, "data_size")) <= 0)
return (ENXIO);
OF_getencprop(node, "data_size", dts_value, len);
sc->data_size = dts_value[0];
if ((len = OF_getproplen(node, "data_read")) <= 0)
return (ENXIO);
OF_getencprop(node, "data_read", dts_value, len);
sc->data_read = dts_value[0];
if ((len = OF_getproplen(node, "data_write")) <= 0)
return (ENXIO);
OF_getencprop(node, "data_write", dts_value, len);
sc->data_write = dts_value[0];
if ((len = OF_getproplen(node, "control_read")) <= 0)
return (ENXIO);
OF_getencprop(node, "control_read", dts_value, len);
sc->control_read = dts_value[0];
if ((len = OF_getproplen(node, "control_write")) <= 0)
return (ENXIO);
OF_getencprop(node, "control_write", dts_value, len);
sc->control_write = dts_value[0];
return (0);
}
static int
beri_probe(device_t dev)
{
if (!ofw_bus_status_okay(dev))
return (ENXIO);
if (!ofw_bus_is_compatible(dev, "sri-cambridge,beri-ring"))
return (ENXIO);
device_set_desc(dev, "SRI-Cambridge BERI ring buffer");
return (BUS_PROBE_DEFAULT);
}
static int
beri_attach(device_t dev)
{
struct beri_softc *sc;
sc = device_get_softc(dev);
sc->dev = dev;
if (bus_alloc_resources(dev, beri_spec, sc->res)) {
device_printf(dev, "could not allocate resources\n");
return (ENXIO);
}
/* Memory interface */
sc->bst = rman_get_bustag(sc->res[0]);
sc->bsh = rman_get_bushandle(sc->res[0]);
if (parse_fdt(sc)) {
device_printf(sc->dev, "Can't get FDT values\n");
return (ENXIO);
}
sc->cdev = make_dev(&beri_cdevsw, 0, UID_ROOT, GID_WHEEL,
S_IRWXU, "%s", sc->devname);
if (sc->cdev == NULL) {
device_printf(dev, "Failed to create character device.\n");
return (ENXIO);
}
sc->cdev->si_drv1 = sc;
mtx_init(&sc->beri_mtx, "beri_mtx", NULL, MTX_DEF);
knlist_init_mtx(&sc->beri_rsel.si_note, &sc->beri_mtx);
return (0);
}
static device_method_t beri_methods[] = {
DEVMETHOD(device_probe, beri_probe),
DEVMETHOD(device_attach, beri_attach),
{ 0, 0 }
};
static driver_t beri_driver = {
"beri_ring",
beri_methods,
sizeof(struct beri_softc),
};
DRIVER_MODULE(beri_ring, simplebus, beri_driver, 0, 0);

View file

@ -1,648 +0,0 @@
/*-
* Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com>
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
* ("CTSRD"), as part of the DARPA CRASH research programme.
*
* 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.
*/
/*
* BERI Virtio Networking Frontend
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/malloc.h>
#include <sys/rman.h>
#include <sys/timeet.h>
#include <sys/timetc.h>
#include <sys/endian.h>
#include <sys/lock.h>
#include <sys/mbuf.h>
#include <sys/mutex.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/sysctl.h>
#include <sys/mdioctl.h>
#include <sys/conf.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <dev/fdt/fdt_common.h>
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
#include <net/bpf.h>
#include <net/if.h>
#include <net/ethernet.h>
#include <net/if_dl.h>
#include <net/if_media.h>
#include <net/if_types.h>
#include <net/if_var.h>
#include <net/if_vlan_var.h>
#include <netinet/in.h>
#include <netinet/udp.h>
#include <netinet/tcp.h>
#include <machine/bus.h>
#include <machine/fdt.h>
#include <machine/cpu.h>
#include <machine/intr.h>
#include <dev/beri/virtio/virtio.h>
#include <dev/beri/virtio/virtio_mmio_platform.h>
#include <dev/altera/pio/pio.h>
#include <dev/virtio/mmio/virtio_mmio.h>
#include <dev/virtio/network/virtio_net.h>
#include <dev/virtio/virtio_ids.h>
#include <dev/virtio/virtio_config.h>
#include <dev/virtio/virtio_ring.h>
#include "pio_if.h"
#define DPRINTF(fmt, args...) printf(fmt, ##args)
#define READ4(_sc, _reg) \
bus_read_4((_sc)->res[0], _reg)
#define WRITE4(_sc, _reg, _val) \
bus_write_4((_sc)->res[0], _reg, _val)
#define VTBE_LOCK(sc) mtx_lock(&(sc)->mtx)
#define VTBE_UNLOCK(sc) mtx_unlock(&(sc)->mtx)
#define VTBE_ASSERT_LOCKED(sc) mtx_assert(&(sc)->mtx, MA_OWNED);
#define VTBE_ASSERT_UNLOCKED(sc) mtx_assert(&(sc)->mtx, MA_NOTOWNED);
/*
* Driver data and defines.
*/
#define DESC_COUNT 256
struct vtbe_softc {
struct resource *res[2];
bus_space_tag_t bst;
bus_space_handle_t bsh;
device_t dev;
if_t ifp;
int if_flags;
struct mtx mtx;
boolean_t is_attached;
int beri_mem_offset;
device_t pio_send;
device_t pio_recv;
int opened;
struct vqueue_info vs_queues[2];
int vs_curq;
int hdrsize;
};
static struct resource_spec vtbe_spec[] = {
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
{ -1, 0 }
};
static void vtbe_txfinish_locked(struct vtbe_softc *sc);
static void vtbe_rxfinish_locked(struct vtbe_softc *sc);
static void vtbe_stop_locked(struct vtbe_softc *sc);
static int pio_enable_irq(struct vtbe_softc *sc, int enable);
static void
vtbe_txstart_locked(struct vtbe_softc *sc)
{
struct iovec iov[DESC_COUNT];
struct virtio_net_hdr *vnh;
struct vqueue_info *vq;
struct iovec *tiov;
if_t ifp;
struct mbuf *m;
struct uio uio;
int enqueued;
int iolen;
int error;
int reg;
int len;
int n;
VTBE_ASSERT_LOCKED(sc);
/* RX queue */
vq = &sc->vs_queues[0];
if (!vq_has_descs(vq)) {
return;
}
ifp = sc->ifp;
if (if_getdrvflags(ifp) & IFF_DRV_OACTIVE) {
return;
}
enqueued = 0;
if (!vq_ring_ready(vq))
return;
vq->vq_save_used = be16toh(vq->vq_used->idx);
for (;;) {
if (!vq_has_descs(vq)) {
if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0);
break;
}
m = if_dequeue(ifp);
if (m == NULL) {
break;
}
n = vq_getchain(sc->beri_mem_offset, vq, iov,
DESC_COUNT, NULL);
KASSERT(n == 2,
("Unexpected amount of descriptors (%d)", n));
tiov = getcopy(iov, n);
vnh = iov[0].iov_base;
memset(vnh, 0, sc->hdrsize);
len = iov[1].iov_len;
uio.uio_resid = len;
uio.uio_iov = &tiov[1];
uio.uio_segflg = UIO_SYSSPACE;
uio.uio_iovcnt = 1;
uio.uio_offset = 0;
uio.uio_rw = UIO_READ;
error = m_mbuftouio(&uio, m, 0);
if (error)
panic("m_mbuftouio failed\n");
iolen = (len - uio.uio_resid + sc->hdrsize);
free(tiov, M_DEVBUF);
vq_relchain(vq, iov, n, iolen);
if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
BPF_MTAP(ifp, m);
m_freem(m);
++enqueued;
}
if (enqueued != 0) {
reg = htobe32(VIRTIO_MMIO_INT_VRING);
WRITE4(sc, VIRTIO_MMIO_INTERRUPT_STATUS, reg);
PIO_SET(sc->pio_send, Q_INTR, 1);
}
}
static void
vtbe_txstart(if_t ifp)
{
struct vtbe_softc *sc = if_getsoftc(ifp);
VTBE_LOCK(sc);
vtbe_txstart_locked(sc);
VTBE_UNLOCK(sc);
}
static void
vtbe_stop_locked(struct vtbe_softc *sc)
{
if_t ifp;
VTBE_ASSERT_LOCKED(sc);
ifp = sc->ifp;
if_setdrvflagbits(ifp, 0, (IFF_DRV_RUNNING | IFF_DRV_OACTIVE));
}
static void
vtbe_init_locked(struct vtbe_softc *sc)
{
if_t ifp = sc->ifp;
VTBE_ASSERT_LOCKED(sc);
if (if_getdrvflags(ifp) & IFF_DRV_RUNNING)
return;
if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0);
}
static void
vtbe_init(void *if_softc)
{
struct vtbe_softc *sc = if_softc;
VTBE_LOCK(sc);
vtbe_init_locked(sc);
VTBE_UNLOCK(sc);
}
static int
vtbe_ioctl(if_t ifp, u_long cmd, caddr_t data)
{
struct ifmediareq *ifmr;
struct vtbe_softc *sc;
struct ifreq *ifr;
int mask, error;
sc = if_getsoftc(ifp);
ifr = (struct ifreq *)data;
error = 0;
switch (cmd) {
case SIOCSIFFLAGS:
VTBE_LOCK(sc);
if (if_getflags(ifp) & IFF_UP) {
pio_enable_irq(sc, 1);
if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0) {
vtbe_init_locked(sc);
}
} else {
pio_enable_irq(sc, 0);
if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
vtbe_stop_locked(sc);
}
}
sc->if_flags = if_getflags(ifp);
VTBE_UNLOCK(sc);
break;
case SIOCADDMULTI:
case SIOCDELMULTI:
break;
case SIOCSIFMEDIA:
case SIOCGIFMEDIA:
ifmr = (struct ifmediareq *)data;
ifmr->ifm_count = 1;
ifmr->ifm_status = (IFM_AVALID | IFM_ACTIVE);
ifmr->ifm_active = (IFM_ETHER | IFM_10G_T | IFM_FDX);
ifmr->ifm_current = ifmr->ifm_active;
break;
case SIOCSIFCAP:
mask = if_getcapenable(ifp) ^ ifr->ifr_reqcap;
if (mask & IFCAP_VLAN_MTU) {
if_togglecapenable(ifp, IFCAP_VLAN_MTU);
}
break;
case SIOCSIFADDR:
pio_enable_irq(sc, 1);
default:
error = ether_ioctl(ifp, cmd, data);
break;
}
return (error);
}
static void
vtbe_txfinish_locked(struct vtbe_softc *sc)
{
if_t ifp;
VTBE_ASSERT_LOCKED(sc);
ifp = sc->ifp;
}
static int
vq_init(struct vtbe_softc *sc)
{
struct vqueue_info *vq;
uint8_t *base;
int size;
int reg;
int pfn;
vq = &sc->vs_queues[sc->vs_curq];
vq->vq_qsize = DESC_COUNT;
reg = READ4(sc, VIRTIO_MMIO_QUEUE_PFN);
pfn = be32toh(reg);
vq->vq_pfn = pfn;
size = vring_size(vq->vq_qsize, VRING_ALIGN);
base = paddr_map(sc->beri_mem_offset,
(pfn << PAGE_SHIFT), size);
/* First pages are descriptors */
vq->vq_desc = (struct vring_desc *)base;
base += vq->vq_qsize * sizeof(struct vring_desc);
/* Then avail ring */
vq->vq_avail = (struct vring_avail *)base;
base += (2 + vq->vq_qsize + 1) * sizeof(uint16_t);
/* Then it's rounded up to the next page */
base = (uint8_t *)roundup2((uintptr_t)base, VRING_ALIGN);
/* And the last pages are the used ring */
vq->vq_used = (struct vring_used *)base;
/* Mark queue as allocated, and start at 0 when we use it. */
vq->vq_flags = VQ_ALLOC;
vq->vq_last_avail = 0;
return (0);
}
static void
vtbe_proc_rx(struct vtbe_softc *sc, struct vqueue_info *vq)
{
struct iovec iov[DESC_COUNT];
struct iovec *tiov;
if_t ifp;
struct uio uio;
struct mbuf *m;
int iolen;
int i;
int n;
ifp = sc->ifp;
n = vq_getchain(sc->beri_mem_offset, vq, iov,
DESC_COUNT, NULL);
KASSERT(n >= 1 && n <= DESC_COUNT,
("wrong n %d", n));
tiov = getcopy(iov, n);
iolen = 0;
for (i = 1; i < n; i++) {
iolen += iov[i].iov_len;
}
uio.uio_resid = iolen;
uio.uio_iov = &tiov[1];
uio.uio_segflg = UIO_SYSSPACE;
uio.uio_iovcnt = (n - 1);
uio.uio_rw = UIO_WRITE;
if ((m = m_uiotombuf(&uio, M_NOWAIT, 0, ETHER_ALIGN,
M_PKTHDR)) == NULL) {
if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
goto done;
}
m->m_pkthdr.rcvif = ifp;
if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
CURVNET_SET(if_getvnet(ifp));
VTBE_UNLOCK(sc);
if_input(ifp, m);
VTBE_LOCK(sc);
CURVNET_RESTORE();
done:
free(tiov, M_DEVBUF);
vq_relchain(vq, iov, n, iolen + sc->hdrsize);
}
static void
vtbe_rxfinish_locked(struct vtbe_softc *sc)
{
struct vqueue_info *vq;
int reg;
/* TX queue */
vq = &sc->vs_queues[1];
if (!vq_ring_ready(vq))
return;
/* Process new descriptors */
vq->vq_save_used = be16toh(vq->vq_used->idx);
while (vq_has_descs(vq)) {
vtbe_proc_rx(sc, vq);
}
/* Interrupt the other side */
reg = htobe32(VIRTIO_MMIO_INT_VRING);
WRITE4(sc, VIRTIO_MMIO_INTERRUPT_STATUS, reg);
PIO_SET(sc->pio_send, Q_INTR, 1);
}
static void
vtbe_intr(void *arg)
{
struct vtbe_softc *sc;
int pending;
uint32_t reg;
sc = arg;
VTBE_LOCK(sc);
reg = PIO_READ(sc->pio_recv);
/* Ack */
PIO_SET(sc->pio_recv, reg, 0);
pending = htobe32(reg);
if (pending & Q_SEL) {
reg = READ4(sc, VIRTIO_MMIO_QUEUE_SEL);
sc->vs_curq = be32toh(reg);
}
if (pending & Q_PFN) {
vq_init(sc);
}
if (pending & Q_NOTIFY) {
/* beri rx / arm tx notify */
vtbe_txfinish_locked(sc);
}
if (pending & Q_NOTIFY1) {
vtbe_rxfinish_locked(sc);
}
VTBE_UNLOCK(sc);
}
static int
vtbe_get_hwaddr(struct vtbe_softc *sc, uint8_t *hwaddr)
{
int rnd;
/*
* Generate MAC address, use 'bsd' + random 24 low-order bits.
*/
rnd = arc4random() & 0x00ffffff;
hwaddr[0] = 'b';
hwaddr[1] = 's';
hwaddr[2] = 'd';
hwaddr[3] = rnd >> 16;
hwaddr[4] = rnd >> 8;
hwaddr[5] = rnd >> 0;
return (0);
}
static int
pio_enable_irq(struct vtbe_softc *sc, int enable)
{
/*
* IRQ lines should be disabled while reprogram FPGA core.
*/
if (enable) {
if (sc->opened == 0) {
sc->opened = 1;
PIO_SETUP_IRQ(sc->pio_recv, vtbe_intr, sc);
}
} else {
if (sc->opened == 1) {
PIO_TEARDOWN_IRQ(sc->pio_recv);
sc->opened = 0;
}
}
return (0);
}
static int
vtbe_probe(device_t dev)
{
if (!ofw_bus_status_okay(dev))
return (ENXIO);
if (!ofw_bus_is_compatible(dev, "sri-cambridge,beri-vtnet"))
return (ENXIO);
device_set_desc(dev, "Virtio BERI Ethernet Controller");
return (BUS_PROBE_DEFAULT);
}
static int
vtbe_attach(device_t dev)
{
uint8_t macaddr[ETHER_ADDR_LEN];
struct vtbe_softc *sc;
if_t ifp;
int reg;
sc = device_get_softc(dev);
sc->dev = dev;
sc->hdrsize = sizeof(struct virtio_net_hdr);
if (bus_alloc_resources(dev, vtbe_spec, sc->res)) {
device_printf(dev, "could not allocate resources\n");
return (ENXIO);
}
/* Memory interface */
sc->bst = rman_get_bustag(sc->res[0]);
sc->bsh = rman_get_bushandle(sc->res[0]);
mtx_init(&sc->mtx, device_get_nameunit(sc->dev),
MTX_NETWORK_LOCK, MTX_DEF);
if (setup_offset(dev, &sc->beri_mem_offset) != 0)
return (ENXIO);
if (setup_pio(dev, "pio-send", &sc->pio_send) != 0)
return (ENXIO);
if (setup_pio(dev, "pio-recv", &sc->pio_recv) != 0)
return (ENXIO);
/* Setup MMIO */
/* Specify that we provide network device */
reg = htobe32(VIRTIO_ID_NETWORK);
WRITE4(sc, VIRTIO_MMIO_DEVICE_ID, reg);
/* The number of desc we support */
reg = htobe32(DESC_COUNT);
WRITE4(sc, VIRTIO_MMIO_QUEUE_NUM_MAX, reg);
/* Our features */
reg = htobe32(VIRTIO_NET_F_MAC |
VIRTIO_F_NOTIFY_ON_EMPTY);
WRITE4(sc, VIRTIO_MMIO_HOST_FEATURES, reg);
/* Get MAC */
if (vtbe_get_hwaddr(sc, macaddr)) {
device_printf(sc->dev, "can't get mac\n");
return (ENXIO);
}
/* Set up the ethernet interface. */
sc->ifp = ifp = if_alloc(IFT_ETHER);
if_setbaudrate(ifp, IF_Gbps(10));
if_setsoftc(ifp, sc);
if_initname(ifp, device_get_name(dev), device_get_unit(dev));
if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX |
IFF_MULTICAST | IFF_PROMISC);
if_setcapabilities(ifp, IFCAP_VLAN_MTU);
if_setcapenable(ifp, if_getcapabilities(ifp));
if_setstartfn(ifp, vtbe_txstart);
if_setioctlfn(ifp, vtbe_ioctl);
if_setinitfn(ifp, vtbe_init);
if_setsendqlen(ifp, DESC_COUNT - 1);
if_setsendqready(ifp);
if_setifheaderlen(ifp, sizeof(struct ether_vlan_header));
/* All ready to run, attach the ethernet interface. */
ether_ifattach(ifp, macaddr);
sc->is_attached = true;
return (0);
}
static device_method_t vtbe_methods[] = {
DEVMETHOD(device_probe, vtbe_probe),
DEVMETHOD(device_attach, vtbe_attach),
{ 0, 0 }
};
static driver_t vtbe_driver = {
"vtbe",
vtbe_methods,
sizeof(struct vtbe_softc),
};
DRIVER_MODULE(vtbe, simplebus, vtbe_driver, 0, 0);
MODULE_DEPEND(vtbe, ether, 1, 1, 1);

View file

@ -1,261 +0,0 @@
/*-
* Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com>
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
* ("CTSRD"), as part of the DARPA CRASH research programme.
*
* 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.
*/
/*
* BERI virtio mmio backend common methods
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/cdefs.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/malloc.h>
#include <sys/rman.h>
#include <sys/timeet.h>
#include <sys/timetc.h>
#include <sys/conf.h>
#include <sys/uio.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/event.h>
#include <sys/selinfo.h>
#include <sys/endian.h>
#include <sys/rwlock.h>
#include <machine/bus.h>
#include <machine/fdt.h>
#include <machine/cpu.h>
#include <machine/intr.h>
#include <dev/fdt/fdt_common.h>
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
#include <dev/beri/virtio/virtio.h>
#include <dev/virtio/virtqueue.h>
#include <dev/virtio/virtio_ring.h>
#include <dev/altera/pio/pio.h>
#include "pio_if.h"
int
vq_ring_ready(struct vqueue_info *vq)
{
return (vq->vq_flags & VQ_ALLOC);
}
int
vq_has_descs(struct vqueue_info *vq)
{
return (vq_ring_ready(vq) && vq->vq_last_avail !=
be16toh(vq->vq_avail->idx));
}
void *
paddr_map(uint32_t offset, uint32_t phys, uint32_t size)
{
bus_space_handle_t bsh;
if (bus_space_map(fdtbus_bs_tag, (phys + offset),
size, 0, &bsh) != 0) {
panic("Couldn't map 0x%08x\n", (phys + offset));
}
return (void *)(bsh);
}
void
paddr_unmap(void *phys, uint32_t size)
{
bus_space_unmap(fdtbus_bs_tag, (bus_space_handle_t)phys, size);
}
static inline void
_vq_record(uint32_t offs, int i, volatile struct vring_desc *vd,
struct iovec *iov, int n_iov, uint16_t *flags) {
uint32_t len;
uint64_t addr;
if (i >= n_iov)
return;
len = atomic_load_32(&vd->len);
addr = atomic_load_64(&vd->addr);
iov[i].iov_base = paddr_map(offs, be64toh(addr),
be32toh(len));
iov[i].iov_len = be32toh(len);
if (flags != NULL)
flags[i] = be16toh(vd->flags);
}
int
vq_getchain(uint32_t offs, struct vqueue_info *vq,
struct iovec *iov, int n_iov, uint16_t *flags)
{
volatile struct vring_desc *vdir, *vindir, *vp;
int idx, ndesc, n_indir;
int head, next;
int i;
idx = vq->vq_last_avail;
ndesc = (be16toh(vq->vq_avail->idx) - idx);
if (ndesc == 0)
return (0);
head = be16toh(vq->vq_avail->ring[idx & (vq->vq_qsize - 1)]);
next = head;
for (i = 0; i < VQ_MAX_DESCRIPTORS; next = be16toh(vdir->next)) {
vdir = &vq->vq_desc[next];
if ((be16toh(vdir->flags) & VRING_DESC_F_INDIRECT) == 0) {
_vq_record(offs, i, vdir, iov, n_iov, flags);
i++;
} else {
n_indir = be32toh(vdir->len) / 16;
vindir = paddr_map(offs, be64toh(vdir->addr),
be32toh(vdir->len));
next = 0;
for (;;) {
vp = &vindir[next];
_vq_record(offs, i, vp, iov, n_iov, flags);
i+=1;
if ((be16toh(vp->flags) & \
VRING_DESC_F_NEXT) == 0)
break;
next = be16toh(vp->next);
}
paddr_unmap(__DEVOLATILE(void *, vindir), be32toh(vdir->len));
}
if ((be16toh(vdir->flags) & VRING_DESC_F_NEXT) == 0)
return (i);
}
return (i);
}
void
vq_relchain(struct vqueue_info *vq, struct iovec *iov, int n, uint32_t iolen)
{
volatile struct vring_used_elem *vue;
volatile struct vring_used *vu;
uint16_t head, uidx, mask;
int i;
mask = vq->vq_qsize - 1;
vu = vq->vq_used;
head = be16toh(vq->vq_avail->ring[vq->vq_last_avail++ & mask]);
uidx = be16toh(vu->idx);
vue = &vu->ring[uidx++ & mask];
vue->id = htobe32(head);
vue->len = htobe32(iolen);
vu->idx = htobe16(uidx);
/* Clean up */
for (i = 0; i < n; i++) {
paddr_unmap((void *)iov[i].iov_base, iov[i].iov_len);
}
}
int
setup_pio(device_t dev, char *name, device_t *pio_dev)
{
phandle_t pio_node;
struct fdt_ic *ic;
phandle_t xref;
phandle_t node;
if ((node = ofw_bus_get_node(dev)) == -1)
return (ENXIO);
if (OF_searchencprop(node, name, &xref,
sizeof(xref)) == -1) {
return (ENXIO);
}
pio_node = OF_node_from_xref(xref);
SLIST_FOREACH(ic, &fdt_ic_list_head, fdt_ics) {
if (ic->iph == pio_node) {
*pio_dev = ic->dev;
return (0);
}
}
return (ENXIO);
}
int
setup_offset(device_t dev, uint32_t *offset)
{
pcell_t dts_value[2];
phandle_t mem_node;
phandle_t xref;
phandle_t node;
int len;
if ((node = ofw_bus_get_node(dev)) == -1)
return (ENXIO);
if (OF_searchencprop(node, "beri-mem", &xref,
sizeof(xref)) == -1) {
return (ENXIO);
}
mem_node = OF_node_from_xref(xref);
if ((len = OF_getproplen(mem_node, "reg")) <= 0)
return (ENXIO);
OF_getencprop(mem_node, "reg", dts_value, len);
*offset = dts_value[0];
return (0);
}
struct iovec *
getcopy(struct iovec *iov, int n)
{
struct iovec *tiov;
int i;
tiov = malloc(n * sizeof(struct iovec), M_DEVBUF, M_NOWAIT);
for (i = 0; i < n; i++) {
tiov[i].iov_base = iov[i].iov_base;
tiov[i].iov_len = iov[i].iov_len;
}
return (tiov);
}

View file

@ -1,69 +0,0 @@
/*-
* Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com>
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
* ("CTSRD"), as part of the DARPA CRASH research programme.
*
* 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.
*/
#define READ2(_sc, _reg) \
bus_read_2((_sc)->res[0], _reg)
#define READ4(_sc, _reg) \
bus_read_4((_sc)->res[0], _reg)
#define WRITE2(_sc, _reg, _val) \
bus_write_2((_sc)->res[0], _reg, _val)
#define WRITE4(_sc, _reg, _val) \
bus_write_4((_sc)->res[0], _reg, _val)
#define PAGE_SHIFT 12
#define VRING_ALIGN 4096
#define VQ_ALLOC 0x01 /* set once we have a pfn */
#define VQ_MAX_DESCRIPTORS 512
struct vqueue_info {
uint16_t vq_qsize; /* size of this queue (a power of 2) */
uint16_t vq_num;
uint16_t vq_flags;
uint16_t vq_last_avail; /* a recent value of vq_avail->va_idx */
uint16_t vq_save_used; /* saved vq_used->vu_idx; see vq_endchains */
uint32_t vq_pfn; /* PFN of virt queue (not shifted!) */
volatile struct vring_desc *vq_desc; /* descriptor array */
volatile struct vring_avail *vq_avail; /* the "avail" ring */
volatile struct vring_used *vq_used; /* the "used" ring */
};
int vq_ring_ready(struct vqueue_info *vq);
int vq_has_descs(struct vqueue_info *vq);
void * paddr_map(uint32_t offset, uint32_t phys, uint32_t size);
void paddr_unmap(void *phys, uint32_t size);
int vq_getchain(uint32_t beri_mem_offset, struct vqueue_info *vq,
struct iovec *iov, int n_iov, uint16_t *flags);
void vq_relchain(struct vqueue_info *vq, struct iovec *iov, int n, uint32_t iolen);
struct iovec * getcopy(struct iovec *iov, int n);
int setup_pio(device_t dev, char *name, device_t *pio_dev);
int setup_offset(device_t dev, uint32_t *offset);

View file

@ -1,553 +0,0 @@
/*-
* Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com>
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
* ("CTSRD"), as part of the DARPA CRASH research programme.
*
* 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.
*/
/*
* BERI virtio block backend driver
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/rman.h>
#include <sys/conf.h>
#include <sys/stat.h>
#include <sys/endian.h>
#include <sys/disk.h>
#include <sys/vnode.h>
#include <sys/fcntl.h>
#include <sys/kthread.h>
#include <sys/buf.h>
#include <sys/mdioctl.h>
#include <sys/namei.h>
#include <machine/bus.h>
#include <machine/fdt.h>
#include <machine/cpu.h>
#include <machine/intr.h>
#include <dev/fdt/fdt_common.h>
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
#include <dev/beri/virtio/virtio.h>
#include <dev/beri/virtio/virtio_mmio_platform.h>
#include <dev/altera/pio/pio.h>
#include <dev/virtio/mmio/virtio_mmio.h>
#include <dev/virtio/block/virtio_blk.h>
#include <dev/virtio/virtio_ids.h>
#include <dev/virtio/virtio_config.h>
#include <dev/virtio/virtio_ring.h>
#include "pio_if.h"
#define DPRINTF(fmt, ...)
/* We use indirect descriptors */
#define NUM_DESCS 1
#define NUM_QUEUES 1
#define VTBLK_BLK_ID_BYTES 20
#define VTBLK_MAXSEGS 256
struct beri_vtblk_softc {
struct resource *res[1];
bus_space_tag_t bst;
bus_space_handle_t bsh;
struct cdev *cdev;
device_t dev;
int opened;
device_t pio_recv;
device_t pio_send;
struct vqueue_info vs_queues[NUM_QUEUES];
char ident[VTBLK_BLK_ID_BYTES];
struct ucred *cred;
struct vnode *vnode;
struct thread *vtblk_ktd;
struct sx sc_mtx;
int beri_mem_offset;
struct md_ioctl *mdio;
struct virtio_blk_config *cfg;
};
static struct resource_spec beri_spec[] = {
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
{ -1, 0 }
};
static int
vtblk_rdwr(struct beri_vtblk_softc *sc, struct iovec *iov,
int cnt, int offset, int operation, int iolen)
{
struct vnode *vp;
struct mount *mp;
struct uio auio;
int error;
bzero(&auio, sizeof(auio));
vp = sc->vnode;
KASSERT(vp != NULL, ("file not opened"));
auio.uio_iov = iov;
auio.uio_iovcnt = cnt;
auio.uio_offset = offset;
auio.uio_segflg = UIO_SYSSPACE;
auio.uio_rw = operation;
auio.uio_resid = iolen;
auio.uio_td = curthread;
if (operation == 0) {
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
error = VOP_READ(vp, &auio, IO_DIRECT, sc->cred);
VOP_UNLOCK(vp);
} else {
(void) vn_start_write(vp, &mp, V_WAIT);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
error = VOP_WRITE(vp, &auio, IO_SYNC, sc->cred);
VOP_UNLOCK(vp);
vn_finished_write(mp);
}
return (error);
}
static void
vtblk_proc(struct beri_vtblk_softc *sc, struct vqueue_info *vq)
{
struct iovec iov[VTBLK_MAXSEGS + 2];
uint16_t flags[VTBLK_MAXSEGS + 2];
struct virtio_blk_outhdr *vbh;
struct iovec *tiov;
uint8_t *status;
off_t offset;
int iolen;
int type;
int i, n;
int err;
n = vq_getchain(sc->beri_mem_offset, vq, iov,
VTBLK_MAXSEGS + 2, flags);
KASSERT(n >= 2 && n <= VTBLK_MAXSEGS + 2,
("wrong n value %d", n));
tiov = getcopy(iov, n);
vbh = iov[0].iov_base;
status = iov[n-1].iov_base;
KASSERT(iov[n-1].iov_len == 1,
("iov_len == %d", iov[n-1].iov_len));
type = be32toh(vbh->type) & ~VIRTIO_BLK_T_BARRIER;
offset = be64toh(vbh->sector) * DEV_BSIZE;
iolen = 0;
for (i = 1; i < (n-1); i++) {
iolen += iov[i].iov_len;
}
switch (type) {
case VIRTIO_BLK_T_OUT:
case VIRTIO_BLK_T_IN:
err = vtblk_rdwr(sc, tiov + 1, i - 1,
offset, type, iolen);
break;
case VIRTIO_BLK_T_GET_ID:
/* Assume a single buffer */
strncpy(iov[1].iov_base, sc->ident,
MIN(iov[1].iov_len, sizeof(sc->ident)));
err = 0;
break;
case VIRTIO_BLK_T_FLUSH:
/* Possible? */
default:
err = -ENOSYS;
break;
}
if (err < 0) {
if (err == -ENOSYS) {
*status = VIRTIO_BLK_S_UNSUPP;
} else
*status = VIRTIO_BLK_S_IOERR;
} else
*status = VIRTIO_BLK_S_OK;
free(tiov, M_DEVBUF);
vq_relchain(vq, iov, n, 1);
}
static int
close_file(struct beri_vtblk_softc *sc, struct thread *td)
{
int error;
if (sc->vnode != NULL) {
vn_lock(sc->vnode, LK_EXCLUSIVE | LK_RETRY);
sc->vnode->v_vflag &= ~VV_MD;
VOP_UNLOCK(sc->vnode);
error = vn_close(sc->vnode, (FREAD|FWRITE),
sc->cred, td);
if (error != 0)
return (error);
sc->vnode = NULL;
}
if (sc->cred != NULL)
crfree(sc->cred);
return (0);
}
static int
open_file(struct beri_vtblk_softc *sc, struct thread *td)
{
struct nameidata nd;
struct vattr vattr;
int error;
int flags;
flags = (FREAD | FWRITE);
NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, sc->mdio->md_file);
error = vn_open(&nd, &flags, 0, NULL);
if (error != 0)
return (error);
NDFREE_PNBUF(&nd);
if (nd.ni_vp->v_type != VREG) {
return (EINVAL);
}
error = VOP_GETATTR(nd.ni_vp, &vattr, td->td_ucred);
if (error != 0)
return (error);
if (VOP_ISLOCKED(nd.ni_vp) != LK_EXCLUSIVE) {
vn_lock(nd.ni_vp, LK_UPGRADE | LK_RETRY);
if (VN_IS_DOOMED(nd.ni_vp)) {
return (1);
}
}
nd.ni_vp->v_vflag |= VV_MD;
VOP_UNLOCK(nd.ni_vp);
sc->vnode = nd.ni_vp;
sc->cred = crhold(td->td_ucred);
return (0);
}
static int
vtblk_notify(struct beri_vtblk_softc *sc)
{
struct vqueue_info *vq;
int queue;
int reg;
vq = &sc->vs_queues[0];
if (!vq_ring_ready(vq))
return (0);
if (!sc->opened)
return (0);
reg = READ2(sc, VIRTIO_MMIO_QUEUE_NOTIFY);
queue = be16toh(reg);
KASSERT(queue == 0, ("we support single queue only"));
/* Process new descriptors */
vq = &sc->vs_queues[queue];
vq->vq_save_used = be16toh(vq->vq_used->idx);
while (vq_has_descs(vq))
vtblk_proc(sc, vq);
/* Interrupt the other side */
if ((be16toh(vq->vq_avail->flags) & VRING_AVAIL_F_NO_INTERRUPT) == 0) {
reg = htobe32(VIRTIO_MMIO_INT_VRING);
WRITE4(sc, VIRTIO_MMIO_INTERRUPT_STATUS, reg);
PIO_SET(sc->pio_send, Q_INTR, 1);
}
return (0);
}
static int
vq_init(struct beri_vtblk_softc *sc)
{
struct vqueue_info *vq;
uint8_t *base;
int size;
int reg;
int pfn;
vq = &sc->vs_queues[0];
vq->vq_qsize = NUM_DESCS;
reg = READ4(sc, VIRTIO_MMIO_QUEUE_PFN);
pfn = be32toh(reg);
vq->vq_pfn = pfn;
size = vring_size(vq->vq_qsize, VRING_ALIGN);
base = paddr_map(sc->beri_mem_offset,
(pfn << PAGE_SHIFT), size);
/* First pages are descriptors */
vq->vq_desc = (struct vring_desc *)base;
base += vq->vq_qsize * sizeof(struct vring_desc);
/* Then avail ring */
vq->vq_avail = (struct vring_avail *)base;
base += (2 + vq->vq_qsize + 1) * sizeof(uint16_t);
/* Then it's rounded up to the next page */
base = (uint8_t *)roundup2((uintptr_t)base, VRING_ALIGN);
/* And the last pages are the used ring */
vq->vq_used = (struct vring_used *)base;
/* Mark queue as allocated, and start at 0 when we use it. */
vq->vq_flags = VQ_ALLOC;
vq->vq_last_avail = 0;
return (0);
}
static void
vtblk_thread(void *arg)
{
struct beri_vtblk_softc *sc;
int err;
sc = arg;
sx_xlock(&sc->sc_mtx);
for (;;) {
err = msleep(sc, &sc->sc_mtx, PCATCH | PZERO, "prd", hz);
vtblk_notify(sc);
}
sx_xunlock(&sc->sc_mtx);
kthread_exit();
}
static int
backend_info(struct beri_vtblk_softc *sc)
{
struct virtio_blk_config *cfg;
uint32_t *s;
int reg;
int i;
/* Specify that we provide block device */
reg = htobe32(VIRTIO_ID_BLOCK);
WRITE4(sc, VIRTIO_MMIO_DEVICE_ID, reg);
/* Queue size */
reg = htobe32(NUM_DESCS);
WRITE4(sc, VIRTIO_MMIO_QUEUE_NUM_MAX, reg);
/* Our features */
reg = htobe32(VIRTIO_RING_F_INDIRECT_DESC
| VIRTIO_BLK_F_BLK_SIZE
| VIRTIO_BLK_F_SEG_MAX);
WRITE4(sc, VIRTIO_MMIO_HOST_FEATURES, reg);
cfg = sc->cfg;
cfg->capacity = htobe64(sc->mdio->md_mediasize / DEV_BSIZE);
cfg->size_max = 0; /* not negotiated */
cfg->seg_max = htobe32(VTBLK_MAXSEGS);
cfg->blk_size = htobe32(DEV_BSIZE);
s = (uint32_t *)cfg;
for (i = 0; i < sizeof(struct virtio_blk_config); i+=4) {
WRITE4(sc, VIRTIO_MMIO_CONFIG + i, *s);
s+=1;
}
strncpy(sc->ident, "Virtio block backend", sizeof(sc->ident));
return (0);
}
static void
vtblk_intr(void *arg)
{
struct beri_vtblk_softc *sc;
int pending;
int reg;
sc = arg;
reg = PIO_READ(sc->pio_recv);
/* Ack */
PIO_SET(sc->pio_recv, reg, 0);
pending = htobe32(reg);
if (pending & Q_PFN) {
vq_init(sc);
}
if (pending & Q_NOTIFY) {
wakeup(sc);
}
}
static int
beri_ioctl(struct cdev *dev, u_long cmd, caddr_t addr,
int flags, struct thread *td)
{
struct beri_vtblk_softc *sc;
int err;
sc = dev->si_drv1;
switch (cmd) {
case MDIOCATTACH:
/* take file as argument */
if (sc->vnode != NULL) {
/* Already opened */
return (1);
}
sc->mdio = (struct md_ioctl *)addr;
backend_info(sc);
DPRINTF("opening file, td 0x%08x\n", (int)td);
err = open_file(sc, td);
if (err)
return (err);
PIO_SETUP_IRQ(sc->pio_recv, vtblk_intr, sc);
sc->opened = 1;
break;
case MDIOCDETACH:
if (sc->vnode == NULL) {
/* File not opened */
return (1);
}
sc->opened = 0;
DPRINTF("closing file, td 0x%08x\n", (int)td);
err = close_file(sc, td);
if (err)
return (err);
PIO_TEARDOWN_IRQ(sc->pio_recv);
break;
default:
break;
}
return (0);
}
static struct cdevsw beri_cdevsw = {
.d_version = D_VERSION,
.d_ioctl = beri_ioctl,
.d_name = "virtio block backend",
};
static int
beri_vtblk_probe(device_t dev)
{
if (!ofw_bus_status_okay(dev))
return (ENXIO);
if (!ofw_bus_is_compatible(dev, "sri-cambridge,beri-vtblk"))
return (ENXIO);
device_set_desc(dev, "SRI-Cambridge BERI block");
return (BUS_PROBE_DEFAULT);
}
static int
beri_vtblk_attach(device_t dev)
{
struct beri_vtblk_softc *sc;
int error;
sc = device_get_softc(dev);
sc->dev = dev;
if (bus_alloc_resources(dev, beri_spec, sc->res)) {
device_printf(dev, "could not allocate resources\n");
return (ENXIO);
}
/* Memory interface */
sc->bst = rman_get_bustag(sc->res[0]);
sc->bsh = rman_get_bushandle(sc->res[0]);
sc->cfg = malloc(sizeof(struct virtio_blk_config),
M_DEVBUF, M_NOWAIT|M_ZERO);
sx_init(&sc->sc_mtx, device_get_nameunit(sc->dev));
error = kthread_add(vtblk_thread, sc, NULL, &sc->vtblk_ktd,
0, 0, "beri_virtio_block");
if (error) {
device_printf(dev, "cannot create kthread\n");
return (ENXIO);
}
if (setup_offset(dev, &sc->beri_mem_offset) != 0)
return (ENXIO);
if (setup_pio(dev, "pio-send", &sc->pio_send) != 0)
return (ENXIO);
if (setup_pio(dev, "pio-recv", &sc->pio_recv) != 0)
return (ENXIO);
sc->cdev = make_dev(&beri_cdevsw, 0, UID_ROOT, GID_WHEEL,
S_IRWXU, "beri_vtblk");
if (sc->cdev == NULL) {
device_printf(dev, "Failed to create character device.\n");
return (ENXIO);
}
sc->cdev->si_drv1 = sc;
return (0);
}
static device_method_t beri_vtblk_methods[] = {
DEVMETHOD(device_probe, beri_vtblk_probe),
DEVMETHOD(device_attach, beri_vtblk_attach),
{ 0, 0 }
};
static driver_t beri_vtblk_driver = {
"beri_vtblk",
beri_vtblk_methods,
sizeof(struct beri_vtblk_softc),
};
DRIVER_MODULE(beri_vtblk, simplebus, beri_vtblk_driver, 0, 0);

View file

@ -1,307 +0,0 @@
/*-
* Copyright (c) 2014-2015 Ruslan Bukin <br@bsdpad.com>
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
* ("CTSRD"), as part of the DARPA CRASH research programme.
*
* 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.
*/
/*
* BERI interface for Virtio MMIO bus.
*
* This driver provides interrupt-engine for software-implemented
* Virtio MMIO backend.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/malloc.h>
#include <sys/rman.h>
#include <sys/timeet.h>
#include <sys/timetc.h>
#include <sys/watchdog.h>
#include <machine/bus.h>
#include <machine/fdt.h>
#include <machine/cpu.h>
#include <machine/cache.h>
#include <dev/fdt/fdt_common.h>
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
#include <dev/beri/virtio/virtio_mmio_platform.h>
#include <dev/virtio/mmio/virtio_mmio.h>
#include <dev/altera/pio/pio.h>
#include "virtio_mmio_if.h"
#include "pio_if.h"
static void platform_intr(void *arg);
struct virtio_mmio_platform_softc {
struct resource *res[1];
void *ih;
bus_space_tag_t bst;
bus_space_handle_t bsh;
device_t dev;
void (*intr_handler)(void *);
void *ih_user;
device_t pio_recv;
device_t pio_send;
int use_pio;
};
static int
setup_pio(struct virtio_mmio_platform_softc *sc, char *name, device_t *dev)
{
phandle_t pio_node;
struct fdt_ic *ic;
phandle_t xref;
phandle_t node;
if ((node = ofw_bus_get_node(sc->dev)) == -1)
return (ENXIO);
if (OF_searchencprop(node, name, &xref,
sizeof(xref)) == -1) {
return (ENXIO);
}
pio_node = OF_node_from_xref(xref);
SLIST_FOREACH(ic, &fdt_ic_list_head, fdt_ics) {
if (ic->iph == pio_node) {
*dev = ic->dev;
PIO_CONFIGURE(*dev, PIO_OUT_ALL,
PIO_UNMASK_ALL);
return (0);
}
}
return (ENXIO);
}
static int
virtio_mmio_platform_probe(device_t dev)
{
if (!ofw_bus_status_okay(dev))
return (ENXIO);
if (!ofw_bus_is_compatible(dev, "beri,virtio_mmio_platform"))
return (ENXIO);
device_set_desc(dev, "Virtio MMIO platform");
return (BUS_PROBE_DEFAULT);
}
static int
virtio_mmio_platform_attach(device_t dev)
{
struct virtio_mmio_platform_softc *sc;
struct fdt_ic *fic;
phandle_t node;
sc = device_get_softc(dev);
sc->dev = dev;
sc->use_pio = 1;
if ((setup_pio(sc, "pio-send", &sc->pio_send) != 0) ||
(setup_pio(sc, "pio-recv", &sc->pio_recv) != 0))
sc->use_pio = 0;
if ((node = ofw_bus_get_node(sc->dev)) == -1)
return (ENXIO);
fic = malloc(sizeof(*fic), M_DEVBUF, M_WAITOK|M_ZERO);
fic->iph = node;
fic->dev = dev;
SLIST_INSERT_HEAD(&fdt_ic_list_head, fic, fdt_ics);
return (0);
}
static int
platform_prewrite(device_t dev, size_t offset, int val)
{
struct virtio_mmio_platform_softc *sc;
sc = device_get_softc(dev);
switch (offset) {
case (VIRTIO_MMIO_QUEUE_NOTIFY):
mips_dcache_wbinv_all();
break;
default:
break;
}
return (0);
}
static int
platform_note(device_t dev, size_t offset, int val)
{
struct virtio_mmio_platform_softc *sc;
int note;
int i;
sc = device_get_softc(dev);
switch (offset) {
case (VIRTIO_MMIO_QUEUE_NOTIFY):
if (val == 0)
note = Q_NOTIFY;
else if (val == 1)
note = Q_NOTIFY1;
else
note = 0;
break;
case (VIRTIO_MMIO_QUEUE_PFN):
note = Q_PFN;
break;
case (VIRTIO_MMIO_QUEUE_SEL):
note = Q_SEL;
break;
default:
note = 0;
}
if (note) {
mips_dcache_wbinv_all();
if (!sc->use_pio)
return (0);
PIO_SET(sc->pio_send, note, 1);
/*
* Wait until host ack the request.
* Usually done within few cycles.
* TODO: bad
*/
for (i = 100; i > 0; i--) {
if (PIO_READ(sc->pio_send) == 0)
break;
}
if (i == 0)
device_printf(sc->dev, "Warning: host busy\n");
}
return (0);
}
static void
platform_intr(void *arg)
{
struct virtio_mmio_platform_softc *sc;
int reg;
sc = arg;
if (sc->use_pio) {
/* Read pending */
reg = PIO_READ(sc->pio_recv);
/* Ack */
PIO_SET(sc->pio_recv, reg, 0);
}
/* Writeback, invalidate cache */
mips_dcache_wbinv_all();
if (sc->intr_handler != NULL)
sc->intr_handler(sc->ih_user);
}
static int
platform_setup_intr(device_t dev, device_t mmio_dev,
void *intr_handler, void *ih_user)
{
struct virtio_mmio_platform_softc *sc;
int rid;
sc = device_get_softc(dev);
sc->intr_handler = intr_handler;
sc->ih_user = ih_user;
if (sc->use_pio) {
PIO_SETUP_IRQ(sc->pio_recv, platform_intr, sc);
return (0);
}
rid = 0;
sc->res[0] = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
RF_ACTIVE);
if (!sc->res[0]) {
device_printf(dev, "Can't allocate interrupt\n");
return (ENXIO);
}
if (bus_setup_intr(dev, sc->res[0], INTR_TYPE_MISC | INTR_MPSAFE,
NULL, platform_intr, sc, &sc->ih)) {
device_printf(dev, "Can't setup the interrupt\n");
return (ENXIO);
}
return (0);
}
static int
platform_poll(device_t dev)
{
mips_dcache_wbinv_all();
return (0);
}
static device_method_t virtio_mmio_platform_methods[] = {
DEVMETHOD(device_probe, virtio_mmio_platform_probe),
DEVMETHOD(device_attach, virtio_mmio_platform_attach),
/* virtio_mmio_if.h */
DEVMETHOD(virtio_mmio_prewrite, platform_prewrite),
DEVMETHOD(virtio_mmio_note, platform_note),
DEVMETHOD(virtio_mmio_poll, platform_poll),
DEVMETHOD(virtio_mmio_setup_intr, platform_setup_intr),
DEVMETHOD_END
};
static driver_t virtio_mmio_platform_driver = {
"virtio_mmio_platform",
virtio_mmio_platform_methods,
sizeof(struct virtio_mmio_platform_softc),
};
DRIVER_MODULE(virtio_mmio_platform, simplebus, virtio_mmio_platform_driver,
0, 0);

View file

@ -1,35 +0,0 @@
/*-
* Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com>
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
* ("CTSRD"), as part of the DARPA CRASH research programme.
*
* 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.
*/
#define Q_NOTIFY 0x01
#define Q_PFN 0x02
#define Q_INTR 0x04
#define Q_SEL 0x08
#define Q_NOTIFY1 0x10

View file

@ -1,151 +0,0 @@
/*-
* Copyright (c) 2017 Ruslan Bukin <br@bsdpad.com>
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
* ("CTSRD"), as part of the DARPA CRASH research programme.
*
* 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.
*/
/* /dts-v1/; */
#include "socfpga_cyclone5_sockit.dts"
/ {
model = "Terasic SoCkit";
compatible = "altr,socfpga-cyclone5", "altr,socfpga";
memreserve = < 0x00000000 0x1000 >, /* SMP trampoline */
< 0x00001000 0x1000 >, /* virtio block */
< 0x00002000 0x1000 >; /* virtio net */
soc {
/* Local timer */
timer@fffec600 {
clock-frequency = <200000000>;
};
/* Global timer */
global_timer: timer@fffec200 {
compatible = "arm,cortex-a9-global-timer";
reg = <0xfffec200 0x20>;
interrupts = <1 11 0xf04>;
clock-frequency = <200000000>;
};
beri_mem0: mem@d0000000 {
compatible = "sri-cambridge,beri-mem";
reg = <0xd0000000 0x10000000>; /* 256mb */
status = "okay";
};
pio0: pio@c0020000 {
compatible = "altr,pio";
reg = <0xc0020000 0x1000>; /* recv */
interrupts = < 76 >;
status = "okay";
};
pio1: pio@c0021000 {
compatible = "altr,pio";
reg = <0xc0021000 0x1000>; /* send */
interrupts = < 82 >; /* not in use on arm side */
status = "okay";
};
pio2: pio@c0022000 {
compatible = "altr,pio";
reg = <0xc0022000 0x1000>; /* recv */
interrupts = < 77 >;
status = "okay";
};
pio3: pio@c0023000 {
compatible = "altr,pio";
reg = <0xc0023000 0x1000>; /* send */
interrupts = < 83 >; /* not in use on arm side */
status = "okay";
};
beri_vtblk: vtblk@00001000 {
compatible = "sri-cambridge,beri-vtblk";
reg = <0x00001000 0x1000>;
pio-recv = <&pio0>;
pio-send = <&pio1>;
beri-mem = <&beri_mem0>;
status = "okay";
};
beri_vtnet: vtnet@00002000 {
compatible = "sri-cambridge,beri-vtnet";
reg = <0x00002000 0x1000>;
pio-recv = <&pio2>;
pio-send = <&pio3>;
beri-mem = <&beri_mem0>;
status = "okay";
};
beri_debug: ring@c0000000 {
compatible = "sri-cambridge,beri-ring";
reg = <0xc0000000 0x3000>;
interrupts = < 72 73 >;
device_name = "beri_debug";
data_size = <0x1000>;
data_read = <0x0>;
data_write = <0x1000>;
control_read = <0x2000>;
control_write = <0x2010>;
status = "okay";
};
beri_console: ring@c0004000 {
compatible = "sri-cambridge,beri-ring";
reg = <0xc0004000 0x3000>;
interrupts = < 74 75 >;
device_name = "beri_console";
data_size = <0x1000>;
data_read = <0x0>;
data_write = <0x1000>;
control_read = <0x2000>;
control_write = <0x2010>;
status = "okay";
};
};
chosen {
stdin = "serial0";
stdout = "serial0";
};
};
&mmc0 {
bus-frequency = <25000000>;
};
&uart0 {
clock-frequency = <100000000>;
};
&uart1 {
status = "disabled";
};

View file

@ -1,19 +0,0 @@
# Doxyfile 1.5.2
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
PROJECT_NAME = "FreeBSD kernel altera device code"
OUTPUT_DIRECTORY = $(DOXYGEN_DEST_PATH)/dev_altera/
EXTRACT_ALL = YES # for undocumented src, no warnings enabled
#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------
INPUT = $(DOXYGEN_SRC_PATH)/dev/altera/ \
$(NOTREVIEWED)
GENERATE_TAGFILE = dev_altera/dev_altera.tag
@INCLUDE_PATH = $(DOXYGEN_INCLUDE_PATH)
@INCLUDE = common-Doxyfile

View file

@ -1,19 +0,0 @@
# Doxyfile 1.5.2
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
PROJECT_NAME = "FreeBSD kernel beri device code"
OUTPUT_DIRECTORY = $(DOXYGEN_DEST_PATH)/dev_beri/
EXTRACT_ALL = YES # for undocumented src, no warnings enabled
#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------
INPUT = $(DOXYGEN_SRC_PATH)/dev/beri/ \
$(NOTREVIEWED)
GENERATE_TAGFILE = dev_beri/dev_beri.tag
@INCLUDE_PATH = $(DOXYGEN_INCLUDE_PATH)
@INCLUDE = common-Doxyfile