mirror of
https://github.com/opnsense/src.git
synced 2026-02-25 19:05:20 -05:00
Mainly focus on files that use BSD 2-Clause license, however the tool I was using misidentified many licenses so this was mostly a manual - error prone - task. The Software Package Data Exchange (SPDX) group provides a specification to make it easier for automated tools to detect and summarize well known opensource licenses. We are gradually adopting the specification, noting that the tags are considered only advisory and do not, in any way, superceed or replace the license texts.
1456 lines
38 KiB
C
1456 lines
38 KiB
C
/*-
|
|
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
|
*
|
|
* Copyright (c) 2003-2012 Broadcom Corporation
|
|
* 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 BROADCOM ``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 BROADCOM OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
|
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
|
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
|
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <sys/cdefs.h>
|
|
__FBSDID("$FreeBSD$");
|
|
#include <sys/types.h>
|
|
#include <sys/systm.h>
|
|
|
|
#include <mips/nlm/hal/mips-extns.h>
|
|
#include <mips/nlm/hal/haldefs.h>
|
|
#include <mips/nlm/hal/iomap.h>
|
|
#include <mips/nlm/hal/sys.h>
|
|
#include <mips/nlm/hal/nae.h>
|
|
#include <mips/nlm/hal/mdio.h>
|
|
#include <mips/nlm/hal/sgmii.h>
|
|
#include <mips/nlm/hal/xaui.h>
|
|
|
|
#include <mips/nlm/board.h>
|
|
#include <mips/nlm/xlp.h>
|
|
|
|
void
|
|
nlm_nae_flush_free_fifo(uint64_t nae_base, int nblocks)
|
|
{
|
|
uint32_t data, fifo_mask;
|
|
|
|
fifo_mask = (1 << (4 * nblocks)) - 1;
|
|
|
|
nlm_write_nae_reg(nae_base, NAE_RX_FREE_FIFO_POP, fifo_mask);
|
|
do {
|
|
data = nlm_read_nae_reg(nae_base, NAE_RX_FREE_FIFO_POP);
|
|
} while (data != fifo_mask);
|
|
|
|
nlm_write_nae_reg(nae_base, NAE_RX_FREE_FIFO_POP, 0);
|
|
}
|
|
|
|
void
|
|
nlm_program_nae_parser_seq_fifo(uint64_t nae_base, int maxports,
|
|
struct nae_port_config *cfg)
|
|
{
|
|
uint32_t val;
|
|
int start = 0, size, i;
|
|
|
|
for (i = 0; i < maxports; i++) {
|
|
size = cfg[i].pseq_fifo_size;
|
|
val = (((size & 0x1fff) << 17) |
|
|
((start & 0xfff) << 5) |
|
|
(i & 0x1f));
|
|
nlm_write_nae_reg(nae_base, NAE_PARSER_SEQ_FIFO_CFG, val);
|
|
start += size;
|
|
}
|
|
}
|
|
|
|
void
|
|
nlm_setup_rx_cal_cfg(uint64_t nae_base, int total_num_ports,
|
|
struct nae_port_config *cfg)
|
|
{
|
|
int rx_slots = 0, port;
|
|
int cal_len, cal = 0, last_free = 0;
|
|
uint32_t val;
|
|
|
|
for (port = 0; port < total_num_ports; port++) {
|
|
if (cfg[port].rx_slots_reqd)
|
|
rx_slots += cfg[port].rx_slots_reqd;
|
|
if (rx_slots > MAX_CAL_SLOTS) {
|
|
rx_slots = MAX_CAL_SLOTS;
|
|
break;
|
|
}
|
|
}
|
|
|
|
cal_len = rx_slots - 1;
|
|
|
|
do {
|
|
if (cal >= MAX_CAL_SLOTS)
|
|
break;
|
|
last_free = cal;
|
|
for (port = 0; port < total_num_ports; port++) {
|
|
if (cfg[port].rx_slots_reqd > 0) {
|
|
val = (cal_len << 16) | (port << 8) | cal;
|
|
nlm_write_nae_reg(nae_base,
|
|
NAE_RX_IF_SLOT_CAL, val);
|
|
cal++;
|
|
cfg[port].rx_slots_reqd--;
|
|
}
|
|
}
|
|
if (last_free == cal)
|
|
break;
|
|
} while (1);
|
|
}
|
|
|
|
void
|
|
nlm_setup_tx_cal_cfg(uint64_t nae_base, int total_num_ports,
|
|
struct nae_port_config *cfg)
|
|
{
|
|
int tx_slots = 0, port;
|
|
int cal = 0, last_free = 0;
|
|
uint32_t val;
|
|
|
|
for (port = 0; port < total_num_ports; port++) {
|
|
if (cfg[port].tx_slots_reqd)
|
|
tx_slots += cfg[port].tx_slots_reqd;
|
|
if (tx_slots > MAX_CAL_SLOTS) {
|
|
tx_slots = MAX_CAL_SLOTS;
|
|
break;
|
|
}
|
|
}
|
|
|
|
nlm_write_nae_reg(nae_base, NAE_EGR_NIOR_CAL_LEN_REG, tx_slots - 1);
|
|
do {
|
|
if (cal >= MAX_CAL_SLOTS)
|
|
break;
|
|
last_free = cal;
|
|
for (port = 0; port < total_num_ports; port++) {
|
|
if (cfg[port].tx_slots_reqd > 0) {
|
|
val = (port << 7) | (cal << 1) | 1;
|
|
nlm_write_nae_reg(nae_base,
|
|
NAE_EGR_NIOR_CRDT_CAL_PROG, val);
|
|
cal++;
|
|
cfg[port].tx_slots_reqd--;
|
|
}
|
|
}
|
|
if (last_free == cal)
|
|
break;
|
|
} while (1);
|
|
}
|
|
|
|
void
|
|
nlm_deflate_frin_fifo_carving(uint64_t nae_base, int total_num_ports)
|
|
{
|
|
const int minimum_size = 8;
|
|
uint32_t value;
|
|
int intf, start;
|
|
|
|
for (intf = 0; intf < total_num_ports; intf++) {
|
|
start = minimum_size * intf;
|
|
value = (minimum_size << 20) | (start << 8) | (intf);
|
|
nlm_write_nae_reg(nae_base, NAE_FREE_IN_FIFO_CFG, value);
|
|
}
|
|
}
|
|
|
|
void
|
|
nlm_reset_nae(int node)
|
|
{
|
|
uint64_t sysbase;
|
|
uint64_t nae_base;
|
|
uint64_t nae_pcibase;
|
|
uint32_t rx_config;
|
|
uint32_t bar0;
|
|
int reset_bit;
|
|
|
|
sysbase = nlm_get_sys_regbase(node);
|
|
nae_base = nlm_get_nae_regbase(node);
|
|
nae_pcibase = nlm_get_nae_pcibase(node);
|
|
|
|
bar0 = nlm_read_pci_reg(nae_pcibase, XLP_PCI_CFGREG4);
|
|
|
|
#if BYTE_ORDER == LITTLE_ENDIAN
|
|
if (nlm_is_xlp8xx_ax()) {
|
|
uint8_t val;
|
|
/* membar fixup */
|
|
val = (bar0 >> 24) & 0xff;
|
|
bar0 = (val << 24) | (val << 16) | (val << 8) | val;
|
|
}
|
|
#endif
|
|
|
|
if (nlm_is_xlp3xx())
|
|
reset_bit = 6;
|
|
else
|
|
reset_bit = 9;
|
|
|
|
/* Reset NAE */
|
|
nlm_write_sys_reg(sysbase, SYS_RESET, (1 << reset_bit));
|
|
|
|
/* XXXJC - 1s delay here may be too high */
|
|
DELAY(1000000);
|
|
nlm_write_sys_reg(sysbase, SYS_RESET, (0 << reset_bit));
|
|
DELAY(1000000);
|
|
|
|
rx_config = nlm_read_nae_reg(nae_base, NAE_RX_CONFIG);
|
|
nlm_write_pci_reg(nae_pcibase, XLP_PCI_CFGREG4, bar0);
|
|
}
|
|
|
|
void
|
|
nlm_setup_poe_class_config(uint64_t nae_base, int max_poe_classes,
|
|
int num_contexts, int *poe_cl_tbl)
|
|
{
|
|
uint32_t val;
|
|
int i, max_poe_class_ctxt_tbl_sz;
|
|
|
|
max_poe_class_ctxt_tbl_sz = num_contexts/max_poe_classes;
|
|
for (i = 0; i < max_poe_class_ctxt_tbl_sz; i++) {
|
|
val = (poe_cl_tbl[(i/max_poe_classes) & 0x7] << 8) | i;
|
|
nlm_write_nae_reg(nae_base, NAE_POE_CLASS_SETUP_CFG, val);
|
|
}
|
|
}
|
|
|
|
void
|
|
nlm_setup_vfbid_mapping(uint64_t nae_base)
|
|
{
|
|
uint32_t val;
|
|
int dest_vc, vfbid;
|
|
|
|
/* 127 is max vfbid */
|
|
for (vfbid = 127; vfbid >= 0; vfbid--) {
|
|
dest_vc = nlm_get_vfbid_mapping(vfbid);
|
|
if (dest_vc < 0)
|
|
continue;
|
|
val = (dest_vc << 16) | (vfbid << 4) | 1;
|
|
nlm_write_nae_reg(nae_base, NAE_VFBID_DESTMAP_CMD, val);
|
|
}
|
|
}
|
|
|
|
void
|
|
nlm_setup_flow_crc_poly(uint64_t nae_base, uint32_t poly)
|
|
{
|
|
nlm_write_nae_reg(nae_base, NAE_FLOW_CRC16_POLY_CFG, poly);
|
|
}
|
|
|
|
void
|
|
nlm_setup_iface_fifo_cfg(uint64_t nae_base, int maxports,
|
|
struct nae_port_config *cfg)
|
|
{
|
|
uint32_t reg;
|
|
int fifo_xoff_thresh = 12;
|
|
int i, size;
|
|
int cur_iface_start = 0;
|
|
|
|
for (i = 0; i < maxports; i++) {
|
|
size = cfg[i].iface_fifo_size;
|
|
reg = ((fifo_xoff_thresh << 25) |
|
|
((size & 0x1ff) << 16) |
|
|
((cur_iface_start & 0xff) << 8) |
|
|
(i & 0x1f));
|
|
nlm_write_nae_reg(nae_base, NAE_IFACE_FIFO_CFG, reg);
|
|
cur_iface_start += size;
|
|
}
|
|
}
|
|
|
|
void
|
|
nlm_setup_rx_base_config(uint64_t nae_base, int maxports,
|
|
struct nae_port_config *cfg)
|
|
{
|
|
int base = 0;
|
|
uint32_t val;
|
|
int i;
|
|
int id;
|
|
|
|
for (i = 0; i < (maxports/2); i++) {
|
|
id = 0x12 + i; /* RX_IF_BASE_CONFIG0 */
|
|
|
|
val = (base & 0x3ff);
|
|
base += cfg[(i * 2)].num_channels;
|
|
|
|
val |= ((base & 0x3ff) << 16);
|
|
base += cfg[(i * 2) + 1].num_channels;
|
|
|
|
nlm_write_nae_reg(nae_base, NAE_REG(7, 0, id), val);
|
|
}
|
|
}
|
|
|
|
void
|
|
nlm_setup_rx_buf_config(uint64_t nae_base, int maxports,
|
|
struct nae_port_config *cfg)
|
|
{
|
|
uint32_t val;
|
|
int i, sz, k;
|
|
int context = 0;
|
|
int base = 0;
|
|
|
|
for (i = 0; i < maxports; i++) {
|
|
if (cfg[i].type == UNKNOWN)
|
|
continue;
|
|
for (k = 0; k < cfg[i].num_channels; k++) {
|
|
/* write index (context num) */
|
|
nlm_write_nae_reg(nae_base, NAE_RXBUF_BASE_DPTH_ADDR,
|
|
(context+k));
|
|
|
|
/* write value (rx buf sizes) */
|
|
sz = cfg[i].rxbuf_size;
|
|
val = 0x80000000 | ((base << 2) & 0x3fff); /* base */
|
|
val |= (((sz << 2) & 0x3fff) << 16); /* size */
|
|
|
|
nlm_write_nae_reg(nae_base, NAE_RXBUF_BASE_DPTH, val);
|
|
nlm_write_nae_reg(nae_base, NAE_RXBUF_BASE_DPTH,
|
|
(0x7fffffff & val));
|
|
base += sz;
|
|
}
|
|
context += cfg[i].num_channels;
|
|
}
|
|
}
|
|
|
|
void
|
|
nlm_setup_freein_fifo_cfg(uint64_t nae_base, struct nae_port_config *cfg)
|
|
{
|
|
int size, i;
|
|
uint32_t reg;
|
|
int start = 0, maxbufpool;
|
|
|
|
if (nlm_is_xlp8xx())
|
|
maxbufpool = MAX_FREE_FIFO_POOL_8XX;
|
|
else
|
|
maxbufpool = MAX_FREE_FIFO_POOL_3XX;
|
|
for (i = 0; i < maxbufpool; i++) {
|
|
/* Each entry represents 2 descs; hence division by 2 */
|
|
size = (cfg[i].num_free_descs / 2);
|
|
if (size == 0)
|
|
size = 8;
|
|
reg = ((size & 0x3ff ) << 20) | /* fcSize */
|
|
((start & 0x1ff) << 8) | /* fcStart */
|
|
(i & 0x1f);
|
|
|
|
nlm_write_nae_reg(nae_base, NAE_FREE_IN_FIFO_CFG, reg);
|
|
start += size;
|
|
}
|
|
}
|
|
|
|
/* XXX function name */
|
|
int
|
|
nlm_get_flow_mask(int num_ports)
|
|
{
|
|
const int max_bits = 5; /* upto 32 ports */
|
|
int i;
|
|
|
|
/* Compute the number of bits to needed to
|
|
* represent all the ports */
|
|
for (i = 0; i < max_bits; i++) {
|
|
if (num_ports <= (2 << i))
|
|
return (i + 1);
|
|
}
|
|
return (max_bits);
|
|
}
|
|
|
|
void
|
|
nlm_program_flow_cfg(uint64_t nae_base, int port,
|
|
uint32_t cur_flow_base, uint32_t flow_mask)
|
|
{
|
|
uint32_t val;
|
|
|
|
val = (cur_flow_base << 16) | port;
|
|
val |= ((flow_mask & 0x1f) << 8);
|
|
nlm_write_nae_reg(nae_base, NAE_FLOW_BASEMASK_CFG, val);
|
|
}
|
|
|
|
void
|
|
xlp_ax_nae_lane_reset_txpll(uint64_t nae_base, int block, int lane_ctrl,
|
|
int mode)
|
|
{
|
|
uint32_t val = 0, saved_data;
|
|
int rext_sel = 0;
|
|
|
|
val = PHY_LANE_CTRL_RST |
|
|
PHY_LANE_CTRL_PWRDOWN |
|
|
(mode << PHY_LANE_CTRL_PHYMODE_POS);
|
|
|
|
/* set comma bypass for XAUI */
|
|
if (mode != PHYMODE_SGMII)
|
|
val |= PHY_LANE_CTRL_BPC_XAUI;
|
|
|
|
nlm_write_nae_reg(nae_base, NAE_REG(block, PHY, lane_ctrl), val);
|
|
|
|
if (lane_ctrl != 4) {
|
|
rext_sel = (1 << 23);
|
|
if (mode != PHYMODE_SGMII)
|
|
rext_sel |= PHY_LANE_CTRL_BPC_XAUI;
|
|
|
|
val = nlm_read_nae_reg(nae_base,
|
|
NAE_REG(block, PHY, lane_ctrl));
|
|
val &= ~PHY_LANE_CTRL_RST;
|
|
val |= rext_sel;
|
|
|
|
/* Resetting PMA for non-zero lanes */
|
|
nlm_write_nae_reg(nae_base,
|
|
NAE_REG(block, PHY, lane_ctrl), val);
|
|
|
|
DELAY(20000); /* 20 ms delay, XXXJC: needed? */
|
|
|
|
val |= PHY_LANE_CTRL_RST;
|
|
nlm_write_nae_reg(nae_base,
|
|
NAE_REG(block, PHY, lane_ctrl), val);
|
|
|
|
val = 0;
|
|
}
|
|
|
|
/* Come out of reset for TXPLL */
|
|
saved_data = nlm_read_nae_reg(nae_base,
|
|
NAE_REG(block, PHY, lane_ctrl)) & 0xFFC00000;
|
|
|
|
nlm_write_nae_reg(nae_base,
|
|
NAE_REG(block, PHY, lane_ctrl),
|
|
(0x66 << PHY_LANE_CTRL_ADDR_POS)
|
|
| PHY_LANE_CTRL_CMD_READ
|
|
| PHY_LANE_CTRL_CMD_START
|
|
| PHY_LANE_CTRL_RST
|
|
| rext_sel
|
|
| val );
|
|
|
|
while (((val = nlm_read_nae_reg(nae_base,
|
|
NAE_REG(block, PHY, lane_ctrl))) &
|
|
PHY_LANE_CTRL_CMD_PENDING));
|
|
|
|
val &= 0xFF;
|
|
/* set bit[4] to 0 */
|
|
val &= ~(1 << 4);
|
|
nlm_write_nae_reg(nae_base,
|
|
NAE_REG(block, PHY, lane_ctrl),
|
|
(0x66 << PHY_LANE_CTRL_ADDR_POS)
|
|
| PHY_LANE_CTRL_CMD_WRITE
|
|
| PHY_LANE_CTRL_CMD_START
|
|
| (0x0 << 19) /* (0x4 << 19) */
|
|
| rext_sel
|
|
| saved_data
|
|
| val );
|
|
|
|
/* re-do */
|
|
nlm_write_nae_reg(nae_base,
|
|
NAE_REG(block, PHY, lane_ctrl),
|
|
(0x66 << PHY_LANE_CTRL_ADDR_POS)
|
|
| PHY_LANE_CTRL_CMD_WRITE
|
|
| PHY_LANE_CTRL_CMD_START
|
|
| (0x0 << 19) /* (0x4 << 19) */
|
|
| rext_sel
|
|
| saved_data
|
|
| val );
|
|
|
|
while (!((val = nlm_read_nae_reg(nae_base,
|
|
NAE_REG(block, PHY, (lane_ctrl - PHY_LANE_0_CTRL)))) &
|
|
PHY_LANE_STAT_PCR));
|
|
|
|
/* Clear the Power Down bit */
|
|
val = nlm_read_nae_reg(nae_base, NAE_REG(block, PHY, lane_ctrl));
|
|
val &= ~((1 << 29) | (0x7ffff));
|
|
nlm_write_nae_reg(nae_base, NAE_REG(block, PHY, lane_ctrl),
|
|
(rext_sel | val));
|
|
}
|
|
|
|
void
|
|
xlp_nae_lane_reset_txpll(uint64_t nae_base, int block, int lane_ctrl,
|
|
int mode)
|
|
{
|
|
uint32_t val = 0;
|
|
int rext_sel = 0;
|
|
|
|
if (lane_ctrl != 4)
|
|
rext_sel = (1 << 23);
|
|
|
|
val = nlm_read_nae_reg(nae_base,
|
|
NAE_REG(block, PHY, lane_ctrl));
|
|
|
|
/* set comma bypass for XAUI */
|
|
if (mode != PHYMODE_SGMII)
|
|
val |= PHY_LANE_CTRL_BPC_XAUI;
|
|
val |= 0x100000;
|
|
val |= (mode << PHY_LANE_CTRL_PHYMODE_POS);
|
|
val &= ~(0x20000);
|
|
nlm_write_nae_reg(nae_base,
|
|
NAE_REG(block, PHY, lane_ctrl), val);
|
|
|
|
val = nlm_read_nae_reg(nae_base,
|
|
NAE_REG(block, PHY, lane_ctrl));
|
|
val |= 0x40000000;
|
|
nlm_write_nae_reg(nae_base,
|
|
NAE_REG(block, PHY, lane_ctrl), val);
|
|
|
|
/* clear the power down bit */
|
|
val = nlm_read_nae_reg(nae_base,
|
|
NAE_REG(block, PHY, lane_ctrl));
|
|
val &= ~( (1 << 29) | (0x7ffff));
|
|
nlm_write_nae_reg(nae_base,
|
|
NAE_REG(block, PHY, lane_ctrl), rext_sel | val);
|
|
}
|
|
|
|
void
|
|
xlp_nae_config_lane_gmac(uint64_t nae_base, int cplx_mask)
|
|
{
|
|
int block, lane_ctrl;
|
|
int cplx_lane_enable;
|
|
int lane_enable = 0;
|
|
|
|
cplx_lane_enable = LM_SGMII |
|
|
(LM_SGMII << 4) |
|
|
(LM_SGMII << 8) |
|
|
(LM_SGMII << 12);
|
|
|
|
/* Lane mode progamming */
|
|
block = 7;
|
|
|
|
/* Complexes 0, 1 */
|
|
if (cplx_mask & 0x1)
|
|
lane_enable |= cplx_lane_enable;
|
|
|
|
if (cplx_mask & 0x2)
|
|
lane_enable |= (cplx_lane_enable << 16);
|
|
|
|
if (lane_enable) {
|
|
nlm_write_nae_reg(nae_base,
|
|
NAE_REG(block, LANE_CFG, LANE_CFG_CPLX_0_1),
|
|
lane_enable);
|
|
lane_enable = 0;
|
|
}
|
|
/* Complexes 2 3 */
|
|
if (cplx_mask & 0x4)
|
|
lane_enable |= cplx_lane_enable;
|
|
|
|
if (cplx_mask & 0x8)
|
|
lane_enable |= (cplx_lane_enable << 16);
|
|
|
|
nlm_write_nae_reg(nae_base,
|
|
NAE_REG(block, LANE_CFG, LANE_CFG_CPLX_2_3),
|
|
lane_enable);
|
|
|
|
/* complex 4 */
|
|
/* XXXJC : fix duplicate code */
|
|
if (cplx_mask & 0x10) {
|
|
nlm_write_nae_reg(nae_base,
|
|
NAE_REG(block, LANE_CFG, LANE_CFG_CPLX_4),
|
|
((LM_SGMII << 4) | LM_SGMII));
|
|
for (lane_ctrl = PHY_LANE_0_CTRL;
|
|
lane_ctrl <= PHY_LANE_1_CTRL; lane_ctrl++) {
|
|
if (!nlm_is_xlp8xx_ax())
|
|
xlp_nae_lane_reset_txpll(nae_base,
|
|
4, lane_ctrl, PHYMODE_SGMII);
|
|
else
|
|
xlp_ax_nae_lane_reset_txpll(nae_base, 4,
|
|
lane_ctrl, PHYMODE_SGMII);
|
|
}
|
|
}
|
|
|
|
for (block = 0; block < 4; block++) {
|
|
if ((cplx_mask & (1 << block)) == 0)
|
|
continue;
|
|
|
|
for (lane_ctrl = PHY_LANE_0_CTRL;
|
|
lane_ctrl <= PHY_LANE_3_CTRL; lane_ctrl++) {
|
|
if (!nlm_is_xlp8xx_ax())
|
|
xlp_nae_lane_reset_txpll(nae_base,
|
|
block, lane_ctrl, PHYMODE_SGMII);
|
|
else
|
|
xlp_ax_nae_lane_reset_txpll(nae_base, block,
|
|
lane_ctrl, PHYMODE_SGMII);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
config_egress_fifo_carvings(uint64_t nae_base, int hwport, int start_ctxt,
|
|
int num_ctxts, int max_ctxts, struct nae_port_config *cfg)
|
|
{
|
|
static uint32_t cur_start[6] = {0, 0, 0, 0, 0, 0};
|
|
uint32_t data = 0;
|
|
uint32_t start = 0, size, offset;
|
|
int i, limit;
|
|
|
|
limit = start_ctxt + num_ctxts;
|
|
/* Stage 2 FIFO */
|
|
start = cur_start[0];
|
|
for (i = start_ctxt; i < limit; i++) {
|
|
size = cfg[hwport].stg2_fifo_size / max_ctxts;
|
|
if (size)
|
|
offset = size - 1;
|
|
else
|
|
offset = size;
|
|
if (offset > cfg[hwport].max_stg2_offset)
|
|
offset = cfg[hwport].max_stg2_offset;
|
|
data = offset << 23 |
|
|
start << 11 |
|
|
i << 1 |
|
|
1;
|
|
nlm_write_nae_reg(nae_base, NAE_STG2_PMEM_PROG, data);
|
|
start += size;
|
|
}
|
|
cur_start[0] = start;
|
|
|
|
/* EH FIFO */
|
|
start = cur_start[1];
|
|
for (i = start_ctxt; i < limit; i++) {
|
|
size = cfg[hwport].eh_fifo_size / max_ctxts;
|
|
if (size)
|
|
offset = size - 1;
|
|
else
|
|
offset = size ;
|
|
if (offset > cfg[hwport].max_eh_offset)
|
|
offset = cfg[hwport].max_eh_offset;
|
|
data = offset << 23 |
|
|
start << 11 |
|
|
i << 1 |
|
|
1;
|
|
nlm_write_nae_reg(nae_base, NAE_EH_PMEM_PROG, data);
|
|
start += size;
|
|
}
|
|
cur_start[1] = start;
|
|
|
|
/* FROUT FIFO */
|
|
start = cur_start[2];
|
|
for (i = start_ctxt; i < limit; i++) {
|
|
size = cfg[hwport].frout_fifo_size / max_ctxts;
|
|
if (size)
|
|
offset = size - 1;
|
|
else
|
|
offset = size ;
|
|
if (offset > cfg[hwport].max_frout_offset)
|
|
offset = cfg[hwport].max_frout_offset;
|
|
data = offset << 23 |
|
|
start << 11 |
|
|
i << 1 |
|
|
1;
|
|
nlm_write_nae_reg(nae_base, NAE_FREE_PMEM_PROG, data);
|
|
start += size;
|
|
}
|
|
cur_start[2] = start;
|
|
|
|
/* MS FIFO */
|
|
start = cur_start[3];
|
|
for (i = start_ctxt; i < limit; i++) {
|
|
size = cfg[hwport].ms_fifo_size / max_ctxts;
|
|
if (size)
|
|
offset = size - 1;
|
|
else
|
|
offset = size ;
|
|
if (offset > cfg[hwport].max_ms_offset)
|
|
offset = cfg[hwport].max_ms_offset;
|
|
data = offset << 22 | /* FIXME in PRM */
|
|
start << 11 |
|
|
i << 1 |
|
|
1;
|
|
nlm_write_nae_reg(nae_base, NAE_STR_PMEM_CMD, data);
|
|
start += size;
|
|
}
|
|
cur_start[3] = start;
|
|
|
|
/* PKT FIFO */
|
|
start = cur_start[4];
|
|
for (i = start_ctxt; i < limit; i++) {
|
|
size = cfg[hwport].pkt_fifo_size / max_ctxts;
|
|
if (size)
|
|
offset = size - 1;
|
|
else
|
|
offset = size ;
|
|
if (offset > cfg[hwport].max_pmem_offset)
|
|
offset = cfg[hwport].max_pmem_offset;
|
|
nlm_write_nae_reg(nae_base, NAE_TX_PKT_PMEM_CMD1, offset);
|
|
|
|
data = start << 11 |
|
|
i << 1 |
|
|
1;
|
|
nlm_write_nae_reg(nae_base, NAE_TX_PKT_PMEM_CMD0, data);
|
|
start += size;
|
|
}
|
|
cur_start[4] = start;
|
|
|
|
/* PKT LEN FIFO */
|
|
start = cur_start[5];
|
|
for (i = start_ctxt; i < limit; i++) {
|
|
size = cfg[hwport].pktlen_fifo_size / max_ctxts;
|
|
if (size)
|
|
offset = size - 1;
|
|
else
|
|
offset = size ;
|
|
data = offset << 22 |
|
|
start << 11 |
|
|
i << 1 |
|
|
1;
|
|
nlm_write_nae_reg(nae_base, NAE_TX_PKTLEN_PMEM_CMD, data);
|
|
start += size;
|
|
}
|
|
cur_start[5] = start;
|
|
}
|
|
|
|
void
|
|
config_egress_fifo_credits(uint64_t nae_base, int hwport, int start_ctxt,
|
|
int num_ctxts, int max_ctxts, struct nae_port_config *cfg)
|
|
{
|
|
uint32_t data, credit, max_credit;
|
|
int i, limit;
|
|
|
|
limit = start_ctxt + num_ctxts;
|
|
/* Stage1 -> Stage2 */
|
|
max_credit = cfg[hwport].max_stg2_offset + 1;
|
|
for (i = start_ctxt; i < limit; i++) {
|
|
credit = cfg[hwport].stg1_2_credit / max_ctxts;
|
|
if (credit > max_credit)
|
|
credit = max_credit;
|
|
data = credit << 16 |
|
|
i << 4 |
|
|
1;
|
|
nlm_write_nae_reg(nae_base, NAE_STG1_STG2CRDT_CMD, data);
|
|
}
|
|
|
|
/* Stage2 -> EH */
|
|
max_credit = cfg[hwport].max_eh_offset + 1;
|
|
for (i = start_ctxt; i < limit; i++) {
|
|
credit = cfg[hwport].stg2_eh_credit / max_ctxts;
|
|
if (credit > max_credit)
|
|
credit = max_credit;
|
|
data = credit << 16 |
|
|
i << 4 |
|
|
1;
|
|
nlm_write_nae_reg(nae_base, NAE_STG2_EHCRDT_CMD, data);
|
|
}
|
|
|
|
/* Stage2 -> Frout */
|
|
max_credit = cfg[hwport].max_frout_offset + 1;
|
|
for (i = start_ctxt; i < limit; i++) {
|
|
credit = cfg[hwport].stg2_frout_credit / max_ctxts;
|
|
if (credit > max_credit)
|
|
credit = max_credit;
|
|
data = credit << 16 |
|
|
i << 4 |
|
|
1;
|
|
nlm_write_nae_reg(nae_base, NAE_EH_FREECRDT_CMD, data);
|
|
}
|
|
|
|
/* Stage2 -> MS */
|
|
max_credit = cfg[hwport].max_ms_offset + 1;
|
|
for (i = start_ctxt; i < limit; i++) {
|
|
credit = cfg[hwport].stg2_ms_credit / max_ctxts;
|
|
if (credit > max_credit)
|
|
credit = max_credit;
|
|
data = credit << 16 |
|
|
i << 4 |
|
|
1;
|
|
nlm_write_nae_reg(nae_base, NAE_STG2_STRCRDT_CMD, data);
|
|
}
|
|
}
|
|
|
|
void
|
|
nlm_config_freein_fifo_uniq_cfg(uint64_t nae_base, int port,
|
|
int nblock_free_desc)
|
|
{
|
|
uint32_t val;
|
|
int size_in_clines;
|
|
|
|
size_in_clines = (nblock_free_desc / NAE_CACHELINE_SIZE);
|
|
val = (size_in_clines << 8) | (port & 0x1f);
|
|
nlm_write_nae_reg(nae_base, NAE_FREEIN_FIFO_UNIQ_SZ_CFG, val);
|
|
}
|
|
|
|
/* XXXJC: redundant, see ucore_spray_config() */
|
|
void
|
|
nlm_config_ucore_iface_mask_cfg(uint64_t nae_base, int port,
|
|
int nblock_ucore_mask)
|
|
{
|
|
uint32_t val;
|
|
|
|
val = ( 0x1U << 31) | ((nblock_ucore_mask & 0xffff) << 8) |
|
|
(port & 0x1f);
|
|
nlm_write_nae_reg(nae_base, NAE_UCORE_IFACEMASK_CFG, val);
|
|
}
|
|
|
|
int
|
|
nlm_nae_init_netior(uint64_t nae_base, int nblocks)
|
|
{
|
|
uint32_t ctrl1, ctrl2, ctrl3;
|
|
|
|
if (nblocks == 5)
|
|
ctrl3 = 0x07 << 18;
|
|
else
|
|
ctrl3 = 0;
|
|
|
|
switch (nblocks) {
|
|
case 2:
|
|
ctrl1 = 0xff;
|
|
ctrl2 = 0x0707;
|
|
break;
|
|
case 4:
|
|
case 5:
|
|
ctrl1 = 0xfffff;
|
|
ctrl2 = 0x07070707;
|
|
break;
|
|
default:
|
|
printf("WARNING: unsupported blocks %d\n", nblocks);
|
|
return (-1);
|
|
}
|
|
|
|
nlm_write_nae_reg(nae_base, NAE_LANE_CFG_SOFTRESET, 0);
|
|
nlm_write_nae_reg(nae_base, NAE_NETIOR_MISC_CTRL3, ctrl3);
|
|
nlm_write_nae_reg(nae_base, NAE_NETIOR_MISC_CTRL2, ctrl2);
|
|
nlm_write_nae_reg(nae_base, NAE_NETIOR_MISC_CTRL1, ctrl1);
|
|
nlm_write_nae_reg(nae_base, NAE_NETIOR_MISC_CTRL1, 0x0);
|
|
return (0);
|
|
}
|
|
|
|
void
|
|
nlm_nae_init_ingress(uint64_t nae_base, uint32_t desc_size)
|
|
{
|
|
uint32_t rx_cfg;
|
|
uint32_t parser_threshold = 384;
|
|
|
|
rx_cfg = nlm_read_nae_reg(nae_base, NAE_RX_CONFIG);
|
|
rx_cfg &= ~(0x3 << 1); /* reset max message size */
|
|
rx_cfg &= ~(0xff << 4); /* clear freein desc cluster size */
|
|
rx_cfg &= ~(0x3f << 24); /* reset rx status mask */ /*XXX: why not 7f */
|
|
|
|
rx_cfg |= 1; /* rx enable */
|
|
rx_cfg |= (0x0 << 1); /* max message size */
|
|
rx_cfg |= (0x43 & 0x7f) << 24; /* rx status mask */
|
|
rx_cfg |= ((desc_size / 64) & 0xff) << 4; /* freein desc cluster size */
|
|
nlm_write_nae_reg(nae_base, NAE_RX_CONFIG, rx_cfg);
|
|
nlm_write_nae_reg(nae_base, NAE_PARSER_CONFIG,
|
|
(parser_threshold & 0x3ff) |
|
|
(((parser_threshold / desc_size) + 1) & 0xff) << 12 |
|
|
(((parser_threshold / 64) % desc_size) & 0xff) << 20);
|
|
|
|
/*nlm_write_nae_reg(nae_base, NAE_RX_FREE_FIFO_THRESH, 33);*/
|
|
}
|
|
|
|
void
|
|
nlm_nae_init_egress(uint64_t nae_base)
|
|
{
|
|
uint32_t tx_cfg;
|
|
|
|
tx_cfg = nlm_read_nae_reg(nae_base, NAE_TX_CONFIG);
|
|
if (!nlm_is_xlp8xx_ax()) {
|
|
nlm_write_nae_reg(nae_base, NAE_TX_CONFIG,
|
|
tx_cfg |
|
|
0x1 | /* tx enable */
|
|
0x2 | /* tx ace */
|
|
0x4 | /* tx compatible */
|
|
(1 << 3));
|
|
} else {
|
|
nlm_write_nae_reg(nae_base, NAE_TX_CONFIG,
|
|
tx_cfg |
|
|
0x1 | /* tx enable */
|
|
0x2); /* tx ace */
|
|
}
|
|
}
|
|
|
|
uint32_t
|
|
ucore_spray_config(uint32_t interface, uint32_t ucore_mask, int cmd)
|
|
{
|
|
return ((cmd & 0x1) << 31) | ((ucore_mask & 0xffff) << 8) |
|
|
(interface & 0x1f);
|
|
}
|
|
|
|
void
|
|
nlm_nae_init_ucore(uint64_t nae_base, int if_num, u_int ucore_mask)
|
|
{
|
|
uint32_t ucfg;
|
|
|
|
ucfg = ucore_spray_config(if_num, ucore_mask, 1); /* 1 : write */
|
|
nlm_write_nae_reg(nae_base, NAE_UCORE_IFACEMASK_CFG, ucfg);
|
|
}
|
|
|
|
uint64_t
|
|
nae_tx_desc(u_int type, u_int rdex, u_int fbid, u_int len, uint64_t addr)
|
|
{
|
|
return ((uint64_t)type << 62) |
|
|
((uint64_t)rdex << 61) |
|
|
((uint64_t)fbid << 54) |
|
|
((uint64_t)len << 40) | addr;
|
|
}
|
|
|
|
void
|
|
nlm_setup_l2type(uint64_t nae_base, int hwport, uint32_t l2extlen,
|
|
uint32_t l2extoff, uint32_t extra_hdrsize, uint32_t proto_offset,
|
|
uint32_t fixed_hdroff, uint32_t l2proto)
|
|
{
|
|
uint32_t val;
|
|
|
|
val = ((l2extlen & 0x3f) << 26) |
|
|
((l2extoff & 0x3f) << 20) |
|
|
((extra_hdrsize & 0x3f) << 14) |
|
|
((proto_offset & 0x3f) << 8) |
|
|
((fixed_hdroff & 0x3f) << 2) |
|
|
(l2proto & 0x3);
|
|
nlm_write_nae_reg(nae_base, (NAE_L2_TYPE_PORT0 + hwport), val);
|
|
}
|
|
|
|
void
|
|
nlm_setup_l3ctable_mask(uint64_t nae_base, int hwport, uint32_t ptmask,
|
|
uint32_t l3portmask)
|
|
{
|
|
uint32_t val;
|
|
|
|
val = ((ptmask & 0x1) << 6) |
|
|
((l3portmask & 0x1) << 5) |
|
|
(hwport & 0x1f);
|
|
nlm_write_nae_reg(nae_base, NAE_L3_CTABLE_MASK0, val);
|
|
}
|
|
|
|
void
|
|
nlm_setup_l3ctable_even(uint64_t nae_base, int entry, uint32_t l3hdroff,
|
|
uint32_t ipcsum_en, uint32_t l4protooff,
|
|
uint32_t l2proto, uint32_t eth_type)
|
|
{
|
|
uint32_t val;
|
|
|
|
val = ((l3hdroff & 0x3f) << 26) |
|
|
((l4protooff & 0x3f) << 20) |
|
|
((ipcsum_en & 0x1) << 18) |
|
|
((l2proto & 0x3) << 16) |
|
|
(eth_type & 0xffff);
|
|
nlm_write_nae_reg(nae_base, (NAE_L3CTABLE0 + (entry * 2)), val);
|
|
}
|
|
|
|
void
|
|
nlm_setup_l3ctable_odd(uint64_t nae_base, int entry, uint32_t l3off0,
|
|
uint32_t l3len0, uint32_t l3off1, uint32_t l3len1,
|
|
uint32_t l3off2, uint32_t l3len2)
|
|
{
|
|
uint32_t val;
|
|
|
|
val = ((l3off0 & 0x3f) << 26) |
|
|
((l3len0 & 0x1f) << 21) |
|
|
((l3off1 & 0x3f) << 15) |
|
|
((l3len1 & 0x1f) << 10) |
|
|
((l3off2 & 0x3f) << 4) |
|
|
(l3len2 & 0xf);
|
|
nlm_write_nae_reg(nae_base, (NAE_L3CTABLE0 + ((entry * 2) + 1)), val);
|
|
}
|
|
|
|
void
|
|
nlm_setup_l4ctable_even(uint64_t nae_base, int entry, uint32_t im,
|
|
uint32_t l3cm, uint32_t l4pm, uint32_t port,
|
|
uint32_t l3camaddr, uint32_t l4proto)
|
|
{
|
|
uint32_t val;
|
|
|
|
val = ((im & 0x1) << 19) |
|
|
((l3cm & 0x1) << 18) |
|
|
((l4pm & 0x1) << 17) |
|
|
((port & 0x1f) << 12) |
|
|
((l3camaddr & 0xf) << 8) |
|
|
(l4proto & 0xff);
|
|
nlm_write_nae_reg(nae_base, (NAE_L4CTABLE0 + (entry * 2)), val);
|
|
}
|
|
|
|
void
|
|
nlm_setup_l4ctable_odd(uint64_t nae_base, int entry, uint32_t l4off0,
|
|
uint32_t l4len0, uint32_t l4off1, uint32_t l4len1)
|
|
{
|
|
uint32_t val;
|
|
|
|
val = ((l4off0 & 0x3f) << 21) |
|
|
((l4len0 & 0xf) << 17) |
|
|
((l4off1 & 0x3f) << 11) |
|
|
(l4len1 & 0xf);
|
|
nlm_write_nae_reg(nae_base, (NAE_L4CTABLE0 + ((entry * 2) + 1)), val);
|
|
}
|
|
|
|
void
|
|
nlm_enable_hardware_parser(uint64_t nae_base)
|
|
{
|
|
uint32_t val;
|
|
|
|
val = nlm_read_nae_reg(nae_base, NAE_RX_CONFIG);
|
|
val |= (1 << 12); /* hardware parser enable */
|
|
nlm_write_nae_reg(nae_base, NAE_RX_CONFIG, val);
|
|
|
|
/***********************************************
|
|
* program L3 CAM table
|
|
***********************************************/
|
|
|
|
/*
|
|
* entry-0 is ipv4 MPLS type 1 label
|
|
*/
|
|
/* l3hdroff = 4 bytes, ether_type = 0x8847 for MPLS_type1 */
|
|
nlm_setup_l3ctable_even(nae_base, 0, 4, 1, 9, 1, 0x8847);
|
|
/* l3off0 (8 bytes) -> l3len0 (1 byte) := ip proto
|
|
* l3off1 (12 bytes) -> l3len1 (4 bytes) := src ip
|
|
* l3off2 (16 bytes) -> l3len2 (4 bytes) := dst ip
|
|
*/
|
|
nlm_setup_l3ctable_odd(nae_base, 0, 9, 1, 12, 4, 16, 4);
|
|
|
|
/*
|
|
* entry-1 is for ethernet IPv4 packets
|
|
*/
|
|
nlm_setup_l3ctable_even(nae_base, 1, 0, 1, 9, 1, 0x0800);
|
|
/* l3off0 (8 bytes) -> l3len0 (1 byte) := ip proto
|
|
* l3off1 (12 bytes) -> l3len1 (4 bytes) := src ip
|
|
* l3off2 (16 bytes) -> l3len2 (4 bytes) := dst ip
|
|
*/
|
|
nlm_setup_l3ctable_odd(nae_base, 1, 9, 1, 12, 4, 16, 4);
|
|
|
|
/*
|
|
* entry-2 is for ethernet IPv6 packets
|
|
*/
|
|
nlm_setup_l3ctable_even(nae_base, 2, 0, 1, 6, 1, 0x86dd);
|
|
/* l3off0 (6 bytes) -> l3len0 (1 byte) := next header (ip proto)
|
|
* l3off1 (8 bytes) -> l3len1 (16 bytes) := src ip
|
|
* l3off2 (24 bytes) -> l3len2 (16 bytes) := dst ip
|
|
*/
|
|
nlm_setup_l3ctable_odd(nae_base, 2, 6, 1, 8, 16, 24, 16);
|
|
|
|
/*
|
|
* entry-3 is for ethernet ARP packets
|
|
*/
|
|
nlm_setup_l3ctable_even(nae_base, 3, 0, 0, 9, 1, 0x0806);
|
|
/* extract 30 bytes from packet start */
|
|
nlm_setup_l3ctable_odd(nae_base, 3, 0, 30, 0, 0, 0, 0);
|
|
|
|
/*
|
|
* entry-4 is for ethernet FCoE packets
|
|
*/
|
|
nlm_setup_l3ctable_even(nae_base, 4, 0, 0, 9, 1, 0x8906);
|
|
/* FCoE packet consists of 4 byte start-of-frame,
|
|
* and 24 bytes of frame header, followed by
|
|
* 64 bytes of optional-header (ESP, network..),
|
|
* 2048 bytes of payload, 36 bytes of optional
|
|
* "fill bytes" or ESP trailer, 4 bytes of CRC,
|
|
* and 4 bytes of end-of-frame
|
|
* We extract the first 4 + 24 = 28 bytes
|
|
*/
|
|
nlm_setup_l3ctable_odd(nae_base, 4, 0, 28, 0, 0, 0, 0);
|
|
|
|
/*
|
|
* entry-5 is for vlan tagged frames (0x8100)
|
|
*/
|
|
nlm_setup_l3ctable_even(nae_base, 5, 0, 0, 9, 1, 0x8100);
|
|
/* we extract 31 bytes from the payload */
|
|
nlm_setup_l3ctable_odd(nae_base, 5, 0, 31, 0, 0, 0, 0);
|
|
|
|
/*
|
|
* entry-6 is for ieee 802.1ad provider bridging
|
|
* tagged frames (0x88a8)
|
|
*/
|
|
nlm_setup_l3ctable_even(nae_base, 6, 0, 0, 9, 1, 0x88a8);
|
|
/* we extract 31 bytes from the payload */
|
|
nlm_setup_l3ctable_odd(nae_base, 6, 0, 31, 0, 0, 0, 0);
|
|
|
|
/*
|
|
* entry-7 is for Cisco's Q-in-Q tagged frames (0x9100)
|
|
*/
|
|
nlm_setup_l3ctable_even(nae_base, 7, 0, 0, 9, 1, 0x9100);
|
|
/* we extract 31 bytes from the payload */
|
|
nlm_setup_l3ctable_odd(nae_base, 7, 0, 31, 0, 0, 0, 0);
|
|
|
|
/*
|
|
* entry-8 is for Ethernet Jumbo frames (0x8870)
|
|
*/
|
|
nlm_setup_l3ctable_even(nae_base, 8, 0, 0, 9, 1, 0x8870);
|
|
/* we extract 31 bytes from the payload */
|
|
nlm_setup_l3ctable_odd(nae_base, 8, 0, 31, 0, 0, 0, 0);
|
|
|
|
/*
|
|
* entry-9 is for MPLS Multicast frames (0x8848)
|
|
*/
|
|
nlm_setup_l3ctable_even(nae_base, 9, 0, 0, 9, 1, 0x8848);
|
|
/* we extract 31 bytes from the payload */
|
|
nlm_setup_l3ctable_odd(nae_base, 9, 0, 31, 0, 0, 0, 0);
|
|
|
|
/*
|
|
* entry-10 is for IEEE 802.1ae MAC Security frames (0x88e5)
|
|
*/
|
|
nlm_setup_l3ctable_even(nae_base, 10, 0, 0, 9, 1, 0x88e5);
|
|
/* we extract 31 bytes from the payload */
|
|
nlm_setup_l3ctable_odd(nae_base, 10, 0, 31, 0, 0, 0, 0);
|
|
|
|
/*
|
|
* entry-11 is for PTP frames (0x88f7)
|
|
*/
|
|
nlm_setup_l3ctable_even(nae_base, 11, 0, 0, 9, 1, 0x88f7);
|
|
/* PTP messages can be sent as UDP messages over
|
|
* IPv4 or IPv6; and as a raw ethernet message
|
|
* with ethertype 0x88f7. The message contents
|
|
* are the same for UDP or ethernet based encapsulations
|
|
* The header is 34 bytes long, and we extract
|
|
* it all out.
|
|
*/
|
|
nlm_setup_l3ctable_odd(nae_base, 11, 0, 31, 31, 2, 0, 0);
|
|
|
|
/*
|
|
* entry-12 is for ethernet Link Control Protocol (LCP)
|
|
* used with PPPoE
|
|
*/
|
|
nlm_setup_l3ctable_even(nae_base, 12, 0, 0, 9, 1, 0xc021);
|
|
/* LCP packet consists of 1 byte of code, 1 byte of
|
|
* identifier and two bytes of length followed by
|
|
* data (upto length bytes).
|
|
* We extract 4 bytes from start of packet
|
|
*/
|
|
nlm_setup_l3ctable_odd(nae_base, 12, 0, 4, 0, 0, 0, 0);
|
|
|
|
/*
|
|
* entry-13 is for ethernet Link Quality Report (0xc025)
|
|
* used with PPPoE
|
|
*/
|
|
nlm_setup_l3ctable_even(nae_base, 13, 0, 0, 9, 1, 0xc025);
|
|
/* We extract 31 bytes from packet start */
|
|
nlm_setup_l3ctable_odd(nae_base, 13, 0, 31, 0, 0, 0, 0);
|
|
|
|
/*
|
|
* entry-14 is for PPPoE Session (0x8864)
|
|
*/
|
|
nlm_setup_l3ctable_even(nae_base, 14, 0, 0, 9, 1, 0x8864);
|
|
/* We extract 31 bytes from packet start */
|
|
nlm_setup_l3ctable_odd(nae_base, 14, 0, 31, 0, 0, 0, 0);
|
|
|
|
/*
|
|
* entry-15 - default entry
|
|
*/
|
|
nlm_setup_l3ctable_even(nae_base, 15, 0, 0, 0, 0, 0x0000);
|
|
/* We extract 31 bytes from packet start */
|
|
nlm_setup_l3ctable_odd(nae_base, 15, 0, 31, 0, 0, 0, 0);
|
|
|
|
/***********************************************
|
|
* program L4 CAM table
|
|
***********************************************/
|
|
|
|
/*
|
|
* entry-0 - tcp packets (0x6)
|
|
*/
|
|
nlm_setup_l4ctable_even(nae_base, 0, 0, 0, 1, 0, 0, 0x6);
|
|
/* tcp header is 20 bytes without tcp options
|
|
* We extract 20 bytes from tcp start */
|
|
nlm_setup_l4ctable_odd(nae_base, 0, 0, 15, 15, 5);
|
|
|
|
/*
|
|
* entry-1 - udp packets (0x11)
|
|
*/
|
|
nlm_setup_l4ctable_even(nae_base, 1, 0, 0, 1, 0, 0, 0x11);
|
|
/* udp header is 8 bytes in size.
|
|
* We extract 8 bytes from udp start */
|
|
nlm_setup_l4ctable_odd(nae_base, 1, 0, 8, 0, 0);
|
|
|
|
/*
|
|
* entry-2 - sctp packets (0x84)
|
|
*/
|
|
nlm_setup_l4ctable_even(nae_base, 2, 0, 0, 1, 0, 0, 0x84);
|
|
/* sctp packets have a 12 byte generic header
|
|
* and various chunks.
|
|
* We extract 12 bytes from sctp start */
|
|
nlm_setup_l4ctable_odd(nae_base, 2, 0, 12, 0, 0);
|
|
|
|
/*
|
|
* entry-3 - RDP packets (0x1b)
|
|
*/
|
|
nlm_setup_l4ctable_even(nae_base, 3, 0, 0, 1, 0, 0, 0x1b);
|
|
/* RDP packets have 18 bytes of generic header
|
|
* before variable header starts.
|
|
* We extract 18 bytes from rdp start */
|
|
nlm_setup_l4ctable_odd(nae_base, 3, 0, 15, 15, 3);
|
|
|
|
/*
|
|
* entry-4 - DCCP packets (0x21)
|
|
*/
|
|
nlm_setup_l4ctable_even(nae_base, 4, 0, 0, 1, 0, 0, 0x21);
|
|
/* DCCP has two types of generic headers of
|
|
* sizes 16 bytes and 12 bytes if X = 1.
|
|
* We extract 16 bytes from dccp start */
|
|
nlm_setup_l4ctable_odd(nae_base, 4, 0, 15, 15, 1);
|
|
|
|
/*
|
|
* entry-5 - ipv6 encapsulated in ipv4 packets (0x29)
|
|
*/
|
|
nlm_setup_l4ctable_even(nae_base, 5, 0, 0, 1, 0, 0, 0x29);
|
|
/* ipv4 header is 20 bytes excluding IP options.
|
|
* We extract 20 bytes from IPv4 start */
|
|
nlm_setup_l4ctable_odd(nae_base, 5, 0, 15, 15, 5);
|
|
|
|
/*
|
|
* entry-6 - ip in ip encapsulation packets (0x04)
|
|
*/
|
|
nlm_setup_l4ctable_even(nae_base, 6, 0, 0, 1, 0, 0, 0x04);
|
|
/* ipv4 header is 20 bytes excluding IP options.
|
|
* We extract 20 bytes from ipv4 start */
|
|
nlm_setup_l4ctable_odd(nae_base, 6, 0, 15, 15, 5);
|
|
|
|
/*
|
|
* entry-7 - default entry (0x0)
|
|
*/
|
|
nlm_setup_l4ctable_even(nae_base, 7, 0, 0, 1, 0, 0, 0x0);
|
|
/* We extract 20 bytes from packet start */
|
|
nlm_setup_l4ctable_odd(nae_base, 7, 0, 15, 15, 5);
|
|
}
|
|
|
|
void
|
|
nlm_enable_hardware_parser_per_port(uint64_t nae_base, int block, int port)
|
|
{
|
|
int hwport = (block * 4) + (port & 0x3);
|
|
|
|
/* program L2 and L3 header extraction for each port */
|
|
/* enable ethernet L2 mode on port */
|
|
nlm_setup_l2type(nae_base, hwport, 0, 0, 0, 0, 0, 1);
|
|
|
|
/* l2proto and ethtype included in l3cam */
|
|
nlm_setup_l3ctable_mask(nae_base, hwport, 1, 0);
|
|
}
|
|
|
|
void
|
|
nlm_prepad_enable(uint64_t nae_base, int size)
|
|
{
|
|
uint32_t val;
|
|
|
|
val = nlm_read_nae_reg(nae_base, NAE_RX_CONFIG);
|
|
val |= (1 << 13); /* prepad enable */
|
|
val |= ((size & 0x3) << 22); /* prepad size */
|
|
nlm_write_nae_reg(nae_base, NAE_RX_CONFIG, val);
|
|
}
|
|
|
|
void
|
|
nlm_setup_1588_timer(uint64_t nae_base, struct nae_port_config *cfg)
|
|
{
|
|
uint32_t hi, lo, val;
|
|
|
|
hi = cfg[0].ieee1588_userval >> 32;
|
|
lo = cfg[0].ieee1588_userval & 0xffffffff;
|
|
nlm_write_nae_reg(nae_base, NAE_1588_PTP_USER_VALUE_HI, hi);
|
|
nlm_write_nae_reg(nae_base, NAE_1588_PTP_USER_VALUE_LO, lo);
|
|
|
|
hi = cfg[0].ieee1588_ptpoff >> 32;
|
|
lo = cfg[0].ieee1588_ptpoff & 0xffffffff;
|
|
nlm_write_nae_reg(nae_base, NAE_1588_PTP_OFFSET_HI, hi);
|
|
nlm_write_nae_reg(nae_base, NAE_1588_PTP_OFFSET_LO, lo);
|
|
|
|
hi = cfg[0].ieee1588_tmr1 >> 32;
|
|
lo = cfg[0].ieee1588_tmr1 & 0xffffffff;
|
|
nlm_write_nae_reg(nae_base, NAE_1588_PTP_TMR1_HI, hi);
|
|
nlm_write_nae_reg(nae_base, NAE_1588_PTP_TMR1_LO, lo);
|
|
|
|
hi = cfg[0].ieee1588_tmr2 >> 32;
|
|
lo = cfg[0].ieee1588_tmr2 & 0xffffffff;
|
|
nlm_write_nae_reg(nae_base, NAE_1588_PTP_TMR2_HI, hi);
|
|
nlm_write_nae_reg(nae_base, NAE_1588_PTP_TMR2_LO, lo);
|
|
|
|
hi = cfg[0].ieee1588_tmr3 >> 32;
|
|
lo = cfg[0].ieee1588_tmr3 & 0xffffffff;
|
|
nlm_write_nae_reg(nae_base, NAE_1588_PTP_TMR3_HI, hi);
|
|
nlm_write_nae_reg(nae_base, NAE_1588_PTP_TMR3_LO, lo);
|
|
|
|
nlm_write_nae_reg(nae_base, NAE_1588_PTP_INC_INTG,
|
|
cfg[0].ieee1588_inc_intg);
|
|
nlm_write_nae_reg(nae_base, NAE_1588_PTP_INC_NUM,
|
|
cfg[0].ieee1588_inc_num);
|
|
nlm_write_nae_reg(nae_base, NAE_1588_PTP_INC_DEN,
|
|
cfg[0].ieee1588_inc_den);
|
|
|
|
val = nlm_read_nae_reg(nae_base, NAE_1588_PTP_CONTROL);
|
|
/* set and clear freq_mul = 1 */
|
|
nlm_write_nae_reg(nae_base, NAE_1588_PTP_CONTROL, val | (0x1 << 1));
|
|
nlm_write_nae_reg(nae_base, NAE_1588_PTP_CONTROL, val);
|
|
/* set and clear load_user_val = 1 */
|
|
nlm_write_nae_reg(nae_base, NAE_1588_PTP_CONTROL, val | (0x1 << 6));
|
|
nlm_write_nae_reg(nae_base, NAE_1588_PTP_CONTROL, val);
|
|
}
|
|
|
|
void
|
|
nlm_mac_enable(uint64_t nae_base, int nblock, int port_type, int port)
|
|
{
|
|
uint32_t mac_cfg1, xaui_cfg;
|
|
uint32_t netwk_inf;
|
|
int iface = port & 0x3;
|
|
|
|
switch(port_type) {
|
|
case SGMIIC:
|
|
netwk_inf = nlm_read_nae_reg(nae_base,
|
|
SGMII_NET_IFACE_CTRL(nblock, iface));
|
|
nlm_write_nae_reg(nae_base,
|
|
SGMII_NET_IFACE_CTRL(nblock, iface),
|
|
netwk_inf |
|
|
(1 << 2)); /* enable tx */
|
|
mac_cfg1 = nlm_read_nae_reg(nae_base,
|
|
SGMII_MAC_CONF1(nblock, iface));
|
|
nlm_write_nae_reg(nae_base,
|
|
SGMII_MAC_CONF1(nblock, iface),
|
|
mac_cfg1 |
|
|
(1 << 2) | /* rx enable */
|
|
1); /* tx enable */
|
|
break;
|
|
case XAUIC:
|
|
xaui_cfg = nlm_read_nae_reg(nae_base,
|
|
XAUI_CONFIG1(nblock));
|
|
nlm_write_nae_reg(nae_base,
|
|
XAUI_CONFIG1(nblock),
|
|
xaui_cfg |
|
|
XAUI_CONFIG_TFEN |
|
|
XAUI_CONFIG_RFEN);
|
|
break;
|
|
case ILC:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
nlm_mac_disable(uint64_t nae_base, int nblock, int port_type, int port)
|
|
{
|
|
uint32_t mac_cfg1, xaui_cfg;
|
|
uint32_t netwk_inf;
|
|
int iface = port & 0x3;
|
|
|
|
switch(port_type) {
|
|
case SGMIIC:
|
|
mac_cfg1 = nlm_read_nae_reg(nae_base,
|
|
SGMII_MAC_CONF1(nblock, iface));
|
|
nlm_write_nae_reg(nae_base,
|
|
SGMII_MAC_CONF1(nblock, iface),
|
|
mac_cfg1 &
|
|
~((1 << 2) | /* rx enable */
|
|
1)); /* tx enable */
|
|
netwk_inf = nlm_read_nae_reg(nae_base,
|
|
SGMII_NET_IFACE_CTRL(nblock, iface));
|
|
nlm_write_nae_reg(nae_base,
|
|
SGMII_NET_IFACE_CTRL(nblock, iface),
|
|
netwk_inf &
|
|
~(1 << 2)); /* enable tx */
|
|
break;
|
|
case XAUIC:
|
|
xaui_cfg = nlm_read_nae_reg(nae_base,
|
|
XAUI_CONFIG1(nblock));
|
|
nlm_write_nae_reg(nae_base,
|
|
XAUI_CONFIG1(nblock),
|
|
xaui_cfg &
|
|
~(XAUI_CONFIG_TFEN |
|
|
XAUI_CONFIG_RFEN));
|
|
break;
|
|
case ILC:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Set IOR credits for the ports in ifmask to valmask
|
|
*/
|
|
static void
|
|
nlm_nae_set_ior_credit(uint64_t nae_base, uint32_t ifmask, uint32_t valmask)
|
|
{
|
|
uint32_t tx_config, tx_ior_credit;
|
|
|
|
tx_ior_credit = nlm_read_nae_reg(nae_base, NAE_TX_IORCRDT_INIT);
|
|
tx_ior_credit &= ~ifmask;
|
|
tx_ior_credit |= valmask;
|
|
nlm_write_nae_reg(nae_base, NAE_TX_IORCRDT_INIT, tx_ior_credit);
|
|
|
|
tx_config = nlm_read_nae_reg(nae_base, NAE_TX_CONFIG);
|
|
/* need to toggle these bits for credits to be loaded */
|
|
nlm_write_nae_reg(nae_base, NAE_TX_CONFIG,
|
|
tx_config | (TXINITIORCR(ifmask)));
|
|
nlm_write_nae_reg(nae_base, NAE_TX_CONFIG,
|
|
tx_config & ~(TXINITIORCR(ifmask)));
|
|
}
|
|
|
|
int
|
|
nlm_nae_open_if(uint64_t nae_base, int nblock, int port_type,
|
|
int port, uint32_t desc_size)
|
|
{
|
|
uint32_t netwk_inf;
|
|
uint32_t mac_cfg1, netior_ctrl3;
|
|
int iface, iface_ctrl_reg, iface_ctrl3_reg, conf1_reg, conf2_reg;
|
|
|
|
switch (port_type) {
|
|
case XAUIC:
|
|
netwk_inf = nlm_read_nae_reg(nae_base,
|
|
XAUI_NETIOR_XGMAC_CTRL1(nblock));
|
|
netwk_inf |= (1 << NETIOR_XGMAC_STATS_CLR_POS);
|
|
nlm_write_nae_reg(nae_base,
|
|
XAUI_NETIOR_XGMAC_CTRL1(nblock), netwk_inf);
|
|
|
|
nlm_nae_set_ior_credit(nae_base, 0xf << port, 0xf << port);
|
|
break;
|
|
|
|
case ILC:
|
|
nlm_nae_set_ior_credit(nae_base, 0xff << port, 0xff << port);
|
|
break;
|
|
|
|
case SGMIIC:
|
|
nlm_nae_set_ior_credit(nae_base, 0x1 << port, 0);
|
|
|
|
/*
|
|
* XXXJC: split this and merge to sgmii.c
|
|
* some of this is duplicated from there.
|
|
*/
|
|
/* init phy id to access internal PCS */
|
|
iface = port & 0x3;
|
|
iface_ctrl_reg = SGMII_NET_IFACE_CTRL(nblock, iface);
|
|
conf1_reg = SGMII_MAC_CONF1(nblock, iface);
|
|
conf2_reg = SGMII_MAC_CONF2(nblock, iface);
|
|
|
|
netwk_inf = nlm_read_nae_reg(nae_base, iface_ctrl_reg);
|
|
netwk_inf &= 0x7ffffff;
|
|
netwk_inf |= (port << 27);
|
|
nlm_write_nae_reg(nae_base, iface_ctrl_reg, netwk_inf);
|
|
|
|
/* Sofreset sgmii port - set bit 11 to 0 */
|
|
netwk_inf &= 0xfffff7ff;
|
|
nlm_write_nae_reg(nae_base, iface_ctrl_reg, netwk_inf);
|
|
|
|
/* Reset Gmac */
|
|
mac_cfg1 = nlm_read_nae_reg(nae_base, conf1_reg);
|
|
nlm_write_nae_reg(nae_base, conf1_reg,
|
|
mac_cfg1 |
|
|
(1U << 31) | /* soft reset */
|
|
(1 << 2) | /* rx enable */
|
|
(1)); /* tx enable */
|
|
|
|
/* default to 1G */
|
|
nlm_write_nae_reg(nae_base,
|
|
conf2_reg,
|
|
(0x7 << 12) | /* interface preamble length */
|
|
(0x2 << 8) | /* interface mode */
|
|
(0x1 << 2) | /* pad crc enable */
|
|
(0x1)); /* full duplex */
|
|
|
|
/* clear gmac reset */
|
|
mac_cfg1 = nlm_read_nae_reg(nae_base, conf1_reg);
|
|
nlm_write_nae_reg(nae_base, conf1_reg, mac_cfg1 & ~(1U << 31));
|
|
|
|
/* clear speed debug bit */
|
|
iface_ctrl3_reg = SGMII_NET_IFACE_CTRL3(nblock, iface);
|
|
netior_ctrl3 = nlm_read_nae_reg(nae_base, iface_ctrl3_reg);
|
|
nlm_write_nae_reg(nae_base, iface_ctrl3_reg,
|
|
netior_ctrl3 & ~(1 << 6));
|
|
|
|
/* disable TX, RX for now */
|
|
mac_cfg1 = nlm_read_nae_reg(nae_base, conf1_reg);
|
|
nlm_write_nae_reg(nae_base, conf1_reg, mac_cfg1 & ~(0x5));
|
|
netwk_inf = nlm_read_nae_reg(nae_base, iface_ctrl_reg);
|
|
nlm_write_nae_reg(nae_base, iface_ctrl_reg,
|
|
netwk_inf & ~(0x1 << 2));
|
|
|
|
/* clear stats counters */
|
|
netwk_inf = nlm_read_nae_reg(nae_base, iface_ctrl_reg);
|
|
nlm_write_nae_reg(nae_base, iface_ctrl_reg,
|
|
netwk_inf | (1 << 15));
|
|
|
|
/* enable stats counters */
|
|
netwk_inf = nlm_read_nae_reg(nae_base, iface_ctrl_reg);
|
|
nlm_write_nae_reg(nae_base, iface_ctrl_reg,
|
|
(netwk_inf & ~(1 << 15)) | (1 << 16));
|
|
|
|
/* flow control? */
|
|
mac_cfg1 = nlm_read_nae_reg(nae_base, conf1_reg);
|
|
nlm_write_nae_reg(nae_base, conf1_reg,
|
|
mac_cfg1 | (0x3 << 4));
|
|
break;
|
|
}
|
|
|
|
nlm_nae_init_ingress(nae_base, desc_size);
|
|
nlm_nae_init_egress(nae_base);
|
|
|
|
return (0);
|
|
}
|