7a40b8a89e
Reported by: ziaee@
Fixes: fd8d34ce27 ("dpaa: Migrate from NCSW base to a home-grown driver")
698 lines
18 KiB
C
698 lines
18 KiB
C
/*
|
|
* Copyright (c) 2026 Justin Hibbits
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#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_parser.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 /* Counts are units of 16 bytes */
|
|
#define RICP_ICEOF_M 0x001f0000
|
|
#define RICP_ICEOF_S 16
|
|
#define RICP_ICIOF_M 0x00000f00
|
|
#define RICP_ICIOF_S 8
|
|
#define RICP_ICSZ_S 0x0000001f
|
|
#define FMBM_RIM 0x018
|
|
#define FMBM_REBM 0x01c
|
|
#define REBM_BSM_M 0x01ff0000
|
|
#define REBM_BSM_S 16
|
|
#define REBM_BEM_M 0x000001ff
|
|
#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_TICP 0x014
|
|
#define TICP_ICEOF_M 0x001f0000
|
|
#define TICP_ICEOF_S 16
|
|
#define TICP_ICIOF_M 0x00000f00
|
|
#define TICP_ICIOF_S 8
|
|
#define TICP_ICSZ_S 0x0000001f
|
|
#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)
|
|
{
|
|
uint32_t reg;
|
|
|
|
/* 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_BMI | NIA_BMI_AC_ENQ_FRAME);
|
|
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);
|
|
|
|
/* Insert internal context ahead of the frame */
|
|
reg = sizeof(struct fman_internal_context) << REBM_BSM_S;
|
|
bus_write_4(sc->sc_mem, FMBM_REBM, reg);
|
|
reg = howmany(FMAN_PARSE_RESULT_OFF, 0x10) << RICP_ICIOF_S;
|
|
reg |= howmany(sizeof(struct fman_internal_context), 0x10);
|
|
bus_write_4(sc->sc_mem, FMBM_RICP, reg);
|
|
|
|
bus_write_4(sc->sc_mem, FMBM_RFNE, NIA_ENG_HWP);
|
|
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);
|
|
|
|
/* Insert internal context ahead of the frame */
|
|
reg = howmany(FMAN_PARSE_RESULT_OFF, 0x10) << TICP_ICIOF_S;
|
|
reg |= howmany(sizeof(struct fman_internal_context), 0x10);
|
|
bus_write_4(sc->sc_mem, FMBM_TICP, reg);
|
|
|
|
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;
|
|
|
|
/* Stop the parser so we can initialize it for our uses */
|
|
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);
|
|
|
|
/* Re-enable the parser */
|
|
bus_write_4(sc->sc_mem, HWP_PCAC, 0);
|
|
|
|
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);
|