/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <npi_fflp.h>
#include <npi_mac.h>
#include <nxge_defs.h>
#include <nxge_flow.h>
#include <nxge_fflp.h>
#include <nxge_impl.h>
#include <nxge_fflp_hash.h>
#include <nxge_common.h>
/*
* Function prototypes
*/
static nxge_status_t nxge_fflp_vlan_tbl_clear_all(p_nxge_t);
static nxge_status_t nxge_fflp_tcam_invalidate_all(p_nxge_t);
static nxge_status_t nxge_fflp_tcam_init(p_nxge_t);
static nxge_status_t nxge_fflp_fcram_invalidate_all(p_nxge_t);
static nxge_status_t nxge_fflp_fcram_init(p_nxge_t);
static int nxge_flow_need_hash_lookup(p_nxge_t, flow_resource_t *);
static void nxge_fill_tcam_entry_tcp(p_nxge_t, flow_spec_t *, tcam_entry_t *);
static void nxge_fill_tcam_entry_udp(p_nxge_t, flow_spec_t *, tcam_entry_t *);
static void nxge_fill_tcam_entry_sctp(p_nxge_t, flow_spec_t *, tcam_entry_t *);
static void nxge_fill_tcam_entry_tcp_ipv6(p_nxge_t, flow_spec_t *,
tcam_entry_t *);
static void nxge_fill_tcam_entry_udp_ipv6(p_nxge_t, flow_spec_t *,
tcam_entry_t *);
static void nxge_fill_tcam_entry_sctp_ipv6(p_nxge_t, flow_spec_t *,
tcam_entry_t *);
static uint8_t nxge_get_rdc_offset(p_nxge_t, uint8_t, uint64_t);
static uint8_t nxge_get_rdc_group(p_nxge_t, uint8_t, uint64_t);
static uint16_t nxge_tcam_get_index(p_nxge_t, uint16_t);
static uint32_t nxge_tcam_cls_to_flow(uint32_t);
static uint8_t nxge_iptun_pkt_type_to_pid(uint8_t);
static npi_status_t nxge_set_iptun_usr_cls_reg(p_nxge_t, uint64_t,
iptun_cfg_t *);
static boolean_t nxge_is_iptun_cls_present(p_nxge_t, uint8_t, int *);
/*
* functions used outside this file
*/
nxge_status_t nxge_fflp_config_vlan_table(p_nxge_t, uint16_t);
nxge_status_t nxge_fflp_ip_class_config_all(p_nxge_t);
nxge_status_t nxge_add_flow(p_nxge_t, flow_resource_t *);
static nxge_status_t nxge_tcam_handle_ip_fragment(p_nxge_t);
nxge_status_t nxge_add_tcam_entry(p_nxge_t, flow_resource_t *);
nxge_status_t nxge_add_fcram_entry(p_nxge_t, flow_resource_t *);
nxge_status_t nxge_flow_get_hash(p_nxge_t, flow_resource_t *,
uint32_t *, uint16_t *);
int nxge_get_valid_tcam_cnt(p_nxge_t);
void nxge_get_tcam_entry_all(p_nxge_t, rx_class_cfg_t *);
void nxge_get_tcam_entry(p_nxge_t, flow_resource_t *);
void nxge_del_tcam_entry(p_nxge_t, uint32_t);
void nxge_add_iptun_class(p_nxge_t, iptun_cfg_t *, uint8_t *);
void nxge_cfg_iptun_hash(p_nxge_t, iptun_cfg_t *, uint8_t);
void nxge_del_iptun_class(p_nxge_t, uint8_t);
void nxge_get_iptun_class(p_nxge_t, iptun_cfg_t *, uint8_t);
void nxge_set_ip_cls_sym(p_nxge_t, uint8_t, uint8_t);
void nxge_get_ip_cls_sym(p_nxge_t, uint8_t, uint8_t *);
nxge_status_t
nxge_tcam_dump_entry(p_nxge_t nxgep, uint32_t location)
{
tcam_entry_t tcam_rdptr;
uint64_t asc_ram = 0;
npi_handle_t handle;
npi_status_t status;
handle = nxgep->npi_reg_handle;
bzero((char *)&tcam_rdptr, sizeof (struct tcam_entry));
status = npi_fflp_tcam_entry_read(handle, (tcam_location_t)location,
(struct tcam_entry *)&tcam_rdptr);
if (status & NPI_FAILURE) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
" nxge_tcam_dump_entry:"
" tcam read failed at location %d ", location));
return (NXGE_ERROR);
}
status = npi_fflp_tcam_asc_ram_entry_read(handle,
(tcam_location_t)location, &asc_ram);
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "location %x\n"
" key: %llx %llx %llx %llx \n"
" mask: %llx %llx %llx %llx \n"
" ASC RAM %llx \n", location,
tcam_rdptr.key0, tcam_rdptr.key1,
tcam_rdptr.key2, tcam_rdptr.key3,
tcam_rdptr.mask0, tcam_rdptr.mask1,
tcam_rdptr.mask2, tcam_rdptr.mask3, asc_ram));
return (NXGE_OK);
}
void
nxge_get_tcam(p_nxge_t nxgep, p_mblk_t mp)
{
uint32_t tcam_loc;
int *lptr;
int location;
uint32_t start_location = 0;
uint32_t stop_location = nxgep->classifier.tcam_size;
lptr = (int *)mp->b_rptr;
location = *lptr;
if ((location >= nxgep->classifier.tcam_size) || (location < -1)) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"nxge_tcam_dump: Invalid location %d \n", location));
return;
}
if (location == -1) {
start_location = 0;
stop_location = nxgep->classifier.tcam_size;
} else {
start_location = location;
stop_location = location + 1;
}
for (tcam_loc = start_location; tcam_loc < stop_location; tcam_loc++)
(void) nxge_tcam_dump_entry(nxgep, tcam_loc);
}
/*
* nxge_fflp_vlan_table_invalidate_all
* invalidates the vlan RDC table entries.
* INPUT
* nxge soft state data structure
* Return
* NXGE_OK
* NXGE_ERROR
*
*/
static nxge_status_t
nxge_fflp_vlan_tbl_clear_all(p_nxge_t nxgep)
{
vlan_id_t vlan_id;
npi_handle_t handle;
npi_status_t rs = NPI_SUCCESS;
vlan_id_t start = 0, stop = NXGE_MAX_VLANS;
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, "==> nxge_fflp_vlan_tbl_clear_all "));
handle = nxgep->npi_reg_handle;
for (vlan_id = start; vlan_id < stop; vlan_id++) {
rs = npi_fflp_cfg_vlan_table_clear(handle, vlan_id);
if (rs != NPI_SUCCESS) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"VLAN Table invalidate failed for vlan id %d ",
vlan_id));
return (NXGE_ERROR | rs);
}
}
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, "<== nxge_fflp_vlan_tbl_clear_all "));
return (NXGE_OK);
}
/*
* The following functions are used by other modules to init
* the fflp module.
* these functions are the basic API used to init
* the fflp modules (tcam, fcram etc ......)
*
* The TCAM search future would be disabled by default.
*/
static nxge_status_t
nxge_fflp_tcam_init(p_nxge_t nxgep)
{
uint8_t access_ratio;
tcam_class_t class;
npi_status_t rs = NPI_SUCCESS;
npi_handle_t handle;
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, "==> nxge_fflp_tcam_init"));
handle = nxgep->npi_reg_handle;
rs = npi_fflp_cfg_tcam_disable(handle);
if (rs != NPI_SUCCESS) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "failed TCAM Disable\n"));
return (NXGE_ERROR | rs);
}
access_ratio = nxgep->param_arr[param_tcam_access_ratio].value;
rs = npi_fflp_cfg_tcam_access(handle, access_ratio);
if (rs != NPI_SUCCESS) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"failed TCAM Access cfg\n"));
return (NXGE_ERROR | rs);
}
/* disable configurable classes */
/* disable the configurable ethernet classes; */
for (class = TCAM_CLASS_ETYPE_1;
class <= TCAM_CLASS_ETYPE_2; class++) {
rs = npi_fflp_cfg_enet_usr_cls_disable(handle, class);
if (rs != NPI_SUCCESS) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"TCAM USR Ether Class config failed."));
return (NXGE_ERROR | rs);
}
}
/* disable the configurable ip classes; */
for (class = TCAM_CLASS_IP_USER_4;
class <= TCAM_CLASS_IP_USER_7; class++) {
rs = npi_fflp_cfg_ip_usr_cls_disable(handle, class);
if (rs != NPI_SUCCESS) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"TCAM USR IP Class cnfg failed."));
return (NXGE_ERROR | rs);
}
}
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, "<== nxge_fflp_tcam_init"));
return (NXGE_OK);
}
/*
* nxge_fflp_tcam_invalidate_all
* invalidates all the tcam entries.
* INPUT
* nxge soft state data structure
* Return
* NXGE_OK
* NXGE_ERROR
*
*/
static nxge_status_t
nxge_fflp_tcam_invalidate_all(p_nxge_t nxgep)
{
uint16_t location;
npi_status_t rs = NPI_SUCCESS;
npi_handle_t handle;
uint16_t start = 0, stop = nxgep->classifier.tcam_size;
p_nxge_hw_list_t hw_p;
NXGE_DEBUG_MSG((nxgep, FFLP_CTL,
"==> nxge_fflp_tcam_invalidate_all"));
handle = nxgep->npi_reg_handle;
if ((hw_p = nxgep->nxge_hw_p) == NULL) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
" nxge_fflp_tcam_invalidate_all:"
" common hardware not set", nxgep->niu_type));
return (NXGE_ERROR);
}
MUTEX_ENTER(&hw_p->nxge_tcam_lock);
for (location = start; location < stop; location++) {
rs = npi_fflp_tcam_entry_invalidate(handle, location);
if (rs != NPI_SUCCESS) {
MUTEX_EXIT(&hw_p->nxge_tcam_lock);
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"TCAM invalidate failed at loc %d ", location));
return (NXGE_ERROR | rs);
}
}
MUTEX_EXIT(&hw_p->nxge_tcam_lock);
NXGE_DEBUG_MSG((nxgep, FFLP_CTL,
"<== nxge_fflp_tcam_invalidate_all"));
return (NXGE_OK);
}
/*
* nxge_fflp_fcram_entry_invalidate_all
* invalidates all the FCRAM entries.
* INPUT
* nxge soft state data structure
* Return
* NXGE_OK
* NXGE_ERROR
*
*/
static nxge_status_t
nxge_fflp_fcram_invalidate_all(p_nxge_t nxgep)
{
npi_handle_t handle;
npi_status_t rs = NPI_SUCCESS;
part_id_t pid = 0;
uint8_t base_mask, base_reloc;
fcram_entry_t fc;
uint32_t location;
uint32_t increment, last_location;
/*
* (1) configure and enable partition 0 with no relocation
* (2) Assume the FCRAM is used as IPv4 exact match entry cells
* (3) Invalidate these cells by clearing the valid bit in
* the subareas 0 and 4
* (4) disable the partition
*
*/
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, "==> nxge_fflp_fcram_invalidate_all"));
base_mask = base_reloc = 0x0;
handle = nxgep->npi_reg_handle;
rs = npi_fflp_cfg_fcram_partition(handle, pid, base_mask, base_reloc);
if (rs != NPI_SUCCESS) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "failed partition cfg\n"));
return (NXGE_ERROR | rs);
}
rs = npi_fflp_cfg_fcram_partition_disable(handle, pid);
if (rs != NPI_SUCCESS) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"failed partition enable\n"));
return (NXGE_ERROR | rs);
}
fc.dreg[0].value = 0;
fc.hash_hdr_valid = 0;
fc.hash_hdr_ext = 1; /* specify as IPV4 exact match entry */
increment = sizeof (hash_ipv4_t);
last_location = FCRAM_SIZE * 0x40;
for (location = 0; location < last_location; location += increment) {
rs = npi_fflp_fcram_subarea_write(handle, pid,
location, fc.value[0]);
if (rs != NPI_SUCCESS) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"failed write at location %x ", location));
return (NXGE_ERROR | rs);
}
}
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, "<== nxge_fflp_fcram_invalidate_all"));
return (NXGE_OK);
}
static nxge_status_t
nxge_fflp_fcram_init(p_nxge_t nxgep)
{
fflp_fcram_output_drive_t strength;
fflp_fcram_qs_t qs;
npi_status_t rs = NPI_SUCCESS;
uint8_t access_ratio;
int partition;
npi_handle_t handle;
uint32_t min_time, max_time, sys_time;
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, "==> nxge_fflp_fcram_init"));
/*
* Recommended values are needed.
*/
min_time = FCRAM_REFRESH_DEFAULT_MIN_TIME;
max_time = FCRAM_REFRESH_DEFAULT_MAX_TIME;
sys_time = FCRAM_REFRESH_DEFAULT_SYS_TIME;
handle = nxgep->npi_reg_handle;
strength = FCRAM_OUTDR_NORMAL;
qs = FCRAM_QS_MODE_QS;
rs = npi_fflp_cfg_fcram_reset(handle, strength, qs);
if (rs != NPI_SUCCESS) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "failed FCRAM Reset. "));
return (NXGE_ERROR | rs);
}
access_ratio = nxgep->param_arr[param_fcram_access_ratio].value;
rs = npi_fflp_cfg_fcram_access(handle, access_ratio);
if (rs != NPI_SUCCESS) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "failed FCRAM Access ratio"
"configuration \n"));
return (NXGE_ERROR | rs);
}
rs = npi_fflp_cfg_fcram_refresh_time(handle, min_time,
max_time, sys_time);
if (rs != NPI_SUCCESS) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"failed FCRAM refresh cfg"));
return (NXGE_ERROR);
}
/* disable all the partitions until explicitly enabled */
for (partition = 0; partition < FFLP_FCRAM_MAX_PARTITION; partition++) {
rs = npi_fflp_cfg_fcram_partition_disable(handle, partition);
if (rs != NPI_SUCCESS) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"failed FCRAM partition"
" enable for partition %d ", partition));
return (NXGE_ERROR | rs);
}
}
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, "<== nxge_fflp_fcram_init"));
return (NXGE_OK);
}
nxge_status_t
nxge_logical_mac_assign_rdc_table(p_nxge_t nxgep, uint8_t alt_mac)
{
npi_status_t rs = NPI_SUCCESS;
hostinfo_t mac_rdc;
npi_handle_t handle;
p_nxge_class_pt_cfg_t p_class_cfgp;
p_class_cfgp = (p_nxge_class_pt_cfg_t)&nxgep->class_config;
if (p_class_cfgp->mac_host_info[alt_mac].flag == 0) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
" nxge_logical_mac_assign_rdc_table"
" unconfigured alt MAC addr %d ", alt_mac));
return (NXGE_ERROR);
}
handle = nxgep->npi_reg_handle;
mac_rdc.value = 0;
mac_rdc.bits.w0.rdc_tbl_num =
p_class_cfgp->mac_host_info[alt_mac].rdctbl;
mac_rdc.bits.w0.mac_pref = p_class_cfgp->mac_host_info[alt_mac].mpr_npr;
rs = npi_mac_hostinfo_entry(handle, OP_SET,
nxgep->function_num, alt_mac, &mac_rdc);
if (rs != NPI_SUCCESS) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"failed Assign RDC table"));
return (NXGE_ERROR | rs);
}
return (NXGE_OK);
}
nxge_status_t
nxge_main_mac_assign_rdc_table(p_nxge_t nxgep)
{
npi_status_t rs = NPI_SUCCESS;
hostinfo_t mac_rdc;
npi_handle_t handle;
int i;
handle = nxgep->npi_reg_handle;
mac_rdc.value = 0;
mac_rdc.bits.w0.rdc_tbl_num = nxgep->class_config.mac_rdcgrp;
mac_rdc.bits.w0.mac_pref = 1;
switch (nxgep->function_num) {
case 0:
case 1:
/*
* Tests indicate that it is OK not to re-initialize the
* hostinfo registers for the XMAC's alternate MAC
* addresses. But that is necessary for BMAC (case 2
* and case 3 below)
*/
rs = npi_mac_hostinfo_entry(handle, OP_SET,
nxgep->function_num, XMAC_UNIQUE_HOST_INFO_ENTRY, &mac_rdc);
break;
case 2:
case 3:
rs = npi_mac_hostinfo_entry(handle, OP_SET,
nxgep->function_num, BMAC_UNIQUE_HOST_INFO_ENTRY, &mac_rdc);
for (i = 1; i <= BMAC_MAX_ALT_ADDR_ENTRY; i++)
rs |= npi_mac_hostinfo_entry(handle, OP_SET,
nxgep->function_num, i, &mac_rdc);
break;
default:
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"failed Assign RDC table (invalid function #)"));
return (NXGE_ERROR);
}
if (rs != NPI_SUCCESS) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"failed Assign RDC table"));
return (NXGE_ERROR | rs);
}
return (NXGE_OK);
}
/*
* Initialize hostinfo registers for alternate MAC addresses and
* multicast MAC address.
*/
nxge_status_t
nxge_alt_mcast_mac_assign_rdc_table(p_nxge_t nxgep)
{
npi_status_t rs = NPI_SUCCESS;
hostinfo_t mac_rdc;
npi_handle_t handle;
handle = nxgep->npi_reg_handle;
mac_rdc.value = 0;
mac_rdc.bits.w0.rdc_tbl_num = nxgep->class_config.mcast_rdcgrp;
mac_rdc.bits.w0.mac_pref = 1;
switch (nxgep->function_num) {
case 0:
case 1:
rs = npi_mac_hostinfo_entry(handle, OP_SET,
nxgep->function_num, XMAC_MULTI_HOST_INFO_ENTRY, &mac_rdc);
break;
case 2:
case 3:
rs = npi_mac_hostinfo_entry(handle, OP_SET,
nxgep->function_num, BMAC_MULTI_HOST_INFO_ENTRY, &mac_rdc);
break;
default:
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"failed Assign RDC table (invalid function #)"));
return (NXGE_ERROR);
}
if (rs != NPI_SUCCESS) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"failed Assign RDC table"));
return (NXGE_ERROR | rs);
}
return (NXGE_OK);
}
nxge_status_t
nxge_fflp_init_hostinfo(p_nxge_t nxgep)
{
nxge_status_t status = NXGE_OK;
status = nxge_alt_mcast_mac_assign_rdc_table(nxgep);
status |= nxge_main_mac_assign_rdc_table(nxgep);
return (status);
}
nxge_status_t
nxge_fflp_hw_reset(p_nxge_t nxgep)
{
npi_handle_t handle;
npi_status_t rs = NPI_SUCCESS;
nxge_status_t status = NXGE_OK;
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, " ==> nxge_fflp_hw_reset"));
if (NXGE_IS_VALID_NEPTUNE_TYPE(nxgep)) {
status = nxge_fflp_fcram_init(nxgep);
if (status != NXGE_OK) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
" failed FCRAM init. "));
return (status);
}
}
status = nxge_fflp_tcam_init(nxgep);
if (status != NXGE_OK) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"failed TCAM init."));
return (status);
}
handle = nxgep->npi_reg_handle;
rs = npi_fflp_cfg_llcsnap_enable(handle);
if (rs != NPI_SUCCESS) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"failed LLCSNAP enable. "));
return (NXGE_ERROR | rs);
}
rs = npi_fflp_cfg_cam_errorcheck_disable(handle);
if (rs != NPI_SUCCESS) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"failed CAM Error Check enable. "));
return (NXGE_ERROR | rs);
}
/* init the hash generators */
rs = npi_fflp_cfg_hash_h1poly(handle, 0);
if (rs != NPI_SUCCESS) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"failed H1 Poly Init. "));
return (NXGE_ERROR | rs);
}
rs = npi_fflp_cfg_hash_h2poly(handle, 0);
if (rs != NPI_SUCCESS) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"failed H2 Poly Init. "));
return (NXGE_ERROR | rs);
}
/* invalidate TCAM entries */
status = nxge_fflp_tcam_invalidate_all(nxgep);
if (status != NXGE_OK) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"failed TCAM Entry Invalidate. "));
return (status);
}
/* invalidate FCRAM entries */
if (NXGE_IS_VALID_NEPTUNE_TYPE(nxgep)) {
status = nxge_fflp_fcram_invalidate_all(nxgep);
if (status != NXGE_OK) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"failed FCRAM Entry Invalidate."));
return (status);
}
}
/* invalidate VLAN RDC tables */
status = nxge_fflp_vlan_tbl_clear_all(nxgep);
if (status != NXGE_OK) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"failed VLAN Table Invalidate. "));
return (status);
}
nxgep->classifier.state |= NXGE_FFLP_HW_RESET;
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, "<== nxge_fflp_hw_reset"));
return (NXGE_OK);
}
nxge_status_t
nxge_cfg_ip_cls_flow_key(p_nxge_t nxgep, tcam_class_t l3_class,
uint32_t class_config)
{
flow_key_cfg_t fcfg;
npi_handle_t handle;
npi_status_t rs = NPI_SUCCESS;
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, " ==> nxge_cfg_ip_cls_flow_key"));
handle = nxgep->npi_reg_handle;
bzero(&fcfg, sizeof (flow_key_cfg_t));
if (class_config & NXGE_CLASS_FLOW_USE_PROTO)
fcfg.use_proto = 1;
if (class_config & NXGE_CLASS_FLOW_USE_DST_PORT)
fcfg.use_dport = 1;
if (class_config & NXGE_CLASS_FLOW_USE_SRC_PORT)
fcfg.use_sport = 1;
if (class_config & NXGE_CLASS_FLOW_USE_IPDST)
fcfg.use_daddr = 1;
if (class_config & NXGE_CLASS_FLOW_USE_IPSRC)
fcfg.use_saddr = 1;
if (class_config & NXGE_CLASS_FLOW_USE_VLAN)
fcfg.use_vlan = 1;
if (class_config & NXGE_CLASS_FLOW_USE_L2DA)
fcfg.use_l2da = 1;
if (class_config & NXGE_CLASS_FLOW_USE_PORTNUM)
fcfg.use_portnum = 1;
fcfg.ip_opts_exist = 0;
rs = npi_fflp_cfg_ip_cls_flow_key(handle, l3_class, &fcfg);
if (rs & NPI_FFLP_ERROR) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, " nxge_cfg_ip_cls_flow_key"
" opt %x for class %d failed ", class_config, l3_class));
return (NXGE_ERROR | rs);
}
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, " <== nxge_cfg_ip_cls_flow_key"));
return (NXGE_OK);
}
nxge_status_t
nxge_cfg_ip_cls_flow_key_get(p_nxge_t nxgep, tcam_class_t l3_class,
uint32_t *class_config)
{
flow_key_cfg_t fcfg;
npi_handle_t handle;
npi_status_t rs = NPI_SUCCESS;
uint32_t ccfg = 0;
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, " ==> nxge_cfg_ip_cls_flow_key_get"));
handle = nxgep->npi_reg_handle;
bzero(&fcfg, sizeof (flow_key_cfg_t));
rs = npi_fflp_cfg_ip_cls_flow_key_get(handle, l3_class, &fcfg);
if (rs & NPI_FFLP_ERROR) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, " nxge_cfg_ip_cls_flow_key"
" opt %x for class %d failed ", class_config, l3_class));
return (NXGE_ERROR | rs);
}
if (fcfg.use_proto)
ccfg |= NXGE_CLASS_FLOW_USE_PROTO;
if (fcfg.use_dport)
ccfg |= NXGE_CLASS_FLOW_USE_DST_PORT;
if (fcfg.use_sport)
ccfg |= NXGE_CLASS_FLOW_USE_SRC_PORT;
if (fcfg.use_daddr)
ccfg |= NXGE_CLASS_FLOW_USE_IPDST;
if (fcfg.use_saddr)
ccfg |= NXGE_CLASS_FLOW_USE_IPSRC;
if (fcfg.use_vlan)
ccfg |= NXGE_CLASS_FLOW_USE_VLAN;
if (fcfg.use_l2da)
ccfg |= NXGE_CLASS_FLOW_USE_L2DA;
if (fcfg.use_portnum)
ccfg |= NXGE_CLASS_FLOW_USE_PORTNUM;
NXGE_DEBUG_MSG((nxgep, FFLP_CTL,
" nxge_cfg_ip_cls_flow_key_get %x", ccfg));
*class_config = ccfg;
NXGE_DEBUG_MSG((nxgep, FFLP_CTL,
" <== nxge_cfg_ip_cls_flow_key_get"));
return (NXGE_OK);
}
static nxge_status_t
nxge_cfg_tcam_ip_class_get(p_nxge_t nxgep, tcam_class_t class,
uint32_t *class_config)
{
npi_status_t rs = NPI_SUCCESS;
tcam_key_cfg_t cfg;
npi_handle_t handle;
uint32_t ccfg = 0;
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, "==> nxge_cfg_tcam_ip_class"));
bzero(&cfg, sizeof (tcam_key_cfg_t));
handle = nxgep->npi_reg_handle;
rs = npi_fflp_cfg_ip_cls_tcam_key_get(handle, class, &cfg);
if (rs & NPI_FFLP_ERROR) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, " nxge_cfg_tcam_ip_class"
" opt %x for class %d failed ", class_config, class));
return (NXGE_ERROR | rs);
}
if (cfg.discard)
ccfg |= NXGE_CLASS_DISCARD;
if (cfg.lookup_enable)
ccfg |= NXGE_CLASS_TCAM_LOOKUP;
if (cfg.use_ip_daddr)
ccfg |= NXGE_CLASS_TCAM_USE_SRC_ADDR;
*class_config = ccfg;
NXGE_DEBUG_MSG((nxgep, FFLP_CTL,
" ==> nxge_cfg_tcam_ip_class %x", ccfg));
return (NXGE_OK);
}
static nxge_status_t
nxge_cfg_tcam_ip_class(p_nxge_t nxgep, tcam_class_t class,
uint32_t class_config)
{
npi_status_t rs = NPI_SUCCESS;
tcam_key_cfg_t cfg;
npi_handle_t handle;
p_nxge_class_pt_cfg_t p_class_cfgp;
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, "==> nxge_cfg_tcam_ip_class"));
p_class_cfgp = (p_nxge_class_pt_cfg_t)&nxgep->class_config;
p_class_cfgp->class_cfg[class] = class_config;
bzero(&cfg, sizeof (tcam_key_cfg_t));
handle = nxgep->npi_reg_handle;
cfg.discard = 0;
cfg.lookup_enable = 0;
cfg.use_ip_daddr = 0;
if (class_config & NXGE_CLASS_DISCARD)
cfg.discard = 1;
if (class_config & NXGE_CLASS_TCAM_LOOKUP)
cfg.lookup_enable = 1;
if (class_config & NXGE_CLASS_TCAM_USE_SRC_ADDR)
cfg.use_ip_daddr = 1;
rs = npi_fflp_cfg_ip_cls_tcam_key(handle, class, &cfg);
if (rs & NPI_FFLP_ERROR) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, " nxge_cfg_tcam_ip_class"
" opt %x for class %d failed ", class_config, class));
return (NXGE_ERROR | rs);
}
return (NXGE_OK);
}
nxge_status_t
nxge_fflp_set_hash1(p_nxge_t nxgep, uint32_t h1)
{
npi_status_t rs = NPI_SUCCESS;
npi_handle_t handle;
p_nxge_class_pt_cfg_t p_class_cfgp;
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, " ==> nxge_fflp_init_h1"));
p_class_cfgp = (p_nxge_class_pt_cfg_t)&nxgep->class_config;
p_class_cfgp->init_h1 = h1;
handle = nxgep->npi_reg_handle;
rs = npi_fflp_cfg_hash_h1poly(handle, h1);
if (rs & NPI_FFLP_ERROR) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
" nxge_fflp_init_h1 %x failed ", h1));
return (NXGE_ERROR | rs);
}
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, " <== nxge_fflp_init_h1"));
return (NXGE_OK);
}
nxge_status_t
nxge_fflp_set_hash2(p_nxge_t nxgep, uint16_t h2)
{
npi_status_t rs = NPI_SUCCESS;
npi_handle_t handle;
p_nxge_class_pt_cfg_t p_class_cfgp;
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, " ==> nxge_fflp_init_h2"));
p_class_cfgp = (p_nxge_class_pt_cfg_t)&nxgep->class_config;
p_class_cfgp->init_h2 = h2;
handle = nxgep->npi_reg_handle;
rs = npi_fflp_cfg_hash_h2poly(handle, h2);
if (rs & NPI_FFLP_ERROR) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
" nxge_fflp_init_h2 %x failed ", h2));
return (NXGE_ERROR | rs);
}
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, " <== nxge_fflp_init_h2"));
return (NXGE_OK);
}
nxge_status_t
nxge_classify_init_sw(p_nxge_t nxgep)
{
nxge_classify_t *classify_ptr;
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, "==> nxge_classify_init_sw"));
classify_ptr = &nxgep->classifier;
if (classify_ptr->state & NXGE_FFLP_SW_INIT) {
NXGE_DEBUG_MSG((nxgep, FFLP_CTL,
"nxge_classify_init_sw already init"));
return (NXGE_OK);
}
classify_ptr->tcam_size = nxgep->nxge_hw_p->tcam_size / nxgep->nports;
classify_ptr->tcam_entries = (tcam_flow_spec_t *)nxgep->nxge_hw_p->tcam;
classify_ptr->tcam_top = nxgep->function_num;
/* Init defaults */
/*
* add hacks required for HW shortcomings for example, code to handle
* fragmented packets
*/
nxge_init_h1_table();
nxge_crc_ccitt_init();
nxgep->classifier.tcam_location = nxgep->function_num;
nxgep->classifier.fragment_bug = 1;
classify_ptr->state |= NXGE_FFLP_SW_INIT;
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, "<== nxge_classify_init_sw"));
return (NXGE_OK);
}
nxge_status_t
nxge_classify_exit_sw(p_nxge_t nxgep)
{
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, "==> nxge_classify_exit_sw"));
nxgep->classifier.state = NULL;
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, "<== nxge_classify_exit_sw"));
return (NXGE_OK);
}
/*
* Figures out the RDC Group for the entry
*
* The current implementation is just a place holder and it
* returns 0.
* The real location determining algorithm would consider
* the partition etc ... before deciding w
*
*/
/* ARGSUSED */
static uint8_t
nxge_get_rdc_group(p_nxge_t nxgep, uint8_t class, uint64_t cookie)
{
int use_port_rdc_grp = 0;
uint8_t rdc_grp = 0;
p_nxge_dma_pt_cfg_t p_dma_cfgp;
p_nxge_hw_pt_cfg_t p_cfgp;
p_nxge_rdc_grp_t rdc_grp_p;
p_dma_cfgp = (p_nxge_dma_pt_cfg_t)&nxgep->pt_config;
p_cfgp = (p_nxge_hw_pt_cfg_t)&p_dma_cfgp->hw_config;
rdc_grp_p = &p_dma_cfgp->rdc_grps[use_port_rdc_grp];
rdc_grp = p_cfgp->def_mac_rxdma_grpid;
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"nxge_get_rdc_group: grp 0x%x real_grp %x grpp $%p\n",
cookie, rdc_grp, rdc_grp_p));
return (rdc_grp);
}
/* ARGSUSED */
static uint8_t
nxge_get_rdc_offset(p_nxge_t nxgep, uint8_t class, uint64_t cookie)
{
return ((uint8_t)cookie);
}
/* ARGSUSED */
static void
nxge_fill_tcam_entry_udp(p_nxge_t nxgep, flow_spec_t *flow_spec,
tcam_entry_t *tcam_ptr)
{
udpip4_spec_t *fspec_key;
udpip4_spec_t *fspec_mask;
fspec_key = (udpip4_spec_t *)&flow_spec->uh.udpip4spec;
fspec_mask = (udpip4_spec_t *)&flow_spec->um.udpip4spec;
TCAM_IPV4_ADDR(tcam_ptr->ip4_dest_key, fspec_key->ip4dst);
TCAM_IPV4_ADDR(tcam_ptr->ip4_dest_mask, fspec_mask->ip4dst);
TCAM_IPV4_ADDR(tcam_ptr->ip4_src_key, fspec_key->ip4src);
TCAM_IPV4_ADDR(tcam_ptr->ip4_src_mask, fspec_mask->ip4src);
TCAM_IP_PORTS(tcam_ptr->ip4_port_key,
fspec_key->pdst, fspec_key->psrc);
TCAM_IP_PORTS(tcam_ptr->ip4_port_mask,
fspec_mask->pdst, fspec_mask->psrc);
TCAM_IP_CLASS(tcam_ptr->ip4_class_key,
tcam_ptr->ip4_class_mask,
TCAM_CLASS_UDP_IPV4);
TCAM_IP_PROTO(tcam_ptr->ip4_proto_key,
tcam_ptr->ip4_proto_mask,
IPPROTO_UDP);
tcam_ptr->ip4_tos_key = fspec_key->tos;
tcam_ptr->ip4_tos_mask = fspec_mask->tos;
}
static void
nxge_fill_tcam_entry_udp_ipv6(p_nxge_t nxgep, flow_spec_t *flow_spec,
tcam_entry_t *tcam_ptr)
{
udpip6_spec_t *fspec_key;
udpip6_spec_t *fspec_mask;
p_nxge_class_pt_cfg_t p_class_cfgp;
fspec_key = (udpip6_spec_t *)&flow_spec->uh.udpip6spec;
fspec_mask = (udpip6_spec_t *)&flow_spec->um.udpip6spec;
p_class_cfgp = (p_nxge_class_pt_cfg_t)&nxgep->class_config;
if (p_class_cfgp->class_cfg[TCAM_CLASS_UDP_IPV6] &
NXGE_CLASS_TCAM_USE_SRC_ADDR) {
TCAM_IPV6_ADDR(tcam_ptr->ip6_ip_addr_key, fspec_key->ip6src);
TCAM_IPV6_ADDR(tcam_ptr->ip6_ip_addr_mask, fspec_mask->ip6src);
} else {
TCAM_IPV6_ADDR(tcam_ptr->ip6_ip_addr_key, fspec_key->ip6dst);
TCAM_IPV6_ADDR(tcam_ptr->ip6_ip_addr_mask, fspec_mask->ip6dst);
}
TCAM_IP_CLASS(tcam_ptr->ip6_class_key,
tcam_ptr->ip6_class_mask, TCAM_CLASS_UDP_IPV6);
TCAM_IP_PROTO(tcam_ptr->ip6_nxt_hdr_key,
tcam_ptr->ip6_nxt_hdr_mask, IPPROTO_UDP);
TCAM_IP_PORTS(tcam_ptr->ip6_port_key,
fspec_key->pdst, fspec_key->psrc);
TCAM_IP_PORTS(tcam_ptr->ip6_port_mask,
fspec_mask->pdst, fspec_mask->psrc);
tcam_ptr->ip6_tos_key = fspec_key->tos;
tcam_ptr->ip6_tos_mask = fspec_mask->tos;
}
/* ARGSUSED */
static void
nxge_fill_tcam_entry_tcp(p_nxge_t nxgep, flow_spec_t *flow_spec,
tcam_entry_t *tcam_ptr)
{
tcpip4_spec_t *fspec_key;
tcpip4_spec_t *fspec_mask;
fspec_key = (tcpip4_spec_t *)&flow_spec->uh.tcpip4spec;
fspec_mask = (tcpip4_spec_t *)&flow_spec->um.tcpip4spec;
TCAM_IPV4_ADDR(tcam_ptr->ip4_dest_key, fspec_key->ip4dst);
TCAM_IPV4_ADDR(tcam_ptr->ip4_dest_mask, fspec_mask->ip4dst);
TCAM_IPV4_ADDR(tcam_ptr->ip4_src_key, fspec_key->ip4src);
TCAM_IPV4_ADDR(tcam_ptr->ip4_src_mask, fspec_mask->ip4src);
TCAM_IP_PORTS(tcam_ptr->ip4_port_key,
fspec_key->pdst, fspec_key->psrc);
TCAM_IP_PORTS(tcam_ptr->ip4_port_mask,
fspec_mask->pdst, fspec_mask->psrc);
TCAM_IP_CLASS(tcam_ptr->ip4_class_key,
tcam_ptr->ip4_class_mask, TCAM_CLASS_TCP_IPV4);
TCAM_IP_PROTO(tcam_ptr->ip4_proto_key,
tcam_ptr->ip4_proto_mask, IPPROTO_TCP);
tcam_ptr->ip4_tos_key = fspec_key->tos;
tcam_ptr->ip4_tos_mask = fspec_mask->tos;
}
/* ARGSUSED */
static void
nxge_fill_tcam_entry_sctp(p_nxge_t nxgep, flow_spec_t *flow_spec,
tcam_entry_t *tcam_ptr)
{
tcpip4_spec_t *fspec_key;
tcpip4_spec_t *fspec_mask;
fspec_key = (tcpip4_spec_t *)&flow_spec->uh.tcpip4spec;
fspec_mask = (tcpip4_spec_t *)&flow_spec->um.tcpip4spec;
TCAM_IPV4_ADDR(tcam_ptr->ip4_dest_key, fspec_key->ip4dst);
TCAM_IPV4_ADDR(tcam_ptr->ip4_dest_mask, fspec_mask->ip4dst);
TCAM_IPV4_ADDR(tcam_ptr->ip4_src_key, fspec_key->ip4src);
TCAM_IPV4_ADDR(tcam_ptr->ip4_src_mask, fspec_mask->ip4src);
TCAM_IP_CLASS(tcam_ptr->ip4_class_key,
tcam_ptr->ip4_class_mask, TCAM_CLASS_SCTP_IPV4);
TCAM_IP_PROTO(tcam_ptr->ip4_proto_key,
tcam_ptr->ip4_proto_mask, IPPROTO_SCTP);
TCAM_IP_PORTS(tcam_ptr->ip4_port_key,
fspec_key->pdst, fspec_key->psrc);
TCAM_IP_PORTS(tcam_ptr->ip4_port_mask,
fspec_mask->pdst, fspec_mask->psrc);
tcam_ptr->ip4_tos_key = fspec_key->tos;
tcam_ptr->ip4_tos_mask = fspec_mask->tos;
}
static void
nxge_fill_tcam_entry_tcp_ipv6(p_nxge_t nxgep, flow_spec_t *flow_spec,
tcam_entry_t *tcam_ptr)
{
tcpip6_spec_t *fspec_key;
tcpip6_spec_t *fspec_mask;
p_nxge_class_pt_cfg_t p_class_cfgp;
fspec_key = (tcpip6_spec_t *)&flow_spec->uh.tcpip6spec;
fspec_mask = (tcpip6_spec_t *)&flow_spec->um.tcpip6spec;
p_class_cfgp = (p_nxge_class_pt_cfg_t)&nxgep->class_config;
if (p_class_cfgp->class_cfg[TCAM_CLASS_UDP_IPV6] &
NXGE_CLASS_TCAM_USE_SRC_ADDR) {
TCAM_IPV6_ADDR(tcam_ptr->ip6_ip_addr_key, fspec_key->ip6src);
TCAM_IPV6_ADDR(tcam_ptr->ip6_ip_addr_mask, fspec_mask->ip6src);
} else {
TCAM_IPV6_ADDR(tcam_ptr->ip6_ip_addr_key, fspec_key->ip6dst);
TCAM_IPV6_ADDR(tcam_ptr->ip6_ip_addr_mask, fspec_mask->ip6dst);
}
TCAM_IP_CLASS(tcam_ptr->ip6_class_key,
tcam_ptr->ip6_class_mask, TCAM_CLASS_TCP_IPV6);
TCAM_IP_PROTO(tcam_ptr->ip6_nxt_hdr_key,
tcam_ptr->ip6_nxt_hdr_mask, IPPROTO_TCP);
TCAM_IP_PORTS(tcam_ptr->ip6_port_key,
fspec_key->pdst, fspec_key->psrc);
TCAM_IP_PORTS(tcam_ptr->ip6_port_mask,
fspec_mask->pdst, fspec_mask->psrc);
tcam_ptr->ip6_tos_key = fspec_key->tos;
tcam_ptr->ip6_tos_mask = fspec_mask->tos;
}
static void
nxge_fill_tcam_entry_sctp_ipv6(p_nxge_t nxgep, flow_spec_t *flow_spec,
tcam_entry_t *tcam_ptr)
{
tcpip6_spec_t *fspec_key;
tcpip6_spec_t *fspec_mask;
p_nxge_class_pt_cfg_t p_class_cfgp;
fspec_key = (tcpip6_spec_t *)&flow_spec->uh.tcpip6spec;
fspec_mask = (tcpip6_spec_t *)&flow_spec->um.tcpip6spec;
p_class_cfgp = (p_nxge_class_pt_cfg_t)&nxgep->class_config;
if (p_class_cfgp->class_cfg[TCAM_CLASS_UDP_IPV6] &
NXGE_CLASS_TCAM_USE_SRC_ADDR) {
TCAM_IPV6_ADDR(tcam_ptr->ip6_ip_addr_key, fspec_key->ip6src);
TCAM_IPV6_ADDR(tcam_ptr->ip6_ip_addr_mask, fspec_mask->ip6src);
} else {
TCAM_IPV6_ADDR(tcam_ptr->ip6_ip_addr_key, fspec_key->ip6dst);
TCAM_IPV6_ADDR(tcam_ptr->ip6_ip_addr_mask, fspec_mask->ip6dst);
}
TCAM_IP_CLASS(tcam_ptr->ip6_class_key,
tcam_ptr->ip6_class_mask, TCAM_CLASS_SCTP_IPV6);
TCAM_IP_PROTO(tcam_ptr->ip6_nxt_hdr_key,
tcam_ptr->ip6_nxt_hdr_mask, IPPROTO_SCTP);
TCAM_IP_PORTS(tcam_ptr->ip6_port_key,
fspec_key->pdst, fspec_key->psrc);
TCAM_IP_PORTS(tcam_ptr->ip6_port_mask,
fspec_mask->pdst, fspec_mask->psrc);
tcam_ptr->ip6_tos_key = fspec_key->tos;
tcam_ptr->ip6_tos_mask = fspec_mask->tos;
}
/* ARGSUSED */
static void
nxge_fill_tcam_entry_ah_esp(p_nxge_t nxgep, flow_spec_t *flow_spec,
tcam_entry_t *tcam_ptr)
{
ahip4_spec_t *fspec_key;
ahip4_spec_t *fspec_mask;
fspec_key = (ahip4_spec_t *)&flow_spec->uh.ahip4spec;
fspec_mask = (ahip4_spec_t *)&flow_spec->um.ahip4spec;
TCAM_IPV4_ADDR(tcam_ptr->ip4_dest_key, fspec_key->ip4dst);
TCAM_IPV4_ADDR(tcam_ptr->ip4_dest_mask, fspec_mask->ip4dst);
TCAM_IPV4_ADDR(tcam_ptr->ip4_src_key, fspec_key->ip4src);
TCAM_IPV4_ADDR(tcam_ptr->ip4_src_mask, fspec_mask->ip4src);
tcam_ptr->ip4_port_key = fspec_key->spi;
tcam_ptr->ip4_port_mask = fspec_mask->spi;
TCAM_IP_CLASS(tcam_ptr->ip4_class_key,
tcam_ptr->ip4_class_mask,
TCAM_CLASS_AH_ESP_IPV4);
if (flow_spec->flow_type == FSPEC_AHIP4) {
TCAM_IP_PROTO(tcam_ptr->ip4_proto_key,
tcam_ptr->ip4_proto_mask, IPPROTO_AH);
} else {
TCAM_IP_PROTO(tcam_ptr->ip4_proto_key,
tcam_ptr->ip4_proto_mask, IPPROTO_ESP);
}
tcam_ptr->ip4_tos_key = fspec_key->tos;
tcam_ptr->ip4_tos_mask = fspec_mask->tos;
}
static void
nxge_fill_tcam_entry_ah_esp_ipv6(p_nxge_t nxgep, flow_spec_t *flow_spec,
tcam_entry_t *tcam_ptr)
{
ahip6_spec_t *fspec_key;
ahip6_spec_t *fspec_mask;
p_nxge_class_pt_cfg_t p_class_cfgp;
fspec_key = (ahip6_spec_t *)&flow_spec->uh.ahip6spec;
fspec_mask = (ahip6_spec_t *)&flow_spec->um.ahip6spec;
p_class_cfgp = (p_nxge_class_pt_cfg_t)&nxgep->class_config;
if (p_class_cfgp->class_cfg[TCAM_CLASS_AH_ESP_IPV6] &
NXGE_CLASS_TCAM_USE_SRC_ADDR) {
TCAM_IPV6_ADDR(tcam_ptr->ip6_ip_addr_key, fspec_key->ip6src);
TCAM_IPV6_ADDR(tcam_ptr->ip6_ip_addr_mask, fspec_mask->ip6src);
} else {
TCAM_IPV6_ADDR(tcam_ptr->ip6_ip_addr_key, fspec_key->ip6dst);
TCAM_IPV6_ADDR(tcam_ptr->ip6_ip_addr_mask, fspec_mask->ip6dst);
}
TCAM_IP_CLASS(tcam_ptr->ip6_class_key,
tcam_ptr->ip6_class_mask, TCAM_CLASS_AH_ESP_IPV6);
if (flow_spec->flow_type == FSPEC_AHIP6) {
TCAM_IP_PROTO(tcam_ptr->ip6_nxt_hdr_key,
tcam_ptr->ip6_nxt_hdr_mask, IPPROTO_AH);
} else {
TCAM_IP_PROTO(tcam_ptr->ip6_nxt_hdr_key,
tcam_ptr->ip6_nxt_hdr_mask, IPPROTO_ESP);
}
tcam_ptr->ip6_port_key = fspec_key->spi;
tcam_ptr->ip6_port_mask = fspec_mask->spi;
tcam_ptr->ip6_tos_key = fspec_key->tos;
tcam_ptr->ip6_tos_mask = fspec_mask->tos;
}
/* ARGSUSED */
static void
nxge_fill_tcam_entry_ip_usr(p_nxge_t nxgep, flow_spec_t *flow_spec,
tcam_entry_t *tcam_ptr, tcam_class_t class)
{
ip_user_spec_t *fspec_key;
ip_user_spec_t *fspec_mask;
fspec_key = (ip_user_spec_t *)&flow_spec->uh.ip_usr_spec;
fspec_mask = (ip_user_spec_t *)&flow_spec->um.ip_usr_spec;
if (fspec_key->ip_ver == FSPEC_IP4) {
TCAM_IPV4_ADDR(tcam_ptr->ip4_dest_key, fspec_key->ip4dst);
TCAM_IPV4_ADDR(tcam_ptr->ip4_dest_mask, fspec_mask->ip4dst);
TCAM_IPV4_ADDR(tcam_ptr->ip4_src_key, fspec_key->ip4src);
TCAM_IPV4_ADDR(tcam_ptr->ip4_src_mask, fspec_mask->ip4src);
tcam_ptr->ip4_port_key = fspec_key->l4_4_bytes;
tcam_ptr->ip4_port_mask = fspec_mask->l4_4_bytes;
TCAM_IP_CLASS(tcam_ptr->ip4_class_key,
tcam_ptr->ip4_class_mask, class);
tcam_ptr->ip4_proto_key = fspec_key->proto;
tcam_ptr->ip4_proto_mask = fspec_mask->proto;
tcam_ptr->ip4_tos_key = fspec_key->tos;
tcam_ptr->ip4_tos_mask = fspec_mask->tos;
}
}
nxge_status_t
nxge_flow_get_hash(p_nxge_t nxgep, flow_resource_t *flow_res,
uint32_t *H1, uint16_t *H2)
{
flow_spec_t *flow_spec;
uint32_t class_cfg;
flow_template_t ft;
p_nxge_class_pt_cfg_t p_class_cfgp;
int ft_size = sizeof (flow_template_t);
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, "==> nxge_flow_get_hash"));
flow_spec = (flow_spec_t *)&flow_res->flow_spec;
bzero((char *)&ft, ft_size);
p_class_cfgp = (p_nxge_class_pt_cfg_t)&nxgep->class_config;
switch (flow_spec->flow_type) {
case FSPEC_TCPIP4:
class_cfg = p_class_cfgp->class_cfg[TCAM_CLASS_TCP_IPV4];
if (class_cfg & NXGE_CLASS_FLOW_USE_PROTO)
ft.ip_proto = IPPROTO_TCP;
if (class_cfg & NXGE_CLASS_FLOW_USE_IPSRC)
ft.ip4_saddr = flow_res->flow_spec.uh.tcpip4spec.ip4src;
if (class_cfg & NXGE_CLASS_FLOW_USE_IPDST)
ft.ip4_daddr = flow_res->flow_spec.uh.tcpip4spec.ip4dst;
if (class_cfg & NXGE_CLASS_FLOW_USE_SRC_PORT)
ft.ip_src_port = flow_res->flow_spec.uh.tcpip4spec.psrc;
if (class_cfg & NXGE_CLASS_FLOW_USE_DST_PORT)
ft.ip_dst_port = flow_res->flow_spec.uh.tcpip4spec.pdst;
break;
case FSPEC_UDPIP4:
class_cfg = p_class_cfgp->class_cfg[TCAM_CLASS_UDP_IPV4];
if (class_cfg & NXGE_CLASS_FLOW_USE_PROTO)
ft.ip_proto = IPPROTO_UDP;
if (class_cfg & NXGE_CLASS_FLOW_USE_IPSRC)
ft.ip4_saddr = flow_res->flow_spec.uh.udpip4spec.ip4src;
if (class_cfg & NXGE_CLASS_FLOW_USE_IPDST)
ft.ip4_daddr = flow_res->flow_spec.uh.udpip4spec.ip4dst;
if (class_cfg & NXGE_CLASS_FLOW_USE_SRC_PORT)
ft.ip_src_port = flow_res->flow_spec.uh.udpip4spec.psrc;
if (class_cfg & NXGE_CLASS_FLOW_USE_DST_PORT)
ft.ip_dst_port = flow_res->flow_spec.uh.udpip4spec.pdst;
break;
default:
return (NXGE_ERROR);
}
*H1 = nxge_compute_h1(p_class_cfgp->init_h1,
(uint32_t *)&ft, ft_size) & 0xfffff;
*H2 = nxge_compute_h2(p_class_cfgp->init_h2,
(uint8_t *)&ft, ft_size);
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, "<== nxge_flow_get_hash"));
return (NXGE_OK);
}
nxge_status_t
nxge_add_fcram_entry(p_nxge_t nxgep, flow_resource_t *flow_res)
{
uint32_t H1;
uint16_t H2;
nxge_status_t status = NXGE_OK;
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, "==> nxge_add_fcram_entry"));
status = nxge_flow_get_hash(nxgep, flow_res, &H1, &H2);
if (status != NXGE_OK) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
" nxge_add_fcram_entry failed "));
return (status);
}
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, "<== nxge_add_fcram_entry"));
return (NXGE_OK);
}
/*
* Already decided this flow goes into the tcam
*/
nxge_status_t
nxge_add_tcam_entry(p_nxge_t nxgep, flow_resource_t *flow_res)
{
npi_handle_t handle;
uint64_t channel_cookie;
uint64_t flow_cookie;
flow_spec_t *flow_spec;
npi_status_t rs = NPI_SUCCESS;
tcam_entry_t tcam_ptr;
tcam_location_t location;
uint8_t offset, rdc_grp;
p_nxge_hw_list_t hw_p;
uint64_t class;
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, "==> nxge_add_tcam_entry"));
handle = nxgep->npi_reg_handle;
bzero((void *)&tcam_ptr, sizeof (tcam_entry_t));
flow_spec = (flow_spec_t *)&flow_res->flow_spec;
flow_cookie = flow_res->flow_cookie;
channel_cookie = flow_res->channel_cookie;
location = (tcam_location_t)nxge_tcam_get_index(nxgep,
(uint16_t)flow_res->location);
if ((hw_p = nxgep->nxge_hw_p) == NULL) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
" nxge_add_tcam_entry: common hardware not set",
nxgep->niu_type));
return (NXGE_ERROR);
}
if (flow_spec->flow_type == FSPEC_IP_USR) {
int i;
int add_usr_cls = 0;
int ipv6 = 0;
ip_user_spec_t *uspec = &flow_spec->uh.ip_usr_spec;
ip_user_spec_t *umask = &flow_spec->um.ip_usr_spec;
nxge_usr_l3_cls_t *l3_ucls_p;
MUTEX_ENTER(&hw_p->nxge_tcam_lock);
for (i = 0; i < NXGE_L3_PROG_CLS; i++) {
l3_ucls_p = &hw_p->tcam_l3_prog_cls[i];
if (l3_ucls_p->valid && l3_ucls_p->tcam_ref_cnt) {
if (uspec->proto == l3_ucls_p->pid) {
class = l3_ucls_p->cls;
l3_ucls_p->tcam_ref_cnt++;
add_usr_cls = 1;
break;
}
} else if (l3_ucls_p->valid == 0) {
/* Program new user IP class */
switch (i) {
case 0:
class = TCAM_CLASS_IP_USER_4;
break;
case 1:
class = TCAM_CLASS_IP_USER_5;
break;
case 2:
class = TCAM_CLASS_IP_USER_6;
break;
case 3:
class = TCAM_CLASS_IP_USER_7;
break;
default:
break;
}
if (uspec->ip_ver == FSPEC_IP6)
ipv6 = 1;
rs = npi_fflp_cfg_ip_usr_cls_set(handle,
(tcam_class_t)class, uspec->tos,
umask->tos, uspec->proto, ipv6);
if (rs != NPI_SUCCESS)
goto fail;
rs = npi_fflp_cfg_ip_usr_cls_enable(handle,
(tcam_class_t)class);
if (rs != NPI_SUCCESS)
goto fail;
l3_ucls_p->cls = class;
l3_ucls_p->pid = uspec->proto;
l3_ucls_p->tcam_ref_cnt++;
l3_ucls_p->valid = 1;
add_usr_cls = 1;
break;
} else if (l3_ucls_p->tcam_ref_cnt == 0 &&
uspec->proto == l3_ucls_p->pid) {
/*
* The class has already been programmed,
* probably for flow hash
*/
class = l3_ucls_p->cls;
if (uspec->ip_ver == FSPEC_IP6)
ipv6 = 1;
rs = npi_fflp_cfg_ip_usr_cls_set(handle,
(tcam_class_t)class, uspec->tos,
umask->tos, uspec->proto, ipv6);
if (rs != NPI_SUCCESS)
goto fail;
rs = npi_fflp_cfg_ip_usr_cls_enable(handle,
(tcam_class_t)class);
if (rs != NPI_SUCCESS)
goto fail;
l3_ucls_p->pid = uspec->proto;
l3_ucls_p->tcam_ref_cnt++;
add_usr_cls = 1;
break;
}
}
if (!add_usr_cls) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"nxge_add_tcam_entry: Could not find/insert class"
"for pid %d", uspec->proto));
goto fail;
}
MUTEX_EXIT(&hw_p->nxge_tcam_lock);
}
switch (flow_spec->flow_type) {
case FSPEC_TCPIP4:
nxge_fill_tcam_entry_tcp(nxgep, flow_spec, &tcam_ptr);
rdc_grp = nxge_get_rdc_group(nxgep, TCAM_CLASS_TCP_IPV4,
flow_cookie);
offset = nxge_get_rdc_offset(nxgep, TCAM_CLASS_TCP_IPV4,
channel_cookie);
break;
case FSPEC_UDPIP4:
nxge_fill_tcam_entry_udp(nxgep, flow_spec, &tcam_ptr);
rdc_grp = nxge_get_rdc_group(nxgep,
TCAM_CLASS_UDP_IPV4,
flow_cookie);
offset = nxge_get_rdc_offset(nxgep,
TCAM_CLASS_UDP_IPV4,
channel_cookie);
break;
case FSPEC_TCPIP6:
nxge_fill_tcam_entry_tcp_ipv6(nxgep,
flow_spec, &tcam_ptr);
rdc_grp = nxge_get_rdc_group(nxgep, TCAM_CLASS_TCP_IPV6,
flow_cookie);
offset = nxge_get_rdc_offset(nxgep, TCAM_CLASS_TCP_IPV6,
channel_cookie);
break;
case FSPEC_UDPIP6:
nxge_fill_tcam_entry_udp_ipv6(nxgep,
flow_spec, &tcam_ptr);
rdc_grp = nxge_get_rdc_group(nxgep,
TCAM_CLASS_UDP_IPV6,
flow_cookie);
offset = nxge_get_rdc_offset(nxgep,
TCAM_CLASS_UDP_IPV6,
channel_cookie);
break;
case FSPEC_SCTPIP4:
nxge_fill_tcam_entry_sctp(nxgep, flow_spec, &tcam_ptr);
rdc_grp = nxge_get_rdc_group(nxgep,
TCAM_CLASS_SCTP_IPV4,
flow_cookie);
offset = nxge_get_rdc_offset(nxgep,
TCAM_CLASS_SCTP_IPV4,
channel_cookie);
break;
case FSPEC_SCTPIP6:
nxge_fill_tcam_entry_sctp_ipv6(nxgep,
flow_spec, &tcam_ptr);
rdc_grp = nxge_get_rdc_group(nxgep,
TCAM_CLASS_SCTP_IPV6,
flow_cookie);
offset = nxge_get_rdc_offset(nxgep,
TCAM_CLASS_SCTP_IPV6,
channel_cookie);
break;
case FSPEC_AHIP4:
case FSPEC_ESPIP4:
nxge_fill_tcam_entry_ah_esp(nxgep, flow_spec, &tcam_ptr);
rdc_grp = nxge_get_rdc_group(nxgep,
TCAM_CLASS_AH_ESP_IPV4,
flow_cookie);
offset = nxge_get_rdc_offset(nxgep,
TCAM_CLASS_AH_ESP_IPV4,
channel_cookie);
break;
case FSPEC_AHIP6:
case FSPEC_ESPIP6:
nxge_fill_tcam_entry_ah_esp_ipv6(nxgep,
flow_spec, &tcam_ptr);
rdc_grp = nxge_get_rdc_group(nxgep,
TCAM_CLASS_AH_ESP_IPV6,
flow_cookie);
offset = nxge_get_rdc_offset(nxgep,
TCAM_CLASS_AH_ESP_IPV6,
channel_cookie);
break;
case FSPEC_IP_USR:
nxge_fill_tcam_entry_ip_usr(nxgep, flow_spec, &tcam_ptr,
(tcam_class_t)class);
rdc_grp = nxge_get_rdc_group(nxgep,
(tcam_class_t)class, flow_cookie);
offset = nxge_get_rdc_offset(nxgep,
(tcam_class_t)class, channel_cookie);
break;
default:
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"nxge_add_tcam_entry: Unknown flow spec 0x%x",
flow_spec->flow_type));
return (NXGE_ERROR);
}
NXGE_DEBUG_MSG((nxgep, FFLP_CTL,
" nxge_add_tcam_entry write"
" for location %d offset %d", location, offset));
MUTEX_ENTER(&hw_p->nxge_tcam_lock);
rs = npi_fflp_tcam_entry_write(handle, location, &tcam_ptr);
if (rs & NPI_FFLP_ERROR) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
" nxge_add_tcam_entry write"
" failed for location %d", location));
goto fail;
}
tcam_ptr.match_action.value = 0;
tcam_ptr.match_action.bits.ldw.rdctbl = rdc_grp;
tcam_ptr.match_action.bits.ldw.offset = offset;
tcam_ptr.match_action.bits.ldw.tres =
TRES_TERM_OVRD_L2RDC;
if (channel_cookie == NXGE_PKT_DISCARD)
tcam_ptr.match_action.bits.ldw.disc = 1;
rs = npi_fflp_tcam_asc_ram_entry_write(handle,
location, tcam_ptr.match_action.value);
if (rs & NPI_FFLP_ERROR) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
" nxge_add_tcam_entry write"
" failed for ASC RAM location %d", location));
goto fail;
}
bcopy((void *) &tcam_ptr,
(void *) &nxgep->classifier.tcam_entries[location].tce,
sizeof (tcam_entry_t));
nxgep->classifier.tcam_entry_cnt++;
nxgep->classifier.tcam_entries[location].valid = 1;
MUTEX_EXIT(&hw_p->nxge_tcam_lock);
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, "<== nxge_add_tcam_entry"));
return (NXGE_OK);
fail:
MUTEX_EXIT(&hw_p->nxge_tcam_lock);
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "nxge_add_tcam_entry FAILED"));
return (NXGE_ERROR);
}
static nxge_status_t
nxge_tcam_handle_ip_fragment(p_nxge_t nxgep)
{
tcam_entry_t tcam_ptr;
tcam_location_t location;
uint8_t class;
uint32_t class_config;
npi_handle_t handle;
npi_status_t rs = NPI_SUCCESS;
p_nxge_hw_list_t hw_p;
nxge_status_t status = NXGE_OK;
handle = nxgep->npi_reg_handle;
class = 0;
bzero((void *)&tcam_ptr, sizeof (tcam_entry_t));
tcam_ptr.ip4_noport_key = 1;
tcam_ptr.ip4_noport_mask = 1;
location = nxgep->function_num;
nxgep->classifier.fragment_bug_location = location;
if ((hw_p = nxgep->nxge_hw_p) == NULL) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
" nxge_tcam_handle_ip_fragment: common hardware not set",
nxgep->niu_type));
return (NXGE_ERROR);
}
MUTEX_ENTER(&hw_p->nxge_tcam_lock);
rs = npi_fflp_tcam_entry_write(handle,
location, &tcam_ptr);
if (rs & NPI_FFLP_ERROR) {
MUTEX_EXIT(&hw_p->nxge_tcam_lock);
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
" nxge_tcam_handle_ip_fragment "
" tcam_entry write"
" failed for location %d", location));
return (NXGE_ERROR);
}
tcam_ptr.match_action.bits.ldw.rdctbl = nxgep->class_config.mac_rdcgrp;
tcam_ptr.match_action.bits.ldw.offset = 0; /* use the default */
tcam_ptr.match_action.bits.ldw.tres =
TRES_TERM_USE_OFFSET;
rs = npi_fflp_tcam_asc_ram_entry_write(handle,
location, tcam_ptr.match_action.value);
if (rs & NPI_FFLP_ERROR) {
MUTEX_EXIT(&hw_p->nxge_tcam_lock);
NXGE_DEBUG_MSG((nxgep,
FFLP_CTL,
" nxge_tcam_handle_ip_fragment "
" tcam_entry write"
" failed for ASC RAM location %d", location));
return (NXGE_ERROR);
}
bcopy((void *) &tcam_ptr,
(void *) &nxgep->classifier.tcam_entries[location].tce,
sizeof (tcam_entry_t));
nxgep->classifier.tcam_entry_cnt++;
nxgep->classifier.tcam_entries[location].valid = 1;
for (class = TCAM_CLASS_TCP_IPV4;
class <= TCAM_CLASS_SCTP_IPV6; class++) {
class_config = nxgep->class_config.class_cfg[class];
class_config |= NXGE_CLASS_TCAM_LOOKUP;
status = nxge_fflp_ip_class_config(nxgep, class, class_config);
if (status & NPI_FFLP_ERROR) {
MUTEX_EXIT(&hw_p->nxge_tcam_lock);
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"nxge_tcam_handle_ip_fragment "
"nxge_fflp_ip_class_config failed "
" class %d config %x ", class, class_config));
return (NXGE_ERROR);
}
}
rs = npi_fflp_cfg_tcam_enable(handle);
if (rs & NPI_FFLP_ERROR) {
MUTEX_EXIT(&hw_p->nxge_tcam_lock);
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"nxge_tcam_handle_ip_fragment "
" nxge_fflp_config_tcam_enable failed"));
return (NXGE_ERROR);
}
MUTEX_EXIT(&hw_p->nxge_tcam_lock);
return (NXGE_OK);
}
/* ARGSUSED */
static int
nxge_flow_need_hash_lookup(p_nxge_t nxgep, flow_resource_t *flow_res)
{
return (0);
}
nxge_status_t
nxge_add_flow(p_nxge_t nxgep, flow_resource_t *flow_res)
{
int insert_hash = 0;
nxge_status_t status = NXGE_OK;
if (NXGE_IS_VALID_NEPTUNE_TYPE(nxgep)) {
/* determine whether to do TCAM or Hash flow */
insert_hash = nxge_flow_need_hash_lookup(nxgep, flow_res);
}
if (insert_hash) {
status = nxge_add_fcram_entry(nxgep, flow_res);
} else {
status = nxge_add_tcam_entry(nxgep, flow_res);
}
return (status);
}
void
nxge_put_tcam(p_nxge_t nxgep, p_mblk_t mp)
{
flow_resource_t *fs;
fs = (flow_resource_t *)mp->b_rptr;
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"nxge_put_tcam addr fs $%p type %x offset %x",
fs, fs->flow_spec.flow_type, fs->channel_cookie));
(void) nxge_add_tcam_entry(nxgep, fs);
}
nxge_status_t
nxge_fflp_config_tcam_enable(p_nxge_t nxgep)
{
npi_handle_t handle = nxgep->npi_reg_handle;
npi_status_t rs = NPI_SUCCESS;
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, " ==> nxge_fflp_config_tcam_enable"));
rs = npi_fflp_cfg_tcam_enable(handle);
if (rs & NPI_FFLP_ERROR) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
" nxge_fflp_config_tcam_enable failed"));
return (NXGE_ERROR | rs);
}
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, " <== nxge_fflp_config_tcam_enable"));
return (NXGE_OK);
}
nxge_status_t
nxge_fflp_config_tcam_disable(p_nxge_t nxgep)
{
npi_handle_t handle = nxgep->npi_reg_handle;
npi_status_t rs = NPI_SUCCESS;
NXGE_DEBUG_MSG((nxgep, FFLP_CTL,
" ==> nxge_fflp_config_tcam_disable"));
rs = npi_fflp_cfg_tcam_disable(handle);
if (rs & NPI_FFLP_ERROR) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
" nxge_fflp_config_tcam_disable failed"));
return (NXGE_ERROR | rs);
}
NXGE_DEBUG_MSG((nxgep, FFLP_CTL,
" <== nxge_fflp_config_tcam_disable"));
return (NXGE_OK);
}
nxge_status_t
nxge_fflp_config_hash_lookup_enable(p_nxge_t nxgep)
{
npi_handle_t handle = nxgep->npi_reg_handle;
npi_status_t rs = NPI_SUCCESS;
p_nxge_dma_pt_cfg_t p_dma_cfgp;
p_nxge_hw_pt_cfg_t p_cfgp;
uint8_t partition;
NXGE_DEBUG_MSG((nxgep, FFLP_CTL,
" ==> nxge_fflp_config_hash_lookup_enable"));
p_dma_cfgp = (p_nxge_dma_pt_cfg_t)&nxgep->pt_config;
p_cfgp = (p_nxge_hw_pt_cfg_t)&p_dma_cfgp->hw_config;
for (partition = 0; partition < NXGE_MAX_RDC_GROUPS; partition++) {
if (p_cfgp->grpids[partition]) {
rs = npi_fflp_cfg_fcram_partition_enable(
handle, partition);
if (rs != NPI_SUCCESS) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
" nxge_fflp_config_hash_lookup_enable"
"failed FCRAM partition"
" enable for partition %d ", partition));
return (NXGE_ERROR | rs);
}
}
}
NXGE_DEBUG_MSG((nxgep, FFLP_CTL,
" <== nxge_fflp_config_hash_lookup_enable"));
return (NXGE_OK);
}
nxge_status_t
nxge_fflp_config_hash_lookup_disable(p_nxge_t nxgep)
{
npi_handle_t handle = nxgep->npi_reg_handle;
npi_status_t rs = NPI_SUCCESS;
p_nxge_dma_pt_cfg_t p_dma_cfgp;
p_nxge_hw_pt_cfg_t p_cfgp;
uint8_t partition;
NXGE_DEBUG_MSG((nxgep, FFLP_CTL,
" ==> nxge_fflp_config_hash_lookup_disable"));
p_dma_cfgp = (p_nxge_dma_pt_cfg_t)&nxgep->pt_config;
p_cfgp = (p_nxge_hw_pt_cfg_t)&p_dma_cfgp->hw_config;
for (partition = 0; partition < NXGE_MAX_RDC_GROUPS; partition++) {
if (p_cfgp->grpids[partition]) {
rs = npi_fflp_cfg_fcram_partition_disable(handle,
partition);
if (rs != NPI_SUCCESS) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
" nxge_fflp_config_hash_lookup_disable"
" failed FCRAM partition"
" disable for partition %d ", partition));
return (NXGE_ERROR | rs);
}
}
}
NXGE_DEBUG_MSG((nxgep, FFLP_CTL,
" <== nxge_fflp_config_hash_lookup_disable"));
return (NXGE_OK);
}
nxge_status_t
nxge_fflp_config_llc_snap_enable(p_nxge_t nxgep)
{
npi_handle_t handle = nxgep->npi_reg_handle;
npi_status_t rs = NPI_SUCCESS;
NXGE_DEBUG_MSG((nxgep, FFLP_CTL,
" ==> nxge_fflp_config_llc_snap_enable"));
rs = npi_fflp_cfg_llcsnap_enable(handle);
if (rs & NPI_FFLP_ERROR) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
" nxge_fflp_config_llc_snap_enable failed"));
return (NXGE_ERROR | rs);
}
NXGE_DEBUG_MSG((nxgep, FFLP_CTL,
" <== nxge_fflp_config_llc_snap_enable"));
return (NXGE_OK);
}
nxge_status_t
nxge_fflp_config_llc_snap_disable(p_nxge_t nxgep)
{
npi_handle_t handle = nxgep->npi_reg_handle;
npi_status_t rs = NPI_SUCCESS;
NXGE_DEBUG_MSG((nxgep, FFLP_CTL,
" ==> nxge_fflp_config_llc_snap_disable"));
rs = npi_fflp_cfg_llcsnap_disable(handle);
if (rs & NPI_FFLP_ERROR) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
" nxge_fflp_config_llc_snap_disable failed"));
return (NXGE_ERROR | rs);
}
NXGE_DEBUG_MSG((nxgep, FFLP_CTL,
" <== nxge_fflp_config_llc_snap_disable"));
return (NXGE_OK);
}
nxge_status_t
nxge_fflp_ip_usr_class_config(p_nxge_t nxgep, tcam_class_t class,
uint32_t config)
{
npi_status_t rs = NPI_SUCCESS;
npi_handle_t handle = nxgep->npi_reg_handle;
uint8_t tos, tos_mask, proto, ver = 0;
uint8_t class_enable = 0;
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, "==> nxge_fflp_ip_usr_class_config"));
tos = (config & NXGE_CLASS_CFG_IP_TOS_MASK) >>
NXGE_CLASS_CFG_IP_TOS_SHIFT;
tos_mask = (config & NXGE_CLASS_CFG_IP_TOS_MASK_MASK) >>
NXGE_CLASS_CFG_IP_TOS_MASK_SHIFT;
proto = (config & NXGE_CLASS_CFG_IP_PROTO_MASK) >>
NXGE_CLASS_CFG_IP_PROTO_SHIFT;
if (config & NXGE_CLASS_CFG_IP_IPV6_MASK)
ver = 1;
if (config & NXGE_CLASS_CFG_IP_ENABLE_MASK)
class_enable = 1;
rs = npi_fflp_cfg_ip_usr_cls_set(handle, class, tos, tos_mask,
proto, ver);
if (rs & NPI_FFLP_ERROR) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
" nxge_fflp_ip_usr_class_config"
" for class %d failed ", class));
return (NXGE_ERROR | rs);
}
if (class_enable)
rs = npi_fflp_cfg_ip_usr_cls_enable(handle, class);
else
rs = npi_fflp_cfg_ip_usr_cls_disable(handle, class);
if (rs & NPI_FFLP_ERROR) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
" nxge_fflp_ip_usr_class_config"
" TCAM enable/disable for class %d failed ", class));
return (NXGE_ERROR | rs);
}
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, "<== nxge_fflp_ip_usr_class_config"));
return (NXGE_OK);
}
nxge_status_t
nxge_fflp_ip_class_config(p_nxge_t nxgep, tcam_class_t class, uint32_t config)
{
uint32_t class_config;
nxge_status_t t_status = NXGE_OK;
nxge_status_t f_status = NXGE_OK;
p_nxge_class_pt_cfg_t p_class_cfgp;
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, " ==> nxge_fflp_ip_class_config"));
p_class_cfgp = (p_nxge_class_pt_cfg_t)&nxgep->class_config;
class_config = p_class_cfgp->class_cfg[class];
if (class_config != config) {
p_class_cfgp->class_cfg[class] = config;
class_config = config;
}
t_status = nxge_cfg_tcam_ip_class(nxgep, class, class_config);
f_status = nxge_cfg_ip_cls_flow_key(nxgep, class, class_config);
if (t_status & NPI_FFLP_ERROR) {
NXGE_DEBUG_MSG((nxgep, FFLP_CTL,
" nxge_fflp_ip_class_config %x"
" for class %d tcam failed", config, class));
return (t_status);
}
if (f_status & NPI_FFLP_ERROR) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
" nxge_fflp_ip_class_config %x"
" for class %d flow key failed", config, class));
return (f_status);
}
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, "<== nxge_fflp_ip_class_config"));
return (NXGE_OK);
}
nxge_status_t
nxge_fflp_ip_class_config_get(p_nxge_t nxgep, tcam_class_t class,
uint32_t *config)
{
uint32_t t_class_config, f_class_config;
int t_status = NXGE_OK;
int f_status = NXGE_OK;
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, " ==> nxge_fflp_ip_class_config"));
t_class_config = f_class_config = 0;
t_status = nxge_cfg_tcam_ip_class_get(nxgep, class, &t_class_config);
f_status = nxge_cfg_ip_cls_flow_key_get(nxgep, class, &f_class_config);
if (t_status & NPI_FFLP_ERROR) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
" nxge_fflp_ip_class_config_get "
" for class %d tcam failed", class));
return (t_status);
}
if (f_status & NPI_FFLP_ERROR) {
NXGE_DEBUG_MSG((nxgep, FFLP_CTL,
" nxge_fflp_ip_class_config_get "
" for class %d flow key failed", class));
return (f_status);
}
NXGE_DEBUG_MSG((nxgep, FFLP_CTL,
" nxge_fflp_ip_class_config tcam %x flow %x",
t_class_config, f_class_config));
*config = t_class_config | f_class_config;
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, "<== nxge_fflp_ip_class_config_get"));
return (NXGE_OK);
}
nxge_status_t
nxge_fflp_ip_class_config_all(p_nxge_t nxgep)
{
uint32_t class_config;
tcam_class_t class;
#ifdef NXGE_DEBUG
int status = NXGE_OK;
#endif
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, "==> nxge_fflp_ip_class_config"));
for (class = TCAM_CLASS_TCP_IPV4;
class <= TCAM_CLASS_SCTP_IPV6; class++) {
class_config = nxgep->class_config.class_cfg[class];
#ifndef NXGE_DEBUG
(void) nxge_fflp_ip_class_config(nxgep, class, class_config);
#else
status = nxge_fflp_ip_class_config(nxgep, class, class_config);
if (status & NPI_FFLP_ERROR) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"nxge_fflp_ip_class_config failed "
" class %d config %x ",
class, class_config));
}
#endif
}
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, "<== nxge_fflp_ip_class_config"));
return (NXGE_OK);
}
nxge_status_t
nxge_fflp_config_vlan_table(p_nxge_t nxgep, uint16_t vlan_id)
{
uint8_t port, rdc_grp;
npi_handle_t handle;
npi_status_t rs = NPI_SUCCESS;
uint8_t priority = 1;
p_nxge_mv_cfg_t vlan_table;
p_nxge_class_pt_cfg_t p_class_cfgp;
p_nxge_hw_list_t hw_p;
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, "==> nxge_fflp_config_vlan_table"));
p_class_cfgp = (p_nxge_class_pt_cfg_t)&nxgep->class_config;
handle = nxgep->npi_reg_handle;
vlan_table = p_class_cfgp->vlan_tbl;
port = nxgep->function_num;
if (vlan_table[vlan_id].flag == 0) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
" nxge_fflp_config_vlan_table"
" vlan id is not configured %d", vlan_id));
return (NXGE_ERROR);
}
if ((hw_p = nxgep->nxge_hw_p) == NULL) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
" nxge_fflp_config_vlan_table:"
" common hardware not set", nxgep->niu_type));
return (NXGE_ERROR);
}
MUTEX_ENTER(&hw_p->nxge_vlan_lock);
rdc_grp = vlan_table[vlan_id].rdctbl;
rs = npi_fflp_cfg_enet_vlan_table_assoc(handle,
port, vlan_id,
rdc_grp, priority);
MUTEX_EXIT(&hw_p->nxge_vlan_lock);
if (rs & NPI_FFLP_ERROR) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"nxge_fflp_config_vlan_table failed "
" Port %d vlan_id %d rdc_grp %d",
port, vlan_id, rdc_grp));
return (NXGE_ERROR | rs);
}
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, "<== nxge_fflp_config_vlan_table"));
return (NXGE_OK);
}
nxge_status_t
nxge_fflp_update_hw(p_nxge_t nxgep)
{
nxge_status_t status = NXGE_OK;
p_nxge_param_t pa;
uint64_t cfgd_vlans;
uint64_t *val_ptr;
int i;
int num_macs;
uint8_t alt_mac;
nxge_param_map_t *p_map;
p_nxge_mv_cfg_t vlan_table;
p_nxge_class_pt_cfg_t p_class_cfgp;
p_nxge_dma_pt_cfg_t p_all_cfgp;
p_nxge_hw_pt_cfg_t p_cfgp;
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, "==> nxge_fflp_update_hw"));
p_class_cfgp = (p_nxge_class_pt_cfg_t)&nxgep->class_config;
p_all_cfgp = (p_nxge_dma_pt_cfg_t)&nxgep->pt_config;
p_cfgp = (p_nxge_hw_pt_cfg_t)&p_all_cfgp->hw_config;
status = nxge_fflp_set_hash1(nxgep, p_class_cfgp->init_h1);
if (status != NXGE_OK) {
NXGE_DEBUG_MSG((nxgep, FFLP_CTL,
"nxge_fflp_set_hash1 Failed"));
return (NXGE_ERROR);
}
status = nxge_fflp_set_hash2(nxgep, p_class_cfgp->init_h2);
if (status != NXGE_OK) {
NXGE_DEBUG_MSG((nxgep, FFLP_CTL,
"nxge_fflp_set_hash2 Failed"));
return (NXGE_ERROR);
}
vlan_table = p_class_cfgp->vlan_tbl;
/* configure vlan tables */
pa = (p_nxge_param_t)&nxgep->param_arr[param_vlan_2rdc_grp];
#if defined(__i386)
val_ptr = (uint64_t *)(uint32_t)pa->value;
#else
val_ptr = (uint64_t *)pa->value;
#endif
cfgd_vlans = ((pa->type & NXGE_PARAM_ARRAY_CNT_MASK) >>
NXGE_PARAM_ARRAY_CNT_SHIFT);
for (i = 0; i < cfgd_vlans; i++) {
p_map = (nxge_param_map_t *)&val_ptr[i];
if (vlan_table[p_map->param_id].flag) {
status = nxge_fflp_config_vlan_table(nxgep,
p_map->param_id);
if (status != NXGE_OK) {
NXGE_DEBUG_MSG((nxgep, FFLP_CTL,
"nxge_fflp_config_vlan_table Failed"));
return (NXGE_ERROR);
}
}
}
/* config MAC addresses */
num_macs = p_cfgp->max_macs;
pa = (p_nxge_param_t)&nxgep->param_arr[param_mac_2rdc_grp];
#if defined(__i386)
val_ptr = (uint64_t *)(uint32_t)pa->value;
#else
val_ptr = (uint64_t *)pa->value;
#endif
for (alt_mac = 0; alt_mac < num_macs; alt_mac++) {
if (p_class_cfgp->mac_host_info[alt_mac].flag) {
status = nxge_logical_mac_assign_rdc_table(nxgep,
alt_mac);
if (status != NXGE_OK) {
NXGE_DEBUG_MSG((nxgep, FFLP_CTL,
"nxge_logical_mac_assign_rdc_table"
" Failed"));
return (NXGE_ERROR);
}
}
}
/* Config Hash values */
/* config classes */
status = nxge_fflp_ip_class_config_all(nxgep);
if (status != NXGE_OK) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"nxge_fflp_ip_class_config_all Failed"));
return (NXGE_ERROR);
}
return (NXGE_OK);
}
nxge_status_t
nxge_classify_init_hw(p_nxge_t nxgep)
{
nxge_status_t status = NXGE_OK;
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, "==> nxge_classify_init_hw"));
if (nxgep->classifier.state & NXGE_FFLP_HW_INIT) {
NXGE_DEBUG_MSG((nxgep, FFLP_CTL,
"nxge_classify_init_hw already init"));
return (NXGE_OK);
}
/* Now do a real configuration */
status = nxge_fflp_update_hw(nxgep);
if (status != NXGE_OK) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"nxge_fflp_update_hw failed"));
return (NXGE_ERROR);
}
/* Init RDC tables? ? who should do that? rxdma or fflp ? */
/* attach rdc table to the MAC port. */
status = nxge_main_mac_assign_rdc_table(nxgep);
if (status != NXGE_OK) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"nxge_main_mac_assign_rdc_table failed"));
return (NXGE_ERROR);
}
status = nxge_alt_mcast_mac_assign_rdc_table(nxgep);
if (status != NXGE_OK) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"nxge_multicast_mac_assign_rdc_table failed"));
return (NXGE_ERROR);
}
if (nxgep->classifier.fragment_bug == 1) {
status = nxge_tcam_handle_ip_fragment(nxgep);
if (status != NXGE_OK) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"nxge_tcam_handle_ip_fragment failed"));
return (NXGE_ERROR);
}
}
nxgep->classifier.state |= NXGE_FFLP_HW_INIT;
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, "<== nxge_classify_init_hw"));
return (NXGE_OK);
}
nxge_status_t
nxge_fflp_handle_sys_errors(p_nxge_t nxgep)
{
npi_handle_t handle;
p_nxge_fflp_stats_t statsp;
uint8_t portn, rdc_grp;
p_nxge_dma_pt_cfg_t p_dma_cfgp;
p_nxge_hw_pt_cfg_t p_cfgp;
vlan_par_err_t vlan_err;
tcam_err_t tcam_err;
hash_lookup_err_log1_t fcram1_err;
hash_lookup_err_log2_t fcram2_err;
hash_tbl_data_log_t fcram_err;
handle = nxgep->npi_handle;
statsp = (p_nxge_fflp_stats_t)&nxgep->statsp->fflp_stats;
portn = nxgep->mac.portnum;
/*
* need to read the fflp error registers to figure out what the error
* is
*/
npi_fflp_vlan_error_get(handle, &vlan_err);
npi_fflp_tcam_error_get(handle, &tcam_err);
if (vlan_err.bits.ldw.m_err || vlan_err.bits.ldw.err) {
NXGE_ERROR_MSG((nxgep, FFLP_CTL,
" vlan table parity error on port %d"
" addr: 0x%x data: 0x%x",
portn, vlan_err.bits.ldw.addr,
vlan_err.bits.ldw.data));
statsp->vlan_parity_err++;
if (vlan_err.bits.ldw.m_err) {
NXGE_ERROR_MSG((nxgep, FFLP_CTL,
" vlan table multiple errors on port %d",
portn));
}
statsp->errlog.vlan = (uint32_t)vlan_err.value;
NXGE_FM_REPORT_ERROR(nxgep, NULL, NULL,
NXGE_FM_EREPORT_FFLP_VLAN_PAR_ERR);
npi_fflp_vlan_error_clear(handle);
}
if (tcam_err.bits.ldw.err) {
if (tcam_err.bits.ldw.p_ecc != 0) {
NXGE_ERROR_MSG((nxgep, FFLP_CTL,
" TCAM ECC error on port %d"
" TCAM entry: 0x%x syndrome: 0x%x",
portn, tcam_err.bits.ldw.addr,
tcam_err.bits.ldw.syndrome));
statsp->tcam_ecc_err++;
} else {
NXGE_ERROR_MSG((nxgep, FFLP_CTL,
" TCAM Parity error on port %d"
" addr: 0x%x parity value: 0x%x",
portn, tcam_err.bits.ldw.addr,
tcam_err.bits.ldw.syndrome));
statsp->tcam_parity_err++;
}
if (tcam_err.bits.ldw.mult) {
NXGE_ERROR_MSG((nxgep, FFLP_CTL,
" TCAM Multiple errors on port %d", portn));
} else {
NXGE_ERROR_MSG((nxgep, FFLP_CTL,
" TCAM PIO error on port %d", portn));
}
statsp->errlog.tcam = (uint32_t)tcam_err.value;
NXGE_FM_REPORT_ERROR(nxgep, NULL, NULL,
NXGE_FM_EREPORT_FFLP_TCAM_ERR);
npi_fflp_tcam_error_clear(handle);
}
p_dma_cfgp = (p_nxge_dma_pt_cfg_t)&nxgep->pt_config;
p_cfgp = (p_nxge_hw_pt_cfg_t)&p_dma_cfgp->hw_config;
for (rdc_grp = 0; rdc_grp < NXGE_MAX_RDC_GROUPS; rdc_grp++) {
if (p_cfgp->grpids[rdc_grp]) {
npi_fflp_fcram_error_get(handle, &fcram_err, rdc_grp);
if (fcram_err.bits.ldw.pio_err) {
NXGE_ERROR_MSG((nxgep, FFLP_CTL,
" FCRAM PIO ECC error on port %d"
" rdc group: %d Hash Table addr: 0x%x"
" syndrome: 0x%x",
portn, rdc_grp,
fcram_err.bits.ldw.fcram_addr,
fcram_err.bits.ldw.syndrome));
statsp->hash_pio_err[rdc_grp]++;
statsp->errlog.hash_pio[rdc_grp] =
(uint32_t)fcram_err.value;
NXGE_FM_REPORT_ERROR(nxgep, NULL, NULL,
NXGE_FM_EREPORT_FFLP_HASHT_DATA_ERR);
npi_fflp_fcram_error_clear(handle, rdc_grp);
}
}
}
npi_fflp_fcram_error_log1_get(handle, &fcram1_err);
if (fcram1_err.bits.ldw.ecc_err) {
char *multi_str = "";
char *multi_bit_str = "";
npi_fflp_fcram_error_log2_get(handle, &fcram2_err);
if (fcram1_err.bits.ldw.mult_lk) {
multi_str = "multiple";
}
if (fcram1_err.bits.ldw.mult_bit) {
multi_bit_str = "multiple bits";
}
statsp->hash_lookup_err++;
NXGE_ERROR_MSG((nxgep, FFLP_CTL,
" FCRAM %s lookup %s ECC error on port %d"
" H1: 0x%x Subarea: 0x%x Syndrome: 0x%x",
multi_str, multi_bit_str, portn,
fcram2_err.bits.ldw.h1,
fcram2_err.bits.ldw.subarea,
fcram2_err.bits.ldw.syndrome));
NXGE_FM_REPORT_ERROR(nxgep, NULL, NULL,
NXGE_FM_EREPORT_FFLP_HASHT_LOOKUP_ERR);
}
statsp->errlog.hash_lookup1 = (uint32_t)fcram1_err.value;
statsp->errlog.hash_lookup2 = (uint32_t)fcram2_err.value;
return (NXGE_OK);
}
int
nxge_get_valid_tcam_cnt(p_nxge_t nxgep) {
return ((nxgep->classifier.fragment_bug == 1) ?
nxgep->classifier.tcam_entry_cnt - 1 :
nxgep->classifier.tcam_entry_cnt);
}
int
nxge_rxdma_channel_cnt(p_nxge_t nxgep)
{
p_nxge_dma_pt_cfg_t p_dma_cfgp;
p_nxge_hw_pt_cfg_t p_cfgp;
p_dma_cfgp = (p_nxge_dma_pt_cfg_t)&nxgep->pt_config;
p_cfgp = (p_nxge_hw_pt_cfg_t)&p_dma_cfgp->hw_config;
return (p_cfgp->max_rdcs);
}
/* ARGSUSED */
int
nxge_rxclass_ioctl(p_nxge_t nxgep, queue_t *wq, mblk_t *mp)
{
uint32_t cmd;
rx_class_cfg_t *cfg_info = (rx_class_cfg_t *)mp->b_rptr;
if (nxgep == NULL) {
return (-1);
}
cmd = cfg_info->cmd;
switch (cmd) {
default:
return (-1);
case NXGE_RX_CLASS_GCHAN:
cfg_info->data = nxge_rxdma_channel_cnt(nxgep);
break;
case NXGE_RX_CLASS_GRULE_CNT:
MUTEX_ENTER(&nxgep->nxge_hw_p->nxge_tcam_lock);
cfg_info->rule_cnt = nxge_get_valid_tcam_cnt(nxgep);
MUTEX_EXIT(&nxgep->nxge_hw_p->nxge_tcam_lock);
break;
case NXGE_RX_CLASS_GRULE:
nxge_get_tcam_entry(nxgep, &cfg_info->fs);
break;
case NXGE_RX_CLASS_GRULE_ALL:
nxge_get_tcam_entry_all(nxgep, cfg_info);
break;
case NXGE_RX_CLASS_RULE_DEL:
nxge_del_tcam_entry(nxgep, cfg_info->fs.location);
break;
case NXGE_RX_CLASS_RULE_INS:
(void) nxge_add_tcam_entry(nxgep, &cfg_info->fs);
break;
}
return (0);
}
/* ARGSUSED */
int
nxge_rxhash_ioctl(p_nxge_t nxgep, queue_t *wq, mblk_t *mp)
{
uint32_t cmd;
cfg_cmd_t *cfg_info = (cfg_cmd_t *)mp->b_rptr;
if (nxgep == NULL) {
return (-1);
}
cmd = cfg_info->cmd;
switch (cmd) {
default:
return (-1);
case NXGE_IPTUN_CFG_ADD_CLS:
nxge_add_iptun_class(nxgep, &cfg_info->iptun_cfg,
&cfg_info->class_id);
break;
case NXGE_IPTUN_CFG_SET_HASH:
nxge_cfg_iptun_hash(nxgep, &cfg_info->iptun_cfg,
cfg_info->class_id);
break;
case NXGE_IPTUN_CFG_DEL_CLS:
nxge_del_iptun_class(nxgep, cfg_info->class_id);
break;
case NXGE_IPTUN_CFG_GET_CLS:
nxge_get_iptun_class(nxgep, &cfg_info->iptun_cfg,
cfg_info->class_id);
break;
case NXGE_CLS_CFG_SET_SYM:
nxge_set_ip_cls_sym(nxgep, cfg_info->class_id, cfg_info->sym);
break;
case NXGE_CLS_CFG_GET_SYM:
nxge_get_ip_cls_sym(nxgep, cfg_info->class_id, &cfg_info->sym);
break;
}
return (0);
}
void
nxge_get_tcam_entry_all(p_nxge_t nxgep, rx_class_cfg_t *cfgp)
{
nxge_classify_t *clasp = &nxgep->classifier;
uint16_t n_entries;
int i, j, k;
tcam_flow_spec_t *tcam_entryp;
cfgp->data = clasp->tcam_size;
MUTEX_ENTER(&nxgep->nxge_hw_p->nxge_tcam_lock);
n_entries = cfgp->rule_cnt;
for (i = 0, j = 0; j < cfgp->data; j++) {
k = nxge_tcam_get_index(nxgep, j);
tcam_entryp = &clasp->tcam_entries[k];
if (tcam_entryp->valid != 1)
continue;
cfgp->rule_locs[i] = j;
i++;
};
MUTEX_EXIT(&nxgep->nxge_hw_p->nxge_tcam_lock);
if (n_entries != i) {
/* print warning, this should not happen */
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "nxge_get_tcam_entry_all"
"n_entries[%d] != i[%d]!!!", n_entries, i));
}
}
/* Entries for the ports are interleaved in the TCAM */
static uint16_t
nxge_tcam_get_index(p_nxge_t nxgep, uint16_t index)
{
/* One entry reserved for IP fragment rule */
if (index >= (nxgep->classifier.tcam_size - 1))
index = 0;
if (nxgep->classifier.fragment_bug == 1)
index++;
return (nxgep->classifier.tcam_top + (index * nxgep->nports));
}
static uint32_t
nxge_tcam_cls_to_flow(uint32_t class_code) {
switch (class_code) {
case TCAM_CLASS_TCP_IPV4:
return (FSPEC_TCPIP4);
case TCAM_CLASS_UDP_IPV4:
return (FSPEC_UDPIP4);
case TCAM_CLASS_AH_ESP_IPV4:
return (FSPEC_AHIP4);
case TCAM_CLASS_SCTP_IPV4:
return (FSPEC_SCTPIP4);
case TCAM_CLASS_TCP_IPV6:
return (FSPEC_TCPIP6);
case TCAM_CLASS_UDP_IPV6:
return (FSPEC_UDPIP6);
case TCAM_CLASS_AH_ESP_IPV6:
return (FSPEC_AHIP6);
case TCAM_CLASS_SCTP_IPV6:
return (FSPEC_SCTPIP6);
case TCAM_CLASS_IP_USER_4:
case TCAM_CLASS_IP_USER_5:
case TCAM_CLASS_IP_USER_6:
case TCAM_CLASS_IP_USER_7:
return (FSPEC_IP_USR);
default:
NXGE_ERROR_MSG((NULL, NXGE_ERR_CTL, "nxge_tcam_cls_to_flow"
": Unknown class code [0x%x]", class_code));
break;
}
return (0);
}
void
nxge_get_tcam_entry(p_nxge_t nxgep, flow_resource_t *fs)
{
uint16_t index;
tcam_flow_spec_t *tcam_ep;
tcam_entry_t *tp;
flow_spec_t *fspec;
tcpip4_spec_t *fspec_key;
tcpip4_spec_t *fspec_mask;
index = nxge_tcam_get_index(nxgep, (uint16_t)fs->location);
tcam_ep = &nxgep->classifier.tcam_entries[index];
if (tcam_ep->valid != 1) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "nxge_get_tcam_entry: :"
"Entry [%d] invalid for index [%d]", fs->location, index));
return;
}
/* Fill the flow spec entry */
tp = &tcam_ep->tce;
fspec = &fs->flow_spec;
fspec->flow_type = nxge_tcam_cls_to_flow(tp->ip4_class_key);
/* TODO - look at proto field to differentiate between AH and ESP */
if (fspec->flow_type == FSPEC_AHIP4) {
if (tp->ip4_proto_key == IPPROTO_ESP)
fspec->flow_type = FSPEC_ESPIP4;
}
switch (tp->ip4_class_key) {
case TCAM_CLASS_TCP_IPV4:
case TCAM_CLASS_UDP_IPV4:
case TCAM_CLASS_AH_ESP_IPV4:
case TCAM_CLASS_SCTP_IPV4:
fspec_key = (tcpip4_spec_t *)&fspec->uh.tcpip4spec;
fspec_mask = (tcpip4_spec_t *)&fspec->um.tcpip4spec;
FSPEC_IPV4_ADDR(fspec_key->ip4dst, tp->ip4_dest_key);
FSPEC_IPV4_ADDR(fspec_mask->ip4dst, tp->ip4_dest_mask);
FSPEC_IPV4_ADDR(fspec_key->ip4src, tp->ip4_src_key);
FSPEC_IPV4_ADDR(fspec_mask->ip4src, tp->ip4_src_mask);
fspec_key->tos = tp->ip4_tos_key;
fspec_mask->tos = tp->ip4_tos_mask;
break;
default:
break;
}
switch (tp->ip4_class_key) {
case TCAM_CLASS_TCP_IPV4:
case TCAM_CLASS_UDP_IPV4:
case TCAM_CLASS_SCTP_IPV4:
FSPEC_IP_PORTS(fspec_key->pdst, fspec_key->psrc,
tp->ip4_port_key);
FSPEC_IP_PORTS(fspec_mask->pdst, fspec_mask->psrc,
tp->ip4_port_mask);
break;
case TCAM_CLASS_AH_ESP_IPV4:
fspec->uh.ahip4spec.spi = tp->ip4_port_key;
fspec->um.ahip4spec.spi = tp->ip4_port_mask;
break;
case TCAM_CLASS_IP_USER_4:
case TCAM_CLASS_IP_USER_5:
case TCAM_CLASS_IP_USER_6:
case TCAM_CLASS_IP_USER_7:
fspec->uh.ip_usr_spec.l4_4_bytes = tp->ip4_port_key;
fspec->um.ip_usr_spec.l4_4_bytes = tp->ip4_port_mask;
fspec->uh.ip_usr_spec.ip_ver = FSPEC_IP4;
fspec->uh.ip_usr_spec.proto = tp->ip4_proto_key;
fspec->um.ip_usr_spec.proto = tp->ip4_proto_mask;
break;
default:
break;
}
if (tp->match_action.bits.ldw.disc == 1) {
fs->channel_cookie = NXGE_PKT_DISCARD;
} else {
fs->channel_cookie = tp->match_action.bits.ldw.offset;
}
}
void
nxge_del_tcam_entry(p_nxge_t nxgep, uint32_t location)
{
npi_status_t rs = NPI_SUCCESS;
uint16_t index;
tcam_flow_spec_t *tcam_ep;
tcam_entry_t *tp;
tcam_class_t class;
MUTEX_ENTER(&nxgep->nxge_hw_p->nxge_tcam_lock);
index = nxge_tcam_get_index(nxgep, (uint16_t)location);
tcam_ep = &nxgep->classifier.tcam_entries[index];
if (tcam_ep->valid != 1) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "nxge_del_tcam_entry: :"
"Entry [%d] invalid for index [%d]", location, index));
goto fail;
}
/* Fill the flow spec entry */
tp = &tcam_ep->tce;
class = tp->ip4_class_key;
if (class >= TCAM_CLASS_IP_USER_4 && class <= TCAM_CLASS_IP_USER_7) {
int i;
nxge_usr_l3_cls_t *l3_ucls_p;
p_nxge_hw_list_t hw_p = nxgep->nxge_hw_p;
for (i = 0; i < NXGE_L3_PROG_CLS; i++) {
l3_ucls_p = &hw_p->tcam_l3_prog_cls[i];
if (l3_ucls_p->valid) {
if (l3_ucls_p->cls == class &&
l3_ucls_p->tcam_ref_cnt) {
l3_ucls_p->tcam_ref_cnt--;
if (l3_ucls_p->tcam_ref_cnt > 0)
continue;
/* disable class */
rs = npi_fflp_cfg_ip_usr_cls_disable(
nxgep->npi_reg_handle,
(tcam_class_t)class);
if (rs != NPI_SUCCESS)
goto fail;
l3_ucls_p->cls = 0;
l3_ucls_p->pid = 0;
l3_ucls_p->valid = 0;
break;
}
}
}
if (i == NXGE_L3_PROG_CLS) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"nxge_del_tcam_entry: Usr class "
"0x%llx not found", (unsigned long long) class));
goto fail;
}
}
rs = npi_fflp_tcam_entry_invalidate(nxgep->npi_reg_handle, index);
if (rs != NPI_SUCCESS) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"nxge_del_tcam_entry: TCAM invalidate failed "
"at loc %d ", location));
goto fail;
}
nxgep->classifier.tcam_entries[index].valid = 0;
nxgep->classifier.tcam_entry_cnt--;
MUTEX_EXIT(&nxgep->nxge_hw_p->nxge_tcam_lock);
NXGE_DEBUG_MSG((nxgep, FFLP_CTL, "<== nxge_del_tcam_entry"));
return;
fail:
MUTEX_EXIT(&nxgep->nxge_hw_p->nxge_tcam_lock);
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"<== nxge_del_tcam_entry FAILED"));
}
static uint8_t
nxge_iptun_pkt_type_to_pid(uint8_t pkt_type)
{
uint8_t pid = 0;
switch (pkt_type) {
case IPTUN_PKT_IPV4:
pid = 4;
break;
case IPTUN_PKT_IPV6:
pid = 41;
break;
case IPTUN_PKT_GRE:
pid = 47;
break;
case IPTUN_PKT_GTP:
pid = 17;
break;
default:
NXGE_ERROR_MSG((NULL, NXGE_ERR_CTL,
"nxge_iptun_pkt_type_to_pid: Unknown pkt type 0x%x",
pkt_type));
break;
}
return (pid);
}
static npi_status_t
nxge_set_iptun_usr_cls_reg(p_nxge_t nxgep, uint64_t class,
iptun_cfg_t *iptunp)
{
npi_handle_t handle = nxgep->npi_reg_handle;
npi_status_t rs = NPI_SUCCESS;
switch (iptunp->in_pkt_type) {
case IPTUN_PKT_IPV4:
case IPTUN_PKT_IPV6:
rs = npi_fflp_cfg_ip_usr_cls_set_iptun(handle,
(tcam_class_t)class, 0, 0, 0, 0);
break;
case IPTUN_PKT_GRE:
rs = npi_fflp_cfg_ip_usr_cls_set_iptun(handle,
(tcam_class_t)class, iptunp->l4b0_val,
iptunp->l4b0_mask, 0, 0);
break;
case IPTUN_PKT_GTP:
rs = npi_fflp_cfg_ip_usr_cls_set_iptun(handle,
(tcam_class_t)class, 0, 0, iptunp->l4b23_val,
(iptunp->l4b23_sel & 0x01));
break;
default:
rs = NPI_FFLP_TCAM_CLASS_INVALID;
break;
}
return (rs);
}
void
nxge_add_iptun_class(p_nxge_t nxgep, iptun_cfg_t *iptunp,
uint8_t *cls_idp)
{
int i, add_cls;
uint8_t pid;
uint64_t class;
p_nxge_hw_list_t hw_p = nxgep->nxge_hw_p;
npi_handle_t handle = nxgep->npi_reg_handle;
npi_status_t rs = NPI_SUCCESS;
pid = nxge_iptun_pkt_type_to_pid(iptunp->in_pkt_type);
if (pid == 0)
return;
add_cls = 0;
MUTEX_ENTER(&hw_p->nxge_tcam_lock);
/* Get an user programmable class ID */
for (i = 0; i < NXGE_L3_PROG_CLS; i++) {
if (hw_p->tcam_l3_prog_cls[i].valid == 0) {
/* todo add new usr class reg */
switch (i) {
case 0:
class = TCAM_CLASS_IP_USER_4;
break;
case 1:
class = TCAM_CLASS_IP_USER_5;
break;
case 2:
class = TCAM_CLASS_IP_USER_6;
break;
case 3:
class = TCAM_CLASS_IP_USER_7;
break;
default:
break;
}
rs = npi_fflp_cfg_ip_usr_cls_set(handle,
(tcam_class_t)class, 0, 0, pid, 0);
if (rs != NPI_SUCCESS)
goto fail;
rs = nxge_set_iptun_usr_cls_reg(nxgep, class, iptunp);
if (rs != NPI_SUCCESS)
goto fail;
rs = npi_fflp_cfg_ip_usr_cls_enable(handle,
(tcam_class_t)class);
if (rs != NPI_SUCCESS)
goto fail;
hw_p->tcam_l3_prog_cls[i].cls = class;
hw_p->tcam_l3_prog_cls[i].pid = pid;
hw_p->tcam_l3_prog_cls[i].flow_pkt_type =
iptunp->in_pkt_type;
hw_p->tcam_l3_prog_cls[i].valid = 1;
*cls_idp = (uint8_t)class;
add_cls = 1;
break;
} else if (hw_p->tcam_l3_prog_cls[i].pid == pid) {
if (hw_p->tcam_l3_prog_cls[i].flow_pkt_type == 0) {
/* there is no flow key */
/* todo program the existing usr class reg */
rs = nxge_set_iptun_usr_cls_reg(nxgep, class,
iptunp);
if (rs != NPI_SUCCESS)
goto fail;
rs = npi_fflp_cfg_ip_usr_cls_enable(handle,
(tcam_class_t)class);
if (rs != NPI_SUCCESS)
goto fail;
hw_p->tcam_l3_prog_cls[i].flow_pkt_type =
iptunp->in_pkt_type;
*cls_idp = (uint8_t)class;
add_cls = 1;
} else {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"nxge_add_iptun_class: L3 usr "
"programmable class with pid %d "
"already exists", pid));
}
break;
}
}
MUTEX_EXIT(&hw_p->nxge_tcam_lock);
if (add_cls != 1) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"nxge_add_iptun_class: Could not add IP tunneling class"));
}
return;
fail:
MUTEX_EXIT(&hw_p->nxge_tcam_lock);
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "nxge_add_iptun_class: FAILED"));
}
static boolean_t
nxge_is_iptun_cls_present(p_nxge_t nxgep, uint8_t cls_id, int *idx)
{
int i;
p_nxge_hw_list_t hw_p = nxgep->nxge_hw_p;
MUTEX_ENTER(&hw_p->nxge_tcam_lock);
for (i = 0; i < NXGE_L3_PROG_CLS; i++) {
if (hw_p->tcam_l3_prog_cls[i].valid &&
hw_p->tcam_l3_prog_cls[i].flow_pkt_type != 0) {
if (hw_p->tcam_l3_prog_cls[i].cls == cls_id)
break;
}
}
MUTEX_EXIT(&hw_p->nxge_tcam_lock);
if (i == NXGE_L3_PROG_CLS) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"nxge_is_iptun_cls_present: Invalid class %d", cls_id));
return (B_FALSE);
} else {
*idx = i;
return (B_TRUE);
}
}
void
nxge_cfg_iptun_hash(p_nxge_t nxgep, iptun_cfg_t *iptunp, uint8_t cls_id)
{
int idx;
npi_handle_t handle = nxgep->npi_reg_handle;
flow_key_cfg_t cfg;
/* check to see that this is a valid class ID */
if (!nxge_is_iptun_cls_present(nxgep, cls_id, &idx)) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"nxge_cfg_iptun_hash: nxge_is_iptun_cls_present "
"failed for cls_id %d", cls_id));
return;
}
bzero((void *)&cfg, sizeof (flow_key_cfg_t));
/*
* This ensures that all 4 bytes of the XOR value are loaded to the
* hash key.
*/
cfg.use_dport = cfg.use_sport = cfg.ip_opts_exist = 1;
cfg.l4_xor_sel = (iptunp->l4xor_sel & FL_KEY_USR_L4XOR_MSK);
cfg.use_l4_md = 1;
if (iptunp->hash_flags & HASH_L3PROTO)
cfg.use_proto = 1;
else if (iptunp->hash_flags & HASH_IPDA)
cfg.use_daddr = 1;
else if (iptunp->hash_flags & HASH_IPSA)
cfg.use_saddr = 1;
else if (iptunp->hash_flags & HASH_VLAN)
cfg.use_vlan = 1;
else if (iptunp->hash_flags & HASH_L2DA)
cfg.use_l2da = 1;
else if (iptunp->hash_flags & HASH_IFPORT)
cfg.use_portnum = 1;
(void) npi_fflp_cfg_ip_cls_flow_key_rfnl(handle, (tcam_class_t)cls_id,
&cfg);
}
void
nxge_del_iptun_class(p_nxge_t nxgep, uint8_t cls_id)
{
int i;
npi_handle_t handle = nxgep->npi_reg_handle;
npi_status_t rs = NPI_SUCCESS;
/* check to see that this is a valid class ID */
if (!nxge_is_iptun_cls_present(nxgep, cls_id, &i)) {
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"nxge_del_iptun_class: Invalid class ID 0x%x", cls_id));
return;
}
MUTEX_ENTER(&nxgep->nxge_hw_p->nxge_tcam_lock);
rs = npi_fflp_cfg_ip_usr_cls_disable(handle, (tcam_class_t)cls_id);
if (rs != NPI_SUCCESS)
goto fail;
nxgep->nxge_hw_p->tcam_l3_prog_cls[i].flow_pkt_type = 0;
if (nxgep->nxge_hw_p->tcam_l3_prog_cls[i].tcam_ref_cnt == 0)
nxgep->nxge_hw_p->tcam_l3_prog_cls[i].valid = 0;
MUTEX_EXIT(&nxgep->nxge_hw_p->nxge_tcam_lock);
return;
fail:
MUTEX_EXIT(&nxgep->nxge_hw_p->nxge_tcam_lock);
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "nxge_del_iptun_class: FAILED"));
}
void
nxge_get_iptun_class(p_nxge_t nxgep, iptun_cfg_t *iptunp, uint8_t cls_id)
{
int i;
uint8_t pid;
npi_handle_t handle = nxgep->npi_reg_handle;
npi_status_t rs = NPI_SUCCESS;
flow_key_cfg_t cfg;
/* check to see that this is a valid class ID */
if (!nxge_is_iptun_cls_present(nxgep, cls_id, &i))
return;
bzero((void *)iptunp, sizeof (iptun_cfg_t));
pid = nxgep->nxge_hw_p->tcam_l3_prog_cls[i].pid;
rs = npi_fflp_cfg_ip_usr_cls_get_iptun(handle, (tcam_class_t)cls_id,
&iptunp->l4b0_val, &iptunp->l4b0_mask, &iptunp->l4b23_val,
&iptunp->l4b23_sel);
if (rs != NPI_SUCCESS)
goto fail;
rs = npi_fflp_cfg_ip_cls_flow_key_get_rfnl(handle,
(tcam_class_t)cls_id, &cfg);
if (rs != NPI_SUCCESS)
goto fail;
iptunp->l4xor_sel = cfg.l4_xor_sel;
if (cfg.use_proto)
iptunp->hash_flags |= HASH_L3PROTO;
else if (cfg.use_daddr)
iptunp->hash_flags |= HASH_IPDA;
else if (cfg.use_saddr)
iptunp->hash_flags |= HASH_IPSA;
else if (cfg.use_vlan)
iptunp->hash_flags |= HASH_VLAN;
else if (cfg.use_l2da)
iptunp->hash_flags |= HASH_L2DA;
else if (cfg.use_portnum)
iptunp->hash_flags |= HASH_IFPORT;
switch (pid) {
case 4:
iptunp->in_pkt_type = IPTUN_PKT_IPV4;
break;
case 41:
iptunp->in_pkt_type = IPTUN_PKT_IPV6;
break;
case 47:
iptunp->in_pkt_type = IPTUN_PKT_GRE;
break;
case 17:
iptunp->in_pkt_type = IPTUN_PKT_GTP;
break;
default:
iptunp->in_pkt_type = 0;
break;
}
return;
fail:
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "nxge_get_iptun_class: FAILED"));
}
void
nxge_set_ip_cls_sym(p_nxge_t nxgep, uint8_t cls_id, uint8_t sym)
{
npi_handle_t handle = nxgep->npi_reg_handle;
npi_status_t rs = NPI_SUCCESS;
boolean_t sym_en = (sym == 1) ? B_TRUE : B_FALSE;
rs = npi_fflp_cfg_sym_ip_cls_flow_key(handle, (tcam_class_t)cls_id,
sym_en);
if (rs != NPI_SUCCESS)
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
"nxge_set_ip_cls_sym: FAILED"));
}
void
nxge_get_ip_cls_sym(p_nxge_t nxgep, uint8_t cls_id, uint8_t *sym)
{
npi_handle_t handle = nxgep->npi_reg_handle;
npi_status_t rs = NPI_SUCCESS;
flow_key_cfg_t cfg;
rs = npi_fflp_cfg_ip_cls_flow_key_get_rfnl(handle,
(tcam_class_t)cls_id, &cfg);
if (rs != NPI_SUCCESS)
goto fail;
if (cfg.use_sym)
*sym = 1;
else
*sym = 0;
return;
fail:
NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "nxge_get_ip_cls_sym: FAILED"));
}