dpaa: Migrate from NCSW base to a home-grown driver
The NCSW reference base requires tuning for each target, and currently
is configured for FMANv2. This doesn't readily work on FMANv3 devices,
such as the T-series powerpc, or the LS1043 ARM. Since Freescale/NXP
abandoned the NCSW driver a decade ago, it makes sense to abandon it
ourselves as well. This new driver uses a combination of the NCSW
driver and the Linux driver (BSD/GPL dual licensed) as a reference, but
contains no actual code from them.
The DPAA (Data Path Acceleration Architecture) subsystem consists of the
following components:
* BMan -- Buffer Manager. Manages buffer pools of different sizes (one
size per pool, up to 64 pools)
* QMan -- Queue Manager. Manages the interfaces between DPAA-based
components and the CPU(s).
* FMan -- Frame Manager. Responsible for all ethernet-related
processing. Consists itself of the following components:
* Ports -- interfaces to the QMan. An ethernet interface consists of
2 ports.
Ports use "Next-invoked action" (NIA) descriptors to form a pipeline
for processing on receive and transmit.
* Parser -- performs protocol header parsing and validation. Both
hardware and software parsers are available.
* KeyGen -- Key generator, used to start the classification process
(for the Policer), generating FQIDs and other keys based on the
frame input.
* Policer -- performs traffic shaping and classification
* MAC -- SoC specific ethernet MAC (dTSEC, TGEC, mEMAC). Currently
supports dTSEC and mEMAC, along with their MDIO blocks.
Additional components not yet handled:
SEC -- Security engine (crypto)
RE -- RAID engine
RapidIO
DCE -- Decompression/Compression engine, supports ZLIB, DEFLATE, and
GZIP, as well as base64 encoding and decoding.
BMan and QMan are accessed via cache-coherent portals, using ring
buffers as I/O. The intent is for portals to be per-CPU (core/thread)
to reduce locking contention and improve performance. This driver pins
interrupt handlers to the CPU "owning" a given portal, and uses critical
sections to prevent switching while accessing the portal.
This commit is contained in:
@@ -89,6 +89,27 @@ dev/adb/adb_hb_if.m optional adb
|
||||
dev/adb/adb_if.m optional adb
|
||||
dev/adb/adb_buttons.c optional adb
|
||||
dev/agp/agp_apple.c optional agp powermac
|
||||
dev/dpaa/bman_portals.c optional dpaa fdt
|
||||
dev/dpaa/bman.c optional dpaa
|
||||
dev/dpaa/bman_fdt.c optional dpaa fdt
|
||||
dev/dpaa/dpaa_eth.c optional dpaa
|
||||
dev/dpaa/fman.c optional dpaa fdt
|
||||
dev/dpaa/fman_fdt.c optional dpaa fdt
|
||||
dev/dpaa/fman_if.m optional dpaa
|
||||
dev/dpaa/fman_mdio.c optional dpaa fdt
|
||||
dev/dpaa/fman_port_if.m optional dpaa
|
||||
dev/dpaa/fman_port.c optional dpaa
|
||||
dev/dpaa/fman_xmdio.c optional dpaa fdt mdio miibus
|
||||
dev/dpaa/dpaa_common.c optional dpaa
|
||||
dev/dpaa/if_dtsec.c optional dpaa
|
||||
dev/dpaa/if_dtsec_fdt.c optional dpaa fdt
|
||||
dev/dpaa/if_memac.c optional dpaa
|
||||
dev/dpaa/if_memac_fdt.c optional dpaa
|
||||
dev/dpaa/portals_common.c optional dpaa
|
||||
dev/dpaa/qman_portal_if.m optional dpaa
|
||||
dev/dpaa/qman_portals.c optional dpaa fdt
|
||||
dev/dpaa/qman.c optional dpaa
|
||||
dev/dpaa/qman_fdt.c optional dpaa fdt
|
||||
dev/fb/fb.c optional sc
|
||||
dev/gpio/qoriq_gpio.c optional mpc85xx gpio
|
||||
dev/hwpmc/hwpmc_e500.c optional hwpmc
|
||||
|
||||
+226
-223
@@ -1,27 +1,7 @@
|
||||
/*-
|
||||
* Copyright (c) 2011-2012 Semihalf.
|
||||
* All rights reserved.
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* 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.
|
||||
* Copyright (c) 2026 Justin Hibbits
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
@@ -29,6 +9,7 @@
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/proc.h>
|
||||
@@ -36,63 +17,161 @@
|
||||
#include <sys/rman.h>
|
||||
#include <sys/sched.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
#include <machine/tlb.h>
|
||||
|
||||
#include "bman.h"
|
||||
#include "dpaa_common.h"
|
||||
#include "bman_var.h"
|
||||
|
||||
#define BMAN_POOL_SWDET(n) (0x000 + 4 * (n))
|
||||
#define BMAN_POOL_HWDET(n) (0x100 + 4 * (n))
|
||||
#define BMAN_POOL_SWDXT(n) (0x200 + 4 * (n))
|
||||
#define BMAN_POOL_HWDXT(n) (0x300 + 4 * (n))
|
||||
#define FBPR_FP_LWIT 0x804
|
||||
#define BMAN_IP_REV_1 0x0bf8
|
||||
#define IP_MAJ_S 8
|
||||
#define IP_MAJ_M 0x0000ff00
|
||||
#define IP_MIN_M 0x000000ff
|
||||
#define BMAN_IP_REV_2 0x0bfc
|
||||
#define BMAN_FBPR_BARE 0x0c00
|
||||
#define BMAN_FBPR_BAR 0x0c04
|
||||
#define BMAN_FBPR_AR 0x0c10
|
||||
#define BMAN_LIODNR 0x0d08
|
||||
|
||||
#define BMAN_POOL_CONTENT(n) (0x0600 + 4 * (n))
|
||||
#define BMAN_ECSR 0x0a00
|
||||
#define BMAN_ECIR 0x0a04
|
||||
#define ECIR_PORTAL(r) (((r) >> 24) & 0x0f)
|
||||
#define ECIR_VERB(r) (((r) >> 16) & 0x07)
|
||||
#define ECIR_R 0x00080000
|
||||
#define ECIR_POOL(r) ((r) & 0x3f)
|
||||
#define BMAN_CECR 0x0a34 /* Corruption Error Capture Register */
|
||||
#define BMAN_CEAR 0x0a38 /* Corruption Error Address Register */
|
||||
#define BMAN_AECR 0x0a34 /* Acces Error Capture Register */
|
||||
#define BMAN_AEAR 0x0a38 /* Acces Error Address Register */
|
||||
#define BMAN_ERR_ISR 0x0e00
|
||||
#define BMAN_ERR_IER 0x0e04
|
||||
#define BMAN_ERR_ISDR 0x0e08
|
||||
#define ERR_EMAI 0x00000040
|
||||
#define ERR_EMCI 0x00000020
|
||||
#define ERR_IVCI 0x00000010
|
||||
#define ERR_FLWI 0x00000008
|
||||
#define ERR_MBEI 0x00000004
|
||||
#define ERR_SBEI 0x00000002
|
||||
#define ERR_BSCN 0x00000001
|
||||
|
||||
static MALLOC_DEFINE(M_BMAN, "bman", "DPAA Buffer Manager structures");
|
||||
|
||||
static struct bman_softc *bman_sc;
|
||||
|
||||
extern t_Handle bman_portal_setup(struct bman_softc *bsc);
|
||||
|
||||
static void
|
||||
bman_exception(t_Handle h_App, e_BmExceptions exception)
|
||||
bman_isr(void *arg)
|
||||
{
|
||||
struct bman_softc *sc;
|
||||
const char *message;
|
||||
struct bman_softc *sc = arg;
|
||||
uint32_t ier, isr, isr_bit;
|
||||
uint32_t reg;
|
||||
|
||||
sc = h_App;
|
||||
ier = bus_read_4(sc->sc_rres, BMAN_ERR_IER);
|
||||
isr = bus_read_4(sc->sc_rres, BMAN_ERR_ISR);
|
||||
|
||||
switch (exception) {
|
||||
case e_BM_EX_INVALID_COMMAND:
|
||||
message = "Invalid Command Verb";
|
||||
break;
|
||||
case e_BM_EX_FBPR_THRESHOLD:
|
||||
message = "FBPR pool exhaused. Consider increasing "
|
||||
"BMAN_MAX_BUFFERS";
|
||||
break;
|
||||
case e_BM_EX_SINGLE_ECC:
|
||||
message = "Single bit ECC error";
|
||||
break;
|
||||
case e_BM_EX_MULTI_ECC:
|
||||
message = "Multi bit ECC error";
|
||||
break;
|
||||
default:
|
||||
message = "Unknown error";
|
||||
isr_bit = (isr & ier);
|
||||
if (isr_bit == 0)
|
||||
goto end;
|
||||
|
||||
if (isr_bit & ERR_EMAI) {
|
||||
device_printf(sc->sc_dev, "External memory access error\n");
|
||||
reg = bus_read_4(sc->sc_rres, BMAN_AECR);
|
||||
if (reg <= 63)
|
||||
device_printf(sc->sc_dev, " pool %d\n", reg);
|
||||
else
|
||||
device_printf(sc->sc_dev, " FBPR free list\n");
|
||||
reg = bus_read_4(sc->sc_rres, BMAN_AEAR);
|
||||
device_printf(sc->sc_dev, " offset: %#x\n", reg);
|
||||
}
|
||||
|
||||
device_printf(sc->sc_dev, "BMAN Exception: %s.\n", message);
|
||||
if (isr_bit & ERR_EMCI) {
|
||||
device_printf(sc->sc_dev, "External memory corruption error\n");
|
||||
reg = bus_read_4(sc->sc_rres, BMAN_CECR);
|
||||
if (reg <= 63)
|
||||
device_printf(sc->sc_dev, " pool %d\n", reg);
|
||||
else
|
||||
device_printf(sc->sc_dev, " FBPR free list\n");
|
||||
reg = bus_read_4(sc->sc_rres, BMAN_CEAR);
|
||||
device_printf(sc->sc_dev, " offset: %#x\n", reg);
|
||||
}
|
||||
if (isr_bit & ERR_IVCI) {
|
||||
reg = bus_read_4(sc->sc_rres, BMAN_ECIR);
|
||||
device_printf(sc->sc_dev, "Invalid verb command\n");
|
||||
device_printf(sc->sc_dev, "Portal: %d, ring: %s\n",
|
||||
ECIR_POOL(reg), (reg & ECIR_R) ? "RCR" : "Command");
|
||||
device_printf(sc->sc_dev, "verb: 0x%02x, pool: %d\n",
|
||||
ECIR_VERB(reg), ECIR_POOL(reg));
|
||||
}
|
||||
if (isr_bit & (ERR_MBEI | ERR_SBEI)) {
|
||||
if (isr_bit & ERR_MBEI)
|
||||
device_printf(sc->sc_dev, "Multi-bit ECC error\n");
|
||||
if (isr_bit & ERR_MBEI)
|
||||
device_printf(sc->sc_dev, "Single-bit ECC error\n");
|
||||
/* TODO: Add more error details for ECC errors. */
|
||||
}
|
||||
|
||||
end:
|
||||
bus_write_4(sc->sc_rres, BMAN_ERR_ISR, isr);
|
||||
}
|
||||
|
||||
static void
|
||||
bman_get_version(struct bman_softc *sc)
|
||||
{
|
||||
uint32_t reg = bus_read_4(sc->sc_rres, BMAN_IP_REV_1);
|
||||
|
||||
sc->sc_major = (reg & IP_MAJ_M) >> IP_MAJ_S;
|
||||
sc->sc_minor = (reg & IP_MIN_M);
|
||||
}
|
||||
|
||||
static int
|
||||
bman_set_memory(struct bman_softc *sc, vm_paddr_t pa, vm_size_t size)
|
||||
{
|
||||
vm_paddr_t bar_pa;
|
||||
if ((pa & (size - 1)) != 0 || (size & (size - 1)) != 0) {
|
||||
device_printf(sc->sc_dev,
|
||||
"invalid memory configuration: pa: %#jx, size: %#jx\n",
|
||||
(uintmax_t)pa, (uintmax_t)size);
|
||||
return (ENXIO);
|
||||
}
|
||||
bar_pa = bus_read_4(sc->sc_rres, BMAN_FBPR_BARE);
|
||||
bar_pa <<= 32;
|
||||
bar_pa |= bus_read_4(sc->sc_rres, BMAN_FBPR_BAR);
|
||||
if (bar_pa != 0 && bar_pa != pa) {
|
||||
device_printf(sc->sc_dev,
|
||||
"attempted to reinitialize BMan with different BAR\n");
|
||||
return (ENOMEM);
|
||||
} else if (bar_pa == pa)
|
||||
return (0);
|
||||
|
||||
bus_write_4(sc->sc_rres, BMAN_FBPR_BARE, pa >> 32);
|
||||
bus_write_4(sc->sc_rres, BMAN_FBPR_BAR, pa & 0xffffffff);
|
||||
bus_write_4(sc->sc_rres, BMAN_FBPR_AR, ilog2(size) - 1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
bman_attach(device_t dev)
|
||||
{
|
||||
struct bman_softc *sc;
|
||||
t_BmRevisionInfo rev;
|
||||
t_Error error;
|
||||
t_BmParam bp;
|
||||
vm_paddr_t bp_pa;
|
||||
size_t bp_size;
|
||||
int bp_count;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
sc->sc_dev = dev;
|
||||
bman_sc = sc;
|
||||
|
||||
/* Check if MallocSmart allocator is ready */
|
||||
if (XX_MallocSmartInit() != E_OK)
|
||||
return (ENXIO);
|
||||
|
||||
/* Allocate resources */
|
||||
sc->sc_rrid = 0;
|
||||
sc->sc_rres = bus_alloc_resource_anywhere(dev, SYS_RES_MEMORY,
|
||||
&sc->sc_rrid, BMAN_CCSR_SIZE, RF_ACTIVE);
|
||||
sc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
|
||||
sc->sc_rrid, RF_ACTIVE);
|
||||
if (sc->sc_rres == NULL)
|
||||
return (ENXIO);
|
||||
|
||||
@@ -102,37 +181,34 @@ bman_attach(device_t dev)
|
||||
if (sc->sc_ires == NULL)
|
||||
goto err;
|
||||
|
||||
/* Initialize BMAN */
|
||||
memset(&bp, 0, sizeof(bp));
|
||||
bp.guestId = NCSW_MASTER_ID;
|
||||
bp.baseAddress = rman_get_bushandle(sc->sc_rres);
|
||||
bp.totalNumOfBuffers = BMAN_MAX_BUFFERS;
|
||||
bp.f_Exception = bman_exception;
|
||||
bp.h_App = sc;
|
||||
bp.errIrq = (uintptr_t)sc->sc_ires;
|
||||
bp.partBpidBase = 0;
|
||||
bp.partNumOfPools = BM_MAX_NUM_OF_POOLS;
|
||||
bman_get_version(sc);
|
||||
if (sc->sc_major == 2 && sc->sc_minor == 0)
|
||||
bp_count = BMAN_MAX_POOLS_1023;
|
||||
else
|
||||
bp_count = BMAN_MAX_POOLS;
|
||||
|
||||
sc->sc_bh = BM_Config(&bp);
|
||||
if (sc->sc_bh == NULL)
|
||||
/* TODO: LIODN */
|
||||
bus_write_4(sc->sc_rres, BMAN_LIODNR, 0);
|
||||
|
||||
sc->sc_vmem = vmem_create("BMan Pools", 0, bp_count, 1, 0, M_WAITOK);
|
||||
|
||||
/* Pool is reserved memory, so no need to track it ourselves. */
|
||||
dpaa_map_private_memory(dev, 0, "fsl,bman-fbpr", &bp_pa, &bp_size);
|
||||
bman_set_memory(sc, bp_pa, bp_size);
|
||||
|
||||
/* Warn if FBPR drops below 5% total. */
|
||||
bus_write_4(sc->sc_rres, FBPR_FP_LWIT, (bp_size / 8) / 20);
|
||||
|
||||
/* Clear interrupt status, and enable all interrupts. */
|
||||
bus_write_4(sc->sc_rres, BMAN_ERR_ISR, 0xffffffff);
|
||||
bus_write_4(sc->sc_rres, BMAN_ERR_IER, 0xffffffff);
|
||||
bus_write_4(sc->sc_rres, BMAN_ERR_ISDR, 0);
|
||||
|
||||
/* Enable the IRQ line now. */
|
||||
if (bus_setup_intr(dev, sc->sc_ires, INTR_TYPE_NET, NULL, bman_isr,
|
||||
sc, &sc->sc_icookie) != 0)
|
||||
goto err;
|
||||
|
||||
/* Warn if there is less than 5% free FPBR's in pool */
|
||||
error = BM_ConfigFbprThreshold(sc->sc_bh, (BMAN_MAX_BUFFERS / 8) / 20);
|
||||
if (error != E_OK)
|
||||
goto err;
|
||||
|
||||
error = BM_Init(sc->sc_bh);
|
||||
if (error != E_OK)
|
||||
goto err;
|
||||
|
||||
error = BM_GetRevision(sc->sc_bh, &rev);
|
||||
if (error != E_OK)
|
||||
goto err;
|
||||
|
||||
device_printf(dev, "Hardware version: %d.%d.\n",
|
||||
rev.majorRev, rev.minorRev);
|
||||
|
||||
return (0);
|
||||
|
||||
err:
|
||||
@@ -147,9 +223,10 @@ bman_detach(device_t dev)
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
if (sc->sc_bh != NULL)
|
||||
BM_Free(sc->sc_bh);
|
||||
|
||||
if (sc->sc_vmem != NULL)
|
||||
vmem_destroy(sc->sc_vmem);
|
||||
if (sc->sc_icookie != NULL)
|
||||
bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie);
|
||||
if (sc->sc_ires != NULL)
|
||||
bus_release_resource(dev, SYS_RES_IRQ,
|
||||
sc->sc_irid, sc->sc_ires);
|
||||
@@ -186,179 +263,105 @@ bman_shutdown(device_t dev)
|
||||
* BMAN API
|
||||
*/
|
||||
|
||||
t_Handle
|
||||
bman_pool_create(uint8_t *bpid, uint16_t bufferSize, uint16_t maxBuffers,
|
||||
uint16_t minBuffers, uint16_t allocBuffers, t_GetBufFunction *f_GetBuf,
|
||||
t_PutBufFunction *f_PutBuf, uint32_t dep_sw_entry, uint32_t dep_sw_exit,
|
||||
uint32_t dep_hw_entry, uint32_t dep_hw_exit,
|
||||
t_BmDepletionCallback *f_Depletion, t_Handle h_BufferPool,
|
||||
t_PhysToVirt *f_PhysToVirt, t_VirtToPhys *f_VirtToPhys)
|
||||
struct bman_pool *
|
||||
bman_new_pool(void)
|
||||
{
|
||||
uint32_t thresholds[MAX_DEPLETION_THRESHOLDS];
|
||||
struct bman_softc *sc;
|
||||
t_Handle pool, portal;
|
||||
t_BmPoolParam bpp;
|
||||
int error;
|
||||
vmem_addr_t bpid;
|
||||
struct bman_pool *pool;
|
||||
|
||||
sc = bman_sc;
|
||||
pool = NULL;
|
||||
|
||||
sched_pin();
|
||||
if (vmem_alloc(sc->sc_vmem, 1, M_FIRSTFIT | M_NOWAIT, &bpid) != 0)
|
||||
return (NULL);
|
||||
|
||||
portal = bman_portal_setup(sc);
|
||||
if (portal == NULL)
|
||||
goto err;
|
||||
pool = malloc(sizeof(*pool), M_BMAN, M_WAITOK | M_ZERO);
|
||||
|
||||
memset(&bpp, 0, sizeof(bpp));
|
||||
bpp.h_Bm = sc->sc_bh;
|
||||
bpp.h_BmPortal = portal;
|
||||
bpp.h_App = h_BufferPool;
|
||||
bpp.numOfBuffers = allocBuffers;
|
||||
|
||||
bpp.bufferPoolInfo.h_BufferPool = h_BufferPool;
|
||||
bpp.bufferPoolInfo.f_GetBuf = f_GetBuf;
|
||||
bpp.bufferPoolInfo.f_PutBuf = f_PutBuf;
|
||||
bpp.bufferPoolInfo.f_PhysToVirt = f_PhysToVirt;
|
||||
bpp.bufferPoolInfo.f_VirtToPhys = f_VirtToPhys;
|
||||
bpp.bufferPoolInfo.bufferSize = bufferSize;
|
||||
|
||||
pool = BM_POOL_Config(&bpp);
|
||||
if (pool == NULL)
|
||||
goto err;
|
||||
|
||||
/*
|
||||
* Buffer context must be disabled on FreeBSD
|
||||
* as it could cause memory corruption.
|
||||
*/
|
||||
BM_POOL_ConfigBuffContextMode(pool, 0);
|
||||
|
||||
if (minBuffers != 0 || maxBuffers != 0) {
|
||||
error = BM_POOL_ConfigStockpile(pool, maxBuffers, minBuffers);
|
||||
if (error != E_OK)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (f_Depletion != NULL) {
|
||||
thresholds[BM_POOL_DEP_THRESH_SW_ENTRY] = dep_sw_entry;
|
||||
thresholds[BM_POOL_DEP_THRESH_SW_EXIT] = dep_sw_exit;
|
||||
thresholds[BM_POOL_DEP_THRESH_HW_ENTRY] = dep_hw_entry;
|
||||
thresholds[BM_POOL_DEP_THRESH_HW_EXIT] = dep_hw_exit;
|
||||
error = BM_POOL_ConfigDepletion(pool, f_Depletion, thresholds);
|
||||
if (error != E_OK)
|
||||
goto err;
|
||||
}
|
||||
|
||||
error = BM_POOL_Init(pool);
|
||||
if (error != E_OK)
|
||||
goto err;
|
||||
|
||||
*bpid = BM_POOL_GetId(pool);
|
||||
sc->sc_bpool_cpu[*bpid] = PCPU_GET(cpuid);
|
||||
|
||||
sched_unpin();
|
||||
pool->bpid = bpid;
|
||||
|
||||
return (pool);
|
||||
}
|
||||
|
||||
err:
|
||||
if (pool != NULL)
|
||||
BM_POOL_Free(pool);
|
||||
struct bman_pool *
|
||||
bman_pool_create(uint8_t *bpid, uint16_t buffer_size, uint16_t max_buffers,
|
||||
uint32_t dep_sw_entry, uint32_t dep_sw_exit,
|
||||
uint32_t dep_hw_entry, uint32_t dep_hw_exit,
|
||||
bm_depletion_handler dep_cb, void *arg)
|
||||
{
|
||||
struct bman_softc *sc;
|
||||
struct bman_pool *bp;
|
||||
|
||||
sched_unpin();
|
||||
sc = bman_sc;
|
||||
bp = bman_new_pool();
|
||||
if (bpid != NULL)
|
||||
*bpid = bp->bpid;
|
||||
|
||||
return (NULL);
|
||||
if (dep_cb) {
|
||||
bp->dep_cb = dep_cb;
|
||||
bus_write_4(sc->sc_rres, BMAN_POOL_SWDET(bp->bpid),
|
||||
dep_sw_entry);
|
||||
bus_write_4(sc->sc_rres, BMAN_POOL_SWDXT(bp->bpid),
|
||||
dep_sw_exit);
|
||||
bus_write_4(sc->sc_rres, BMAN_POOL_HWDET(bp->bpid),
|
||||
dep_hw_entry);
|
||||
bus_write_4(sc->sc_rres, BMAN_POOL_HWDXT(bp->bpid),
|
||||
dep_hw_exit);
|
||||
bp->arg = arg;
|
||||
bman_portal_enable_scn(DPCPU_GET(bman_affine_portal), bp);
|
||||
}
|
||||
|
||||
return (bp);
|
||||
}
|
||||
|
||||
int
|
||||
bman_pool_destroy(t_Handle pool)
|
||||
bman_pool_destroy(struct bman_pool *pool)
|
||||
{
|
||||
struct bman_softc *sc;
|
||||
|
||||
sc = bman_sc;
|
||||
thread_lock(curthread);
|
||||
sched_bind(curthread, sc->sc_bpool_cpu[BM_POOL_GetId(pool)]);
|
||||
thread_unlock(curthread);
|
||||
|
||||
BM_POOL_Free(pool);
|
||||
|
||||
thread_lock(curthread);
|
||||
sched_unbind(curthread);
|
||||
thread_unlock(curthread);
|
||||
/* Need to error, or print a warning, if the pool isn't empty */
|
||||
if (bman_count(pool) != 0)
|
||||
return (EBUSY);
|
||||
vmem_free(bman_sc->sc_vmem, pool->bpid, 1);
|
||||
free(pool, M_BMAN);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
bman_pool_fill(t_Handle pool, uint16_t nbufs)
|
||||
bman_put_buffers(struct bman_pool *pool, struct bman_buffer *buffers, int count)
|
||||
{
|
||||
struct bman_softc *sc;
|
||||
t_Handle portal;
|
||||
struct bman_portal_softc *portal;
|
||||
int error;
|
||||
|
||||
sc = bman_sc;
|
||||
sched_pin();
|
||||
critical_enter();
|
||||
|
||||
portal = bman_portal_setup(sc);
|
||||
portal = DPCPU_GET(bman_affine_portal);
|
||||
if (portal == NULL) {
|
||||
sched_unpin();
|
||||
critical_exit();
|
||||
return (EIO);
|
||||
}
|
||||
|
||||
error = BM_POOL_FillBufs(pool, portal, nbufs);
|
||||
|
||||
sched_unpin();
|
||||
|
||||
return ((error == E_OK) ? 0 : EIO);
|
||||
}
|
||||
|
||||
void *
|
||||
bman_get_buffer(t_Handle pool)
|
||||
{
|
||||
struct bman_softc *sc;
|
||||
t_Handle portal;
|
||||
void *buffer;
|
||||
|
||||
sc = bman_sc;
|
||||
sched_pin();
|
||||
|
||||
portal = bman_portal_setup(sc);
|
||||
if (portal == NULL) {
|
||||
sched_unpin();
|
||||
return (NULL);
|
||||
while (count > 0) {
|
||||
int c = min(count, 8);
|
||||
error = bman_release(pool, buffers, c);
|
||||
buffers += c;
|
||||
count -= c;
|
||||
}
|
||||
|
||||
buffer = BM_POOL_GetBuf(pool, portal);
|
||||
critical_exit();
|
||||
|
||||
sched_unpin();
|
||||
|
||||
return (buffer);
|
||||
}
|
||||
|
||||
int
|
||||
bman_put_buffer(t_Handle pool, void *buffer)
|
||||
{
|
||||
struct bman_softc *sc;
|
||||
t_Handle portal;
|
||||
int error;
|
||||
|
||||
sc = bman_sc;
|
||||
sched_pin();
|
||||
|
||||
portal = bman_portal_setup(sc);
|
||||
if (portal == NULL) {
|
||||
sched_unpin();
|
||||
return (EIO);
|
||||
}
|
||||
|
||||
error = BM_POOL_PutBuf(pool, portal, buffer);
|
||||
|
||||
sched_unpin();
|
||||
|
||||
return ((error == E_OK) ? 0 : EIO);
|
||||
return (error);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
bman_count(t_Handle pool)
|
||||
bman_get_bpid(struct bman_pool *pool)
|
||||
{
|
||||
return (pool->bpid);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
bman_count(struct bman_pool *pool)
|
||||
{
|
||||
|
||||
return (BM_POOL_GetCounter(pool, e_BM_POOL_COUNTERS_CONTENT));
|
||||
return (bus_read_4(bman_sc->sc_rres, BMAN_POOL_CONTENT(pool->bpid)));
|
||||
}
|
||||
|
||||
|
||||
+49
-125
@@ -1,3 +1,9 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2026 Justin Hibbits
|
||||
*/
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2011-2012 Semihalf.
|
||||
* All rights reserved.
|
||||
@@ -27,29 +33,16 @@
|
||||
#ifndef _BMAN_H
|
||||
#define _BMAN_H
|
||||
|
||||
#include <sys/vmem.h>
|
||||
#include <machine/vmparam.h>
|
||||
|
||||
#include <contrib/ncsw/inc/Peripherals/bm_ext.h>
|
||||
|
||||
/*
|
||||
* BMAN Configuration
|
||||
*/
|
||||
|
||||
/* Maximum number of buffers in all BMAN pools */
|
||||
#define BMAN_MAX_BUFFERS 4096
|
||||
|
||||
/*
|
||||
* Portal definitions
|
||||
*/
|
||||
#define BMAN_CE_PA(base) (base)
|
||||
#define BMAN_CI_PA(base) ((base) + 0x100000)
|
||||
|
||||
#define BMAN_PORTAL_CE_PA(base, n) \
|
||||
(BMAN_CE_PA(base) + ((n) * BMAN_PORTAL_CE_SIZE))
|
||||
#define BMAN_PORTAL_CI_PA(base, n) \
|
||||
(BMAN_CI_PA(base) + ((n) * BMAN_PORTAL_CI_SIZE))
|
||||
|
||||
#define BMAN_CCSR_SIZE 0x1000
|
||||
|
||||
struct bman_softc {
|
||||
device_t sc_dev; /* device handle */
|
||||
@@ -57,129 +50,42 @@ struct bman_softc {
|
||||
struct resource *sc_rres; /* register resource */
|
||||
int sc_irid; /* interrupt rid */
|
||||
struct resource *sc_ires; /* interrupt resource */
|
||||
|
||||
bool sc_regs_mapped[MAXCPU]; /* register mapping status */
|
||||
|
||||
t_Handle sc_bh; /* BMAN handle */
|
||||
t_Handle sc_bph[MAXCPU]; /* BMAN portal handles */
|
||||
vm_paddr_t sc_bp_pa; /* BMAN portals PA */
|
||||
unsigned int sc_bpool_cpu[BM_MAX_NUM_OF_POOLS];
|
||||
void *sc_icookie;
|
||||
vmem_t *sc_vmem; /* resource pool */
|
||||
int sc_major;
|
||||
int sc_minor;
|
||||
};
|
||||
|
||||
struct bman_buffer {
|
||||
uint16_t bpid;
|
||||
uint16_t buf_hi;
|
||||
uint32_t buf_lo;
|
||||
} __aligned(8);
|
||||
|
||||
struct bman_pool;
|
||||
struct bman_buffer;
|
||||
|
||||
typedef void (*bm_depletion_handler)(void *, bool);
|
||||
|
||||
/*
|
||||
* External API
|
||||
*/
|
||||
|
||||
/*
|
||||
* @brief Function to create BMAN pool.
|
||||
*
|
||||
* @param bpid The pointer to variable where Buffer Pool ID will be
|
||||
* stored.
|
||||
*
|
||||
* @param bufferSize The size of buffers in newly created pool.
|
||||
*
|
||||
* @param maxBuffers The maximum number of buffers in software stockpile.
|
||||
* Set to 0 if software stockpile should not be created.
|
||||
*
|
||||
* @param minBuffers The minimum number of buffers in software stockpile.
|
||||
* Set to 0 if software stockpile should not be created.
|
||||
*
|
||||
* @param allocBuffers The number of buffers to preallocate during pool
|
||||
* creation.
|
||||
*
|
||||
* @param f_GetBuf The buffer allocating function. Called only by
|
||||
* bman_pool_create() and bman_pool_fill().
|
||||
*
|
||||
* @param f_PutBuf The buffer freeing function. Called only by
|
||||
* bman_pool_destroy().
|
||||
*
|
||||
* @param dep_sw_entry The software portal depletion entry threshold.
|
||||
* Set to 0 if depletion should not be signaled on
|
||||
* software portal.
|
||||
*
|
||||
* @param dep_sw_exit The software portal depletion exit threshold.
|
||||
* Set to 0 if depletion should not be signaled on
|
||||
* software portal.
|
||||
*
|
||||
* @param dep_hw_entry The hardware portal depletion entry threshold.
|
||||
* Set to 0 if depletion should not be signaled on
|
||||
* hardware portal.
|
||||
*
|
||||
* @param dep_hw_exit The hardware portal depletion exit threshold.
|
||||
* Set to 0 if depletion should not be signaled on
|
||||
* hardware portal.
|
||||
*
|
||||
* @param f_Depletion The software portal depletion notification function.
|
||||
* Set to NULL if depletion notification is not used.
|
||||
*
|
||||
* @param h_BufferPool The user provided buffer pool context passed to
|
||||
* f_GetBuf, f_PutBuf and f_Depletion functions.
|
||||
*
|
||||
* @param f_PhysToVirt The PA to VA translation function. Set to NULL if
|
||||
* default one should be used.
|
||||
*
|
||||
* @param f_VirtToPhys The VA to PA translation function. Set to NULL if
|
||||
* default one should be used.
|
||||
*
|
||||
* @returns Handle to newly created BMAN pool or NULL on error.
|
||||
*
|
||||
* @cautions If pool uses software stockpile, all accesses to given
|
||||
* pool must be protected by lock. Even if only hardware
|
||||
* portal depletion notification is used, the caller must
|
||||
* provide valid @p f_Depletion function.
|
||||
*/
|
||||
t_Handle bman_pool_create(uint8_t *bpid, uint16_t bufferSize,
|
||||
uint16_t maxBuffers, uint16_t minBuffers, uint16_t allocBuffers,
|
||||
t_GetBufFunction *f_GetBuf, t_PutBufFunction *f_PutBuf,
|
||||
uint32_t dep_sw_entry, uint32_t dep_sw_exit, uint32_t dep_hw_entry,
|
||||
uint32_t dep_hw_exit, t_BmDepletionCallback *f_Depletion,
|
||||
t_Handle h_BufferPool, t_PhysToVirt *f_PhysToVirt,
|
||||
t_VirtToPhys *f_VirtToPhys);
|
||||
|
||||
/*
|
||||
* @brief Fill pool with buffers.
|
||||
*
|
||||
* The bman_pool_fill() function fills the BMAN pool with buffers. The buffers
|
||||
* are allocated through f_GetBuf function (see bman_pool_create() description).
|
||||
*
|
||||
* @param pool The BMAN pool handle.
|
||||
* @param nbufs The number of buffers to allocate. To maximize
|
||||
* performance this value should be multiple of 8.
|
||||
*
|
||||
* @returns Zero on success or error code on failure.
|
||||
*/
|
||||
int bman_pool_fill(t_Handle pool, uint16_t nbufs);
|
||||
struct bman_pool *bman_new_pool(void);
|
||||
struct bman_pool *bman_pool_create(uint8_t *bpid, uint16_t buffer_size,
|
||||
uint16_t max_buffers, uint32_t dep_sw_entry, uint32_t dep_sw_exit, uint32_t
|
||||
dep_hw_entry, uint32_t dep_hw_exit, bm_depletion_handler dep_cb, void *arg);
|
||||
|
||||
/*
|
||||
* @brief Destroy pool.
|
||||
*
|
||||
* The bman_pool_destroy() function destroys the BMAN pool. Buffers for pool
|
||||
* are free through f_PutBuf function (see bman_pool_create() description).
|
||||
* The bman_pool_destroy() function destroys the BMAN pool.
|
||||
* The buffer pool must be empty.
|
||||
*
|
||||
* @param pool The BMAN pool handle.
|
||||
*
|
||||
* @returns Zero on success or error code on failure.
|
||||
* @return 0 on success, EBUSY if the pool is not empty.
|
||||
*/
|
||||
int bman_pool_destroy(t_Handle pool);
|
||||
|
||||
/*
|
||||
* @brief Get a buffer from BMAN pool.
|
||||
*
|
||||
* @param pool The BMAN pool handle.
|
||||
*
|
||||
* @returns Pointer to the buffer or NULL if pool is empty.
|
||||
*/
|
||||
void *bman_get_buffer(t_Handle pool);
|
||||
|
||||
/*
|
||||
* @brief Put a buffer to BMAN pool.
|
||||
*
|
||||
* @param pool The BMAN pool handle.
|
||||
* @param buffer The pointer to buffer.
|
||||
*
|
||||
* @returns Zero on success or error code on failure.
|
||||
*/
|
||||
int bman_put_buffer(t_Handle pool, void *buffer);
|
||||
int bman_pool_destroy(struct bman_pool *pool);
|
||||
|
||||
/*
|
||||
* @brief Count free buffers in given pool.
|
||||
@@ -188,7 +94,25 @@ int bman_put_buffer(t_Handle pool, void *buffer);
|
||||
*
|
||||
* @returns Number of free buffers in pool.
|
||||
*/
|
||||
uint32_t bman_count(t_Handle pool);
|
||||
uint32_t bman_count(struct bman_pool *pool);
|
||||
|
||||
int bman_put_buffers(struct bman_pool *, struct bman_buffer *, int);
|
||||
static inline int
|
||||
bman_put_buffer(struct bman_pool *p, vm_paddr_t buf, int bpid)
|
||||
{
|
||||
struct bman_buffer b = {
|
||||
.bpid = bpid,
|
||||
.buf_hi = ((uintptr_t)buf) >> 32,
|
||||
.buf_lo = ((uintptr_t)buf) & 0xffffffff
|
||||
};
|
||||
return (bman_put_buffers(p, &b, 1));
|
||||
}
|
||||
|
||||
int bman_acquire(struct bman_pool *, struct bman_buffer *, uint8_t);
|
||||
|
||||
int bman_create_affine_portal(device_t, vm_offset_t, vm_offset_t, int);
|
||||
void bman_destroy_affine_portal(int);
|
||||
uint32_t bman_get_bpid(struct bman_pool *);
|
||||
|
||||
/*
|
||||
* Bus i/f
|
||||
|
||||
+23
-125
@@ -40,6 +40,7 @@
|
||||
#include <dev/ofw/ofw_subr.h>
|
||||
|
||||
#include "bman.h"
|
||||
#include "bman_var.h"
|
||||
#include "portals.h"
|
||||
|
||||
#define FBMAN_DEVSTR "Freescale Buffer Manager"
|
||||
@@ -59,12 +60,7 @@ static device_method_t bman_methods[] = {
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
||||
static driver_t bman_driver = {
|
||||
"bman",
|
||||
bman_methods,
|
||||
sizeof(struct bman_softc),
|
||||
};
|
||||
|
||||
DEFINE_CLASS_0(bman, bman_driver, bman_methods, sizeof(struct bman_softc));
|
||||
EARLY_DRIVER_MODULE(bman, simplebus, bman_driver, 0, 0, BUS_PASS_SUPPORTDEV);
|
||||
|
||||
static int
|
||||
@@ -82,144 +78,46 @@ bman_fdt_probe(device_t dev)
|
||||
/*
|
||||
* BMAN Portals
|
||||
*/
|
||||
#define BMAN_PORT_DEVSTR "Freescale Buffer Manager - Portals"
|
||||
#define BMAN_PORT_DEVSTR "Freescale Buffer Manager - Portal"
|
||||
|
||||
static device_probe_t bman_portals_fdt_probe;
|
||||
static device_attach_t bman_portals_fdt_attach;
|
||||
static int portal_ncpus;
|
||||
static device_probe_t bman_portal_fdt_probe;
|
||||
static device_attach_t bman_portal_fdt_attach;
|
||||
|
||||
static device_method_t bm_portals_methods[] = {
|
||||
static device_method_t bman_portal_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, bman_portals_fdt_probe),
|
||||
DEVMETHOD(device_attach, bman_portals_fdt_attach),
|
||||
DEVMETHOD(device_detach, bman_portals_detach),
|
||||
DEVMETHOD(device_probe, bman_portal_fdt_probe),
|
||||
DEVMETHOD(device_attach, bman_portal_fdt_attach),
|
||||
DEVMETHOD(device_detach, bman_portal_detach),
|
||||
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
||||
static driver_t bm_portals_driver = {
|
||||
"bman-portals",
|
||||
bm_portals_methods,
|
||||
sizeof(struct dpaa_portals_softc),
|
||||
};
|
||||
|
||||
EARLY_DRIVER_MODULE(bman_portals, ofwbus, bm_portals_driver, 0, 0,
|
||||
BUS_PASS_BUS);
|
||||
|
||||
static void
|
||||
get_addr_props(phandle_t node, uint32_t *addrp, uint32_t *sizep)
|
||||
{
|
||||
|
||||
*addrp = 2;
|
||||
*sizep = 1;
|
||||
OF_getencprop(node, "#address-cells", addrp, sizeof(*addrp));
|
||||
OF_getencprop(node, "#size-cells", sizep, sizeof(*sizep));
|
||||
}
|
||||
DEFINE_CLASS_0(bman_portal, bman_portal_driver, bman_portal_methods,
|
||||
sizeof(struct bman_portal_softc));
|
||||
EARLY_DRIVER_MODULE(bman_portal, simplebus, bman_portal_driver, 0, 0,
|
||||
BUS_PASS_SUPPORTDEV + BUS_PASS_ORDER_MIDDLE);
|
||||
|
||||
static int
|
||||
bman_portals_fdt_probe(device_t dev)
|
||||
bman_portal_fdt_probe(device_t dev)
|
||||
{
|
||||
phandle_t node;
|
||||
|
||||
if (ofw_bus_is_compatible(dev, "simple-bus")) {
|
||||
node = ofw_bus_get_node(dev);
|
||||
for (node = OF_child(node); node > 0; node = OF_peer(node)) {
|
||||
if (ofw_bus_node_is_compatible(node, "fsl,bman-portal"))
|
||||
break;
|
||||
}
|
||||
if (node <= 0)
|
||||
return (ENXIO);
|
||||
} else if (!ofw_bus_is_compatible(dev, "fsl,bman-portals"))
|
||||
if (!ofw_bus_is_compatible(dev, "fsl,bman-portal"))
|
||||
return (ENXIO);
|
||||
|
||||
device_set_desc(dev, BMAN_PORT_DEVSTR);
|
||||
|
||||
return (BUS_PROBE_DEFAULT);
|
||||
}
|
||||
|
||||
static int
|
||||
bman_portals_fdt_attach(device_t dev)
|
||||
bman_portal_fdt_attach(device_t dev)
|
||||
{
|
||||
struct dpaa_portals_softc *sc;
|
||||
struct resource_list_entry *rle;
|
||||
phandle_t node, child, cpu_node;
|
||||
vm_paddr_t portal_pa;
|
||||
vm_size_t portal_size;
|
||||
uint32_t addr, size;
|
||||
ihandle_t cpu;
|
||||
int cpu_num, cpus, intr_rid;
|
||||
struct dpaa_portals_devinfo di;
|
||||
struct ofw_bus_devinfo ofw_di = {};
|
||||
int portal_cpu = portal_ncpus;
|
||||
|
||||
cpus = 0;
|
||||
sc = device_get_softc(dev);
|
||||
sc->sc_dev = dev;
|
||||
/* Don't attach to more portals than we have CPUs */
|
||||
if (mp_ncpus == portal_ncpus)
|
||||
return (ENXIO);
|
||||
|
||||
node = ofw_bus_get_node(dev);
|
||||
get_addr_props(node, &addr, &size);
|
||||
portal_ncpus++;
|
||||
|
||||
/* Find portals tied to CPUs */
|
||||
for (child = OF_child(node); child != 0; child = OF_peer(child)) {
|
||||
if (cpus >= mp_ncpus)
|
||||
break;
|
||||
if (!ofw_bus_node_is_compatible(child, "fsl,bman-portal")) {
|
||||
continue;
|
||||
}
|
||||
/* Checkout related cpu */
|
||||
if (OF_getprop(child, "cpu-handle", (void *)&cpu,
|
||||
sizeof(cpu)) > 0) {
|
||||
cpu_node = OF_instance_to_package(cpu);
|
||||
/* Acquire cpu number */
|
||||
if (OF_getencprop(cpu_node, "reg", &cpu_num, sizeof(cpu_num)) <= 0) {
|
||||
device_printf(dev, "Could not retrieve CPU number.\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
} else
|
||||
cpu_num = cpus;
|
||||
|
||||
cpus++;
|
||||
|
||||
if (ofw_bus_gen_setup_devinfo(&ofw_di, child) != 0) {
|
||||
device_printf(dev, "could not set up devinfo\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
resource_list_init(&di.di_res);
|
||||
if (ofw_bus_reg_to_rl(dev, child, addr, size, &di.di_res)) {
|
||||
device_printf(dev, "%s: could not process 'reg' "
|
||||
"property\n", ofw_di.obd_name);
|
||||
ofw_bus_gen_destroy_devinfo(&ofw_di);
|
||||
continue;
|
||||
}
|
||||
if (ofw_bus_intr_to_rl(dev, child, &di.di_res, &intr_rid)) {
|
||||
device_printf(dev, "%s: could not process "
|
||||
"'interrupts' property\n", ofw_di.obd_name);
|
||||
resource_list_free(&di.di_res);
|
||||
ofw_bus_gen_destroy_devinfo(&ofw_di);
|
||||
continue;
|
||||
}
|
||||
di.di_intr_rid = intr_rid;
|
||||
|
||||
ofw_reg_to_paddr(child, 0, &portal_pa, &portal_size, NULL);
|
||||
rle = resource_list_find(&di.di_res, SYS_RES_MEMORY, 0);
|
||||
|
||||
if (sc->sc_dp_pa == 0)
|
||||
sc->sc_dp_pa = portal_pa - rle->start;
|
||||
|
||||
portal_size = rle->end + 1;
|
||||
rle = resource_list_find(&di.di_res, SYS_RES_MEMORY, 1);
|
||||
portal_size = ulmax(rle->end + 1, portal_size);
|
||||
sc->sc_dp_size = ulmax(sc->sc_dp_size, portal_size);
|
||||
|
||||
if (dpaa_portal_alloc_res(dev, &di, cpu_num))
|
||||
goto err;
|
||||
}
|
||||
|
||||
ofw_bus_gen_destroy_devinfo(&ofw_di);
|
||||
|
||||
return (bman_portals_attach(dev));
|
||||
err:
|
||||
resource_list_free(&di.di_res);
|
||||
ofw_bus_gen_destroy_devinfo(&ofw_di);
|
||||
bman_portals_detach(dev);
|
||||
return (ENXIO);
|
||||
return (bman_portal_attach(dev, portal_cpu));
|
||||
}
|
||||
|
||||
+268
-118
@@ -1,27 +1,7 @@
|
||||
/*-
|
||||
* Copyright (c) 2012 Semihalf.
|
||||
* All rights reserved.
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* 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.
|
||||
* Copyright (c) 2026 Justin Hibbits
|
||||
*/
|
||||
|
||||
#include "opt_platform.h"
|
||||
@@ -30,6 +10,8 @@
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/cpuset.h>
|
||||
#include <sys/interrupt.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/mutex.h>
|
||||
@@ -46,132 +28,300 @@
|
||||
#include <powerpc/mpc85xx/mpc85xx.h>
|
||||
|
||||
#include "bman.h"
|
||||
#include "bman_var.h"
|
||||
#include "portals.h"
|
||||
|
||||
t_Handle bman_portal_setup(struct bman_softc *);
|
||||
#define BCSP_CFG 0x0100
|
||||
#define CFG_RPM_M 0x00000003
|
||||
#define CFG_RPM_PI 0x00000000
|
||||
#define CFG_RPM_PE 0x00000001
|
||||
#define CFG_RPM_VBM 0x00000002
|
||||
#define BCSP_SCN0 0x0200
|
||||
#define BCSP_SCN1 0x0204
|
||||
#define BCSP_ISR 0x0e00
|
||||
#define BCSP_IER 0x0e04
|
||||
#define BCSP_ISDR 0x0e08
|
||||
#define INTR_RCDI 0x00000004
|
||||
#define INTR_RCRI 0x00000002
|
||||
#define INTR_BSCN 0x00000001
|
||||
|
||||
struct dpaa_portals_softc *bp_sc;
|
||||
#define BMAN_CE_CR 0x0000
|
||||
#define BMAN_CE_RR0 0x0100
|
||||
#define BMAN_CE_RR1 0x0140
|
||||
#define BMAN_CE_RR(n) (BMAN_CE_RR0 + 0x40 * (n))
|
||||
#define BMAN_CE_RCR 0x1000
|
||||
#define BCSP_RCR_PI_CENA 0x3000
|
||||
#define BCSP_RCR_CI_CENA 0x3100
|
||||
#define BCSP_RCR_PI_CINH 0x000
|
||||
#define BCSP_RCR_CI_CINH 0x004
|
||||
|
||||
#define BMAN_MC_VERB_VBIT 0x80
|
||||
#define BMAN_MC_VERB_ACQUIRE 0x10
|
||||
#define BMAN_MC_VERB_QUERY 0x40
|
||||
#define BMAN_RCR_VERB_BPID0 0x20
|
||||
#define BMAN_RCR_VERB_BPID_BUF 0x30
|
||||
|
||||
struct bman_mc_command {
|
||||
uint8_t verb;
|
||||
uint8_t cd;
|
||||
uint8_t rsvd[62];
|
||||
};
|
||||
|
||||
union bman_mc_result {
|
||||
struct {
|
||||
uint8_t verb;
|
||||
uint8_t cd;
|
||||
uint8_t rsvd[62];
|
||||
};
|
||||
struct {
|
||||
uint64_t rsvd_q1[5];
|
||||
uint64_t bp_as;
|
||||
uint64_t rsvd_q2;
|
||||
uint64_t bp_ds;
|
||||
};
|
||||
struct bman_buffer bufs[8];
|
||||
};
|
||||
|
||||
struct bman_rcr_entry {
|
||||
union {
|
||||
struct {
|
||||
uint8_t verb;
|
||||
uint8_t bpid;
|
||||
uint8_t rsvd[62];
|
||||
};
|
||||
struct bman_buffer bufs[8];
|
||||
};
|
||||
};
|
||||
|
||||
static void bman_portal_isr(void *arg);
|
||||
|
||||
static union bman_mc_result *bman_mc_send(struct bman_portal_softc *p,
|
||||
uint8_t verb, uint8_t cd);
|
||||
|
||||
DPCPU_DEFINE(struct bman_portal_softc *, bman_affine_portal);
|
||||
|
||||
DPAA_RING(bman_rcr, 8, BCSP_RCR_PI_CENA, BCSP_RCR_CI_CENA,
|
||||
BCSP_RCR_PI_CINH, BCSP_RCR_CI_CINH);
|
||||
|
||||
static uint32_t
|
||||
bm_ci_read(struct bman_portal_softc *sc, bus_size_t off)
|
||||
{
|
||||
return (bus_read_4(sc->sc_base.sc_mres[1], off));
|
||||
}
|
||||
|
||||
static void
|
||||
bm_ci_write(struct bman_portal_softc *sc, bus_size_t off, uint32_t val)
|
||||
{
|
||||
bus_write_4(sc->sc_base.sc_mres[1], off, val);
|
||||
}
|
||||
|
||||
int
|
||||
bman_portals_attach(device_t dev)
|
||||
bman_portal_attach(device_t dev, int cpu)
|
||||
{
|
||||
struct dpaa_portals_softc *sc;
|
||||
struct bman_portal_softc *sc = device_get_softc(dev);
|
||||
|
||||
sc = bp_sc = device_get_softc(dev);
|
||||
|
||||
/* Map bman portal to physical address space */
|
||||
if (law_enable(OCP85XX_TGTIF_BMAN, sc->sc_dp_pa, sc->sc_dp_size)) {
|
||||
bman_portals_detach(dev);
|
||||
return (ENXIO);
|
||||
}
|
||||
/* Set portal properties for XX_VirtToPhys() */
|
||||
XX_PortalSetInfo(dev);
|
||||
sc->sc_base.sc_cpu = cpu;
|
||||
dpaa_portal_alloc_res(dev, cpu);
|
||||
|
||||
bm_ci_write(sc, BCSP_ISDR, 0);
|
||||
bm_ci_write(sc, BCSP_IER, INTR_RCRI | INTR_BSCN);
|
||||
bus_setup_intr(dev, sc->sc_base.sc_ires, INTR_TYPE_NET | INTR_MPSAFE,
|
||||
NULL, bman_portal_isr, sc, &sc->sc_base.sc_intr_cookie);
|
||||
bus_bind_intr(dev, sc->sc_base.sc_ires, cpu);
|
||||
|
||||
/* Select valid-bit mode for rings */
|
||||
bus_write_4(sc->sc_base.sc_mres[1], BCSP_CFG, CFG_RPM_VBM);
|
||||
/* Disable pool depletion notifications. */
|
||||
bm_ci_write(sc, BCSP_SCN0, 0);
|
||||
bm_ci_write(sc, BCSP_SCN1, 0);
|
||||
|
||||
DPCPU_ID_SET(cpu, bman_affine_portal, sc);
|
||||
|
||||
sc->sc_rcr.ring =
|
||||
(struct bman_rcr_entry *)(sc->sc_base.sc_ce_va + BMAN_CE_RCR);
|
||||
bman_rcr_ring_init(&sc->sc_rcr, &sc->sc_base);
|
||||
/* Starting MC polarity is always 1 */
|
||||
sc->mc.polarity = BMAN_MC_VERB_VBIT;
|
||||
|
||||
bus_attach_children(dev);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
bman_portals_detach(device_t dev)
|
||||
bman_portal_detach(device_t dev)
|
||||
{
|
||||
struct dpaa_portals_softc *sc;
|
||||
struct bman_portal_softc *sc;
|
||||
int i;
|
||||
|
||||
bp_sc = NULL;
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sc->sc_dp); i++) {
|
||||
if (sc->sc_dp[i].dp_ph != NULL) {
|
||||
thread_lock(curthread);
|
||||
sched_bind(curthread, i);
|
||||
thread_unlock(curthread);
|
||||
|
||||
BM_PORTAL_Free(sc->sc_dp[i].dp_ph);
|
||||
/* TODO: Unmap TLB regions */
|
||||
thread_lock(curthread);
|
||||
sched_bind(curthread, sc->sc_base.sc_cpu);
|
||||
thread_unlock(curthread);
|
||||
|
||||
thread_lock(curthread);
|
||||
sched_unbind(curthread);
|
||||
thread_unlock(curthread);
|
||||
}
|
||||
if (sc->sc_base.sc_ires != NULL)
|
||||
bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_base.sc_ires);
|
||||
|
||||
if (sc->sc_dp[i].dp_ires != NULL) {
|
||||
XX_DeallocIntr((uintptr_t)sc->sc_dp[i].dp_ires);
|
||||
bus_release_resource(dev, SYS_RES_IRQ,
|
||||
sc->sc_dp[i].dp_irid, sc->sc_dp[i].dp_ires);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < ARRAY_SIZE(sc->sc_rres); i++) {
|
||||
if (sc->sc_rres[i] != NULL)
|
||||
for (i = 0; i < nitems(sc->sc_base.sc_mres); i++) {
|
||||
if (sc->sc_base.sc_mres[i] != NULL)
|
||||
bus_release_resource(dev, SYS_RES_MEMORY,
|
||||
sc->sc_rrid[i],
|
||||
sc->sc_rres[i]);
|
||||
i, sc->sc_base.sc_mres[i]);
|
||||
}
|
||||
thread_lock(curthread);
|
||||
sched_unbind(curthread);
|
||||
thread_unlock(curthread);
|
||||
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
t_Handle
|
||||
bman_portal_setup(struct bman_softc *bsc)
|
||||
static uint64_t
|
||||
bman_query(struct bman_portal_softc *sc, bool depletion)
|
||||
{
|
||||
struct dpaa_portals_softc *sc;
|
||||
t_BmPortalParam bpp;
|
||||
t_Handle portal;
|
||||
unsigned int cpu;
|
||||
uintptr_t p;
|
||||
union bman_mc_result *mc_res;
|
||||
uint64_t res;
|
||||
|
||||
/* Return NULL if we're not ready or while detach */
|
||||
if (bp_sc == NULL)
|
||||
return (NULL);
|
||||
|
||||
sc = bp_sc;
|
||||
|
||||
sched_pin();
|
||||
portal = NULL;
|
||||
cpu = PCPU_GET(cpuid);
|
||||
|
||||
/* Check if portal is ready */
|
||||
while (atomic_cmpset_acq_ptr((uintptr_t *)&sc->sc_dp[cpu].dp_ph,
|
||||
0, -1) == 0) {
|
||||
p = atomic_load_acq_ptr((uintptr_t *)&sc->sc_dp[cpu].dp_ph);
|
||||
|
||||
/* Return if portal is already initialized */
|
||||
if (p != 0 && p != -1) {
|
||||
sched_unpin();
|
||||
return ((t_Handle)p);
|
||||
}
|
||||
|
||||
/* Not inititialized and "owned" by another thread */
|
||||
sched_relinquish(curthread);
|
||||
}
|
||||
|
||||
/* Map portal registers */
|
||||
dpaa_portal_map_registers(sc);
|
||||
|
||||
/* Configure and initialize portal */
|
||||
bpp.ceBaseAddress = rman_get_bushandle(sc->sc_rres[0]);
|
||||
bpp.ciBaseAddress = rman_get_bushandle(sc->sc_rres[1]);
|
||||
bpp.h_Bm = bsc->sc_bh;
|
||||
bpp.swPortalId = cpu;
|
||||
bpp.irq = (uintptr_t)sc->sc_dp[cpu].dp_ires;
|
||||
|
||||
portal = BM_PORTAL_Config(&bpp);
|
||||
if (portal == NULL)
|
||||
critical_enter();
|
||||
mc_res = bman_mc_send(sc, BMAN_MC_VERB_QUERY, 0);
|
||||
if (mc_res == NULL)
|
||||
goto err;
|
||||
|
||||
if (BM_PORTAL_Init(portal) != E_OK)
|
||||
goto err;
|
||||
if (depletion)
|
||||
res = mc_res->bp_ds;
|
||||
else
|
||||
res = mc_res->bp_as;
|
||||
critical_exit();
|
||||
|
||||
atomic_store_rel_ptr((uintptr_t *)&sc->sc_dp[cpu].dp_ph, (uintptr_t)portal);
|
||||
|
||||
sched_unpin();
|
||||
|
||||
return (portal);
|
||||
return (res);
|
||||
|
||||
err:
|
||||
if (portal != NULL)
|
||||
BM_PORTAL_Free(portal);
|
||||
|
||||
atomic_store_rel_ptr((uintptr_t *)&sc->sc_dp[cpu].dp_ph, 0);
|
||||
sched_unpin();
|
||||
|
||||
return (NULL);
|
||||
critical_exit();
|
||||
device_printf(sc->sc_base.sc_dev, "Timeout querying depltetion\n");
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
bman_portal_isr(void *arg)
|
||||
{
|
||||
struct bman_portal_softc *sc = arg;
|
||||
uint32_t intrs;
|
||||
|
||||
intrs = bm_ci_read(sc, BCSP_ISR);
|
||||
|
||||
/* Release Command Ring interrupt. */
|
||||
if (intrs & INTR_RCRI) {
|
||||
bman_rcr_update(&sc->sc_rcr, &sc->sc_base);
|
||||
}
|
||||
/* Buffer Pool State Change Notification. */
|
||||
if (intrs & INTR_BSCN) {
|
||||
struct bman_pool *pool;
|
||||
uint64_t res = bman_query(sc, true);
|
||||
if (__predict_true(res != 0)) {
|
||||
int idx = flsll(res);
|
||||
pool = sc->sc_pools[64 - idx];
|
||||
KASSERT(pool != NULL,
|
||||
("state change on unassociated bpid %d\n", idx));
|
||||
pool->dep_cb(pool->arg, true);
|
||||
}
|
||||
}
|
||||
|
||||
bm_ci_write(sc, BCSP_ISR, intrs);
|
||||
}
|
||||
|
||||
/* RCR */
|
||||
|
||||
int
|
||||
bman_release(struct bman_pool *pool, const struct bman_buffer *bufs,
|
||||
uint8_t count)
|
||||
{
|
||||
struct bman_portal_softc *portal;
|
||||
struct bman_rcr_entry *rcr;
|
||||
|
||||
if (count > 8)
|
||||
return (EINVAL);
|
||||
|
||||
critical_enter();
|
||||
portal = DPCPU_GET(bman_affine_portal);
|
||||
rcr = bman_rcr_start(&portal->sc_rcr, &portal->sc_base);
|
||||
bzero(rcr, sizeof(*rcr));
|
||||
|
||||
/* This should be safe, because bpid must be less than 256. */
|
||||
for (int i = 0; i < count; i++)
|
||||
rcr->bufs[i] = bufs[i];
|
||||
rcr->bufs[0].bpid = pool->bpid;
|
||||
bman_rcr_commit(&portal->sc_rcr, BMAN_RCR_VERB_BPID0 | count);
|
||||
critical_exit();
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* MC commands */
|
||||
/* Assumes pinned */
|
||||
static union bman_mc_result *
|
||||
bman_mc_send(struct bman_portal_softc *p, uint8_t verb, uint8_t cd)
|
||||
{
|
||||
int res_idx;
|
||||
struct bman_mc_command *command;
|
||||
union bman_mc_result *rr;
|
||||
uintptr_t ce_va = p->sc_base.sc_ce_va;
|
||||
|
||||
command = (struct bman_mc_command *)(ce_va + BMAN_CE_CR);
|
||||
dpaa_zero_line(command);
|
||||
command->cd = cd;
|
||||
dpaa_lw_barrier();
|
||||
command->verb = verb | p->mc.polarity;
|
||||
res_idx = (p->mc.polarity ? 1 : 0);
|
||||
p->mc.polarity ^= BMAN_MC_VERB_VBIT;
|
||||
dpaa_flush_line(command);
|
||||
|
||||
rr = (union bman_mc_result *)(ce_va + BMAN_CE_RR(res_idx));
|
||||
for (;;) {
|
||||
if (rr->verb != 0)
|
||||
break;
|
||||
dpaa_flush_line(rr);
|
||||
}
|
||||
return (rr);
|
||||
}
|
||||
|
||||
int
|
||||
bman_acquire(struct bman_pool *pool, struct bman_buffer *bufs, uint8_t count)
|
||||
{
|
||||
union bman_mc_result *rr;
|
||||
|
||||
if (count > 8 || count == 0)
|
||||
return (EINVAL);
|
||||
critical_enter();
|
||||
rr = bman_mc_send(DPCPU_GET(bman_affine_portal),
|
||||
BMAN_MC_VERB_ACQUIRE | count,
|
||||
pool->bpid);
|
||||
critical_exit();
|
||||
|
||||
if (rr == NULL)
|
||||
return (ETIMEDOUT);
|
||||
if ((rr->verb & ~BMAN_MC_VERB_VBIT) == 0)
|
||||
return (ENOMEM);
|
||||
|
||||
memcpy(bufs, rr, count * sizeof(*bufs));
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable pool state change notifications on this portal. This requires the
|
||||
* pool to already be configured with the callback to handle state changes.
|
||||
*/
|
||||
void
|
||||
bman_portal_enable_scn(struct bman_portal_softc *sc, struct bman_pool *pool)
|
||||
{
|
||||
uint32_t reg, reg_ptr;
|
||||
|
||||
if (pool->bpid >= 32)
|
||||
reg_ptr = BCSP_SCN1;
|
||||
else
|
||||
reg_ptr = BCSP_SCN0;
|
||||
reg = bm_ci_read(sc, reg_ptr);
|
||||
reg |= (1 << (31 - pool->bpid));
|
||||
bm_ci_write(sc, reg_ptr, reg);
|
||||
sc->sc_pools[pool->bpid] = pool;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2026 Justin Hibbits
|
||||
*/
|
||||
|
||||
#ifndef BMAN_VAR_H
|
||||
#define BMAN_VAR_H
|
||||
|
||||
#include "dpaa_common.h"
|
||||
#include "portals.h"
|
||||
|
||||
#define BMAN_MAX_POOLS 64
|
||||
#define BMAN_MAX_POOLS_1023 8
|
||||
|
||||
DPAA_RING_DECLARE(bman_rcr);
|
||||
|
||||
struct bman_mc {
|
||||
uint8_t polarity;
|
||||
bool busy;
|
||||
};
|
||||
|
||||
struct bman_portal_softc {
|
||||
struct dpaa_portal_softc sc_base;
|
||||
|
||||
struct bman_mc mc;
|
||||
struct bman_rcr_ring sc_rcr;
|
||||
struct bman_pool *sc_pools[BMAN_MAX_POOLS];
|
||||
};
|
||||
|
||||
struct bman_pool {
|
||||
uint32_t bpid;
|
||||
bm_depletion_handler dep_cb;
|
||||
void *arg;
|
||||
};
|
||||
|
||||
DPCPU_DECLARE(struct bman_portal_softc *, bman_affine_portal);
|
||||
|
||||
int bman_release(struct bman_pool *pool, const struct bman_buffer *bufs,
|
||||
uint8_t count);
|
||||
|
||||
void bman_portal_enable_scn(struct bman_portal_softc *, struct bman_pool *);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2026 Justin Hibbits
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <vm/vm.h>
|
||||
#include <vm/pmap.h>
|
||||
|
||||
#include <dev/fdt/fdt_common.h>
|
||||
#include <dev/ofw/ofw_bus.h>
|
||||
#include <dev/ofw/ofw_bus_subr.h>
|
||||
|
||||
#include "dpaa_common.h"
|
||||
|
||||
#define FDT_REG_CELLS 4
|
||||
int
|
||||
dpaa_map_private_memory(device_t dev, int idx, const char *compat,
|
||||
vm_paddr_t *addrp, size_t *sizep)
|
||||
{
|
||||
phandle_t node;
|
||||
pcell_t cells[idx + 1];
|
||||
pcell_t *cell_alloc;
|
||||
int addr_cells, size_cells;
|
||||
uint64_t tmp;
|
||||
u_long align, base, size;
|
||||
vm_paddr_t alloc_base;
|
||||
vm_size_t alloc_range_size;
|
||||
ssize_t alloc_size;
|
||||
void *reserved;
|
||||
int rv;
|
||||
|
||||
node = ofw_bus_get_node(dev);
|
||||
if (OF_getencprop(node, "memory-region", cells, sizeof(cells)) <= 0)
|
||||
return (ENXIO);
|
||||
|
||||
node = OF_node_from_xref(cells[idx]);
|
||||
/* If the memory is already reserved, we just need to return it. */
|
||||
if (fdt_regsize(node, &base, &size) == 0)
|
||||
goto success;
|
||||
|
||||
rv = fdt_addrsize_cells(OF_parent(node), &addr_cells, &size_cells);
|
||||
if (rv != 0)
|
||||
return (rv);
|
||||
|
||||
if (OF_getprop(node, "alignment", &tmp, sizeof(tmp)) <= 0)
|
||||
return (ENXIO);
|
||||
|
||||
align = fdt_data_get(&tmp, addr_cells);
|
||||
if (OF_getprop(node, "size", &tmp, sizeof(tmp)) <= 0)
|
||||
return (ENXIO);
|
||||
size = fdt_data_get(&tmp, size_cells);
|
||||
|
||||
alloc_size =
|
||||
OF_getencprop_alloc(node, "alloc-ranges", (void **)&cell_alloc);
|
||||
if (alloc_size < 0)
|
||||
return (ENXIO);
|
||||
|
||||
alloc_size /= sizeof(pcell_t);
|
||||
for (int i = 0; i < alloc_size; i += (addr_cells + size_cells)) {
|
||||
alloc_base = fdt_data_get(&cell_alloc[i], addr_cells);
|
||||
alloc_range_size =
|
||||
fdt_data_get(&cell_alloc[i + addr_cells], size_cells);
|
||||
reserved = contigmalloc(size, M_DEVBUF, M_NOWAIT | M_ZERO,
|
||||
alloc_base, alloc_base + alloc_range_size, align, 0);
|
||||
if (reserved != NULL)
|
||||
break;
|
||||
}
|
||||
if (reserved == NULL)
|
||||
return (ENOMEM);
|
||||
/* Flush the cache (zeroed memory) because it won't be touched later. */
|
||||
cpu_flush_dcache(reserved, size);
|
||||
base = pmap_kextract((vm_offset_t)reserved);
|
||||
|
||||
success:
|
||||
*addrp = base;
|
||||
*sizep = size;
|
||||
|
||||
return (0);
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2026 Justin Hibbits
|
||||
*/
|
||||
|
||||
#ifndef DPAA_COMMON_H
|
||||
#define DPAA_COMMON_H
|
||||
|
||||
#include <machine/atomic.h>
|
||||
|
||||
int dpaa_map_private_memory(device_t dev, int idx, const char *compat,
|
||||
vm_paddr_t *addrp, size_t *sizep);
|
||||
|
||||
struct dpaa_fd {
|
||||
uint64_t liodn:8;
|
||||
uint64_t bpid:8;
|
||||
uint64_t eliodn:4;
|
||||
uint64_t _rsvd1:4;
|
||||
uint64_t addr:40;
|
||||
uint32_t format:3;
|
||||
uint32_t offset:9;
|
||||
uint32_t length:20;
|
||||
uint32_t cmd_stat;
|
||||
} __packed;
|
||||
|
||||
#define DPAA_FD_FORMAT_SHORT_MBSF 4
|
||||
|
||||
#define DPAA_FD_GET_ADDR(fd) ((void *)PHYS_TO_DMAP(fd->addr))
|
||||
|
||||
struct dpaa_sgte {
|
||||
uint64_t addr;
|
||||
uint32_t extension:1;
|
||||
uint32_t final:1;
|
||||
uint32_t length:30;
|
||||
uint16_t bpid;
|
||||
uint16_t offset;
|
||||
} __packed;
|
||||
struct qman_fqr;
|
||||
|
||||
|
||||
#define DPAA_NUM_OF_SG_TABLE_ENTRY 16
|
||||
|
||||
/*
|
||||
* Ring API infrastructure
|
||||
*
|
||||
* BMan and QMan both use cache-enabled rings. Abstract this away to a more
|
||||
* generalized interface to reduce code copying.
|
||||
*
|
||||
* Requirements:
|
||||
* - Before calling <ring>_init() the ring base (ring->ring) must be initialized
|
||||
* to the base of the ring.
|
||||
*/
|
||||
#define DPAA_RING_DECLARE(pfx) \
|
||||
struct pfx##_ring { \
|
||||
struct pfx##_entry *ring; \
|
||||
struct pfx##_entry *cursor; \
|
||||
uint8_t vbit; \
|
||||
uint8_t avail; \
|
||||
uint8_t ci; \
|
||||
uint8_t ithresh; \
|
||||
}
|
||||
|
||||
/*
|
||||
* Ring functions:
|
||||
*
|
||||
* ring_cyc_diff() -- get the (circular) difference of `l - f`
|
||||
* ring_ring_init() -- Set up the ring structures. Portal must be
|
||||
* initialized beforehand, and ring->ring must be nonzero.
|
||||
* ring_CARRYCLEAR() -- stealth math to do circular roll-over
|
||||
* ring_INC() -- Increment the cursor within the ring
|
||||
* ring_update() -- Update ring entry availability count
|
||||
* ring_start() -- Reserve the next entry in the ring if available.
|
||||
* ring_commit() -- Commit the reserved ring entry by setting the verb and
|
||||
* AVB bit
|
||||
*/
|
||||
#define DPAA_RING(pfx,sz,pi_e,ci_e,pi_i,ci_i) \
|
||||
static inline int \
|
||||
pfx##_cyc_diff(uint8_t size, uint8_t f, uint8_t l) \
|
||||
{ \
|
||||
if (f <= l) \
|
||||
return (uint8_t)(l - f); \
|
||||
return (uint8_t)(l + size - f); \
|
||||
} \
|
||||
static inline void \
|
||||
pfx##_ring_init(struct pfx##_ring *ring, struct dpaa_portal_softc *portal)\
|
||||
{ \
|
||||
uint32_t pi = *(uint32_t*)(portal->sc_ci_va + pi_i) & (sz - 1); \
|
||||
uint32_t ci = *(uint32_t*)(portal->sc_ci_va + ci_i); \
|
||||
ring->ci = ci & (sz - 1); \
|
||||
ring->vbit = !!(ci & sz) << 7; \
|
||||
ring->cursor = ring->ring + pi; \
|
||||
ring->avail = sz - 1 - pfx##_cyc_diff(sz, ring->ci, pi); \
|
||||
} \
|
||||
static inline void * \
|
||||
pfx##_CARRYCLEAR(struct pfx##_entry *p) \
|
||||
{ \
|
||||
return ((void *)((uintptr_t)p & (~(uintptr_t)(sz << 6)))); \
|
||||
} \
|
||||
static inline void \
|
||||
pfx##_INC(struct pfx##_ring *ring) \
|
||||
{ \
|
||||
struct pfx##_entry *partial = ring->cursor + 1; \
|
||||
ring->cursor = pfx##_CARRYCLEAR(partial); \
|
||||
if (partial != ring->cursor) \
|
||||
ring->vbit ^= 0x80; \
|
||||
} \
|
||||
static inline uint8_t \
|
||||
pfx##_update(struct pfx##_ring *ring, struct dpaa_portal_softc *portal) \
|
||||
{ \
|
||||
uint8_t diff, old_ci = ring->ci; \
|
||||
ring->ci = *(uint32_t*)(portal->sc_ci_va + ci_i) & (sz - 1); \
|
||||
diff = pfx##_cyc_diff(sz, old_ci, ring->ci); \
|
||||
ring->avail += diff; \
|
||||
return (diff); \
|
||||
} \
|
||||
static inline struct pfx##_entry * __unused \
|
||||
pfx##_start(struct pfx##_ring *ring, struct dpaa_portal_softc *portal) \
|
||||
{ \
|
||||
if (ring->avail <= 1) { \
|
||||
pfx##_update(ring, portal); \
|
||||
if (ring->avail == 0) \
|
||||
return (NULL); \
|
||||
} \
|
||||
dpaa_zero_line(ring->cursor); \
|
||||
return (ring->cursor); \
|
||||
} \
|
||||
static inline void __unused \
|
||||
pfx##_commit(struct pfx##_ring *ring, uint8_t verb) \
|
||||
{ \
|
||||
struct pfx##_entry *entry = ring->cursor; \
|
||||
dpaa_lw_barrier(); \
|
||||
entry->verb = verb | ring->vbit; \
|
||||
dpaa_flush_line(entry); \
|
||||
pfx##_INC(ring); \
|
||||
ring->avail--; \
|
||||
} struct hack
|
||||
|
||||
#ifdef __powerpc__
|
||||
static inline void
|
||||
dpaa_flush_line(void *line)
|
||||
{
|
||||
__asm __volatile ("dcbf 0, %0" :: "r"(line) : "memory");
|
||||
}
|
||||
|
||||
static inline void
|
||||
dpaa_zero_line(void *line)
|
||||
{
|
||||
__asm __volatile ("dcbz 0, %0" :: "r"(line) : "memory");
|
||||
}
|
||||
|
||||
static inline void
|
||||
dpaa_touch_line(void *line)
|
||||
{
|
||||
__asm __volatile ("dcbt 0, %0" :: "r"(line) : "memory");
|
||||
}
|
||||
|
||||
static inline void
|
||||
dpaa_lw_barrier(void)
|
||||
{
|
||||
powerpc_lwsync();
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,634 @@
|
||||
/*-
|
||||
* Copyright (c) 2012 Semihalf.
|
||||
* 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 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/kernel.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/rman.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/smp.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sockio.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <net/if_media.h>
|
||||
#include <net/if_types.h>
|
||||
#include <net/if_arp.h>
|
||||
|
||||
#include <dev/mii/mii.h>
|
||||
#include <dev/mii/miivar.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/pmap.h>
|
||||
|
||||
#include "miibus_if.h"
|
||||
|
||||
#include "bman.h"
|
||||
#include "dpaa_common.h"
|
||||
#include "dpaa_eth.h"
|
||||
#include "fman.h"
|
||||
#include "fman_port.h"
|
||||
#include "fman_if.h"
|
||||
#include "fman_port_if.h"
|
||||
#include "if_dtsec.h"
|
||||
#include "qman.h"
|
||||
#include "qman_var.h"
|
||||
#include "qman_portal_if.h"
|
||||
|
||||
|
||||
#define DPAA_ETH_LOCK(sc) mtx_lock(&(sc)->sc_lock)
|
||||
#define DPAA_ETH_UNLOCK(sc) mtx_unlock(&(sc)->sc_lock)
|
||||
#define DPAA_ETH_LOCK_ASSERT(sc) mtx_assert(&(sc)->sc_lock, MA_OWNED)
|
||||
|
||||
/**
|
||||
* @group dTSEC RM private defines.
|
||||
* @{
|
||||
*/
|
||||
#define DTSEC_BPOOLS_USED (1)
|
||||
#define DTSEC_MAX_TX_QUEUE_LEN 256
|
||||
|
||||
struct dpaa_eth_frame_info {
|
||||
struct mbuf *fi_mbuf;
|
||||
struct dpaa_sgte fi_sgt[DPAA_NUM_OF_SG_TABLE_ENTRY];
|
||||
};
|
||||
|
||||
enum dpaa_eth_pool_params {
|
||||
DTSEC_RM_POOL_RX_LOW_MARK = 16,
|
||||
DTSEC_RM_POOL_RX_HIGH_MARK = 64,
|
||||
DTSEC_RM_POOL_RX_MAX_SIZE = 256,
|
||||
|
||||
DTSEC_RM_POOL_FI_LOW_MARK = 16,
|
||||
DTSEC_RM_POOL_FI_HIGH_MARK = 64,
|
||||
DTSEC_RM_POOL_FI_MAX_SIZE = 256,
|
||||
};
|
||||
|
||||
#define DTSEC_RM_FQR_RX_CHANNEL 0x401
|
||||
#define DTSEC_RM_FQR_TX_CONF_CHANNEL 0
|
||||
enum dpaa_eth_fq_params {
|
||||
DTSEC_RM_FQR_RX_WQ = 1,
|
||||
DTSEC_RM_FQR_TX_WQ = 1,
|
||||
DTSEC_RM_FQR_TX_CONF_WQ = 1
|
||||
};
|
||||
/** @} */
|
||||
|
||||
|
||||
/**
|
||||
* @group dTSEC Frame Info routines.
|
||||
* @{
|
||||
*/
|
||||
void
|
||||
dpaa_eth_fi_pool_free(struct dpaa_eth_softc *sc)
|
||||
{
|
||||
|
||||
if (sc->sc_fi_zone != NULL)
|
||||
uma_zdestroy(sc->sc_fi_zone);
|
||||
}
|
||||
|
||||
int
|
||||
dpaa_eth_fi_pool_init(struct dpaa_eth_softc *sc)
|
||||
{
|
||||
|
||||
snprintf(sc->sc_fi_zname, sizeof(sc->sc_fi_zname), "%s: Frame Info",
|
||||
device_get_nameunit(sc->sc_dev));
|
||||
|
||||
sc->sc_fi_zone = uma_zcreate(sc->sc_fi_zname,
|
||||
sizeof(struct dpaa_eth_frame_info), NULL, NULL, NULL, NULL,
|
||||
UMA_ALIGN_PTR, 0);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static struct dpaa_eth_frame_info *
|
||||
dpaa_eth_fi_alloc(struct dpaa_eth_softc *sc)
|
||||
{
|
||||
struct dpaa_eth_frame_info *fi;
|
||||
|
||||
fi = uma_zalloc(sc->sc_fi_zone, M_NOWAIT);
|
||||
|
||||
return (fi);
|
||||
}
|
||||
|
||||
static void
|
||||
dpaa_eth_fi_free(struct dpaa_eth_softc *sc, struct dpaa_eth_frame_info *fi)
|
||||
{
|
||||
|
||||
uma_zfree(sc->sc_fi_zone, fi);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
|
||||
/**
|
||||
* @group dTSEC FMan PORT routines.
|
||||
* @{
|
||||
*/
|
||||
int
|
||||
dpaa_eth_fm_port_rx_init(struct dpaa_eth_softc *sc)
|
||||
{
|
||||
struct fman_port_params params;
|
||||
int error;
|
||||
|
||||
params.dflt_fqid = sc->sc_rx_fqid;
|
||||
params.err_fqid = sc->sc_rx_fqid;
|
||||
params.rx_params.num_pools = 1;
|
||||
params.rx_params.bpools[0].bpid = bman_get_bpid(sc->sc_rx_pool);
|
||||
params.rx_params.bpools[0].size = MCLBYTES;
|
||||
error = FMAN_PORT_CONFIG(sc->sc_rx_port, ¶ms);
|
||||
error = FMAN_PORT_INIT(sc->sc_rx_port);
|
||||
if (error != 0) {
|
||||
device_printf(sc->sc_dev, "couldn't initialize FM Port RX.\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
dpaa_eth_fm_port_tx_init(struct dpaa_eth_softc *sc)
|
||||
{
|
||||
struct fman_port_params params;
|
||||
int error;
|
||||
|
||||
params.dflt_fqid = sc->sc_tx_conf_fqid;
|
||||
params.err_fqid = sc->sc_tx_conf_fqid;
|
||||
|
||||
error = FMAN_PORT_CONFIG(sc->sc_tx_port, ¶ms);
|
||||
error = FMAN_PORT_INIT(sc->sc_tx_port);
|
||||
if (error != 0) {
|
||||
device_printf(sc->sc_dev, "couldn't initialize FM Port TX.\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
|
||||
/**
|
||||
* @group dTSEC buffer pools routines.
|
||||
* @{
|
||||
*/
|
||||
static int
|
||||
dpaa_eth_pool_rx_put_buffer(struct dpaa_eth_softc *sc, uint8_t *buffer,
|
||||
void *context)
|
||||
{
|
||||
|
||||
uma_zfree(sc->sc_rx_zone, buffer);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
dtsec_add_buffers(struct dpaa_eth_softc *sc, int count)
|
||||
{
|
||||
struct bman_buffer bufs[8] = {};
|
||||
int err;
|
||||
int c;
|
||||
|
||||
while (count > 0) {
|
||||
c = min(8, count);
|
||||
for (int i = 0; i < c; i++) {
|
||||
void *b;
|
||||
vm_paddr_t pa;
|
||||
|
||||
b = uma_zalloc(sc->sc_rx_zone, M_NOWAIT);
|
||||
if (b == NULL)
|
||||
return (ENOMEM);
|
||||
pa = pmap_kextract((vm_offset_t)b);
|
||||
bufs[i].buf_hi = (pa >> 32);
|
||||
bufs[i].buf_lo = (pa & 0xffffffff);
|
||||
}
|
||||
|
||||
err = bman_put_buffers(sc->sc_rx_pool, bufs, c);
|
||||
if (err != 0)
|
||||
return (err);
|
||||
count -= c;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
dpaa_eth_pool_rx_depleted(void *h_App, bool in)
|
||||
{
|
||||
struct dpaa_eth_softc *sc;
|
||||
unsigned int count;
|
||||
|
||||
sc = h_App;
|
||||
|
||||
if (!in)
|
||||
return;
|
||||
|
||||
while (1) {
|
||||
count = bman_count(sc->sc_rx_pool);
|
||||
if (count > DTSEC_RM_POOL_RX_HIGH_MARK)
|
||||
return;
|
||||
|
||||
/* Can only release 8 buffers at a time */
|
||||
count = min(DTSEC_RM_POOL_RX_HIGH_MARK - count + 8, 8);
|
||||
if (dtsec_add_buffers(sc, count) != 0)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dpaa_eth_pool_rx_free(struct dpaa_eth_softc *sc)
|
||||
{
|
||||
|
||||
if (sc->sc_rx_pool != NULL)
|
||||
bman_pool_destroy(sc->sc_rx_pool);
|
||||
|
||||
if (sc->sc_rx_zone != NULL)
|
||||
uma_zdestroy(sc->sc_rx_zone);
|
||||
}
|
||||
|
||||
int
|
||||
dpaa_eth_pool_rx_init(struct dpaa_eth_softc *sc)
|
||||
{
|
||||
|
||||
/* MCLBYTES must be less than PAGE_SIZE */
|
||||
CTASSERT(MCLBYTES < PAGE_SIZE);
|
||||
|
||||
snprintf(sc->sc_rx_zname, sizeof(sc->sc_rx_zname), "%s: RX Buffers",
|
||||
device_get_nameunit(sc->sc_dev));
|
||||
|
||||
sc->sc_rx_zone = uma_zcreate(sc->sc_rx_zname, MCLBYTES, NULL,
|
||||
NULL, NULL, NULL, MCLBYTES - 1, 0);
|
||||
|
||||
sc->sc_rx_pool = bman_pool_create(&sc->sc_rx_bpid, MCLBYTES,
|
||||
DTSEC_RM_POOL_RX_MAX_SIZE, DTSEC_RM_POOL_RX_LOW_MARK,
|
||||
DTSEC_RM_POOL_RX_HIGH_MARK, 0, 0, dpaa_eth_pool_rx_depleted, sc);
|
||||
if (sc->sc_rx_pool == NULL) {
|
||||
device_printf(sc->sc_dev, "NULL rx pool somehow\n");
|
||||
dpaa_eth_pool_rx_free(sc);
|
||||
return (EIO);
|
||||
}
|
||||
|
||||
dtsec_add_buffers(sc, DTSEC_RM_POOL_RX_HIGH_MARK);
|
||||
|
||||
return (0);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
|
||||
/**
|
||||
* @group dTSEC Frame Queue Range routines.
|
||||
* @{
|
||||
*/
|
||||
static void
|
||||
dpaa_eth_fq_mext_free(struct mbuf *m)
|
||||
{
|
||||
struct dpaa_eth_softc *sc;
|
||||
void *buffer;
|
||||
|
||||
buffer = m->m_ext.ext_arg1;
|
||||
sc = m->m_ext.ext_arg2;
|
||||
if (bman_count(sc->sc_rx_pool) <= DTSEC_RM_POOL_RX_MAX_SIZE)
|
||||
bman_put_buffer(sc->sc_rx_pool,
|
||||
pmap_kextract((vm_offset_t)buffer), sc->sc_rx_bpid);
|
||||
else
|
||||
dpaa_eth_pool_rx_put_buffer(sc, buffer, NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
dpaa_eth_fq_rx_callback(device_t portal, struct qman_fq *fq,
|
||||
struct qman_fd *frame, void *app)
|
||||
{
|
||||
struct dpaa_eth_softc *sc;
|
||||
struct mbuf *m;
|
||||
void *frame_va;
|
||||
|
||||
m = NULL;
|
||||
sc = app;
|
||||
|
||||
frame_va = DPAA_FD_GET_ADDR(frame);
|
||||
KASSERT(frame->format == 0,
|
||||
("%s(): Got unsupported frame format 0x%02X!", __func__,
|
||||
frame->format));
|
||||
|
||||
KASSERT(frame->offset == 0,
|
||||
("%s(): Only offset 0 is supported!", __func__));
|
||||
|
||||
if (frame->cmd_stat != 0) {
|
||||
device_printf(sc->sc_dev, "RX error: 0x%08X\n",
|
||||
frame->cmd_stat);
|
||||
goto err;
|
||||
}
|
||||
|
||||
m = m_gethdr(M_NOWAIT, MT_HEADER);
|
||||
if (m == NULL)
|
||||
goto err;
|
||||
|
||||
m_extadd(m, frame_va, MCLBYTES, dpaa_eth_fq_mext_free, frame_va, sc, 0,
|
||||
EXT_NET_DRV);
|
||||
|
||||
m->m_pkthdr.rcvif = sc->sc_ifnet;
|
||||
m->m_len = frame->length;
|
||||
m_fixhdr(m);
|
||||
|
||||
if_input(sc->sc_ifnet, m);
|
||||
|
||||
return (1);
|
||||
|
||||
err:
|
||||
bman_put_buffer(sc->sc_rx_pool, frame->addr, sc->sc_rx_bpid);
|
||||
if (m != NULL)
|
||||
m_freem(m);
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
static int
|
||||
dpaa_eth_fq_tx_confirm_callback(device_t portal, struct qman_fq *fq,
|
||||
struct qman_fd *frame, void *app)
|
||||
{
|
||||
struct dpaa_eth_frame_info *fi;
|
||||
struct dpaa_eth_softc *sc;
|
||||
unsigned int qlen;
|
||||
struct dpaa_sgte *sgt0;
|
||||
|
||||
sc = app;
|
||||
|
||||
if (frame->cmd_stat != 0)
|
||||
device_printf(sc->sc_dev, "TX error: 0x%08X\n",
|
||||
frame->cmd_stat);
|
||||
|
||||
/*
|
||||
* We are storing struct dpaa_eth_frame_info in first entry
|
||||
* of scatter-gather table.
|
||||
*/
|
||||
sgt0 = (struct dpaa_sgte *)PHYS_TO_DMAP(frame->addr);
|
||||
fi = (struct dpaa_eth_frame_info *)PHYS_TO_DMAP(sgt0->addr);
|
||||
|
||||
/* Free transmitted frame */
|
||||
m_freem(fi->fi_mbuf);
|
||||
dpaa_eth_fi_free(sc, fi);
|
||||
|
||||
qlen = qman_fq_get_counter(sc->sc_tx_conf_fq, QMAN_COUNTER_FRAME);
|
||||
|
||||
if (qlen == 0) {
|
||||
DPAA_ETH_LOCK(sc);
|
||||
|
||||
if (sc->sc_tx_fq_full) {
|
||||
sc->sc_tx_fq_full = 0;
|
||||
dpaa_eth_if_start_locked(sc);
|
||||
}
|
||||
|
||||
DPAA_ETH_UNLOCK(sc);
|
||||
}
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
void
|
||||
dpaa_eth_fq_rx_free(struct dpaa_eth_softc *sc)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
if (sc->sc_rx_fq)
|
||||
qman_fq_free(sc->sc_rx_fq);
|
||||
if (sc->sc_rx_channel != 0) {
|
||||
CPU_FOREACH(cpu) {
|
||||
device_t portal = DPCPU_ID_GET(cpu, qman_affine_portal);
|
||||
QMAN_PORTAL_STATIC_DEQUEUE_RM_CHANNEL(portal,
|
||||
sc->sc_rx_channel);
|
||||
}
|
||||
qman_free_channel(sc->sc_rx_channel);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
dpaa_eth_fq_rx_init(struct dpaa_eth_softc *sc)
|
||||
{
|
||||
void *fq;
|
||||
int error;
|
||||
int cpu;
|
||||
|
||||
/* Default Frame Queue */
|
||||
if (sc->sc_rx_channel == 0)
|
||||
sc->sc_rx_channel = qman_alloc_channel();
|
||||
fq = qman_fq_create(1, sc->sc_rx_channel, DTSEC_RM_FQR_RX_WQ,
|
||||
false, 0, false, false, true, false, 0, 0, 0);
|
||||
if (fq == NULL) {
|
||||
device_printf(sc->sc_dev,
|
||||
"could not create default RX queue\n");
|
||||
return (EIO);
|
||||
}
|
||||
|
||||
CPU_FOREACH(cpu) {
|
||||
device_t portal = DPCPU_ID_GET(cpu, qman_affine_portal);
|
||||
QMAN_PORTAL_STATIC_DEQUEUE_CHANNEL(portal, sc->sc_rx_channel);
|
||||
}
|
||||
|
||||
sc->sc_rx_fq = fq;
|
||||
sc->sc_rx_fqid = qman_fq_get_fqid(fq);
|
||||
|
||||
error = qman_fq_register_cb(fq, dpaa_eth_fq_rx_callback, sc);
|
||||
if (error != 0) {
|
||||
device_printf(sc->sc_dev, "could not register RX callback\n");
|
||||
dpaa_eth_fq_rx_free(sc);
|
||||
return (EIO);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
dpaa_eth_fq_tx_free(struct dpaa_eth_softc *sc)
|
||||
{
|
||||
|
||||
if (sc->sc_tx_fq)
|
||||
qman_fq_free(sc->sc_tx_fq);
|
||||
|
||||
if (sc->sc_tx_conf_fq)
|
||||
qman_fq_free(sc->sc_tx_conf_fq);
|
||||
}
|
||||
|
||||
int
|
||||
dpaa_eth_fq_tx_init(struct dpaa_eth_softc *sc)
|
||||
{
|
||||
int error;
|
||||
void *fq;
|
||||
|
||||
/* TX Frame Queue */
|
||||
fq = qman_fq_create(1, sc->sc_port_tx_qman_chan,
|
||||
DTSEC_RM_FQR_TX_WQ, false, 0, false, false, true, false, 0, 0, 0);
|
||||
if (fq == NULL) {
|
||||
device_printf(sc->sc_dev, "could not create default TX queue"
|
||||
"\n");
|
||||
return (EIO);
|
||||
}
|
||||
|
||||
sc->sc_tx_fq = fq;
|
||||
|
||||
if (sc->sc_rx_channel == 0)
|
||||
sc->sc_rx_channel = qman_alloc_channel();
|
||||
/* TX Confirmation Frame Queue */
|
||||
fq = qman_fq_create(1, sc->sc_rx_channel,
|
||||
DTSEC_RM_FQR_TX_CONF_WQ, false, 0, false, false, true, false, 0, 0,
|
||||
0);
|
||||
if (fq == NULL) {
|
||||
device_printf(sc->sc_dev, "could not create TX confirmation "
|
||||
"queue\n");
|
||||
dpaa_eth_fq_tx_free(sc);
|
||||
return (EIO);
|
||||
}
|
||||
|
||||
sc->sc_tx_conf_fq = fq;
|
||||
sc->sc_tx_conf_fqid = qman_fq_get_fqid(fq);
|
||||
|
||||
error = qman_fq_register_cb(fq, dpaa_eth_fq_tx_confirm_callback, sc);
|
||||
if (error != 0) {
|
||||
device_printf(sc->sc_dev, "could not register TX confirmation "
|
||||
"callback\n");
|
||||
dpaa_eth_fq_tx_free(sc);
|
||||
return (EIO);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
|
||||
/**
|
||||
* @group dTSEC IFnet routines.
|
||||
* @{
|
||||
*/
|
||||
void
|
||||
dpaa_eth_if_start_locked(struct dpaa_eth_softc *sc)
|
||||
{
|
||||
vm_size_t dsize, psize, ssize;
|
||||
struct dpaa_eth_frame_info *fi;
|
||||
unsigned int qlen, i;
|
||||
struct mbuf *m0, *m;
|
||||
vm_offset_t vaddr;
|
||||
struct dpaa_fd fd;
|
||||
|
||||
DPAA_ETH_LOCK_ASSERT(sc);
|
||||
/* TODO: IFF_DRV_OACTIVE */
|
||||
|
||||
if ((sc->sc_mii->mii_media_status & IFM_ACTIVE) == 0)
|
||||
return;
|
||||
|
||||
if ((if_getdrvflags(sc->sc_ifnet) & IFF_DRV_RUNNING) != IFF_DRV_RUNNING)
|
||||
return;
|
||||
|
||||
while (!if_sendq_empty(sc->sc_ifnet)) {
|
||||
/* Check length of the TX queue */
|
||||
qlen = qman_fq_get_counter(sc->sc_tx_fq, QMAN_COUNTER_FRAME);
|
||||
|
||||
if (qlen >= DTSEC_MAX_TX_QUEUE_LEN) {
|
||||
sc->sc_tx_fq_full = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
fi = dpaa_eth_fi_alloc(sc);
|
||||
if (fi == NULL)
|
||||
return;
|
||||
|
||||
m0 = if_dequeue(sc->sc_ifnet);
|
||||
if (m0 == NULL) {
|
||||
dpaa_eth_fi_free(sc, fi);
|
||||
return;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
m = m0;
|
||||
psize = 0;
|
||||
dsize = 0;
|
||||
fi->fi_mbuf = m0;
|
||||
while (m && i < DPAA_NUM_OF_SG_TABLE_ENTRY) {
|
||||
if (m->m_len == 0)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* First entry in scatter-gather table is used to keep
|
||||
* pointer to frame info structure.
|
||||
*/
|
||||
memset(&fi->fi_sgt[i], 0, sizeof(fi->fi_sgt[i]));
|
||||
fi->fi_sgt[i].addr = pmap_kextract((vm_offset_t)fi);
|
||||
i++;
|
||||
|
||||
dsize = m->m_len;
|
||||
vaddr = (vm_offset_t)m->m_data;
|
||||
while (dsize > 0 && i < DPAA_NUM_OF_SG_TABLE_ENTRY) {
|
||||
ssize = PAGE_SIZE - (vaddr & PAGE_MASK);
|
||||
if (m->m_len < ssize)
|
||||
ssize = m->m_len;
|
||||
|
||||
fi->fi_sgt[i].addr = pmap_kextract(vaddr);
|
||||
fi->fi_sgt[i].length = ssize;
|
||||
|
||||
fi->fi_sgt[i].extension = 0;
|
||||
fi->fi_sgt[i].final = 0;
|
||||
fi->fi_sgt[i].bpid = 0;
|
||||
fi->fi_sgt[i].offset = 0;
|
||||
|
||||
dsize -= ssize;
|
||||
vaddr += ssize;
|
||||
psize += ssize;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (dsize > 0)
|
||||
break;
|
||||
|
||||
m = m->m_next;
|
||||
}
|
||||
|
||||
/* Check if SG table was constructed properly */
|
||||
if (m != NULL || dsize != 0) {
|
||||
dpaa_eth_fi_free(sc, fi);
|
||||
m_freem(m0);
|
||||
continue;
|
||||
}
|
||||
|
||||
fi->fi_sgt[i - 1].final = 1;
|
||||
|
||||
fd.addr = pmap_kextract((vm_offset_t)fi->fi_sgt);
|
||||
fd.length = psize;
|
||||
fd.format = DPAA_FD_FORMAT_SHORT_MBSF;
|
||||
|
||||
fd.liodn = 0;
|
||||
fd.bpid = 0;
|
||||
fd.eliodn = 0;
|
||||
fd.offset = 0;
|
||||
fd.cmd_stat = 0;
|
||||
|
||||
DPAA_ETH_UNLOCK(sc);
|
||||
if (qman_fq_enqueue(sc->sc_tx_fq, &fd) != 0) {
|
||||
dpaa_eth_fi_free(sc, fi);
|
||||
m_freem(m0);
|
||||
}
|
||||
DPAA_ETH_LOCK(sc);
|
||||
}
|
||||
}
|
||||
/** @} */
|
||||
@@ -0,0 +1,116 @@
|
||||
/*-
|
||||
* Copyright (c) 2012 Semihalf.
|
||||
* 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 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 DPAA_ETH_H_
|
||||
#define DPAA_ETH_H_
|
||||
|
||||
struct dpaa_eth_softc {
|
||||
/* XXX MII bus requires that struct ifnet is first!!! */
|
||||
if_t sc_ifnet;
|
||||
|
||||
device_t sc_dev;
|
||||
struct resource *sc_mem;
|
||||
struct mtx sc_lock;
|
||||
|
||||
int sc_mac_enet_mode;
|
||||
|
||||
/* RX Pool */
|
||||
struct bman_pool *sc_rx_pool;
|
||||
uint8_t sc_rx_bpid;
|
||||
uma_zone_t sc_rx_zone;
|
||||
char sc_rx_zname[64];
|
||||
|
||||
/* RX Frame Queue */
|
||||
struct qman_fq *sc_rx_fq;
|
||||
uint32_t sc_rx_fqid;
|
||||
|
||||
/* TX Frame Queue */
|
||||
struct qman_fq *sc_tx_fq;
|
||||
bool sc_tx_fq_full;
|
||||
struct qman_fq *sc_tx_conf_fq;
|
||||
uint32_t sc_tx_conf_fqid;
|
||||
|
||||
/* Methods */
|
||||
int (*sc_port_rx_init)
|
||||
(struct dpaa_eth_softc *sc, int unit);
|
||||
int (*sc_port_tx_init)
|
||||
(struct dpaa_eth_softc *sc, int unit);
|
||||
void (*sc_start_locked)
|
||||
(struct dpaa_eth_softc *sc);
|
||||
|
||||
/* dTSEC data */
|
||||
uint8_t sc_eth_id; /* Ethernet ID within its frame manager */
|
||||
uintptr_t sc_mac_mem_offset;
|
||||
int sc_mac_mdio_irq;
|
||||
uint8_t sc_mac_addr[6];
|
||||
int sc_port_rx_hw_id;
|
||||
int sc_port_tx_hw_id;
|
||||
uint32_t sc_port_tx_qman_chan;
|
||||
int sc_phy_addr;
|
||||
bool sc_hidden;
|
||||
device_t sc_mdio;
|
||||
int sc_rev_major;
|
||||
int sc_rev_minor;
|
||||
|
||||
device_t sc_rx_port;
|
||||
device_t sc_tx_port;
|
||||
|
||||
int sc_rx_channel;
|
||||
|
||||
/* MII data */
|
||||
struct mii_data *sc_mii;
|
||||
device_t sc_mii_dev;
|
||||
struct mtx sc_mii_lock;
|
||||
|
||||
struct callout sc_tick_callout;
|
||||
|
||||
/* Frame Info Zone */
|
||||
uma_zone_t sc_fi_zone;
|
||||
char sc_fi_zname[64];
|
||||
};
|
||||
|
||||
/**
|
||||
* @group dTSEC Regular Mode API.
|
||||
* @{
|
||||
*/
|
||||
int dpaa_eth_fm_port_rx_init(struct dpaa_eth_softc *sc);
|
||||
int dpaa_eth_fm_port_tx_init(struct dpaa_eth_softc *sc);
|
||||
|
||||
void dpaa_eth_if_start_locked(struct dpaa_eth_softc *sc);
|
||||
|
||||
int dpaa_eth_pool_rx_init(struct dpaa_eth_softc *sc);
|
||||
void dpaa_eth_pool_rx_free(struct dpaa_eth_softc *sc);
|
||||
|
||||
int dpaa_eth_fi_pool_init(struct dpaa_eth_softc *sc);
|
||||
void dpaa_eth_fi_pool_free(struct dpaa_eth_softc *sc);
|
||||
|
||||
int dpaa_eth_fq_rx_init(struct dpaa_eth_softc *sc);
|
||||
int dpaa_eth_fq_tx_init(struct dpaa_eth_softc *sc);
|
||||
void dpaa_eth_fq_rx_free(struct dpaa_eth_softc *sc);
|
||||
void dpaa_eth_fq_tx_free(struct dpaa_eth_softc *sc);
|
||||
/** @} */
|
||||
|
||||
#endif /* DPAA_ETH_H_ */
|
||||
+642
-238
File diff suppressed because it is too large
Load Diff
+67
-6
@@ -28,6 +28,23 @@
|
||||
#define FMAN_H_
|
||||
|
||||
#include <dev/fdt/simplebus.h>
|
||||
#include <sys/vmem.h>
|
||||
|
||||
#define FMAN_BMI_FIFO_UNITS 0x100
|
||||
#define FMAN_BMI_FIFO_ALIGN 0x100
|
||||
|
||||
#define FM_FD_ERR_DMA 0x01000000
|
||||
#define FM_FD_ERR_FPE 0x00080000
|
||||
#define FM_FD_ERR_FSE 0x00040000
|
||||
#define FM_FD_ERR_DIS 0x00020000
|
||||
#define FM_FD_ERR_EOF 0x00008000
|
||||
#define FM_FD_ERR_NSS 0x00004000
|
||||
#define FM_FD_ERR_KSO 0x00002000
|
||||
#define FM_FD_ERR_IPP 0x00000200
|
||||
#define FM_FD_ERR_PTE 0x00000080
|
||||
#define FM_FD_ERR_ISP 0x00000040
|
||||
#define FM_FD_ERR_PHE 0x00000020
|
||||
#define FM_FD_ERR_BLE 0x00000008
|
||||
|
||||
/**
|
||||
* FMan driver instance data.
|
||||
@@ -38,22 +55,61 @@ struct fman_softc {
|
||||
struct resource *irq_res;
|
||||
struct resource *err_irq_res;
|
||||
struct rman rman;
|
||||
vmem_t *muram_vmem;
|
||||
int mem_rid;
|
||||
int irq_rid;
|
||||
int err_irq_rid;
|
||||
void *irq_cookie;
|
||||
int qman_chan_base;
|
||||
int qman_chan_count;
|
||||
int fm_id;
|
||||
|
||||
t_Handle fm_handle;
|
||||
t_Handle muram_handle;
|
||||
int sc_revision_major;
|
||||
int sc_revision_minor;
|
||||
|
||||
uint16_t clock;
|
||||
bool timestamps;
|
||||
|
||||
uint32_t iram_size;
|
||||
uint32_t dma_thresh_max_commq;
|
||||
uint32_t dma_thresh_max_buf;
|
||||
uint32_t dma_cam_num_entries;
|
||||
uint32_t max_open_dmas;
|
||||
|
||||
uint32_t qmi_max_tnums;
|
||||
uint32_t qmi_def_tnums_thresh;
|
||||
|
||||
uint32_t bmi_max_tasks;
|
||||
uint32_t bmi_max_fifo_size;
|
||||
uint32_t bmi_fifo_base;
|
||||
|
||||
uint32_t port_cgs;
|
||||
uint32_t rx_ports;
|
||||
uint32_t total_fifo_size;
|
||||
|
||||
uint32_t qman_channel_base;
|
||||
uint32_t qman_channels;
|
||||
};
|
||||
|
||||
struct fman_port_init_params {
|
||||
int port_id;
|
||||
bool is_rx_port;
|
||||
uint8_t num_tasks;
|
||||
uint8_t extra_tasks;
|
||||
uint8_t open_dmas;
|
||||
uint8_t extra_dmas;
|
||||
uint32_t fifo_size;
|
||||
uint32_t extra_fifo_size;
|
||||
uint8_t deq_pipeline_size;
|
||||
uint16_t max_frame_length;
|
||||
uint16_t liodn;
|
||||
};
|
||||
|
||||
/**
|
||||
* @group QMan bus interface.
|
||||
* @group FMan bus interface.
|
||||
* @{
|
||||
*/
|
||||
struct resource * fman_alloc_resource(device_t bus, device_t child, int type,
|
||||
struct resource *fman_alloc_resource(device_t bus, device_t child, int type,
|
||||
int rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags);
|
||||
int fman_activate_resource(device_t bus, device_t child,
|
||||
struct resource *res);
|
||||
@@ -66,11 +122,16 @@ int fman_shutdown(device_t dev);
|
||||
int fman_read_ivar(device_t dev, device_t child, int index,
|
||||
uintptr_t *result);
|
||||
int fman_qman_channel_id(device_t, int);
|
||||
void fman_get_revision(device_t, int *, int *);
|
||||
/** @} */
|
||||
|
||||
uint32_t fman_get_clock(struct fman_softc *sc);
|
||||
int fman_get_handle(device_t dev, t_Handle *fmh);
|
||||
int fman_get_muram_handle(device_t dev, t_Handle *muramh);
|
||||
int fman_get_bushandle(device_t dev, vm_offset_t *fm_base);
|
||||
size_t fman_get_bmi_max_fifo_size(device_t);
|
||||
int fman_reset_mac(device_t, int);
|
||||
int fman_set_port_params(device_t dev, struct fman_port_init_params *params);
|
||||
int fman_qman_channel_id(device_t, int);
|
||||
int fman_set_mac_intr_handler(device_t, int, driver_intr_t, void *);
|
||||
int fman_set_mac_err_handler(device_t, int, driver_intr_t, void *);
|
||||
|
||||
#endif /* FMAN_H_ */
|
||||
|
||||
@@ -34,10 +34,8 @@
|
||||
#include <dev/ofw/ofw_bus.h>
|
||||
#include <dev/ofw/ofw_bus_subr.h>
|
||||
|
||||
#include <contrib/ncsw/inc/ncsw_ext.h>
|
||||
#include <contrib/ncsw/inc/enet_ext.h>
|
||||
|
||||
#include "fman.h"
|
||||
#include "fman_if.h"
|
||||
|
||||
#define FFMAN_DEVSTR "Freescale Frame Manager"
|
||||
|
||||
@@ -56,6 +54,12 @@ static device_method_t fman_methods[] = {
|
||||
DEVMETHOD(bus_alloc_resource, fman_alloc_resource),
|
||||
DEVMETHOD(bus_activate_resource, fman_activate_resource),
|
||||
DEVMETHOD(bus_release_resource, fman_release_resource),
|
||||
|
||||
DEVMETHOD(fman_get_revision, fman_get_revision),
|
||||
DEVMETHOD(fman_reset_mac, fman_reset_mac),
|
||||
DEVMETHOD(fman_set_port_params, fman_set_port_params),
|
||||
DEVMETHOD(fman_get_qman_channel_id, fman_qman_channel_id),
|
||||
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
||||
@@ -92,8 +96,8 @@ fman_get_clock(struct fman_softc *sc)
|
||||
|
||||
if ((OF_getprop(node, "clock-frequency", &fman_clock,
|
||||
sizeof(fman_clock)) <= 0) || (fman_clock == 0)) {
|
||||
device_printf(dev, "could not acquire correct frequency "
|
||||
"from DTS\n");
|
||||
device_printf(dev,
|
||||
"could not acquire correct frequency from DTS\n");
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
#-
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
#
|
||||
# Copyright (c) 2026 Justin Hibbits
|
||||
|
||||
#include <machine/bus.h>
|
||||
#include <dev/dpaa/fman.h>
|
||||
|
||||
/**
|
||||
* @brief DPAA FMan interface
|
||||
*
|
||||
*/
|
||||
INTERFACE fman;
|
||||
|
||||
METHOD void get_revision {
|
||||
device_t dev;
|
||||
int *major;
|
||||
int *minor;
|
||||
};
|
||||
|
||||
METHOD size_t get_bmi_max_fifo_size {
|
||||
device_t dev;
|
||||
};
|
||||
|
||||
METHOD int get_qman_channel_id {
|
||||
device_t dev;
|
||||
int port_id;
|
||||
};
|
||||
|
||||
METHOD int reset_mac {
|
||||
device_t dev;
|
||||
int mac_id;
|
||||
};
|
||||
|
||||
METHOD int set_port_params {
|
||||
device_t dev;
|
||||
struct fman_port_init_params *params;
|
||||
};
|
||||
@@ -46,17 +46,15 @@
|
||||
#include <dev/ofw/ofw_bus.h>
|
||||
#include <dev/ofw/ofw_bus_subr.h>
|
||||
|
||||
#include <contrib/ncsw/inc/Peripherals/fm_ext.h>
|
||||
|
||||
#include "fman.h"
|
||||
#include "miibus_if.h"
|
||||
|
||||
#define MDIO_LOCK() mtx_lock(&sc->sc_lock)
|
||||
#define MDIO_UNLOCK() mtx_unlock(&sc->sc_lock)
|
||||
#define MDIO_WRITE4(sc,r,v) \
|
||||
bus_space_write_4(&bs_be_tag, sc->sc_handle, sc->sc_offset + r, v)
|
||||
#define MDIO_WRITE4(sc, r, v) \
|
||||
bus_write_4(sc->sc_res, r, v)
|
||||
#define MDIO_READ4(sc, r) \
|
||||
bus_space_read_4(&bs_be_tag, sc->sc_handle, sc->sc_offset + r)
|
||||
bus_read_4(sc->sc_res, r)
|
||||
|
||||
#define MDIO_MIIMCFG 0x0
|
||||
#define MDIO_MIIMCOM 0x4
|
||||
@@ -76,8 +74,7 @@ static int pqmdio_miibus_writereg(device_t dev, int phy, int reg, int value);
|
||||
|
||||
struct pqmdio_softc {
|
||||
struct mtx sc_lock;
|
||||
bus_space_handle_t sc_handle;
|
||||
int sc_offset;
|
||||
struct resource *sc_res;
|
||||
};
|
||||
|
||||
static device_method_t pqmdio_methods[] = {
|
||||
@@ -123,13 +120,10 @@ static int
|
||||
pqmdio_fdt_attach(device_t dev)
|
||||
{
|
||||
struct pqmdio_softc *sc;
|
||||
rman_res_t start, count;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
fman_get_bushandle(device_get_parent(dev), &sc->sc_handle);
|
||||
bus_get_resource(dev, SYS_RES_MEMORY, 0, &start, &count);
|
||||
sc->sc_offset = start;
|
||||
sc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 0, RF_ACTIVE);
|
||||
|
||||
OF_device_register_xref(OF_xref_from_node(ofw_bus_get_node(dev)), dev);
|
||||
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2026 Justin Hibbits
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/rman.h>
|
||||
#include <sys/malloc.h>
|
||||
|
||||
#include <dev/ofw/ofw_bus.h>
|
||||
#include <dev/ofw/ofw_bus_subr.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
|
||||
#include "opt_platform.h"
|
||||
|
||||
#include <powerpc/mpc85xx/mpc85xx.h>
|
||||
|
||||
#include "fman.h"
|
||||
|
||||
struct fman_muram_softc {
|
||||
struct resource *sc_mem;
|
||||
vmem_t sc_vmem;
|
||||
};
|
||||
|
||||
static int
|
||||
fman_muram_probe(device_t dev)
|
||||
{
|
||||
if (!ofw_bus_is_compatible(dev, "fsl,fman-muram"))
|
||||
return (ENXIO);
|
||||
|
||||
device_set_desc(dev, "FMan MURAM");
|
||||
|
||||
return (BUS_PROBE_DEFAULT);
|
||||
}
|
||||
|
||||
static int
|
||||
fman_muram_attach(device_t dev)
|
||||
{
|
||||
struct fman_muram_softc *sc = device_get_softc(dev);
|
||||
|
||||
sc->sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 0,
|
||||
RF_ACTIVE | RF_SHAREABLE);
|
||||
|
||||
if (sc->sc_mem == NULL) {
|
||||
device_printf(dev, "cannot allocate memory\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
sc->sc_vmem = vmem_create("MURAM", rman_get_bushandle(sc->sc_mem),
|
||||
rman_get_size(sc->sc_mem),
|
||||
}
|
||||
|
||||
static device_method_t muram_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, fman_muram_probe),
|
||||
DEVMETHOD(device_attach, fman_muram_attach),
|
||||
DEVMETHOD(device_detach, fman_muram_detach),
|
||||
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
||||
DEFINE_CLASS_0(fman_muram, fman_muram_driver, muram_methods,
|
||||
sizeof(struct fman_muram_softc));
|
||||
EARLY_DRIVER_MODULE(fman_muram, fman, fman_muram_driver, 0, 0,
|
||||
BUS_PASS_SUPPORTDEV);
|
||||
@@ -0,0 +1,680 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2026 Justin Hibbits
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/module.h>
|
||||
#include <dev/ofw/ofw_bus_subr.h>
|
||||
#include <machine/bus.h>
|
||||
#include "fman.h"
|
||||
#include "fman_port.h"
|
||||
#include "fman_if.h"
|
||||
#include "fman_port_if.h"
|
||||
|
||||
struct fman_port_rsrc {
|
||||
uint32_t num;
|
||||
uint32_t extra;
|
||||
};
|
||||
|
||||
#define MAX_BM_POOLS 64
|
||||
struct fman_port_softc {
|
||||
device_t sc_dev;
|
||||
struct resource *sc_mem;
|
||||
int sc_port_id;
|
||||
int sc_port_speed;
|
||||
int sc_port_type;
|
||||
|
||||
int sc_revision_major;
|
||||
int sc_revision_minor;
|
||||
|
||||
int sc_max_frame_length;
|
||||
int sc_bm_max_pools;
|
||||
int sc_max_port_fifo_size;
|
||||
int sc_qman_channel_id;
|
||||
|
||||
int sc_deq_byte_count;
|
||||
int sc_deq_high_priority;
|
||||
int sc_tx_deq_pipeline_depth;
|
||||
|
||||
int sc_default_fqid;
|
||||
int sc_err_fqid;
|
||||
int pcd_base_fqid;
|
||||
int pcd_fqs_count;
|
||||
|
||||
int sc_max_ext_portals;
|
||||
int sc_max_sub_portals;
|
||||
|
||||
struct fman_port_rsrc sc_open_dmas;
|
||||
struct fman_port_rsrc sc_tasks;
|
||||
struct fman_port_rsrc sc_fifo_bufs;
|
||||
|
||||
struct fman_port_buffer_pool sc_bpools[FMAN_PORT_MAX_POOLS];
|
||||
};
|
||||
|
||||
#define TX_10G_PORT_BASE 0x30
|
||||
#define RX_10G_PORT_BASE 0x10
|
||||
|
||||
#define FMAN_PORT_TYPE_TX 0
|
||||
#define FMAN_PORT_TYPE_RX 1
|
||||
|
||||
#define PORT_RX 0x01
|
||||
#define PORT_TX 0x02
|
||||
#define PORT_V3 0x04
|
||||
|
||||
#define FMBM_RCFG 0x000
|
||||
#define BMI_PORT_CFG_EN 0x80000000
|
||||
#define FMBM_RST 0x004
|
||||
#define FMBM_RDA 0x008
|
||||
#define RDA_WOPT 0x00100000
|
||||
#define FMBM_RFP 0x00c
|
||||
#define FMBM_RFED 0x010
|
||||
#define BMI_RX_FRAME_END_CUT_SHIFT 16
|
||||
#define FMBM_RICP 0x014
|
||||
#define FMBM_RIM 0x018
|
||||
#define FMBM_REBM 0x01c
|
||||
#define FMBM_RFNE 0x020
|
||||
#define FMBM_RFCA 0x024
|
||||
#define RFCA_OR 0x80000000
|
||||
#define RFCA_COLOR 0x0c000000
|
||||
#define RFCA_SYNC 0x03000000
|
||||
#define RFCA_SYNC_REQ 0x02000000
|
||||
#define RFCA_MR 0x003f0000
|
||||
#define RFCA_MR_DEF 0x003c0000
|
||||
#define FMBM_RFPNE 0x028
|
||||
#define FMBM_RETH 0x038
|
||||
#define RETH_ETHE 0x80000000 /* Excessive Threshold Enable */
|
||||
#define FMBM_RFQID 0x060
|
||||
#define FMBM_REFQID 0x064
|
||||
#define FMBM_RFSDM 0x068
|
||||
#define FMBM_RFSEM 0x06c
|
||||
#define FMBM_RFENE 0x070
|
||||
#define FMBM_REBMPI(i) (0x100 + (4 * (i)))
|
||||
#define REBMPI_VAL 0x80000000
|
||||
#define REBMPI_ACE 0x40000000
|
||||
#define REBMPI_BPID_S 16
|
||||
#define FMBM_RSTC 0x0200
|
||||
#define RSTC_EN 0x80000000
|
||||
|
||||
#define FMBM_TCFG 0x000
|
||||
#define FMBM_TST 0x004
|
||||
#define FMBM_TDA 0x008
|
||||
#define FMBM_TFP 0x00c
|
||||
#define BMI_FIFO_PIPELINE_DEPTH_SHIFT 12
|
||||
#define FMBM_TFED 0x010
|
||||
#define FMBM_TFDNE 0x018
|
||||
#define FMBM_TFCA 0x01c
|
||||
#define TFCA_MR_DEF 0
|
||||
#define TFCA_ATTR_ORDER 0x80000000
|
||||
#define FMBM_TCFQID 0x020
|
||||
#define FMBM_TEFQID 0x024
|
||||
#define FMBM_TFENE 0x028
|
||||
#define FMBM_TFNE 0x070
|
||||
#define TFNE_EBD 0x80000000
|
||||
|
||||
#define FMQM_PNC 0x400
|
||||
#define PNC_EN 0x80000000
|
||||
#define PNC_STEN 0x80000000
|
||||
#define FMQM_PNS 0x404
|
||||
#define PNS_DEQ_FD_BSY 0x20000000
|
||||
#define FMQM_PNEN 0x41c
|
||||
#define FMQM_PNDN 0x42c
|
||||
#define FMQM_PNDC 0x430
|
||||
#define QMI_DEQ_CFG_PRI 0x80000000
|
||||
#define QMI_DEQ_CFG_TYPE1 0x10000000
|
||||
#define QMI_DEQ_CFG_TYPE2 0x20000000
|
||||
#define QMI_DEQ_CFG_TYPE3 0x30000000
|
||||
#define QMI_DEQ_CFG_PREFETCH_PARTIAL 0x01000000
|
||||
#define QMI_DEQ_CFG_PREFETCH_FULL 0x03000000
|
||||
#define QMI_DEQ_CFG_SP_MASK 0xf
|
||||
#define QMI_DEQ_CFG_SP_SHIFT 20
|
||||
|
||||
#define HWP_PCAC 0xbf8
|
||||
#define HWP_PCAC_PSTOP 0x00000001
|
||||
#define HWP_HXS_PCAC_PSTAT 0x00000100
|
||||
#define HWP_HXS_SSA(x) (0x800 + x * 2 * sizeof(uint32_t))
|
||||
#define HWP_HXS_LCV(x) (0x800 + (x * 2 + 1) * sizeof(uint32_t))
|
||||
#define HWP_HXS_TCP 0xA
|
||||
#define HWP_HXS_UDP 0xB
|
||||
#define HXS_SH_PAD_REM 0x80000000
|
||||
#define HWP_HXS_COUNT 16
|
||||
|
||||
#define PORT_MAX_FRAME_LENGTH 9600
|
||||
|
||||
#define NIA_ORDER_RESTORE 0x00800000
|
||||
#define NIA_ENG_BMI 0x00500000
|
||||
#define NIA_ENG_QMI_DEQ 0x00580000
|
||||
#define NIA_ENG_QMI_ENQ 0x00540000
|
||||
#define NIA_ENG_HWP 0x00440000
|
||||
#define NIA_ENG_HWK 0x00480000
|
||||
#define NIA_BMI_AC_TX_RELEASE 0x000002c0
|
||||
#define NIA_BMI_AC_TX 0x00000274
|
||||
#define NIA_BMI_AC_RELEASE 0x000000c0
|
||||
#define NIA_BMI_AC_ENQ_FRAME 0x00000002
|
||||
#define NIA_BMI_AC_FETCH_ALLFRAME 0x0000020c
|
||||
|
||||
#define BMI_RX_ERR (FM_FD_ERR_DMA | FM_FD_ERR_FPE | \
|
||||
FM_FD_ERR_FSE | FM_FD_ERR_DIS | \
|
||||
FM_FD_ERR_EOF | FM_FD_ERR_NSS | \
|
||||
FM_FD_ERR_KSO | FM_FD_ERR_IPP | \
|
||||
FM_FD_ERR_PTE | FM_FD_ERR_PHE | \
|
||||
FM_FD_ERR_BLE)
|
||||
|
||||
/* Default configurations */
|
||||
#define DEFAULT_RX_CUT_END_BYTES 4
|
||||
|
||||
static struct ofw_compat_data compats[] = {
|
||||
{ "fsl,fman-v2-port-rx", PORT_RX },
|
||||
{ "fsl,fman-v2-port-tx", PORT_TX },
|
||||
{ "fsl,fman-v3-port-rx", PORT_V3 | PORT_RX },
|
||||
{ "fsl,fman-v3-port-tx", PORT_V3 | PORT_TX },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
static int
|
||||
fman_port_probe(device_t dev)
|
||||
{
|
||||
if (ofw_bus_search_compatible(dev, compats)->ocd_str == NULL)
|
||||
return (ENXIO);
|
||||
|
||||
device_set_desc(dev, "FMan port");
|
||||
|
||||
return (BUS_PROBE_DEFAULT);
|
||||
}
|
||||
|
||||
static int
|
||||
fman_port_attach(device_t dev)
|
||||
{
|
||||
struct fman_port_softc *sc;
|
||||
phandle_t node;
|
||||
pcell_t cell;
|
||||
uintptr_t compat_data =
|
||||
ofw_bus_search_compatible(dev, compats)->ocd_data;
|
||||
int port_speed = 1000;
|
||||
int port_type;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
sc->sc_dev = dev;
|
||||
|
||||
node = ofw_bus_get_node(dev);
|
||||
if (OF_getencprop(node, "cell-index", &cell, sizeof(cell)) < 0) {
|
||||
device_printf(dev, "No cell-index property");
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
sc->sc_port_id = cell;
|
||||
|
||||
sc->sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 0,
|
||||
RF_ACTIVE | RF_SHAREABLE);
|
||||
|
||||
if (sc->sc_mem == NULL) {
|
||||
device_printf(dev, "failed to allocate MMIO");
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
FMAN_GET_REVISION(device_get_parent(dev),
|
||||
&sc->sc_revision_major, &sc->sc_revision_minor);
|
||||
|
||||
if ((compat_data & PORT_TX) == PORT_TX)
|
||||
port_type = FMAN_PORT_TYPE_TX;
|
||||
else
|
||||
port_type = FMAN_PORT_TYPE_RX;
|
||||
|
||||
if ((compat_data & PORT_V3) == PORT_V3) {
|
||||
if (OF_hasprop(node, "fsl,fman-10g-port"))
|
||||
port_speed = 10000;
|
||||
} else {
|
||||
if ((compat_data & PORT_TX) &&
|
||||
sc->sc_port_id > TX_10G_PORT_BASE)
|
||||
port_speed = 10000;
|
||||
else if ((compat_data & PORT_RX) &&
|
||||
sc->sc_port_id > RX_10G_PORT_BASE)
|
||||
port_speed = 10000;
|
||||
}
|
||||
|
||||
if (sc->sc_port_speed == 10000) {
|
||||
sc->sc_deq_high_priority = true;
|
||||
sc->sc_deq_byte_count = 0x1400;
|
||||
} else {
|
||||
sc->sc_deq_high_priority = false;
|
||||
sc->sc_deq_byte_count = 0x0400;
|
||||
}
|
||||
|
||||
sc->sc_port_type = port_type;
|
||||
sc->sc_port_speed = port_speed;
|
||||
|
||||
sc->sc_bm_max_pools = MAX_BM_POOLS;
|
||||
sc->sc_max_frame_length = PORT_MAX_FRAME_LENGTH;
|
||||
|
||||
if (port_type == FMAN_PORT_TYPE_TX)
|
||||
sc->sc_qman_channel_id =
|
||||
FMAN_GET_QMAN_CHANNEL_ID(device_get_parent(dev),
|
||||
sc->sc_port_id);
|
||||
|
||||
OF_device_register_xref(OF_xref_from_node(ofw_bus_get_node(dev)), dev);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
fman_port_detach(device_t dev)
|
||||
{
|
||||
struct fman_port_softc *sc = device_get_softc(dev);
|
||||
|
||||
if (sc->sc_mem != NULL)
|
||||
bus_release_resource(dev, sc->sc_mem);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
fman_port_config(device_t dev, struct fman_port_params *params)
|
||||
{
|
||||
struct fman_port_softc *sc = device_get_softc(dev);
|
||||
|
||||
sc->sc_default_fqid = params->dflt_fqid;
|
||||
sc->sc_err_fqid = params->err_fqid;
|
||||
|
||||
sc->sc_max_port_fifo_size =
|
||||
FMAN_GET_BMI_MAX_FIFO_SIZE(device_get_parent(dev));
|
||||
switch (sc->sc_revision_major) {
|
||||
case 2:
|
||||
case 3:
|
||||
sc->sc_max_ext_portals = 4;
|
||||
sc->sc_max_sub_portals = 12;
|
||||
break;
|
||||
case 6:
|
||||
sc->sc_max_ext_portals = 8;
|
||||
sc->sc_max_sub_portals = 16;
|
||||
break;
|
||||
}
|
||||
if (sc->sc_revision_major >= 6 &&
|
||||
sc->sc_port_type == FMAN_PORT_TYPE_TX && sc->sc_port_speed == 1000)
|
||||
/* Errata A005127 workaround */
|
||||
bus_write_4(sc->sc_mem, FMBM_TFP, 0x00001013);
|
||||
|
||||
sc->sc_tasks.extra = 0;
|
||||
|
||||
switch (sc->sc_port_speed) {
|
||||
case 10000:
|
||||
if (sc->sc_revision_major < 6) {
|
||||
sc->sc_tasks.num = 16;
|
||||
if (sc->sc_port_type == FMAN_PORT_TYPE_RX)
|
||||
sc->sc_tasks.extra = 8;
|
||||
} else
|
||||
sc->sc_tasks.num = 14;
|
||||
break;
|
||||
case 1000:
|
||||
if (sc->sc_revision_major >= 6)
|
||||
sc->sc_tasks.num = 4;
|
||||
else {
|
||||
sc->sc_tasks.num = 3;
|
||||
if (sc->sc_port_type == FMAN_PORT_TYPE_RX)
|
||||
sc->sc_tasks.extra = 2;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
sc->sc_tasks.num = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Open DMAs */
|
||||
if (sc->sc_revision_major >= 6) {
|
||||
sc->sc_open_dmas.extra = 0;
|
||||
if (sc->sc_port_speed == 10000) {
|
||||
if (sc->sc_port_type == FMAN_PORT_TYPE_TX)
|
||||
sc->sc_open_dmas.num = 12;
|
||||
else
|
||||
sc->sc_open_dmas.num = 8;
|
||||
} else {
|
||||
if (sc->sc_port_type == FMAN_PORT_TYPE_TX)
|
||||
sc->sc_open_dmas.num = 3;
|
||||
else
|
||||
sc->sc_open_dmas.num = 2;
|
||||
}
|
||||
} else {
|
||||
if (sc->sc_port_speed == 10000) {
|
||||
sc->sc_open_dmas.num = 8;
|
||||
sc->sc_open_dmas.num = 8;
|
||||
} else {
|
||||
sc->sc_open_dmas.num = 1;
|
||||
sc->sc_open_dmas.extra = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* FIFO bufs */
|
||||
if (sc->sc_revision_major >= 6) {
|
||||
if (sc->sc_port_type == FMAN_PORT_TYPE_TX)
|
||||
if (sc->sc_port_speed == 10000)
|
||||
sc->sc_fifo_bufs.num = 64;
|
||||
else
|
||||
sc->sc_fifo_bufs.num = 50;
|
||||
else
|
||||
if (sc->sc_port_speed == 10000)
|
||||
sc->sc_fifo_bufs.num = 96;
|
||||
else
|
||||
sc->sc_fifo_bufs.num = 50;
|
||||
} else {
|
||||
if (sc->sc_port_type == FMAN_PORT_TYPE_TX)
|
||||
if (sc->sc_port_speed == 10000)
|
||||
sc->sc_fifo_bufs.num = 48;
|
||||
else
|
||||
sc->sc_fifo_bufs.num = 44;
|
||||
else
|
||||
if (sc->sc_port_speed == 10000)
|
||||
sc->sc_fifo_bufs.num = 48;
|
||||
else
|
||||
sc->sc_fifo_bufs.num = 45;
|
||||
}
|
||||
|
||||
sc->sc_fifo_bufs.extra = 0;
|
||||
sc->sc_fifo_bufs.num *= FMAN_BMI_FIFO_UNITS;
|
||||
|
||||
if (sc->sc_port_type == FMAN_PORT_TYPE_RX)
|
||||
for (int i = 0; i < params->rx_params.num_pools; i++)
|
||||
sc->sc_bpools[i] = params->rx_params.bpools[i];
|
||||
|
||||
/* TODO: buf_margins? See fman_sp_build_buffer_struct */
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
fman_port_init_bmi_rx(struct fman_port_softc *sc)
|
||||
{
|
||||
|
||||
/* TODO: Sort the buffer pool list. */
|
||||
/* TODO: Backup pools */
|
||||
/* TODO: Depletion mode */
|
||||
for (int i = 0; i < FMAN_PORT_MAX_POOLS; i++) {
|
||||
/* Initialize the external pool info */
|
||||
if (sc->sc_bpools[i].size != 0) {
|
||||
bus_write_4(sc->sc_mem, FMBM_REBMPI(i),
|
||||
REBMPI_VAL | REBMPI_ACE |
|
||||
(sc->sc_bpools[i].bpid << REBMPI_BPID_S) |
|
||||
sc->sc_bpools[i].size);
|
||||
} else
|
||||
/* Mark invalid if zero */
|
||||
bus_write_4(sc->sc_mem, FMBM_REBMPI(i), 0);
|
||||
}
|
||||
|
||||
bus_write_4(sc->sc_mem, FMBM_RDA, RDA_WOPT);
|
||||
|
||||
bus_write_4(sc->sc_mem, FMBM_RFCA,
|
||||
RFCA_OR | RFCA_SYNC_REQ | RFCA_MR_DEF);
|
||||
|
||||
bus_write_4(sc->sc_mem, FMBM_RFPNE,
|
||||
NIA_ENG_HWK);
|
||||
bus_write_4(sc->sc_mem, FMBM_RFENE,
|
||||
NIA_ENG_QMI_ENQ | NIA_ORDER_RESTORE);
|
||||
|
||||
bus_write_4(sc->sc_mem, FMBM_RFQID, sc->sc_default_fqid);
|
||||
bus_write_4(sc->sc_mem, FMBM_REFQID, sc->sc_err_fqid);
|
||||
|
||||
if (sc->sc_revision_major < 6)
|
||||
bus_write_4(sc->sc_mem, FMBM_RETH, RETH_ETHE);
|
||||
|
||||
/* Errata A006320 makes CFED field bad */
|
||||
if (sc->sc_revision_major == 6 && (sc->sc_revision_minor == 0))
|
||||
/* These are under errata A006320 */;
|
||||
else
|
||||
bus_write_4(sc->sc_mem, FMBM_RFED,
|
||||
DEFAULT_RX_CUT_END_BYTES << BMI_RX_FRAME_END_CUT_SHIFT);
|
||||
|
||||
/* No internal context */
|
||||
bus_write_4(sc->sc_mem, FMBM_RICP, 0);
|
||||
|
||||
/* TODO: Enable HW Parser. */
|
||||
bus_write_4(sc->sc_mem, FMBM_RFNE, NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME);
|
||||
bus_write_4(sc->sc_mem, FMBM_RFSDM, FM_FD_ERR_DIS);
|
||||
bus_write_4(sc->sc_mem, FMBM_RFSEM, BMI_RX_ERR & ~FM_FD_ERR_DIS);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
fman_port_init_bmi_tx(struct fman_port_softc *sc)
|
||||
{
|
||||
uint32_t reg;
|
||||
int depth;
|
||||
|
||||
bus_write_4(sc->sc_mem, FMBM_TCFG, 0);
|
||||
bus_write_4(sc->sc_mem, FMBM_TDA, 0);
|
||||
bus_write_4(sc->sc_mem, FMBM_TFED, 0);
|
||||
if (sc->sc_port_speed == 10000)
|
||||
depth = 4;
|
||||
else if (sc->sc_revision_major >= 6)
|
||||
depth = 2;
|
||||
else
|
||||
depth = 1;
|
||||
sc->sc_tx_deq_pipeline_depth = depth;
|
||||
reg = ((depth - 1) << BMI_FIFO_PIPELINE_DEPTH_SHIFT) | 0x13;
|
||||
bus_write_4(sc->sc_mem, FMBM_TFP, reg);
|
||||
|
||||
/* Default color: green */
|
||||
bus_write_4(sc->sc_mem, FMBM_TFCA,
|
||||
TFCA_MR_DEF | TFCA_ATTR_ORDER);
|
||||
|
||||
bus_write_4(sc->sc_mem, FMBM_TFDNE, NIA_ENG_QMI_DEQ);
|
||||
bus_write_4(sc->sc_mem, FMBM_TFENE,
|
||||
NIA_ENG_QMI_ENQ | NIA_ORDER_RESTORE);
|
||||
|
||||
if (sc->sc_revision_major >= 6)
|
||||
bus_write_4(sc->sc_mem, FMBM_TFNE,
|
||||
(sc->sc_default_fqid == 0 ? TFNE_EBD : 0) |
|
||||
NIA_BMI_AC_FETCH_ALLFRAME);
|
||||
bus_write_4(sc->sc_mem, FMBM_TCFQID, sc->sc_default_fqid);
|
||||
bus_write_4(sc->sc_mem, FMBM_TEFQID, sc->sc_err_fqid);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
fman_port_init_hwp(struct fman_port_softc *sc)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* TODO: fman_port_init_hwp */
|
||||
bus_write_4(sc->sc_mem, HWP_PCAC, HWP_PCAC_PSTOP);
|
||||
|
||||
for (i = 0; i < 100 &&
|
||||
(bus_read_4(sc->sc_mem, HWP_PCAC) & HWP_HXS_PCAC_PSTAT) != 0; i++) {
|
||||
DELAY(10);
|
||||
}
|
||||
if (i == 100) {
|
||||
device_printf(sc->sc_dev, "Timeout stopping HW parser\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
/* set the parser examination config */
|
||||
for (i = 0; i < HWP_HXS_COUNT; i++) {
|
||||
bus_write_4(sc->sc_mem, HWP_HXS_SSA(i), 0);
|
||||
bus_write_4(sc->sc_mem, HWP_HXS_LCV(i), 0xffffffff);
|
||||
}
|
||||
bus_write_4(sc->sc_mem, HWP_HXS_SSA(HWP_HXS_TCP), HXS_SH_PAD_REM);
|
||||
bus_write_4(sc->sc_mem, HWP_HXS_SSA(HWP_HXS_UDP), HXS_SH_PAD_REM);
|
||||
|
||||
bus_write_4(sc->sc_mem, HWP_PCAC, 0);
|
||||
|
||||
for (i = 100; i > 0 &&
|
||||
(bus_read_4(sc->sc_mem, HWP_PCAC) & HWP_HXS_PCAC_PSTAT) == 0; i--) {
|
||||
DELAY(10);
|
||||
}
|
||||
if (i == 0) {
|
||||
device_printf(sc->sc_dev, "Timeout starting HW parser\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
fman_port_init_qmi(struct fman_port_softc *sc)
|
||||
{
|
||||
uint32_t reg;
|
||||
|
||||
if (sc->sc_port_type == FMAN_PORT_TYPE_RX) {
|
||||
bus_write_4(sc->sc_mem, FMQM_PNEN,
|
||||
NIA_ENG_BMI | NIA_BMI_AC_RELEASE);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* TX port */
|
||||
bus_write_4(sc->sc_mem, FMQM_PNDN,
|
||||
NIA_ENG_BMI | NIA_BMI_AC_TX);
|
||||
/* TX port */
|
||||
bus_write_4(sc->sc_mem, FMQM_PNEN,
|
||||
NIA_ENG_BMI | NIA_BMI_AC_TX_RELEASE);
|
||||
|
||||
reg = 0;
|
||||
|
||||
if (sc->sc_deq_high_priority)
|
||||
reg |= QMI_DEQ_CFG_PRI;
|
||||
|
||||
reg |= QMI_DEQ_CFG_TYPE1;
|
||||
reg |= QMI_DEQ_CFG_PREFETCH_FULL;
|
||||
reg |= (sc->sc_qman_channel_id & QMI_DEQ_CFG_SP_MASK) << QMI_DEQ_CFG_SP_SHIFT;
|
||||
reg |= sc->sc_deq_byte_count;
|
||||
bus_write_4(sc->sc_mem, FMQM_PNDC, reg);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
fman_port_init(device_t dev)
|
||||
{
|
||||
struct fman_port_init_params params;
|
||||
struct fman_port_softc *sc = device_get_softc(dev);
|
||||
int err;
|
||||
|
||||
if (sc->sc_port_type == FMAN_PORT_TYPE_RX) {
|
||||
/* Set up RX buffers and fifo */
|
||||
}
|
||||
params.port_id = sc->sc_port_id;
|
||||
params.is_rx_port = (sc->sc_port_type == FMAN_PORT_TYPE_RX);
|
||||
params.num_tasks = sc->sc_tasks.num;
|
||||
params.extra_tasks = sc->sc_tasks.extra;
|
||||
params.open_dmas = sc->sc_open_dmas.num;
|
||||
params.extra_dmas = sc->sc_open_dmas.extra;
|
||||
params.fifo_size = sc->sc_fifo_bufs.num;
|
||||
params.extra_fifo_size = sc->sc_fifo_bufs.extra;
|
||||
params.max_frame_length = sc->sc_max_frame_length;
|
||||
params.deq_pipeline_size = sc->sc_tx_deq_pipeline_depth;
|
||||
|
||||
/* TODO: verify_size_of_fifo() from Linux driver */
|
||||
err = FMAN_SET_PORT_PARAMS(device_get_parent(dev), ¶ms);
|
||||
|
||||
if (err != 0)
|
||||
return (err);
|
||||
|
||||
if (sc->sc_port_type == FMAN_PORT_TYPE_TX)
|
||||
err = fman_port_init_bmi_tx(sc);
|
||||
else {
|
||||
err = fman_port_init_bmi_rx(sc);
|
||||
if (err == 0)
|
||||
fman_port_init_hwp(sc);
|
||||
}
|
||||
|
||||
if (err != 0)
|
||||
return (err);
|
||||
|
||||
err = fman_port_init_qmi(sc);
|
||||
|
||||
/* TODO: keygen here */
|
||||
|
||||
return (err);
|
||||
}
|
||||
|
||||
static int
|
||||
fman_port_disable(device_t dev)
|
||||
{
|
||||
struct fman_port_softc *sc;
|
||||
uint32_t reg;
|
||||
int count;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
switch (sc->sc_port_type) {
|
||||
case FMAN_PORT_TYPE_TX:
|
||||
reg = bus_read_4(sc->sc_mem, FMQM_PNC);
|
||||
bus_write_4(sc->sc_mem, FMQM_PNC, reg & ~PNC_EN);
|
||||
for (count = 0; count < 100; count++) {
|
||||
DELAY(10);
|
||||
reg = bus_read_4(sc->sc_mem, FMQM_PNS);
|
||||
if (!(reg & PNS_DEQ_FD_BSY))
|
||||
break;
|
||||
}
|
||||
if (count == 100)
|
||||
device_printf(sc->sc_dev, "Timeout stopping QMI\n");
|
||||
reg = bus_read_4(sc->sc_mem, FMBM_TCFG);
|
||||
bus_write_4(sc->sc_mem, FMBM_TCFG, reg & ~BMI_PORT_CFG_EN);
|
||||
for (count = 0; count < 100; count++) {
|
||||
DELAY(10);
|
||||
reg = bus_read_4(sc->sc_mem, FMBM_TST);
|
||||
if (!(reg & PNS_DEQ_FD_BSY))
|
||||
break;
|
||||
}
|
||||
if (count == 100)
|
||||
device_printf(sc->sc_dev, "Timeout stopping BMI");
|
||||
break;
|
||||
case FMAN_PORT_TYPE_RX:
|
||||
reg = bus_read_4(sc->sc_mem, FMBM_RCFG);
|
||||
bus_write_4(sc->sc_mem, FMBM_RCFG, reg & ~BMI_PORT_CFG_EN);
|
||||
for (count = 0; count < 100; count++) {
|
||||
DELAY(10);
|
||||
reg = bus_read_4(sc->sc_mem, FMBM_RST);
|
||||
if (!(reg & PNS_DEQ_FD_BSY))
|
||||
break;
|
||||
}
|
||||
if (count == 100)
|
||||
device_printf(sc->sc_dev, "Timeout stopping BMI");
|
||||
break;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
fman_port_enable(device_t dev)
|
||||
{
|
||||
struct fman_port_softc *sc;
|
||||
uint32_t reg;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
switch (sc->sc_port_type) {
|
||||
case FMAN_PORT_TYPE_TX:
|
||||
reg = bus_read_4(sc->sc_mem, FMQM_PNC);
|
||||
bus_write_4(sc->sc_mem, FMQM_PNC, reg | PNC_EN | PNC_STEN);
|
||||
reg = bus_read_4(sc->sc_mem, FMBM_TCFG);
|
||||
bus_write_4(sc->sc_mem, FMBM_TCFG, reg | BMI_PORT_CFG_EN);
|
||||
break;
|
||||
case FMAN_PORT_TYPE_RX:
|
||||
reg = bus_read_4(sc->sc_mem, FMBM_RCFG);
|
||||
bus_write_4(sc->sc_mem, FMQM_PNC, reg | PNC_EN | PNC_STEN);
|
||||
bus_write_4(sc->sc_mem, FMBM_RCFG, reg | BMI_PORT_CFG_EN);
|
||||
bus_write_4(sc->sc_mem, FMBM_RSTC, RSTC_EN);
|
||||
break;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static device_method_t fman_port_methods[] = {
|
||||
DEVMETHOD(device_probe, fman_port_probe),
|
||||
DEVMETHOD(device_attach, fman_port_attach),
|
||||
DEVMETHOD(device_detach, fman_port_detach),
|
||||
|
||||
DEVMETHOD(fman_port_config, fman_port_config),
|
||||
DEVMETHOD(fman_port_init, fman_port_init),
|
||||
DEVMETHOD(fman_port_enable, fman_port_enable),
|
||||
DEVMETHOD(fman_port_disable, fman_port_disable),
|
||||
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
||||
DEFINE_CLASS_0(fman_port, fman_port_driver, fman_port_methods,
|
||||
sizeof(struct fman_port_softc));
|
||||
EARLY_DRIVER_MODULE(fman_port, fman, fman_port_driver, 0, 0,
|
||||
BUS_PASS_SUPPORTDEV + BUS_PASS_ORDER_MIDDLE);
|
||||
@@ -0,0 +1,29 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2026 Justin Hibbits
|
||||
*/
|
||||
|
||||
#ifndef DPAA_FMAN_PORT_H
|
||||
#define DPAA_FMAN_PORT_H
|
||||
|
||||
#define FMAN_PORT_MAX_POOLS 4
|
||||
struct fman_port_buffer_pool {
|
||||
uint8_t bpid;
|
||||
uint16_t size;
|
||||
};
|
||||
|
||||
struct fman_port_params {
|
||||
uint32_t dflt_fqid; /* Must not be 0 */
|
||||
uint32_t err_fqid;
|
||||
union {
|
||||
struct {
|
||||
int num_pools;
|
||||
struct fman_port_buffer_pool bpools[FMAN_PORT_MAX_POOLS];
|
||||
} rx_params;
|
||||
struct {
|
||||
} tx_params;
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,55 @@
|
||||
#-
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
#
|
||||
# Copyright (c) 2026 Justin Hibbits
|
||||
#
|
||||
# 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 <machine/bus.h>
|
||||
#include <dev/dpaa/fman_port.h>
|
||||
|
||||
/**
|
||||
* @brief DPAA FMan Port interface
|
||||
*
|
||||
*/
|
||||
INTERFACE fman_port;
|
||||
|
||||
/**
|
||||
* @brief Configure the port for a specific purpose
|
||||
*/
|
||||
METHOD int config {
|
||||
device_t dev;
|
||||
struct fman_port_params *params;
|
||||
};
|
||||
|
||||
METHOD int init {
|
||||
device_t dev;
|
||||
};
|
||||
|
||||
METHOD int disable {
|
||||
device_t dev;
|
||||
};
|
||||
|
||||
METHOD int enable {
|
||||
device_t dev;
|
||||
};
|
||||
@@ -0,0 +1,284 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2026 Justin Hibbits
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/if_media.h>
|
||||
#include <net/if_types.h>
|
||||
#include <net/if_var.h>
|
||||
|
||||
#include <dev/mdio/mdio.h>
|
||||
#include <dev/mii/mii.h>
|
||||
#include <dev/mii/miivar.h>
|
||||
|
||||
#include <dev/ofw/ofw_bus.h>
|
||||
#include <dev/ofw/ofw_bus_subr.h>
|
||||
|
||||
#include "fman.h"
|
||||
#include "miibus_if.h"
|
||||
#include "mdio_if.h"
|
||||
|
||||
#define MDIO_LOCK() mtx_lock(&sc->sc_lock)
|
||||
#define MDIO_UNLOCK() mtx_unlock(&sc->sc_lock)
|
||||
#define MDIO_WRITE4(sc, r, v) \
|
||||
bus_write_4(sc->sc_res, r, v)
|
||||
#define MDIO_READ4(sc, r) \
|
||||
bus_read_4(sc->sc_res, r)
|
||||
|
||||
#define MDIO_CFG 0x30
|
||||
#define CFG_ENC45 0x00000040
|
||||
#define MDIO_STAT 0x30
|
||||
#define STAT_BUSY 0x80000000
|
||||
#define STAT_MDIO_RD_ER 0x00000002
|
||||
#define MDIO_CTL 0x34
|
||||
#define CTL_READ 0x00008000
|
||||
#define MDIO_DATA 0x38
|
||||
#define MDIO_ADDR 0x3c
|
||||
|
||||
static int xmdio_fdt_probe(device_t dev);
|
||||
static int xmdio_fdt_attach(device_t dev);
|
||||
static int xmdio_detach(device_t dev);
|
||||
static int xmdio_miibus_readreg(device_t dev, int phy, int reg);
|
||||
static int xmdio_miibus_writereg(device_t dev, int phy, int reg, int value);
|
||||
static int xmdio_mdio_readextreg(device_t dev, int phy, int devad, int reg);
|
||||
static int xmdio_mdio_writeextreg(device_t dev, int phy, int devad, int reg,
|
||||
int val);
|
||||
|
||||
struct xmdio_softc {
|
||||
struct mtx sc_lock;
|
||||
struct resource *sc_res;
|
||||
};
|
||||
|
||||
static struct ofw_compat_data mdio_compat_data[] = {
|
||||
{"fsl,fman-memac-mdio", 0},
|
||||
{"fsl,fman-xmdio", 0},
|
||||
{NULL, 0}
|
||||
};
|
||||
|
||||
static device_method_t xmdio_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, xmdio_fdt_probe),
|
||||
DEVMETHOD(device_attach, xmdio_fdt_attach),
|
||||
DEVMETHOD(device_detach, xmdio_detach),
|
||||
DEVMETHOD(bus_add_child, bus_generic_add_child),
|
||||
|
||||
/* MII interface */
|
||||
DEVMETHOD(miibus_readreg, xmdio_miibus_readreg),
|
||||
DEVMETHOD(miibus_writereg, xmdio_miibus_writereg),
|
||||
|
||||
/* MDIO interface */
|
||||
DEVMETHOD(mdio_readreg, xmdio_miibus_readreg),
|
||||
DEVMETHOD(mdio_writereg, xmdio_miibus_writereg),
|
||||
DEVMETHOD(mdio_readextreg, xmdio_mdio_readextreg),
|
||||
DEVMETHOD(mdio_writeextreg, xmdio_mdio_writeextreg),
|
||||
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
||||
static driver_t xmdio_driver = {
|
||||
"xmdio",
|
||||
xmdio_methods,
|
||||
sizeof(struct xmdio_softc),
|
||||
};
|
||||
|
||||
EARLY_DRIVER_MODULE(xmdio, fman, xmdio_driver, 0, 0,
|
||||
BUS_PASS_SUPPORTDEV);
|
||||
DRIVER_MODULE(miibus, xmdio, miibus_driver, 0, 0);
|
||||
DRIVER_MODULE(mdio, xmdio, mdio_driver, 0, 0);
|
||||
MODULE_DEPEND(xmdio, miibus, 1, 1, 1);
|
||||
|
||||
static int
|
||||
xmdio_fdt_probe(device_t dev)
|
||||
{
|
||||
|
||||
if (!ofw_bus_status_okay(dev))
|
||||
return (ENXIO);
|
||||
|
||||
if (!ofw_bus_search_compatible(dev, mdio_compat_data)->ocd_str)
|
||||
return (ENXIO);
|
||||
|
||||
device_set_desc(dev, "Freescale XGMAC MDIO");
|
||||
|
||||
return (BUS_PROBE_DEFAULT);
|
||||
}
|
||||
|
||||
static int
|
||||
xmdio_fdt_attach(device_t dev)
|
||||
{
|
||||
struct xmdio_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
sc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 0, RF_ACTIVE);
|
||||
|
||||
OF_device_register_xref(OF_xref_from_node(ofw_bus_get_node(dev)), dev);
|
||||
|
||||
mtx_init(&sc->sc_lock, device_get_nameunit(dev), "XMDIO lock",
|
||||
MTX_DEF);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
xmdio_detach(device_t dev)
|
||||
{
|
||||
struct xmdio_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
mtx_destroy(&sc->sc_lock);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
set_clause45(struct xmdio_softc *sc)
|
||||
{
|
||||
uint32_t reg;
|
||||
|
||||
reg = MDIO_READ4(sc, MDIO_CFG);
|
||||
MDIO_WRITE4(sc, MDIO_CFG, reg | CFG_ENC45);
|
||||
}
|
||||
|
||||
static void
|
||||
set_clause22(struct xmdio_softc *sc)
|
||||
{
|
||||
uint32_t reg;
|
||||
|
||||
reg = MDIO_READ4(sc, MDIO_CFG);
|
||||
MDIO_WRITE4(sc, MDIO_CFG, reg & ~CFG_ENC45);
|
||||
}
|
||||
|
||||
static int
|
||||
xmdio_wait_no_busy(struct xmdio_softc *sc)
|
||||
{
|
||||
uint32_t count, val;
|
||||
|
||||
for (count = 1000; count > 0; count--) {
|
||||
val = MDIO_READ4(sc, MDIO_CFG);
|
||||
if ((val & STAT_BUSY) == 0)
|
||||
break;
|
||||
DELAY(1);
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
return (0xffff);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
xmdio_miibus_readreg(device_t dev, int phy, int reg)
|
||||
{
|
||||
struct xmdio_softc *sc;
|
||||
int rv;
|
||||
uint32_t ctl;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
MDIO_LOCK();
|
||||
|
||||
set_clause22(sc);
|
||||
ctl = (phy << 5) | reg;
|
||||
MDIO_WRITE4(sc, MDIO_CTL, ctl | CTL_READ);
|
||||
|
||||
MDIO_READ4(sc, MDIO_CTL);
|
||||
|
||||
if (xmdio_wait_no_busy(sc))
|
||||
rv = 0xffff;
|
||||
else
|
||||
rv = MDIO_READ4(sc, MDIO_DATA);
|
||||
|
||||
MDIO_WRITE4(sc, MDIO_CTL, 0);
|
||||
MDIO_UNLOCK();
|
||||
|
||||
return (rv);
|
||||
}
|
||||
|
||||
int
|
||||
xmdio_miibus_writereg(device_t dev, int phy, int reg, int value)
|
||||
{
|
||||
struct xmdio_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
MDIO_LOCK();
|
||||
set_clause22(sc);
|
||||
/* Stop the MII management read cycle */
|
||||
MDIO_WRITE4(sc, MDIO_CTL, (phy << 5) | reg);
|
||||
|
||||
MDIO_WRITE4(sc, MDIO_DATA, value);
|
||||
|
||||
/* Wait till MII management write is complete */
|
||||
xmdio_wait_no_busy(sc);
|
||||
MDIO_UNLOCK();
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
xmdio_mdio_readextreg(device_t dev, int phy, int devad, int reg)
|
||||
{
|
||||
struct xmdio_softc *sc;
|
||||
int rv;
|
||||
uint32_t ctl;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
MDIO_LOCK();
|
||||
|
||||
set_clause45(sc);
|
||||
ctl = (phy << 5) | devad;
|
||||
MDIO_WRITE4(sc, MDIO_CTL, ctl);
|
||||
MDIO_WRITE4(sc, MDIO_ADDR, reg);
|
||||
xmdio_wait_no_busy(sc);
|
||||
MDIO_WRITE4(sc, MDIO_CTL, ctl | CTL_READ);
|
||||
MDIO_READ4(sc, MDIO_CTL);
|
||||
|
||||
xmdio_wait_no_busy(sc);
|
||||
|
||||
if (MDIO_READ4(sc, MDIO_STAT) & STAT_MDIO_RD_ER)
|
||||
rv = 0xffff;
|
||||
else
|
||||
rv = MDIO_READ4(sc, MDIO_DATA);
|
||||
|
||||
MDIO_WRITE4(sc, MDIO_CTL, 0);
|
||||
MDIO_UNLOCK();
|
||||
|
||||
return (rv);
|
||||
}
|
||||
|
||||
static int
|
||||
xmdio_mdio_writeextreg(device_t dev, int phy, int devad, int reg, int val)
|
||||
{
|
||||
struct xmdio_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
MDIO_LOCK();
|
||||
set_clause45(sc);
|
||||
/* Stop the MII management read cycle */
|
||||
MDIO_WRITE4(sc, MDIO_CTL, (phy << 5) | devad);
|
||||
|
||||
MDIO_WRITE4(sc, MDIO_DATA, val);
|
||||
|
||||
/* Wait till MII management write is complete */
|
||||
xmdio_wait_no_busy(sc);
|
||||
MDIO_UNLOCK();
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
+201
-413
@@ -54,271 +54,60 @@
|
||||
|
||||
#include "miibus_if.h"
|
||||
|
||||
#include <contrib/ncsw/inc/integrations/dpaa_integration_ext.h>
|
||||
#include <contrib/ncsw/inc/Peripherals/fm_mac_ext.h>
|
||||
#include <contrib/ncsw/inc/Peripherals/fm_port_ext.h>
|
||||
#include <contrib/ncsw/inc/flib/fsl_fman_dtsec.h>
|
||||
#include <contrib/ncsw/inc/xx_ext.h>
|
||||
|
||||
#include "dpaa_eth.h"
|
||||
#include "fman.h"
|
||||
#include "fman_port.h"
|
||||
#include "if_dtsec.h"
|
||||
#include "if_dtsec_im.h"
|
||||
#include "if_dtsec_rm.h"
|
||||
|
||||
#include "fman_if.h"
|
||||
#include "fman_port_if.h"
|
||||
|
||||
#define DTSEC_MIN_FRAME_SIZE 64
|
||||
#define DTSEC_MAX_FRAME_SIZE 9600
|
||||
|
||||
#define DTSEC_REG_MAXFRM 0x110
|
||||
#define DTSEC_REG_GADDR(i) (0x0a0 + 4*(i))
|
||||
#define DTSEC_REG_IGADDR(i) (0x080 + 4 * (i))
|
||||
#define DTSEC_REG_GADDR(i) (0x0a0 + 4 * (i))
|
||||
|
||||
/**
|
||||
* @group dTSEC private defines.
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* dTSEC FMan MAC exceptions info struct.
|
||||
*/
|
||||
struct dtsec_fm_mac_ex_str {
|
||||
const int num;
|
||||
const char *str;
|
||||
};
|
||||
/** @} */
|
||||
#define DTSEC_ECNTRL 0x014
|
||||
#define ECNTRL_R100M 0x00000008
|
||||
#define DTSEC_TCTRL 0x040
|
||||
#define TCTRL_GTS 0x00000020
|
||||
#define DTSEC_RCTRL 0x050
|
||||
#define RCTRL_CFA 0x00008000
|
||||
#define RCTRL_GHTX 0x00000400
|
||||
#define RCTRL_GRS 0x00000020
|
||||
#define RCTRL_MPROM 0x00000008
|
||||
#define DTSEC_MACCFG1 0x100
|
||||
#define DTSEC_MACCFG2 0x104
|
||||
#define MACCFG_IF_M 0x00000300
|
||||
#define MACCFG_IF_10_100 0x00000100
|
||||
#define MACCFG_IF_1G 0x00000200
|
||||
#define MACCFG_FULLDUPLEX 0x00000001
|
||||
#define DTSEC_MACSTNADDR1 0x140
|
||||
#define DTSEC_MACSTNADDR2 0x144
|
||||
|
||||
static void dtsec_if_init_locked(struct dtsec_softc *sc);
|
||||
|
||||
/**
|
||||
* @group FMan MAC routines.
|
||||
* @{
|
||||
*/
|
||||
#define DTSEC_MAC_EXCEPTIONS_END (-1)
|
||||
|
||||
/**
|
||||
* FMan MAC exceptions.
|
||||
*/
|
||||
static const struct dtsec_fm_mac_ex_str dtsec_fm_mac_exceptions[] = {
|
||||
{ e_FM_MAC_EX_10G_MDIO_SCAN_EVENTMDIO, "MDIO scan event" },
|
||||
{ e_FM_MAC_EX_10G_MDIO_CMD_CMPL, "MDIO command completion" },
|
||||
{ e_FM_MAC_EX_10G_REM_FAULT, "Remote fault" },
|
||||
{ e_FM_MAC_EX_10G_LOC_FAULT, "Local fault" },
|
||||
{ e_FM_MAC_EX_10G_1TX_ECC_ER, "Transmit frame ECC error" },
|
||||
{ e_FM_MAC_EX_10G_TX_FIFO_UNFL, "Transmit FIFO underflow" },
|
||||
{ e_FM_MAC_EX_10G_TX_FIFO_OVFL, "Receive FIFO overflow" },
|
||||
{ e_FM_MAC_EX_10G_TX_ER, "Transmit frame error" },
|
||||
{ e_FM_MAC_EX_10G_RX_FIFO_OVFL, "Receive FIFO overflow" },
|
||||
{ e_FM_MAC_EX_10G_RX_ECC_ER, "Receive frame ECC error" },
|
||||
{ e_FM_MAC_EX_10G_RX_JAB_FRM, "Receive jabber frame" },
|
||||
{ e_FM_MAC_EX_10G_RX_OVRSZ_FRM, "Receive oversized frame" },
|
||||
{ e_FM_MAC_EX_10G_RX_RUNT_FRM, "Receive runt frame" },
|
||||
{ e_FM_MAC_EX_10G_RX_FRAG_FRM, "Receive fragment frame" },
|
||||
{ e_FM_MAC_EX_10G_RX_LEN_ER, "Receive payload length error" },
|
||||
{ e_FM_MAC_EX_10G_RX_CRC_ER, "Receive CRC error" },
|
||||
{ e_FM_MAC_EX_10G_RX_ALIGN_ER, "Receive alignment error" },
|
||||
{ e_FM_MAC_EX_1G_BAB_RX, "Babbling receive error" },
|
||||
{ e_FM_MAC_EX_1G_RX_CTL, "Receive control (pause frame) interrupt" },
|
||||
{ e_FM_MAC_EX_1G_GRATEFUL_TX_STP_COMPLET, "Graceful transmit stop "
|
||||
"complete" },
|
||||
{ e_FM_MAC_EX_1G_BAB_TX, "Babbling transmit error" },
|
||||
{ e_FM_MAC_EX_1G_TX_CTL, "Transmit control (pause frame) interrupt" },
|
||||
{ e_FM_MAC_EX_1G_TX_ERR, "Transmit error" },
|
||||
{ e_FM_MAC_EX_1G_LATE_COL, "Late collision" },
|
||||
{ e_FM_MAC_EX_1G_COL_RET_LMT, "Collision retry limit" },
|
||||
{ e_FM_MAC_EX_1G_TX_FIFO_UNDRN, "Transmit FIFO underrun" },
|
||||
{ e_FM_MAC_EX_1G_MAG_PCKT, "Magic Packet detected when dTSEC is in "
|
||||
"Magic Packet detection mode" },
|
||||
{ e_FM_MAC_EX_1G_MII_MNG_RD_COMPLET, "MII management read completion" },
|
||||
{ e_FM_MAC_EX_1G_MII_MNG_WR_COMPLET, "MII management write completion" },
|
||||
{ e_FM_MAC_EX_1G_GRATEFUL_RX_STP_COMPLET, "Graceful receive stop "
|
||||
"complete" },
|
||||
{ e_FM_MAC_EX_1G_TX_DATA_ERR, "Internal data error on transmit" },
|
||||
{ e_FM_MAC_EX_1G_RX_DATA_ERR, "Internal data error on receive" },
|
||||
{ e_FM_MAC_EX_1G_1588_TS_RX_ERR, "Time-Stamp Receive Error" },
|
||||
{ e_FM_MAC_EX_1G_RX_MIB_CNT_OVFL, "MIB counter overflow" },
|
||||
{ DTSEC_MAC_EXCEPTIONS_END, "" }
|
||||
};
|
||||
|
||||
static const char *
|
||||
dtsec_fm_mac_ex_to_str(e_FmMacExceptions exception)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; dtsec_fm_mac_exceptions[i].num != exception &&
|
||||
dtsec_fm_mac_exceptions[i].num != DTSEC_MAC_EXCEPTIONS_END; ++i)
|
||||
;
|
||||
|
||||
if (dtsec_fm_mac_exceptions[i].num == DTSEC_MAC_EXCEPTIONS_END)
|
||||
return ("<Unknown Exception>");
|
||||
|
||||
return (dtsec_fm_mac_exceptions[i].str);
|
||||
}
|
||||
|
||||
static void
|
||||
dtsec_fm_mac_mdio_event_callback(t_Handle h_App,
|
||||
e_FmMacExceptions exception)
|
||||
{
|
||||
struct dtsec_softc *sc;
|
||||
|
||||
sc = h_App;
|
||||
device_printf(sc->sc_dev, "MDIO event %i: %s.\n", exception,
|
||||
dtsec_fm_mac_ex_to_str(exception));
|
||||
}
|
||||
|
||||
static void
|
||||
dtsec_fm_mac_exception_callback(t_Handle app, e_FmMacExceptions exception)
|
||||
{
|
||||
struct dtsec_softc *sc;
|
||||
|
||||
sc = app;
|
||||
device_printf(sc->sc_dev, "MAC exception %i: %s.\n", exception,
|
||||
dtsec_fm_mac_ex_to_str(exception));
|
||||
}
|
||||
|
||||
static void
|
||||
dtsec_fm_mac_free(struct dtsec_softc *sc)
|
||||
{
|
||||
if (sc->sc_mach == NULL)
|
||||
return;
|
||||
|
||||
FM_MAC_Disable(sc->sc_mach, e_COMM_MODE_RX_AND_TX);
|
||||
FM_MAC_Free(sc->sc_mach);
|
||||
sc->sc_mach = NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
dtsec_fm_mac_init(struct dtsec_softc *sc, uint8_t *mac)
|
||||
{
|
||||
t_FmMacParams params;
|
||||
t_Error error;
|
||||
FMAN_GET_REVISION(device_get_parent(sc->sc_base.sc_dev), &sc->sc_base.sc_rev_major,
|
||||
&sc->sc_base.sc_rev_minor);
|
||||
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
memcpy(¶ms.addr, mac, sizeof(params.addr));
|
||||
|
||||
params.baseAddr = rman_get_bushandle(sc->sc_mem);
|
||||
params.enetMode = sc->sc_mac_enet_mode;
|
||||
params.macId = sc->sc_eth_id;
|
||||
params.mdioIrq = sc->sc_mac_mdio_irq;
|
||||
params.f_Event = dtsec_fm_mac_mdio_event_callback;
|
||||
params.f_Exception = dtsec_fm_mac_exception_callback;
|
||||
params.h_App = sc;
|
||||
params.h_Fm = sc->sc_fmh;
|
||||
|
||||
sc->sc_mach = FM_MAC_Config(¶ms);
|
||||
if (sc->sc_mach == NULL) {
|
||||
device_printf(sc->sc_dev, "couldn't configure FM_MAC module.\n"
|
||||
);
|
||||
if (FMAN_RESET_MAC(device_get_parent(sc->sc_base.sc_dev), sc->sc_base.sc_eth_id) != 0)
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
error = FM_MAC_ConfigResetOnInit(sc->sc_mach, TRUE);
|
||||
if (error != E_OK) {
|
||||
device_printf(sc->sc_dev, "couldn't enable reset on init "
|
||||
"feature.\n");
|
||||
dtsec_fm_mac_free(sc);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
/* Do not inform about pause frames */
|
||||
error = FM_MAC_ConfigException(sc->sc_mach, e_FM_MAC_EX_1G_RX_CTL,
|
||||
FALSE);
|
||||
if (error != E_OK) {
|
||||
device_printf(sc->sc_dev, "couldn't disable pause frames "
|
||||
"exception.\n");
|
||||
dtsec_fm_mac_free(sc);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
error = FM_MAC_Init(sc->sc_mach);
|
||||
if (error != E_OK) {
|
||||
device_printf(sc->sc_dev, "couldn't initialize FM_MAC module."
|
||||
"\n");
|
||||
dtsec_fm_mac_free(sc);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
|
||||
/**
|
||||
* @group FMan PORT routines.
|
||||
* @{
|
||||
*/
|
||||
static const char *
|
||||
dtsec_fm_port_ex_to_str(e_FmPortExceptions exception)
|
||||
{
|
||||
|
||||
switch (exception) {
|
||||
case e_FM_PORT_EXCEPTION_IM_BUSY:
|
||||
return ("IM: RX busy");
|
||||
default:
|
||||
return ("<Unknown Exception>");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dtsec_fm_port_rx_exception_callback(t_Handle app,
|
||||
e_FmPortExceptions exception)
|
||||
{
|
||||
struct dtsec_softc *sc;
|
||||
|
||||
sc = app;
|
||||
device_printf(sc->sc_dev, "RX exception: %i: %s.\n", exception,
|
||||
dtsec_fm_port_ex_to_str(exception));
|
||||
}
|
||||
|
||||
void
|
||||
dtsec_fm_port_tx_exception_callback(t_Handle app,
|
||||
e_FmPortExceptions exception)
|
||||
{
|
||||
struct dtsec_softc *sc;
|
||||
|
||||
sc = app;
|
||||
device_printf(sc->sc_dev, "TX exception: %i: %s.\n", exception,
|
||||
dtsec_fm_port_ex_to_str(exception));
|
||||
}
|
||||
|
||||
e_FmPortType
|
||||
dtsec_fm_port_rx_type(enum eth_dev_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case ETH_DTSEC:
|
||||
return (e_FM_PORT_TYPE_RX);
|
||||
case ETH_10GSEC:
|
||||
return (e_FM_PORT_TYPE_RX_10G);
|
||||
default:
|
||||
return (e_FM_PORT_TYPE_DUMMY);
|
||||
}
|
||||
}
|
||||
|
||||
e_FmPortType
|
||||
dtsec_fm_port_tx_type(enum eth_dev_type type)
|
||||
{
|
||||
|
||||
switch (type) {
|
||||
case ETH_DTSEC:
|
||||
return (e_FM_PORT_TYPE_TX);
|
||||
case ETH_10GSEC:
|
||||
return (e_FM_PORT_TYPE_TX_10G);
|
||||
default:
|
||||
return (e_FM_PORT_TYPE_DUMMY);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dtsec_fm_port_free_both(struct dtsec_softc *sc)
|
||||
{
|
||||
if (sc->sc_rxph) {
|
||||
FM_PORT_Free(sc->sc_rxph);
|
||||
sc->sc_rxph = NULL;
|
||||
}
|
||||
|
||||
if (sc->sc_txph) {
|
||||
FM_PORT_Free(sc->sc_txph);
|
||||
sc->sc_txph = NULL;
|
||||
}
|
||||
}
|
||||
/** @} */
|
||||
|
||||
|
||||
/**
|
||||
* @group IFnet routines.
|
||||
* @{
|
||||
@@ -332,7 +121,7 @@ dtsec_set_mtu(struct dtsec_softc *sc, unsigned int mtu)
|
||||
DTSEC_LOCK_ASSERT(sc);
|
||||
|
||||
if (mtu >= DTSEC_MIN_FRAME_SIZE && mtu <= DTSEC_MAX_FRAME_SIZE) {
|
||||
bus_write_4(sc->sc_mem, DTSEC_REG_MAXFRM, mtu);
|
||||
bus_write_4(sc->sc_base.sc_mem, DTSEC_REG_MAXFRM, mtu);
|
||||
return (mtu);
|
||||
}
|
||||
|
||||
@@ -342,9 +131,10 @@ dtsec_set_mtu(struct dtsec_softc *sc, unsigned int mtu)
|
||||
static u_int
|
||||
dtsec_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt)
|
||||
{
|
||||
struct dtsec_softc *sc = arg;
|
||||
uint32_t h, *hashtable = arg;
|
||||
|
||||
FM_MAC_AddHashMacAddr(sc->sc_mach, (t_EnetAddr *)LLADDR(sdl));
|
||||
h = (ether_crc32_be(LLADDR(sdl), ETHER_ADDR_LEN) >> 24) & 0xFF;
|
||||
hashtable[(h >> 5)] |= 1 << (0x1F - (h & 0x1F));
|
||||
|
||||
return (1);
|
||||
}
|
||||
@@ -352,18 +142,52 @@ dtsec_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt)
|
||||
static void
|
||||
dtsec_setup_multicast(struct dtsec_softc *sc)
|
||||
{
|
||||
uint32_t hashtable[8] = {};
|
||||
int i;
|
||||
|
||||
if (if_getflags(sc->sc_ifnet) & IFF_ALLMULTI) {
|
||||
if (if_getflags(sc->sc_base.sc_ifnet) & IFF_ALLMULTI) {
|
||||
for (i = 0; i < 8; i++)
|
||||
bus_write_4(sc->sc_mem, DTSEC_REG_GADDR(i), 0xFFFFFFFF);
|
||||
bus_write_4(sc->sc_base.sc_mem, DTSEC_REG_GADDR(i), 0xFFFFFFFF);
|
||||
bus_write_4(sc->sc_base.sc_mem, DTSEC_RCTRL,
|
||||
bus_read_4(sc->sc_base.sc_mem, DTSEC_RCTRL) | RCTRL_MPROM);
|
||||
|
||||
return;
|
||||
}
|
||||
bus_write_4(sc->sc_base.sc_mem, DTSEC_RCTRL,
|
||||
bus_read_4(sc->sc_base.sc_mem, DTSEC_RCTRL) & ~RCTRL_MPROM);
|
||||
|
||||
fman_dtsec_reset_filter_table(rman_get_virtual(sc->sc_mem),
|
||||
true, false);
|
||||
if_foreach_llmaddr(sc->sc_ifnet, dtsec_hash_maddr, sc);
|
||||
if_foreach_llmaddr(sc->sc_base.sc_ifnet, dtsec_hash_maddr, hashtable);
|
||||
for (i = 0; i < 8; i++)
|
||||
bus_write_4(sc->sc_base.sc_mem, DTSEC_REG_GADDR(i),
|
||||
hashtable[i]);
|
||||
}
|
||||
|
||||
static void
|
||||
dtsec_if_graceful_stop(struct dtsec_softc *sc)
|
||||
{
|
||||
bus_write_4(sc->sc_base.sc_mem, DTSEC_RCTRL,
|
||||
bus_read_4(sc->sc_base.sc_mem, DTSEC_RCTRL) | RCTRL_GRS);
|
||||
if (sc->sc_base.sc_rev_major == 2)
|
||||
DELAY(100);
|
||||
else
|
||||
DELAY(10);
|
||||
|
||||
bus_write_4(sc->sc_base.sc_mem, DTSEC_TCTRL,
|
||||
bus_read_4(sc->sc_base.sc_mem, DTSEC_TCTRL) | TCTRL_GTS);
|
||||
}
|
||||
|
||||
static void
|
||||
dtsec_if_graceful_start(struct dtsec_softc *sc)
|
||||
{
|
||||
bus_write_4(sc->sc_base.sc_mem, DTSEC_RCTRL,
|
||||
bus_read_4(sc->sc_base.sc_mem, DTSEC_RCTRL) & ~RCTRL_GRS);
|
||||
if (sc->sc_base.sc_rev_major == 2)
|
||||
DELAY(100);
|
||||
else
|
||||
DELAY(10);
|
||||
|
||||
bus_write_4(sc->sc_base.sc_mem, DTSEC_TCTRL,
|
||||
bus_read_4(sc->sc_base.sc_mem, DTSEC_TCTRL) & ~TCTRL_GTS);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -373,24 +197,22 @@ dtsec_if_enable_locked(struct dtsec_softc *sc)
|
||||
|
||||
DTSEC_LOCK_ASSERT(sc);
|
||||
|
||||
error = FM_MAC_Enable(sc->sc_mach, e_COMM_MODE_RX_AND_TX);
|
||||
if (error != E_OK)
|
||||
dtsec_if_graceful_start(sc);
|
||||
|
||||
error = FMAN_PORT_ENABLE(sc->sc_base.sc_rx_port);
|
||||
if (error != 0)
|
||||
return (EIO);
|
||||
|
||||
error = FM_PORT_Enable(sc->sc_rxph);
|
||||
if (error != E_OK)
|
||||
return (EIO);
|
||||
|
||||
error = FM_PORT_Enable(sc->sc_txph);
|
||||
if (error != E_OK)
|
||||
error = FMAN_PORT_ENABLE(sc->sc_base.sc_tx_port);
|
||||
if (error != 0)
|
||||
return (EIO);
|
||||
|
||||
dtsec_setup_multicast(sc);
|
||||
|
||||
if_setdrvflagbits(sc->sc_ifnet, IFF_DRV_RUNNING, 0);
|
||||
if_setdrvflagbits(sc->sc_base.sc_ifnet, IFF_DRV_RUNNING, 0);
|
||||
|
||||
/* Refresh link state */
|
||||
dtsec_miibus_statchg(sc->sc_dev);
|
||||
dtsec_miibus_statchg(sc->sc_base.sc_dev);
|
||||
|
||||
return (0);
|
||||
}
|
||||
@@ -402,19 +224,17 @@ dtsec_if_disable_locked(struct dtsec_softc *sc)
|
||||
|
||||
DTSEC_LOCK_ASSERT(sc);
|
||||
|
||||
error = FM_MAC_Disable(sc->sc_mach, e_COMM_MODE_RX_AND_TX);
|
||||
if (error != E_OK)
|
||||
dtsec_if_graceful_stop(sc);
|
||||
|
||||
error = FMAN_PORT_DISABLE(sc->sc_base.sc_rx_port);
|
||||
if (error != 0)
|
||||
return (EIO);
|
||||
|
||||
error = FM_PORT_Disable(sc->sc_rxph);
|
||||
if (error != E_OK)
|
||||
error = FMAN_PORT_DISABLE(sc->sc_base.sc_tx_port);
|
||||
if (error != 0)
|
||||
return (EIO);
|
||||
|
||||
error = FM_PORT_Disable(sc->sc_txph);
|
||||
if (error != E_OK)
|
||||
return (EIO);
|
||||
|
||||
if_setdrvflagbits(sc->sc_ifnet, 0, IFF_DRV_RUNNING);
|
||||
if_setdrvflagbits(sc->sc_base.sc_ifnet, 0, IFF_DRV_RUNNING);
|
||||
|
||||
return (0);
|
||||
}
|
||||
@@ -443,9 +263,10 @@ dtsec_if_ioctl(if_t ifp, u_long command, caddr_t data)
|
||||
case SIOCSIFFLAGS:
|
||||
DTSEC_LOCK(sc);
|
||||
|
||||
if (if_getflags(sc->sc_ifnet) & IFF_UP)
|
||||
error = dtsec_if_enable_locked(sc);
|
||||
else
|
||||
if (if_getflags(ifp) & IFF_UP) {
|
||||
if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING))
|
||||
dtsec_if_init_locked(sc);
|
||||
} else
|
||||
error = dtsec_if_disable_locked(sc);
|
||||
|
||||
DTSEC_UNLOCK(sc);
|
||||
@@ -453,7 +274,7 @@ dtsec_if_ioctl(if_t ifp, u_long command, caddr_t data)
|
||||
|
||||
case SIOCGIFMEDIA:
|
||||
case SIOCSIFMEDIA:
|
||||
error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii->mii_media,
|
||||
error = ifmedia_ioctl(ifp, ifr, &sc->sc_base.sc_mii->mii_media,
|
||||
command);
|
||||
break;
|
||||
|
||||
@@ -474,8 +295,8 @@ dtsec_if_tick(void *arg)
|
||||
/* TODO */
|
||||
DTSEC_LOCK(sc);
|
||||
|
||||
mii_tick(sc->sc_mii);
|
||||
callout_reset(&sc->sc_tick_callout, hz, dtsec_if_tick, sc);
|
||||
mii_tick(sc->sc_base.sc_mii);
|
||||
callout_reset(&sc->sc_base.sc_tick_callout, hz, dtsec_if_tick, sc);
|
||||
|
||||
DTSEC_UNLOCK(sc);
|
||||
}
|
||||
@@ -487,30 +308,38 @@ dtsec_if_deinit_locked(struct dtsec_softc *sc)
|
||||
DTSEC_LOCK_ASSERT(sc);
|
||||
|
||||
DTSEC_UNLOCK(sc);
|
||||
callout_drain(&sc->sc_tick_callout);
|
||||
callout_drain(&sc->sc_base.sc_tick_callout);
|
||||
DTSEC_LOCK(sc);
|
||||
}
|
||||
|
||||
static void
|
||||
dtsec_if_set_macaddr(struct dtsec_softc *sc, const char *addr)
|
||||
{
|
||||
uint32_t reg;
|
||||
|
||||
reg = (addr[5] << 24) | (addr[4] << 16) | (addr[3] << 8) | addr[2];
|
||||
bus_write_4(sc->sc_base.sc_mem, DTSEC_MACSTNADDR1, reg);
|
||||
reg = (addr[1] << 24) | (addr[0] << 16);
|
||||
bus_write_4(sc->sc_base.sc_mem, DTSEC_MACSTNADDR2, reg);
|
||||
}
|
||||
|
||||
static void
|
||||
dtsec_if_init_locked(struct dtsec_softc *sc)
|
||||
{
|
||||
int error;
|
||||
const char *macaddr;
|
||||
|
||||
DTSEC_LOCK_ASSERT(sc);
|
||||
|
||||
/* Set MAC address */
|
||||
error = FM_MAC_ModifyMacAddr(sc->sc_mach,
|
||||
(t_EnetAddr *)if_getlladdr(sc->sc_ifnet));
|
||||
if (error != E_OK) {
|
||||
device_printf(sc->sc_dev, "couldn't set MAC address.\n");
|
||||
goto err;
|
||||
}
|
||||
macaddr = if_getlladdr(sc->sc_base.sc_ifnet);
|
||||
dtsec_if_set_macaddr(sc, macaddr);
|
||||
|
||||
/* Start MII polling */
|
||||
if (sc->sc_mii)
|
||||
callout_reset(&sc->sc_tick_callout, hz, dtsec_if_tick, sc);
|
||||
if (sc->sc_base.sc_mii)
|
||||
callout_reset(&sc->sc_base.sc_tick_callout, hz,
|
||||
dtsec_if_tick, sc);
|
||||
|
||||
if (if_getflags(sc->sc_ifnet) & IFF_UP) {
|
||||
if (if_getflags(sc->sc_base.sc_ifnet) & IFF_UP) {
|
||||
error = dtsec_if_enable_locked(sc);
|
||||
if (error != 0)
|
||||
goto err;
|
||||
@@ -524,7 +353,7 @@ dtsec_if_init_locked(struct dtsec_softc *sc)
|
||||
|
||||
err:
|
||||
dtsec_if_deinit_locked(sc);
|
||||
device_printf(sc->sc_dev, "initialization error.\n");
|
||||
device_printf(sc->sc_base.sc_dev, "initialization error.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -547,7 +376,7 @@ dtsec_if_start(if_t ifp)
|
||||
|
||||
sc = if_getsoftc(ifp);
|
||||
DTSEC_LOCK(sc);
|
||||
sc->sc_start_locked(sc);
|
||||
dpaa_eth_if_start_locked(&sc->sc_base);
|
||||
DTSEC_UNLOCK(sc);
|
||||
}
|
||||
|
||||
@@ -569,7 +398,7 @@ dtsec_ifmedia_upd(if_t ifp)
|
||||
struct dtsec_softc *sc = if_getsoftc(ifp);
|
||||
|
||||
DTSEC_LOCK(sc);
|
||||
mii_mediachg(sc->sc_mii);
|
||||
mii_mediachg(sc->sc_base.sc_mii);
|
||||
DTSEC_UNLOCK(sc);
|
||||
|
||||
return (0);
|
||||
@@ -582,10 +411,10 @@ dtsec_ifmedia_sts(if_t ifp, struct ifmediareq *ifmr)
|
||||
|
||||
DTSEC_LOCK(sc);
|
||||
|
||||
mii_pollstat(sc->sc_mii);
|
||||
mii_pollstat(sc->sc_base.sc_mii);
|
||||
|
||||
ifmr->ifm_active = sc->sc_mii->mii_media_active;
|
||||
ifmr->ifm_status = sc->sc_mii->mii_media_status;
|
||||
ifmr->ifm_active = sc->sc_base.sc_mii->mii_media_active;
|
||||
ifmr->ifm_status = sc->sc_base.sc_mii->mii_media_status;
|
||||
|
||||
DTSEC_UNLOCK(sc);
|
||||
}
|
||||
@@ -596,118 +425,75 @@ dtsec_ifmedia_sts(if_t ifp, struct ifmediareq *ifmr)
|
||||
* @group dTSEC bus interface.
|
||||
* @{
|
||||
*/
|
||||
static void
|
||||
dtsec_configure_mode(struct dtsec_softc *sc)
|
||||
{
|
||||
char tunable[64];
|
||||
|
||||
snprintf(tunable, sizeof(tunable), "%s.independent_mode",
|
||||
device_get_nameunit(sc->sc_dev));
|
||||
|
||||
sc->sc_mode = DTSEC_MODE_REGULAR;
|
||||
TUNABLE_INT_FETCH(tunable, &sc->sc_mode);
|
||||
|
||||
if (sc->sc_mode == DTSEC_MODE_REGULAR) {
|
||||
sc->sc_port_rx_init = dtsec_rm_fm_port_rx_init;
|
||||
sc->sc_port_tx_init = dtsec_rm_fm_port_tx_init;
|
||||
sc->sc_start_locked = dtsec_rm_if_start_locked;
|
||||
} else {
|
||||
sc->sc_port_rx_init = dtsec_im_fm_port_rx_init;
|
||||
sc->sc_port_tx_init = dtsec_im_fm_port_tx_init;
|
||||
sc->sc_start_locked = dtsec_im_if_start_locked;
|
||||
}
|
||||
|
||||
device_printf(sc->sc_dev, "Configured for %s mode.\n",
|
||||
(sc->sc_mode == DTSEC_MODE_REGULAR) ? "regular" : "independent");
|
||||
}
|
||||
|
||||
int
|
||||
dtsec_attach(device_t dev)
|
||||
{
|
||||
struct dtsec_softc *sc;
|
||||
device_t parent;
|
||||
cell_t ports[2];
|
||||
phandle_t node;
|
||||
int error;
|
||||
if_t ifp;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
parent = device_get_parent(dev);
|
||||
sc->sc_dev = dev;
|
||||
sc->sc_mac_mdio_irq = NO_IRQ;
|
||||
|
||||
/* Check if MallocSmart allocator is ready */
|
||||
if (XX_MallocSmartInit() != E_OK)
|
||||
return (ENXIO);
|
||||
sc->sc_base.sc_dev = dev;
|
||||
node = ofw_bus_get_node(dev);
|
||||
|
||||
/* Init locks */
|
||||
mtx_init(&sc->sc_lock, device_get_nameunit(dev),
|
||||
mtx_init(&sc->sc_base.sc_lock, device_get_nameunit(dev),
|
||||
"DTSEC Global Lock", MTX_DEF);
|
||||
|
||||
mtx_init(&sc->sc_mii_lock, device_get_nameunit(dev),
|
||||
mtx_init(&sc->sc_base.sc_mii_lock, device_get_nameunit(dev),
|
||||
"DTSEC MII Lock", MTX_DEF);
|
||||
|
||||
/* Init callouts */
|
||||
callout_init(&sc->sc_tick_callout, CALLOUT_MPSAFE);
|
||||
callout_init(&sc->sc_base.sc_tick_callout, CALLOUT_MPSAFE);
|
||||
|
||||
/* Read configuraton */
|
||||
if ((error = fman_get_handle(parent, &sc->sc_fmh)) != 0)
|
||||
return (error);
|
||||
/* Create RX buffer pool */
|
||||
error = dpaa_eth_pool_rx_init(&sc->sc_base);
|
||||
if (error != 0)
|
||||
return (EIO);
|
||||
|
||||
if ((error = fman_get_muram_handle(parent, &sc->sc_muramh)) != 0)
|
||||
return (error);
|
||||
/* Create RX frame queue range */
|
||||
error = dpaa_eth_fq_rx_init(&sc->sc_base);
|
||||
if (error != 0)
|
||||
return (EIO);
|
||||
|
||||
if ((error = fman_get_bushandle(parent, &sc->sc_fm_base)) != 0)
|
||||
return (error);
|
||||
/* Create frame info pool */
|
||||
error = dpaa_eth_fi_pool_init(&sc->sc_base);
|
||||
if (error != 0)
|
||||
return (EIO);
|
||||
|
||||
/* Configure working mode */
|
||||
dtsec_configure_mode(sc);
|
||||
/* Create TX frame queue range */
|
||||
error = dpaa_eth_fq_tx_init(&sc->sc_base);
|
||||
if (error != 0)
|
||||
return (EIO);
|
||||
|
||||
/* If we are working in regular mode configure BMAN and QMAN */
|
||||
if (sc->sc_mode == DTSEC_MODE_REGULAR) {
|
||||
/* Create RX buffer pool */
|
||||
error = dtsec_rm_pool_rx_init(sc);
|
||||
if (error != 0)
|
||||
return (EIO);
|
||||
|
||||
/* Create RX frame queue range */
|
||||
error = dtsec_rm_fqr_rx_init(sc);
|
||||
if (error != 0)
|
||||
return (EIO);
|
||||
|
||||
/* Create frame info pool */
|
||||
error = dtsec_rm_fi_pool_init(sc);
|
||||
if (error != 0)
|
||||
return (EIO);
|
||||
|
||||
/* Create TX frame queue range */
|
||||
error = dtsec_rm_fqr_tx_init(sc);
|
||||
if (error != 0)
|
||||
return (EIO);
|
||||
if (OF_getencprop(node, "fsl,fman-ports", ports, sizeof(ports)) < 0) {
|
||||
device_printf(dev, "missing ports in device tree\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
/* Init FMan MAC module. */
|
||||
error = dtsec_fm_mac_init(sc, sc->sc_mac_addr);
|
||||
error = dtsec_fm_mac_init(sc, sc->sc_base.sc_mac_addr);
|
||||
if (error != 0) {
|
||||
dtsec_detach(dev);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
/* Init FMan TX port */
|
||||
error = sc->sc_port_tx_init(sc, device_get_unit(sc->sc_dev));
|
||||
if (error != 0) {
|
||||
dtsec_detach(dev);
|
||||
return (ENXIO);
|
||||
}
|
||||
sc->sc_base.sc_rx_port = OF_device_from_xref(ports[0]);
|
||||
sc->sc_base.sc_tx_port = OF_device_from_xref(ports[1]);
|
||||
dpaa_eth_fm_port_rx_init(&sc->sc_base);
|
||||
dpaa_eth_fm_port_tx_init(&sc->sc_base);
|
||||
|
||||
/* Init FMan RX port */
|
||||
error = sc->sc_port_rx_init(sc, device_get_unit(sc->sc_dev));
|
||||
if (error != 0) {
|
||||
if (sc->sc_base.sc_rx_port == NULL || sc->sc_base.sc_tx_port == NULL) {
|
||||
device_printf(dev, "invalid ports");
|
||||
dtsec_detach(dev);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
/* Create network interface for upper layers */
|
||||
ifp = sc->sc_ifnet = if_alloc(IFT_ETHER);
|
||||
ifp = sc->sc_base.sc_ifnet = if_alloc(IFT_ETHER);
|
||||
if_setsoftc(ifp, sc);
|
||||
|
||||
if_setflags(ifp, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST);
|
||||
@@ -716,11 +502,12 @@ dtsec_attach(device_t dev)
|
||||
if_setioctlfn(ifp, dtsec_if_ioctl);
|
||||
if_setsendqlen(ifp, IFQ_MAXLEN);
|
||||
|
||||
if (sc->sc_phy_addr >= 0)
|
||||
if_initname(ifp, device_get_name(sc->sc_dev),
|
||||
device_get_unit(sc->sc_dev));
|
||||
if (sc->sc_base.sc_phy_addr >= 0)
|
||||
if_initname(ifp, device_get_name(sc->sc_base.sc_dev),
|
||||
device_get_unit(sc->sc_base.sc_dev));
|
||||
else
|
||||
if_initname(ifp, "dtsec_phy", device_get_unit(sc->sc_dev));
|
||||
if_initname(ifp, "dtsec_phy",
|
||||
device_get_unit(sc->sc_base.sc_dev));
|
||||
|
||||
/* TODO */
|
||||
#if 0
|
||||
@@ -732,18 +519,18 @@ dtsec_attach(device_t dev)
|
||||
if_setcapenable(ifp, if_getcapabilities(ifp));
|
||||
|
||||
/* Attach PHY(s) */
|
||||
error = mii_attach(sc->sc_dev, &sc->sc_mii_dev, ifp, dtsec_ifmedia_upd,
|
||||
dtsec_ifmedia_sts, BMSR_DEFCAPMASK, sc->sc_phy_addr,
|
||||
MII_OFFSET_ANY, 0);
|
||||
error = mii_attach(sc->sc_base.sc_dev, &sc->sc_base.sc_mii_dev,
|
||||
ifp, dtsec_ifmedia_upd, dtsec_ifmedia_sts, BMSR_DEFCAPMASK,
|
||||
sc->sc_base.sc_phy_addr, MII_OFFSET_ANY, 0);
|
||||
if (error) {
|
||||
device_printf(sc->sc_dev, "attaching PHYs failed: %d\n", error);
|
||||
dtsec_detach(sc->sc_dev);
|
||||
device_printf(sc->sc_base.sc_dev,
|
||||
"attaching PHYs failed: %d\n", error);
|
||||
dtsec_detach(sc->sc_base.sc_dev);
|
||||
return (error);
|
||||
}
|
||||
sc->sc_mii = device_get_softc(sc->sc_mii_dev);
|
||||
|
||||
/* Attach to stack */
|
||||
ether_ifattach(ifp, sc->sc_mac_addr);
|
||||
ether_ifattach(ifp, sc->sc_base.sc_mac_addr);
|
||||
|
||||
return (0);
|
||||
}
|
||||
@@ -755,7 +542,7 @@ dtsec_detach(device_t dev)
|
||||
if_t ifp;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
ifp = sc->sc_ifnet;
|
||||
ifp = sc->sc_base.sc_ifnet;
|
||||
|
||||
if (device_is_attached(dev)) {
|
||||
ether_ifdetach(ifp);
|
||||
@@ -765,28 +552,23 @@ dtsec_detach(device_t dev)
|
||||
DTSEC_UNLOCK(sc);
|
||||
}
|
||||
|
||||
if (sc->sc_ifnet) {
|
||||
if_free(sc->sc_ifnet);
|
||||
sc->sc_ifnet = NULL;
|
||||
if (sc->sc_base.sc_ifnet) {
|
||||
if_free(sc->sc_base.sc_ifnet);
|
||||
sc->sc_base.sc_ifnet = NULL;
|
||||
}
|
||||
|
||||
if (sc->sc_mode == DTSEC_MODE_REGULAR) {
|
||||
/* Free RX/TX FQRs */
|
||||
dtsec_rm_fqr_rx_free(sc);
|
||||
dtsec_rm_fqr_tx_free(sc);
|
||||
/* Free RX/TX FQRs */
|
||||
dpaa_eth_fq_rx_free(&sc->sc_base);
|
||||
dpaa_eth_fq_tx_free(&sc->sc_base);
|
||||
|
||||
/* Free frame info pool */
|
||||
dtsec_rm_fi_pool_free(sc);
|
||||
/* Free frame info pool */
|
||||
dpaa_eth_fi_pool_free(&sc->sc_base);
|
||||
|
||||
/* Free RX buffer pool */
|
||||
dtsec_rm_pool_rx_free(sc);
|
||||
}
|
||||
|
||||
dtsec_fm_mac_free(sc);
|
||||
dtsec_fm_port_free_both(sc);
|
||||
/* Free RX buffer pool */
|
||||
dpaa_eth_pool_rx_free(&sc->sc_base);
|
||||
|
||||
/* Destroy lock */
|
||||
mtx_destroy(&sc->sc_lock);
|
||||
mtx_destroy(&sc->sc_base.sc_lock);
|
||||
|
||||
return (0);
|
||||
}
|
||||
@@ -825,7 +607,7 @@ dtsec_miibus_readreg(device_t dev, int phy, int reg)
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
return (MIIBUS_READREG(sc->sc_mdio, phy, reg));
|
||||
return (MIIBUS_READREG(sc->sc_base.sc_mdio, phy, reg));
|
||||
}
|
||||
|
||||
int
|
||||
@@ -836,43 +618,49 @@ dtsec_miibus_writereg(device_t dev, int phy, int reg, int value)
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
return (MIIBUS_WRITEREG(sc->sc_mdio, phy, reg, value));
|
||||
return (MIIBUS_WRITEREG(sc->sc_base.sc_mdio, phy, reg, value));
|
||||
}
|
||||
|
||||
void
|
||||
dtsec_miibus_statchg(device_t dev)
|
||||
{
|
||||
struct dtsec_softc *sc;
|
||||
e_EnetSpeed speed;
|
||||
uint32_t reg;
|
||||
bool duplex;
|
||||
int error;
|
||||
int speed;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
DTSEC_LOCK_ASSERT(sc);
|
||||
|
||||
duplex = ((sc->sc_mii->mii_media_active & IFM_GMASK) == IFM_FDX);
|
||||
duplex = ((sc->sc_base.sc_mii->mii_media_active & IFM_GMASK) == IFM_FDX);
|
||||
|
||||
switch (IFM_SUBTYPE(sc->sc_mii->mii_media_active)) {
|
||||
switch (IFM_SUBTYPE(sc->sc_base.sc_mii->mii_media_active)) {
|
||||
case IFM_1000_T:
|
||||
case IFM_1000_SX:
|
||||
speed = e_ENET_SPEED_1000;
|
||||
break;
|
||||
|
||||
case IFM_100_TX:
|
||||
speed = e_ENET_SPEED_100;
|
||||
break;
|
||||
|
||||
case IFM_10_T:
|
||||
speed = e_ENET_SPEED_10;
|
||||
if (!duplex) {
|
||||
device_printf(sc->sc_base.sc_dev,
|
||||
"Only full-duplex supported for 1Gbps speeds");
|
||||
return;
|
||||
}
|
||||
speed = MACCFG_IF_1G;
|
||||
break;
|
||||
|
||||
default:
|
||||
speed = e_ENET_SPEED_10;
|
||||
speed = MACCFG_IF_10_100;
|
||||
}
|
||||
|
||||
error = FM_MAC_AdjustLink(sc->sc_mach, speed, duplex);
|
||||
if (error != E_OK)
|
||||
device_printf(sc->sc_dev, "error while adjusting MAC speed.\n");
|
||||
reg = bus_read_4(sc->sc_base.sc_mem, DTSEC_MACCFG2);
|
||||
reg &= ~(MACCFG_IF_M | MACCFG_FULLDUPLEX);
|
||||
|
||||
if (duplex)
|
||||
reg |= MACCFG_FULLDUPLEX;
|
||||
reg |= speed;
|
||||
bus_write_4(sc->sc_base.sc_mem, DTSEC_MACCFG2, reg);
|
||||
|
||||
reg = bus_read_4(sc->sc_base.sc_mem, DTSEC_ECNTRL) & ~ECNTRL_R100M;
|
||||
if (IFM_SUBTYPE(sc->sc_base.sc_mii->mii_media_active) == IFM_100_TX)
|
||||
reg |= ECNTRL_R100M;
|
||||
bus_write_4(sc->sc_base.sc_mem, DTSEC_ECNTRL, reg);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
+6
-90
@@ -34,11 +34,11 @@
|
||||
#define DTSEC_MODE_REGULAR 0
|
||||
#define DTSEC_MODE_INDEPENDENT 1
|
||||
|
||||
#define DTSEC_LOCK(sc) mtx_lock(&(sc)->sc_lock)
|
||||
#define DTSEC_UNLOCK(sc) mtx_unlock(&(sc)->sc_lock)
|
||||
#define DTSEC_LOCK_ASSERT(sc) mtx_assert(&(sc)->sc_lock, MA_OWNED)
|
||||
#define DTSEC_MII_LOCK(sc) mtx_lock(&(sc)->sc_mii_lock)
|
||||
#define DTSEC_MII_UNLOCK(sc) mtx_unlock(&(sc)->sc_mii_lock)
|
||||
#define DTSEC_LOCK(sc) mtx_lock(&(sc)->sc_base.sc_lock)
|
||||
#define DTSEC_UNLOCK(sc) mtx_unlock(&(sc)->sc_base.sc_lock)
|
||||
#define DTSEC_LOCK_ASSERT(sc) mtx_assert(&(sc)->sc_base.sc_lock, MA_OWNED)
|
||||
#define DTSEC_MII_LOCK(sc) mtx_lock(&(sc)->sc_base.sc_mii_lock)
|
||||
#define DTSEC_MII_UNLOCK(sc) mtx_unlock(&(sc)->sc_base.sc_mii_lock)
|
||||
|
||||
enum eth_dev_type {
|
||||
ETH_DTSEC = 0x1,
|
||||
@@ -46,96 +46,12 @@ enum eth_dev_type {
|
||||
};
|
||||
|
||||
struct dtsec_softc {
|
||||
/* XXX MII bus requires that struct ifnet is first!!! */
|
||||
if_t sc_ifnet;
|
||||
|
||||
device_t sc_dev;
|
||||
struct resource *sc_mem;
|
||||
struct mtx sc_lock;
|
||||
int sc_mode;
|
||||
|
||||
/* Methods */
|
||||
int (*sc_port_rx_init)
|
||||
(struct dtsec_softc *sc, int unit);
|
||||
int (*sc_port_tx_init)
|
||||
(struct dtsec_softc *sc, int unit);
|
||||
void (*sc_start_locked)
|
||||
(struct dtsec_softc *sc);
|
||||
|
||||
/* dTSEC data */
|
||||
struct dpaa_eth_softc sc_base;
|
||||
enum eth_dev_type sc_eth_dev_type;
|
||||
uint8_t sc_eth_id; /* Ethernet ID within its frame manager */
|
||||
uintptr_t sc_mac_mem_offset;
|
||||
e_EnetMode sc_mac_enet_mode;
|
||||
int sc_mac_mdio_irq;
|
||||
uint8_t sc_mac_addr[6];
|
||||
int sc_port_rx_hw_id;
|
||||
int sc_port_tx_hw_id;
|
||||
uint32_t sc_port_tx_qman_chan;
|
||||
int sc_phy_addr;
|
||||
bool sc_hidden;
|
||||
device_t sc_mdio;
|
||||
|
||||
/* Params from fman_bus driver */
|
||||
vm_offset_t sc_fm_base;
|
||||
t_Handle sc_fmh;
|
||||
t_Handle sc_muramh;
|
||||
|
||||
t_Handle sc_mach;
|
||||
t_Handle sc_rxph;
|
||||
t_Handle sc_txph;
|
||||
|
||||
/* MII data */
|
||||
struct mii_data *sc_mii;
|
||||
device_t sc_mii_dev;
|
||||
struct mtx sc_mii_lock;
|
||||
|
||||
struct callout sc_tick_callout;
|
||||
|
||||
/* RX Pool */
|
||||
t_Handle sc_rx_pool;
|
||||
uint8_t sc_rx_bpid;
|
||||
uma_zone_t sc_rx_zone;
|
||||
char sc_rx_zname[64];
|
||||
|
||||
/* RX Frame Queue */
|
||||
t_Handle sc_rx_fqr;
|
||||
uint32_t sc_rx_fqid;
|
||||
|
||||
/* TX Frame Queue */
|
||||
t_Handle sc_tx_fqr;
|
||||
bool sc_tx_fqr_full;
|
||||
t_Handle sc_tx_conf_fqr;
|
||||
uint32_t sc_tx_conf_fqid;
|
||||
|
||||
/* Frame Info Zone */
|
||||
uma_zone_t sc_fi_zone;
|
||||
char sc_fi_zname[64];
|
||||
};
|
||||
/** @} */
|
||||
|
||||
|
||||
/**
|
||||
* @group dTSEC FMan PORT API.
|
||||
* @{
|
||||
*/
|
||||
enum dtsec_fm_port_params {
|
||||
FM_PORT_LIODN_BASE = 0,
|
||||
FM_PORT_LIODN_OFFSET = 0,
|
||||
FM_PORT_MEM_ID = 0,
|
||||
FM_PORT_MEM_ATTR = MEMORY_ATTR_CACHEABLE,
|
||||
FM_PORT_BUFFER_SIZE = MCLBYTES,
|
||||
};
|
||||
|
||||
e_FmPortType dtsec_fm_port_rx_type(enum eth_dev_type type);
|
||||
void dtsec_fm_port_rx_exception_callback(t_Handle app,
|
||||
e_FmPortExceptions exception);
|
||||
void dtsec_fm_port_tx_exception_callback(t_Handle app,
|
||||
e_FmPortExceptions exception);
|
||||
e_FmPortType dtsec_fm_port_tx_type(enum eth_dev_type type);
|
||||
/** @} */
|
||||
|
||||
|
||||
/**
|
||||
* @group dTSEC bus interface.
|
||||
* @{
|
||||
|
||||
+14
-41
@@ -48,9 +48,7 @@
|
||||
|
||||
#include "miibus_if.h"
|
||||
|
||||
#include <contrib/ncsw/inc/Peripherals/fm_port_ext.h>
|
||||
#include <contrib/ncsw/inc/xx_ext.h>
|
||||
|
||||
#include "dpaa_eth.h"
|
||||
#include "if_dtsec.h"
|
||||
#include "fman.h"
|
||||
|
||||
@@ -123,7 +121,7 @@ dtsec_fdt_attach(device_t dev)
|
||||
enet_node = ofw_bus_get_node(dev);
|
||||
|
||||
if (OF_getprop(enet_node, "local-mac-address",
|
||||
(void *)sc->sc_mac_addr, 6) == -1) {
|
||||
(void *)sc->sc_base.sc_mac_addr, 6) == -1) {
|
||||
device_printf(dev,
|
||||
"Could not load local-mac-addr property from DTS\n");
|
||||
return (ENXIO);
|
||||
@@ -135,17 +133,17 @@ dtsec_fdt_attach(device_t dev)
|
||||
else if (ofw_bus_is_compatible(dev, "fsl,fman-xgec") != 0)
|
||||
sc->sc_eth_dev_type = ETH_10GSEC;
|
||||
else
|
||||
return(ENXIO);
|
||||
return (ENXIO);
|
||||
|
||||
/* Get PHY address */
|
||||
if (OF_getprop(enet_node, "phy-handle", (void *)&phy_node,
|
||||
if (OF_getprop(enet_node, "tbi-handle", (void *)&phy_node,
|
||||
sizeof(phy_node)) <= 0)
|
||||
return (ENXIO);
|
||||
|
||||
phy_node = OF_node_from_xref(phy_node);
|
||||
|
||||
if (OF_getprop(phy_node, "reg", (void *)&sc->sc_phy_addr,
|
||||
sizeof(sc->sc_phy_addr)) <= 0)
|
||||
if (OF_getprop(phy_node, "reg", (void *)&sc->sc_base.sc_phy_addr,
|
||||
sizeof(sc->sc_base.sc_phy_addr)) <= 0)
|
||||
return (ENXIO);
|
||||
|
||||
phy_dev = OF_device_from_xref(OF_parent(phy_node));
|
||||
@@ -155,12 +153,12 @@ dtsec_fdt_attach(device_t dev)
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
sc->sc_mdio = phy_dev;
|
||||
sc->sc_base.sc_mdio = phy_dev;
|
||||
|
||||
/* Get MAC memory offset in SoC */
|
||||
rid = 0;
|
||||
sc->sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
|
||||
if (sc->sc_mem == NULL)
|
||||
sc->sc_base.sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
|
||||
if (sc->sc_base.sc_mem == NULL)
|
||||
return (ENXIO);
|
||||
|
||||
/* Get PHY connection type */
|
||||
@@ -168,20 +166,10 @@ dtsec_fdt_attach(device_t dev)
|
||||
sizeof(phy_type)) <= 0)
|
||||
return (ENXIO);
|
||||
|
||||
if (!strcmp(phy_type, "sgmii"))
|
||||
sc->sc_mac_enet_mode = e_ENET_MODE_SGMII_1000;
|
||||
else if (!strcmp(phy_type, "rgmii"))
|
||||
sc->sc_mac_enet_mode = e_ENET_MODE_RGMII_1000;
|
||||
else if (!strcmp(phy_type, "xgmii"))
|
||||
/* We set 10 Gigabit mode flag however we don't support it */
|
||||
sc->sc_mac_enet_mode = e_ENET_MODE_XGMII_10000;
|
||||
else
|
||||
return (ENXIO);
|
||||
|
||||
if (OF_getencprop(enet_node, "cell-index",
|
||||
(void *)&mac_id, sizeof(mac_id)) <= 0)
|
||||
return (ENXIO);
|
||||
sc->sc_eth_id = mac_id;
|
||||
sc->sc_base.sc_eth_id = mac_id;
|
||||
|
||||
/* Get RX/TX port handles */
|
||||
if (OF_getprop(enet_node, "fsl,fman-ports", (void *)fman_rxtx_node,
|
||||
@@ -194,32 +182,17 @@ dtsec_fdt_attach(device_t dev)
|
||||
if (fman_rxtx_node[1] == 0)
|
||||
return (ENXIO);
|
||||
|
||||
fman_rxtx_node[0] = OF_instance_to_package(fman_rxtx_node[0]);
|
||||
fman_rxtx_node[1] = OF_instance_to_package(fman_rxtx_node[1]);
|
||||
sc->sc_base.sc_rx_port = OF_device_from_xref(fman_rxtx_node[0]);
|
||||
sc->sc_base.sc_tx_port = OF_device_from_xref(fman_rxtx_node[1]);
|
||||
|
||||
if (ofw_bus_node_is_compatible(fman_rxtx_node[0],
|
||||
"fsl,fman-v2-port-rx") == 0)
|
||||
return (ENXIO);
|
||||
|
||||
if (ofw_bus_node_is_compatible(fman_rxtx_node[1],
|
||||
"fsl,fman-v2-port-tx") == 0)
|
||||
return (ENXIO);
|
||||
|
||||
/* Get RX port HW id */
|
||||
if (OF_getprop(fman_rxtx_node[0], "reg", (void *)&sc->sc_port_rx_hw_id,
|
||||
sizeof(sc->sc_port_rx_hw_id)) <= 0)
|
||||
return (ENXIO);
|
||||
|
||||
/* Get TX port HW id */
|
||||
if (OF_getprop(fman_rxtx_node[1], "reg", (void *)&sc->sc_port_tx_hw_id,
|
||||
sizeof(sc->sc_port_tx_hw_id)) <= 0)
|
||||
if (sc->sc_base.sc_rx_port == NULL || sc->sc_base.sc_tx_port == NULL)
|
||||
return (ENXIO);
|
||||
|
||||
if (OF_getprop(fman_rxtx_node[1], "cell-index", &fman_tx_cell,
|
||||
sizeof(fman_tx_cell)) <= 0)
|
||||
return (ENXIO);
|
||||
/* Get QMan channel */
|
||||
sc->sc_port_tx_qman_chan = fman_qman_channel_id(device_get_parent(dev),
|
||||
sc->sc_base.sc_port_tx_qman_chan = fman_qman_channel_id(device_get_parent(dev),
|
||||
fman_tx_cell);
|
||||
|
||||
return (dtsec_attach(dev));
|
||||
|
||||
@@ -1,260 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2012 Semihalf.
|
||||
* 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 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/kernel.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/rman.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/sockio.h>
|
||||
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <net/if_media.h>
|
||||
#include <net/if_types.h>
|
||||
#include <net/if_arp.h>
|
||||
|
||||
#include <dev/mii/mii.h>
|
||||
#include <dev/mii/miivar.h>
|
||||
|
||||
#include "miibus_if.h"
|
||||
|
||||
#include <contrib/ncsw/inc/integrations/dpaa_integration_ext.h>
|
||||
#include <contrib/ncsw/inc/Peripherals/fm_mac_ext.h>
|
||||
#include <contrib/ncsw/inc/Peripherals/fm_port_ext.h>
|
||||
#include <contrib/ncsw/inc/xx_ext.h>
|
||||
|
||||
#include "fman.h"
|
||||
#include "if_dtsec.h"
|
||||
#include "if_dtsec_im.h"
|
||||
|
||||
|
||||
/**
|
||||
* @group dTSEC FMan PORT routines.
|
||||
* @{
|
||||
*/
|
||||
static e_RxStoreResponse
|
||||
dtsec_im_fm_port_rx_callback(t_Handle app, uint8_t *data, uint16_t length,
|
||||
uint16_t status, uint8_t position, t_Handle buf_context)
|
||||
{
|
||||
struct dtsec_softc *sc;
|
||||
struct mbuf *m;
|
||||
|
||||
/* TODO STATUS / Position checking */
|
||||
sc = app;
|
||||
|
||||
m = m_devget(data, length, 0, sc->sc_ifnet, NULL);
|
||||
if (m)
|
||||
if_input(sc->sc_ifnet, m);
|
||||
|
||||
XX_FreeSmart(data);
|
||||
|
||||
return (e_RX_STORE_RESPONSE_CONTINUE);
|
||||
}
|
||||
|
||||
static void
|
||||
dtsec_im_fm_port_tx_conf_callback(t_Handle app, uint8_t *data, uint16_t status,
|
||||
t_Handle buf_context)
|
||||
{
|
||||
|
||||
/* TODO: Check status */
|
||||
XX_FreeSmart(data);
|
||||
}
|
||||
|
||||
static uint8_t *
|
||||
dtsec_im_fm_port_rx_get_buf(t_Handle buffer_pool, t_Handle *buf_context_handle)
|
||||
{
|
||||
struct dtsec_softc *sc;
|
||||
uint8_t *buffer;
|
||||
|
||||
sc = buffer_pool;
|
||||
|
||||
buffer = XX_MallocSmart(FM_PORT_BUFFER_SIZE, 0, sizeof(void *));
|
||||
if (!buffer)
|
||||
device_printf(sc->sc_dev, "couldn't allocate RX buffer.\n");
|
||||
|
||||
return (buffer);
|
||||
}
|
||||
|
||||
static t_Error
|
||||
dtsec_im_fm_port_rx_put_buf(t_Handle buffer_pool, uint8_t *buffer,
|
||||
t_Handle buf_context)
|
||||
{
|
||||
|
||||
XX_FreeSmart(buffer);
|
||||
return (E_OK);
|
||||
}
|
||||
|
||||
int
|
||||
dtsec_im_fm_port_rx_init(struct dtsec_softc *sc, int unit)
|
||||
{
|
||||
t_FmPortParams params;
|
||||
t_BufferPoolInfo *pool_params;
|
||||
t_FmPortImRxTxParams *im_params;
|
||||
t_Error error;
|
||||
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
|
||||
params.baseAddr = sc->sc_fm_base + sc->sc_port_rx_hw_id;
|
||||
params.h_Fm = sc->sc_fmh;
|
||||
params.portType = dtsec_fm_port_rx_type(sc->sc_eth_dev_type);
|
||||
params.portId = sc->sc_eth_id;
|
||||
params.independentModeEnable = TRUE;
|
||||
params.liodnBase = FM_PORT_LIODN_BASE;
|
||||
params.f_Exception = dtsec_fm_port_rx_exception_callback;
|
||||
params.h_App = sc;
|
||||
|
||||
im_params = ¶ms.specificParams.imRxTxParams;
|
||||
im_params->h_FmMuram = sc->sc_muramh;
|
||||
im_params->liodnOffset = FM_PORT_LIODN_OFFSET;
|
||||
im_params->dataMemId = FM_PORT_MEM_ID;
|
||||
im_params->dataMemAttributes = FM_PORT_MEM_ATTR;
|
||||
im_params->f_RxStore = dtsec_im_fm_port_rx_callback;
|
||||
|
||||
pool_params = ¶ms.specificParams.imRxTxParams.rxPoolParams;
|
||||
pool_params->h_BufferPool = sc;
|
||||
pool_params->f_GetBuf = dtsec_im_fm_port_rx_get_buf;
|
||||
pool_params->f_PutBuf = dtsec_im_fm_port_rx_put_buf;
|
||||
pool_params->bufferSize = FM_PORT_BUFFER_SIZE;
|
||||
|
||||
sc->sc_rxph = FM_PORT_Config(¶ms);
|
||||
if (sc->sc_rxph == NULL) {
|
||||
device_printf(sc->sc_dev, "couldn't configure FM Port RX.\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
error = FM_PORT_Init(sc->sc_rxph);
|
||||
if (error != E_OK) {
|
||||
device_printf(sc->sc_dev, "couldn't initialize FM Port RX.\n");
|
||||
FM_PORT_Free(sc->sc_rxph);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
if (bootverbose)
|
||||
device_printf(sc->sc_dev, "RX hw port 0x%02x initialized.\n",
|
||||
sc->sc_port_rx_hw_id);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
dtsec_im_fm_port_tx_init(struct dtsec_softc *sc, int unit)
|
||||
{
|
||||
t_FmPortParams params;
|
||||
t_FmPortImRxTxParams *im_params;
|
||||
t_Error error;
|
||||
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
|
||||
params.baseAddr = sc->sc_fm_base + sc->sc_port_tx_hw_id;
|
||||
params.h_Fm = sc->sc_fmh;
|
||||
params.portType = dtsec_fm_port_tx_type(sc->sc_eth_dev_type);
|
||||
params.portId = unit;
|
||||
params.independentModeEnable = TRUE;
|
||||
params.liodnBase = FM_PORT_LIODN_BASE;
|
||||
params.f_Exception = dtsec_fm_port_tx_exception_callback;
|
||||
params.h_App = sc;
|
||||
|
||||
im_params = ¶ms.specificParams.imRxTxParams;
|
||||
im_params->h_FmMuram = sc->sc_muramh;
|
||||
im_params->liodnOffset = FM_PORT_LIODN_OFFSET;
|
||||
im_params->dataMemId = FM_PORT_MEM_ID;
|
||||
im_params->dataMemAttributes = FM_PORT_MEM_ATTR;
|
||||
im_params->f_TxConf = dtsec_im_fm_port_tx_conf_callback;
|
||||
|
||||
sc->sc_txph = FM_PORT_Config(¶ms);
|
||||
if (sc->sc_txph == NULL) {
|
||||
device_printf(sc->sc_dev, "couldn't configure FM Port TX.\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
error = FM_PORT_Init(sc->sc_txph);
|
||||
if (error != E_OK) {
|
||||
device_printf(sc->sc_dev, "couldn't initialize FM Port TX.\n");
|
||||
FM_PORT_Free(sc->sc_txph);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
if (bootverbose)
|
||||
device_printf(sc->sc_dev, "TX hw port 0x%02x initialized.\n",
|
||||
sc->sc_port_tx_hw_id);
|
||||
|
||||
return (0);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
|
||||
/**
|
||||
* @group dTSEC IFnet routines.
|
||||
* @{
|
||||
*/
|
||||
void
|
||||
dtsec_im_if_start_locked(struct dtsec_softc *sc)
|
||||
{
|
||||
uint8_t *buffer;
|
||||
uint16_t length;
|
||||
struct mbuf *m;
|
||||
int error;
|
||||
|
||||
DTSEC_LOCK_ASSERT(sc);
|
||||
/* TODO: IFF_DRV_OACTIVE */
|
||||
|
||||
if ((sc->sc_mii->mii_media_status & IFM_ACTIVE) == 0)
|
||||
return;
|
||||
|
||||
if ((if_getdrvflags(sc->sc_ifnet) & IFF_DRV_RUNNING) != IFF_DRV_RUNNING)
|
||||
return;
|
||||
|
||||
while (!if_sendq_empty(sc->sc_ifnet)) {
|
||||
m = if_dequeue(sc->sc_ifnet);
|
||||
if (m == NULL)
|
||||
break;
|
||||
|
||||
length = m_length(m, NULL);
|
||||
buffer = XX_MallocSmart(length, 0, sizeof(void *));
|
||||
if (!buffer) {
|
||||
m_freem(m);
|
||||
break;
|
||||
}
|
||||
|
||||
m_copydata(m, 0, length, buffer);
|
||||
m_freem(m);
|
||||
|
||||
error = FM_PORT_ImTx(sc->sc_txph, buffer, length, TRUE, buffer);
|
||||
if (error != E_OK) {
|
||||
/* TODO: Ring full */
|
||||
XX_FreeSmart(buffer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/** @} */
|
||||
@@ -1,39 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2012 Semihalf.
|
||||
* 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 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 IF_DTSEC_IM_H_
|
||||
#define IF_DTSEC_IM_H_
|
||||
|
||||
/**
|
||||
* @group dTSEC Independent Mode API.
|
||||
* @{
|
||||
*/
|
||||
int dtsec_im_fm_port_tx_init(struct dtsec_softc *sc, int unit);
|
||||
int dtsec_im_fm_port_rx_init(struct dtsec_softc *sc, int unit);
|
||||
void dtsec_im_if_start_locked(struct dtsec_softc *sc);
|
||||
/** @} */
|
||||
|
||||
#endif /* IF_DTSEC_IM_H_ */
|
||||
@@ -1,651 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2012 Semihalf.
|
||||
* 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 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/kernel.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/rman.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/sockio.h>
|
||||
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <net/if_media.h>
|
||||
#include <net/if_types.h>
|
||||
#include <net/if_arp.h>
|
||||
|
||||
#include <dev/mii/mii.h>
|
||||
#include <dev/mii/miivar.h>
|
||||
|
||||
#include "miibus_if.h"
|
||||
|
||||
#include <contrib/ncsw/inc/integrations/dpaa_integration_ext.h>
|
||||
#include <contrib/ncsw/inc/Peripherals/fm_ext.h>
|
||||
#include <contrib/ncsw/inc/Peripherals/fm_mac_ext.h>
|
||||
#include <contrib/ncsw/inc/Peripherals/fm_port_ext.h>
|
||||
#include <contrib/ncsw/inc/xx_ext.h>
|
||||
|
||||
#include "fman.h"
|
||||
#include "bman.h"
|
||||
#include "qman.h"
|
||||
#include "if_dtsec.h"
|
||||
#include "if_dtsec_rm.h"
|
||||
|
||||
|
||||
/**
|
||||
* @group dTSEC RM private defines.
|
||||
* @{
|
||||
*/
|
||||
#define DTSEC_BPOOLS_USED (1)
|
||||
#define DTSEC_MAX_TX_QUEUE_LEN 256
|
||||
|
||||
struct dtsec_rm_frame_info {
|
||||
struct mbuf *fi_mbuf;
|
||||
t_DpaaSGTE fi_sgt[DPAA_NUM_OF_SG_TABLE_ENTRY];
|
||||
};
|
||||
|
||||
enum dtsec_rm_pool_params {
|
||||
DTSEC_RM_POOL_RX_LOW_MARK = 16,
|
||||
DTSEC_RM_POOL_RX_HIGH_MARK = 64,
|
||||
DTSEC_RM_POOL_RX_MAX_SIZE = 256,
|
||||
|
||||
DTSEC_RM_POOL_FI_LOW_MARK = 16,
|
||||
DTSEC_RM_POOL_FI_HIGH_MARK = 64,
|
||||
DTSEC_RM_POOL_FI_MAX_SIZE = 256,
|
||||
};
|
||||
|
||||
#define DTSEC_RM_FQR_RX_CHANNEL e_QM_FQ_CHANNEL_POOL1
|
||||
#define DTSEC_RM_FQR_TX_CONF_CHANNEL e_QM_FQ_CHANNEL_SWPORTAL0
|
||||
enum dtsec_rm_fqr_params {
|
||||
DTSEC_RM_FQR_RX_WQ = 1,
|
||||
DTSEC_RM_FQR_TX_WQ = 1,
|
||||
DTSEC_RM_FQR_TX_CONF_WQ = 1
|
||||
};
|
||||
/** @} */
|
||||
|
||||
|
||||
/**
|
||||
* @group dTSEC Frame Info routines.
|
||||
* @{
|
||||
*/
|
||||
void
|
||||
dtsec_rm_fi_pool_free(struct dtsec_softc *sc)
|
||||
{
|
||||
|
||||
if (sc->sc_fi_zone != NULL)
|
||||
uma_zdestroy(sc->sc_fi_zone);
|
||||
}
|
||||
|
||||
int
|
||||
dtsec_rm_fi_pool_init(struct dtsec_softc *sc)
|
||||
{
|
||||
|
||||
snprintf(sc->sc_fi_zname, sizeof(sc->sc_fi_zname), "%s: Frame Info",
|
||||
device_get_nameunit(sc->sc_dev));
|
||||
|
||||
sc->sc_fi_zone = uma_zcreate(sc->sc_fi_zname,
|
||||
sizeof(struct dtsec_rm_frame_info), NULL, NULL, NULL, NULL,
|
||||
UMA_ALIGN_PTR, 0);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static struct dtsec_rm_frame_info *
|
||||
dtsec_rm_fi_alloc(struct dtsec_softc *sc)
|
||||
{
|
||||
struct dtsec_rm_frame_info *fi;
|
||||
|
||||
fi = uma_zalloc(sc->sc_fi_zone, M_NOWAIT);
|
||||
|
||||
return (fi);
|
||||
}
|
||||
|
||||
static void
|
||||
dtsec_rm_fi_free(struct dtsec_softc *sc, struct dtsec_rm_frame_info *fi)
|
||||
{
|
||||
|
||||
uma_zfree(sc->sc_fi_zone, fi);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
|
||||
/**
|
||||
* @group dTSEC FMan PORT routines.
|
||||
* @{
|
||||
*/
|
||||
int
|
||||
dtsec_rm_fm_port_rx_init(struct dtsec_softc *sc, int unit)
|
||||
{
|
||||
t_FmPortParams params;
|
||||
t_FmPortRxParams *rx_params;
|
||||
t_FmExtPools *pool_params;
|
||||
t_Error error;
|
||||
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
|
||||
params.baseAddr = sc->sc_fm_base + sc->sc_port_rx_hw_id;
|
||||
params.h_Fm = sc->sc_fmh;
|
||||
params.portType = dtsec_fm_port_rx_type(sc->sc_eth_dev_type);
|
||||
params.portId = sc->sc_eth_id;
|
||||
params.independentModeEnable = false;
|
||||
params.liodnBase = FM_PORT_LIODN_BASE;
|
||||
params.f_Exception = dtsec_fm_port_rx_exception_callback;
|
||||
params.h_App = sc;
|
||||
|
||||
rx_params = ¶ms.specificParams.rxParams;
|
||||
rx_params->errFqid = sc->sc_rx_fqid;
|
||||
rx_params->dfltFqid = sc->sc_rx_fqid;
|
||||
rx_params->liodnOffset = 0;
|
||||
|
||||
pool_params = &rx_params->extBufPools;
|
||||
pool_params->numOfPoolsUsed = DTSEC_BPOOLS_USED;
|
||||
pool_params->extBufPool->id = sc->sc_rx_bpid;
|
||||
pool_params->extBufPool->size = FM_PORT_BUFFER_SIZE;
|
||||
|
||||
sc->sc_rxph = FM_PORT_Config(¶ms);
|
||||
if (sc->sc_rxph == NULL) {
|
||||
device_printf(sc->sc_dev, "couldn't configure FM Port RX.\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
error = FM_PORT_Init(sc->sc_rxph);
|
||||
if (error != E_OK) {
|
||||
device_printf(sc->sc_dev, "couldn't initialize FM Port RX.\n");
|
||||
FM_PORT_Free(sc->sc_rxph);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
if (bootverbose)
|
||||
device_printf(sc->sc_dev, "RX hw port 0x%02x initialized.\n",
|
||||
sc->sc_port_rx_hw_id);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
dtsec_rm_fm_port_tx_init(struct dtsec_softc *sc, int unit)
|
||||
{
|
||||
t_FmPortParams params;
|
||||
t_FmPortNonRxParams *tx_params;
|
||||
t_Error error;
|
||||
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
|
||||
params.baseAddr = sc->sc_fm_base + sc->sc_port_tx_hw_id;
|
||||
params.h_Fm = sc->sc_fmh;
|
||||
params.portType = dtsec_fm_port_tx_type(sc->sc_eth_dev_type);
|
||||
params.portId = sc->sc_eth_id;
|
||||
params.independentModeEnable = false;
|
||||
params.liodnBase = FM_PORT_LIODN_BASE;
|
||||
params.f_Exception = dtsec_fm_port_tx_exception_callback;
|
||||
params.h_App = sc;
|
||||
|
||||
tx_params = ¶ms.specificParams.nonRxParams;
|
||||
tx_params->errFqid = sc->sc_tx_conf_fqid;
|
||||
tx_params->dfltFqid = sc->sc_tx_conf_fqid;
|
||||
tx_params->qmChannel = sc->sc_port_tx_qman_chan;
|
||||
#ifdef FM_OP_PARTITION_ERRATA_FMANx8
|
||||
tx_params->opLiodnOffset = 0;
|
||||
#endif
|
||||
|
||||
sc->sc_txph = FM_PORT_Config(¶ms);
|
||||
if (sc->sc_txph == NULL) {
|
||||
device_printf(sc->sc_dev, "couldn't configure FM Port TX.\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
error = FM_PORT_Init(sc->sc_txph);
|
||||
if (error != E_OK) {
|
||||
device_printf(sc->sc_dev, "couldn't initialize FM Port TX.\n");
|
||||
FM_PORT_Free(sc->sc_txph);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
if (bootverbose)
|
||||
device_printf(sc->sc_dev, "TX hw port 0x%02x initialized.\n",
|
||||
sc->sc_port_tx_hw_id);
|
||||
|
||||
return (0);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
|
||||
/**
|
||||
* @group dTSEC buffer pools routines.
|
||||
* @{
|
||||
*/
|
||||
static t_Error
|
||||
dtsec_rm_pool_rx_put_buffer(t_Handle h_BufferPool, uint8_t *buffer,
|
||||
t_Handle context)
|
||||
{
|
||||
struct dtsec_softc *sc;
|
||||
|
||||
sc = h_BufferPool;
|
||||
uma_zfree(sc->sc_rx_zone, buffer);
|
||||
|
||||
return (E_OK);
|
||||
}
|
||||
|
||||
static uint8_t *
|
||||
dtsec_rm_pool_rx_get_buffer(t_Handle h_BufferPool, t_Handle *context)
|
||||
{
|
||||
struct dtsec_softc *sc;
|
||||
uint8_t *buffer;
|
||||
|
||||
sc = h_BufferPool;
|
||||
buffer = uma_zalloc(sc->sc_rx_zone, M_NOWAIT);
|
||||
|
||||
return (buffer);
|
||||
}
|
||||
|
||||
static void
|
||||
dtsec_rm_pool_rx_depleted(t_Handle h_App, bool in)
|
||||
{
|
||||
struct dtsec_softc *sc;
|
||||
unsigned int count;
|
||||
|
||||
sc = h_App;
|
||||
|
||||
if (!in)
|
||||
return;
|
||||
|
||||
while (1) {
|
||||
count = bman_count(sc->sc_rx_pool);
|
||||
if (count > DTSEC_RM_POOL_RX_HIGH_MARK)
|
||||
return;
|
||||
|
||||
bman_pool_fill(sc->sc_rx_pool, DTSEC_RM_POOL_RX_HIGH_MARK);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dtsec_rm_pool_rx_free(struct dtsec_softc *sc)
|
||||
{
|
||||
|
||||
if (sc->sc_rx_pool != NULL)
|
||||
bman_pool_destroy(sc->sc_rx_pool);
|
||||
|
||||
if (sc->sc_rx_zone != NULL)
|
||||
uma_zdestroy(sc->sc_rx_zone);
|
||||
}
|
||||
|
||||
int
|
||||
dtsec_rm_pool_rx_init(struct dtsec_softc *sc)
|
||||
{
|
||||
|
||||
/* FM_PORT_BUFFER_SIZE must be less than PAGE_SIZE */
|
||||
CTASSERT(FM_PORT_BUFFER_SIZE < PAGE_SIZE);
|
||||
|
||||
snprintf(sc->sc_rx_zname, sizeof(sc->sc_rx_zname), "%s: RX Buffers",
|
||||
device_get_nameunit(sc->sc_dev));
|
||||
|
||||
sc->sc_rx_zone = uma_zcreate(sc->sc_rx_zname, FM_PORT_BUFFER_SIZE, NULL,
|
||||
NULL, NULL, NULL, FM_PORT_BUFFER_SIZE - 1, 0);
|
||||
|
||||
sc->sc_rx_pool = bman_pool_create(&sc->sc_rx_bpid, FM_PORT_BUFFER_SIZE,
|
||||
0, 0, DTSEC_RM_POOL_RX_MAX_SIZE, dtsec_rm_pool_rx_get_buffer,
|
||||
dtsec_rm_pool_rx_put_buffer, DTSEC_RM_POOL_RX_LOW_MARK,
|
||||
DTSEC_RM_POOL_RX_HIGH_MARK, 0, 0, dtsec_rm_pool_rx_depleted, sc, NULL,
|
||||
NULL);
|
||||
if (sc->sc_rx_pool == NULL) {
|
||||
device_printf(sc->sc_dev, "NULL rx pool somehow\n");
|
||||
dtsec_rm_pool_rx_free(sc);
|
||||
return (EIO);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
|
||||
/**
|
||||
* @group dTSEC Frame Queue Range routines.
|
||||
* @{
|
||||
*/
|
||||
static void
|
||||
dtsec_rm_fqr_mext_free(struct mbuf *m)
|
||||
{
|
||||
struct dtsec_softc *sc;
|
||||
void *buffer;
|
||||
|
||||
buffer = m->m_ext.ext_arg1;
|
||||
sc = m->m_ext.ext_arg2;
|
||||
if (bman_count(sc->sc_rx_pool) <= DTSEC_RM_POOL_RX_MAX_SIZE)
|
||||
bman_put_buffer(sc->sc_rx_pool, buffer);
|
||||
else
|
||||
dtsec_rm_pool_rx_put_buffer(sc, buffer, NULL);
|
||||
}
|
||||
|
||||
static e_RxStoreResponse
|
||||
dtsec_rm_fqr_rx_callback(t_Handle app, t_Handle fqr, t_Handle portal,
|
||||
uint32_t fqid_off, t_DpaaFD *frame)
|
||||
{
|
||||
struct dtsec_softc *sc;
|
||||
struct mbuf *m;
|
||||
void *frame_va;
|
||||
|
||||
m = NULL;
|
||||
sc = app;
|
||||
|
||||
frame_va = DPAA_FD_GET_ADDR(frame);
|
||||
KASSERT(DPAA_FD_GET_FORMAT(frame) == e_DPAA_FD_FORMAT_TYPE_SHORT_SBSF,
|
||||
("%s(): Got unsupported frame format 0x%02X!", __func__,
|
||||
DPAA_FD_GET_FORMAT(frame)));
|
||||
|
||||
KASSERT(DPAA_FD_GET_OFFSET(frame) == 0,
|
||||
("%s(): Only offset 0 is supported!", __func__));
|
||||
|
||||
if (DPAA_FD_GET_STATUS(frame) != 0) {
|
||||
device_printf(sc->sc_dev, "RX error: 0x%08X\n",
|
||||
DPAA_FD_GET_STATUS(frame));
|
||||
goto err;
|
||||
}
|
||||
|
||||
m = m_gethdr(M_NOWAIT, MT_HEADER);
|
||||
if (m == NULL)
|
||||
goto err;
|
||||
|
||||
m_extadd(m, frame_va, FM_PORT_BUFFER_SIZE,
|
||||
dtsec_rm_fqr_mext_free, frame_va, sc, 0,
|
||||
EXT_NET_DRV);
|
||||
|
||||
m->m_pkthdr.rcvif = sc->sc_ifnet;
|
||||
m->m_len = DPAA_FD_GET_LENGTH(frame);
|
||||
m_fixhdr(m);
|
||||
|
||||
if_input(sc->sc_ifnet, m);
|
||||
|
||||
return (e_RX_STORE_RESPONSE_CONTINUE);
|
||||
|
||||
err:
|
||||
bman_put_buffer(sc->sc_rx_pool, frame_va);
|
||||
if (m != NULL)
|
||||
m_freem(m);
|
||||
|
||||
return (e_RX_STORE_RESPONSE_CONTINUE);
|
||||
}
|
||||
|
||||
static e_RxStoreResponse
|
||||
dtsec_rm_fqr_tx_confirm_callback(t_Handle app, t_Handle fqr, t_Handle portal,
|
||||
uint32_t fqid_off, t_DpaaFD *frame)
|
||||
{
|
||||
struct dtsec_rm_frame_info *fi;
|
||||
struct dtsec_softc *sc;
|
||||
unsigned int qlen;
|
||||
t_DpaaSGTE *sgt0;
|
||||
|
||||
sc = app;
|
||||
|
||||
if (DPAA_FD_GET_STATUS(frame) != 0)
|
||||
device_printf(sc->sc_dev, "TX error: 0x%08X\n",
|
||||
DPAA_FD_GET_STATUS(frame));
|
||||
|
||||
/*
|
||||
* We are storing struct dtsec_rm_frame_info in first entry
|
||||
* of scatter-gather table.
|
||||
*/
|
||||
sgt0 = DPAA_FD_GET_ADDR(frame);
|
||||
fi = DPAA_SGTE_GET_ADDR(sgt0);
|
||||
|
||||
/* Free transmitted frame */
|
||||
m_freem(fi->fi_mbuf);
|
||||
dtsec_rm_fi_free(sc, fi);
|
||||
|
||||
qlen = qman_fqr_get_counter(sc->sc_tx_conf_fqr, 0,
|
||||
e_QM_FQR_COUNTERS_FRAME);
|
||||
|
||||
if (qlen == 0) {
|
||||
DTSEC_LOCK(sc);
|
||||
|
||||
if (sc->sc_tx_fqr_full) {
|
||||
sc->sc_tx_fqr_full = 0;
|
||||
dtsec_rm_if_start_locked(sc);
|
||||
}
|
||||
|
||||
DTSEC_UNLOCK(sc);
|
||||
}
|
||||
|
||||
return (e_RX_STORE_RESPONSE_CONTINUE);
|
||||
}
|
||||
|
||||
void
|
||||
dtsec_rm_fqr_rx_free(struct dtsec_softc *sc)
|
||||
{
|
||||
|
||||
if (sc->sc_rx_fqr)
|
||||
qman_fqr_free(sc->sc_rx_fqr);
|
||||
}
|
||||
|
||||
int
|
||||
dtsec_rm_fqr_rx_init(struct dtsec_softc *sc)
|
||||
{
|
||||
t_Error error;
|
||||
t_Handle fqr;
|
||||
|
||||
/* Default Frame Queue */
|
||||
fqr = qman_fqr_create(1, DTSEC_RM_FQR_RX_CHANNEL, DTSEC_RM_FQR_RX_WQ,
|
||||
false, 0, false, false, true, false, 0, 0, 0);
|
||||
if (fqr == NULL) {
|
||||
device_printf(sc->sc_dev, "could not create default RX queue"
|
||||
"\n");
|
||||
return (EIO);
|
||||
}
|
||||
|
||||
sc->sc_rx_fqr = fqr;
|
||||
sc->sc_rx_fqid = qman_fqr_get_base_fqid(fqr);
|
||||
|
||||
error = qman_fqr_register_cb(fqr, dtsec_rm_fqr_rx_callback, sc);
|
||||
if (error != E_OK) {
|
||||
device_printf(sc->sc_dev, "could not register RX callback\n");
|
||||
dtsec_rm_fqr_rx_free(sc);
|
||||
return (EIO);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
dtsec_rm_fqr_tx_free(struct dtsec_softc *sc)
|
||||
{
|
||||
|
||||
if (sc->sc_tx_fqr)
|
||||
qman_fqr_free(sc->sc_tx_fqr);
|
||||
|
||||
if (sc->sc_tx_conf_fqr)
|
||||
qman_fqr_free(sc->sc_tx_conf_fqr);
|
||||
}
|
||||
|
||||
int
|
||||
dtsec_rm_fqr_tx_init(struct dtsec_softc *sc)
|
||||
{
|
||||
t_Error error;
|
||||
t_Handle fqr;
|
||||
|
||||
/* TX Frame Queue */
|
||||
fqr = qman_fqr_create(1, sc->sc_port_tx_qman_chan,
|
||||
DTSEC_RM_FQR_TX_WQ, false, 0, false, false, true, false, 0, 0, 0);
|
||||
if (fqr == NULL) {
|
||||
device_printf(sc->sc_dev, "could not create default TX queue"
|
||||
"\n");
|
||||
return (EIO);
|
||||
}
|
||||
|
||||
sc->sc_tx_fqr = fqr;
|
||||
|
||||
/* TX Confirmation Frame Queue */
|
||||
fqr = qman_fqr_create(1, DTSEC_RM_FQR_TX_CONF_CHANNEL,
|
||||
DTSEC_RM_FQR_TX_CONF_WQ, false, 0, false, false, true, false, 0, 0,
|
||||
0);
|
||||
if (fqr == NULL) {
|
||||
device_printf(sc->sc_dev, "could not create TX confirmation "
|
||||
"queue\n");
|
||||
dtsec_rm_fqr_tx_free(sc);
|
||||
return (EIO);
|
||||
}
|
||||
|
||||
sc->sc_tx_conf_fqr = fqr;
|
||||
sc->sc_tx_conf_fqid = qman_fqr_get_base_fqid(fqr);
|
||||
|
||||
error = qman_fqr_register_cb(fqr, dtsec_rm_fqr_tx_confirm_callback, sc);
|
||||
if (error != E_OK) {
|
||||
device_printf(sc->sc_dev, "could not register TX confirmation "
|
||||
"callback\n");
|
||||
dtsec_rm_fqr_tx_free(sc);
|
||||
return (EIO);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
|
||||
/**
|
||||
* @group dTSEC IFnet routines.
|
||||
* @{
|
||||
*/
|
||||
void
|
||||
dtsec_rm_if_start_locked(struct dtsec_softc *sc)
|
||||
{
|
||||
vm_size_t dsize, psize, ssize;
|
||||
struct dtsec_rm_frame_info *fi;
|
||||
unsigned int qlen, i;
|
||||
struct mbuf *m0, *m;
|
||||
vm_offset_t vaddr;
|
||||
t_DpaaFD fd;
|
||||
|
||||
DTSEC_LOCK_ASSERT(sc);
|
||||
/* TODO: IFF_DRV_OACTIVE */
|
||||
|
||||
if ((sc->sc_mii->mii_media_status & IFM_ACTIVE) == 0)
|
||||
return;
|
||||
|
||||
if ((if_getdrvflags(sc->sc_ifnet) & IFF_DRV_RUNNING) != IFF_DRV_RUNNING)
|
||||
return;
|
||||
|
||||
while (!if_sendq_empty(sc->sc_ifnet)) {
|
||||
/* Check length of the TX queue */
|
||||
qlen = qman_fqr_get_counter(sc->sc_tx_fqr, 0,
|
||||
e_QM_FQR_COUNTERS_FRAME);
|
||||
|
||||
if (qlen >= DTSEC_MAX_TX_QUEUE_LEN) {
|
||||
sc->sc_tx_fqr_full = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
fi = dtsec_rm_fi_alloc(sc);
|
||||
if (fi == NULL)
|
||||
return;
|
||||
|
||||
m0 = if_dequeue(sc->sc_ifnet);
|
||||
if (m0 == NULL) {
|
||||
dtsec_rm_fi_free(sc, fi);
|
||||
return;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
m = m0;
|
||||
psize = 0;
|
||||
dsize = 0;
|
||||
fi->fi_mbuf = m0;
|
||||
while (m && i < DPAA_NUM_OF_SG_TABLE_ENTRY) {
|
||||
if (m->m_len == 0)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* First entry in scatter-gather table is used to keep
|
||||
* pointer to frame info structure.
|
||||
*/
|
||||
DPAA_SGTE_SET_ADDR(&fi->fi_sgt[i], (void *)fi);
|
||||
DPAA_SGTE_SET_LENGTH(&fi->fi_sgt[i], 0);
|
||||
|
||||
DPAA_SGTE_SET_EXTENSION(&fi->fi_sgt[i], 0);
|
||||
DPAA_SGTE_SET_FINAL(&fi->fi_sgt[i], 0);
|
||||
DPAA_SGTE_SET_BPID(&fi->fi_sgt[i], 0);
|
||||
DPAA_SGTE_SET_OFFSET(&fi->fi_sgt[i], 0);
|
||||
i++;
|
||||
|
||||
dsize = m->m_len;
|
||||
vaddr = (vm_offset_t)m->m_data;
|
||||
while (dsize > 0 && i < DPAA_NUM_OF_SG_TABLE_ENTRY) {
|
||||
ssize = PAGE_SIZE - (vaddr & PAGE_MASK);
|
||||
if (m->m_len < ssize)
|
||||
ssize = m->m_len;
|
||||
|
||||
DPAA_SGTE_SET_ADDR(&fi->fi_sgt[i],
|
||||
(void *)vaddr);
|
||||
DPAA_SGTE_SET_LENGTH(&fi->fi_sgt[i], ssize);
|
||||
|
||||
DPAA_SGTE_SET_EXTENSION(&fi->fi_sgt[i], 0);
|
||||
DPAA_SGTE_SET_FINAL(&fi->fi_sgt[i], 0);
|
||||
DPAA_SGTE_SET_BPID(&fi->fi_sgt[i], 0);
|
||||
DPAA_SGTE_SET_OFFSET(&fi->fi_sgt[i], 0);
|
||||
|
||||
dsize -= ssize;
|
||||
vaddr += ssize;
|
||||
psize += ssize;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (dsize > 0)
|
||||
break;
|
||||
|
||||
m = m->m_next;
|
||||
}
|
||||
|
||||
/* Check if SG table was constructed properly */
|
||||
if (m != NULL || dsize != 0) {
|
||||
dtsec_rm_fi_free(sc, fi);
|
||||
m_freem(m0);
|
||||
continue;
|
||||
}
|
||||
|
||||
DPAA_SGTE_SET_FINAL(&fi->fi_sgt[i-1], 1);
|
||||
|
||||
DPAA_FD_SET_ADDR(&fd, fi->fi_sgt);
|
||||
DPAA_FD_SET_LENGTH(&fd, psize);
|
||||
DPAA_FD_SET_FORMAT(&fd, e_DPAA_FD_FORMAT_TYPE_SHORT_MBSF);
|
||||
|
||||
fd.liodn = 0;
|
||||
fd.bpid = 0;
|
||||
fd.elion = 0;
|
||||
DPAA_FD_SET_OFFSET(&fd, 0);
|
||||
DPAA_FD_SET_STATUS(&fd, 0);
|
||||
|
||||
DTSEC_UNLOCK(sc);
|
||||
if (qman_fqr_enqueue(sc->sc_tx_fqr, 0, &fd) != E_OK) {
|
||||
dtsec_rm_fi_free(sc, fi);
|
||||
m_freem(m0);
|
||||
}
|
||||
DTSEC_LOCK(sc);
|
||||
}
|
||||
}
|
||||
/** @} */
|
||||
@@ -0,0 +1,802 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2026 Justin Hibbits
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/rman.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/sockio.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
#include <machine/resource.h>
|
||||
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <net/if_media.h>
|
||||
#include <net/if_types.h>
|
||||
#include <net/if_arp.h>
|
||||
|
||||
#include <dev/mii/mii.h>
|
||||
#include <dev/mii/miivar.h>
|
||||
#include <dev/ofw/ofw_bus.h>
|
||||
#include <dev/ofw/ofw_bus_subr.h>
|
||||
#include <dev/ofw/openfirm.h>
|
||||
|
||||
#include "miibus_if.h"
|
||||
|
||||
#include "dpaa_eth.h"
|
||||
#include "fman.h"
|
||||
#include "fman_port.h"
|
||||
#include "if_memac.h"
|
||||
|
||||
#include "fman_if.h"
|
||||
#include "fman_port_if.h"
|
||||
|
||||
#define MEMAC_MIN_FRAME_SIZE 64
|
||||
#define MEMAC_MAX_FRAME_SIZE 32736
|
||||
|
||||
#define MEMAC_COMMAND_CONFIG 0x008
|
||||
#define COMMAND_CONFIG_RXSTP 0x20000000
|
||||
#define COMMAND_CONFIG_NO_LEN_CHK 0x00020000
|
||||
#define COMMAND_CONFIG_SWR 0x00001000
|
||||
#define COMMAND_CONFIG_TXP 0x00000800
|
||||
#define COMMAND_CONFIG_CRC 0x00000040
|
||||
#define COMMAND_CONFIG_PROMISC 0x00000010
|
||||
#define COMMAND_CONFIG_RX_EN 0x00000002
|
||||
#define COMMAND_CONFIG_TX_EN 0x00000001
|
||||
#define MEMAC_MAC_ADDR_0 0x00c
|
||||
#define MEMAC_MAC_ADDR_1 0x010
|
||||
#define MEMAC_REG_MAXFRM 0x14
|
||||
#define MEMAC_REG_TX_FIFO_SECTIONS 0x020
|
||||
#define TX_FIFO_SECTIONS_TX_EMPTY_M 0xffff0000
|
||||
#define TX_FIFO_SECTIONS_TX_EMPTY_S 16
|
||||
#define TX_FIFO_SECTIONS_TX_AVAIL_M 0x0000ffff
|
||||
|
||||
#define HASHTABLE_CTRL 0x02c
|
||||
#define CTRL_MCAST 0x00000100
|
||||
#define CTRL_HASH_ADDR_M 0x0000003f
|
||||
#define HASHTABLE_SIZE 64
|
||||
#define MEMAC_IEVENT 0x040
|
||||
#define IEVENT_RX_EMPTY 0x00000040
|
||||
#define IEVENT_TX_EMPTY 0x00000020
|
||||
#define MEMAC_CL01_PAUSE_QUANTA 0x054
|
||||
#define MEMAC_IF_MODE 0x300
|
||||
#define IF_MODE_ENA 0x00008000
|
||||
#define IF_MODE_SSP_M 0x00006000
|
||||
#define IF_MODE_SSP_100MB 0x00000000
|
||||
#define IF_MODE_SSP_10MB 0x00002000
|
||||
#define IF_MODE_SSP_1GB 0x00004000
|
||||
#define IF_MODE_SFD 0x00001000
|
||||
#define IF_MODE_MSG 0x00000200
|
||||
#define IF_MODE_HG 0x00000100
|
||||
#define IF_MODE_HD 0x00000040
|
||||
#define IF_MODE_RLP 0x00000020
|
||||
#define IF_MODE_RG 0x00000004
|
||||
#define IF_MODE_IFMODE_M 0x00000003
|
||||
#define IF_MODE_IFMODE_XGMII 0x00000000
|
||||
#define IF_MODE_IFMODE_MII 0x00000001
|
||||
#define IF_MODE_IFMODE_GMII 0x00000002
|
||||
|
||||
#define DEFAULT_PAUSE_QUANTA 0xf000
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @group FMan MAC routines.
|
||||
* @{
|
||||
*/
|
||||
#define MEMAC_MAC_EXCEPTIONS_END (-1)
|
||||
|
||||
static void memac_if_init_locked(struct memac_softc *sc);
|
||||
|
||||
static int
|
||||
memac_fm_mac_init(struct memac_softc *sc, uint8_t *mac)
|
||||
{
|
||||
uint32_t reg;
|
||||
|
||||
FMAN_GET_REVISION(device_get_parent(sc->sc_base.sc_dev), &sc->sc_base.sc_rev_major,
|
||||
&sc->sc_base.sc_rev_minor);
|
||||
|
||||
if (FMAN_RESET_MAC(device_get_parent(sc->sc_base.sc_dev), sc->sc_base.sc_eth_id) != 0)
|
||||
return (ENXIO);
|
||||
|
||||
reg = bus_read_4(sc->sc_base.sc_mem, MEMAC_COMMAND_CONFIG);
|
||||
reg |= COMMAND_CONFIG_SWR;
|
||||
bus_write_4(sc->sc_base.sc_mem, MEMAC_COMMAND_CONFIG, reg);
|
||||
|
||||
while (bus_read_4(sc->sc_base.sc_mem, MEMAC_COMMAND_CONFIG) & COMMAND_CONFIG_SWR)
|
||||
;
|
||||
|
||||
/* TODO: TX_FIFO_SECTIONS */
|
||||
/* TODO: CL01 pause quantum */
|
||||
bus_write_4(sc->sc_base.sc_mem, MEMAC_COMMAND_CONFIG,
|
||||
COMMAND_CONFIG_NO_LEN_CHK | COMMAND_CONFIG_TXP | COMMAND_CONFIG_CRC);
|
||||
|
||||
reg = bus_read_4(sc->sc_base.sc_mem, MEMAC_IF_MODE);
|
||||
reg &= ~(IF_MODE_IFMODE_M | IF_MODE_RG);
|
||||
switch (sc->sc_base.sc_mac_enet_mode) {
|
||||
case MII_CONTYPE_RGMII:
|
||||
reg |= IF_MODE_RG;
|
||||
/* FALLTHROUGH */
|
||||
case MII_CONTYPE_GMII:
|
||||
case MII_CONTYPE_SGMII:
|
||||
case MII_CONTYPE_QSGMII:
|
||||
reg |= IF_MODE_IFMODE_GMII;
|
||||
break;
|
||||
case MII_CONTYPE_RMII:
|
||||
reg |= IF_MODE_RG;
|
||||
/* FALLTHROUGH */
|
||||
case MII_CONTYPE_MII:
|
||||
reg |= IF_MODE_IFMODE_MII;
|
||||
break;
|
||||
}
|
||||
|
||||
bus_write_4(sc->sc_base.sc_mem, MEMAC_IF_MODE, reg);
|
||||
|
||||
return (0);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
|
||||
/**
|
||||
* @group IFnet routines.
|
||||
* @{
|
||||
*/
|
||||
static int
|
||||
memac_set_mtu(struct memac_softc *sc, unsigned int mtu)
|
||||
{
|
||||
|
||||
mtu += ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN + ETHER_CRC_LEN;
|
||||
|
||||
MEMAC_LOCK_ASSERT(sc);
|
||||
|
||||
if (mtu >= MEMAC_MIN_FRAME_SIZE && mtu <= MEMAC_MAX_FRAME_SIZE) {
|
||||
bus_write_4(sc->sc_base.sc_mem, MEMAC_REG_MAXFRM, mtu);
|
||||
return (mtu);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static u_int
|
||||
memac_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt)
|
||||
{
|
||||
struct memac_softc *sc = arg;
|
||||
uint8_t *addr = LLADDR(sdl);
|
||||
uint32_t hash = 0;
|
||||
uint8_t a, h;
|
||||
|
||||
/* Hash is 6 bits, composed if [XOR{47:40},XOR{39:32},....] */
|
||||
for (int i = 0; i < 6; i++) {
|
||||
a = addr[i];
|
||||
h = 0;
|
||||
for (int j = 0; j < 8; j++, a >>= 1) {
|
||||
h ^= (a & 0x1);
|
||||
}
|
||||
hash |= (h << i);
|
||||
}
|
||||
bus_write_4(sc->sc_base.sc_mem, HASHTABLE_CTRL, hash | CTRL_MCAST);
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
static void
|
||||
memac_setup_multicast(struct memac_softc *sc)
|
||||
{
|
||||
|
||||
if (if_getflags(sc->sc_base.sc_ifnet) & IFF_ALLMULTI) {
|
||||
for (int i = 0; i < HASHTABLE_SIZE; i++)
|
||||
bus_write_4(sc->sc_base.sc_mem,
|
||||
HASHTABLE_CTRL, CTRL_MCAST | i);
|
||||
} else {
|
||||
/* Clear the hash table */
|
||||
for (int i = 0; i < HASHTABLE_SIZE; i++)
|
||||
bus_write_4(sc->sc_base.sc_mem,
|
||||
HASHTABLE_CTRL, i);
|
||||
}
|
||||
|
||||
if_foreach_llmaddr(sc->sc_base.sc_ifnet, memac_hash_maddr, sc);
|
||||
}
|
||||
|
||||
static void
|
||||
memac_setup_promisc(struct memac_softc *sc)
|
||||
{
|
||||
uint32_t reg;
|
||||
|
||||
reg = bus_read_4(sc->sc_base.sc_mem, MEMAC_COMMAND_CONFIG);
|
||||
reg &= ~COMMAND_CONFIG_PROMISC;
|
||||
|
||||
if ((if_getflags(sc->sc_base.sc_ifnet) & IFF_PROMISC) != 0)
|
||||
bus_write_4(sc->sc_base.sc_mem, MEMAC_COMMAND_CONFIG,
|
||||
reg | COMMAND_CONFIG_PROMISC);
|
||||
}
|
||||
|
||||
static void
|
||||
memac_if_graceful_stop(struct memac_softc *sc)
|
||||
{
|
||||
struct resource *regs = sc->sc_base.sc_mem;
|
||||
uint32_t reg;
|
||||
|
||||
reg = bus_read_4(regs, MEMAC_COMMAND_CONFIG);
|
||||
reg |= COMMAND_CONFIG_RXSTP;
|
||||
|
||||
bus_write_4(regs, MEMAC_COMMAND_CONFIG, reg);
|
||||
while ((bus_read_4(regs, MEMAC_IEVENT) & IEVENT_RX_EMPTY) == 0)
|
||||
;
|
||||
reg &= COMMAND_CONFIG_RX_EN;
|
||||
bus_write_4(regs, MEMAC_COMMAND_CONFIG, reg);
|
||||
|
||||
while ((bus_read_4(regs, MEMAC_IEVENT) & IEVENT_TX_EMPTY) == 0)
|
||||
;
|
||||
bus_write_4(regs, MEMAC_COMMAND_CONFIG, reg & ~COMMAND_CONFIG_TX_EN);
|
||||
}
|
||||
|
||||
static void
|
||||
memac_mac_enable(struct memac_softc *sc)
|
||||
{
|
||||
uint32_t reg = bus_read_4(sc->sc_base.sc_mem, MEMAC_COMMAND_CONFIG);
|
||||
|
||||
reg |= (COMMAND_CONFIG_RX_EN | COMMAND_CONFIG_TX_EN);
|
||||
|
||||
bus_write_4(sc->sc_base.sc_mem, MEMAC_COMMAND_CONFIG, reg);
|
||||
}
|
||||
|
||||
static int
|
||||
memac_if_enable_locked(struct memac_softc *sc)
|
||||
{
|
||||
int error;
|
||||
|
||||
MEMAC_LOCK_ASSERT(sc);
|
||||
|
||||
memac_set_mtu(sc, if_getmtu(sc->sc_base.sc_ifnet));
|
||||
memac_mac_enable(sc);
|
||||
|
||||
error = FMAN_PORT_ENABLE(sc->sc_base.sc_rx_port);
|
||||
if (error != 0)
|
||||
return (EIO);
|
||||
|
||||
error = FMAN_PORT_ENABLE(sc->sc_base.sc_tx_port);
|
||||
if (error != 0)
|
||||
return (EIO);
|
||||
|
||||
bus_write_4(sc->sc_base.sc_mem, MEMAC_IEVENT, 0);
|
||||
memac_setup_multicast(sc);
|
||||
memac_setup_promisc(sc);
|
||||
|
||||
if_setdrvflagbits(sc->sc_base.sc_ifnet, IFF_DRV_RUNNING, 0);
|
||||
|
||||
/* Refresh link state */
|
||||
memac_miibus_statchg(sc->sc_base.sc_dev);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
memac_if_disable_locked(struct memac_softc *sc)
|
||||
{
|
||||
int error;
|
||||
|
||||
MEMAC_LOCK_ASSERT(sc);
|
||||
|
||||
error = FMAN_PORT_DISABLE(sc->sc_base.sc_tx_port);
|
||||
if (error != 0)
|
||||
return (EIO);
|
||||
|
||||
memac_if_graceful_stop(sc);
|
||||
|
||||
error = FMAN_PORT_DISABLE(sc->sc_base.sc_rx_port);
|
||||
if (error != 0)
|
||||
return (EIO);
|
||||
|
||||
if_setdrvflagbits(sc->sc_base.sc_ifnet, 0, IFF_DRV_RUNNING);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
memac_if_ioctl(if_t ifp, u_long command, caddr_t data)
|
||||
{
|
||||
struct memac_softc *sc;
|
||||
struct ifreq *ifr;
|
||||
int error;
|
||||
|
||||
sc = if_getsoftc(ifp);
|
||||
ifr = (struct ifreq *)data;
|
||||
error = 0;
|
||||
|
||||
/* Basic functionality to achieve media status reports */
|
||||
switch (command) {
|
||||
case SIOCSIFMTU:
|
||||
MEMAC_LOCK(sc);
|
||||
if (memac_set_mtu(sc, ifr->ifr_mtu))
|
||||
if_setmtu(ifp, ifr->ifr_mtu);
|
||||
else
|
||||
error = EINVAL;
|
||||
MEMAC_UNLOCK(sc);
|
||||
break;
|
||||
case SIOCSIFFLAGS:
|
||||
MEMAC_LOCK(sc);
|
||||
if (if_getflags(ifp) & IFF_UP) {
|
||||
if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING))
|
||||
memac_if_init_locked(sc);
|
||||
} else if (if_getdrvflags(ifp) & IFF_DRV_RUNNING)
|
||||
error = memac_if_disable_locked(sc);
|
||||
|
||||
MEMAC_UNLOCK(sc);
|
||||
break;
|
||||
|
||||
case SIOCADDMULTI:
|
||||
case SIOCDELMULTI:
|
||||
if (if_getflags(sc->sc_base.sc_ifnet) & IFF_UP) {
|
||||
MEMAC_LOCK(sc);
|
||||
memac_setup_multicast(sc);
|
||||
MEMAC_UNLOCK(sc);
|
||||
}
|
||||
break;
|
||||
|
||||
case SIOCGIFMEDIA:
|
||||
case SIOCSIFMEDIA:
|
||||
error = ifmedia_ioctl(ifp, ifr, &sc->sc_base.sc_mii->mii_media,
|
||||
command);
|
||||
break;
|
||||
|
||||
default:
|
||||
error = ether_ioctl(ifp, command, data);
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
static void
|
||||
memac_if_tick(void *arg)
|
||||
{
|
||||
struct memac_softc *sc;
|
||||
|
||||
sc = arg;
|
||||
|
||||
/* TODO */
|
||||
MEMAC_LOCK(sc);
|
||||
|
||||
mii_tick(sc->sc_base.sc_mii);
|
||||
callout_reset(&sc->sc_base.sc_tick_callout, hz, memac_if_tick, sc);
|
||||
|
||||
MEMAC_UNLOCK(sc);
|
||||
}
|
||||
|
||||
static void
|
||||
memac_if_deinit_locked(struct memac_softc *sc)
|
||||
{
|
||||
|
||||
MEMAC_LOCK_ASSERT(sc);
|
||||
|
||||
MEMAC_UNLOCK(sc);
|
||||
callout_drain(&sc->sc_base.sc_tick_callout);
|
||||
MEMAC_LOCK(sc);
|
||||
}
|
||||
|
||||
static void
|
||||
memac_if_set_macaddr(struct memac_softc *sc, const char *addr)
|
||||
{
|
||||
uint32_t reg;
|
||||
|
||||
reg = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
|
||||
bus_write_4(sc->sc_base.sc_mem, MEMAC_MAC_ADDR_0, reg);
|
||||
reg = (addr[5] << 8) | (addr[4]);
|
||||
bus_write_4(sc->sc_base.sc_mem, MEMAC_MAC_ADDR_1, reg);
|
||||
}
|
||||
|
||||
static void
|
||||
memac_if_init_locked(struct memac_softc *sc)
|
||||
{
|
||||
int error;
|
||||
const char *macaddr;
|
||||
|
||||
MEMAC_LOCK_ASSERT(sc);
|
||||
|
||||
macaddr = if_getlladdr(sc->sc_base.sc_ifnet);
|
||||
memac_if_set_macaddr(sc, macaddr);
|
||||
|
||||
/* Start MII polling */
|
||||
if (sc->sc_base.sc_mii)
|
||||
callout_reset(&sc->sc_base.sc_tick_callout, hz,
|
||||
memac_if_tick, sc);
|
||||
|
||||
if (if_getflags(sc->sc_base.sc_ifnet) & IFF_UP) {
|
||||
error = memac_if_enable_locked(sc);
|
||||
if (error != 0)
|
||||
goto err;
|
||||
} else {
|
||||
error = memac_if_disable_locked(sc);
|
||||
if (error != 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if_link_state_change(sc->sc_base.sc_ifnet, LINK_STATE_UP);
|
||||
|
||||
bus_write_4(sc->sc_base.sc_mem, MEMAC_CL01_PAUSE_QUANTA,
|
||||
DEFAULT_PAUSE_QUANTA);
|
||||
|
||||
return;
|
||||
|
||||
err:
|
||||
memac_if_deinit_locked(sc);
|
||||
device_printf(sc->sc_base.sc_dev, "initialization error.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
memac_if_init(void *data)
|
||||
{
|
||||
struct memac_softc *sc;
|
||||
|
||||
sc = data;
|
||||
|
||||
MEMAC_LOCK(sc);
|
||||
memac_if_init_locked(sc);
|
||||
MEMAC_UNLOCK(sc);
|
||||
}
|
||||
|
||||
static void
|
||||
memac_if_start(if_t ifp)
|
||||
{
|
||||
struct memac_softc *sc;
|
||||
|
||||
sc = if_getsoftc(ifp);
|
||||
MEMAC_LOCK(sc);
|
||||
dpaa_eth_if_start_locked(&sc->sc_base);
|
||||
MEMAC_UNLOCK(sc);
|
||||
}
|
||||
|
||||
static void
|
||||
memac_if_watchdog(if_t ifp)
|
||||
{
|
||||
/* TODO */
|
||||
}
|
||||
/** @} */
|
||||
|
||||
|
||||
/**
|
||||
* @group IFmedia routines.
|
||||
* @{
|
||||
*/
|
||||
static int
|
||||
memac_ifmedia_upd(if_t ifp)
|
||||
{
|
||||
struct memac_softc *sc = if_getsoftc(ifp);
|
||||
|
||||
return (0);
|
||||
MEMAC_LOCK(sc);
|
||||
mii_mediachg(sc->sc_base.sc_mii);
|
||||
MEMAC_UNLOCK(sc);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
memac_ifmedia_fixed_sts(if_t ifp, struct ifmediareq *ifmr)
|
||||
{
|
||||
struct memac_softc *sc = if_getsoftc(ifp);
|
||||
|
||||
MEMAC_LOCK(sc);
|
||||
ifmr->ifm_count = 1;
|
||||
ifmr->ifm_mask = 0;
|
||||
ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE;
|
||||
ifmr->ifm_current = ifmr->ifm_active =
|
||||
sc->sc_base.sc_mii->mii_media.ifm_cur->ifm_media;
|
||||
ifmr->ifm_active = ifmr->ifm_current;
|
||||
|
||||
/*
|
||||
* In non-PHY usecases, we need to signal link state up, otherwise
|
||||
* certain things requiring a link event (e.g async DHCP client) from
|
||||
* devd do not happen.
|
||||
*/
|
||||
if (if_getlinkstate(ifp) == LINK_STATE_UNKNOWN) {
|
||||
if_link_state_change(ifp, LINK_STATE_UP);
|
||||
}
|
||||
|
||||
/* We assume the link is static, as in a peer switch. */
|
||||
|
||||
MEMAC_UNLOCK(sc);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
memac_ifmedia_sts(if_t ifp, struct ifmediareq *ifmr)
|
||||
{
|
||||
struct memac_softc *sc = if_getsoftc(ifp);
|
||||
|
||||
MEMAC_LOCK(sc);
|
||||
|
||||
mii_pollstat(sc->sc_base.sc_mii);
|
||||
|
||||
ifmr->ifm_active = sc->sc_base.sc_mii->mii_media_active;
|
||||
ifmr->ifm_status = sc->sc_base.sc_mii->mii_media_status;
|
||||
|
||||
MEMAC_UNLOCK(sc);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
|
||||
/**
|
||||
* @group dTSEC bus interface.
|
||||
* @{
|
||||
*/
|
||||
|
||||
int
|
||||
memac_attach(device_t dev)
|
||||
{
|
||||
struct memac_softc *sc;
|
||||
int error;
|
||||
if_t ifp;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
sc->sc_base.sc_dev = dev;
|
||||
|
||||
/* Init locks */
|
||||
mtx_init(&sc->sc_base.sc_lock, device_get_nameunit(dev),
|
||||
"mEMAC Global Lock", MTX_DEF);
|
||||
|
||||
mtx_init(&sc->sc_base.sc_mii_lock, device_get_nameunit(dev),
|
||||
"mEMAC MII Lock", MTX_DEF);
|
||||
|
||||
/* Init callouts */
|
||||
callout_init(&sc->sc_base.sc_tick_callout, CALLOUT_MPSAFE);
|
||||
|
||||
/* Create RX buffer pool */
|
||||
error = dpaa_eth_pool_rx_init(&sc->sc_base);
|
||||
if (error != 0)
|
||||
return (EIO);
|
||||
|
||||
/* Create RX frame queue range */
|
||||
error = dpaa_eth_fq_rx_init(&sc->sc_base);
|
||||
if (error != 0)
|
||||
return (EIO);
|
||||
|
||||
/* Create frame info pool */
|
||||
error = dpaa_eth_fi_pool_init(&sc->sc_base);
|
||||
if (error != 0)
|
||||
return (EIO);
|
||||
|
||||
/* Create TX frame queue range */
|
||||
error = dpaa_eth_fq_tx_init(&sc->sc_base);
|
||||
if (error != 0)
|
||||
return (EIO);
|
||||
|
||||
/* Init FMan MAC module. */
|
||||
error = memac_fm_mac_init(sc, sc->sc_base.sc_mac_addr);
|
||||
if (error != 0) {
|
||||
memac_detach(dev);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
dpaa_eth_fm_port_rx_init(&sc->sc_base);
|
||||
dpaa_eth_fm_port_tx_init(&sc->sc_base);
|
||||
|
||||
/* Create network interface for upper layers */
|
||||
ifp = sc->sc_base.sc_ifnet = if_alloc(IFT_ETHER);
|
||||
if_setsoftc(ifp, sc);
|
||||
|
||||
if_setflags(ifp, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST);
|
||||
if_setinitfn(ifp, memac_if_init);
|
||||
if_setstartfn(ifp, memac_if_start);
|
||||
if_setioctlfn(ifp, memac_if_ioctl);
|
||||
if_setsendqlen(ifp, IFQ_MAXLEN);
|
||||
if_setsendqready(ifp);
|
||||
|
||||
if (sc->sc_base.sc_phy_addr >= 0)
|
||||
if_initname(ifp, device_get_name(sc->sc_base.sc_dev),
|
||||
device_get_unit(sc->sc_base.sc_dev));
|
||||
else
|
||||
if_initname(ifp, "memac_phy",
|
||||
device_get_unit(sc->sc_base.sc_dev));
|
||||
|
||||
|
||||
if_setcapabilities(ifp, IFCAP_VLAN_MTU);
|
||||
if_setcapenable(ifp, if_getcapabilities(ifp));
|
||||
|
||||
/* Attach PHY(s) */
|
||||
if (!sc->sc_fixed_link) {
|
||||
error = mii_attach(sc->sc_base.sc_dev, &sc->sc_base.sc_mii_dev,
|
||||
ifp, memac_ifmedia_upd, memac_ifmedia_sts, BMSR_DEFCAPMASK,
|
||||
sc->sc_base.sc_phy_addr, MII_OFFSET_ANY, 0);
|
||||
if (error) {
|
||||
device_printf(sc->sc_base.sc_dev,
|
||||
"attaching PHYs failed: %d\n", error);
|
||||
memac_detach(sc->sc_base.sc_dev);
|
||||
return (error);
|
||||
}
|
||||
sc->sc_base.sc_mii = device_get_softc(sc->sc_base.sc_mii_dev);
|
||||
} else {
|
||||
phandle_t node;
|
||||
uint32_t type = IFM_ETHER;
|
||||
uint32_t speed;
|
||||
|
||||
node = ofw_bus_find_child(ofw_bus_get_node(dev), "fixed-link");
|
||||
if (OF_getencprop(node, "speed", &speed, sizeof(speed)) <= 0) {
|
||||
device_printf(dev,
|
||||
"fixed link has no speed property\n");
|
||||
memac_detach(sc->sc_base.sc_dev);
|
||||
return (ENXIO);
|
||||
}
|
||||
switch (speed) {
|
||||
case 10:
|
||||
type |= IFM_10_T;
|
||||
break;
|
||||
case 100:
|
||||
type |= IFM_100_TX;
|
||||
break;
|
||||
case 1000:
|
||||
type |= IFM_1000_T;
|
||||
break;
|
||||
case 2500:
|
||||
type |= IFM_2500_T;
|
||||
break;
|
||||
case 5000:
|
||||
type |= IFM_5000_T;
|
||||
break;
|
||||
case 10000:
|
||||
type |= IFM_10G_T;
|
||||
break;
|
||||
}
|
||||
if (OF_hasprop(node, "full-duplex"))
|
||||
type |= IFM_FDX;
|
||||
sc->sc_base.sc_mii = malloc(sizeof(*sc->sc_base.sc_mii),
|
||||
M_DEVBUF, M_WAITOK | M_ZERO);
|
||||
ifmedia_init(&sc->sc_base.sc_mii->mii_media, 0,
|
||||
memac_ifmedia_upd, memac_ifmedia_fixed_sts);
|
||||
ifmedia_add(&sc->sc_base.sc_mii->mii_media, type, 0, NULL);
|
||||
ifmedia_set(&sc->sc_base.sc_mii->mii_media, type);
|
||||
}
|
||||
|
||||
/* Attach to stack */
|
||||
ether_ifattach(ifp, sc->sc_base.sc_mac_addr);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
memac_detach(device_t dev)
|
||||
{
|
||||
struct memac_softc *sc;
|
||||
if_t ifp;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
ifp = sc->sc_base.sc_ifnet;
|
||||
|
||||
if (device_is_attached(dev)) {
|
||||
ether_ifdetach(ifp);
|
||||
/* Shutdown interface */
|
||||
MEMAC_LOCK(sc);
|
||||
memac_if_deinit_locked(sc);
|
||||
MEMAC_UNLOCK(sc);
|
||||
}
|
||||
|
||||
if (sc->sc_base.sc_ifnet) {
|
||||
if_free(sc->sc_base.sc_ifnet);
|
||||
sc->sc_base.sc_ifnet = NULL;
|
||||
}
|
||||
|
||||
/* Free RX/TX FQRs */
|
||||
dpaa_eth_fq_rx_free(&sc->sc_base);
|
||||
dpaa_eth_fq_tx_free(&sc->sc_base);
|
||||
|
||||
/* Free frame info pool */
|
||||
dpaa_eth_fi_pool_free(&sc->sc_base);
|
||||
|
||||
/* Free RX buffer pool */
|
||||
dpaa_eth_pool_rx_free(&sc->sc_base);
|
||||
|
||||
/* Destroy lock */
|
||||
mtx_destroy(&sc->sc_base.sc_lock);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
memac_suspend(device_t dev)
|
||||
{
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
memac_resume(device_t dev)
|
||||
{
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
memac_shutdown(device_t dev)
|
||||
{
|
||||
|
||||
return (0);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
|
||||
/**
|
||||
* @group MII bus interface.
|
||||
* @{
|
||||
*/
|
||||
int
|
||||
memac_miibus_readreg(device_t dev, int phy, int reg)
|
||||
{
|
||||
struct memac_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
return (MIIBUS_READREG(sc->sc_base.sc_mdio, phy, reg));
|
||||
}
|
||||
|
||||
int
|
||||
memac_miibus_writereg(device_t dev, int phy, int reg, int value)
|
||||
{
|
||||
|
||||
struct memac_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
return (MIIBUS_WRITEREG(sc->sc_base.sc_mdio, phy, reg, value));
|
||||
}
|
||||
|
||||
void
|
||||
memac_miibus_statchg(device_t dev)
|
||||
{
|
||||
struct memac_softc *sc;
|
||||
uint32_t reg;
|
||||
bool duplex;
|
||||
int speed;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
MEMAC_LOCK_ASSERT(sc);
|
||||
|
||||
duplex = ((sc->sc_base.sc_mii->mii_media_active & IFM_GMASK) == IFM_FDX);
|
||||
|
||||
switch (IFM_SUBTYPE(sc->sc_base.sc_mii->mii_media_active)) {
|
||||
case IFM_AUTO:
|
||||
speed = IF_MODE_ENA;
|
||||
break;
|
||||
case IFM_1000_T:
|
||||
case IFM_1000_SX:
|
||||
if (!duplex) {
|
||||
device_printf(sc->sc_base.sc_dev,
|
||||
"Only full-duplex supported for 1Gbps speeds");
|
||||
return;
|
||||
}
|
||||
speed = IF_MODE_SSP_1GB;
|
||||
break;
|
||||
|
||||
case IFM_100_TX:
|
||||
speed = IF_MODE_SSP_100MB;
|
||||
break;
|
||||
default:
|
||||
speed = IF_MODE_SSP_10MB;
|
||||
break;
|
||||
}
|
||||
|
||||
reg = bus_read_4(sc->sc_base.sc_mem, MEMAC_IF_MODE);
|
||||
reg &= ~(IF_MODE_ENA | IF_MODE_SSP_M | IF_MODE_SFD);
|
||||
reg |= 0x2;
|
||||
|
||||
if (duplex)
|
||||
reg |= IF_MODE_SFD;
|
||||
else
|
||||
reg |= IF_MODE_HD;
|
||||
reg |= speed;
|
||||
bus_write_4(sc->sc_base.sc_mem, MEMAC_IF_MODE, reg);
|
||||
}
|
||||
/** @} */
|
||||
@@ -1,5 +1,5 @@
|
||||
/*-
|
||||
* Copyright (c) 2012 Semihalf.
|
||||
* Copyright (c) 2011-2012 Semihalf.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -24,28 +24,46 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef IF_DTSEC_RM_H_
|
||||
#define IF_DTSEC_RM_H_
|
||||
#ifndef IF_MEMAC_H_
|
||||
#define IF_MEMAC_H_
|
||||
|
||||
/**
|
||||
* @group dTSEC Regular Mode API.
|
||||
* @group dTSEC common API.
|
||||
* @{
|
||||
*/
|
||||
int dtsec_rm_fm_port_rx_init(struct dtsec_softc *sc, int unit);
|
||||
int dtsec_rm_fm_port_tx_init(struct dtsec_softc *sc, int unit);
|
||||
#define MEMAC_MODE_REGULAR 0
|
||||
|
||||
void dtsec_rm_if_start_locked(struct dtsec_softc *sc);
|
||||
#define MEMAC_LOCK(sc) mtx_lock(&(sc)->sc_base.sc_lock)
|
||||
#define MEMAC_UNLOCK(sc) mtx_unlock(&(sc)->sc_base.sc_lock)
|
||||
#define MEMAC_LOCK_ASSERT(sc) mtx_assert(&(sc)->sc_base.sc_lock, MA_OWNED)
|
||||
#define MEMAC_MII_LOCK(sc) mtx_lock(&(sc)->sc_base.sc_mii_lock)
|
||||
#define MEMAC_MII_UNLOCK(sc) mtx_unlock(&(sc)->sc_base.sc_mii_lock)
|
||||
|
||||
int dtsec_rm_pool_rx_init(struct dtsec_softc *sc);
|
||||
void dtsec_rm_pool_rx_free(struct dtsec_softc *sc);
|
||||
enum eth_dev_type {
|
||||
ETH_MEMAC = 0x1,
|
||||
ETH_10GSEC = 0x2
|
||||
};
|
||||
|
||||
int dtsec_rm_fi_pool_init(struct dtsec_softc *sc);
|
||||
void dtsec_rm_fi_pool_free(struct dtsec_softc *sc);
|
||||
|
||||
int dtsec_rm_fqr_rx_init(struct dtsec_softc *sc);
|
||||
int dtsec_rm_fqr_tx_init(struct dtsec_softc *sc);
|
||||
void dtsec_rm_fqr_rx_free(struct dtsec_softc *sc);
|
||||
void dtsec_rm_fqr_tx_free(struct dtsec_softc *sc);
|
||||
struct memac_softc {
|
||||
struct dpaa_eth_softc sc_base;
|
||||
bool sc_fixed_link;
|
||||
};
|
||||
/** @} */
|
||||
|
||||
#endif /* IF_DTSEC_RM_H_ */
|
||||
|
||||
/**
|
||||
* @group dTSEC bus interface.
|
||||
* @{
|
||||
*/
|
||||
int memac_attach(device_t dev);
|
||||
int memac_detach(device_t dev);
|
||||
int memac_suspend(device_t dev);
|
||||
int memac_resume(device_t dev);
|
||||
int memac_shutdown(device_t dev);
|
||||
int memac_miibus_readreg(device_t dev, int phy, int reg);
|
||||
int memac_miibus_writereg(device_t dev, int phy, int reg,
|
||||
int value);
|
||||
void memac_miibus_statchg(device_t dev);
|
||||
/** @} */
|
||||
|
||||
#endif /* IF_MEMAC_H_ */
|
||||
@@ -0,0 +1,190 @@
|
||||
/*-
|
||||
* Copyright (c) 2012 Semihalf.
|
||||
* 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 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 <sys/module.h>
|
||||
#include <sys/rman.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
|
||||
#include <powerpc/mpc85xx/mpc85xx.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/if_media.h>
|
||||
|
||||
#include <dev/mii/mii.h>
|
||||
#include <dev/mii/miivar.h>
|
||||
#include <dev/mii/mii_fdt.h>
|
||||
|
||||
#include <dev/ofw/ofw_bus.h>
|
||||
#include <dev/ofw/ofw_bus_subr.h>
|
||||
#include <dev/ofw/openfirm.h>
|
||||
|
||||
#include "miibus_if.h"
|
||||
|
||||
#include "dpaa_eth.h"
|
||||
#include "if_memac.h"
|
||||
#include "fman.h"
|
||||
|
||||
|
||||
static int memac_fdt_probe(device_t dev);
|
||||
static int memac_fdt_attach(device_t dev);
|
||||
|
||||
static device_method_t memac_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, memac_fdt_probe),
|
||||
DEVMETHOD(device_attach, memac_fdt_attach),
|
||||
DEVMETHOD(device_detach, memac_detach),
|
||||
|
||||
DEVMETHOD(device_shutdown, memac_shutdown),
|
||||
DEVMETHOD(device_suspend, memac_suspend),
|
||||
DEVMETHOD(device_resume, memac_resume),
|
||||
|
||||
/* Bus interface */
|
||||
DEVMETHOD(bus_print_child, bus_generic_print_child),
|
||||
DEVMETHOD(bus_driver_added, bus_generic_driver_added),
|
||||
|
||||
/* MII interface */
|
||||
DEVMETHOD(miibus_readreg, memac_miibus_readreg),
|
||||
DEVMETHOD(miibus_writereg, memac_miibus_writereg),
|
||||
DEVMETHOD(miibus_statchg, memac_miibus_statchg),
|
||||
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
||||
DEFINE_CLASS_0(memac, memac_driver, memac_methods, sizeof(struct memac_softc));
|
||||
|
||||
DRIVER_MODULE(memac, fman, memac_driver, 0, 0);
|
||||
DRIVER_MODULE(miibus, memac, miibus_driver, 0, 0);
|
||||
MODULE_DEPEND(memac, ether, 1, 1, 1);
|
||||
MODULE_DEPEND(memac, miibus, 1, 1, 1);
|
||||
|
||||
static int
|
||||
memac_fdt_probe(device_t dev)
|
||||
{
|
||||
|
||||
if (!ofw_bus_status_okay(dev))
|
||||
return (ENXIO);
|
||||
|
||||
if (!ofw_bus_is_compatible(dev, "fsl,fman-memac"))
|
||||
return (ENXIO);
|
||||
|
||||
device_set_desc(dev,
|
||||
"Freescale Multirate Ethernet Media Access Controller");
|
||||
|
||||
return (BUS_PROBE_DEFAULT);
|
||||
}
|
||||
|
||||
static int
|
||||
memac_fdt_attach(device_t dev)
|
||||
{
|
||||
struct memac_softc *sc;
|
||||
device_t phy_dev;
|
||||
phandle_t enet_node, phy_node;
|
||||
phandle_t fman_rxtx_node[2];
|
||||
pcell_t fman_tx_cell, mac_id;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
enet_node = ofw_bus_get_node(dev);
|
||||
|
||||
if (OF_getprop(enet_node, "local-mac-address",
|
||||
(void *)sc->sc_base.sc_mac_addr, 6) == -1) {
|
||||
device_printf(dev,
|
||||
"Could not load local-mac-addr property from DTS\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
/* Get PHY connection type */
|
||||
sc->sc_base.sc_mac_enet_mode = mii_fdt_get_contype(enet_node);
|
||||
|
||||
sc->sc_fixed_link = OF_hasprop(enet_node, "fixed-link") ||
|
||||
(ofw_bus_find_child(enet_node, "fixed-link") != 0);
|
||||
if (!sc->sc_fixed_link) {
|
||||
OF_getprop(enet_node, "phy-handle", &phy_node, sizeof(phy_node));
|
||||
phy_node = OF_node_from_xref(phy_node);
|
||||
|
||||
if (OF_getencprop(phy_node, "reg", (void *)&sc->sc_base.sc_phy_addr,
|
||||
sizeof(sc->sc_base.sc_phy_addr)) <= 0)
|
||||
return (ENXIO);
|
||||
|
||||
phy_dev = OF_device_from_xref(OF_xref_from_node(OF_parent(phy_node)));
|
||||
|
||||
if (phy_dev == NULL) {
|
||||
device_printf(dev, "No PHY found.\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
sc->sc_base.sc_mdio = phy_dev;
|
||||
}
|
||||
|
||||
/* Get MAC memory offset in SoC */
|
||||
sc->sc_base.sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 0, RF_ACTIVE);
|
||||
if (sc->sc_base.sc_mem == NULL)
|
||||
return (ENXIO);
|
||||
|
||||
sc->sc_base.sc_mac_enet_mode = mii_fdt_get_contype(enet_node);
|
||||
|
||||
if (sc->sc_base.sc_mac_enet_mode == MII_CONTYPE_UNKNOWN) {
|
||||
device_printf(dev, "unknown MII type, defaulting to SGMII\n");
|
||||
sc->sc_base.sc_mac_enet_mode = MII_CONTYPE_SGMII;
|
||||
}
|
||||
|
||||
if (OF_getencprop(enet_node, "cell-index",
|
||||
(void *)&mac_id, sizeof(mac_id)) <= 0)
|
||||
return (ENXIO);
|
||||
sc->sc_base.sc_eth_id = mac_id;
|
||||
|
||||
/* Get RX/TX port handles */
|
||||
if (OF_getencprop(enet_node, "fsl,fman-ports", (void *)fman_rxtx_node,
|
||||
sizeof(fman_rxtx_node)) <= 0)
|
||||
return (ENXIO);
|
||||
|
||||
if (fman_rxtx_node[0] == 0)
|
||||
return (ENXIO);
|
||||
|
||||
if (fman_rxtx_node[1] == 0)
|
||||
return (ENXIO);
|
||||
|
||||
sc->sc_base.sc_rx_port = OF_device_from_xref(fman_rxtx_node[0]);
|
||||
sc->sc_base.sc_tx_port = OF_device_from_xref(fman_rxtx_node[1]);
|
||||
|
||||
if (sc->sc_base.sc_rx_port == NULL || sc->sc_base.sc_tx_port == NULL)
|
||||
return (ENXIO);
|
||||
|
||||
fman_rxtx_node[1] = OF_node_from_xref(fman_rxtx_node[1]);
|
||||
if (OF_getencprop(fman_rxtx_node[1], "cell-index", &fman_tx_cell,
|
||||
sizeof(fman_tx_cell)) <= 0)
|
||||
return (ENXIO);
|
||||
/* Get QMan channel */
|
||||
sc->sc_base.sc_port_tx_qman_chan = fman_qman_channel_id(device_get_parent(dev),
|
||||
fman_tx_cell);
|
||||
|
||||
return (memac_attach(dev));
|
||||
}
|
||||
+21
-30
@@ -24,39 +24,30 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
typedef struct dpaa_portal {
|
||||
int dp_irid; /* interrupt rid */
|
||||
struct resource *dp_ires; /* interrupt resource */
|
||||
#ifndef DPAA_PORTALS_H
|
||||
#define DPAA_PORTALS_H
|
||||
|
||||
bool dp_regs_mapped; /* register mapping status */
|
||||
|
||||
t_Handle dp_ph; /* portal's handle */
|
||||
vm_paddr_t dp_ce_pa; /* portal's CE area PA */
|
||||
vm_paddr_t dp_ci_pa; /* portal's CI area PA */
|
||||
uint32_t dp_ce_size; /* portal's CE area size */
|
||||
uint32_t dp_ci_size; /* portal's CI area size */
|
||||
uintptr_t dp_intr_num; /* portal's intr. number */
|
||||
} dpaa_portal_t;
|
||||
|
||||
struct dpaa_portals_softc {
|
||||
struct dpaa_portal_softc {
|
||||
device_t sc_dev; /* device handle */
|
||||
vm_paddr_t sc_dp_pa; /* portal's PA */
|
||||
uint32_t sc_dp_size; /* portal's size */
|
||||
int sc_rrid[2]; /* memory rid */
|
||||
struct resource *sc_rres[2]; /* memory resource */
|
||||
dpaa_portal_t sc_dp[MAXCPU];
|
||||
vm_paddr_t sc_ce_pa; /* portal's CE PA */
|
||||
vm_offset_t sc_ce_va;
|
||||
vm_paddr_t sc_ci_pa; /* portal's CI PA */
|
||||
vm_offset_t sc_ci_va;
|
||||
int sc_cpu;
|
||||
uint32_t sc_ce_size; /* portal's CE size */
|
||||
uint32_t sc_ci_size; /* portal's CI size */
|
||||
struct resource *sc_mres[2]; /* memory resource */
|
||||
struct resource *sc_ires; /* Interrupt */
|
||||
void *sc_intr_cookie;
|
||||
bool sc_regs_mapped; /* register mapping status */
|
||||
};
|
||||
|
||||
struct dpaa_portals_devinfo {
|
||||
struct resource_list di_res;
|
||||
int di_intr_rid;
|
||||
};
|
||||
int bman_portal_attach(device_t, int);
|
||||
int bman_portal_detach(device_t);
|
||||
|
||||
int bman_portals_attach(device_t);
|
||||
int bman_portals_detach(device_t);
|
||||
int qman_portal_attach(device_t, int);
|
||||
int qman_portal_detach(device_t);
|
||||
|
||||
int qman_portals_attach(device_t);
|
||||
int qman_portals_detach(device_t);
|
||||
|
||||
int dpaa_portal_alloc_res(device_t, struct dpaa_portals_devinfo *, int);
|
||||
void dpaa_portal_map_registers(struct dpaa_portals_softc *);
|
||||
int dpaa_portal_alloc_res(device_t, int);
|
||||
void dpaa_portal_map_registers(struct dpaa_portal_softc *);
|
||||
#endif
|
||||
|
||||
+27
-108
@@ -41,127 +41,46 @@
|
||||
#include <machine/resource.h>
|
||||
#include <machine/tlb.h>
|
||||
|
||||
#include <contrib/ncsw/inc/error_ext.h>
|
||||
#include <contrib/ncsw/inc/xx_ext.h>
|
||||
|
||||
#include "portals.h"
|
||||
|
||||
|
||||
int
|
||||
dpaa_portal_alloc_res(device_t dev, struct dpaa_portals_devinfo *di, int cpu)
|
||||
dpaa_portal_alloc_res(device_t dev, int cpu)
|
||||
{
|
||||
struct dpaa_portals_softc *sc = device_get_softc(dev);
|
||||
struct resource_list_entry *rle;
|
||||
int err;
|
||||
struct resource_list *res;
|
||||
struct dpaa_portal_softc *sc = device_get_softc(dev);
|
||||
|
||||
/* Check if MallocSmart allocator is ready */
|
||||
if (XX_MallocSmartInit() != E_OK)
|
||||
sc->sc_mres[0] = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
|
||||
0, RF_ACTIVE);
|
||||
if (sc->sc_mres[0] == NULL) {
|
||||
device_printf(dev,
|
||||
"Could not allocate cache enabled memory.\n");
|
||||
return (ENXIO);
|
||||
|
||||
res = &di->di_res;
|
||||
|
||||
/*
|
||||
* Allocate memory.
|
||||
* Reserve only one pair of CE/CI virtual memory regions
|
||||
* for all CPUs, in order to save the space.
|
||||
*/
|
||||
if (sc->sc_rres[0] == NULL) {
|
||||
/* Cache enabled area */
|
||||
rle = resource_list_find(res, SYS_RES_MEMORY, 0);
|
||||
sc->sc_rrid[0] = 0;
|
||||
sc->sc_rres[0] = bus_alloc_resource(dev,
|
||||
SYS_RES_MEMORY, &sc->sc_rrid[0], rle->start + sc->sc_dp_pa,
|
||||
rle->end + sc->sc_dp_pa, rle->count, RF_ACTIVE);
|
||||
if (sc->sc_rres[0] == NULL) {
|
||||
device_printf(dev,
|
||||
"Could not allocate cache enabled memory.\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
tlb1_set_entry(rman_get_bushandle(sc->sc_rres[0]),
|
||||
rle->start + sc->sc_dp_pa, rle->count, _TLB_ENTRY_MEM);
|
||||
/* Cache inhibited area */
|
||||
rle = resource_list_find(res, SYS_RES_MEMORY, 1);
|
||||
sc->sc_rrid[1] = 1;
|
||||
sc->sc_rres[1] = bus_alloc_resource(dev,
|
||||
SYS_RES_MEMORY, &sc->sc_rrid[1], rle->start + sc->sc_dp_pa,
|
||||
rle->end + sc->sc_dp_pa, rle->count, RF_ACTIVE);
|
||||
if (sc->sc_rres[1] == NULL) {
|
||||
device_printf(dev,
|
||||
"Could not allocate cache inhibited memory.\n");
|
||||
bus_release_resource(dev, SYS_RES_MEMORY,
|
||||
sc->sc_rrid[0], sc->sc_rres[0]);
|
||||
return (ENXIO);
|
||||
}
|
||||
tlb1_set_entry(rman_get_bushandle(sc->sc_rres[1]),
|
||||
rle->start + sc->sc_dp_pa, rle->count, _TLB_ENTRY_IO);
|
||||
sc->sc_dp[cpu].dp_regs_mapped = 1;
|
||||
}
|
||||
/* Acquire portal's CE_PA and CI_PA */
|
||||
rle = resource_list_find(res, SYS_RES_MEMORY, 0);
|
||||
sc->sc_dp[cpu].dp_ce_pa = rle->start + sc->sc_dp_pa;
|
||||
sc->sc_dp[cpu].dp_ce_size = rle->count;
|
||||
rle = resource_list_find(res, SYS_RES_MEMORY, 1);
|
||||
sc->sc_dp[cpu].dp_ci_pa = rle->start + sc->sc_dp_pa;
|
||||
sc->sc_dp[cpu].dp_ci_size = rle->count;
|
||||
/* Cache inhibited area */
|
||||
sc->sc_mres[1] = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
|
||||
1, RF_ACTIVE);
|
||||
if (sc->sc_mres[1] == NULL) {
|
||||
device_printf(dev,
|
||||
"Could not allocate cache inhibited memory.\n");
|
||||
bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mres[0]);
|
||||
return (ENXIO);
|
||||
}
|
||||
sc->sc_dev = dev;
|
||||
sc->sc_ce_va = rman_get_bushandle(sc->sc_mres[0]);
|
||||
sc->sc_ce_size = rman_get_size(sc->sc_mres[0]);
|
||||
sc->sc_ce_pa = pmap_kextract(sc->sc_ce_va);
|
||||
sc->sc_ci_va = rman_get_bushandle(sc->sc_mres[1]);
|
||||
sc->sc_ci_size = rman_get_size(sc->sc_mres[1]);
|
||||
sc->sc_ci_pa = pmap_kextract(sc->sc_ci_va);
|
||||
tlb1_set_entry(sc->sc_ce_va, sc->sc_ce_pa, sc->sc_ce_size,
|
||||
_TLB_ENTRY_MEM | _TLB_ENTRY_SHARED);
|
||||
sc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, 0, RF_ACTIVE);
|
||||
|
||||
/* Allocate interrupts */
|
||||
rle = resource_list_find(res, SYS_RES_IRQ, 0);
|
||||
sc->sc_dp[cpu].dp_irid = 0;
|
||||
sc->sc_dp[cpu].dp_ires = bus_alloc_resource(dev,
|
||||
SYS_RES_IRQ, &sc->sc_dp[cpu].dp_irid, rle->start, rle->end,
|
||||
rle->count, RF_ACTIVE);
|
||||
/* Save interrupt number for later use */
|
||||
sc->sc_dp[cpu].dp_intr_num = rle->start;
|
||||
|
||||
if (sc->sc_dp[cpu].dp_ires == NULL) {
|
||||
if (sc->sc_ires == NULL) {
|
||||
device_printf(dev, "Could not allocate irq.\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
err = XX_PreallocAndBindIntr(dev, (uintptr_t)sc->sc_dp[cpu].dp_ires, cpu);
|
||||
|
||||
if (err != E_OK) {
|
||||
device_printf(dev, "Could not prealloc and bind interrupt\n");
|
||||
bus_release_resource(dev, SYS_RES_IRQ,
|
||||
sc->sc_dp[cpu].dp_irid, sc->sc_dp[cpu].dp_ires);
|
||||
sc->sc_dp[cpu].dp_ires = NULL;
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
#if 0
|
||||
err = bus_generic_config_intr(dev, rle->start, di->di_intr_trig,
|
||||
di->di_intr_pol);
|
||||
if (err != 0) {
|
||||
device_printf(dev, "Could not configure interrupt\n");
|
||||
bus_release_resource(dev, SYS_RES_IRQ,
|
||||
sc->sc_dp[cpu].dp_irid, sc->sc_dp[cpu].dp_ires);
|
||||
sc->sc_dp[cpu].dp_ires = NULL;
|
||||
return (err);
|
||||
}
|
||||
#endif
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
dpaa_portal_map_registers(struct dpaa_portals_softc *sc)
|
||||
{
|
||||
unsigned int cpu;
|
||||
|
||||
sched_pin();
|
||||
cpu = PCPU_GET(cpuid);
|
||||
if (sc->sc_dp[cpu].dp_regs_mapped)
|
||||
goto out;
|
||||
|
||||
tlb1_set_entry(rman_get_bushandle(sc->sc_rres[0]),
|
||||
sc->sc_dp[cpu].dp_ce_pa, sc->sc_dp[cpu].dp_ce_size,
|
||||
_TLB_ENTRY_MEM);
|
||||
tlb1_set_entry(rman_get_bushandle(sc->sc_rres[1]),
|
||||
sc->sc_dp[cpu].dp_ci_pa, sc->sc_dp[cpu].dp_ci_size,
|
||||
_TLB_ENTRY_IO);
|
||||
|
||||
sc->sc_dp[cpu].dp_regs_mapped = 1;
|
||||
|
||||
out:
|
||||
sched_unpin();
|
||||
}
|
||||
|
||||
+473
-329
@@ -1,3 +1,8 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2026 Justin Hibbits
|
||||
*/
|
||||
/*-
|
||||
* Copyright (c) 2011-2012 Semihalf.
|
||||
* All rights reserved.
|
||||
@@ -29,6 +34,7 @@
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/proc.h>
|
||||
@@ -41,139 +47,276 @@
|
||||
#include <machine/resource.h>
|
||||
#include <machine/tlb.h>
|
||||
|
||||
#include "qman.h"
|
||||
#include "dpaa_common.h"
|
||||
#include "portals.h"
|
||||
#include "qman.h"
|
||||
#include "qman_var.h"
|
||||
#include "qman_portal_if.h"
|
||||
|
||||
/* Registers */
|
||||
#define QCSP_IO_CFG(n) (0x004 + (n) * 16)
|
||||
#define IO_CFG_SDEST_M 0x00ff0000
|
||||
#define IO_CFG_SDEST_S 16
|
||||
#define QMAN_DCP_CFG(n) (0x300 + (n) * 0x10)
|
||||
#define DCP_CFG_ED 0x00000100
|
||||
#define DCP_CFG_ED_3 0x00001000
|
||||
#define QMAN_PFDR_FP_LWIT 0x410
|
||||
#define QMAN_PFDR_CFG 0x414
|
||||
#define QMAN_SFDR_CFG 0x500
|
||||
#define QMAN_MCR 0xb00
|
||||
#define MCR_INIT_PFDR 0x01000000
|
||||
#define MCR_READ_PFDR 0x02000000
|
||||
#define MCR_READ_SFDR 0x03000000
|
||||
#define MCR_QUERY_FQD_FILL 0x10000000
|
||||
#define MCR_QUERY_FQD_TAGS 0x11000000
|
||||
#define MCR_QUERY_FQD_CACHE 0x12000000
|
||||
#define MCR_QUERY_WQ 0x20000000
|
||||
#define MCR_RSLT_OK 0xf0000000
|
||||
#define MCR_RSLT_OK_DATA 0xf1000000
|
||||
#define MCR_RSLT_ABRT_INV 0xf4000000
|
||||
#define MCR_RSLT_ABRT_DIS 0xf8000000
|
||||
#define MCR_RSLT_ABRT_IDX 0xff000000
|
||||
#define MCR_RSLT_ABRT_MASK 0xff000000
|
||||
#define QMAN_MCP0 0xb04
|
||||
#define QMAN_MCP1 0xb08
|
||||
#define QMAN_IP_REV_1 0xbf8
|
||||
#define IP_MJ_M 0x0000ff00
|
||||
#define IP_MJ_S 8
|
||||
#define IP_MN_M 0x000000ff
|
||||
#define QMAN_FQD_BARE 0xc00
|
||||
#define QMAN_FQD_BAR 0xc04
|
||||
#define QMAN_FQD_AR 0xc10
|
||||
#define AR_EN 0x80000000
|
||||
#define QMAN_PFDR_BARE 0xc20
|
||||
#define QMAN_PFDR_BAR 0xc24
|
||||
#define QMAN_PFDR_AR 0xc30
|
||||
#define QMAN_QCSP_BARE 0xc80
|
||||
#define QMAN_QCSP_BAR 0xc84
|
||||
#define QMAN_QCSP_AR 0xc90
|
||||
#define QMAN_CI_SCHED_CFG 0xd00
|
||||
#define CI_SCHED_CFG_SW 0x80000000
|
||||
#define CI_SCHED_CFG_SRCCIV 0x04000000 /* Recommended */
|
||||
#define CI_SCHED_CFG_SRQ_W_M 0x00000700
|
||||
#define CI_SCHED_CFG_SRQ_W_S 8
|
||||
#define CI_SCHED_CFG_RW_W_M 0x00000070
|
||||
#define CI_SCHED_CFG_RW_W_S 4
|
||||
#define CI_SCHED_CFG_BMAN_W_M 0x00000007
|
||||
#define QMAN_ERR_ISR 0xe00
|
||||
#define QMAN_ERR_IER 0xe04
|
||||
#define QCSP_IO_CFG_3(n) (0x1004 + (n) * 16)
|
||||
|
||||
/* Software portals. Cache-inhibited registers */
|
||||
|
||||
#define QCSP_DQRR_PDQCR 0x05c
|
||||
|
||||
/* Software portals. Cache-enabled registers */
|
||||
|
||||
#define QCSP_VERB_INIT_FQ_PARK 0x40
|
||||
#define QCSP_VERB_INIT_FQ_SCHED 0x41
|
||||
#define QCSP_VERB_QUERY_FQ 0x44
|
||||
#define QCSP_VERB_QUERY_FQ_NP 0x45
|
||||
#define QCSP_VERB_ALTER_FQ_SCHED 0x48
|
||||
#define QCSP_VERB_ALTER_FQ_FE 0x49
|
||||
#define QCSP_VERB_ALTER_FQ_RETIRE 0x4a
|
||||
#define QCSP_VERB_ALTER_FQ_TAKE_OUT 0x4b
|
||||
#define QCSP_VERB_ALTER_FQ_RETIRE_CTXB 0x4c
|
||||
#define QCSP_VERB_ALTER_FQ_XON 0x4d
|
||||
#define QCSP_VERB_ALTER_FQ_XOFF 0x4e
|
||||
|
||||
/* Init FQ */
|
||||
#define QCSP_INIT_FQ_WE_OAC 0x0100
|
||||
#define QCSP_INIT_FQ_WE_ORPC 0x0080
|
||||
#define QCSP_INIT_FQ_WE_CGID 0x0040
|
||||
#define QCSP_INIT_FQ_WE_FQ_CTRL 0x0020
|
||||
#define QCSP_INIT_FQ_WE_DEST_WQ 0x0010
|
||||
#define QCSP_INIT_FQ_WE_ICS_CRED 0x0008
|
||||
#define QCSP_INIT_FQ_WE_TD_THRESH 0x0004
|
||||
#define QCSP_INIT_FQ_WE_CONTEXT_B 0x0002
|
||||
#define QCSP_INIT_FQ_WE_CONTEXT_A 0x0001
|
||||
|
||||
#define QMAN_MC_RES_OK 0xf0
|
||||
|
||||
#define QMAN_MC_AFQS_NE 0x01
|
||||
|
||||
/* Init FQ options */
|
||||
#define QM_FQCTRL_CGE 0x0400
|
||||
#define QM_FQCTRL_TDE 0x0200
|
||||
#define QM_FQCTRL_ORP 0x0100
|
||||
#define QM_FQCTRL_CTXASTASH 0x0080
|
||||
#define QM_FQCTRL_CPCSTASH 0x0040
|
||||
#define QM_FQCTRL_FORCESFDR 0x0008
|
||||
#define QM_FQCTRL_AVOIDBLOCK 0x0004
|
||||
#define QM_FQCTRL_HOLDACTIVE 0x0002
|
||||
#define QM_FQCTRL_LIC 0x0001
|
||||
|
||||
#define QMAN_CHANNEL_POOL1_REV1 0x21
|
||||
#define QMAN_CHANNEL_POOL1_REV3 0x401
|
||||
|
||||
#define QMAN_PFDR_MAX 0xfffeff
|
||||
|
||||
/* P1023 has only 3 pool channels, but we don't support that SoC. */
|
||||
#define QMAN_POOL_CHANNELS 15
|
||||
|
||||
/* P1023 only supports 64 congestion groups... */
|
||||
#define QMAN_CGRS 256
|
||||
|
||||
extern struct dpaa_portals_softc *qp_sc;
|
||||
static struct qman_softc *qman_sc;
|
||||
|
||||
extern t_Handle qman_portal_setup(struct qman_softc *qsc);
|
||||
static MALLOC_DEFINE(M_QMAN, "qman", "DPAA Queue Manager structures");
|
||||
|
||||
int qman_channel_base;
|
||||
int qman_total_fqids;
|
||||
struct qman_fq **qman_fq_list;
|
||||
|
||||
/* Entries sorted right-to-left in bit order of the ISR */
|
||||
static const char * const qman_errors[] = {
|
||||
"Invalid enqueue queue",
|
||||
"Invalid enqueue channel!",
|
||||
"Invalid enqueue state",
|
||||
"Invalid enqueue overflow",
|
||||
"Invalid enqueue configuration",
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
"Invalid dequeue queue",
|
||||
"Invalid dequeue source",
|
||||
"Invalid dequeue FQ",
|
||||
"Invalid dequeue direct connect portal",
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
"Invalid command verb",
|
||||
"Invalid FQ flow control state",
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
"Insufficient free PFDRs",
|
||||
"Single-bit ECC error",
|
||||
"Multi-bit ECC error",
|
||||
"PFDR low watermark",
|
||||
"Invalid target transaction",
|
||||
"Initiator data error",
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
static void
|
||||
qman_exception(t_Handle app, e_QmExceptions exception)
|
||||
qman_isr(void *arg)
|
||||
{
|
||||
struct qman_softc *sc;
|
||||
const char *message;
|
||||
struct qman_softc *sc = arg;
|
||||
uint32_t ier, isr, isr_bit;
|
||||
int i;
|
||||
|
||||
sc = app;
|
||||
ier = bus_read_4(sc->sc_rres, QMAN_ERR_IER);
|
||||
isr = bus_read_4(sc->sc_rres, QMAN_ERR_ISR);
|
||||
|
||||
switch (exception) {
|
||||
case e_QM_EX_CORENET_INITIATOR_DATA:
|
||||
message = "Initiator Data Error";
|
||||
break;
|
||||
case e_QM_EX_CORENET_TARGET_DATA:
|
||||
message = "CoreNet Target Data Error";
|
||||
break;
|
||||
case e_QM_EX_CORENET_INVALID_TARGET_TRANSACTION:
|
||||
message = "Invalid Target Transaction";
|
||||
break;
|
||||
case e_QM_EX_PFDR_THRESHOLD:
|
||||
message = "PFDR Low Watermark Interrupt";
|
||||
break;
|
||||
case e_QM_EX_PFDR_ENQUEUE_BLOCKED:
|
||||
message = "PFDR Enqueues Blocked Interrupt";
|
||||
break;
|
||||
case e_QM_EX_SINGLE_ECC:
|
||||
message = "Single Bit ECC Error Interrupt";
|
||||
break;
|
||||
case e_QM_EX_MULTI_ECC:
|
||||
message = "Multi Bit ECC Error Interrupt";
|
||||
break;
|
||||
case e_QM_EX_INVALID_COMMAND:
|
||||
message = "Invalid Command Verb Interrupt";
|
||||
break;
|
||||
case e_QM_EX_DEQUEUE_DCP:
|
||||
message = "Invalid Dequeue Direct Connect Portal Interrupt";
|
||||
break;
|
||||
case e_QM_EX_DEQUEUE_FQ:
|
||||
message = "Invalid Dequeue FQ Interrupt";
|
||||
break;
|
||||
case e_QM_EX_DEQUEUE_SOURCE:
|
||||
message = "Invalid Dequeue Source Interrupt";
|
||||
break;
|
||||
case e_QM_EX_DEQUEUE_QUEUE:
|
||||
message = "Invalid Dequeue Queue Interrupt";
|
||||
break;
|
||||
case e_QM_EX_ENQUEUE_OVERFLOW:
|
||||
message = "Invalid Enqueue Overflow Interrupt";
|
||||
break;
|
||||
case e_QM_EX_ENQUEUE_STATE:
|
||||
message = "Invalid Enqueue State Interrupt";
|
||||
break;
|
||||
case e_QM_EX_ENQUEUE_CHANNEL:
|
||||
message = "Invalid Enqueue Channel Interrupt";
|
||||
break;
|
||||
case e_QM_EX_ENQUEUE_QUEUE:
|
||||
message = "Invalid Enqueue Queue Interrupt";
|
||||
break;
|
||||
case e_QM_EX_CG_STATE_CHANGE:
|
||||
message = "CG change state notification";
|
||||
break;
|
||||
default:
|
||||
message = "Unknown error";
|
||||
if ((ier & isr) == 0)
|
||||
return;
|
||||
|
||||
isr_bit = (isr & ier);
|
||||
for (i = 0; isr_bit != 0; i++, isr_bit >>= 1) {
|
||||
if (isr_bit & 1)
|
||||
device_printf(sc->sc_dev, "%s", qman_errors[i]);
|
||||
}
|
||||
|
||||
device_printf(sc->sc_dev, "QMan Exception: %s.\n", message);
|
||||
bus_write_4(sc->sc_rres, QMAN_ERR_ISR, isr);
|
||||
}
|
||||
|
||||
/**
|
||||
* General received frame callback.
|
||||
* This is called, when user did not register his own callback for a given
|
||||
* frame queue range (fqr).
|
||||
*/
|
||||
e_RxStoreResponse
|
||||
qman_received_frame_callback(t_Handle app, t_Handle qm_fqr, t_Handle qm_portal,
|
||||
uint32_t fqid_offset, t_DpaaFD *frame)
|
||||
|
||||
/* Set up reserved memory configuration for PFDR and FQD, per `off`. */
|
||||
static int
|
||||
qman_set_memory(struct qman_softc *sc, vm_paddr_t pa,
|
||||
vm_size_t size, bus_size_t off)
|
||||
{
|
||||
struct qman_softc *sc;
|
||||
uint32_t bar, bare;
|
||||
vm_paddr_t old_bar;
|
||||
|
||||
sc = app;
|
||||
/*
|
||||
* Register offsets:
|
||||
* 0 - BARE
|
||||
* 4 - BAR
|
||||
* 0x10 - AR
|
||||
*/
|
||||
bare = bus_read_4(sc->sc_rres, off);
|
||||
bar = bus_read_4(sc->sc_rres, off + 4);
|
||||
old_bar = (vm_paddr_t)bare << 32 | bar;
|
||||
|
||||
device_printf(sc->sc_dev, "dummy callback for received frame.\n");
|
||||
return (e_RX_STORE_RESPONSE_CONTINUE);
|
||||
if (old_bar != 0 && old_bar != pa) {
|
||||
device_printf(sc->sc_dev, "QMan BAR already initialized!\n");
|
||||
return (ENOMEM);
|
||||
} else if (old_bar == pa)
|
||||
return (EEXIST);
|
||||
|
||||
/*
|
||||
* Zero the memory and flush cache through DMAP. QMan accesses the
|
||||
* memory as non-coherent.
|
||||
*/
|
||||
memset((void *)PHYS_TO_DMAP(pa), 0, size);
|
||||
cpu_flush_dcache((void *)PHYS_TO_DMAP(pa), size);
|
||||
|
||||
bus_write_4(sc->sc_rres, off, pa >> 32);
|
||||
bus_write_4(sc->sc_rres, off + 4, (uint32_t)pa);
|
||||
bus_write_4(sc->sc_rres, off + 0x10, AR_EN | (ilog2(size) - 1));
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**
|
||||
* General rejected frame callback.
|
||||
* This is called, when user did not register his own callback for a given
|
||||
* frame queue range (fqr).
|
||||
/*
|
||||
* Set up PFDR structures. Some things to keep in mind:
|
||||
* - npfdr is the total number of PFDRs in the private memory. PFDRs are 64
|
||||
* bytes in size, so npfdr is (pfdr_sz/64).
|
||||
* - PFDR 0-7 are reserved, so the base starts at 8, not 0, so we adjust
|
||||
* internally.
|
||||
* - The second parameter is the last PFDR, not the number of PFDRs, so needs to
|
||||
* be adjusted down one more, so subtract 9.
|
||||
*/
|
||||
e_RxStoreResponse
|
||||
qman_rejected_frame_callback(t_Handle app, t_Handle qm_fqr, t_Handle qm_portal,
|
||||
uint32_t fqid_offset, t_DpaaFD *frame,
|
||||
t_QmRejectedFrameInfo *qm_rejected_frame_info)
|
||||
static int
|
||||
qman_setup_pfdr(struct qman_softc *sc, int npfdr)
|
||||
{
|
||||
struct qman_softc *sc;
|
||||
uint32_t res;
|
||||
|
||||
sc = app;
|
||||
npfdr = min(npfdr, QMAN_PFDR_MAX);
|
||||
bus_write_4(sc->sc_rres, QMAN_MCP0, 8);
|
||||
bus_write_4(sc->sc_rres, QMAN_MCP1, npfdr - 9);
|
||||
bus_write_4(sc->sc_rres, QMAN_MCR, MCR_INIT_PFDR);
|
||||
|
||||
device_printf(sc->sc_dev, "dummy callback for rejected frame.\n");
|
||||
return (e_RX_STORE_RESPONSE_CONTINUE);
|
||||
for (int timeout = 100000; timeout > 0; timeout--) {
|
||||
DELAY(1);
|
||||
res = bus_read_4(sc->sc_rres, QMAN_MCR);
|
||||
if (res >= MCR_RSLT_OK)
|
||||
break;
|
||||
}
|
||||
|
||||
if (res < MCR_RSLT_OK)
|
||||
return (EBUSY);
|
||||
if (res == MCR_RSLT_OK)
|
||||
return (0);
|
||||
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
int
|
||||
qman_attach(device_t dev)
|
||||
{
|
||||
struct qman_softc *sc;
|
||||
t_QmParam qp;
|
||||
t_Error error;
|
||||
t_QmRevisionInfo rev;
|
||||
int error;
|
||||
vm_paddr_t fqd_pa, pfdr_pa;
|
||||
vm_size_t fqd_sz, pfdr_sz;
|
||||
int qman_channel_pool1 = QMAN_CHANNEL_POOL1_REV1;
|
||||
uint32_t ver;
|
||||
uint32_t nfqd;
|
||||
bool qman3 = false;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
sc->sc_dev = dev;
|
||||
qman_sc = sc;
|
||||
|
||||
if (XX_MallocSmartInit() != E_OK) {
|
||||
device_printf(dev, "could not initialize smart allocator.\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
sched_pin();
|
||||
|
||||
/* Allocate resources */
|
||||
sc->sc_rrid = 0;
|
||||
sc->sc_rres = bus_alloc_resource(dev, SYS_RES_MEMORY,
|
||||
&sc->sc_rrid, 0, ~0, QMAN_CCSR_SIZE, RF_ACTIVE);
|
||||
sc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 0, RF_ACTIVE);
|
||||
if (sc->sc_rres == NULL) {
|
||||
device_printf(dev, "could not allocate memory.\n");
|
||||
goto err;
|
||||
@@ -186,57 +329,79 @@ qman_attach(device_t dev)
|
||||
device_printf(dev, "could not allocate error interrupt.\n");
|
||||
goto err;
|
||||
}
|
||||
error = dpaa_map_private_memory(dev, 0, "fsl,qman-fqd",
|
||||
&fqd_pa, &fqd_sz);
|
||||
error = dpaa_map_private_memory(dev, 1, "fsl,qman-pfdr",
|
||||
&pfdr_pa, &pfdr_sz);
|
||||
|
||||
if (qp_sc == NULL)
|
||||
bzero((void *)PHYS_TO_DMAP(fqd_pa), fqd_sz);
|
||||
cpu_flush_dcache((void *)PHYS_TO_DMAP(fqd_pa), fqd_sz);
|
||||
/*
|
||||
* FQDs are 64 bytes in size, with 24 bit pointers, so FQIDs are 24
|
||||
* bits, fits fine in a uint32_t.
|
||||
*/
|
||||
nfqd = fqd_sz / 64;
|
||||
qman_total_fqids = nfqd;
|
||||
qman_channel_base = qman_channel_pool1;
|
||||
qman_fq_list = malloc(nfqd * sizeof(struct qman_fq *), M_QMAN,
|
||||
M_WAITOK);
|
||||
|
||||
error = qman_set_memory(sc, fqd_pa, fqd_sz, QMAN_FQD_BARE);
|
||||
if (error != 0 && error != EEXIST)
|
||||
goto err;
|
||||
|
||||
dpaa_portal_map_registers(qp_sc);
|
||||
|
||||
/* Initialize QMan */
|
||||
qp.guestId = NCSW_MASTER_ID;
|
||||
qp.baseAddress = rman_get_bushandle(sc->sc_rres);
|
||||
qp.swPortalsBaseAddress = rman_get_bushandle(qp_sc->sc_rres[0]);
|
||||
qp.liodn = 0;
|
||||
qp.totalNumOfFqids = QMAN_MAX_FQIDS;
|
||||
qp.fqdMemPartitionId = NCSW_MASTER_ID;
|
||||
qp.pfdrMemPartitionId = NCSW_MASTER_ID;
|
||||
qp.f_Exception = qman_exception;
|
||||
qp.h_App = sc;
|
||||
qp.errIrq = (uintptr_t)sc->sc_ires;
|
||||
qp.partFqidBase = QMAN_FQID_BASE;
|
||||
qp.partNumOfFqids = QMAN_MAX_FQIDS;
|
||||
qp.partCgsBase = 0;
|
||||
qp.partNumOfCgs = 0;
|
||||
|
||||
sc->sc_qh = QM_Config(&qp);
|
||||
if (sc->sc_qh == NULL) {
|
||||
device_printf(dev, "could not be configured\n");
|
||||
error = qman_set_memory(sc, pfdr_pa, pfdr_sz, QMAN_PFDR_BARE);
|
||||
if (error != 0 && error != EEXIST)
|
||||
goto err;
|
||||
if (error == 0) {
|
||||
/* Initialize PFDRs if it hasn't been initialized before */
|
||||
error = qman_setup_pfdr(sc, pfdr_sz / 64);
|
||||
if (error != 0)
|
||||
goto err;
|
||||
/* Magic constant from documentation */
|
||||
bus_write_4(sc->sc_rres, QMAN_PFDR_CFG, 64);
|
||||
}
|
||||
|
||||
error = QM_Init(sc->sc_qh);
|
||||
if (error != E_OK) {
|
||||
bus_write_4(sc->sc_rres, QMAN_ERR_ISR, 0xffffffff);
|
||||
bus_write_4(sc->sc_rres, QMAN_ERR_IER, 0xffffffff);
|
||||
|
||||
ver = bus_read_4(sc->sc_rres, QMAN_IP_REV_1);
|
||||
sc->sc_qman_major = ((ver & IP_MJ_M) >> IP_MJ_S);
|
||||
if (sc->sc_qman_major >= 3)
|
||||
qman3 = true;
|
||||
|
||||
if (qman3)
|
||||
qman_channel_pool1 = QMAN_CHANNEL_POOL1_REV3;
|
||||
|
||||
sc->sc_qman_base_channel = qman_channel_pool1;
|
||||
|
||||
sc->sc_fqalloc =
|
||||
vmem_create("qman-fqalloc", 1, nfqd - 1, 1, 0, M_WAITOK);
|
||||
sc->sc_qpalloc =
|
||||
vmem_create("qman-fqalloc", qman_channel_pool1,
|
||||
QMAN_POOL_CHANNELS, 1, 0, M_WAITOK);
|
||||
sc->sc_cgalloc = vmem_create("qman->cgalloc", 0, QMAN_CGRS,
|
||||
1, 0, M_WAITOK);
|
||||
|
||||
if (bus_setup_intr(dev, sc->sc_ires, INTR_TYPE_NET, NULL, qman_isr,
|
||||
sc, &sc->sc_intr_cookie) != 0)
|
||||
goto err;
|
||||
|
||||
if (error != 0) {
|
||||
device_printf(dev, "could not be initialized\n");
|
||||
goto err;
|
||||
}
|
||||
bus_write_4(sc->sc_rres, QMAN_DCP_CFG(0),
|
||||
qman3 ? DCP_CFG_ED_3 : DCP_CFG_ED);
|
||||
bus_write_4(sc->sc_rres, QMAN_DCP_CFG(1),
|
||||
qman3 ? DCP_CFG_ED_3 : DCP_CFG_ED);
|
||||
|
||||
error = QM_GetRevision(sc->sc_qh, &rev);
|
||||
if (error != E_OK) {
|
||||
device_printf(dev, "could not get QMan revision\n");
|
||||
goto err;
|
||||
}
|
||||
bus_write_4(sc->sc_rres, 0xd00, 0x80000322);
|
||||
|
||||
device_printf(dev, "Hardware version: %d.%d.\n",
|
||||
rev.majorRev, rev.minorRev);
|
||||
|
||||
sched_unpin();
|
||||
|
||||
qman_portal_setup(sc);
|
||||
/* TODO: DO we need a taskqueue? Allocate here if so */
|
||||
|
||||
return (0);
|
||||
|
||||
err:
|
||||
sched_unpin();
|
||||
qman_detach(dev);
|
||||
return (ENXIO);
|
||||
}
|
||||
@@ -248,11 +413,15 @@ qman_detach(device_t dev)
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
if (sc->sc_qh)
|
||||
QM_Free(sc->sc_qh);
|
||||
if (sc->sc_fqalloc != NULL)
|
||||
vmem_destroy(sc->sc_fqalloc);
|
||||
if (sc->sc_qpalloc != NULL)
|
||||
vmem_destroy(sc->sc_qpalloc);
|
||||
if (sc->sc_cgalloc != NULL)
|
||||
vmem_destroy(sc->sc_cgalloc);
|
||||
|
||||
if (sc->sc_ires != NULL)
|
||||
XX_DeallocIntr((uintptr_t)sc->sc_ires);
|
||||
if (sc->sc_intr_cookie != NULL)
|
||||
bus_teardown_intr(dev, sc->sc_ires, sc->sc_intr_cookie);
|
||||
|
||||
if (sc->sc_ires != NULL)
|
||||
bus_release_resource(dev, SYS_RES_IRQ,
|
||||
@@ -262,6 +431,9 @@ qman_detach(device_t dev)
|
||||
bus_release_resource(dev, SYS_RES_MEMORY,
|
||||
sc->sc_rrid, sc->sc_rres);
|
||||
|
||||
free(qman_fq_list, M_QMAN);
|
||||
qman_fq_list = NULL;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -286,261 +458,233 @@ qman_shutdown(device_t dev)
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
qman_alloc_channel(void)
|
||||
{
|
||||
struct qman_softc *sc = qman_sc;
|
||||
vmem_addr_t channel;
|
||||
|
||||
vmem_alloc(sc->sc_qpalloc, 1, M_BESTFIT | M_WAITOK, &channel);
|
||||
|
||||
return (channel);
|
||||
}
|
||||
|
||||
void
|
||||
qman_free_channel(int channel)
|
||||
{
|
||||
struct qman_softc *sc = qman_sc;
|
||||
|
||||
vmem_free(sc->sc_qpalloc, channel, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group QMan API functions implementation.
|
||||
* @{
|
||||
*/
|
||||
|
||||
t_Handle
|
||||
qman_fqr_create(uint32_t fqids_num, e_QmFQChannel channel, uint8_t wq,
|
||||
struct qman_fq *
|
||||
qman_fq_from_index(uint32_t fqid)
|
||||
{
|
||||
if (fqid > qman_total_fqids)
|
||||
return (NULL);
|
||||
return (qman_fq_list[fqid]);
|
||||
}
|
||||
|
||||
/* Allocate and initialize an FQ Range */
|
||||
struct qman_fq *
|
||||
qman_fq_create(uint32_t fqids_num, int channel, uint8_t wq,
|
||||
bool force_fqid, uint32_t fqid_or_align, bool init_parked,
|
||||
bool hold_active, bool prefer_in_cache, bool congst_avoid_ena,
|
||||
t_Handle congst_group, int8_t overhead_accounting_len,
|
||||
void *congst_group, int8_t overhead_accounting_len,
|
||||
uint32_t tail_drop_threshold)
|
||||
{
|
||||
union qman_mc_command cmd;
|
||||
struct qman_softc *sc;
|
||||
t_QmFqrParams fqr;
|
||||
t_Handle fqrh, portal;
|
||||
union qman_mc_result *res;
|
||||
struct qman_fq *fqh;
|
||||
device_t portal;
|
||||
vmem_addr_t fqid_base;
|
||||
uint8_t rslt;
|
||||
|
||||
sc = qman_sc;
|
||||
|
||||
sched_pin();
|
||||
if (fqids_num != 1) {
|
||||
device_printf(sc->sc_dev,
|
||||
"Only one fq allocation allowed currently\n");
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
bzero(&cmd, sizeof(cmd));
|
||||
vmem_alloc(sc->sc_fqalloc, fqids_num, M_BESTFIT | M_WAITOK, &fqid_base);
|
||||
cmd.init_fq.fqid = fqid_base;
|
||||
cmd.init_fq.count = fqids_num - 1;
|
||||
cmd.init_fq.dest_chan = channel;
|
||||
cmd.init_fq.dest_wq = wq;
|
||||
cmd.init_fq.we_mask = QCSP_INIT_FQ_WE_DEST_WQ | QCSP_INIT_FQ_WE_FQ_CTRL;
|
||||
if (init_parked)
|
||||
cmd.init_fq.verb = QCSP_VERB_INIT_FQ_PARK;
|
||||
else
|
||||
cmd.init_fq.verb = QCSP_VERB_INIT_FQ_SCHED;
|
||||
cmd.init_fq.fq_ctrl = (prefer_in_cache ? QM_FQCTRL_LIC : 0) |
|
||||
(hold_active ? QM_FQCTRL_HOLDACTIVE : 0) |
|
||||
(congst_avoid_ena ? QM_FQCTRL_AVOIDBLOCK : 0);
|
||||
|
||||
critical_enter();
|
||||
|
||||
/* Ensure we have got QMan port initialized */
|
||||
portal = qman_portal_setup(sc);
|
||||
if (portal == NULL) {
|
||||
device_printf(sc->sc_dev, "could not setup QMan portal\n");
|
||||
portal = DPCPU_GET(qman_affine_portal);
|
||||
res = QMAN_PORTAL_MC_SEND_RAW(portal, &cmd);
|
||||
|
||||
rslt = 0;
|
||||
if (res != NULL)
|
||||
rslt = res->init_fq.rslt;
|
||||
|
||||
critical_exit();
|
||||
if (res == NULL || rslt != QMAN_MC_RES_OK) {
|
||||
vmem_free(sc->sc_fqalloc, fqid_base, fqids_num);
|
||||
goto err;
|
||||
}
|
||||
|
||||
fqr.h_Qm = sc->sc_qh;
|
||||
fqr.h_QmPortal = portal;
|
||||
fqr.initParked = init_parked;
|
||||
fqr.holdActive = hold_active;
|
||||
fqr.preferInCache = prefer_in_cache;
|
||||
fqh = malloc(sizeof(*fqh), M_QMAN, M_WAITOK | M_ZERO);
|
||||
fqh->fqid = fqid_base;
|
||||
|
||||
/* We do not support stashing */
|
||||
fqr.useContextAForStash = FALSE;
|
||||
fqr.p_ContextA = 0;
|
||||
fqr.p_ContextB = 0;
|
||||
qman_fq_list[fqid_base] = fqh;
|
||||
|
||||
fqr.channel = channel;
|
||||
fqr.wq = wq;
|
||||
fqr.shadowMode = FALSE;
|
||||
fqr.numOfFqids = fqids_num;
|
||||
|
||||
/* FQID */
|
||||
fqr.useForce = force_fqid;
|
||||
if (force_fqid) {
|
||||
fqr.qs.frcQ.fqid = fqid_or_align;
|
||||
} else {
|
||||
fqr.qs.nonFrcQs.align = fqid_or_align;
|
||||
}
|
||||
|
||||
/* Congestion Avoidance */
|
||||
fqr.congestionAvoidanceEnable = congst_avoid_ena;
|
||||
if (congst_avoid_ena) {
|
||||
fqr.congestionAvoidanceParams.h_QmCg = congst_group;
|
||||
fqr.congestionAvoidanceParams.overheadAccountingLength =
|
||||
overhead_accounting_len;
|
||||
fqr.congestionAvoidanceParams.fqTailDropThreshold =
|
||||
tail_drop_threshold;
|
||||
} else {
|
||||
fqr.congestionAvoidanceParams.h_QmCg = 0;
|
||||
fqr.congestionAvoidanceParams.overheadAccountingLength = 0;
|
||||
fqr.congestionAvoidanceParams.fqTailDropThreshold = 0;
|
||||
}
|
||||
|
||||
fqrh = QM_FQR_Create(&fqr);
|
||||
if (fqrh == NULL) {
|
||||
device_printf(sc->sc_dev, "could not create Frame Queue Range"
|
||||
"\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
sc->sc_fqr_cpu[QM_FQR_GetFqid(fqrh)] = PCPU_GET(cpuid);
|
||||
|
||||
sched_unpin();
|
||||
|
||||
return (fqrh);
|
||||
return (fqh);
|
||||
|
||||
err:
|
||||
sched_unpin();
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
t_Error
|
||||
qman_fqr_free(t_Handle fqr)
|
||||
static int
|
||||
qman_fq_retire(device_t portal, struct qman_fq *fq)
|
||||
{
|
||||
struct qman_softc *sc;
|
||||
t_Error error;
|
||||
union qman_mc_command cmd;
|
||||
union qman_mc_result *rr;
|
||||
|
||||
sc = qman_sc;
|
||||
thread_lock(curthread);
|
||||
sched_bind(curthread, sc->sc_fqr_cpu[QM_FQR_GetFqid(fqr)]);
|
||||
thread_unlock(curthread);
|
||||
bzero(&cmd, sizeof(cmd));
|
||||
|
||||
error = QM_FQR_Free(fqr);
|
||||
cmd.alter_fqs.verb = QCSP_VERB_ALTER_FQ_RETIRE;
|
||||
cmd.alter_fqs.fqid = fq->fqid;
|
||||
rr = QMAN_PORTAL_MC_SEND_RAW(portal, &cmd);
|
||||
if (rr == NULL)
|
||||
return (ETIMEDOUT);
|
||||
|
||||
thread_lock(curthread);
|
||||
sched_unbind(curthread);
|
||||
thread_unlock(curthread);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
t_Error
|
||||
qman_fqr_register_cb(t_Handle fqr, t_QmReceivedFrameCallback *callback,
|
||||
t_Handle app)
|
||||
{
|
||||
struct qman_softc *sc;
|
||||
t_Error error;
|
||||
t_Handle portal;
|
||||
|
||||
sc = qman_sc;
|
||||
sched_pin();
|
||||
|
||||
/* Ensure we have got QMan port initialized */
|
||||
portal = qman_portal_setup(sc);
|
||||
if (portal == NULL) {
|
||||
device_printf(sc->sc_dev, "could not setup QMan portal\n");
|
||||
sched_unpin();
|
||||
return (E_NOT_SUPPORTED);
|
||||
if (rr->alter_fqs.rslt == QMAN_MC_RES_OK) {
|
||||
if (rr->alter_fqs.fqs & QMAN_MC_AFQS_NE) {
|
||||
/* TODO: Drain.... */
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
error = QM_FQR_RegisterCB(fqr, callback, app);
|
||||
|
||||
sched_unpin();
|
||||
|
||||
return (error);
|
||||
return (0);
|
||||
}
|
||||
|
||||
t_Error
|
||||
qman_fqr_enqueue(t_Handle fqr, uint32_t fqid_off, t_DpaaFD *frame)
|
||||
int
|
||||
qman_fq_free(struct qman_fq *fq)
|
||||
{
|
||||
struct qman_softc *sc;
|
||||
t_Error error;
|
||||
t_Handle portal;
|
||||
int error;
|
||||
|
||||
sc = qman_sc;
|
||||
sched_pin();
|
||||
|
||||
critical_enter();
|
||||
error = qman_fq_retire(DPCPU_GET(qman_affine_portal), fq);
|
||||
/* TODO: Take FQ out of service. */
|
||||
critical_exit();
|
||||
if (error != 0)
|
||||
return (error);
|
||||
vmem_free(sc->sc_fqalloc, fq->fqid, 1);
|
||||
qman_fq_list[fq->fqid] = NULL;
|
||||
free(fq, M_QMAN);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
qman_fq_register_cb(struct qman_fq *fq, qman_cb_dqrr callback,
|
||||
void *ctx)
|
||||
{
|
||||
fq->cb.dqrr = callback;
|
||||
fq->cb.ctx = ctx;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
qman_fq_enqueue(struct qman_fq *fq, struct dpaa_fd *frame)
|
||||
{
|
||||
struct qman_softc *sc;
|
||||
int error;
|
||||
void *portal;
|
||||
|
||||
sc = qman_sc;
|
||||
critical_enter();
|
||||
|
||||
/* Ensure we have got QMan port initialized */
|
||||
portal = qman_portal_setup(sc);
|
||||
portal = DPCPU_GET(qman_affine_portal);
|
||||
if (portal == NULL) {
|
||||
device_printf(sc->sc_dev, "could not setup QMan portal\n");
|
||||
sched_unpin();
|
||||
return (E_NOT_SUPPORTED);
|
||||
critical_exit();
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
error = QM_FQR_Enqueue(fqr, portal, fqid_off, frame);
|
||||
error = QMAN_PORTAL_ENQUEUE(portal, fq, frame);
|
||||
|
||||
sched_unpin();
|
||||
critical_exit();
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
qman_fqr_get_counter(t_Handle fqr, uint32_t fqid_off,
|
||||
e_QmFqrCounters counter)
|
||||
qman_fq_get_fqid(struct qman_fq *fq)
|
||||
{
|
||||
struct qman_softc *sc;
|
||||
uint32_t val;
|
||||
t_Handle portal;
|
||||
|
||||
sc = qman_sc;
|
||||
sched_pin();
|
||||
|
||||
/* Ensure we have got QMan port initialized */
|
||||
portal = qman_portal_setup(sc);
|
||||
if (portal == NULL) {
|
||||
device_printf(sc->sc_dev, "could not setup QMan portal\n");
|
||||
sched_unpin();
|
||||
return (0);
|
||||
}
|
||||
|
||||
val = QM_FQR_GetCounter(fqr, portal, fqid_off, counter);
|
||||
|
||||
sched_unpin();
|
||||
|
||||
return (val);
|
||||
return (fq->fqid);
|
||||
}
|
||||
|
||||
t_Error
|
||||
qman_fqr_pull_frame(t_Handle fqr, uint32_t fqid_off, t_DpaaFD *frame)
|
||||
{
|
||||
struct qman_softc *sc;
|
||||
t_Error error;
|
||||
t_Handle portal;
|
||||
|
||||
sc = qman_sc;
|
||||
sched_pin();
|
||||
|
||||
/* Ensure we have got QMan port initialized */
|
||||
portal = qman_portal_setup(sc);
|
||||
if (portal == NULL) {
|
||||
device_printf(sc->sc_dev, "could not setup QMan portal\n");
|
||||
sched_unpin();
|
||||
return (E_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
error = QM_FQR_PullFrame(fqr, portal, fqid_off, frame);
|
||||
|
||||
sched_unpin();
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
qman_fqr_get_base_fqid(t_Handle fqr)
|
||||
qman_fq_get_counter(struct qman_fq *fq, int counter)
|
||||
{
|
||||
struct qman_softc *sc;
|
||||
uint32_t val;
|
||||
t_Handle portal;
|
||||
union qman_mc_result *cmd_res;
|
||||
union qman_mc_command command;
|
||||
device_t portal;
|
||||
u_int ret = 0;
|
||||
|
||||
sc = qman_sc;
|
||||
sched_pin();
|
||||
bzero(&command, sizeof(command));
|
||||
command.query_fq_np.verb = QCSP_VERB_QUERY_FQ_NP;
|
||||
command.query_fq_np.fqid = fq->fqid;
|
||||
critical_enter();
|
||||
portal = DPCPU_GET(qman_affine_portal);
|
||||
cmd_res = QMAN_PORTAL_MC_SEND_RAW(portal, &command);
|
||||
if (counter == QMAN_COUNTER_FRAME)
|
||||
ret = cmd_res->query_fq_np.frm_cnt;
|
||||
else if (counter == QMAN_COUNTER_BYTES)
|
||||
ret = cmd_res->query_fq_np.byte_cnt;
|
||||
|
||||
/* Ensure we have got QMan port initialized */
|
||||
portal = qman_portal_setup(sc);
|
||||
if (portal == NULL) {
|
||||
device_printf(sc->sc_dev, "could not setup QMan portal\n");
|
||||
sched_unpin();
|
||||
return (0);
|
||||
}
|
||||
critical_exit();
|
||||
|
||||
val = QM_FQR_GetFqid(fqr);
|
||||
|
||||
sched_unpin();
|
||||
|
||||
return (val);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
t_Error
|
||||
qman_poll(e_QmPortalPollSource source)
|
||||
void
|
||||
qman_set_sdest(uint16_t channel, int cpu)
|
||||
{
|
||||
struct qman_softc *sc;
|
||||
t_Error error;
|
||||
t_Handle portal;
|
||||
struct qman_softc *sc = qman_sc;
|
||||
uint32_t reg;
|
||||
|
||||
sc = qman_sc;
|
||||
sched_pin();
|
||||
|
||||
/* Ensure we have got QMan port initialized */
|
||||
portal = qman_portal_setup(sc);
|
||||
if (portal == NULL) {
|
||||
device_printf(sc->sc_dev, "could not setup QMan portal\n");
|
||||
sched_unpin();
|
||||
return (E_NOT_SUPPORTED);
|
||||
if (sc->sc_qman_major >= 3) {
|
||||
reg = bus_read_4(sc->sc_rres, QCSP_IO_CFG_3(channel));
|
||||
reg &= IO_CFG_SDEST_M;
|
||||
reg |= (cpu << IO_CFG_SDEST_S);
|
||||
bus_write_4(sc->sc_rres, QCSP_IO_CFG_3(channel), reg);
|
||||
} else {
|
||||
reg = bus_read_4(sc->sc_rres, QCSP_IO_CFG(channel));
|
||||
reg &= IO_CFG_SDEST_M;
|
||||
reg |= (cpu << IO_CFG_SDEST_S);
|
||||
bus_write_4(sc->sc_rres, QCSP_IO_CFG(channel), reg);
|
||||
}
|
||||
|
||||
error = QM_Poll(sc->sc_qh, source);
|
||||
|
||||
sched_unpin();
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+142
-42
@@ -27,10 +27,13 @@
|
||||
#ifndef _QMAN_H
|
||||
#define _QMAN_H
|
||||
|
||||
#include <sys/vmem.h>
|
||||
#include <machine/vmparam.h>
|
||||
|
||||
#include <contrib/ncsw/inc/Peripherals/qm_ext.h>
|
||||
|
||||
struct qman_fq;
|
||||
struct qman_fq;
|
||||
struct dpaa_fd;
|
||||
struct qman_portal;
|
||||
|
||||
/**
|
||||
* @group QMan private defines/declarations
|
||||
@@ -44,13 +47,15 @@
|
||||
/**
|
||||
* Pool channel common to all software portals.
|
||||
* @note Value of 0 reflects the e_QM_FQ_CHANNEL_POOL1 from e_QmFQChannel
|
||||
* type used in qman_fqr_create().
|
||||
* type used in qman_fq_create().
|
||||
*/
|
||||
#define QMAN_COMMON_POOL_CHANNEL 0
|
||||
|
||||
#define QMAN_FQID_BASE 1
|
||||
|
||||
#define QMAN_CCSR_SIZE 0x1000
|
||||
/* Counters */
|
||||
#define QMAN_COUNTER_FRAME 0
|
||||
#define QMAN_COUNTER_BYTES 1
|
||||
|
||||
/*
|
||||
* Portal defines
|
||||
@@ -69,18 +74,103 @@ struct qman_softc {
|
||||
struct resource *sc_rres; /* register resource */
|
||||
int sc_irid; /* interrupt rid */
|
||||
struct resource *sc_ires; /* interrupt resource */
|
||||
vmem_t *sc_fqalloc;
|
||||
vmem_t *sc_qpalloc;
|
||||
vmem_t *sc_cgalloc;
|
||||
void *sc_intr_cookie;
|
||||
int sc_qman_base_channel;
|
||||
int sc_qman_major;
|
||||
|
||||
bool sc_regs_mapped[MAXCPU];
|
||||
|
||||
t_Handle sc_qh; /* QMAN handle */
|
||||
t_Handle sc_qph[MAXCPU]; /* QMAN portal handles */
|
||||
vm_paddr_t sc_qp_pa; /* QMAN portal PA */
|
||||
|
||||
int sc_fqr_cpu[QMAN_MAX_FQIDS];
|
||||
int sc_fq_cpu[QMAN_MAX_FQIDS];
|
||||
};
|
||||
|
||||
struct qman_fd {
|
||||
uint64_t dd:2;
|
||||
uint64_t liodn_off:6;
|
||||
uint64_t bpid:8;
|
||||
uint64_t eliodn_off:4;
|
||||
uint64_t _rsvd0:4;
|
||||
uint64_t addr:40;
|
||||
union {
|
||||
struct {
|
||||
uint32_t format:3;
|
||||
uint32_t offset:9;
|
||||
uint32_t length:20;
|
||||
};
|
||||
struct {
|
||||
uint32_t format2:3;
|
||||
uint32_t wlength:29;
|
||||
};
|
||||
};
|
||||
uint32_t cmd_stat;
|
||||
};
|
||||
|
||||
_Static_assert(sizeof(struct qman_fd) == 16, "qman_fd size mismatch");
|
||||
|
||||
struct qman_dqrr_entry {
|
||||
uint8_t verb;
|
||||
uint8_t stat;
|
||||
uint16_t seqnum;
|
||||
uint8_t tok;
|
||||
uint8_t _rsvd0[3];
|
||||
uint32_t fqid;
|
||||
uint32_t ctxb;
|
||||
struct qman_fd fd;
|
||||
uint8_t _rsvd1[32];
|
||||
};
|
||||
|
||||
/* Bits for qman_dqrr_entry fields */
|
||||
#define QMAN_DQRR_STAT_FQ_EMPTY 0x80
|
||||
#define QMAN_DQRR_STAT_FQ_HELD_ACTIVE 0x40
|
||||
#define QMAN_DQRR_STAT_FQ_FORCED 0x20
|
||||
#define QMAN_DQRR_STAT_HAS_FRAME 0x10
|
||||
#define QMAN_DQRR_STAT_VDQCR 0x02
|
||||
#define QMAN_DQRR_STAT_EXPIRED 0x01
|
||||
|
||||
struct qman_mr_entry {
|
||||
union {
|
||||
struct {
|
||||
uint8_t verb;
|
||||
uint8_t data[63];
|
||||
};
|
||||
struct {
|
||||
uint8_t verb;
|
||||
uint8_t dca;
|
||||
uint16_t seqnum;
|
||||
uint32_t rc:8;
|
||||
uint32_t orp:24;
|
||||
uint32_t fqid;
|
||||
uint32_t tag;
|
||||
struct qman_fd fd;
|
||||
uint8_t _rsvd[32];
|
||||
} ern;
|
||||
struct {
|
||||
uint8_t verb;
|
||||
uint8_t fqs;
|
||||
uint8_t _rsvd0[6];
|
||||
uint32_t fqid;
|
||||
uint32_t ctxb;
|
||||
uint8_t _rsvd1[48];
|
||||
} fqscn;
|
||||
};
|
||||
};
|
||||
|
||||
_Static_assert(sizeof(struct qman_mr_entry) == 64, "bad sizeof qman_mr");
|
||||
/** @> */
|
||||
|
||||
typedef int (*qman_cb_dqrr)(device_t, struct qman_fq *,
|
||||
struct qman_fd *, void *);
|
||||
typedef void (*qman_cb_mr)(device_t, struct qman_fq *,
|
||||
struct qman_mr_entry *);
|
||||
|
||||
struct qman_cb {
|
||||
qman_cb_dqrr dqrr;
|
||||
qman_cb_mr ern;
|
||||
qman_cb_mr fqscn;
|
||||
void *ctx;
|
||||
};
|
||||
/**
|
||||
* @group QMan bus interface
|
||||
* @{
|
||||
@@ -91,6 +181,8 @@ int qman_suspend(device_t dev);
|
||||
int qman_resume(device_t dev);
|
||||
int qman_shutdown(device_t dev);
|
||||
/** @> */
|
||||
int qman_create_affine_portal(device_t, vm_offset_t, vm_offset_t, int);
|
||||
void qman_set_sdest(uint16_t, int);
|
||||
|
||||
|
||||
/**
|
||||
@@ -149,69 +241,77 @@ int qman_shutdown(device_t dev);
|
||||
*
|
||||
* @return A handle to newly created FQR object.
|
||||
*/
|
||||
t_Handle qman_fqr_create(uint32_t fqids_num, e_QmFQChannel channel, uint8_t wq,
|
||||
bool force_fqid, uint32_t fqid_or_align, bool init_parked,
|
||||
struct qman_fq *qman_fq_create(uint32_t fqids_num, int channel,
|
||||
uint8_t wq, bool force_fqid, uint32_t fqid_or_align, bool init_parked,
|
||||
bool hold_active, bool prefer_in_cache, bool congst_avoid_ena,
|
||||
t_Handle congst_group, int8_t overhead_accounting_len,
|
||||
void *congst_group, int8_t overhead_accounting_len,
|
||||
uint32_t tail_drop_threshold);
|
||||
|
||||
/**
|
||||
* Free Frame Queue Range.
|
||||
*
|
||||
* @param fqr A handle to FQR to be freed.
|
||||
* @param fq A handle to FQR to be freed.
|
||||
* @return E_OK on success; error code otherwise.
|
||||
*/
|
||||
t_Error qman_fqr_free(t_Handle fqr);
|
||||
int qman_fq_free(struct qman_fq *fq);
|
||||
|
||||
/**
|
||||
* Register the callback function.
|
||||
* The callback function will be called when a frame comes from this FQR.
|
||||
*
|
||||
* @param fqr A handle to FQR.
|
||||
* @param fq A handle to FQR.
|
||||
* @param callback A pointer to the callback function.
|
||||
* @param app A pointer to the user's data.
|
||||
* @return E_OK on success; error code otherwise.
|
||||
*/
|
||||
t_Error qman_fqr_register_cb(t_Handle fqr, t_QmReceivedFrameCallback *callback,
|
||||
t_Handle app);
|
||||
int qman_fq_register_cb(struct qman_fq *fq, qman_cb_dqrr callback,
|
||||
void *ctx);
|
||||
|
||||
/**
|
||||
* Enqueue a frame on a given FQR.
|
||||
* Enqueue a frame on a given FQ.
|
||||
*
|
||||
* @param fqr A handle to FQR.
|
||||
* @param fqid_off FQID offset wihin the FQR.
|
||||
* @param fq A handle to FQ.
|
||||
* @param frame A frame to be enqueued to the transmission.
|
||||
* @return E_OK on success; error code otherwise.
|
||||
*/
|
||||
t_Error qman_fqr_enqueue(t_Handle fqr, uint32_t fqid_off, t_DpaaFD *frame);
|
||||
int qman_fq_enqueue(struct qman_fq *fq, struct dpaa_fd *frame);
|
||||
|
||||
/**
|
||||
* Get one of the FQR counter's value.
|
||||
* Get one of the FQ counter's value.
|
||||
*
|
||||
* @param fqr A handle to FQR.
|
||||
* @param fqid_off FQID offset within the FQR.
|
||||
* @param fq A handle to FQ.
|
||||
* @param counter The requested counter.
|
||||
* @return Counter's current value.
|
||||
*/
|
||||
uint32_t qman_fqr_get_counter(t_Handle fqr, uint32_t fqid_off,
|
||||
e_QmFqrCounters counter);
|
||||
uint32_t qman_fq_get_counter(struct qman_fq *fq, int counter);
|
||||
|
||||
/**
|
||||
* Pull frame from FQR.
|
||||
* Pull frame from FQ.
|
||||
*
|
||||
* @param fqr A handle to FQR.
|
||||
* @param fqid_off FQID offset within the FQR.
|
||||
* @param fq A handle to FQ.
|
||||
* @param frame The received frame.
|
||||
* @return E_OK on success; error code otherwise.
|
||||
*/
|
||||
t_Error qman_fqr_pull_frame(t_Handle fqr, uint32_t fqid_off, t_DpaaFD *frame);
|
||||
int qman_fq_pull_frame(struct qman_fq *fq, struct dpaa_fd *frame);
|
||||
|
||||
/**
|
||||
* Get base FQID of the FQR.
|
||||
* @param fqr A handle to FQR.
|
||||
* @return Base FQID of the FQR.
|
||||
* Get FQID of the FQ.
|
||||
* @param fq A handle to FQ.
|
||||
* @return FQID of the FQ.
|
||||
*/
|
||||
uint32_t qman_fqr_get_base_fqid(t_Handle fqr);
|
||||
uint32_t qman_fq_get_fqid(struct qman_fq *fq);
|
||||
|
||||
/*
|
||||
* Allocate a QMan channel to be used with an FQ.
|
||||
* @return Channel ID
|
||||
*/
|
||||
int qman_alloc_channel(void);
|
||||
|
||||
/*
|
||||
* Free a channel
|
||||
* @param chan Channel ID returned from qman_alloc_channel().
|
||||
*/
|
||||
void qman_free_channel(int);
|
||||
|
||||
/**
|
||||
* Poll frames from QMan.
|
||||
@@ -220,24 +320,24 @@ uint32_t qman_fqr_get_base_fqid(t_Handle fqr);
|
||||
* @param source Type of frames to be polled.
|
||||
* @return E_OK on success; error otherwise.
|
||||
*/
|
||||
t_Error qman_poll(e_QmPortalPollSource source);
|
||||
int qman_poll(int source);
|
||||
|
||||
/**
|
||||
* General received frame callback.
|
||||
* This is called, when user did not register his own callback for a given
|
||||
* frame queue range (fqr).
|
||||
* frame queue range (fq).
|
||||
*/
|
||||
e_RxStoreResponse qman_received_frame_callback(t_Handle app, t_Handle qm_fqr,
|
||||
t_Handle qm_portal, uint32_t fqid_offset, t_DpaaFD *frame);
|
||||
int qman_received_frame_callback(void *ctx, struct qman_fq *fq,
|
||||
void *qm_portal, uint32_t fqid_offset, struct dpaa_fd *frame);
|
||||
|
||||
/**
|
||||
* General rejected frame callback.
|
||||
* This is called, when user did not register his own callback for a given
|
||||
* frame queue range (fqr).
|
||||
* frame queue range (fq).
|
||||
*/
|
||||
e_RxStoreResponse qman_rejected_frame_callback(t_Handle app, t_Handle qm_fqr,
|
||||
t_Handle qm_portal, uint32_t fqid_offset, t_DpaaFD *frame,
|
||||
t_QmRejectedFrameInfo *qm_rejected_frame_info);
|
||||
int qman_rejected_frame_callback(void *ctx, struct qman_fq *fq,
|
||||
void *qm_portal, uint32_t fqid_offset, struct dpaa_fd *frame,
|
||||
void *qm_rejected_frame_info);
|
||||
|
||||
/** @} */
|
||||
|
||||
|
||||
+30
-138
@@ -41,6 +41,8 @@
|
||||
|
||||
#include "qman.h"
|
||||
#include "portals.h"
|
||||
#include "qman_var.h"
|
||||
#include "qman_portal_if.h"
|
||||
|
||||
#define FQMAN_DEVSTR "Freescale Queue Manager"
|
||||
|
||||
@@ -59,12 +61,7 @@ static device_method_t qman_methods[] = {
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
||||
static driver_t qman_driver = {
|
||||
"qman",
|
||||
qman_methods,
|
||||
sizeof(struct qman_softc),
|
||||
};
|
||||
|
||||
DEFINE_CLASS_0(qman, qman_driver, qman_methods, sizeof(struct qman_softc));
|
||||
EARLY_DRIVER_MODULE(qman, simplebus, qman_driver, 0, 0, BUS_PASS_SUPPORTDEV);
|
||||
|
||||
static int
|
||||
@@ -82,53 +79,38 @@ qman_fdt_probe(device_t dev)
|
||||
/*
|
||||
* QMAN Portals
|
||||
*/
|
||||
#define QMAN_PORT_DEVSTR "Freescale Queue Manager - Portals"
|
||||
#define QMAN_PORT_DEVSTR "Freescale Queue Manager - Portal"
|
||||
|
||||
static device_probe_t qman_portals_fdt_probe;
|
||||
static device_attach_t qman_portals_fdt_attach;
|
||||
static int portal_ncpus;
|
||||
static device_probe_t qman_portal_fdt_probe;
|
||||
static device_attach_t qman_portal_fdt_attach;
|
||||
|
||||
static device_method_t qm_portals_methods[] = {
|
||||
static device_method_t qman_portal_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, qman_portals_fdt_probe),
|
||||
DEVMETHOD(device_attach, qman_portals_fdt_attach),
|
||||
DEVMETHOD(device_detach, qman_portals_detach),
|
||||
DEVMETHOD(device_probe, qman_portal_fdt_probe),
|
||||
DEVMETHOD(device_attach, qman_portal_fdt_attach),
|
||||
DEVMETHOD(device_detach, qman_portal_detach),
|
||||
|
||||
DEVMETHOD(qman_portal_enqueue, qman_portal_fq_enqueue),
|
||||
DEVMETHOD(qman_portal_mc_send_raw, qman_portal_mc_send_raw),
|
||||
DEVMETHOD(qman_portal_static_dequeue_channel,
|
||||
qman_portal_static_dequeue_channel),
|
||||
DEVMETHOD(qman_portal_static_dequeue_rm_channel,
|
||||
qman_portal_static_dequeue_rm_channel),
|
||||
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
||||
static driver_t qm_portals_driver = {
|
||||
"qman-portals",
|
||||
qm_portals_methods,
|
||||
sizeof(struct dpaa_portals_softc),
|
||||
};
|
||||
|
||||
EARLY_DRIVER_MODULE(qman_portals, ofwbus, qm_portals_driver, 0, 0,
|
||||
BUS_PASS_BUS);
|
||||
|
||||
static void
|
||||
get_addr_props(phandle_t node, uint32_t *addrp, uint32_t *sizep)
|
||||
{
|
||||
|
||||
*addrp = 2;
|
||||
*sizep = 1;
|
||||
OF_getencprop(node, "#address-cells", addrp, sizeof(*addrp));
|
||||
OF_getencprop(node, "#size-cells", sizep, sizeof(*sizep));
|
||||
}
|
||||
DEFINE_CLASS_0(qman_portal, qman_portal_driver, qman_portal_methods,
|
||||
sizeof(struct qman_softc));
|
||||
EARLY_DRIVER_MODULE(qman_portal, simplebus, qman_portal_driver, 0, 0,
|
||||
BUS_PASS_SUPPORTDEV + BUS_PASS_ORDER_MIDDLE);
|
||||
|
||||
static int
|
||||
qman_portals_fdt_probe(device_t dev)
|
||||
qman_portal_fdt_probe(device_t dev)
|
||||
{
|
||||
phandle_t node;
|
||||
|
||||
if (ofw_bus_is_compatible(dev, "simple-bus")) {
|
||||
node = ofw_bus_get_node(dev);
|
||||
for (node = OF_child(node); node > 0; node = OF_peer(node)) {
|
||||
if (ofw_bus_node_is_compatible(node, "fsl,qman-portal"))
|
||||
break;
|
||||
}
|
||||
if (node <= 0)
|
||||
return (ENXIO);
|
||||
} else if (!ofw_bus_is_compatible(dev, "fsl,qman-portals"))
|
||||
if (!ofw_bus_is_compatible(dev, "fsl,qman-portal"))
|
||||
return (ENXIO);
|
||||
|
||||
device_set_desc(dev, QMAN_PORT_DEVSTR);
|
||||
@@ -137,105 +119,15 @@ qman_portals_fdt_probe(device_t dev)
|
||||
}
|
||||
|
||||
static int
|
||||
qman_portals_fdt_attach(device_t dev)
|
||||
qman_portal_fdt_attach(device_t dev)
|
||||
{
|
||||
struct dpaa_portals_softc *sc;
|
||||
phandle_t node, child, cpu_node;
|
||||
vm_paddr_t portal_pa, portal_par_pa;
|
||||
vm_size_t portal_size;
|
||||
uint32_t addr, paddr, size;
|
||||
ihandle_t cpu;
|
||||
int cpu_num, cpus, intr_rid;
|
||||
struct dpaa_portals_devinfo di;
|
||||
struct ofw_bus_devinfo ofw_di = {};
|
||||
cell_t *range;
|
||||
int nrange;
|
||||
int i;
|
||||
int portal_cpu = portal_ncpus;
|
||||
|
||||
cpus = 0;
|
||||
sc = device_get_softc(dev);
|
||||
sc->sc_dev = dev;
|
||||
|
||||
node = ofw_bus_get_node(dev);
|
||||
|
||||
/* Get this node's range */
|
||||
get_addr_props(ofw_bus_get_node(device_get_parent(dev)), &paddr, &size);
|
||||
get_addr_props(node, &addr, &size);
|
||||
|
||||
nrange = OF_getencprop_alloc_multi(node, "ranges",
|
||||
sizeof(*range), (void **)&range);
|
||||
if (nrange < addr + paddr + size)
|
||||
/* Don't attach to more portals than we have CPUs */
|
||||
if (mp_ncpus == portal_ncpus)
|
||||
return (ENXIO);
|
||||
portal_pa = portal_par_pa = 0;
|
||||
portal_size = 0;
|
||||
for (i = 0; i < addr; i++) {
|
||||
portal_pa <<= 32;
|
||||
portal_pa |= range[i];
|
||||
}
|
||||
for (; i < paddr + addr; i++) {
|
||||
portal_par_pa <<= 32;
|
||||
portal_par_pa |= range[i];
|
||||
}
|
||||
portal_pa += portal_par_pa;
|
||||
for (; i < size + paddr + addr; i++) {
|
||||
portal_size = (uintmax_t)portal_size << 32;
|
||||
portal_size |= range[i];
|
||||
}
|
||||
OF_prop_free(range);
|
||||
sc->sc_dp_size = portal_size;
|
||||
sc->sc_dp_pa = portal_pa;
|
||||
|
||||
/* Find portals tied to CPUs */
|
||||
for (child = OF_child(node); child != 0; child = OF_peer(child)) {
|
||||
if (cpus >= mp_ncpus)
|
||||
break;
|
||||
if (!ofw_bus_node_is_compatible(child, "fsl,qman-portal")) {
|
||||
continue;
|
||||
}
|
||||
/* Checkout related cpu */
|
||||
if (OF_getprop(child, "cpu-handle", (void *)&cpu,
|
||||
sizeof(cpu)) > 0) {
|
||||
cpu_node = OF_instance_to_package(cpu);
|
||||
/* Acquire cpu number */
|
||||
if (OF_getencprop(cpu_node, "reg", &cpu_num, sizeof(cpu_num)) <= 0) {
|
||||
device_printf(dev, "Could not retrieve CPU number.\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
} else
|
||||
cpu_num = cpus;
|
||||
cpus++;
|
||||
portal_ncpus++;
|
||||
|
||||
if (ofw_bus_gen_setup_devinfo(&ofw_di, child) != 0) {
|
||||
device_printf(dev, "could not set up devinfo\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
resource_list_init(&di.di_res);
|
||||
if (ofw_bus_reg_to_rl(dev, child, addr, size, &di.di_res)) {
|
||||
device_printf(dev, "%s: could not process 'reg' "
|
||||
"property\n", ofw_di.obd_name);
|
||||
ofw_bus_gen_destroy_devinfo(&ofw_di);
|
||||
continue;
|
||||
}
|
||||
if (ofw_bus_intr_to_rl(dev, child, &di.di_res, &intr_rid)) {
|
||||
device_printf(dev, "%s: could not process "
|
||||
"'interrupts' property\n", ofw_di.obd_name);
|
||||
resource_list_free(&di.di_res);
|
||||
ofw_bus_gen_destroy_devinfo(&ofw_di);
|
||||
continue;
|
||||
}
|
||||
di.di_intr_rid = intr_rid;
|
||||
|
||||
if (dpaa_portal_alloc_res(dev, &di, cpu_num))
|
||||
goto err;
|
||||
}
|
||||
|
||||
ofw_bus_gen_destroy_devinfo(&ofw_di);
|
||||
|
||||
return (qman_portals_attach(dev));
|
||||
err:
|
||||
resource_list_free(&di.di_res);
|
||||
ofw_bus_gen_destroy_devinfo(&ofw_di);
|
||||
qman_portals_detach(dev);
|
||||
return (ENXIO);
|
||||
return (qman_portal_attach(dev, portal_cpu));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
#-
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
#
|
||||
# Copyright (c) 2026 Justin Hibbits
|
||||
|
||||
#include <sys/pcpu.h>
|
||||
#include <machine/bus.h>
|
||||
#include <dev/dpaa/portals.h>
|
||||
#include <dev/dpaa/qman.h>
|
||||
#include <dev/dpaa/qman_var.h>
|
||||
|
||||
/**
|
||||
* @brief DPAA QMan portal interface
|
||||
*
|
||||
*/
|
||||
INTERFACE qman_portal;
|
||||
|
||||
METHOD int enqueue {
|
||||
device_t dev;
|
||||
struct qman_fq *fq;
|
||||
struct dpaa_fd *fd;
|
||||
};
|
||||
|
||||
METHOD union qman_mc_result * mc_send_raw {
|
||||
device_t dev;
|
||||
union qman_mc_command *cmd;
|
||||
};
|
||||
|
||||
METHOD void static_dequeue_channel {
|
||||
device_t dev;
|
||||
int channel;
|
||||
}
|
||||
|
||||
METHOD void static_dequeue_rm_channel {
|
||||
device_t dev;
|
||||
int channel;
|
||||
}
|
||||
+389
-139
@@ -1,27 +1,7 @@
|
||||
/*-
|
||||
* Copyright (c) 2012 Semihalf.
|
||||
* All rights reserved.
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* 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.
|
||||
* Copyright (c) 2026 Justin Hibbits
|
||||
*/
|
||||
|
||||
#include "opt_platform.h"
|
||||
@@ -36,6 +16,7 @@
|
||||
#include <sys/proc.h>
|
||||
#include <sys/pcpu.h>
|
||||
#include <sys/sched.h>
|
||||
#include <ddb/ddb.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
#include <machine/tlb.h>
|
||||
@@ -47,143 +28,412 @@
|
||||
|
||||
#include "qman.h"
|
||||
#include "portals.h"
|
||||
#include "qman_var.h"
|
||||
|
||||
extern e_RxStoreResponse qman_received_frame_callback(t_Handle, t_Handle,
|
||||
t_Handle, uint32_t, t_DpaaFD *);
|
||||
extern e_RxStoreResponse qman_rejected_frame_callback(t_Handle, t_Handle,
|
||||
t_Handle, uint32_t, t_DpaaFD *, t_QmRejectedFrameInfo *);
|
||||
|
||||
t_Handle qman_portal_setup(struct qman_softc *);
|
||||
/* Cache-enabled registers */
|
||||
#define QCSP_EQCR_N(n) (0x0000 + (n * 64))
|
||||
#define QMAN_EQCR_COUNT 8
|
||||
#define QCSP_DQRR_N(n) (0x1000 + (n * 64))
|
||||
#define QMAN_DQRR_COUNT 16
|
||||
#define QCSP_MR_N(n) (0x2000 + (n * 64))
|
||||
#define QMAN_MR_COUNT 8
|
||||
#define QCSP_CR 0x3800
|
||||
#define QCSP_RR(n) (0x3900 + 0x40 * (n))
|
||||
|
||||
struct dpaa_portals_softc *qp_sc;
|
||||
#define QCSP_EQCR_PI_CENA 0x0000
|
||||
#define EQCR_PI_VP 0x00000008
|
||||
#define EQCR_PI_PI_M 0x00000007
|
||||
#define QCSP_EQCR_CI_CENA 0x0004
|
||||
#define EQCR_CI_C 0x00000008
|
||||
#define EQCR_CI_CI_M 0x00000007
|
||||
#define QCSP_DQRR_PI_CENA 0x0000
|
||||
#define DQRR_PI_VP 0x00000010
|
||||
#define DQRR_PI_PI_M 0x0000000f
|
||||
#define QCSP_DQRR_CI_CENA 0x0004
|
||||
#define DQRR_CI_C 0x00000010
|
||||
#define DQRR_CI_CI_M 0x0000000f
|
||||
|
||||
#define QMAN_MC_VERB_VBIT 0x80
|
||||
|
||||
|
||||
/* Cache-inhibited registers */
|
||||
#define QCSP_EQCR_PI_CINH 0x0000
|
||||
#define QCSP_EQCR_CI_CINH 0x0004
|
||||
#define QCSP_DQRR_PI_CINH 0x0040
|
||||
#define QCSP_DQRR_CI_CINH 0x0044
|
||||
#define QCSP_EQCR_ITR 0x0008
|
||||
#define QCSP_DQRR_ITR 0x0048
|
||||
#define QCSP_DQRR_SDQCR 0x0054
|
||||
#define SDQCR_SS 0x40000000
|
||||
#define SDQCR_FC 0x20000000
|
||||
#define SDQCR_DP 0x10000000
|
||||
#define SDQCR_DCT_NUL 0x00000000
|
||||
#define SDQCR_DCT_PRI_PREC 0x01000000
|
||||
#define SDQCR_DCT_ACTIVE_WQ 0x02000000
|
||||
#define SDQCR_DCT_ACTIVE_FQ_O 0x03000000
|
||||
#define SDQCR_DCT_M 0x03000000
|
||||
#define SDQCR_TOKEN_M 0x00ff0000
|
||||
#define SDQCR_TOKEN_S 16
|
||||
#define DQRR_DQ_SRC_M 0x0000ffff
|
||||
#define DQRR_DQ_SRC_DCP 0x00008000
|
||||
#define SDQCR_DQ_SRC_CHAN(n) (0x8000 >> (n + 1))
|
||||
#define QCSP_DQRR_VDQCR 0x0058
|
||||
#define QCSP_DQRR_PDQCR 0x005c
|
||||
#define QCSP_MR_ITR 0x0088
|
||||
#define QCSP_CFG 0x0100
|
||||
#define CFG_EST_M 0x70000000
|
||||
#define CFG_EST_S 28
|
||||
#define CFG_EP 0x04000000
|
||||
#define CFG_EPM_M 0x03000000
|
||||
#define CFG_EPM_PI_CI 0x00000000
|
||||
#define CFG_EPM_PI_CE 0x01000000
|
||||
#define CFG_EPM_VB1 0x02000000
|
||||
#define CFG_EPM_VB2 0x03000000
|
||||
#define CFG_DQRR_MF_M 0x00f00000
|
||||
#define CFG_DQRR_MF_S 20
|
||||
#define CFG_DP 0x00040000
|
||||
#define CFG_DCM_C_M 0x00030000
|
||||
#define CFG_DCM_CI_CI 0x00000000
|
||||
#define CFG_DCM_CI_CE 0x00010000
|
||||
#define CFG_DCM_DCA1 0x00020000
|
||||
#define CFG_DCM_DCA2 0x00030000
|
||||
#define CFG_SD 0x00000200
|
||||
#define CFG_MM 0x00000100
|
||||
#define CFG_RE 0x00000080
|
||||
#define CFG_RP 0x00000040
|
||||
#define CFG_SE 0x00000020
|
||||
#define CFG_SP 0x00000010
|
||||
#define CFG_SDEST_M 0x00000007
|
||||
#define QCSP_ISR 0x0e00
|
||||
#define QM_PIRQ_CSCI 0x00100000
|
||||
#define QM_PIRQ_EQCI 0x00080000
|
||||
#define QM_PIRQ_EQRI 0x00040000
|
||||
#define QM_PIRQ_DQRI 0x00020000
|
||||
#define QM_PIRQ_MRI 0x00010000
|
||||
#define QM_PIRQ_DQ_AVAIL_M 0x0000ffff
|
||||
#define QCSP_IER 0x0e04
|
||||
#define QCSP_ISDR 0x0e08
|
||||
#define QCSP_IIR 0xe0c
|
||||
|
||||
#define QM_EQCR_VERB_CMD_ENQUEUE 0x01
|
||||
#define QM_EQCR_VERB_BIT_INT 0x04
|
||||
|
||||
#define DEF_SDQCR_TOKEN 0xab
|
||||
|
||||
static void qman_portal_loop_rings(struct qman_portal_softc *sc);
|
||||
static void qman_portal_isr(void *);
|
||||
|
||||
DPCPU_DEFINE(device_t, qman_affine_portal);
|
||||
DPAA_RING(qman_eqcr, QMAN_EQCR_COUNT, QCSP_EQCR_PI_CENA, QCSP_EQCR_CI_CENA,
|
||||
QCSP_EQCR_PI_CINH, QCSP_EQCR_CI_CINH);
|
||||
DPAA_RING(qman_dqrr, QMAN_DQRR_COUNT, QCSP_DQRR_PI_CENA, QCSP_DQRR_CI_CENA,
|
||||
QCSP_DQRR_PI_CINH, QCSP_DQRR_CI_CINH);
|
||||
|
||||
/*
|
||||
* pmode: one of the CFG_EPM constants.
|
||||
* stash_prio: 0 or CFG_EP
|
||||
* stash_thresh: 0-7
|
||||
*/
|
||||
static int
|
||||
qman_eqcr_init(struct qman_portal_softc *sc, int pmode, u_int stash_thresh,
|
||||
u_int stash_prio)
|
||||
{
|
||||
struct resource *regs = sc->sc_base.sc_mres[1];
|
||||
uint32_t reg;
|
||||
|
||||
sc->sc_eqcr.ring =
|
||||
(struct qman_eqcr_entry *)(sc->sc_base.sc_ce_va + QCSP_EQCR_N(0));
|
||||
qman_eqcr_ring_init(&sc->sc_eqcr, &sc->sc_base);
|
||||
reg = bus_read_4(regs, QCSP_CFG);
|
||||
reg &= 0x00ffffff;
|
||||
reg |= pmode;
|
||||
reg |= ((stash_thresh << CFG_EST_S) & CFG_EST_M);
|
||||
reg |= stash_prio;
|
||||
|
||||
bus_write_4(regs, QCSP_CFG, reg);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
qman_dqrr_init(struct qman_portal_softc *sc)
|
||||
{
|
||||
struct resource *regs = sc->sc_base.sc_mres[1];
|
||||
uint32_t reg;
|
||||
|
||||
/* Dequeue from the direct-connect channel and pool 0, up to 3 frames */
|
||||
bus_write_4(regs, QCSP_DQRR_SDQCR,
|
||||
SDQCR_FC | SDQCR_DP | SDQCR_DCT_PRI_PREC |
|
||||
(DEF_SDQCR_TOKEN << SDQCR_TOKEN_S) |
|
||||
DQRR_DQ_SRC_DCP | SDQCR_DQ_SRC_CHAN(0));
|
||||
bus_write_4(regs, QCSP_DQRR_VDQCR, 0);
|
||||
bus_write_4(regs, QCSP_DQRR_PDQCR, 0);
|
||||
|
||||
sc->sc_dqrr.ring =
|
||||
(struct qman_dqrr_entry *)(sc->sc_base.sc_ce_va + QCSP_DQRR_N(0));
|
||||
qman_dqrr_ring_init(&sc->sc_dqrr, &sc->sc_base);
|
||||
|
||||
/* Set DQRR max fill to 15 */
|
||||
reg = bus_read_4(regs, QCSP_CFG);
|
||||
reg |= (0xf << CFG_DQRR_MF_S);
|
||||
bus_write_4(regs, QCSP_CFG, reg);
|
||||
|
||||
for (int i = 0; i < QMAN_DQRR_COUNT; i++)
|
||||
__asm __volatile ("dcbi 0,%0" :: "r"(&sc->sc_dqrr.ring[i]) : "memory");
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
qman_portals_attach(device_t dev)
|
||||
qman_portal_attach(device_t dev, int cpu)
|
||||
{
|
||||
struct dpaa_portals_softc *sc;
|
||||
struct qman_portal_softc *sc = device_get_softc(dev);
|
||||
union qman_mc_command *cr;
|
||||
pcell_t cell;
|
||||
phandle_t node;
|
||||
|
||||
sc = qp_sc = device_get_softc(dev);
|
||||
|
||||
/* Map bman portal to physical address space */
|
||||
if (law_enable(OCP85XX_TGTIF_QMAN, sc->sc_dp_pa, sc->sc_dp_size)) {
|
||||
qman_portals_detach(dev);
|
||||
sc->sc_base.sc_cpu = cpu;
|
||||
dpaa_portal_alloc_res(dev, cpu);
|
||||
|
||||
qman_eqcr_init(sc, CFG_EPM_VB1, 0, 0);
|
||||
qman_dqrr_init(sc);
|
||||
bus_setup_intr(dev, sc->sc_base.sc_ires, INTR_TYPE_NET | INTR_MPSAFE,
|
||||
NULL, qman_portal_isr, sc, &sc->sc_base.sc_intr_cookie);
|
||||
bus_bind_intr(dev, sc->sc_base.sc_ires, cpu);
|
||||
|
||||
node = ofw_bus_get_node(dev);
|
||||
if (OF_getencprop(node, "cell-index", &cell, sizeof(cell)) <= 0) {
|
||||
device_printf(dev, "missing 'cell-index' property\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
/* Set portal properties for XX_VirtToPhys() */
|
||||
XX_PortalSetInfo(dev);
|
||||
sc->sc_affine_channel = cell;
|
||||
DPCPU_ID_SET(cpu, qman_affine_portal, dev);
|
||||
bus_write_4(sc->sc_base.sc_mres[1], QCSP_IER,
|
||||
QM_PIRQ_EQCI | QM_PIRQ_EQRI | QM_PIRQ_MRI | QM_PIRQ_CSCI |
|
||||
QM_PIRQ_DQRI);
|
||||
bus_write_4(sc->sc_base.sc_mres[1], QCSP_ISDR, 0);
|
||||
|
||||
/* Initialize the MC polarity bit, it may not be 0. */
|
||||
cr = (union qman_mc_command *)(sc->sc_base.sc_ce_va + QCSP_CR);
|
||||
sc->sc_mc.polarity =
|
||||
(cr->common.verb & QMAN_MC_VERB_VBIT) ^ QMAN_MC_VERB_VBIT;
|
||||
/* TODO: LIODN. Fake it for now */
|
||||
|
||||
qman_set_sdest(sc->sc_affine_channel, cpu);
|
||||
|
||||
bus_attach_children(dev);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
qman_portal_detach(device_t dev)
|
||||
{
|
||||
struct qman_portal_softc *sc;
|
||||
int i;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
/* TODO: Unmap TLB regions */
|
||||
thread_lock(curthread);
|
||||
sched_bind(curthread, sc->sc_base.sc_cpu);
|
||||
thread_unlock(curthread);
|
||||
|
||||
if (sc->sc_base.sc_ires != NULL)
|
||||
bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_base.sc_ires);
|
||||
|
||||
for (i = 0; i < nitems(sc->sc_base.sc_mres); i++) {
|
||||
if (sc->sc_base.sc_mres[i] != NULL)
|
||||
bus_release_resource(dev, SYS_RES_MEMORY,
|
||||
i, sc->sc_base.sc_mres[i]);
|
||||
}
|
||||
thread_lock(curthread);
|
||||
sched_unbind(curthread);
|
||||
thread_unlock(curthread);
|
||||
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
qman_portal_isr(void *arg)
|
||||
{
|
||||
struct qman_portal_softc *sc = arg;
|
||||
|
||||
qman_portal_loop_rings(sc);
|
||||
}
|
||||
|
||||
int
|
||||
qman_portals_detach(device_t dev)
|
||||
qman_portal_fq_enqueue(device_t dev, struct qman_fq *fq, struct dpaa_fd *frame)
|
||||
{
|
||||
struct dpaa_portals_softc *sc;
|
||||
int i;
|
||||
struct qman_portal_softc *sc = device_get_softc(dev);
|
||||
struct qman_eqcr_entry *eqcr;
|
||||
|
||||
qp_sc = NULL;
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sc->sc_dp); i++) {
|
||||
if (sc->sc_dp[i].dp_ph != NULL) {
|
||||
thread_lock(curthread);
|
||||
sched_bind(curthread, i);
|
||||
thread_unlock(curthread);
|
||||
|
||||
QM_PORTAL_Free(sc->sc_dp[i].dp_ph);
|
||||
|
||||
thread_lock(curthread);
|
||||
sched_unbind(curthread);
|
||||
thread_unlock(curthread);
|
||||
}
|
||||
|
||||
if (sc->sc_dp[i].dp_ires != NULL) {
|
||||
XX_DeallocIntr((uintptr_t)sc->sc_dp[i].dp_ires);
|
||||
bus_release_resource(dev, SYS_RES_IRQ,
|
||||
sc->sc_dp[i].dp_irid, sc->sc_dp[i].dp_ires);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < ARRAY_SIZE(sc->sc_rres); i++) {
|
||||
if (sc->sc_rres[i] != NULL)
|
||||
bus_release_resource(dev, SYS_RES_MEMORY,
|
||||
sc->sc_rrid[i],
|
||||
sc->sc_rres[i]);
|
||||
}
|
||||
/* Get available... */
|
||||
eqcr = qman_eqcr_start(&sc->sc_eqcr, &sc->sc_base);
|
||||
if (eqcr == NULL)
|
||||
return (EBUSY);
|
||||
eqcr->fd = *frame;
|
||||
eqcr->fqid = fq->fqid;
|
||||
qman_eqcr_commit(&sc->sc_eqcr, QM_EQCR_VERB_CMD_ENQUEUE);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
t_Handle
|
||||
qman_portal_setup(struct qman_softc *qsc)
|
||||
static int
|
||||
qman_portal_loop_dqrr(struct qman_portal_softc *sc)
|
||||
{
|
||||
struct dpaa_portals_softc *sc;
|
||||
t_QmPortalParam qpp;
|
||||
unsigned int cpu;
|
||||
uintptr_t p;
|
||||
t_Handle portal;
|
||||
struct qman_dqrr_entry *dqrr;
|
||||
struct qman_dqrr_entry *base;
|
||||
struct qman_fq *fq;
|
||||
int ci = bus_read_4(sc->sc_base.sc_mres[1], QCSP_DQRR_CI_CINH) &
|
||||
DQRR_CI_CI_M;
|
||||
int pi = bus_read_4(sc->sc_base.sc_mres[1], QCSP_DQRR_PI_CINH) &
|
||||
DQRR_PI_PI_M;
|
||||
|
||||
/* Return NULL if we're not ready or while detach */
|
||||
if (qp_sc == NULL)
|
||||
return (NULL);
|
||||
base = sc->sc_dqrr.ring;
|
||||
do {
|
||||
dqrr = &base[ci];
|
||||
dpaa_flush_line(dqrr);
|
||||
dpaa_touch_line(dqrr);
|
||||
if ((dqrr->stat & QMAN_DQRR_STAT_HAS_FRAME)) {
|
||||
fq = qman_fq_from_index(dqrr->fqid);
|
||||
if (fq != NULL && fq->cb.dqrr != NULL) {
|
||||
fq->cb.dqrr(sc->sc_base.sc_dev, fq,
|
||||
&dqrr->fd, fq->cb.ctx);
|
||||
}
|
||||
} else
|
||||
break;
|
||||
ci = (ci + 1) & DQRR_CI_CI_M;
|
||||
bus_write_4(sc->sc_base.sc_mres[1], QCSP_DQRR_CI_CINH, ci);
|
||||
} while (ci != pi);
|
||||
|
||||
sc = qp_sc;
|
||||
|
||||
sched_pin();
|
||||
portal = NULL;
|
||||
cpu = PCPU_GET(cpuid);
|
||||
|
||||
/* Check if portal is ready */
|
||||
while (atomic_cmpset_acq_ptr((uintptr_t *)&sc->sc_dp[cpu].dp_ph,
|
||||
0, -1) == 0) {
|
||||
p = atomic_load_acq_ptr((uintptr_t *)&sc->sc_dp[cpu].dp_ph);
|
||||
|
||||
/* Return if portal is already initialized */
|
||||
if (p != 0 && p != -1) {
|
||||
sched_unpin();
|
||||
return ((t_Handle)p);
|
||||
}
|
||||
|
||||
/* Not inititialized and "owned" by another thread */
|
||||
sched_relinquish(curthread);
|
||||
}
|
||||
|
||||
/* Map portal registers */
|
||||
dpaa_portal_map_registers(sc);
|
||||
|
||||
/* Configure and initialize portal */
|
||||
qpp.ceBaseAddress = rman_get_bushandle(sc->sc_rres[0]);
|
||||
qpp.ciBaseAddress = rman_get_bushandle(sc->sc_rres[1]);
|
||||
qpp.h_Qm = qsc->sc_qh;
|
||||
qpp.swPortalId = cpu;
|
||||
qpp.irq = (uintptr_t)sc->sc_dp[cpu].dp_ires;
|
||||
qpp.fdLiodnOffset = 0;
|
||||
qpp.f_DfltFrame = qman_received_frame_callback;
|
||||
qpp.f_RejectedFrame = qman_rejected_frame_callback;
|
||||
qpp.h_App = qsc;
|
||||
|
||||
portal = QM_PORTAL_Config(&qpp);
|
||||
if (portal == NULL)
|
||||
goto err;
|
||||
|
||||
if (QM_PORTAL_Init(portal) != E_OK)
|
||||
goto err;
|
||||
|
||||
if (QM_PORTAL_AddPoolChannel(portal, QMAN_COMMON_POOL_CHANNEL) != E_OK)
|
||||
goto err;
|
||||
|
||||
atomic_store_rel_ptr((uintptr_t *)&sc->sc_dp[cpu].dp_ph,
|
||||
(uintptr_t)portal);
|
||||
sched_unpin();
|
||||
|
||||
return (portal);
|
||||
|
||||
err:
|
||||
if (portal != NULL)
|
||||
QM_PORTAL_Free(portal);
|
||||
|
||||
atomic_store_rel_32((uint32_t *)&sc->sc_dp[cpu].dp_ph, 0);
|
||||
sched_unpin();
|
||||
|
||||
return (NULL);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
qman_portal_loop_rings(struct qman_portal_softc *sc)
|
||||
{
|
||||
uint32_t isr;
|
||||
|
||||
isr = bus_read_4(sc->sc_base.sc_mres[1], QCSP_ISR);
|
||||
|
||||
/* Handle DQRR first. */
|
||||
if ((isr & QM_PIRQ_DQRI)) {
|
||||
qman_portal_loop_dqrr(sc);
|
||||
}
|
||||
if ((isr & QM_PIRQ_CSCI)) {
|
||||
}
|
||||
if ((isr & QM_PIRQ_EQRI)) {
|
||||
qman_eqcr_update(&sc->sc_eqcr, &sc->sc_base);
|
||||
}
|
||||
bus_write_4(sc->sc_base.sc_mres[1], QCSP_ISR, isr);
|
||||
}
|
||||
|
||||
/* MC commands */
|
||||
|
||||
/* Assumes pinned */
|
||||
union qman_mc_result *
|
||||
qman_portal_mc_send_raw(device_t dev, union qman_mc_command *c)
|
||||
{
|
||||
struct qman_portal_softc *sc;
|
||||
int res_idx;
|
||||
union qman_mc_result *rr;
|
||||
union qman_mc_command *cr;
|
||||
int timeout = 10000;
|
||||
uint8_t verb;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
verb = c->common.verb;
|
||||
c->common.verb = 0;
|
||||
cr = (union qman_mc_command *)(sc->sc_base.sc_ce_va + QCSP_CR);
|
||||
dpaa_zero_line(cr);
|
||||
*cr = *c;
|
||||
dpaa_lw_barrier();
|
||||
cr->common.verb = verb | sc->sc_mc.polarity;
|
||||
res_idx = (sc->sc_mc.polarity ? 1 : 0);
|
||||
sc->sc_mc.polarity ^= QMAN_MC_VERB_VBIT;
|
||||
dpaa_flush_line(cr);
|
||||
dpaa_touch_line(cr);
|
||||
|
||||
rr = (union qman_mc_result *)(sc->sc_base.sc_ce_va + QCSP_RR(res_idx));
|
||||
for (; timeout > 0; --timeout) {
|
||||
dpaa_flush_line(rr);
|
||||
if (rr->common.verb != 0)
|
||||
break;
|
||||
}
|
||||
if (timeout == 0)
|
||||
return (NULL);
|
||||
return (rr);
|
||||
}
|
||||
|
||||
void
|
||||
qman_portal_static_dequeue_channel(device_t dev, int channel)
|
||||
{
|
||||
struct qman_portal_softc *sc = device_get_softc(dev);
|
||||
uint32_t reg;
|
||||
|
||||
reg = bus_read_4(sc->sc_base.sc_mres[1], QCSP_DQRR_SDQCR);
|
||||
reg |= (1 << (15 - (channel - qman_channel_base)));
|
||||
bus_write_4(sc->sc_base.sc_mres[1], QCSP_DQRR_SDQCR, reg);
|
||||
}
|
||||
|
||||
void
|
||||
qman_portal_static_dequeue_rm_channel(device_t dev, int channel)
|
||||
{
|
||||
struct qman_portal_softc *sc = device_get_softc(dev);
|
||||
uint32_t reg;
|
||||
|
||||
reg = bus_read_4(sc->sc_base.sc_mres[1], QCSP_DQRR_SDQCR);
|
||||
reg &= ~(1 << (15 - (channel - qman_channel_base)));
|
||||
bus_write_4(sc->sc_base.sc_mres[1], QCSP_DQRR_SDQCR, reg);
|
||||
}
|
||||
|
||||
DB_SHOW_COMMAND(fqid, qman_show_fqid)
|
||||
{
|
||||
union qman_mc_command cmd;
|
||||
union qman_mc_result *res;
|
||||
union qman_mc_result save_res;
|
||||
device_t portal;
|
||||
|
||||
if (!have_addr)
|
||||
return;
|
||||
|
||||
bzero(&cmd, sizeof(cmd));
|
||||
cmd.query_fq_np.fqid = addr;
|
||||
|
||||
/* Ensure we have got QMan port initialized */
|
||||
portal = DPCPU_GET(qman_affine_portal);
|
||||
res = qman_portal_mc_send_raw(portal, &cmd);
|
||||
|
||||
if (res != NULL)
|
||||
save_res = *res;
|
||||
|
||||
/* Dump all NP fields */
|
||||
if (res != NULL && save_res.query_fq_np.rslt == 0xf0) {
|
||||
db_printf("FQID: %d\n", (int)addr);
|
||||
db_printf(" State: %x\n", save_res.query_fq_np.state);
|
||||
db_printf(" Link: %x\n", save_res.query_fq_np.fqd_link);
|
||||
db_printf(" ODP_SEQ: %x\n", save_res.query_fq_np.odp_seq);
|
||||
db_printf(" ORP_NESN: %x\n", save_res.query_fq_np.orp_nesn);
|
||||
db_printf(" ORP_EA_HSEQ: %x\n",
|
||||
save_res.query_fq_np.orp_ea_hseq);
|
||||
db_printf(" ORP_EA_TSEQ: %x\n",
|
||||
save_res.query_fq_np.orp_ea_tseq);
|
||||
db_printf(" ORP_EA_HPTR: %x\n",
|
||||
save_res.query_fq_np.orp_ea_hptr);
|
||||
db_printf(" ORP_EA_TPTR: %x\n",
|
||||
save_res.query_fq_np.orp_ea_tptr);
|
||||
db_printf(" pfdr_hptr: %x\n", save_res.query_fq_np.pfdr_hptr);
|
||||
db_printf(" pfdr_tptr: %x\n", save_res.query_fq_np.pfdr_tptr);
|
||||
db_printf(" IS: %x\n", save_res.query_fq_np.is);
|
||||
db_printf(" ICS_SURP: %x\n", save_res.query_fq_np.ics_surp);
|
||||
db_printf(" byte_cnt: %x\n", save_res.query_fq_np.byte_cnt);
|
||||
db_printf(" frm_cnt: %x\n", save_res.query_fq_np.frm_cnt);
|
||||
db_printf(" ra1_sfdr: %x\n", save_res.query_fq_np.ra1_sfdr);
|
||||
db_printf(" ra2_sfdr: %x\n", save_res.query_fq_np.ra2_sfdr);
|
||||
db_printf(" od1_sfdr: %x\n", save_res.query_fq_np.od1_sfdr);
|
||||
db_printf(" od2_sfdr: %x\n", save_res.query_fq_np.od2_sfdr);
|
||||
db_printf(" od3_sfdr: %x\n", save_res.query_fq_np.od3_sfdr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2026 Justin Hibbits
|
||||
*/
|
||||
|
||||
#ifndef QMAN_VAR_H
|
||||
#define QMAN_VAR_H
|
||||
|
||||
#include "dpaa_common.h"
|
||||
#include "portals.h"
|
||||
|
||||
struct qman_eqcr_entry {
|
||||
uint8_t verb;
|
||||
uint8_t dca;
|
||||
uint16_t seqnum;
|
||||
uint32_t orp;
|
||||
uint32_t fqid;
|
||||
uint32_t tag;
|
||||
struct dpaa_fd fd;
|
||||
uint8_t _rsvd[32];
|
||||
};
|
||||
_Static_assert(sizeof(struct qman_eqcr_entry) == 64, "EQCR entry mis-sized");
|
||||
DPAA_RING_DECLARE(qman_eqcr);
|
||||
DPAA_RING_DECLARE(qman_dqrr);
|
||||
DPAA_RING_DECLARE(qman_mr);
|
||||
|
||||
union qman_mc_command {
|
||||
struct {
|
||||
uint8_t verb;
|
||||
uint8_t data[63];
|
||||
} common;
|
||||
struct {
|
||||
uint8_t verb;
|
||||
uint8_t _rsvd0;
|
||||
uint16_t we_mask;
|
||||
uint32_t fqid; /* Only bottom 24 bits allowed */
|
||||
uint16_t count;
|
||||
uint8_t orpc;
|
||||
uint8_t cgid;
|
||||
uint16_t fq_ctrl;
|
||||
uint16_t dest_chan:13;
|
||||
uint16_t dest_wq:3;
|
||||
uint16_t ics_cred;
|
||||
uint16_t td_thresh_oac;
|
||||
uint32_t context_b;
|
||||
uint32_t context_a;
|
||||
uint8_t _rsvd1[32];
|
||||
} init_fq;
|
||||
struct {
|
||||
uint8_t verb;
|
||||
uint8_t _rsvd0[3];
|
||||
uint32_t fqid; /* Only bottom 24 bits used */
|
||||
uint8_t _rsvd1[56];
|
||||
} query_fq;
|
||||
struct {
|
||||
uint8_t verb;
|
||||
uint8_t _rsvd0[3];
|
||||
uint32_t fqid;
|
||||
uint8_t _rsvd1[56];
|
||||
} query_fq_np;
|
||||
struct {
|
||||
uint8_t verb;
|
||||
uint8_t _rsvd0[3];
|
||||
uint32_t fqid;
|
||||
uint8_t _rsvd1;
|
||||
uint8_t count;
|
||||
uint8_t _rsvd2[10];
|
||||
uint32_t context_b;
|
||||
uint8_t _rsvd3[40];
|
||||
} alter_fqs;
|
||||
};
|
||||
|
||||
union qman_mc_result {
|
||||
struct {
|
||||
uint8_t verb;
|
||||
uint8_t data[63];
|
||||
} common;
|
||||
struct {
|
||||
uint8_t verb;
|
||||
uint8_t rslt;
|
||||
uint8_t _rsvd[62];
|
||||
} init_fq;
|
||||
struct {
|
||||
uint8_t verb;
|
||||
uint8_t rslt;
|
||||
uint8_t _rsvd0[8];
|
||||
uint8_t orpc;
|
||||
uint8_t cgid;
|
||||
uint16_t fq_ctrl;
|
||||
uint16_t dest_wq;
|
||||
uint16_t ics_cred;
|
||||
uint16_t td_thresh;
|
||||
uint32_t context_b;
|
||||
uint32_t context_a;
|
||||
uint16_t oac;
|
||||
uint8_t _rsvd1[30];
|
||||
} query_fq;
|
||||
struct {
|
||||
uint8_t verb;
|
||||
uint8_t rslt;
|
||||
uint8_t _rsvd0;
|
||||
uint8_t state;
|
||||
uint32_t fqd_link;
|
||||
uint16_t odp_seq;
|
||||
uint16_t orp_nesn;
|
||||
uint16_t orp_ea_hseq;
|
||||
uint16_t orp_ea_tseq;
|
||||
uint32_t orp_ea_hptr;
|
||||
uint32_t orp_ea_tptr;
|
||||
uint32_t pfdr_hptr;
|
||||
uint32_t pfdr_tptr;
|
||||
uint8_t _rsvd1[5];
|
||||
uint8_t is;
|
||||
uint16_t ics_surp;
|
||||
uint32_t byte_cnt;
|
||||
uint32_t frm_cnt;
|
||||
uint32_t _rsvd2;
|
||||
uint16_t ra1_sfdr;
|
||||
uint16_t ra2_sfdr;
|
||||
uint16_t _rsvd3;
|
||||
uint16_t od1_sfdr;
|
||||
uint16_t od2_sfdr;
|
||||
uint16_t od3_sfdr;
|
||||
} query_fq_np;
|
||||
struct {
|
||||
uint8_t verb;
|
||||
uint8_t rslt;
|
||||
uint8_t fqs;
|
||||
uint8_t _rsvd[61];
|
||||
} alter_fqs;
|
||||
};
|
||||
|
||||
struct qman_mc {
|
||||
uint8_t polarity;
|
||||
bool busy;
|
||||
};
|
||||
|
||||
struct qman_fq {
|
||||
uint32_t fqid;
|
||||
struct qman_cb cb;
|
||||
};
|
||||
|
||||
struct qman_portal_softc {
|
||||
struct dpaa_portal_softc sc_base;
|
||||
|
||||
/* Rings (Enqueue, Dequeue, Message */
|
||||
struct qman_eqcr_ring sc_eqcr;
|
||||
struct qman_dqrr_ring sc_dqrr;
|
||||
struct qman_mr_ring sc_mr;
|
||||
struct qman_mc sc_mc;
|
||||
|
||||
int sc_affine_channel;
|
||||
};
|
||||
|
||||
struct qman_fq *qman_fq_from_index(uint32_t fqid);
|
||||
|
||||
union qman_mc_result *
|
||||
qman_portal_mc_send_raw(device_t, union qman_mc_command *);
|
||||
int qman_portal_fq_enqueue(device_t, struct qman_fq *, struct dpaa_fd *);
|
||||
void qman_portal_static_dequeue_channel(device_t, int);
|
||||
void qman_portal_static_dequeue_rm_channel(device_t dev, int channel);
|
||||
|
||||
extern int qman_channel_base;
|
||||
DPCPU_DECLARE(device_t, qman_affine_portal);
|
||||
|
||||
#endif /* QMAN_VAR_H */
|
||||
@@ -10,7 +10,6 @@ ident QORIQ64
|
||||
|
||||
machine powerpc powerpc64
|
||||
|
||||
include "dpaa/config.dpaa"
|
||||
makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols
|
||||
makeoptions WITH_CTF=1
|
||||
#makeoptions WERROR="-Werror -Wno-format"
|
||||
@@ -22,6 +21,7 @@ options _KPOSIX_PRIORITY_SCHEDULING
|
||||
options ALT_BREAK_TO_DEBUGGER
|
||||
options BREAK_TO_DEBUGGER
|
||||
options BOOTP
|
||||
#options BOOTP_WIRED_TO=memac0
|
||||
options BOOTP_NFSROOT
|
||||
#options BOOTP_NFSV3
|
||||
options CD9660
|
||||
@@ -134,3 +134,5 @@ device uinput # install /dev/uinput cdev
|
||||
options HID_DEBUG # enable debug msgs
|
||||
device hid # Generic HID support
|
||||
device hidbus # Generic HID bus
|
||||
|
||||
options BOOTVERBOSE
|
||||
|
||||
@@ -1,99 +0,0 @@
|
||||
#
|
||||
# Common kernel config for Freescale QorIQ DPAA development boards like the
|
||||
# P2041RDB, P3041DS and P5020DS.
|
||||
#
|
||||
# This is not standalone kernel config. Use it only for including
|
||||
# purposes.
|
||||
#
|
||||
|
||||
cpu BOOKE
|
||||
cpu BOOKE_E500
|
||||
|
||||
machine powerpc powerpc
|
||||
#makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols
|
||||
#makeoptions WERROR="-Werror -Wno-format"
|
||||
makeoptions NO_MODULES=yes
|
||||
|
||||
# Platform support
|
||||
options MPC85XX #Freescale SoC family
|
||||
|
||||
options SMP #Symmetric Multi Processing
|
||||
|
||||
#options SCHED_4BSD #4BSD scheduler
|
||||
options INET #InterNETworking
|
||||
options INET6 #IPv6 communications protocols
|
||||
options FFS #Berkeley Fast Filesystem
|
||||
options NFSCL #New Network Filesystem Client
|
||||
options SOFTUPDATES #Enable FFS soft updates support
|
||||
options PROCFS #Process filesystem (requires PSEUDOFS)
|
||||
options PSEUDOFS #Pseudo-filesystem framework
|
||||
options GEOM_PART_GPT #GUID Partition Tables.
|
||||
options GEOM_LABEL
|
||||
options COMPAT_43 #Compatible with BSD 4.3 [KEEP THIS!]
|
||||
options SYSVSHM #SYSV-style shared memory
|
||||
options SYSVMSG #SYSV-style message queues
|
||||
options SYSVSEM #SYSV-style semaphores
|
||||
options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions
|
||||
|
||||
options KDB #Enable the kernel debugger
|
||||
options DDB #Support DDB
|
||||
options GDB
|
||||
|
||||
options ALT_BREAK_TO_DEBUGGER
|
||||
options BREAK_TO_DEBUGGER
|
||||
options DIAGNOSTIC
|
||||
options INVARIANTS #Enable calls of extra sanity checking
|
||||
options INVARIANT_SUPPORT #Extra sanity checks of internal structures, required by INVARIANTS
|
||||
|
||||
options KTR
|
||||
options KTR_COMPILE=0xffffffff
|
||||
options KTR_MASK=KTR_PMAP
|
||||
options KTR_ENTRIES=8192
|
||||
|
||||
options WITNESS #Enable checks to detect deadlocks and cycles
|
||||
#options WITNESS_KDB
|
||||
|
||||
# RamFS Root
|
||||
#options GEOM_UZIP
|
||||
#options MD_ROOT
|
||||
#options MD_ROOT_SIZE=10240
|
||||
|
||||
# Netbooting
|
||||
options BOOTP
|
||||
options BOOTP_NFSROOT
|
||||
options BOOTP_NFSV3
|
||||
options BOOTP_WIRED_TO=dtsec3
|
||||
options NFS_ROOT
|
||||
|
||||
# Block devices
|
||||
device mmc
|
||||
device mmcsd
|
||||
device sdhci
|
||||
|
||||
# Network devices
|
||||
device miibus # MII bus support
|
||||
device iflib
|
||||
device em
|
||||
|
||||
|
||||
# I2C support
|
||||
device iicbus
|
||||
device iic
|
||||
|
||||
device uart
|
||||
device ehci
|
||||
device usb
|
||||
device scbus
|
||||
device da
|
||||
device umass
|
||||
device pty
|
||||
device cfi
|
||||
|
||||
device pci
|
||||
|
||||
# Pseudo devices
|
||||
device ether # Ethernet support
|
||||
device loop # Network loopback
|
||||
device bpf # Berkeley packet filter
|
||||
device md # Memory "disks"
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
|
||||
files "dpaa/files.dpaa"
|
||||
|
||||
makeoptions DPAA_COMPILE_CMD="${LINUXKPI_C} ${DPAAWARNFLAGS} \
|
||||
-Wno-cast-qual -Wno-unused-function -Wno-init-self \
|
||||
-include $S/contrib/ncsw/build/dflags.h \
|
||||
-Wno-error=missing-prototypes \
|
||||
-I$S/contrib/ncsw/build/ \
|
||||
-I$S/contrib/ncsw/inc \
|
||||
-I$S/contrib/ncsw/inc/cores \
|
||||
-I$S/contrib/ncsw/inc/etc \
|
||||
-I$S/contrib/ncsw/inc/Peripherals \
|
||||
-I$S/contrib/ncsw/etc \
|
||||
-I$S/contrib/ncsw/Peripherals/BM \
|
||||
-I$S/contrib/ncsw/Peripherals/FM \
|
||||
-I$S/contrib/ncsw/Peripherals/FM/HC \
|
||||
-I$S/contrib/ncsw/Peripherals/FM/inc \
|
||||
-I$S/contrib/ncsw/Peripherals/FM/MAC \
|
||||
-I$S/contrib/ncsw/Peripherals/FM/Pcd \
|
||||
-I$S/contrib/ncsw/Peripherals/FM/Port \
|
||||
-I$S/contrib/ncsw/Peripherals/FM/Rtc \
|
||||
-I$S/contrib/ncsw/Peripherals/QM \
|
||||
-I$S/contrib/ncsw/inc/flib \
|
||||
-I$S/contrib/ncsw/inc/integrations"
|
||||
@@ -1,122 +0,0 @@
|
||||
|
||||
# NetCommSw drivers
|
||||
contrib/ncsw/etc/error.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
contrib/ncsw/etc/ncsw_list.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
contrib/ncsw/etc/memcpy.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
contrib/ncsw/etc/mm.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
contrib/ncsw/etc/ncsw_mem.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
contrib/ncsw/etc/sprint.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
contrib/ncsw/Peripherals/BM/bm.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
contrib/ncsw/Peripherals/BM/bman_low.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
contrib/ncsw/Peripherals/BM/bm_pool.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
contrib/ncsw/Peripherals/BM/bm_portal.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
contrib/ncsw/Peripherals/FM/SP/fm_sp.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
contrib/ncsw/Peripherals/FM/Rtc/fm_rtc.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
contrib/ncsw/Peripherals/FM/Rtc/fman_rtc.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
contrib/ncsw/Peripherals/FM/Port/fman_port.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
contrib/ncsw/Peripherals/FM/Port/fm_port.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
contrib/ncsw/Peripherals/FM/Port/fm_port_im.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
contrib/ncsw/Peripherals/FM/Pcd/fm_cc.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
contrib/ncsw/Peripherals/FM/Pcd/fm_kg.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
contrib/ncsw/Peripherals/FM/Pcd/fman_kg.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
contrib/ncsw/Peripherals/FM/Pcd/fm_manip.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
contrib/ncsw/Peripherals/FM/Pcd/fm_pcd.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
contrib/ncsw/Peripherals/FM/Pcd/fm_plcr.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
contrib/ncsw/Peripherals/FM/Pcd/fm_prs.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
contrib/ncsw/Peripherals/FM/Pcd/fman_prs.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
contrib/ncsw/Peripherals/FM/MAC/dtsec.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
contrib/ncsw/Peripherals/FM/MAC/dtsec_mii_acc.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
contrib/ncsw/Peripherals/FM/MAC/fman_dtsec.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
contrib/ncsw/Peripherals/FM/MAC/fman_dtsec_mii_acc.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
contrib/ncsw/Peripherals/FM/MAC/fm_mac.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
contrib/ncsw/Peripherals/FM/MAC/fman_dtsec.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
contrib/ncsw/Peripherals/FM/MAC/tgec.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
contrib/ncsw/Peripherals/FM/MAC/tgec_mii_acc.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
contrib/ncsw/Peripherals/FM/MAC/fman_tgec.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
contrib/ncsw/Peripherals/FM/HC/hc.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
contrib/ncsw/Peripherals/FM/fm_muram.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
contrib/ncsw/Peripherals/FM/fm_ncsw.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
contrib/ncsw/Peripherals/FM/fman_ncsw.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD} ${NO_WMISLEADING_INDENTATION}"
|
||||
contrib/ncsw/Peripherals/QM/qm.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
contrib/ncsw/Peripherals/QM/qm_portal_fqr.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
contrib/ncsw/user/env/stdlib.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
contrib/ncsw/user/env/xx.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
contrib/ncsw/user/env/core.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
|
||||
# FreeBSD Wrappers
|
||||
dev/dpaa/portals_common.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
dev/dpaa/bman_portals.c optional dpaa fdt \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
dev/dpaa/bman.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
dev/dpaa/bman_fdt.c optional dpaa fdt \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
dev/dpaa/qman_portals.c optional dpaa fdt \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
dev/dpaa/qman.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
dev/dpaa/qman_fdt.c optional dpaa fdt \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
dev/dpaa/fman.c optional dpaa fdt \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
dev/dpaa/fman_mdio.c optional dpaa fdt \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
dev/dpaa/fman_fdt.c optional dpaa fdt \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
dev/dpaa/if_dtsec.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
dev/dpaa/if_dtsec_im.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
dev/dpaa/if_dtsec_rm.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
dev/dpaa/if_dtsec_fdt.c optional dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
|
||||
# Examples
|
||||
dev/dpaa/bman-example.c optional bman_example dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
dev/dpaa/qman-example.c optional qman_example dpaa \
|
||||
no-depend compile-with "${DPAA_COMPILE_CMD}"
|
||||
Reference in New Issue
Block a user