mirror of https://github.com/F-Stack/f-stack.git
889 lines
23 KiB
C
889 lines
23 KiB
C
/*
|
|
* Copyright 2008-2012 Freescale Semiconductor Inc.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * 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.
|
|
* * Neither the name of Freescale Semiconductor nor the
|
|
* names of its contributors may be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
*
|
|
* ALTERNATIVELY, this software may be distributed under the terms of the
|
|
* GNU General Public License ("GPL") as published by the Free Software
|
|
* Foundation, either version 2 of that License or (at your option) any
|
|
* later version.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``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 Freescale Semiconductor 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 "fsl_fman_kg.h"
|
|
|
|
/****************************************/
|
|
/* static functions */
|
|
/****************************************/
|
|
|
|
|
|
static uint32_t build_ar_bind_scheme(uint8_t hwport_id, bool write)
|
|
{
|
|
uint32_t rw;
|
|
|
|
rw = write ? (uint32_t)FM_KG_KGAR_WRITE : (uint32_t)FM_KG_KGAR_READ;
|
|
|
|
return (uint32_t)(FM_KG_KGAR_GO |
|
|
rw |
|
|
FM_PCD_KG_KGAR_SEL_PORT_ENTRY |
|
|
hwport_id |
|
|
FM_PCD_KG_KGAR_SEL_PORT_WSEL_SP);
|
|
}
|
|
|
|
static void clear_pe_all_scheme(struct fman_kg_regs *regs, uint8_t hwport_id)
|
|
{
|
|
uint32_t ar;
|
|
|
|
fman_kg_write_sp(regs, 0xffffffff, 0);
|
|
|
|
ar = build_ar_bind_scheme(hwport_id, TRUE);
|
|
fman_kg_write_ar_wait(regs, ar);
|
|
}
|
|
|
|
static uint32_t build_ar_bind_cls_plan(uint8_t hwport_id, bool write)
|
|
{
|
|
uint32_t rw;
|
|
|
|
rw = write ? (uint32_t)FM_KG_KGAR_WRITE : (uint32_t)FM_KG_KGAR_READ;
|
|
|
|
return (uint32_t)(FM_KG_KGAR_GO |
|
|
rw |
|
|
FM_PCD_KG_KGAR_SEL_PORT_ENTRY |
|
|
hwport_id |
|
|
FM_PCD_KG_KGAR_SEL_PORT_WSEL_CPP);
|
|
}
|
|
|
|
static void clear_pe_all_cls_plan(struct fman_kg_regs *regs, uint8_t hwport_id)
|
|
{
|
|
uint32_t ar;
|
|
|
|
fman_kg_write_cpp(regs, 0);
|
|
|
|
ar = build_ar_bind_cls_plan(hwport_id, TRUE);
|
|
fman_kg_write_ar_wait(regs, ar);
|
|
}
|
|
|
|
static uint8_t get_gen_ht_code(enum fman_kg_gen_extract_src src,
|
|
bool no_validation,
|
|
uint8_t *offset)
|
|
{
|
|
int code;
|
|
|
|
switch (src) {
|
|
case E_FMAN_KG_GEN_EXTRACT_ETH:
|
|
code = no_validation ? 0x73 : 0x3;
|
|
break;
|
|
|
|
case E_FMAN_KG_GEN_EXTRACT_ETYPE:
|
|
code = no_validation ? 0x77 : 0x7;
|
|
break;
|
|
|
|
case E_FMAN_KG_GEN_EXTRACT_SNAP:
|
|
code = no_validation ? 0x74 : 0x4;
|
|
break;
|
|
|
|
case E_FMAN_KG_GEN_EXTRACT_VLAN_TCI_1:
|
|
code = no_validation ? 0x75 : 0x5;
|
|
break;
|
|
|
|
case E_FMAN_KG_GEN_EXTRACT_VLAN_TCI_N:
|
|
code = no_validation ? 0x76 : 0x6;
|
|
break;
|
|
|
|
case E_FMAN_KG_GEN_EXTRACT_PPPoE:
|
|
code = no_validation ? 0x78 : 0x8;
|
|
break;
|
|
|
|
case E_FMAN_KG_GEN_EXTRACT_MPLS_1:
|
|
code = no_validation ? 0x79 : 0x9;
|
|
break;
|
|
|
|
case E_FMAN_KG_GEN_EXTRACT_MPLS_2:
|
|
code = no_validation ? FM_KG_SCH_GEN_HT_INVALID : 0x19;
|
|
break;
|
|
|
|
case E_FMAN_KG_GEN_EXTRACT_MPLS_3:
|
|
code = no_validation ? FM_KG_SCH_GEN_HT_INVALID : 0x29;
|
|
break;
|
|
|
|
case E_FMAN_KG_GEN_EXTRACT_MPLS_N:
|
|
code = no_validation ? 0x7a : 0xa;
|
|
break;
|
|
|
|
case E_FMAN_KG_GEN_EXTRACT_IPv4_1:
|
|
code = no_validation ? 0x7b : 0xb;
|
|
break;
|
|
|
|
case E_FMAN_KG_GEN_EXTRACT_IPv6_1:
|
|
code = no_validation ? 0x7b : 0x1b;
|
|
break;
|
|
|
|
case E_FMAN_KG_GEN_EXTRACT_IPv4_2:
|
|
code = no_validation ? 0x7c : 0xc;
|
|
break;
|
|
|
|
case E_FMAN_KG_GEN_EXTRACT_IPv6_2:
|
|
code = no_validation ? 0x7c : 0x1c;
|
|
break;
|
|
|
|
case E_FMAN_KG_GEN_EXTRACT_MINENCAP:
|
|
code = no_validation ? 0x7c : 0x2c;
|
|
break;
|
|
|
|
case E_FMAN_KG_GEN_EXTRACT_IP_PID:
|
|
code = no_validation ? 0x72 : 0x2;
|
|
break;
|
|
|
|
case E_FMAN_KG_GEN_EXTRACT_GRE:
|
|
code = no_validation ? 0x7d : 0xd;
|
|
break;
|
|
|
|
case E_FMAN_KG_GEN_EXTRACT_TCP:
|
|
code = no_validation ? 0x7e : 0xe;
|
|
break;
|
|
|
|
case E_FMAN_KG_GEN_EXTRACT_UDP:
|
|
code = no_validation ? 0x7e : 0x1e;
|
|
break;
|
|
|
|
case E_FMAN_KG_GEN_EXTRACT_SCTP:
|
|
code = no_validation ? 0x7e : 0x3e;
|
|
break;
|
|
|
|
case E_FMAN_KG_GEN_EXTRACT_DCCP:
|
|
code = no_validation ? 0x7e : 0x4e;
|
|
break;
|
|
|
|
case E_FMAN_KG_GEN_EXTRACT_IPSEC_AH:
|
|
code = no_validation ? 0x7e : 0x2e;
|
|
break;
|
|
|
|
case E_FMAN_KG_GEN_EXTRACT_IPSEC_ESP:
|
|
code = no_validation ? 0x7e : 0x6e;
|
|
break;
|
|
|
|
case E_FMAN_KG_GEN_EXTRACT_SHIM_1:
|
|
code = 0x70;
|
|
break;
|
|
|
|
case E_FMAN_KG_GEN_EXTRACT_SHIM_2:
|
|
code = 0x71;
|
|
break;
|
|
|
|
case E_FMAN_KG_GEN_EXTRACT_FROM_DFLT:
|
|
code = 0x10;
|
|
break;
|
|
|
|
case E_FMAN_KG_GEN_EXTRACT_FROM_FRAME_START:
|
|
code = 0x40;
|
|
break;
|
|
|
|
case E_FMAN_KG_GEN_EXTRACT_FROM_PARSE_RESULT:
|
|
code = 0x20;
|
|
break;
|
|
|
|
case E_FMAN_KG_GEN_EXTRACT_FROM_END_OF_PARSE:
|
|
code = 0x7f;
|
|
break;
|
|
|
|
case E_FMAN_KG_GEN_EXTRACT_FROM_FQID:
|
|
code = 0x20;
|
|
*offset += 0x20;
|
|
break;
|
|
|
|
default:
|
|
code = FM_KG_SCH_GEN_HT_INVALID;
|
|
}
|
|
|
|
return (uint8_t)code;
|
|
}
|
|
|
|
static uint32_t build_ar_scheme(uint8_t scheme,
|
|
uint8_t hwport_id,
|
|
bool update_counter,
|
|
bool write)
|
|
{
|
|
uint32_t rw;
|
|
|
|
rw = (uint32_t)(write ? FM_KG_KGAR_WRITE : FM_KG_KGAR_READ);
|
|
|
|
return (uint32_t)(FM_KG_KGAR_GO |
|
|
rw |
|
|
FM_KG_KGAR_SEL_SCHEME_ENTRY |
|
|
hwport_id |
|
|
((uint32_t)scheme << FM_KG_KGAR_NUM_SHIFT) |
|
|
(update_counter ? FM_KG_KGAR_SCM_WSEL_UPDATE_CNT : 0));
|
|
}
|
|
|
|
static uint32_t build_ar_cls_plan(uint8_t grp,
|
|
uint8_t entries_mask,
|
|
uint8_t hwport_id,
|
|
bool write)
|
|
{
|
|
uint32_t rw;
|
|
|
|
rw = (uint32_t)(write ? FM_KG_KGAR_WRITE : FM_KG_KGAR_READ);
|
|
|
|
return (uint32_t)(FM_KG_KGAR_GO |
|
|
rw |
|
|
FM_PCD_KG_KGAR_SEL_CLS_PLAN_ENTRY |
|
|
hwport_id |
|
|
((uint32_t)grp << FM_KG_KGAR_NUM_SHIFT) |
|
|
((uint32_t)entries_mask << FM_KG_KGAR_WSEL_SHIFT));
|
|
}
|
|
|
|
int fman_kg_write_ar_wait(struct fman_kg_regs *regs, uint32_t fmkg_ar)
|
|
{
|
|
iowrite32be(fmkg_ar, ®s->fmkg_ar);
|
|
/* Wait for GO to be idle and read error */
|
|
while ((fmkg_ar = ioread32be(®s->fmkg_ar)) & FM_KG_KGAR_GO) ;
|
|
if (fmkg_ar & FM_PCD_KG_KGAR_ERR)
|
|
return -EINVAL;
|
|
return 0;
|
|
}
|
|
|
|
void fman_kg_write_sp(struct fman_kg_regs *regs, uint32_t sp, bool add)
|
|
{
|
|
|
|
struct fman_kg_pe_regs *kgpe_regs;
|
|
uint32_t tmp;
|
|
|
|
kgpe_regs = (struct fman_kg_pe_regs *)&(regs->fmkg_indirect[0]);
|
|
tmp = ioread32be(&kgpe_regs->fmkg_pe_sp);
|
|
|
|
if (add)
|
|
tmp |= sp;
|
|
else /* clear */
|
|
tmp &= ~sp;
|
|
|
|
iowrite32be(tmp, &kgpe_regs->fmkg_pe_sp);
|
|
|
|
}
|
|
|
|
void fman_kg_write_cpp(struct fman_kg_regs *regs, uint32_t cpp)
|
|
{
|
|
struct fman_kg_pe_regs *kgpe_regs;
|
|
|
|
kgpe_regs = (struct fman_kg_pe_regs *)&(regs->fmkg_indirect[0]);
|
|
|
|
iowrite32be(cpp, &kgpe_regs->fmkg_pe_cpp);
|
|
}
|
|
|
|
void fman_kg_get_event(struct fman_kg_regs *regs,
|
|
uint32_t *event,
|
|
uint32_t *scheme_idx)
|
|
{
|
|
uint32_t mask, force;
|
|
|
|
*event = ioread32be(®s->fmkg_eer);
|
|
mask = ioread32be(®s->fmkg_eeer);
|
|
*scheme_idx = ioread32be(®s->fmkg_seer);
|
|
*scheme_idx &= ioread32be(®s->fmkg_seeer);
|
|
|
|
*event &= mask;
|
|
|
|
/* clear the forced events */
|
|
force = ioread32be(®s->fmkg_feer);
|
|
if (force & *event)
|
|
iowrite32be(force & ~*event ,®s->fmkg_feer);
|
|
|
|
iowrite32be(*event, ®s->fmkg_eer);
|
|
iowrite32be(*scheme_idx, ®s->fmkg_seer);
|
|
}
|
|
|
|
|
|
void fman_kg_init(struct fman_kg_regs *regs,
|
|
uint32_t exceptions,
|
|
uint32_t dflt_nia)
|
|
{
|
|
uint32_t tmp;
|
|
int i;
|
|
|
|
iowrite32be(FM_EX_KG_DOUBLE_ECC | FM_EX_KG_KEYSIZE_OVERFLOW,
|
|
®s->fmkg_eer);
|
|
|
|
tmp = 0;
|
|
if (exceptions & FM_EX_KG_DOUBLE_ECC)
|
|
tmp |= FM_EX_KG_DOUBLE_ECC;
|
|
|
|
if (exceptions & FM_EX_KG_KEYSIZE_OVERFLOW)
|
|
tmp |= FM_EX_KG_KEYSIZE_OVERFLOW;
|
|
|
|
iowrite32be(tmp, ®s->fmkg_eeer);
|
|
iowrite32be(0, ®s->fmkg_fdor);
|
|
iowrite32be(0, ®s->fmkg_gdv0r);
|
|
iowrite32be(0, ®s->fmkg_gdv1r);
|
|
iowrite32be(dflt_nia, ®s->fmkg_gcr);
|
|
|
|
/* Clear binding between ports to schemes and classification plans
|
|
* so that all ports are not bound to any scheme/classification plan */
|
|
for (i = 0; i < FMAN_MAX_NUM_OF_HW_PORTS; i++) {
|
|
clear_pe_all_scheme(regs, (uint8_t)i);
|
|
clear_pe_all_cls_plan(regs, (uint8_t)i);
|
|
}
|
|
}
|
|
|
|
void fman_kg_enable_scheme_interrupts(struct fman_kg_regs *regs)
|
|
{
|
|
/* enable and enable all scheme interrupts */
|
|
iowrite32be(0xFFFFFFFF, ®s->fmkg_seer);
|
|
iowrite32be(0xFFFFFFFF, ®s->fmkg_seeer);
|
|
}
|
|
|
|
void fman_kg_enable(struct fman_kg_regs *regs)
|
|
{
|
|
iowrite32be(ioread32be(®s->fmkg_gcr) | FM_KG_KGGCR_EN,
|
|
®s->fmkg_gcr);
|
|
}
|
|
|
|
void fman_kg_disable(struct fman_kg_regs *regs)
|
|
{
|
|
iowrite32be(ioread32be(®s->fmkg_gcr) & ~FM_KG_KGGCR_EN,
|
|
®s->fmkg_gcr);
|
|
}
|
|
|
|
void fman_kg_set_data_after_prs(struct fman_kg_regs *regs, uint8_t offset)
|
|
{
|
|
iowrite32be(offset, ®s->fmkg_fdor);
|
|
}
|
|
|
|
void fman_kg_set_dflt_val(struct fman_kg_regs *regs,
|
|
uint8_t def_id,
|
|
uint32_t val)
|
|
{
|
|
if(def_id == 0)
|
|
iowrite32be(val, ®s->fmkg_gdv0r);
|
|
else
|
|
iowrite32be(val, ®s->fmkg_gdv1r);
|
|
}
|
|
|
|
|
|
void fman_kg_set_exception(struct fman_kg_regs *regs,
|
|
uint32_t exception,
|
|
bool enable)
|
|
{
|
|
uint32_t tmp;
|
|
|
|
tmp = ioread32be(®s->fmkg_eeer);
|
|
|
|
if (enable) {
|
|
tmp |= exception;
|
|
} else {
|
|
tmp &= ~exception;
|
|
}
|
|
|
|
iowrite32be(tmp, ®s->fmkg_eeer);
|
|
}
|
|
|
|
void fman_kg_get_exception(struct fman_kg_regs *regs,
|
|
uint32_t *events,
|
|
uint32_t *scheme_ids,
|
|
bool clear)
|
|
{
|
|
uint32_t mask;
|
|
|
|
*events = ioread32be(®s->fmkg_eer);
|
|
mask = ioread32be(®s->fmkg_eeer);
|
|
*events &= mask;
|
|
|
|
*scheme_ids = 0;
|
|
|
|
if (*events & FM_EX_KG_KEYSIZE_OVERFLOW) {
|
|
*scheme_ids = ioread32be(®s->fmkg_seer);
|
|
mask = ioread32be(®s->fmkg_seeer);
|
|
*scheme_ids &= mask;
|
|
}
|
|
|
|
if (clear) {
|
|
iowrite32be(*scheme_ids, ®s->fmkg_seer);
|
|
iowrite32be(*events, ®s->fmkg_eer);
|
|
}
|
|
}
|
|
|
|
void fman_kg_get_capture(struct fman_kg_regs *regs,
|
|
struct fman_kg_ex_ecc_attr *ecc_attr,
|
|
bool clear)
|
|
{
|
|
uint32_t tmp;
|
|
|
|
tmp = ioread32be(®s->fmkg_serc);
|
|
|
|
if (tmp & KG_FMKG_SERC_CAP) {
|
|
/* Captured data is valid */
|
|
ecc_attr->valid = TRUE;
|
|
ecc_attr->double_ecc =
|
|
(bool)((tmp & KG_FMKG_SERC_CET) ? TRUE : FALSE);
|
|
ecc_attr->single_ecc_count =
|
|
(uint8_t)((tmp & KG_FMKG_SERC_CNT_MSK) >>
|
|
KG_FMKG_SERC_CNT_SHIFT);
|
|
ecc_attr->addr = (uint16_t)(tmp & KG_FMKG_SERC_ADDR_MSK);
|
|
|
|
if (clear)
|
|
iowrite32be(KG_FMKG_SERC_CAP, ®s->fmkg_serc);
|
|
} else {
|
|
/* No ECC error is captured */
|
|
ecc_attr->valid = FALSE;
|
|
}
|
|
}
|
|
|
|
int fman_kg_build_scheme(struct fman_kg_scheme_params *params,
|
|
struct fman_kg_scheme_regs *scheme_regs)
|
|
{
|
|
struct fman_kg_extract_params *extract_params;
|
|
struct fman_kg_gen_extract_params *gen_params;
|
|
uint32_t tmp_reg, i, select, mask, fqb;
|
|
uint8_t offset, shift, ht;
|
|
|
|
/* Zero out all registers so no need to care about unused ones */
|
|
memset(scheme_regs, 0, sizeof(struct fman_kg_scheme_regs));
|
|
|
|
/* Mode register */
|
|
tmp_reg = fm_kg_build_nia(params->next_engine,
|
|
params->next_engine_action);
|
|
if (tmp_reg == KG_NIA_INVALID) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (params->next_engine == E_FMAN_PCD_PLCR) {
|
|
tmp_reg |= FMAN_KG_SCH_MODE_NIA_PLCR;
|
|
}
|
|
else if (params->next_engine == E_FMAN_PCD_CC) {
|
|
tmp_reg |= (uint32_t)params->cc_params.base_offset <<
|
|
FMAN_KG_SCH_MODE_CCOBASE_SHIFT;
|
|
}
|
|
|
|
tmp_reg |= FMAN_KG_SCH_MODE_EN;
|
|
scheme_regs->kgse_mode = tmp_reg;
|
|
|
|
/* Match vector */
|
|
scheme_regs->kgse_mv = params->match_vector;
|
|
|
|
extract_params = ¶ms->extract_params;
|
|
|
|
/* Scheme default values registers */
|
|
scheme_regs->kgse_dv0 = extract_params->def_scheme_0;
|
|
scheme_regs->kgse_dv1 = extract_params->def_scheme_1;
|
|
|
|
/* Extract Known Fields Command register */
|
|
scheme_regs->kgse_ekfc = extract_params->known_fields;
|
|
|
|
/* Entry Extract Known Default Value register */
|
|
tmp_reg = 0;
|
|
tmp_reg |= extract_params->known_fields_def.mac_addr <<
|
|
FMAN_KG_SCH_DEF_MAC_ADDR_SHIFT;
|
|
tmp_reg |= extract_params->known_fields_def.vlan_tci <<
|
|
FMAN_KG_SCH_DEF_VLAN_TCI_SHIFT;
|
|
tmp_reg |= extract_params->known_fields_def.etype <<
|
|
FMAN_KG_SCH_DEF_ETYPE_SHIFT;
|
|
tmp_reg |= extract_params->known_fields_def.ppp_sid <<
|
|
FMAN_KG_SCH_DEF_PPP_SID_SHIFT;
|
|
tmp_reg |= extract_params->known_fields_def.ppp_pid <<
|
|
FMAN_KG_SCH_DEF_PPP_PID_SHIFT;
|
|
tmp_reg |= extract_params->known_fields_def.mpls <<
|
|
FMAN_KG_SCH_DEF_MPLS_SHIFT;
|
|
tmp_reg |= extract_params->known_fields_def.ip_addr <<
|
|
FMAN_KG_SCH_DEF_IP_ADDR_SHIFT;
|
|
tmp_reg |= extract_params->known_fields_def.ptype <<
|
|
FMAN_KG_SCH_DEF_PTYPE_SHIFT;
|
|
tmp_reg |= extract_params->known_fields_def.ip_tos_tc <<
|
|
FMAN_KG_SCH_DEF_IP_TOS_TC_SHIFT;
|
|
tmp_reg |= extract_params->known_fields_def.ipv6_fl <<
|
|
FMAN_KG_SCH_DEF_IPv6_FL_SHIFT;
|
|
tmp_reg |= extract_params->known_fields_def.ipsec_spi <<
|
|
FMAN_KG_SCH_DEF_IPSEC_SPI_SHIFT;
|
|
tmp_reg |= extract_params->known_fields_def.l4_port <<
|
|
FMAN_KG_SCH_DEF_L4_PORT_SHIFT;
|
|
tmp_reg |= extract_params->known_fields_def.tcp_flg <<
|
|
FMAN_KG_SCH_DEF_TCP_FLG_SHIFT;
|
|
|
|
scheme_regs->kgse_ekdv = tmp_reg;
|
|
|
|
/* Generic extract registers */
|
|
if (extract_params->gen_extract_num > FM_KG_NUM_OF_GENERIC_REGS) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
for (i = 0; i < extract_params->gen_extract_num; i++) {
|
|
gen_params = extract_params->gen_extract + i;
|
|
|
|
tmp_reg = FMAN_KG_SCH_GEN_VALID;
|
|
tmp_reg |= (uint32_t)gen_params->def_val <<
|
|
FMAN_KG_SCH_GEN_DEF_SHIFT;
|
|
|
|
if (gen_params->type == E_FMAN_KG_HASH_EXTRACT) {
|
|
if ((gen_params->extract > FMAN_KG_SCH_GEN_SIZE_MAX) ||
|
|
(gen_params->extract == 0)) {
|
|
return -EINVAL;
|
|
}
|
|
} else {
|
|
tmp_reg |= FMAN_KG_SCH_GEN_OR;
|
|
}
|
|
|
|
tmp_reg |= (uint32_t)gen_params->extract <<
|
|
FMAN_KG_SCH_GEN_SIZE_SHIFT;
|
|
tmp_reg |= (uint32_t)gen_params->mask <<
|
|
FMAN_KG_SCH_GEN_MASK_SHIFT;
|
|
|
|
offset = gen_params->offset;
|
|
ht = get_gen_ht_code(gen_params->src,
|
|
gen_params->no_validation,
|
|
&offset);
|
|
tmp_reg |= (uint32_t)ht << FMAN_KG_SCH_GEN_HT_SHIFT;
|
|
tmp_reg |= offset;
|
|
|
|
scheme_regs->kgse_gec[i] = tmp_reg;
|
|
}
|
|
|
|
/* Masks registers */
|
|
if (extract_params->masks_num > FM_KG_EXTRACT_MASKS_NUM) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
select = 0;
|
|
mask = 0;
|
|
fqb = 0;
|
|
for (i = 0; i < extract_params->masks_num; i++) {
|
|
/* MCSx fields */
|
|
KG_GET_MASK_SEL_SHIFT(shift, i);
|
|
if (extract_params->masks[i].is_known) {
|
|
/* Mask known field */
|
|
select |= extract_params->masks[i].field_or_gen_idx <<
|
|
shift;
|
|
} else {
|
|
/* Mask generic extract */
|
|
select |= (extract_params->masks[i].field_or_gen_idx +
|
|
FM_KG_MASK_SEL_GEN_BASE) << shift;
|
|
}
|
|
|
|
/* MOx fields - spread between se_bmch and se_fqb registers */
|
|
KG_GET_MASK_OFFSET_SHIFT(shift, i);
|
|
if (i < 2) {
|
|
select |= (uint32_t)extract_params->masks[i].offset <<
|
|
shift;
|
|
} else {
|
|
fqb |= (uint32_t)extract_params->masks[i].offset <<
|
|
shift;
|
|
}
|
|
|
|
/* BMx fields */
|
|
KG_GET_MASK_SHIFT(shift, i);
|
|
mask |= (uint32_t)extract_params->masks[i].mask << shift;
|
|
}
|
|
|
|
/* Finish with rest of BMx fileds -
|
|
* don't mask bits for unused masks by setting
|
|
* corresponding BMx field = 0xFF */
|
|
for (i = extract_params->masks_num; i < FM_KG_EXTRACT_MASKS_NUM; i++) {
|
|
KG_GET_MASK_SHIFT(shift, i);
|
|
mask |= 0xFF << shift;
|
|
}
|
|
|
|
scheme_regs->kgse_bmch = select;
|
|
scheme_regs->kgse_bmcl = mask;
|
|
|
|
/* Finish with FQB register initialization.
|
|
* Check fqid is 24-bit value. */
|
|
if (params->base_fqid & ~0x00FFFFFF) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
fqb |= params->base_fqid;
|
|
scheme_regs->kgse_fqb = fqb;
|
|
|
|
/* Hash Configuration register */
|
|
tmp_reg = 0;
|
|
if (params->hash_params.use_hash) {
|
|
/* Check hash mask is 24-bit value */
|
|
if (params->hash_params.mask & ~0x00FFFFFF) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* Hash function produces 64-bit value, 24 bits of that
|
|
* are used to generate fq_id and policer profile.
|
|
* Thus, maximal shift is 40 bits to allow 24 bits out of 64.
|
|
*/
|
|
if (params->hash_params.shift_r > FMAN_KG_SCH_HASH_HSHIFT_MAX) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
tmp_reg |= params->hash_params.mask;
|
|
tmp_reg |= (uint32_t)params->hash_params.shift_r <<
|
|
FMAN_KG_SCH_HASH_HSHIFT_SHIFT;
|
|
|
|
if (params->hash_params.sym) {
|
|
tmp_reg |= FMAN_KG_SCH_HASH_SYM;
|
|
}
|
|
|
|
}
|
|
|
|
if (params->bypass_fqid_gen) {
|
|
tmp_reg |= FMAN_KG_SCH_HASH_NO_FQID_GEN;
|
|
}
|
|
|
|
scheme_regs->kgse_hc = tmp_reg;
|
|
|
|
/* Policer Profile register */
|
|
if (params->policer_params.bypass_pp_gen) {
|
|
tmp_reg = 0;
|
|
} else {
|
|
/* Lower 8 bits of 24-bits extracted from hash result
|
|
* are used for policer profile generation.
|
|
* That leaves maximum shift value = 23. */
|
|
if (params->policer_params.shift > FMAN_KG_SCH_PP_SHIFT_MAX) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
tmp_reg = params->policer_params.base;
|
|
tmp_reg |= ((uint32_t)params->policer_params.shift <<
|
|
FMAN_KG_SCH_PP_SH_SHIFT) &
|
|
FMAN_KG_SCH_PP_SH_MASK;
|
|
tmp_reg |= ((uint32_t)params->policer_params.shift <<
|
|
FMAN_KG_SCH_PP_SL_SHIFT) &
|
|
FMAN_KG_SCH_PP_SL_MASK;
|
|
tmp_reg |= (uint32_t)params->policer_params.mask <<
|
|
FMAN_KG_SCH_PP_MASK_SHIFT;
|
|
}
|
|
|
|
scheme_regs->kgse_ppc = tmp_reg;
|
|
|
|
/* Coarse Classification Bit Select register */
|
|
if (params->next_engine == E_FMAN_PCD_CC) {
|
|
scheme_regs->kgse_ccbs = params->cc_params.qlcv_bits_sel;
|
|
}
|
|
|
|
/* Packets Counter register */
|
|
if (params->update_counter) {
|
|
scheme_regs->kgse_spc = params->counter_value;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int fman_kg_write_scheme(struct fman_kg_regs *regs,
|
|
uint8_t scheme_id,
|
|
uint8_t hwport_id,
|
|
struct fman_kg_scheme_regs *scheme_regs,
|
|
bool update_counter)
|
|
{
|
|
struct fman_kg_scheme_regs *kgse_regs;
|
|
uint32_t tmp_reg;
|
|
int err, i;
|
|
|
|
/* Write indirect scheme registers */
|
|
kgse_regs = (struct fman_kg_scheme_regs *)&(regs->fmkg_indirect[0]);
|
|
|
|
iowrite32be(scheme_regs->kgse_mode, &kgse_regs->kgse_mode);
|
|
iowrite32be(scheme_regs->kgse_ekfc, &kgse_regs->kgse_ekfc);
|
|
iowrite32be(scheme_regs->kgse_ekdv, &kgse_regs->kgse_ekdv);
|
|
iowrite32be(scheme_regs->kgse_bmch, &kgse_regs->kgse_bmch);
|
|
iowrite32be(scheme_regs->kgse_bmcl, &kgse_regs->kgse_bmcl);
|
|
iowrite32be(scheme_regs->kgse_fqb, &kgse_regs->kgse_fqb);
|
|
iowrite32be(scheme_regs->kgse_hc, &kgse_regs->kgse_hc);
|
|
iowrite32be(scheme_regs->kgse_ppc, &kgse_regs->kgse_ppc);
|
|
iowrite32be(scheme_regs->kgse_spc, &kgse_regs->kgse_spc);
|
|
iowrite32be(scheme_regs->kgse_dv0, &kgse_regs->kgse_dv0);
|
|
iowrite32be(scheme_regs->kgse_dv1, &kgse_regs->kgse_dv1);
|
|
iowrite32be(scheme_regs->kgse_ccbs, &kgse_regs->kgse_ccbs);
|
|
iowrite32be(scheme_regs->kgse_mv, &kgse_regs->kgse_mv);
|
|
|
|
for (i = 0 ; i < FM_KG_NUM_OF_GENERIC_REGS ; i++)
|
|
iowrite32be(scheme_regs->kgse_gec[i], &kgse_regs->kgse_gec[i]);
|
|
|
|
/* Write AR (Action register) */
|
|
tmp_reg = build_ar_scheme(scheme_id, hwport_id, update_counter, TRUE);
|
|
err = fman_kg_write_ar_wait(regs, tmp_reg);
|
|
return err;
|
|
}
|
|
|
|
int fman_kg_delete_scheme(struct fman_kg_regs *regs,
|
|
uint8_t scheme_id,
|
|
uint8_t hwport_id)
|
|
{
|
|
struct fman_kg_scheme_regs *kgse_regs;
|
|
uint32_t tmp_reg;
|
|
int err, i;
|
|
|
|
kgse_regs = (struct fman_kg_scheme_regs *)&(regs->fmkg_indirect[0]);
|
|
|
|
/* Clear all registers including enable bit in mode register */
|
|
for (i = 0; i < (sizeof(struct fman_kg_scheme_regs)) / 4; ++i) {
|
|
iowrite32be(0, ((uint32_t *)kgse_regs + i));
|
|
}
|
|
|
|
/* Write AR (Action register) */
|
|
tmp_reg = build_ar_scheme(scheme_id, hwport_id, FALSE, TRUE);
|
|
err = fman_kg_write_ar_wait(regs, tmp_reg);
|
|
return err;
|
|
}
|
|
|
|
int fman_kg_get_scheme_counter(struct fman_kg_regs *regs,
|
|
uint8_t scheme_id,
|
|
uint8_t hwport_id,
|
|
uint32_t *counter)
|
|
{
|
|
struct fman_kg_scheme_regs *kgse_regs;
|
|
uint32_t tmp_reg;
|
|
int err;
|
|
|
|
kgse_regs = (struct fman_kg_scheme_regs *)&(regs->fmkg_indirect[0]);
|
|
|
|
tmp_reg = build_ar_scheme(scheme_id, hwport_id, TRUE, FALSE);
|
|
err = fman_kg_write_ar_wait(regs, tmp_reg);
|
|
|
|
if (err != 0)
|
|
return err;
|
|
|
|
*counter = ioread32be(&kgse_regs->kgse_spc);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int fman_kg_set_scheme_counter(struct fman_kg_regs *regs,
|
|
uint8_t scheme_id,
|
|
uint8_t hwport_id,
|
|
uint32_t counter)
|
|
{
|
|
struct fman_kg_scheme_regs *kgse_regs;
|
|
uint32_t tmp_reg;
|
|
int err;
|
|
|
|
kgse_regs = (struct fman_kg_scheme_regs *)&(regs->fmkg_indirect[0]);
|
|
|
|
tmp_reg = build_ar_scheme(scheme_id, hwport_id, TRUE, FALSE);
|
|
|
|
err = fman_kg_write_ar_wait(regs, tmp_reg);
|
|
if (err != 0)
|
|
return err;
|
|
|
|
/* Keygen indirect access memory contains all scheme_id registers
|
|
* by now. Change only counter value. */
|
|
iowrite32be(counter, &kgse_regs->kgse_spc);
|
|
|
|
/* Write back scheme registers */
|
|
tmp_reg = build_ar_scheme(scheme_id, hwport_id, TRUE, TRUE);
|
|
err = fman_kg_write_ar_wait(regs, tmp_reg);
|
|
|
|
return err;
|
|
}
|
|
|
|
uint32_t fman_kg_get_schemes_total_counter(struct fman_kg_regs *regs)
|
|
{
|
|
return ioread32be(®s->fmkg_tpc);
|
|
}
|
|
|
|
int fman_kg_build_cls_plan(struct fman_kg_cls_plan_params *params,
|
|
struct fman_kg_cp_regs *cls_plan_regs)
|
|
{
|
|
uint8_t entries_set, entry_bit;
|
|
int i;
|
|
|
|
/* Zero out all group's register */
|
|
memset(cls_plan_regs, 0, sizeof(struct fman_kg_cp_regs));
|
|
|
|
/* Go over all classification entries in params->entries_mask and
|
|
* configure the corresponding cpe register */
|
|
entries_set = params->entries_mask;
|
|
for (i = 0; entries_set; i++) {
|
|
entry_bit = (uint8_t)(0x80 >> i);
|
|
if ((entry_bit & entries_set) == 0)
|
|
continue;
|
|
entries_set ^= entry_bit;
|
|
cls_plan_regs->kgcpe[i] = params->mask_vector[i];
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int fman_kg_write_cls_plan(struct fman_kg_regs *regs,
|
|
uint8_t grp_id,
|
|
uint8_t entries_mask,
|
|
uint8_t hwport_id,
|
|
struct fman_kg_cp_regs *cls_plan_regs)
|
|
{
|
|
struct fman_kg_cp_regs *kgcpe_regs;
|
|
uint32_t tmp_reg;
|
|
int i, err;
|
|
|
|
/* Check group index is valid and the group isn't empty */
|
|
if (grp_id >= FM_KG_CLS_PLAN_GRPS_NUM)
|
|
return -EINVAL;
|
|
|
|
/* Write indirect classification plan registers */
|
|
kgcpe_regs = (struct fman_kg_cp_regs *)&(regs->fmkg_indirect[0]);
|
|
|
|
for (i = 0; i < FM_KG_NUM_CLS_PLAN_ENTR; i++) {
|
|
iowrite32be(cls_plan_regs->kgcpe[i], &kgcpe_regs->kgcpe[i]);
|
|
}
|
|
|
|
tmp_reg = build_ar_cls_plan(grp_id, entries_mask, hwport_id, TRUE);
|
|
err = fman_kg_write_ar_wait(regs, tmp_reg);
|
|
return err;
|
|
}
|
|
|
|
int fman_kg_write_bind_schemes(struct fman_kg_regs *regs,
|
|
uint8_t hwport_id,
|
|
uint32_t schemes)
|
|
{
|
|
struct fman_kg_pe_regs *kg_pe_regs;
|
|
uint32_t tmp_reg;
|
|
int err;
|
|
|
|
kg_pe_regs = (struct fman_kg_pe_regs *)&(regs->fmkg_indirect[0]);
|
|
|
|
iowrite32be(schemes, &kg_pe_regs->fmkg_pe_sp);
|
|
|
|
tmp_reg = build_ar_bind_scheme(hwport_id, TRUE);
|
|
err = fman_kg_write_ar_wait(regs, tmp_reg);
|
|
return err;
|
|
}
|
|
|
|
int fman_kg_build_bind_cls_plans(uint8_t grp_base,
|
|
uint8_t grp_mask,
|
|
uint32_t *bind_cls_plans)
|
|
{
|
|
/* Check grp_base and grp_mask are 5-bits values */
|
|
if ((grp_base & ~0x0000001F) || (grp_mask & ~0x0000001F))
|
|
return -EINVAL;
|
|
|
|
*bind_cls_plans = (uint32_t) ((grp_mask << FMAN_KG_PE_CPP_MASK_SHIFT) | grp_base);
|
|
return 0;
|
|
}
|
|
|
|
|
|
int fman_kg_write_bind_cls_plans(struct fman_kg_regs *regs,
|
|
uint8_t hwport_id,
|
|
uint32_t bind_cls_plans)
|
|
{
|
|
struct fman_kg_pe_regs *kg_pe_regs;
|
|
uint32_t tmp_reg;
|
|
int err;
|
|
|
|
kg_pe_regs = (struct fman_kg_pe_regs *)&(regs->fmkg_indirect[0]);
|
|
|
|
iowrite32be(bind_cls_plans, &kg_pe_regs->fmkg_pe_cpp);
|
|
|
|
tmp_reg = build_ar_bind_cls_plan(hwport_id, TRUE);
|
|
err = fman_kg_write_ar_wait(regs, tmp_reg);
|
|
return err;
|
|
}
|