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