/* * 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 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include /* macros to compute calss configuration register offset */ #define GET_TCAM_CLASS_OFFSET(cls) \ (FFLP_TCAM_CLS_BASE_OFFSET + (cls - 2) * 8) #define GET_TCAM_KEY_OFFSET(cls) \ (FFLP_TCAM_KEY_BASE_OFFSET + (cls - 4) * 8) #define GET_FLOW_KEY_OFFSET(cls) \ (FFLP_FLOW_KEY_BASE_OFFSET + (cls - 4) * 8) #define HASHTBL_PART_REG_STEP 8192 #define HASHTBL_PART_REG_VIR_OFFSET 0x2100 #define HASHTBL_PART_REG_VIR_STEP 0x4000 #define GET_HASHTBL_PART_OFFSET_NVIR(partid, reg) \ ((partid * HASHTBL_PART_REG_STEP) + reg) #define GET_HASHTBL_PART_OFFSET(handle, partid, reg) \ (handle.is_vraddr ? \ (((partid & 0x1) * HASHTBL_PART_REG_VIR_STEP) + \ (reg & 0x8) + (HASHTBL_PART_REG_VIR_OFFSET)) : \ (partid * HASHTBL_PART_REG_STEP) + reg) #define FFLP_PART_OFFSET(partid, reg) ((partid * 8) + reg) #define FFLP_VLAN_OFFSET(vid, reg) ((vid * 8) + reg) #define TCAM_COMPLETION_TRY_COUNT 10 #define BIT_ENABLE 0x1 #define BIT_DISABLE 0x0 #define FCRAM_PARTITION_VALID(partid) \ ((partid < NXGE_MAX_RDC_GRPS)) #define FFLP_VLAN_VALID(vid) \ ((vid > 0) && (vid < NXGE_MAX_VLANS)) #define FFLP_PORT_VALID(port) \ ((port < MAX_PORTS_PER_NXGE)) #define FFLP_RDC_TABLE_VALID(table) \ ((table < NXGE_MAX_RDC_GRPS)) #define TCAM_L3_USR_CLASS_VALID(class) \ ((class >= TCAM_CLASS_IP_USER_4) && (class <= TCAM_CLASS_IP_USER_7)) #define TCAM_L2_USR_CLASS_VALID(class) \ ((class == TCAM_CLASS_ETYPE_1) || (class == TCAM_CLASS_ETYPE_2)) #define TCAM_L3_CLASS_VALID(class) \ ((class >= TCAM_CLASS_IP_USER_4) && (class <= TCAM_CLASS_SCTP_IPV6)) #define TCAM_L3_CLASS_VALID_RFNL(class) \ ((TCAM_L3_CLASS_VALID(class)) || class == TCAM_CLASS_IPV6_FRAG) #define TCAM_CLASS_VALID(class) \ ((class >= TCAM_CLASS_ETYPE_1) && (class <= TCAM_CLASS_RARP)) uint64_t fflp_fzc_offset[] = { FFLP_ENET_VLAN_TBL_REG, FFLP_L2_CLS_ENET1_REG, FFLP_L2_CLS_ENET2_REG, FFLP_TCAM_KEY_IP_USR4_REG, FFLP_TCAM_KEY_IP_USR5_REG, FFLP_TCAM_KEY_IP_USR6_REG, FFLP_TCAM_KEY_IP_USR7_REG, FFLP_TCAM_KEY_IP4_TCP_REG, FFLP_TCAM_KEY_IP4_UDP_REG, FFLP_TCAM_KEY_IP4_AH_ESP_REG, FFLP_TCAM_KEY_IP4_SCTP_REG, FFLP_TCAM_KEY_IP6_TCP_REG, FFLP_TCAM_KEY_IP6_UDP_REG, FFLP_TCAM_KEY_IP6_AH_ESP_REG, FFLP_TCAM_KEY_IP6_SCTP_REG, FFLP_TCAM_KEY_0_REG, FFLP_TCAM_KEY_1_REG, FFLP_TCAM_KEY_2_REG, FFLP_TCAM_KEY_3_REG, FFLP_TCAM_MASK_0_REG, FFLP_TCAM_MASK_1_REG, FFLP_TCAM_MASK_2_REG, FFLP_TCAM_MASK_3_REG, FFLP_TCAM_CTL_REG, FFLP_VLAN_PAR_ERR_REG, FFLP_TCAM_ERR_REG, HASH_LKUP_ERR_LOG1_REG, HASH_LKUP_ERR_LOG2_REG, FFLP_FCRAM_ERR_TST0_REG, FFLP_FCRAM_ERR_TST1_REG, FFLP_FCRAM_ERR_TST2_REG, FFLP_ERR_MSK_REG, FFLP_CFG_1_REG, FFLP_DBG_TRAIN_VCT_REG, FFLP_TCP_CFLAG_MSK_REG, FFLP_FCRAM_REF_TMR_REG, FFLP_FLOW_KEY_IP_USR4_REG, FFLP_FLOW_KEY_IP_USR5_REG, FFLP_FLOW_KEY_IP_USR6_REG, FFLP_FLOW_KEY_IP_USR7_REG, FFLP_FLOW_KEY_IP4_TCP_REG, FFLP_FLOW_KEY_IP4_UDP_REG, FFLP_FLOW_KEY_IP4_AH_ESP_REG, FFLP_FLOW_KEY_IP4_SCTP_REG, FFLP_FLOW_KEY_IP6_TCP_REG, FFLP_FLOW_KEY_IP6_UDP_REG, FFLP_FLOW_KEY_IP6_AH_ESP_REG, FFLP_FLOW_KEY_IP6_SCTP_REG, FFLP_H1POLY_REG, FFLP_H2POLY_REG, FFLP_FLW_PRT_SEL_REG }; const char *fflp_fzc_name[] = { "FFLP_ENET_VLAN_TBL_REG", "FFLP_L2_CLS_ENET1_REG", "FFLP_L2_CLS_ENET2_REG", "FFLP_TCAM_KEY_IP_USR4_REG", "FFLP_TCAM_KEY_IP_USR5_REG", "FFLP_TCAM_KEY_IP_USR6_REG", "FFLP_TCAM_KEY_IP_USR7_REG", "FFLP_TCAM_KEY_IP4_TCP_REG", "FFLP_TCAM_KEY_IP4_UDP_REG", "FFLP_TCAM_KEY_IP4_AH_ESP_REG", "FFLP_TCAM_KEY_IP4_SCTP_REG", "FFLP_TCAM_KEY_IP6_TCP_REG", "FFLP_TCAM_KEY_IP6_UDP_REG", "FFLP_TCAM_KEY_IP6_AH_ESP_REG", "FFLP_TCAM_KEY_IP6_SCTP_REG", "FFLP_TCAM_KEY_0_REG", "FFLP_TCAM_KEY_1_REG", "FFLP_TCAM_KEY_2_REG", "FFLP_TCAM_KEY_3_REG", "FFLP_TCAM_MASK_0_REG", "FFLP_TCAM_MASK_1_REG", "FFLP_TCAM_MASK_2_REG", "FFLP_TCAM_MASK_3_REG", "FFLP_TCAM_CTL_REG", "FFLP_VLAN_PAR_ERR_REG", "FFLP_TCAM_ERR_REG", "HASH_LKUP_ERR_LOG1_REG", "HASH_LKUP_ERR_LOG2_REG", "FFLP_FCRAM_ERR_TST0_REG", "FFLP_FCRAM_ERR_TST1_REG", "FFLP_FCRAM_ERR_TST2_REG", "FFLP_ERR_MSK_REG", "FFLP_CFG_1_REG", "FFLP_DBG_TRAIN_VCT_REG", "FFLP_TCP_CFLAG_MSK_REG", "FFLP_FCRAM_REF_TMR_REG", "FFLP_FLOW_KEY_IP_USR4_REG", "FFLP_FLOW_KEY_IP_USR5_REG", "FFLP_FLOW_KEY_IP_USR6_REG", "FFLP_FLOW_KEY_IP_USR7_REG", "FFLP_FLOW_KEY_IP4_TCP_REG", "FFLP_FLOW_KEY_IP4_UDP_REG", "FFLP_FLOW_KEY_IP4_AH_ESP_REG", "FFLP_FLOW_KEY_IP4_SCTP_REG", "FFLP_FLOW_KEY_IP6_TCP_REG", "FFLP_FLOW_KEY_IP6_UDP_REG", "FFLP_FLOW_KEY_IP6_AH_ESP_REG", "FFLP_FLOW_KEY_IP6_SCTP_REG", "FFLP_H1POLY_REG", "FFLP_H2POLY_REG", "FFLP_FLW_PRT_SEL_REG" }; uint64_t fflp_reg_offset[] = { FFLP_HASH_TBL_ADDR_REG, FFLP_HASH_TBL_DATA_REG, FFLP_HASH_TBL_DATA_LOG_REG }; const char *fflp_reg_name[] = { "FFLP_HASH_TBL_ADDR_REG", "FFLP_HASH_TBL_DATA_REG", "FFLP_HASH_TBL_DATA_LOG_REG" }; npi_status_t npi_fflp_dump_regs(npi_handle_t handle) { uint64_t value; int num_regs, i; num_regs = sizeof (fflp_fzc_offset) / sizeof (uint64_t); NPI_REG_DUMP_MSG((handle.function, NPI_REG_CTL, "\nFFLP_FZC Register Dump \n")); for (i = 0; i < num_regs; i++) { REG_PIO_READ64(handle, fflp_fzc_offset[i], &value); NPI_REG_DUMP_MSG((handle.function, NPI_REG_CTL, " %8llx %s\t %8llx \n", fflp_fzc_offset[i], fflp_fzc_name[i], value)); } NPI_REG_DUMP_MSG((handle.function, NPI_REG_CTL, "\nFFLP Register Dump\n")); num_regs = sizeof (fflp_reg_offset) / sizeof (uint64_t); for (i = 0; i < num_regs; i++) { REG_PIO_READ64(handle, fflp_reg_offset[i], &value); NPI_REG_DUMP_MSG((handle.function, NPI_REG_CTL, " %8llx %s\t %8llx \n", fflp_reg_offset[i], fflp_reg_name[i], value)); } NPI_REG_DUMP_MSG((handle.function, NPI_REG_CTL, "\n FFLP Register Dump done\n")); return (NPI_SUCCESS); } void npi_fflp_vlan_tbl_dump(npi_handle_t handle) { uint64_t offset; vlan_id_t vlan_id; uint64_t value; vlan_id_t start = 0, stop = NXGE_MAX_VLANS; NPI_REG_DUMP_MSG((handle.function, NPI_REG_CTL, "\nVlan Table Dump \n")); NPI_REG_DUMP_MSG((handle.function, NPI_REG_CTL, "VID\t Offset\t Value\n")); for (vlan_id = start; vlan_id < stop; vlan_id++) { offset = FFLP_VLAN_OFFSET(vlan_id, FFLP_ENET_VLAN_TBL_REG); REG_PIO_READ64(handle, offset, &value); NPI_REG_DUMP_MSG((handle.function, NPI_REG_CTL, "%x\t %llx\t %llx\n", vlan_id, offset, value)); } } static uint64_t npi_fflp_tcam_check_completion(npi_handle_t handle, tcam_op_t op_type); /* * npi_fflp_tcam_check_completion() * Returns TCAM completion status. * * Input: * op_type : Read, Write, Compare * handle : OS specific handle * * Output: * For Read and write operations: * 0 Successful * -1 Fail/timeout * * For Compare operations (debug only ) * TCAM_REG_CTL read value on success * value contains match location * NPI_TCAM_COMP_NO_MATCH no match * */ static uint64_t npi_fflp_tcam_check_completion(npi_handle_t handle, tcam_op_t op_type) { uint32_t try_counter, tcam_delay = 10; tcam_ctl_t tctl; try_counter = TCAM_COMPLETION_TRY_COUNT; switch (op_type) { case TCAM_RWC_STAT: READ_TCAM_REG_CTL(handle, &tctl.value); while ((try_counter) && (tctl.bits.ldw.stat != TCAM_CTL_RWC_RWC_STAT)) { try_counter--; NXGE_DELAY(tcam_delay); READ_TCAM_REG_CTL(handle, &tctl.value); } if (!try_counter) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " TCAM RWC_STAT operation" " failed to complete \n")); return (NPI_FFLP_TCAM_HW_ERROR); } tctl.value = 0; break; case TCAM_RWC_MATCH: READ_TCAM_REG_CTL(handle, &tctl.value); while ((try_counter) && (tctl.bits.ldw.match != TCAM_CTL_RWC_RWC_MATCH)) { try_counter--; NXGE_DELAY(tcam_delay); READ_TCAM_REG_CTL(handle, &tctl.value); } if (!try_counter) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " TCAM Match operation" "failed to find match \n")); tctl.value = NPI_TCAM_COMP_NO_MATCH; } break; default: NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " Invalid TCAM completion Request \n")); return (NPI_FFLP_ERROR | NPI_TCAM_ERROR | OPCODE_INVALID); } return (tctl.value); } /* * npi_fflp_tcam_entry_invalidate() * * invalidates entry at tcam location * * Input * handle : OS specific handle * location : TCAM location * * Return * NPI_SUCCESS * NPI_FFLP_TCAM_HW_ERROR * */ npi_status_t npi_fflp_tcam_entry_invalidate(npi_handle_t handle, tcam_location_t location) { tcam_ctl_t tctl, tctl_stat; /* * Need to write zero to class field. * Class field is bits [195:191]. * This corresponds to TCAM key 0 register * */ WRITE_TCAM_REG_MASK0(handle, 0xffULL); WRITE_TCAM_REG_KEY0(handle, 0x0ULL); tctl.value = 0; tctl.bits.ldw.location = location; tctl.bits.ldw.rwc = TCAM_CTL_RWC_TCAM_WR; WRITE_TCAM_REG_CTL(handle, tctl.value); tctl_stat.value = npi_fflp_tcam_check_completion(handle, TCAM_RWC_STAT); if (tctl_stat.value & NPI_FAILURE) return (NPI_FFLP_TCAM_HW_ERROR); return (NPI_SUCCESS); } /* * npi_fflp_tcam_entry_match() * * lookup a tcam entry in the TCAM * * Input * handle : OS specific handle * tcam_ptr : TCAM entry ptr * * Return * * NPI_FAILURE | NPI_XX_ERROR: Operational Error (HW etc ...) * NPI_TCAM_NO_MATCH: no match * 0 - TCAM_SIZE: matching entry location (if match) */ int npi_fflp_tcam_entry_match(npi_handle_t handle, tcam_entry_t *tcam_ptr) { uint64_t tcam_stat = 0; tcam_ctl_t tctl, tctl_stat; WRITE_TCAM_REG_MASK0(handle, tcam_ptr->mask0); WRITE_TCAM_REG_MASK1(handle, tcam_ptr->mask1); WRITE_TCAM_REG_MASK2(handle, tcam_ptr->mask2); WRITE_TCAM_REG_MASK3(handle, tcam_ptr->mask3); WRITE_TCAM_REG_KEY0(handle, tcam_ptr->key0); WRITE_TCAM_REG_KEY1(handle, tcam_ptr->key1); WRITE_TCAM_REG_KEY2(handle, tcam_ptr->key2); WRITE_TCAM_REG_KEY3(handle, tcam_ptr->key3); tctl.value = 0; tctl.bits.ldw.rwc = TCAM_CTL_RWC_TCAM_CMP; WRITE_TCAM_REG_CTL(handle, tctl.value); tcam_stat = npi_fflp_tcam_check_completion(handle, TCAM_RWC_STAT); if (tcam_stat & NPI_FAILURE) { return ((uint32_t)tcam_stat); } tctl_stat.value = npi_fflp_tcam_check_completion(handle, TCAM_RWC_MATCH); if (tctl_stat.bits.ldw.match == TCAM_CTL_RWC_RWC_MATCH) { return (uint32_t)(tctl_stat.bits.ldw.location); } return ((uint32_t)tctl_stat.value); } /* * npi_fflp_tcam_entry_read () * * Reads a tcam entry from the TCAM location, location * * Input: * handle : OS specific handle * location : TCAM location * tcam_ptr : TCAM entry pointer * * Return: * NPI_SUCCESS * NPI_FFLP_TCAM_RD_ERROR * */ npi_status_t npi_fflp_tcam_entry_read(npi_handle_t handle, tcam_location_t location, struct tcam_entry *tcam_ptr) { uint64_t tcam_stat; tcam_ctl_t tctl; tctl.value = 0; tctl.bits.ldw.location = location; tctl.bits.ldw.rwc = TCAM_CTL_RWC_TCAM_RD; WRITE_TCAM_REG_CTL(handle, tctl.value); tcam_stat = npi_fflp_tcam_check_completion(handle, TCAM_RWC_STAT); if (tcam_stat & NPI_FAILURE) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, "TCAM read failed loc %d \n", location)); return (NPI_FFLP_TCAM_RD_ERROR); } READ_TCAM_REG_MASK0(handle, &tcam_ptr->mask0); READ_TCAM_REG_MASK1(handle, &tcam_ptr->mask1); READ_TCAM_REG_MASK2(handle, &tcam_ptr->mask2); READ_TCAM_REG_MASK3(handle, &tcam_ptr->mask3); READ_TCAM_REG_KEY0(handle, &tcam_ptr->key0); READ_TCAM_REG_KEY1(handle, &tcam_ptr->key1); READ_TCAM_REG_KEY2(handle, &tcam_ptr->key2); READ_TCAM_REG_KEY3(handle, &tcam_ptr->key3); return (NPI_SUCCESS); } /* * npi_fflp_tcam_entry_write() * * writes a tcam entry to the TCAM location, location * * Input: * handle : OS specific handle * location : TCAM location * tcam_ptr : TCAM entry pointer * * Return: * NPI_SUCCESS * NPI_FFLP_TCAM_WR_ERROR * */ npi_status_t npi_fflp_tcam_entry_write(npi_handle_t handle, tcam_location_t location, tcam_entry_t *tcam_ptr) { uint64_t tcam_stat; tcam_ctl_t tctl; WRITE_TCAM_REG_MASK0(handle, tcam_ptr->mask0); WRITE_TCAM_REG_MASK1(handle, tcam_ptr->mask1); WRITE_TCAM_REG_MASK2(handle, tcam_ptr->mask2); WRITE_TCAM_REG_MASK3(handle, tcam_ptr->mask3); WRITE_TCAM_REG_KEY0(handle, tcam_ptr->key0); WRITE_TCAM_REG_KEY1(handle, tcam_ptr->key1); WRITE_TCAM_REG_KEY2(handle, tcam_ptr->key2); WRITE_TCAM_REG_KEY3(handle, tcam_ptr->key3); NPI_DEBUG_MSG((handle.function, NPI_FFLP_CTL, " tcam write: location %x\n" " key: %llx %llx %llx %llx \n" " mask: %llx %llx %llx %llx \n", location, tcam_ptr->key0, tcam_ptr->key1, tcam_ptr->key2, tcam_ptr->key3, tcam_ptr->mask0, tcam_ptr->mask1, tcam_ptr->mask2, tcam_ptr->mask3)); tctl.value = 0; tctl.bits.ldw.location = location; tctl.bits.ldw.rwc = TCAM_CTL_RWC_TCAM_WR; NPI_DEBUG_MSG((handle.function, NPI_FFLP_CTL, " tcam write: ctl value %llx \n", tctl.value)); WRITE_TCAM_REG_CTL(handle, tctl.value); tcam_stat = npi_fflp_tcam_check_completion(handle, TCAM_RWC_STAT); if (tcam_stat & NPI_FAILURE) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, "TCAM Write failed loc %d \n", location)); return (NPI_FFLP_TCAM_WR_ERROR); } return (NPI_SUCCESS); } /* * npi_fflp_tcam_asc_ram_entry_write() * * writes a tcam associatedRAM at the TCAM location, location * * Input: * handle : OS specific handle * location : tcam associatedRAM location * ram_data : Value to write * * Return: * NPI_SUCCESS * NPI_FFLP_ASC_RAM_WR_ERROR * */ npi_status_t npi_fflp_tcam_asc_ram_entry_write(npi_handle_t handle, tcam_location_t location, uint64_t ram_data) { uint64_t tcam_stat = 0; tcam_ctl_t tctl; WRITE_TCAM_REG_KEY1(handle, ram_data); tctl.value = 0; tctl.bits.ldw.location = location; tctl.bits.ldw.rwc = TCAM_CTL_RWC_RAM_WR; NPI_DEBUG_MSG((handle.function, NPI_FFLP_CTL, " tcam ascr write: location %x data %llx ctl value %llx \n", location, ram_data, tctl.value)); WRITE_TCAM_REG_CTL(handle, tctl.value); tcam_stat = npi_fflp_tcam_check_completion(handle, TCAM_RWC_STAT); if (tcam_stat & NPI_FAILURE) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, "TCAM RAM write failed loc %d \n", location)); return (NPI_FFLP_ASC_RAM_WR_ERROR); } return (NPI_SUCCESS); } /* * npi_fflp_tcam_asc_ram_entry_read() * * reads a tcam associatedRAM content at the TCAM location, location * * Input: * handle : OS specific handle * location : tcam associatedRAM location * ram_data : ptr to return contents * * Return: * NPI_SUCCESS * NPI_FFLP_ASC_RAM_RD_ERROR * */ npi_status_t npi_fflp_tcam_asc_ram_entry_read(npi_handle_t handle, tcam_location_t location, uint64_t *ram_data) { uint64_t tcam_stat; tcam_ctl_t tctl; tctl.value = 0; tctl.bits.ldw.location = location; tctl.bits.ldw.rwc = TCAM_CTL_RWC_RAM_RD; WRITE_TCAM_REG_CTL(handle, tctl.value); tcam_stat = npi_fflp_tcam_check_completion(handle, TCAM_RWC_STAT); if (tcam_stat & NPI_FAILURE) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, "TCAM RAM read failed loc %d \n", location)); return (NPI_FFLP_ASC_RAM_RD_ERROR); } READ_TCAM_REG_KEY1(handle, ram_data); return (NPI_SUCCESS); } /* FFLP FCRAM Related functions */ /* The following are FCRAM datapath functions */ /* * npi_fflp_fcram_entry_write () * Populates an FCRAM entry * Inputs: * handle: opaque handle interpreted by the underlying OS * partid: Partition ID * location: Index to the FCRAM. * Corresponds to last 20 bits of H1 value * fcram_ptr: Pointer to the FCRAM contents to be used for writing * format: Entry Format. Determines the size of the write. * FCRAM_ENTRY_OPTIM: 8 bytes (a 64 bit write) * FCRAM_ENTRY_EX_IP4: 32 bytes (4 X 64 bit write) * FCRAM_ENTRY_EX_IP6: 56 bytes (7 X 64 bit write) * * Outputs: * NPI success/failure status code */ npi_status_t npi_fflp_fcram_entry_write(npi_handle_t handle, part_id_t partid, uint32_t location, fcram_entry_t *fcram_ptr, fcram_entry_format_t format) { int num_subareas = 0; uint64_t addr_reg, data_reg; int subarea; int autoinc; hash_tbl_addr_t addr; switch (format) { case FCRAM_ENTRY_OPTIM: if (location % 8) { /* need to be 8 byte aligned */ NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " FCRAM_ENTRY_OOPTIM Write:" " unaligned location %llx \n", location)); return (NPI_FFLP_FCRAM_LOC_INVALID); } num_subareas = 1; autoinc = 0; break; case FCRAM_ENTRY_EX_IP4: if (location % 32) { /* need to be 32 byte aligned */ NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " FCRAM_ENTRY_EX_IP4 Write:" " unaligned location %llx \n", location)); return (NPI_FFLP_FCRAM_LOC_INVALID); } num_subareas = 4; autoinc = 1; break; case FCRAM_ENTRY_EX_IP6: if (location % 64) { /* need to be 64 byte aligned */ NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " FCRAM_ENTRY_EX_IP6 Write:" " unaligned location %llx \n", location)); return (NPI_FFLP_FCRAM_LOC_INVALID); } num_subareas = 7; autoinc = 1; break; default: NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " fcram_entry_write:" " unknown format param location %llx\n", location)); return (NPI_FFLP_ERROR | NPI_FCRAM_ERROR | OPCODE_INVALID); } addr.value = 0; addr.bits.ldw.autoinc = autoinc; addr.bits.ldw.addr = location; addr_reg = GET_HASHTBL_PART_OFFSET(handle, partid, FFLP_HASH_TBL_ADDR_REG); data_reg = GET_HASHTBL_PART_OFFSET(handle, partid, FFLP_HASH_TBL_DATA_REG); /* write to addr reg */ REG_PIO_WRITE64(handle, addr_reg, addr.value); /* write data to the data register */ for (subarea = 0; subarea < num_subareas; subarea++) { REG_PIO_WRITE64(handle, data_reg, fcram_ptr->value[subarea]); } return (NPI_SUCCESS); } /* * npi_fflp_fcram_read_read () * Reads an FCRAM entry * Inputs: * handle: opaque handle interpreted by the underlying OS * partid: Partition ID * location: Index to the FCRAM. * Corresponds to last 20 bits of H1 value * * fcram_ptr: Pointer to the FCRAM contents to be updated * format: Entry Format. Determines the size of the read. * FCRAM_ENTRY_OPTIM: 8 bytes (a 64 bit read) * FCRAM_ENTRY_EX_IP4: 32 bytes (4 X 64 bit read ) * FCRAM_ENTRY_EX_IP6: 56 bytes (7 X 64 bit read ) * Return: * NPI Success/Failure status code * */ npi_status_t npi_fflp_fcram_entry_read(npi_handle_t handle, part_id_t partid, uint32_t location, fcram_entry_t *fcram_ptr, fcram_entry_format_t format) { int num_subareas = 0; uint64_t addr_reg, data_reg; int subarea, autoinc; hash_tbl_addr_t addr; switch (format) { case FCRAM_ENTRY_OPTIM: if (location % 8) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " FCRAM_ENTRY_OOPTIM Read:" " unaligned location %llx \n", location)); /* need to be 8 byte aligned */ return (NPI_FFLP_FCRAM_LOC_INVALID); } num_subareas = 1; autoinc = 0; break; case FCRAM_ENTRY_EX_IP4: if (location % 32) { /* need to be 32 byte aligned */ NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " FCRAM_ENTRY_EX_IP4 READ:" " unaligned location %llx \n", location)); return (NPI_FFLP_FCRAM_LOC_INVALID); } num_subareas = 4; autoinc = 1; break; case FCRAM_ENTRY_EX_IP6: if (location % 64) { /* need to be 64 byte aligned */ NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " FCRAM_ENTRY_EX_IP6 READ:" " unaligned location %llx \n", location)); return (NPI_FFLP_FCRAM_LOC_INVALID); } num_subareas = 7; autoinc = 1; break; default: NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " fcram_entry_read:" " unknown format param location %llx\n", location)); return (NPI_FFLP_SW_PARAM_ERROR); } addr.value = 0; addr.bits.ldw.autoinc = autoinc; addr.bits.ldw.addr = location; addr_reg = GET_HASHTBL_PART_OFFSET(handle, partid, FFLP_HASH_TBL_ADDR_REG); data_reg = GET_HASHTBL_PART_OFFSET(handle, partid, FFLP_HASH_TBL_DATA_REG); /* write to addr reg */ REG_PIO_WRITE64(handle, addr_reg, addr.value); /* read data from the data register */ for (subarea = 0; subarea < num_subareas; subarea++) { REG_PIO_READ64(handle, data_reg, &fcram_ptr->value[subarea]); } return (NPI_SUCCESS); } /* * npi_fflp_fcram_entry_invalidate () * Invalidate FCRAM entry at the given location * Inputs: * handle: opaque handle interpreted by the underlying OS * partid: Partition ID * location: location of the FCRAM/hash entry. * * Return: * NPI Success/Failure status code */ npi_status_t npi_fflp_fcram_entry_invalidate(npi_handle_t handle, part_id_t partid, uint32_t location) { hash_tbl_addr_t addr; uint64_t addr_reg, data_reg; hash_hdr_t hdr; if (location % 8) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " FCRAM_ENTRY_Invalidate:" " unaligned location %llx \n", location)); /* need to be 8 byte aligned */ return (NPI_FFLP_FCRAM_LOC_INVALID); } addr.value = 0; addr.bits.ldw.addr = location; addr_reg = GET_HASHTBL_PART_OFFSET(handle, partid, FFLP_HASH_TBL_ADDR_REG); data_reg = GET_HASHTBL_PART_OFFSET(handle, partid, FFLP_HASH_TBL_DATA_REG); /* write to addr reg */ REG_PIO_WRITE64(handle, addr_reg, addr.value); REG_PIO_READ64(handle, data_reg, &hdr.value); hdr.exact_hdr.valid = 0; REG_PIO_WRITE64(handle, data_reg, hdr.value); return (NPI_SUCCESS); } /* * npi_fflp_fcram_write_subarea () * Writes to FCRAM entry subarea i.e the 8 bytes within the 64 bytes * pointed by the last 20 bits of H1. Effectively, this accesses * specific 8 bytes within the hash table bucket. * * H1--> |-----------------| * | subarea 0 | * |_________________| * | Subarea 1 | * |_________________| * | ....... | * |_________________| * | Subarea 7 | * |_________________| * * Inputs: * handle: opaque handle interpreted by the underlying OS * partid: Partition ID * location: location of the subarea. It is derived from: * Bucket = [19:15][14:0] (20 bits of H1) * location = (Bucket << 3 ) + subarea * 8 * = [22:18][17:3] || subarea * 8 * data: Data * * Return: * NPI Success/Failure status code */ npi_status_t npi_fflp_fcram_subarea_write(npi_handle_t handle, part_id_t partid, uint32_t location, uint64_t data) { hash_tbl_addr_t addr; uint64_t addr_reg, data_reg; if (location % 8) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " fcram_subarea_write:" " unaligned location %llx \n", location)); /* need to be 8 byte aligned */ return (NPI_FFLP_FCRAM_LOC_INVALID); } addr.value = 0; addr.bits.ldw.addr = location; addr_reg = GET_HASHTBL_PART_OFFSET(handle, partid, FFLP_HASH_TBL_ADDR_REG); data_reg = GET_HASHTBL_PART_OFFSET(handle, partid, FFLP_HASH_TBL_DATA_REG); /* write to addr reg */ REG_PIO_WRITE64(handle, addr_reg, addr.value); REG_PIO_WRITE64(handle, data_reg, data); return (NPI_SUCCESS); } /* * npi_fflp_fcram_subarea_read () * Reads an FCRAM entry subarea i.e the 8 bytes within the 64 bytes * pointed by the last 20 bits of H1. Effectively, this accesses * specific 8 bytes within the hash table bucket. * * H1--> |-----------------| * | subarea 0 | * |_________________| * | Subarea 1 | * |_________________| * | ....... | * |_________________| * | Subarea 7 | * |_________________| * * Inputs: * handle: opaque handle interpreted by the underlying OS * partid: Partition ID * location: location of the subarea. It is derived from: * Bucket = [19:15][14:0] (20 bits of H1) * location = (Bucket << 3 ) + subarea * 8 * = [22:18][17:3] || subarea * 8 * data: ptr do write subarea contents to. * * Return: * NPI Success/Failure status code */ npi_status_t npi_fflp_fcram_subarea_read(npi_handle_t handle, part_id_t partid, uint32_t location, uint64_t *data) { hash_tbl_addr_t addr; uint64_t addr_reg, data_reg; if (location % 8) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " fcram_subarea_read:" " unaligned location %llx \n", location)); /* need to be 8 byte aligned */ return (NPI_FFLP_FCRAM_LOC_INVALID); } addr.value = 0; addr.bits.ldw.addr = location; addr_reg = GET_HASHTBL_PART_OFFSET(handle, partid, FFLP_HASH_TBL_ADDR_REG); data_reg = GET_HASHTBL_PART_OFFSET(handle, partid, FFLP_HASH_TBL_DATA_REG); /* write to addr reg */ REG_PIO_WRITE64(handle, addr_reg, addr.value); REG_PIO_READ64(handle, data_reg, data); return (NPI_SUCCESS); } /* * The following are zero function fflp configuration functions. */ /* * npi_fflp_fcram_config_partition() * Partitions and configures the FCRAM */ npi_status_t npi_fflp_cfg_fcram_partition(npi_handle_t handle, part_id_t partid, uint8_t base_mask, uint8_t base_reloc) { /* * assumes that the base mask and relocation are computed somewhere * and kept in the state data structure. Alternativiely, one can pass * a partition size and a starting address and this routine can compute * the mask and reloc vlaues. */ flow_prt_sel_t sel; uint64_t offset; ASSERT(FCRAM_PARTITION_VALID(partid)); if (!FCRAM_PARTITION_VALID(partid)) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " npi_fflp_cfg_fcram_partition:" " Invalid Partition %d \n", partid)); return (NPI_FFLP_FCRAM_PART_INVALID); } offset = FFLP_PART_OFFSET(partid, FFLP_FLW_PRT_SEL_REG); sel.value = 0; sel.bits.ldw.mask = base_mask; sel.bits.ldw.base = base_reloc; sel.bits.ldw.ext = BIT_DISABLE; /* disable */ REG_PIO_WRITE64(handle, offset, sel.value); return (NPI_SUCCESS); } /* * npi_fflp_fcram_partition_enable * Enable previously configured FCRAM partition * * Input * handle: opaque handle interpreted by the underlying OS * partid: partition ID, Corresponds to the RDC table * * Return * 0 Successful * Non zero error code Enable failed, and reason. * */ npi_status_t npi_fflp_cfg_fcram_partition_enable (npi_handle_t handle, part_id_t partid) { flow_prt_sel_t sel; uint64_t offset; ASSERT(FCRAM_PARTITION_VALID(partid)); if (!FCRAM_PARTITION_VALID(partid)) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " fcram_partition enable:" " Invalid Partition %d \n", partid)); return (NPI_FFLP_FCRAM_PART_INVALID); } offset = FFLP_PART_OFFSET(partid, FFLP_FLW_PRT_SEL_REG); REG_PIO_READ64(handle, offset, &sel.value); sel.bits.ldw.ext = BIT_ENABLE; /* enable */ REG_PIO_WRITE64(handle, offset, sel.value); return (NPI_SUCCESS); } /* * npi_fflp_fcram_partition_disable * Disable previously configured FCRAM partition * * Input * handle: opaque handle interpreted by the underlying OS * partid: partition ID, Corresponds to the RDC table * * Return: * NPI Success/Failure status code */ npi_status_t npi_fflp_cfg_fcram_partition_disable(npi_handle_t handle, part_id_t partid) { flow_prt_sel_t sel; uint64_t offset; ASSERT(FCRAM_PARTITION_VALID(partid)); if (!FCRAM_PARTITION_VALID(partid)) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " fcram_partition disable:" " Invalid Partition %d \n", partid)); return (NPI_FFLP_FCRAM_PART_INVALID); } offset = FFLP_PART_OFFSET(partid, FFLP_FLW_PRT_SEL_REG); REG_PIO_READ64(handle, offset, &sel.value); sel.bits.ldw.ext = BIT_DISABLE; /* disable */ REG_PIO_WRITE64(handle, offset, sel.value); return (NPI_SUCCESS); } /* * npi_fflp_cam_errorcheck_disable * Disables FCRAM and TCAM error checking */ npi_status_t npi_fflp_cfg_cam_errorcheck_disable(npi_handle_t handle) { fflp_cfg_1_t fflp_cfg; uint64_t offset; offset = FFLP_CFG_1_REG; REG_PIO_READ64(handle, offset, &fflp_cfg.value); fflp_cfg.bits.ldw.errordis = BIT_ENABLE; REG_PIO_WRITE64(handle, offset, fflp_cfg.value); return (NPI_SUCCESS); } /* * npi_fflp_cam_errorcheck_enable * Enables FCRAM and TCAM error checking */ npi_status_t npi_fflp_cfg_cam_errorcheck_enable(npi_handle_t handle) { fflp_cfg_1_t fflp_cfg; uint64_t offset; offset = FFLP_CFG_1_REG; REG_PIO_READ64(handle, offset, &fflp_cfg.value); fflp_cfg.bits.ldw.errordis = BIT_DISABLE; REG_PIO_WRITE64(handle, offset, fflp_cfg.value); return (NPI_SUCCESS); } /* * npi_fflp_cam_llcsnap_enable * Enables input parser llcsnap recognition */ npi_status_t npi_fflp_cfg_llcsnap_enable(npi_handle_t handle) { fflp_cfg_1_t fflp_cfg; uint64_t offset; offset = FFLP_CFG_1_REG; REG_PIO_READ64(handle, offset, &fflp_cfg.value); fflp_cfg.bits.ldw.llcsnap = BIT_ENABLE; REG_PIO_WRITE64(handle, offset, fflp_cfg.value); return (NPI_SUCCESS); } /* * npi_fflp_cam_llcsnap_disable * Disables input parser llcsnap recognition */ npi_status_t npi_fflp_cfg_llcsnap_disable(npi_handle_t handle) { fflp_cfg_1_t fflp_cfg; uint64_t offset; offset = FFLP_CFG_1_REG; REG_PIO_READ64(handle, offset, &fflp_cfg.value); fflp_cfg.bits.ldw.llcsnap = BIT_DISABLE; REG_PIO_WRITE64(handle, offset, fflp_cfg.value); return (NPI_SUCCESS); } /* * npi_fflp_config_fcram_refresh * Set FCRAM min and max refresh time. * * Input * handle opaque handle interpreted by the underlying OS * min_time Minimum Refresh time count * max_time maximum Refresh Time count * sys_time System Clock rate * * The counters are 16 bit counters. The maximum refresh time is * 3.9us/clock cycle. The minimum is 400ns/clock cycle. * Clock cycle is the FCRAM clock cycle????? * If the cycle is FCRAM clock cycle, then sys_time parameter * is not needed as there wont be configuration variation due to * system clock cycle. * * Return: * NPI Success/Failure status code */ npi_status_t npi_fflp_cfg_fcram_refresh_time(npi_handle_t handle, uint32_t min_time, uint32_t max_time, uint32_t sys_time) { uint64_t offset; fcram_ref_tmr_t refresh_timer_reg; uint16_t max, min; offset = FFLP_FCRAM_REF_TMR_REG; /* need to figure out how to dervive the numbers */ max = max_time * sys_time; min = min_time * sys_time; /* for now, just set with #def values */ max = FCRAM_REFRESH_DEFAULT_MAX_TIME; min = FCRAM_REFRESH_DEFAULT_MIN_TIME; REG_PIO_READ64(handle, offset, &refresh_timer_reg.value); refresh_timer_reg.bits.ldw.min = min; refresh_timer_reg.bits.ldw.max = max; REG_PIO_WRITE64(handle, offset, refresh_timer_reg.value); return (NPI_SUCCESS); } /* * npi_fflp_hash_lookup_err_report * Reports hash table (fcram) lookup errors * * Input * handle opaque handle interpreted by the underlying OS * err_stat Pointer to return Error bits * * * Return: * NPI success/failure status code */ npi_status_t npi_fflp_fcram_get_lookup_err_log(npi_handle_t handle, hash_lookup_err_log_t *err_stat) { hash_lookup_err_log1_t err_log1; hash_lookup_err_log2_t err_log2; uint64_t err_log1_offset, err_log2_offset; err_log1.value = 0; err_log2.value = 0; err_log1_offset = HASH_LKUP_ERR_LOG1_REG; err_log2_offset = HASH_LKUP_ERR_LOG2_REG; REG_PIO_READ64(handle, err_log1_offset, &err_log1.value); REG_PIO_READ64(handle, err_log2_offset, &err_log2.value); if (err_log1.value) { /* nonzero means there are some errors */ err_stat->lookup_err = BIT_ENABLE; err_stat->syndrome = err_log2.bits.ldw.syndrome; err_stat->subarea = err_log2.bits.ldw.subarea; err_stat->h1 = err_log2.bits.ldw.h1; err_stat->multi_bit = err_log1.bits.ldw.mult_bit; err_stat->multi_lkup = err_log1.bits.ldw.mult_lk; err_stat->ecc_err = err_log1.bits.ldw.ecc_err; err_stat->uncor_err = err_log1.bits.ldw.cu; } else { err_stat->lookup_err = BIT_DISABLE; } return (NPI_SUCCESS); } /* * npi_fflp_fcram_get_pio_err_log * Reports hash table PIO read errors for the given partition. * by default, it clears the error bit which was set by the HW. * * Input * handle: opaque handle interpreted by the underlying OS * partid: partition ID * err_stat Pointer to return Error bits * * Return * NPI success/failure status code */ npi_status_t npi_fflp_fcram_get_pio_err_log(npi_handle_t handle, part_id_t partid, hash_pio_err_log_t *err_stat) { hash_tbl_data_log_t err_log; uint64_t offset; ASSERT(FCRAM_PARTITION_VALID(partid)); if (!FCRAM_PARTITION_VALID(partid)) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " fcram_get_pio_err_log:" " Invalid Partition %d \n", partid)); return (NPI_FFLP_FCRAM_PART_INVALID); } offset = GET_HASHTBL_PART_OFFSET_NVIR(partid, FFLP_HASH_TBL_DATA_LOG_REG); REG_PIO_READ64(handle, offset, &err_log.value); if (err_log.bits.ldw.pio_err == BIT_ENABLE) { /* nonzero means there are some errors */ err_stat->pio_err = BIT_ENABLE; err_stat->syndrome = err_log.bits.ldw.syndrome; err_stat->addr = err_log.bits.ldw.fcram_addr; err_log.value = 0; REG_PIO_WRITE64(handle, offset, err_log.value); } else { err_stat->pio_err = BIT_DISABLE; } return (NPI_SUCCESS); } /* * npi_fflp_fcram_clr_pio_err_log * Clears FCRAM PIO error status for the partition. * If there are TCAM errors as indicated by err bit set by HW, * then the SW will clear it by clearing the bit. * * Input * handle: opaque handle interpreted by the underlying OS * partid: partition ID * * * Return * NPI success/failure status code */ npi_status_t npi_fflp_fcram_clr_pio_err_log(npi_handle_t handle, part_id_t partid) { uint64_t offset; hash_tbl_data_log_t err_log; ASSERT(FCRAM_PARTITION_VALID(partid)); if (!FCRAM_PARTITION_VALID(partid)) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " fcram_clr_pio_err_log:" " Invalid Partition %d \n", partid)); return (NPI_FFLP_FCRAM_PART_INVALID); } offset = GET_HASHTBL_PART_OFFSET_NVIR(partid, FFLP_HASH_TBL_DATA_LOG_REG); err_log.value = 0; REG_PIO_WRITE64(handle, offset, err_log.value); return (NPI_SUCCESS); } /* * npi_fflp_tcam_get_err_log * Reports TCAM PIO read and lookup errors. * If there are TCAM errors as indicated by err bit set by HW, * then the SW will clear it by clearing the bit. * * Input * handle: opaque handle interpreted by the underlying OS * err_stat: structure to report various TCAM errors. * will be updated if there are TCAM errors. * * * Return * NPI_SUCCESS Success * * */ npi_status_t npi_fflp_tcam_get_err_log(npi_handle_t handle, tcam_err_log_t *err_stat) { tcam_err_t err_log; uint64_t offset; offset = FFLP_TCAM_ERR_REG; err_log.value = 0; REG_PIO_READ64(handle, offset, &err_log.value); if (err_log.bits.ldw.err == BIT_ENABLE) { /* non-zero means err */ err_stat->tcam_err = BIT_ENABLE; if (err_log.bits.ldw.p_ecc) { err_stat->parity_err = 0; err_stat->ecc_err = 1; } else { err_stat->parity_err = 1; err_stat->ecc_err = 0; } err_stat->syndrome = err_log.bits.ldw.syndrome; err_stat->location = err_log.bits.ldw.addr; err_stat->multi_lkup = err_log.bits.ldw.mult; /* now clear the error */ err_log.value = 0; REG_PIO_WRITE64(handle, offset, err_log.value); } else { err_stat->tcam_err = 0; } return (NPI_SUCCESS); } /* * npi_fflp_tcam_clr_err_log * Clears TCAM PIO read and lookup error status. * If there are TCAM errors as indicated by err bit set by HW, * then the SW will clear it by clearing the bit. * * Input * handle: opaque handle interpreted by the underlying OS * * * Return * NPI_SUCCESS Success * * */ npi_status_t npi_fflp_tcam_clr_err_log(npi_handle_t handle) { tcam_err_t err_log; uint64_t offset; offset = FFLP_TCAM_ERR_REG; err_log.value = 0; REG_PIO_WRITE64(handle, offset, err_log.value); return (NPI_SUCCESS); } /* * npi_fflp_fcram_err_synd_test * Tests the FCRAM error detection logic. * The error detection logic for the syndrome is tested. * tst0->synd (8bits) are set to select the syndrome bits * to be XOR'ed * * Input * handle: opaque handle interpreted by the underlying OS * syndrome_bits: Syndrome bits to select bits to be xor'ed * * * Return * NPI_SUCCESS Success * * */ npi_status_t npi_fflp_fcram_err_synd_test(npi_handle_t handle, uint8_t syndrome_bits) { uint64_t t0_offset; fcram_err_tst0_t tst0; t0_offset = FFLP_FCRAM_ERR_TST0_REG; tst0.value = 0; tst0.bits.ldw.syndrome_mask = syndrome_bits; REG_PIO_WRITE64(handle, t0_offset, tst0.value); return (NPI_SUCCESS); } /* * npi_fflp_fcram_err_data_test * Tests the FCRAM error detection logic. * The error detection logic for the datapath is tested. * bits [63:0] are set to select the data bits to be xor'ed * * Input * handle: opaque handle interpreted by the underlying OS * data: data bits to select bits to be xor'ed * * * Return * NPI_SUCCESS Success * * */ npi_status_t npi_fflp_fcram_err_data_test(npi_handle_t handle, fcram_err_data_t *data) { uint64_t t1_offset, t2_offset; fcram_err_tst1_t tst1; /* for data bits [31:0] */ fcram_err_tst2_t tst2; /* for data bits [63:32] */ t1_offset = FFLP_FCRAM_ERR_TST1_REG; t2_offset = FFLP_FCRAM_ERR_TST2_REG; tst1.value = 0; tst2.value = 0; tst1.bits.ldw.dat = data->bits.ldw.dat; tst2.bits.ldw.dat = data->bits.hdw.dat; REG_PIO_WRITE64(handle, t1_offset, tst1.value); REG_PIO_WRITE64(handle, t2_offset, tst2.value); return (NPI_SUCCESS); } /* * npi_fflp_cfg_enet_vlan_table_assoc * associates port vlan id to rdc table. * * Input * handle opaque handle interpreted by the underlying OS * mac_portn port number * vlan_id VLAN ID * rdc_table RDC Table # * priority priority * * Output * * NPI success/failure status code * */ npi_status_t npi_fflp_cfg_enet_vlan_table_assoc(npi_handle_t handle, uint8_t mac_portn, vlan_id_t vlan_id, uint8_t rdc_table, uint8_t priority) { fflp_enet_vlan_tbl_t cfg; uint64_t offset; uint8_t vlan_parity[8] = {0, 1, 1, 2, 1, 2, 2, 3}; uint8_t parity_bit; ASSERT(FFLP_VLAN_VALID(vlan_id)); if (!FFLP_VLAN_VALID(vlan_id)) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " fflp_cfg_enet_vlan_table:" " Invalid vlan ID %d \n", vlan_id)); return (NPI_FFLP_VLAN_INVALID); } ASSERT(FFLP_PORT_VALID(mac_portn)); if (!FFLP_PORT_VALID(mac_portn)) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " fflp_cfg_enet_vlan_table:" " Invalid port num %d \n", mac_portn)); return (NPI_FFLP_PORT_INVALID); } ASSERT(FFLP_RDC_TABLE_VALID(rdc_table)); if (!FFLP_RDC_TABLE_VALID(rdc_table)) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " fflp_cfg_enet_vlan_table:" " Invalid RDC Table %d \n", rdc_table)); return (NPI_FFLP_RDC_TABLE_INVALID); } offset = FFLP_VLAN_OFFSET(vlan_id, FFLP_ENET_VLAN_TBL_REG); REG_PIO_READ64(handle, offset, &cfg.value); switch (mac_portn) { case 0: cfg.bits.ldw.vlanrdctbln0 = rdc_table; if (priority) cfg.bits.ldw.vpr0 = BIT_ENABLE; else cfg.bits.ldw.vpr0 = BIT_DISABLE; /* set the parity bits */ parity_bit = vlan_parity[cfg.bits.ldw.vlanrdctbln0] + vlan_parity[cfg.bits.ldw.vlanrdctbln1] + cfg.bits.ldw.vpr0 + cfg.bits.ldw.vpr1; cfg.bits.ldw.parity0 = parity_bit & 0x1; break; case 1: cfg.bits.ldw.vlanrdctbln1 = rdc_table; if (priority) cfg.bits.ldw.vpr1 = BIT_ENABLE; else cfg.bits.ldw.vpr1 = BIT_DISABLE; /* set the parity bits */ parity_bit = vlan_parity[cfg.bits.ldw.vlanrdctbln0] + vlan_parity[cfg.bits.ldw.vlanrdctbln1] + cfg.bits.ldw.vpr0 + cfg.bits.ldw.vpr1; cfg.bits.ldw.parity0 = parity_bit & 0x1; break; case 2: cfg.bits.ldw.vlanrdctbln2 = rdc_table; if (priority) cfg.bits.ldw.vpr2 = BIT_ENABLE; else cfg.bits.ldw.vpr2 = BIT_DISABLE; /* set the parity bits */ parity_bit = vlan_parity[cfg.bits.ldw.vlanrdctbln2] + vlan_parity[cfg.bits.ldw.vlanrdctbln3] + cfg.bits.ldw.vpr2 + cfg.bits.ldw.vpr3; cfg.bits.ldw.parity1 = parity_bit & 0x1; break; case 3: cfg.bits.ldw.vlanrdctbln3 = rdc_table; if (priority) cfg.bits.ldw.vpr3 = BIT_ENABLE; else cfg.bits.ldw.vpr3 = BIT_DISABLE; /* set the parity bits */ parity_bit = vlan_parity[cfg.bits.ldw.vlanrdctbln2] + vlan_parity[cfg.bits.ldw.vlanrdctbln3] + cfg.bits.ldw.vpr2 + cfg.bits.ldw.vpr3; cfg.bits.ldw.parity1 = parity_bit & 0x1; break; default: return (NPI_FFLP_SW_PARAM_ERROR); } REG_PIO_WRITE64(handle, offset, cfg.value); return (NPI_SUCCESS); } /* * npi_fflp_cfg_enet_vlan_table_set_pri * sets the vlan based classification priority in respect to L2DA * classification. * * Input * handle opaque handle interpreted by the underlying OS * mac_portn port number * vlan_id VLAN ID * priority priority * 1: vlan classification has higher priority * 0: l2da classification has higher priority * * Output * * NPI success/failure status code */ npi_status_t npi_fflp_cfg_enet_vlan_table_set_pri(npi_handle_t handle, uint8_t mac_portn, vlan_id_t vlan_id, uint8_t priority) { fflp_enet_vlan_tbl_t cfg; uint64_t offset; uint64_t old_value; ASSERT(FFLP_VLAN_VALID(vlan_id)); if (!FFLP_VLAN_VALID(vlan_id)) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " enet_vlan_table set pri:" " Invalid vlan ID %d \n", vlan_id)); return (NPI_FFLP_VLAN_INVALID); } ASSERT(FFLP_PORT_VALID(mac_portn)); if (!FFLP_PORT_VALID(mac_portn)) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " enet_vlan_table set pri:" " Invalid port num %d \n", mac_portn)); return (NPI_FFLP_PORT_INVALID); } offset = FFLP_ENET_VLAN_TBL_REG + (vlan_id << 3); REG_PIO_READ64(handle, offset, &cfg.value); old_value = cfg.value; switch (mac_portn) { case 0: if (priority) cfg.bits.ldw.vpr0 = BIT_ENABLE; else cfg.bits.ldw.vpr0 = BIT_DISABLE; break; case 1: if (priority) cfg.bits.ldw.vpr1 = BIT_ENABLE; else cfg.bits.ldw.vpr1 = BIT_DISABLE; break; case 2: if (priority) cfg.bits.ldw.vpr2 = BIT_ENABLE; else cfg.bits.ldw.vpr2 = BIT_DISABLE; break; case 3: if (priority) cfg.bits.ldw.vpr3 = BIT_ENABLE; else cfg.bits.ldw.vpr3 = BIT_DISABLE; break; default: return (NPI_FFLP_SW_PARAM_ERROR); } if (old_value != cfg.value) { if (mac_portn > 1) cfg.bits.ldw.parity1++; else cfg.bits.ldw.parity0++; REG_PIO_WRITE64(handle, offset, cfg.value); } return (NPI_SUCCESS); } /* * npi_fflp_cfg_vlan_table_clear * Clears the vlan RDC table * * Input * handle opaque handle interpreted by the underlying OS * vlan_id VLAN ID * * Output * * NPI success/failure status code * */ npi_status_t npi_fflp_cfg_vlan_table_clear(npi_handle_t handle, vlan_id_t vlan_id) { uint64_t offset; uint64_t clear = 0ULL; vlan_id_t start_vlan = 0; if ((vlan_id < start_vlan) || (vlan_id >= NXGE_MAX_VLANS)) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " enet_vlan_table clear:" " Invalid vlan ID %d \n", vlan_id)); return (NPI_FFLP_VLAN_INVALID); } offset = FFLP_VLAN_OFFSET(vlan_id, FFLP_ENET_VLAN_TBL_REG); REG_PIO_WRITE64(handle, offset, clear); return (NPI_SUCCESS); } /* * npi_fflp_vlan_tbl_get_err_log * Reports VLAN Table errors. * If there are VLAN Table errors as indicated by err bit set by HW, * then the SW will clear it by clearing the bit. * * Input * handle: opaque handle interpreted by the underlying OS * err_stat: structure to report various VLAN table errors. * will be updated if there are errors. * * * Return * NPI_SUCCESS Success * * */ npi_status_t npi_fflp_vlan_tbl_get_err_log(npi_handle_t handle, vlan_tbl_err_log_t *err_stat) { vlan_par_err_t err_log; uint64_t offset; offset = FFLP_VLAN_PAR_ERR_REG; err_log.value = 0; REG_PIO_READ64(handle, offset, &err_log.value); if (err_log.bits.ldw.err == BIT_ENABLE) { /* non-zero means err */ err_stat->err = BIT_ENABLE; err_stat->multi = err_log.bits.ldw.m_err; err_stat->addr = err_log.bits.ldw.addr; err_stat->data = err_log.bits.ldw.data; /* now clear the error */ err_log.value = 0; REG_PIO_WRITE64(handle, offset, err_log.value); } else { err_stat->err = 0; } return (NPI_SUCCESS); } /* * npi_fflp_vlan_tbl_clr_err_log * Clears VLAN Table PIO error status. * If there are VLAN Table errors as indicated by err bit set by HW, * then the SW will clear it by clearing the bit. * * Input * handle: opaque handle interpreted by the underlying OS * * * Return * NPI_SUCCESS Success * * */ npi_status_t npi_fflp_vlan_tbl_clr_err_log(npi_handle_t handle) { vlan_par_err_t err_log; uint64_t offset; offset = FFLP_VLAN_PAR_ERR_REG; err_log.value = 0; REG_PIO_WRITE64(handle, offset, err_log.value); return (NPI_SUCCESS); } /* * npi_fflp_cfg_enet_usr_cls_set() * Configures a user configurable ethernet class * * Input * handle: opaque handle interpreted by the underlying OS * class: Ethernet Class class * (TCAM_CLASS_ETYPE or TCAM_CLASS_ETYPE_2) * enet_type: 16 bit Ethernet Type value, corresponding ethernet bytes * [13:14] in the frame. * * by default, the class will be disabled until explicitly enabled. * * Return * NPI success/failure status code */ npi_status_t npi_fflp_cfg_enet_usr_cls_set(npi_handle_t handle, tcam_class_t class, uint16_t enet_type) { uint64_t offset; tcam_class_prg_ether_t cls_cfg; cls_cfg.value = 0x0; /* check if etype is valid */ ASSERT(TCAM_L2_USR_CLASS_VALID(class)); if (!TCAM_L2_USR_CLASS_VALID(class)) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " npi_fflp_cfg_enet_usr_cls_set:" " Invalid class %d \n", class)); return (NPI_FFLP_TCAM_CLASS_INVALID); } offset = GET_TCAM_CLASS_OFFSET(class); /* * etype check code * * if (check_fail) * return (NPI_FAILURE | NPI_SW_ERROR); */ cls_cfg.bits.ldw.etype = enet_type; cls_cfg.bits.ldw.valid = BIT_DISABLE; REG_PIO_WRITE64(handle, offset, cls_cfg.value); return (NPI_SUCCESS); } /* * npi_fflp_cfg_enet_usr_cls_enable() * Enable previously configured TCAM user configurable Ethernet classes. * * Input * handle: opaque handle interpreted by the underlying OS * class: Ethernet Class class * (TCAM_CLASS_ETYPE or TCAM_CLASS_ETYPE_2) * * Return * NPI success/failure status code */ npi_status_t npi_fflp_cfg_enet_usr_cls_enable(npi_handle_t handle, tcam_class_t class) { uint64_t offset; tcam_class_prg_ether_t cls_cfg; ASSERT(TCAM_L2_USR_CLASS_VALID(class)); if (!TCAM_L2_USR_CLASS_VALID(class)) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " npi_fflp_cfg_enet_usr_cls_enable:" " Invalid class %d \n", class)); return (NPI_FFLP_TCAM_CLASS_INVALID); } offset = GET_TCAM_CLASS_OFFSET(class); REG_PIO_READ64(handle, offset, &cls_cfg.value); cls_cfg.bits.ldw.valid = BIT_ENABLE; REG_PIO_WRITE64(handle, offset, cls_cfg.value); return (NPI_SUCCESS); } /* * npi_fflp_cfg_enet_usr_cls_disable() * Disables previously configured TCAM user configurable Ethernet classes. * * Input * handle: opaque handle interpreted by the underlying OS * class: Ethernet Class class * (TCAM_CLASS_ETYPE or TCAM_CLASS_ETYPE_2) * * Return * NPI success/failure status code */ npi_status_t npi_fflp_cfg_enet_usr_cls_disable(npi_handle_t handle, tcam_class_t class) { uint64_t offset; tcam_class_prg_ether_t cls_cfg; ASSERT(TCAM_L2_USR_CLASS_VALID(class)); if (!TCAM_L2_USR_CLASS_VALID(class)) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " npi_fflp_cfg_enet_usr_cls_disable:" " Invalid class %d \n", class)); return (NPI_FFLP_TCAM_CLASS_INVALID); } offset = GET_TCAM_CLASS_OFFSET(class); REG_PIO_READ64(handle, offset, &cls_cfg.value); cls_cfg.bits.ldw.valid = BIT_DISABLE; REG_PIO_WRITE64(handle, offset, cls_cfg.value); return (NPI_SUCCESS); } /* * npi_fflp_cfg_ip_usr_cls_set() * Configures the TCAM user configurable IP classes. * * Input * handle: opaque handle interpreted by the underlying OS * class: IP Class class * (TCAM_CLASS_IP_USER_4 <= class <= TCAM_CLASS_IP_USER_7) * tos: IP TOS bits * tos_mask: IP TOS bits mask. bits with mask bits set will be used * proto: IP Proto * ver: IP Version * by default, will the class is disabled until explicitly enabled * * Return * NPI success/failure status code */ npi_status_t npi_fflp_cfg_ip_usr_cls_set(npi_handle_t handle, tcam_class_t class, uint8_t tos, uint8_t tos_mask, uint8_t proto, uint8_t ver) { uint64_t offset; tcam_class_prg_ip_t ip_cls_cfg; ASSERT(TCAM_L3_USR_CLASS_VALID(class)); if (!TCAM_L3_USR_CLASS_VALID(class)) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " npi_fflp_cfg_ip_usr_cls_set:" " Invalid class %d \n", class)); return (NPI_FFLP_TCAM_CLASS_INVALID); } offset = GET_TCAM_CLASS_OFFSET(class); ip_cls_cfg.bits.ldw.pid = proto; ip_cls_cfg.bits.ldw.ipver = ver; ip_cls_cfg.bits.ldw.tos = tos; ip_cls_cfg.bits.ldw.tosmask = tos_mask; ip_cls_cfg.bits.ldw.valid = 0; REG_PIO_WRITE64(handle, offset, ip_cls_cfg.value); return (NPI_SUCCESS); } /* * npi_fflp_cfg_ip_usr_cls_set_iptun() * Configures the TCAM user configurable IP classes. This function sets the * new fields that were added for IP tunneling support * * Input * handle: opaque handle interpreted by the underlying OS * class: IP Class class * (TCAM_CLASS_IP_USER_4 <= class <= TCAM_CLASS_IP_USER_7) * l4b0_val value of the first L4 byte to be compared * l4b0_msk mask to apply to compare byte 0 of L4 * l4b23_val values of L4 bytes 2 and 3 to compare * l4b23_sel set to 1 to compare L4 bytes 2 and 3. * by default, the class is disabled until explicitly enabled * * Return * NPI success/failure status code */ npi_status_t npi_fflp_cfg_ip_usr_cls_set_iptun(npi_handle_t handle, tcam_class_t class, uint8_t l4b0_val, uint8_t l4b0_msk, uint16_t l4b23_val, uint8_t l4b23_sel) { uint64_t offset, val; tcam_class_prg_ip_t ip_cls_cfg; ASSERT(TCAM_L3_USR_CLASS_VALID(class)); if (!TCAM_L3_USR_CLASS_VALID(class)) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " npi_fflp_cfg_ip_usr_cls_set:" " Invalid class %d \n", class)); return (NPI_FFLP_TCAM_CLASS_INVALID); } offset = GET_TCAM_CLASS_OFFSET(class); REG_PIO_READ64(handle, offset, &ip_cls_cfg.value); val = 1; ip_cls_cfg.value |= (val << L3_UCLS_L4_MODE_SH); val = l4b0_val; ip_cls_cfg.value |= (val << L3_UCLS_L4B0_VAL_SH); val = l4b0_msk; ip_cls_cfg.value |= (val << L3_UCLS_L4B0_MASK_SH); val = l4b23_sel; ip_cls_cfg.value |= (val << L3_UCLS_L4B23_SEL_SH); val = l4b23_val; ip_cls_cfg.value |= (val << L3_UCLS_L4B23_VAL_SH); ip_cls_cfg.bits.ldw.valid = 0; REG_PIO_WRITE64(handle, offset, ip_cls_cfg.value); return (NPI_SUCCESS); } /* * npi_fflp_cfg_ip_usr_cls_get_iptun() * Retrieves the IP tunneling related settings for the given TCAM user * configurable IP classe. * * Input * handle: opaque handle interpreted by the underlying OS * class: IP Class class * (TCAM_CLASS_IP_USER_4 <= class <= TCAM_CLASS_IP_USER_7) * l4b0_val value of the first L4 byte to be compared * l4b0_msk mask to apply to compare byte 0 of L4 * l4b23_val values of L4 bytes 2 and 3 to compare * l4b23_sel set to 1 to compare L4 bytes 2 and 3. * by default, the class is disabled until explicitly enabled * * Return * NPI success/failure status code */ npi_status_t npi_fflp_cfg_ip_usr_cls_get_iptun(npi_handle_t handle, tcam_class_t class, uint8_t *l4b0_val, uint8_t *l4b0_msk, uint16_t *l4b23_val, uint8_t *l4b23_sel) { uint64_t offset; tcam_class_prg_ip_t ip_cls_cfg; ASSERT(TCAM_L3_USR_CLASS_VALID(class)); if (!TCAM_L3_USR_CLASS_VALID(class)) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " npi_fflp_cfg_ip_usr_cls_set:" " Invalid class %d \n", class)); return (NPI_FFLP_TCAM_CLASS_INVALID); } offset = GET_TCAM_CLASS_OFFSET(class); REG_PIO_READ64(handle, offset, &ip_cls_cfg.value); *l4b0_val = (ip_cls_cfg.value >> L3_UCLS_L4B0_VAL_SH) & L3_UCLS_L4B0_VAL_MSK; *l4b0_msk = (ip_cls_cfg.value >> L3_UCLS_L4B0_MASK_SH) & L3_UCLS_L4B0_MASK_MSK; *l4b23_sel = (ip_cls_cfg.value >> L3_UCLS_L4B23_SEL_SH) & L3_UCLS_L4B23_SEL_MSK; *l4b23_val = (ip_cls_cfg.value >> L3_UCLS_L4B23_VAL_SH) & L3_UCLS_L4B23_VAL_MSK; return (NPI_SUCCESS); } /* * npi_fflp_cfg_ip_usr_cls_enable() * Enable previously configured TCAM user configurable IP classes. * * Input * handle: opaque handle interpreted by the underlying OS * class: IP Class class * (TCAM_CLASS_IP_USER_4 <= class <= TCAM_CLASS_IP_USER_7) * * Return * NPI success/failure status code */ npi_status_t npi_fflp_cfg_ip_usr_cls_enable(npi_handle_t handle, tcam_class_t class) { uint64_t offset; tcam_class_prg_ip_t ip_cls_cfg; ASSERT(TCAM_L3_USR_CLASS_VALID(class)); if (!TCAM_L3_USR_CLASS_VALID(class)) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " npi_fflp_cfg_ip_usr_cls_enable:" " Invalid class %d \n", class)); return (NPI_FFLP_TCAM_CLASS_INVALID); } offset = GET_TCAM_CLASS_OFFSET(class); REG_PIO_READ64(handle, offset, &ip_cls_cfg.value); ip_cls_cfg.bits.ldw.valid = 1; REG_PIO_WRITE64(handle, offset, ip_cls_cfg.value); return (NPI_SUCCESS); } /* * npi_fflp_cfg_ip_usr_cls_disable() * Disables previously configured TCAM user configurable IP classes. * * Input * handle: opaque handle interpreted by the underlying OS * class: IP Class class * (TCAM_CLASS_IP_USER_4 <= class <= TCAM_CLASS_IP_USER_7) * * Return * NPI success/failure status code */ npi_status_t npi_fflp_cfg_ip_usr_cls_disable(npi_handle_t handle, tcam_class_t class) { uint64_t offset; tcam_class_prg_ip_t ip_cls_cfg; ASSERT(TCAM_L3_USR_CLASS_VALID(class)); if (!TCAM_L3_USR_CLASS_VALID(class)) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " npi_fflp_cfg_ip_usr_cls_disable:" " Invalid class %d \n", class)); return (NPI_FFLP_TCAM_CLASS_INVALID); } offset = GET_TCAM_CLASS_OFFSET(class); REG_PIO_READ64(handle, offset, &ip_cls_cfg.value); ip_cls_cfg.bits.ldw.valid = 0; REG_PIO_WRITE64(handle, offset, ip_cls_cfg.value); return (NPI_SUCCESS); } /* * npi_fflp_cfg_ip_cls_tcam_key () * * Configures the TCAM key generation for the IP classes * * Input * handle: opaque handle interpreted by the underlying OS * l3_class: IP class to configure key generation * cfg: Configuration bits: * discard: Discard all frames of this class * use_ip_saddr: use ip src address (for ipv6) * use_ip_daddr: use ip dest address (for ipv6) * lookup_enable: Enable Lookup * * * Return * NPI success/failure status code */ npi_status_t npi_fflp_cfg_ip_cls_tcam_key(npi_handle_t handle, tcam_class_t l3_class, tcam_key_cfg_t *cfg) { uint64_t offset; tcam_class_key_ip_t tcam_cls_cfg; ASSERT(TCAM_L3_CLASS_VALID(l3_class)); if (!(TCAM_L3_CLASS_VALID(l3_class))) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " npi_fflp_cfg_ip_cls_tcam_key:" " Invalid class %d \n", l3_class)); return (NPI_FFLP_TCAM_CLASS_INVALID); } if ((cfg->use_ip_daddr) && (cfg->use_ip_saddr == cfg->use_ip_daddr)) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " npi_fflp_cfg_ip_cls_tcam_key:" " Invalid configuration %x for class %d \n", *cfg, l3_class)); return (NPI_FFLP_SW_PARAM_ERROR); } offset = GET_TCAM_KEY_OFFSET(l3_class); tcam_cls_cfg.value = 0; if (cfg->discard) { tcam_cls_cfg.bits.ldw.discard = 1; } if (cfg->use_ip_saddr) { tcam_cls_cfg.bits.ldw.ipaddr = 1; } if (cfg->use_ip_daddr) { tcam_cls_cfg.bits.ldw.ipaddr = 0; } if (cfg->lookup_enable) { tcam_cls_cfg.bits.ldw.tsel = 1; } REG_PIO_WRITE64(handle, offset, tcam_cls_cfg.value); return (NPI_SUCCESS); } /* * npi_fflp_cfg_ip_cls_flow_key () * * Configures the flow key generation for the IP classes * Flow key is used to generate the H1 hash function value * The fields used for the generation are configured using this * NPI function. * * Input * handle: opaque handle interpreted by the underlying OS * l3_class: IP class to configure flow key generation * cfg: Configuration bits: * use_proto: Use IP proto field * use_dport: use l4 destination port * use_sport: use l4 source port * ip_opts_exist: IP Options Present * use_daddr: use ip dest address * use_saddr: use ip source address * use_vlan: use VLAN ID * use_l2da: use L2 Dest MAC Address * use_portnum: use L2 virtual port number * * * Return * NPI success/failure status code */ npi_status_t npi_fflp_cfg_ip_cls_flow_key(npi_handle_t handle, tcam_class_t l3_class, flow_key_cfg_t *cfg) { uint64_t offset; flow_class_key_ip_t flow_cfg_reg; ASSERT(TCAM_L3_CLASS_VALID(l3_class)); if (!(TCAM_L3_CLASS_VALID(l3_class))) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " npi_fflp_cfg_ip_cls_flow_key:" " Invalid class %d \n", l3_class)); return (NPI_FFLP_TCAM_CLASS_INVALID); } offset = GET_FLOW_KEY_OFFSET(l3_class); flow_cfg_reg.value = 0; /* default */ if (cfg->use_proto) { flow_cfg_reg.bits.ldw.proto = 1; } if (cfg->use_dport) { flow_cfg_reg.bits.ldw.l4_1 = 2; if (cfg->ip_opts_exist) flow_cfg_reg.bits.ldw.l4_1 = 3; } if (cfg->use_sport) { flow_cfg_reg.bits.ldw.l4_0 = 2; if (cfg->ip_opts_exist) flow_cfg_reg.bits.ldw.l4_0 = 3; } if (cfg->use_daddr) { flow_cfg_reg.bits.ldw.ipda = BIT_ENABLE; } if (cfg->use_saddr) { flow_cfg_reg.bits.ldw.ipsa = BIT_ENABLE; } if (cfg->use_vlan) { flow_cfg_reg.bits.ldw.vlan = BIT_ENABLE; } if (cfg->use_l2da) { flow_cfg_reg.bits.ldw.l2da = BIT_ENABLE; } if (cfg->use_portnum) { flow_cfg_reg.bits.ldw.port = BIT_ENABLE; } REG_PIO_WRITE64(handle, offset, flow_cfg_reg.value); return (NPI_SUCCESS); } npi_status_t npi_fflp_cfg_ip_cls_flow_key_get(npi_handle_t handle, tcam_class_t l3_class, flow_key_cfg_t *cfg) { uint64_t offset; flow_class_key_ip_t flow_cfg_reg; ASSERT(TCAM_L3_CLASS_VALID(l3_class)); if (!(TCAM_L3_CLASS_VALID(l3_class))) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " npi_fflp_cfg_ip_cls_flow_key:" " Invalid class %d \n", l3_class)); return (NPI_FFLP_TCAM_CLASS_INVALID); } offset = GET_FLOW_KEY_OFFSET(l3_class); cfg->use_proto = 0; cfg->use_dport = 0; cfg->use_sport = 0; cfg->ip_opts_exist = 0; cfg->use_daddr = 0; cfg->use_saddr = 0; cfg->use_vlan = 0; cfg->use_l2da = 0; cfg->use_portnum = 0; REG_PIO_READ64(handle, offset, &flow_cfg_reg.value); if (flow_cfg_reg.bits.ldw.proto) { cfg->use_proto = 1; } if (flow_cfg_reg.bits.ldw.l4_1 == 2) { cfg->use_dport = 1; } if (flow_cfg_reg.bits.ldw.l4_1 == 3) { cfg->use_dport = 1; cfg->ip_opts_exist = 1; } if (flow_cfg_reg.bits.ldw.l4_0 == 2) { cfg->use_sport = 1; } if (flow_cfg_reg.bits.ldw.l4_0 == 3) { cfg->use_sport = 1; cfg->ip_opts_exist = 1; } if (flow_cfg_reg.bits.ldw.ipda) { cfg->use_daddr = 1; } if (flow_cfg_reg.bits.ldw.ipsa) { cfg->use_saddr = 1; } if (flow_cfg_reg.bits.ldw.vlan) { cfg->use_vlan = 1; } if (flow_cfg_reg.bits.ldw.l2da) { cfg->use_l2da = 1; } if (flow_cfg_reg.bits.ldw.port) { cfg->use_portnum = 1; } NPI_DEBUG_MSG((handle.function, NPI_FFLP_CTL, " npi_fflp_cfg_ip_cls_flow_get %llx \n", flow_cfg_reg.value)); return (NPI_SUCCESS); } /* * npi_fflp_cfg_ip_cls_flow_key_rfnl () * * Configures the flow key generation for the IP classes * Flow key is used to generate the H1 hash function value * The fields used for the generation are configured using this * NPI function. * * Input * handle: opaque handle interpreted by the underlying OS * l3_class: IP class to configure flow key generation * cfg: Configuration bits: * l4_xor_sel: bit field to select the L4 payload * bytes for X-OR to get hash key. * use_l4_md: Set to 1 for enabling L4-mode. * use_sym: Set to 1 to use symmetric mode. * use_proto: Use IP proto field * use_dport: use l4 destination port * use_sport: use l4 source port * ip_opts_exist: IP Options Present * use_daddr: use ip dest address * use_saddr: use ip source address * use_vlan: use VLAN ID * use_l2da: use L2 Dest MAC Address * use_portnum: use L2 virtual port number * * * Return * NPI success/failure status code */ npi_status_t npi_fflp_cfg_ip_cls_flow_key_rfnl(npi_handle_t handle, tcam_class_t l3_class, flow_key_cfg_t *cfg) { uint64_t offset; flow_class_key_ip_t flow_cfg_reg; ASSERT(TCAM_L3_CLASS_VALID_RFNL(l3_class)); if (!(TCAM_L3_CLASS_VALID_RFNL(l3_class))) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " npi_fflp_cfg_ip_cls_flow_key_rfnl:" " Invalid class %d \n", l3_class)); return (NPI_FFLP_TCAM_CLASS_INVALID); } if (l3_class == TCAM_CLASS_IPV6_FRAG) { offset = FFLP_FLOW_KEY_IP6_FRAG_REG; } else { offset = GET_FLOW_KEY_OFFSET(l3_class); } flow_cfg_reg.value = 0; flow_cfg_reg.bits.ldw.l4_xor = cfg->l4_xor_sel; if (cfg->use_l4_md) flow_cfg_reg.bits.ldw.l4_mode = 1; if (cfg->use_sym) flow_cfg_reg.bits.ldw.sym = 1; if (cfg->use_proto) { flow_cfg_reg.bits.ldw.proto = 1; } if (cfg->use_dport) { flow_cfg_reg.bits.ldw.l4_1 = 2; if (cfg->ip_opts_exist) flow_cfg_reg.bits.ldw.l4_1 = 3; } if (cfg->use_sport) { flow_cfg_reg.bits.ldw.l4_0 = 2; if (cfg->ip_opts_exist) flow_cfg_reg.bits.ldw.l4_0 = 3; } if (cfg->use_daddr) { flow_cfg_reg.bits.ldw.ipda = BIT_ENABLE; } if (cfg->use_saddr) { flow_cfg_reg.bits.ldw.ipsa = BIT_ENABLE; } if (cfg->use_vlan) { flow_cfg_reg.bits.ldw.vlan = BIT_ENABLE; } if (cfg->use_l2da) { flow_cfg_reg.bits.ldw.l2da = BIT_ENABLE; } if (cfg->use_portnum) { flow_cfg_reg.bits.ldw.port = BIT_ENABLE; } REG_PIO_WRITE64(handle, offset, flow_cfg_reg.value); return (NPI_SUCCESS); } npi_status_t npi_fflp_cfg_sym_ip_cls_flow_key(npi_handle_t handle, tcam_class_t l3_class, boolean_t enable) { uint64_t offset; flow_class_key_ip_t flow_cfg_reg; ASSERT(TCAM_L3_CLASS_VALID_RFNL(l3_class)); if (!(TCAM_L3_CLASS_VALID_RFNL(l3_class))) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " npi_fflp_cfg_sym_ip_cls_flow_key:" " Invalid class %d \n", l3_class)); return (NPI_FFLP_TCAM_CLASS_INVALID); } if (l3_class == TCAM_CLASS_IPV6_FRAG) { offset = FFLP_FLOW_KEY_IP6_FRAG_REG; } else { offset = GET_FLOW_KEY_OFFSET(l3_class); } REG_PIO_READ64(handle, offset, &flow_cfg_reg.value); if (enable && flow_cfg_reg.bits.ldw.sym == 0) { flow_cfg_reg.bits.ldw.sym = 1; REG_PIO_WRITE64(handle, offset, flow_cfg_reg.value); } else if (!enable && flow_cfg_reg.bits.ldw.sym == 1) { flow_cfg_reg.bits.ldw.sym = 0; REG_PIO_WRITE64(handle, offset, flow_cfg_reg.value); } return (NPI_SUCCESS); } npi_status_t npi_fflp_cfg_ip_cls_flow_key_get_rfnl(npi_handle_t handle, tcam_class_t l3_class, flow_key_cfg_t *cfg) { uint64_t offset; flow_class_key_ip_t flow_cfg_reg; ASSERT(TCAM_L3_CLASS_VALID_RFNL(l3_class)); if (!(TCAM_L3_CLASS_VALID_RFNL(l3_class))) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " npi_fflp_cfg_ip_cls_flow_key_get_rfnl:" " Invalid class %d \n", l3_class)); return (NPI_FFLP_TCAM_CLASS_INVALID); } if (l3_class == TCAM_CLASS_IPV6_FRAG) { offset = FFLP_FLOW_KEY_IP6_FRAG_REG; } else { offset = GET_FLOW_KEY_OFFSET(l3_class); } cfg->l4_xor_sel = 0; cfg->use_l4_md = 0; cfg->use_sym = 0; cfg->use_proto = 0; cfg->use_dport = 0; cfg->use_sport = 0; cfg->ip_opts_exist = 0; cfg->use_daddr = 0; cfg->use_saddr = 0; cfg->use_vlan = 0; cfg->use_l2da = 0; cfg->use_portnum = 0; REG_PIO_READ64(handle, offset, &flow_cfg_reg.value); cfg->l4_xor_sel = flow_cfg_reg.bits.ldw.l4_xor; if (flow_cfg_reg.bits.ldw.l4_mode) cfg->use_l4_md = 1; if (flow_cfg_reg.bits.ldw.sym) cfg->use_sym = 1; if (flow_cfg_reg.bits.ldw.proto) { cfg->use_proto = 1; } if (flow_cfg_reg.bits.ldw.l4_1 == 2) { cfg->use_dport = 1; } if (flow_cfg_reg.bits.ldw.l4_1 == 3) { cfg->use_dport = 1; cfg->ip_opts_exist = 1; } if (flow_cfg_reg.bits.ldw.l4_0 == 2) { cfg->use_sport = 1; } if (flow_cfg_reg.bits.ldw.l4_0 == 3) { cfg->use_sport = 1; cfg->ip_opts_exist = 1; } if (flow_cfg_reg.bits.ldw.ipda) { cfg->use_daddr = 1; } if (flow_cfg_reg.bits.ldw.ipsa) { cfg->use_saddr = 1; } if (flow_cfg_reg.bits.ldw.vlan) { cfg->use_vlan = 1; } if (flow_cfg_reg.bits.ldw.l2da) { cfg->use_l2da = 1; } if (flow_cfg_reg.bits.ldw.port) { cfg->use_portnum = 1; } NPI_DEBUG_MSG((handle.function, NPI_FFLP_CTL, " npi_fflp_cfg_ip_cls_flow_get %llx \n", flow_cfg_reg.value)); return (NPI_SUCCESS); } npi_status_t npi_fflp_cfg_ip_cls_tcam_key_get(npi_handle_t handle, tcam_class_t l3_class, tcam_key_cfg_t *cfg) { uint64_t offset; tcam_class_key_ip_t tcam_cls_cfg; ASSERT(TCAM_L3_CLASS_VALID(l3_class)); if (!(TCAM_L3_CLASS_VALID(l3_class))) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " npi_fflp_cfg_ip_cls_tcam_key_get:" " Invalid class %d \n", l3_class)); return (NPI_FFLP_TCAM_CLASS_INVALID); } offset = GET_TCAM_KEY_OFFSET(l3_class); REG_PIO_READ64(handle, offset, &tcam_cls_cfg.value); cfg->discard = 0; cfg->use_ip_saddr = 0; cfg->use_ip_daddr = 1; cfg->lookup_enable = 0; if (tcam_cls_cfg.bits.ldw.discard) cfg->discard = 1; if (tcam_cls_cfg.bits.ldw.ipaddr) { cfg->use_ip_saddr = 1; cfg->use_ip_daddr = 0; } if (tcam_cls_cfg.bits.ldw.tsel) { cfg->lookup_enable = 1; } NPI_DEBUG_MSG((handle.function, NPI_CTL, " npi_fflp_cfg_ip_cls_tcam_key_get %llx \n", tcam_cls_cfg.value)); return (NPI_SUCCESS); } /* * npi_fflp_cfg_fcram_access () * * Sets the ratio between the FCRAM pio and lookup access * Input: * handle: opaque handle interpreted by the underlying OS * access_ratio: 0 Lookup has the highest priority * 15 PIO has maximum possible priority * * Return * NPI success/failure status code */ npi_status_t npi_fflp_cfg_fcram_access(npi_handle_t handle, uint8_t access_ratio) { fflp_cfg_1_t fflp_cfg; uint64_t offset; offset = FFLP_CFG_1_REG; if (access_ratio > 0xf) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " npi_fflp_cfg_fcram_access:" " Invalid access ratio %d \n", access_ratio)); return (NPI_FFLP_ERROR | NPI_FFLP_SW_PARAM_ERROR); } REG_PIO_READ64(handle, offset, &fflp_cfg.value); fflp_cfg.bits.ldw.fflpinitdone = 0; fflp_cfg.bits.ldw.fcramratio = access_ratio; REG_PIO_WRITE64(handle, offset, fflp_cfg.value); REG_PIO_READ64(handle, offset, &fflp_cfg.value); fflp_cfg.bits.ldw.fflpinitdone = 1; REG_PIO_WRITE64(handle, offset, fflp_cfg.value); return (NPI_SUCCESS); } /* * npi_fflp_cfg_tcam_access () * * Sets the ratio between the TCAM pio and lookup access * Input: * handle: opaque handle interpreted by the underlying OS * access_ratio: 0 Lookup has the highest priority * 15 PIO has maximum possible priority * Return * NPI success/failure status code */ npi_status_t npi_fflp_cfg_tcam_access(npi_handle_t handle, uint8_t access_ratio) { fflp_cfg_1_t fflp_cfg; uint64_t offset; offset = FFLP_CFG_1_REG; if (access_ratio > 0xf) { NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " npi_fflp_cfg_tcram_access:" " Invalid access ratio %d \n", access_ratio)); return (NPI_FFLP_ERROR | NPI_FFLP_SW_PARAM_ERROR); } REG_PIO_READ64(handle, offset, &fflp_cfg.value); fflp_cfg.bits.ldw.fflpinitdone = 0; fflp_cfg.bits.ldw.camratio = access_ratio; /* since the cam latency is fixed, we might set it here */ fflp_cfg.bits.ldw.camlatency = TCAM_DEFAULT_LATENCY; REG_PIO_WRITE64(handle, offset, fflp_cfg.value); REG_PIO_READ64(handle, offset, &fflp_cfg.value); fflp_cfg.bits.ldw.fflpinitdone = 1; REG_PIO_WRITE64(handle, offset, fflp_cfg.value); return (NPI_SUCCESS); } /* * npi_fflp_cfg_hash_h1poly() * Initializes the H1 hash generation logic. * * Input * handle: opaque handle interpreted by the underlying OS * init_value: The initial value (seed) * * Return * NPI success/failure status code */ npi_status_t npi_fflp_cfg_hash_h1poly(npi_handle_t handle, uint32_t init_value) { hash_h1poly_t h1_cfg; uint64_t offset; offset = FFLP_H1POLY_REG; h1_cfg.value = 0; h1_cfg.bits.ldw.init_value = init_value; REG_PIO_WRITE64(handle, offset, h1_cfg.value); return (NPI_SUCCESS); } /* * npi_fflp_cfg_hash_h2poly() * Initializes the H2 hash generation logic. * * Input * handle: opaque handle interpreted by the underlying OS * init_value: The initial value (seed) * * Return * NPI_SUCCESS * */ npi_status_t npi_fflp_cfg_hash_h2poly(npi_handle_t handle, uint16_t init_value) { hash_h2poly_t h2_cfg; uint64_t offset; offset = FFLP_H2POLY_REG; h2_cfg.value = 0; h2_cfg.bits.ldw.init_value = init_value; REG_PIO_WRITE64(handle, offset, h2_cfg.value); return (NPI_SUCCESS); } /* * npi_fflp_cfg_reset * Initializes the FCRAM reset sequence. * * Input * handle: opaque handle interpreted by the underlying OS * strength: FCRAM Drive strength * strong, weak or normal * HW recommended value: * qs: FCRAM QS mode selection * qs mode or free running * HW recommended value is: * * Return: * NPI success/failure status code */ npi_status_t npi_fflp_cfg_fcram_reset(npi_handle_t handle, fflp_fcram_output_drive_t strength, fflp_fcram_qs_t qs) { fflp_cfg_1_t fflp_cfg; uint64_t offset; offset = FFLP_CFG_1_REG; /* These bits have to be configured before FCRAM reset is issued */ fflp_cfg.value = 0; fflp_cfg.bits.ldw.pio_fio_rst = 1; REG_PIO_WRITE64(handle, offset, fflp_cfg.value); NXGE_DELAY(5); /* TODO: What is the correct delay? */ fflp_cfg.bits.ldw.pio_fio_rst = 0; REG_PIO_WRITE64(handle, offset, fflp_cfg.value); fflp_cfg.bits.ldw.fcramqs = qs; fflp_cfg.bits.ldw.fcramoutdr = strength; fflp_cfg.bits.ldw.fflpinitdone = 1; REG_PIO_WRITE64(handle, offset, fflp_cfg.value); return (NPI_SUCCESS); } npi_status_t npi_fflp_cfg_init_done(npi_handle_t handle) { fflp_cfg_1_t fflp_cfg; uint64_t offset; offset = FFLP_CFG_1_REG; REG_PIO_READ64(handle, offset, &fflp_cfg.value); fflp_cfg.bits.ldw.fflpinitdone = 1; REG_PIO_WRITE64(handle, offset, fflp_cfg.value); return (NPI_SUCCESS); } npi_status_t npi_fflp_cfg_init_start(npi_handle_t handle) { fflp_cfg_1_t fflp_cfg; uint64_t offset; offset = FFLP_CFG_1_REG; REG_PIO_READ64(handle, offset, &fflp_cfg.value); fflp_cfg.bits.ldw.fflpinitdone = 0; REG_PIO_WRITE64(handle, offset, fflp_cfg.value); return (NPI_SUCCESS); } /* * Enables the TCAM search function. * */ npi_status_t npi_fflp_cfg_tcam_enable(npi_handle_t handle) { fflp_cfg_1_t fflp_cfg; uint64_t offset; offset = FFLP_CFG_1_REG; REG_PIO_READ64(handle, offset, &fflp_cfg.value); fflp_cfg.bits.ldw.tcam_disable = 0; REG_PIO_WRITE64(handle, offset, fflp_cfg.value); return (NPI_SUCCESS); } /* * Disables the TCAM search function. * While the TCAM is in disabled state, all TCAM matches would return NO_MATCH * */ npi_status_t npi_fflp_cfg_tcam_disable(npi_handle_t handle) { fflp_cfg_1_t fflp_cfg; uint64_t offset; offset = FFLP_CFG_1_REG; REG_PIO_READ64(handle, offset, &fflp_cfg.value); fflp_cfg.bits.ldw.tcam_disable = 1; REG_PIO_WRITE64(handle, offset, fflp_cfg.value); return (NPI_SUCCESS); } /* * npi_rxdma_event_mask_config(): * This function is called to operate on the event mask * register which is used for generating interrupts * and status register. */ npi_status_t npi_fflp_event_mask_config(npi_handle_t handle, io_op_t op_mode, fflp_event_mask_cfg_t *mask_cfgp) { int status = NPI_SUCCESS; fflp_err_mask_t mask_reg; switch (op_mode) { case OP_GET: REG_PIO_READ64(handle, FFLP_ERR_MSK_REG, &mask_reg.value); *mask_cfgp = mask_reg.value & FFLP_ERR_MASK_ALL; break; case OP_SET: mask_reg.value = (~(*mask_cfgp) & FFLP_ERR_MASK_ALL); REG_PIO_WRITE64(handle, FFLP_ERR_MSK_REG, mask_reg.value); break; case OP_UPDATE: REG_PIO_READ64(handle, FFLP_ERR_MSK_REG, &mask_reg.value); mask_reg.value |= (~(*mask_cfgp) & FFLP_ERR_MASK_ALL); REG_PIO_WRITE64(handle, FFLP_ERR_MSK_REG, mask_reg.value); break; case OP_CLEAR: mask_reg.value = FFLP_ERR_MASK_ALL; REG_PIO_WRITE64(handle, FFLP_ERR_MSK_REG, mask_reg.value); break; default: NPI_ERROR_MSG((handle.function, NPI_ERR_CTL, " npi_fflp_event_mask_config", " eventmask <0x%x>", op_mode)); return (NPI_FFLP_ERROR | NPI_FFLP_SW_PARAM_ERROR); } return (status); } /* * Read vlan error bits */ void npi_fflp_vlan_error_get(npi_handle_t handle, p_vlan_par_err_t p_err) { REG_PIO_READ64(handle, FFLP_VLAN_PAR_ERR_REG, &p_err->value); } /* * clear vlan error bits */ void npi_fflp_vlan_error_clear(npi_handle_t handle) { vlan_par_err_t p_err; p_err.value = 0; p_err.bits.ldw.m_err = 0; p_err.bits.ldw.err = 0; REG_PIO_WRITE64(handle, FFLP_ERR_MSK_REG, p_err.value); } /* * Read TCAM error bits */ void npi_fflp_tcam_error_get(npi_handle_t handle, p_tcam_err_t p_err) { REG_PIO_READ64(handle, FFLP_TCAM_ERR_REG, &p_err->value); } /* * clear TCAM error bits */ void npi_fflp_tcam_error_clear(npi_handle_t handle) { tcam_err_t p_err; p_err.value = 0; p_err.bits.ldw.p_ecc = 0; p_err.bits.ldw.mult = 0; p_err.bits.ldw.err = 0; REG_PIO_WRITE64(handle, FFLP_TCAM_ERR_REG, p_err.value); } /* * Read FCRAM error bits */ void npi_fflp_fcram_error_get(npi_handle_t handle, p_hash_tbl_data_log_t p_err, uint8_t partition) { uint64_t offset; offset = FFLP_HASH_TBL_DATA_LOG_REG + partition * 8192; REG_PIO_READ64(handle, offset, &p_err->value); } /* * clear FCRAM error bits */ void npi_fflp_fcram_error_clear(npi_handle_t handle, uint8_t partition) { hash_tbl_data_log_t p_err; uint64_t offset; p_err.value = 0; p_err.bits.ldw.pio_err = 0; offset = FFLP_HASH_TBL_DATA_LOG_REG + partition * 8192; REG_PIO_WRITE64(handle, offset, p_err.value); } /* * Read FCRAM lookup error log1 bits */ void npi_fflp_fcram_error_log1_get(npi_handle_t handle, p_hash_lookup_err_log1_t log1) { REG_PIO_READ64(handle, HASH_LKUP_ERR_LOG1_REG, &log1->value); } /* * Read FCRAM lookup error log2 bits */ void npi_fflp_fcram_error_log2_get(npi_handle_t handle, p_hash_lookup_err_log2_t log2) { REG_PIO_READ64(handle, HASH_LKUP_ERR_LOG2_REG, &log2->value); }