162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * This software is available to you under a choice of one of two 562306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 662306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 762306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 862306a36Sopenharmony_ci * OpenIB.org BSD license below: 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 1162306a36Sopenharmony_ci * without modification, are permitted provided that the following 1262306a36Sopenharmony_ci * conditions are met: 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * - Redistributions of source code must retain the above 1562306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 1662306a36Sopenharmony_ci * disclaimer. 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 1962306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2062306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials 2162306a36Sopenharmony_ci * provided with the distribution. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2462306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2562306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2662306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 2762306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 2862306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 2962306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3062306a36Sopenharmony_ci * SOFTWARE. 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_ci#include "common.h" 3362306a36Sopenharmony_ci#include "regs.h" 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cienum { 3662306a36Sopenharmony_ci IDT75P52100 = 4, 3762306a36Sopenharmony_ci IDT75N43102 = 5 3862306a36Sopenharmony_ci}; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci/* DBGI command mode */ 4162306a36Sopenharmony_cienum { 4262306a36Sopenharmony_ci DBGI_MODE_MBUS = 0, 4362306a36Sopenharmony_ci DBGI_MODE_IDT52100 = 5 4462306a36Sopenharmony_ci}; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci/* IDT 75P52100 commands */ 4762306a36Sopenharmony_ci#define IDT_CMD_READ 0 4862306a36Sopenharmony_ci#define IDT_CMD_WRITE 1 4962306a36Sopenharmony_ci#define IDT_CMD_SEARCH 2 5062306a36Sopenharmony_ci#define IDT_CMD_LEARN 3 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci/* IDT LAR register address and value for 144-bit mode (low 32 bits) */ 5362306a36Sopenharmony_ci#define IDT_LAR_ADR0 0x180006 5462306a36Sopenharmony_ci#define IDT_LAR_MODE144 0xffff0000 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci/* IDT SCR and SSR addresses (low 32 bits) */ 5762306a36Sopenharmony_ci#define IDT_SCR_ADR0 0x180000 5862306a36Sopenharmony_ci#define IDT_SSR0_ADR0 0x180002 5962306a36Sopenharmony_ci#define IDT_SSR1_ADR0 0x180004 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/* IDT GMR base address (low 32 bits) */ 6262306a36Sopenharmony_ci#define IDT_GMR_BASE_ADR0 0x180020 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci/* IDT data and mask array base addresses (low 32 bits) */ 6562306a36Sopenharmony_ci#define IDT_DATARY_BASE_ADR0 0 6662306a36Sopenharmony_ci#define IDT_MSKARY_BASE_ADR0 0x80000 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci/* IDT 75N43102 commands */ 6962306a36Sopenharmony_ci#define IDT4_CMD_SEARCH144 3 7062306a36Sopenharmony_ci#define IDT4_CMD_WRITE 4 7162306a36Sopenharmony_ci#define IDT4_CMD_READ 5 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci/* IDT 75N43102 SCR address (low 32 bits) */ 7462306a36Sopenharmony_ci#define IDT4_SCR_ADR0 0x3 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci/* IDT 75N43102 GMR base addresses (low 32 bits) */ 7762306a36Sopenharmony_ci#define IDT4_GMR_BASE0 0x10 7862306a36Sopenharmony_ci#define IDT4_GMR_BASE1 0x20 7962306a36Sopenharmony_ci#define IDT4_GMR_BASE2 0x30 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci/* IDT 75N43102 data and mask array base addresses (low 32 bits) */ 8262306a36Sopenharmony_ci#define IDT4_DATARY_BASE_ADR0 0x1000000 8362306a36Sopenharmony_ci#define IDT4_MSKARY_BASE_ADR0 0x2000000 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci#define MAX_WRITE_ATTEMPTS 5 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci#define MAX_ROUTES 2048 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci/* 9062306a36Sopenharmony_ci * Issue a command to the TCAM and wait for its completion. The address and 9162306a36Sopenharmony_ci * any data required by the command must have been setup by the caller. 9262306a36Sopenharmony_ci */ 9362306a36Sopenharmony_cistatic int mc5_cmd_write(struct adapter *adapter, u32 cmd) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_CMD, cmd); 9662306a36Sopenharmony_ci return t3_wait_op_done(adapter, A_MC5_DB_DBGI_RSP_STATUS, 9762306a36Sopenharmony_ci F_DBGIRSPVALID, 1, MAX_WRITE_ATTEMPTS, 1); 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistatic inline void dbgi_wr_data3(struct adapter *adapter, u32 v1, u32 v2, 10162306a36Sopenharmony_ci u32 v3) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_DATA0, v1); 10462306a36Sopenharmony_ci t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_DATA1, v2); 10562306a36Sopenharmony_ci t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_DATA2, v3); 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci/* 10962306a36Sopenharmony_ci * Write data to the TCAM register at address (0, 0, addr_lo) using the TCAM 11062306a36Sopenharmony_ci * command cmd. The data to be written must have been set up by the caller. 11162306a36Sopenharmony_ci * Returns -1 on failure, 0 on success. 11262306a36Sopenharmony_ci */ 11362306a36Sopenharmony_cistatic int mc5_write(struct adapter *adapter, u32 addr_lo, u32 cmd) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR0, addr_lo); 11662306a36Sopenharmony_ci if (mc5_cmd_write(adapter, cmd) == 0) 11762306a36Sopenharmony_ci return 0; 11862306a36Sopenharmony_ci CH_ERR(adapter, "MC5 timeout writing to TCAM address 0x%x\n", 11962306a36Sopenharmony_ci addr_lo); 12062306a36Sopenharmony_ci return -1; 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic int init_mask_data_array(struct mc5 *mc5, u32 mask_array_base, 12462306a36Sopenharmony_ci u32 data_array_base, u32 write_cmd, 12562306a36Sopenharmony_ci int addr_shift) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci unsigned int i; 12862306a36Sopenharmony_ci struct adapter *adap = mc5->adapter; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci /* 13162306a36Sopenharmony_ci * We need the size of the TCAM data and mask arrays in terms of 13262306a36Sopenharmony_ci * 72-bit entries. 13362306a36Sopenharmony_ci */ 13462306a36Sopenharmony_ci unsigned int size72 = mc5->tcam_size; 13562306a36Sopenharmony_ci unsigned int server_base = t3_read_reg(adap, A_MC5_DB_SERVER_INDEX); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci if (mc5->mode == MC5_MODE_144_BIT) { 13862306a36Sopenharmony_ci size72 *= 2; /* 1 144-bit entry is 2 72-bit entries */ 13962306a36Sopenharmony_ci server_base *= 2; 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci /* Clear the data array */ 14362306a36Sopenharmony_ci dbgi_wr_data3(adap, 0, 0, 0); 14462306a36Sopenharmony_ci for (i = 0; i < size72; i++) 14562306a36Sopenharmony_ci if (mc5_write(adap, data_array_base + (i << addr_shift), 14662306a36Sopenharmony_ci write_cmd)) 14762306a36Sopenharmony_ci return -1; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci /* Initialize the mask array. */ 15062306a36Sopenharmony_ci dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff); 15162306a36Sopenharmony_ci for (i = 0; i < size72; i++) { 15262306a36Sopenharmony_ci if (i == server_base) /* entering server or routing region */ 15362306a36Sopenharmony_ci t3_write_reg(adap, A_MC5_DB_DBGI_REQ_DATA0, 15462306a36Sopenharmony_ci mc5->mode == MC5_MODE_144_BIT ? 15562306a36Sopenharmony_ci 0xfffffff9 : 0xfffffffd); 15662306a36Sopenharmony_ci if (mc5_write(adap, mask_array_base + (i << addr_shift), 15762306a36Sopenharmony_ci write_cmd)) 15862306a36Sopenharmony_ci return -1; 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci return 0; 16162306a36Sopenharmony_ci} 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_cistatic int init_idt52100(struct mc5 *mc5) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci int i; 16662306a36Sopenharmony_ci struct adapter *adap = mc5->adapter; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci t3_write_reg(adap, A_MC5_DB_RSP_LATENCY, 16962306a36Sopenharmony_ci V_RDLAT(0x15) | V_LRNLAT(0x15) | V_SRCHLAT(0x15)); 17062306a36Sopenharmony_ci t3_write_reg(adap, A_MC5_DB_PART_ID_INDEX, 2); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci /* 17362306a36Sopenharmony_ci * Use GMRs 14-15 for ELOOKUP, GMRs 12-13 for SYN lookups, and 17462306a36Sopenharmony_ci * GMRs 8-9 for ACK- and AOPEN searches. 17562306a36Sopenharmony_ci */ 17662306a36Sopenharmony_ci t3_write_reg(adap, A_MC5_DB_POPEN_DATA_WR_CMD, IDT_CMD_WRITE); 17762306a36Sopenharmony_ci t3_write_reg(adap, A_MC5_DB_POPEN_MASK_WR_CMD, IDT_CMD_WRITE); 17862306a36Sopenharmony_ci t3_write_reg(adap, A_MC5_DB_AOPEN_SRCH_CMD, IDT_CMD_SEARCH); 17962306a36Sopenharmony_ci t3_write_reg(adap, A_MC5_DB_AOPEN_LRN_CMD, IDT_CMD_LEARN); 18062306a36Sopenharmony_ci t3_write_reg(adap, A_MC5_DB_SYN_SRCH_CMD, IDT_CMD_SEARCH | 0x6000); 18162306a36Sopenharmony_ci t3_write_reg(adap, A_MC5_DB_SYN_LRN_CMD, IDT_CMD_LEARN); 18262306a36Sopenharmony_ci t3_write_reg(adap, A_MC5_DB_ACK_SRCH_CMD, IDT_CMD_SEARCH); 18362306a36Sopenharmony_ci t3_write_reg(adap, A_MC5_DB_ACK_LRN_CMD, IDT_CMD_LEARN); 18462306a36Sopenharmony_ci t3_write_reg(adap, A_MC5_DB_ILOOKUP_CMD, IDT_CMD_SEARCH); 18562306a36Sopenharmony_ci t3_write_reg(adap, A_MC5_DB_ELOOKUP_CMD, IDT_CMD_SEARCH | 0x7000); 18662306a36Sopenharmony_ci t3_write_reg(adap, A_MC5_DB_DATA_WRITE_CMD, IDT_CMD_WRITE); 18762306a36Sopenharmony_ci t3_write_reg(adap, A_MC5_DB_DATA_READ_CMD, IDT_CMD_READ); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci /* Set DBGI command mode for IDT TCAM. */ 19062306a36Sopenharmony_ci t3_write_reg(adap, A_MC5_DB_DBGI_CONFIG, DBGI_MODE_IDT52100); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci /* Set up LAR */ 19362306a36Sopenharmony_ci dbgi_wr_data3(adap, IDT_LAR_MODE144, 0, 0); 19462306a36Sopenharmony_ci if (mc5_write(adap, IDT_LAR_ADR0, IDT_CMD_WRITE)) 19562306a36Sopenharmony_ci goto err; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci /* Set up SSRs */ 19862306a36Sopenharmony_ci dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0); 19962306a36Sopenharmony_ci if (mc5_write(adap, IDT_SSR0_ADR0, IDT_CMD_WRITE) || 20062306a36Sopenharmony_ci mc5_write(adap, IDT_SSR1_ADR0, IDT_CMD_WRITE)) 20162306a36Sopenharmony_ci goto err; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci /* Set up GMRs */ 20462306a36Sopenharmony_ci for (i = 0; i < 32; ++i) { 20562306a36Sopenharmony_ci if (i >= 12 && i < 15) 20662306a36Sopenharmony_ci dbgi_wr_data3(adap, 0xfffffff9, 0xffffffff, 0xff); 20762306a36Sopenharmony_ci else if (i == 15) 20862306a36Sopenharmony_ci dbgi_wr_data3(adap, 0xfffffff9, 0xffff8007, 0xff); 20962306a36Sopenharmony_ci else 21062306a36Sopenharmony_ci dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci if (mc5_write(adap, IDT_GMR_BASE_ADR0 + i, IDT_CMD_WRITE)) 21362306a36Sopenharmony_ci goto err; 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci /* Set up SCR */ 21762306a36Sopenharmony_ci dbgi_wr_data3(adap, 1, 0, 0); 21862306a36Sopenharmony_ci if (mc5_write(adap, IDT_SCR_ADR0, IDT_CMD_WRITE)) 21962306a36Sopenharmony_ci goto err; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci return init_mask_data_array(mc5, IDT_MSKARY_BASE_ADR0, 22262306a36Sopenharmony_ci IDT_DATARY_BASE_ADR0, IDT_CMD_WRITE, 0); 22362306a36Sopenharmony_cierr: 22462306a36Sopenharmony_ci return -EIO; 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cistatic int init_idt43102(struct mc5 *mc5) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci int i; 23062306a36Sopenharmony_ci struct adapter *adap = mc5->adapter; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci t3_write_reg(adap, A_MC5_DB_RSP_LATENCY, 23362306a36Sopenharmony_ci adap->params.rev == 0 ? V_RDLAT(0xd) | V_SRCHLAT(0x11) : 23462306a36Sopenharmony_ci V_RDLAT(0xd) | V_SRCHLAT(0x12)); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci /* 23762306a36Sopenharmony_ci * Use GMRs 24-25 for ELOOKUP, GMRs 20-21 for SYN lookups, and no mask 23862306a36Sopenharmony_ci * for ACK- and AOPEN searches. 23962306a36Sopenharmony_ci */ 24062306a36Sopenharmony_ci t3_write_reg(adap, A_MC5_DB_POPEN_DATA_WR_CMD, IDT4_CMD_WRITE); 24162306a36Sopenharmony_ci t3_write_reg(adap, A_MC5_DB_POPEN_MASK_WR_CMD, IDT4_CMD_WRITE); 24262306a36Sopenharmony_ci t3_write_reg(adap, A_MC5_DB_AOPEN_SRCH_CMD, 24362306a36Sopenharmony_ci IDT4_CMD_SEARCH144 | 0x3800); 24462306a36Sopenharmony_ci t3_write_reg(adap, A_MC5_DB_SYN_SRCH_CMD, IDT4_CMD_SEARCH144); 24562306a36Sopenharmony_ci t3_write_reg(adap, A_MC5_DB_ACK_SRCH_CMD, IDT4_CMD_SEARCH144 | 0x3800); 24662306a36Sopenharmony_ci t3_write_reg(adap, A_MC5_DB_ILOOKUP_CMD, IDT4_CMD_SEARCH144 | 0x3800); 24762306a36Sopenharmony_ci t3_write_reg(adap, A_MC5_DB_ELOOKUP_CMD, IDT4_CMD_SEARCH144 | 0x800); 24862306a36Sopenharmony_ci t3_write_reg(adap, A_MC5_DB_DATA_WRITE_CMD, IDT4_CMD_WRITE); 24962306a36Sopenharmony_ci t3_write_reg(adap, A_MC5_DB_DATA_READ_CMD, IDT4_CMD_READ); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci t3_write_reg(adap, A_MC5_DB_PART_ID_INDEX, 3); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci /* Set DBGI command mode for IDT TCAM. */ 25462306a36Sopenharmony_ci t3_write_reg(adap, A_MC5_DB_DBGI_CONFIG, DBGI_MODE_IDT52100); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci /* Set up GMRs */ 25762306a36Sopenharmony_ci dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff); 25862306a36Sopenharmony_ci for (i = 0; i < 7; ++i) 25962306a36Sopenharmony_ci if (mc5_write(adap, IDT4_GMR_BASE0 + i, IDT4_CMD_WRITE)) 26062306a36Sopenharmony_ci goto err; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci for (i = 0; i < 4; ++i) 26362306a36Sopenharmony_ci if (mc5_write(adap, IDT4_GMR_BASE2 + i, IDT4_CMD_WRITE)) 26462306a36Sopenharmony_ci goto err; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci dbgi_wr_data3(adap, 0xfffffff9, 0xffffffff, 0xff); 26762306a36Sopenharmony_ci if (mc5_write(adap, IDT4_GMR_BASE1, IDT4_CMD_WRITE) || 26862306a36Sopenharmony_ci mc5_write(adap, IDT4_GMR_BASE1 + 1, IDT4_CMD_WRITE) || 26962306a36Sopenharmony_ci mc5_write(adap, IDT4_GMR_BASE1 + 4, IDT4_CMD_WRITE)) 27062306a36Sopenharmony_ci goto err; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci dbgi_wr_data3(adap, 0xfffffff9, 0xffff8007, 0xff); 27362306a36Sopenharmony_ci if (mc5_write(adap, IDT4_GMR_BASE1 + 5, IDT4_CMD_WRITE)) 27462306a36Sopenharmony_ci goto err; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci /* Set up SCR */ 27762306a36Sopenharmony_ci dbgi_wr_data3(adap, 0xf0000000, 0, 0); 27862306a36Sopenharmony_ci if (mc5_write(adap, IDT4_SCR_ADR0, IDT4_CMD_WRITE)) 27962306a36Sopenharmony_ci goto err; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci return init_mask_data_array(mc5, IDT4_MSKARY_BASE_ADR0, 28262306a36Sopenharmony_ci IDT4_DATARY_BASE_ADR0, IDT4_CMD_WRITE, 1); 28362306a36Sopenharmony_cierr: 28462306a36Sopenharmony_ci return -EIO; 28562306a36Sopenharmony_ci} 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci/* Put MC5 in DBGI mode. */ 28862306a36Sopenharmony_cistatic inline void mc5_dbgi_mode_enable(const struct mc5 *mc5) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci t3_write_reg(mc5->adapter, A_MC5_DB_CONFIG, 29162306a36Sopenharmony_ci V_TMMODE(mc5->mode == MC5_MODE_72_BIT) | F_DBGIEN); 29262306a36Sopenharmony_ci} 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci/* Put MC5 in M-Bus mode. */ 29562306a36Sopenharmony_cistatic void mc5_dbgi_mode_disable(const struct mc5 *mc5) 29662306a36Sopenharmony_ci{ 29762306a36Sopenharmony_ci t3_write_reg(mc5->adapter, A_MC5_DB_CONFIG, 29862306a36Sopenharmony_ci V_TMMODE(mc5->mode == MC5_MODE_72_BIT) | 29962306a36Sopenharmony_ci V_COMPEN(mc5->mode == MC5_MODE_72_BIT) | 30062306a36Sopenharmony_ci V_PRTYEN(mc5->parity_enabled) | F_MBUSEN); 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci/* 30462306a36Sopenharmony_ci * Initialization that requires the OS and protocol layers to already 30562306a36Sopenharmony_ci * be initialized goes here. 30662306a36Sopenharmony_ci */ 30762306a36Sopenharmony_ciint t3_mc5_init(struct mc5 *mc5, unsigned int nservers, unsigned int nfilters, 30862306a36Sopenharmony_ci unsigned int nroutes) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci u32 cfg; 31162306a36Sopenharmony_ci int err; 31262306a36Sopenharmony_ci unsigned int tcam_size = mc5->tcam_size; 31362306a36Sopenharmony_ci struct adapter *adap = mc5->adapter; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci if (!tcam_size) 31662306a36Sopenharmony_ci return 0; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci if (nroutes > MAX_ROUTES || nroutes + nservers + nfilters > tcam_size) 31962306a36Sopenharmony_ci return -EINVAL; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci /* Reset the TCAM */ 32262306a36Sopenharmony_ci cfg = t3_read_reg(adap, A_MC5_DB_CONFIG) & ~F_TMMODE; 32362306a36Sopenharmony_ci cfg |= V_TMMODE(mc5->mode == MC5_MODE_72_BIT) | F_TMRST; 32462306a36Sopenharmony_ci t3_write_reg(adap, A_MC5_DB_CONFIG, cfg); 32562306a36Sopenharmony_ci if (t3_wait_op_done(adap, A_MC5_DB_CONFIG, F_TMRDY, 1, 500, 0)) { 32662306a36Sopenharmony_ci CH_ERR(adap, "TCAM reset timed out\n"); 32762306a36Sopenharmony_ci return -1; 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci t3_write_reg(adap, A_MC5_DB_ROUTING_TABLE_INDEX, tcam_size - nroutes); 33162306a36Sopenharmony_ci t3_write_reg(adap, A_MC5_DB_FILTER_TABLE, 33262306a36Sopenharmony_ci tcam_size - nroutes - nfilters); 33362306a36Sopenharmony_ci t3_write_reg(adap, A_MC5_DB_SERVER_INDEX, 33462306a36Sopenharmony_ci tcam_size - nroutes - nfilters - nservers); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci mc5->parity_enabled = 1; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci /* All the TCAM addresses we access have only the low 32 bits non 0 */ 33962306a36Sopenharmony_ci t3_write_reg(adap, A_MC5_DB_DBGI_REQ_ADDR1, 0); 34062306a36Sopenharmony_ci t3_write_reg(adap, A_MC5_DB_DBGI_REQ_ADDR2, 0); 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci mc5_dbgi_mode_enable(mc5); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci switch (mc5->part_type) { 34562306a36Sopenharmony_ci case IDT75P52100: 34662306a36Sopenharmony_ci err = init_idt52100(mc5); 34762306a36Sopenharmony_ci break; 34862306a36Sopenharmony_ci case IDT75N43102: 34962306a36Sopenharmony_ci err = init_idt43102(mc5); 35062306a36Sopenharmony_ci break; 35162306a36Sopenharmony_ci default: 35262306a36Sopenharmony_ci CH_ERR(adap, "Unsupported TCAM type %d\n", mc5->part_type); 35362306a36Sopenharmony_ci err = -EINVAL; 35462306a36Sopenharmony_ci break; 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci mc5_dbgi_mode_disable(mc5); 35862306a36Sopenharmony_ci return err; 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci#define MC5_INT_FATAL (F_PARITYERR | F_REQQPARERR | F_DISPQPARERR) 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci/* 36562306a36Sopenharmony_ci * MC5 interrupt handler 36662306a36Sopenharmony_ci */ 36762306a36Sopenharmony_civoid t3_mc5_intr_handler(struct mc5 *mc5) 36862306a36Sopenharmony_ci{ 36962306a36Sopenharmony_ci struct adapter *adap = mc5->adapter; 37062306a36Sopenharmony_ci u32 cause = t3_read_reg(adap, A_MC5_DB_INT_CAUSE); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci if ((cause & F_PARITYERR) && mc5->parity_enabled) { 37362306a36Sopenharmony_ci CH_ALERT(adap, "MC5 parity error\n"); 37462306a36Sopenharmony_ci mc5->stats.parity_err++; 37562306a36Sopenharmony_ci } 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci if (cause & F_REQQPARERR) { 37862306a36Sopenharmony_ci CH_ALERT(adap, "MC5 request queue parity error\n"); 37962306a36Sopenharmony_ci mc5->stats.reqq_parity_err++; 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci if (cause & F_DISPQPARERR) { 38362306a36Sopenharmony_ci CH_ALERT(adap, "MC5 dispatch queue parity error\n"); 38462306a36Sopenharmony_ci mc5->stats.dispq_parity_err++; 38562306a36Sopenharmony_ci } 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci if (cause & F_ACTRGNFULL) 38862306a36Sopenharmony_ci mc5->stats.active_rgn_full++; 38962306a36Sopenharmony_ci if (cause & F_NFASRCHFAIL) 39062306a36Sopenharmony_ci mc5->stats.nfa_srch_err++; 39162306a36Sopenharmony_ci if (cause & F_UNKNOWNCMD) 39262306a36Sopenharmony_ci mc5->stats.unknown_cmd++; 39362306a36Sopenharmony_ci if (cause & F_DELACTEMPTY) 39462306a36Sopenharmony_ci mc5->stats.del_act_empty++; 39562306a36Sopenharmony_ci if (cause & MC5_INT_FATAL) 39662306a36Sopenharmony_ci t3_fatal_err(adap); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci t3_write_reg(adap, A_MC5_DB_INT_CAUSE, cause); 39962306a36Sopenharmony_ci} 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_civoid t3_mc5_prep(struct adapter *adapter, struct mc5 *mc5, int mode) 40262306a36Sopenharmony_ci{ 40362306a36Sopenharmony_ci#define K * 1024 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci static unsigned int tcam_part_size[] = { /* in K 72-bit entries */ 40662306a36Sopenharmony_ci 64 K, 128 K, 256 K, 32 K 40762306a36Sopenharmony_ci }; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci#undef K 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci u32 cfg = t3_read_reg(adapter, A_MC5_DB_CONFIG); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci mc5->adapter = adapter; 41462306a36Sopenharmony_ci mc5->mode = (unsigned char)mode; 41562306a36Sopenharmony_ci mc5->part_type = (unsigned char)G_TMTYPE(cfg); 41662306a36Sopenharmony_ci if (cfg & F_TMTYPEHI) 41762306a36Sopenharmony_ci mc5->part_type |= 4; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci mc5->tcam_size = tcam_part_size[G_TMPARTSIZE(cfg)]; 42062306a36Sopenharmony_ci if (mode == MC5_MODE_144_BIT) 42162306a36Sopenharmony_ci mc5->tcam_size /= 2; 42262306a36Sopenharmony_ci} 423