| /* |
| * 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-> |