1*d39a76e7Sxw161283 /* 2*d39a76e7Sxw161283 * CDDL HEADER START 3*d39a76e7Sxw161283 * 4*d39a76e7Sxw161283 * The contents of this file are subject to the terms of the 5*d39a76e7Sxw161283 * Common Development and Distribution License (the "License"). 6*d39a76e7Sxw161283 * You may not use this file except in compliance with the License. 7*d39a76e7Sxw161283 * 8*d39a76e7Sxw161283 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*d39a76e7Sxw161283 * or http://www.opensolaris.org/os/licensing. 10*d39a76e7Sxw161283 * See the License for the specific language governing permissions 11*d39a76e7Sxw161283 * and limitations under the License. 12*d39a76e7Sxw161283 * 13*d39a76e7Sxw161283 * When distributing Covered Code, include this CDDL HEADER in each 14*d39a76e7Sxw161283 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*d39a76e7Sxw161283 * If applicable, add the following below this CDDL HEADER, with the 16*d39a76e7Sxw161283 * fields enclosed by brackets "[]" replaced with your own identifying 17*d39a76e7Sxw161283 * information: Portions Copyright [yyyy] [name of copyright owner] 18*d39a76e7Sxw161283 * 19*d39a76e7Sxw161283 * CDDL HEADER END 20*d39a76e7Sxw161283 */ 21*d39a76e7Sxw161283 22*d39a76e7Sxw161283 /* 23*d39a76e7Sxw161283 * Copyright (C) 2003-2005 Chelsio Communications. All rights reserved. 24*d39a76e7Sxw161283 */ 25*d39a76e7Sxw161283 26*d39a76e7Sxw161283 #pragma ident "%Z%%M% %I% %E% SMI" /* mc5.c */ 27*d39a76e7Sxw161283 28*d39a76e7Sxw161283 #include "common.h" 29*d39a76e7Sxw161283 #include "regs.h" 30*d39a76e7Sxw161283 #include "mc5.h" 31*d39a76e7Sxw161283 32*d39a76e7Sxw161283 /* DBGI command mode */ 33*d39a76e7Sxw161283 enum { 34*d39a76e7Sxw161283 DBGI_MODE_MBUS, 35*d39a76e7Sxw161283 DBGI_MODE_LARA_7000, 36*d39a76e7Sxw161283 DBGI_MODE_LARA_8000, 37*d39a76e7Sxw161283 DBGI_MODE_NETL_4000, 38*d39a76e7Sxw161283 DBGI_MODE_NETL_5000, 39*d39a76e7Sxw161283 DBGI_MODE_IDT_52100 40*d39a76e7Sxw161283 }; 41*d39a76e7Sxw161283 42*d39a76e7Sxw161283 /* Lara command register address and values (low 32 bits) */ 43*d39a76e7Sxw161283 #define MC5_LRA_CMDREG_ADR0 0x00180038 44*d39a76e7Sxw161283 #define MC5_LRA_CMDREG_72KEY_DATA0 0x00000182 45*d39a76e7Sxw161283 #define MC5_LRA_CMDREG_144KEY_DATA0 0x00AAAB82 46*d39a76e7Sxw161283 47*d39a76e7Sxw161283 /* Lara config register address and values (low 32 bits) */ 48*d39a76e7Sxw161283 #define MC5_LRA_CFGREG_ADR0 0x0018003D 49*d39a76e7Sxw161283 #define MC5_LRA_CFGREG_72KEY_DATA0 0x00000000 50*d39a76e7Sxw161283 #define MC5_LRA_CFGREG_144KEY_DATA0 0x55555555 51*d39a76e7Sxw161283 52*d39a76e7Sxw161283 /* Lara GMR base addresses (low 32 bits) */ 53*d39a76e7Sxw161283 #define MC5_LRA_GMRREG_BASE_ADR0_1 0x00180020 54*d39a76e7Sxw161283 #define MC5_LRA_GMRREG_BASE_ADR0_2 0x00180060 55*d39a76e7Sxw161283 56*d39a76e7Sxw161283 /* Lara 7000 data and mask array base addresses (low 32 bits) */ 57*d39a76e7Sxw161283 #define MC5_LRA_DATARY_BASE_ADR0 0x00000000 58*d39a76e7Sxw161283 #define MC5_LRA_MSKARY_BASE_ADR0 0x00080000 59*d39a76e7Sxw161283 60*d39a76e7Sxw161283 /* Lara commands */ 61*d39a76e7Sxw161283 #define MC5_LRA_CMD_READ 0x00000000 62*d39a76e7Sxw161283 #define MC5_LRA_CMD_WRITE 0x00010001 63*d39a76e7Sxw161283 #define MC5_LRA_CMD_SEARCH 0x00020002 64*d39a76e7Sxw161283 #define MC5_LRA_CMD_LEARN 0x00030003 65*d39a76e7Sxw161283 66*d39a76e7Sxw161283 /* IDT 75P52100 commands */ 67*d39a76e7Sxw161283 #define MC5_IDT_CMD_READ 0x0 68*d39a76e7Sxw161283 #define MC5_IDT_CMD_WRITE 0x1 69*d39a76e7Sxw161283 #define MC5_IDT_CMD_SEARCH 0x2 70*d39a76e7Sxw161283 #define MC5_IDT_CMD_LEARN 0x3 71*d39a76e7Sxw161283 #define MC5_IDT_CMD_NFA_SEARCH 0x4 72*d39a76e7Sxw161283 73*d39a76e7Sxw161283 /* IDT LAR register address and value for 144-bit mode (low 32 bits) */ 74*d39a76e7Sxw161283 #define MC5_IDT_LAR_ADR0 0x180006 75*d39a76e7Sxw161283 #define MC5_IDT_LAR_MODE144 0xffff0000 76*d39a76e7Sxw161283 77*d39a76e7Sxw161283 /* IDT SCR and SSR addresses (low 32 bits) */ 78*d39a76e7Sxw161283 #define MC5_IDT_SCR_ADR0 0x180000 79*d39a76e7Sxw161283 #define MC5_IDT_SSR0_ADR0 0x180002 80*d39a76e7Sxw161283 #define MC5_IDT_SSR1_ADR0 0x180004 81*d39a76e7Sxw161283 82*d39a76e7Sxw161283 /* IDT GMR base address (low 32 bits) */ 83*d39a76e7Sxw161283 #define MC5_IDT_GMR_BASE_ADR0 0x180020 84*d39a76e7Sxw161283 85*d39a76e7Sxw161283 /* IDT data and mask array base addresses (low 32 bits) */ 86*d39a76e7Sxw161283 #define MC5_IDT_DATARY_BASE_ADR0 0x00000000 87*d39a76e7Sxw161283 #define MC5_IDT_MSKARY_BASE_ADR0 0x00080000 88*d39a76e7Sxw161283 89*d39a76e7Sxw161283 #define IDT_ELOOKUP_2Mb 0x7000 90*d39a76e7Sxw161283 #define IDT_ELOOKUP_9Mb 0x16000 91*d39a76e7Sxw161283 92*d39a76e7Sxw161283 enum { 93*d39a76e7Sxw161283 LARA_7000, 94*d39a76e7Sxw161283 LARA_8000, 95*d39a76e7Sxw161283 NETLOGIC_4000, 96*d39a76e7Sxw161283 NETLOGIC_5000, 97*d39a76e7Sxw161283 IDT75P52100 98*d39a76e7Sxw161283 }; 99*d39a76e7Sxw161283 100*d39a76e7Sxw161283 static unsigned int tcam_part_size[] = { 101*d39a76e7Sxw161283 4718592, /* 4.5Mb */ 102*d39a76e7Sxw161283 9437184, /* 9Mb */ 103*d39a76e7Sxw161283 18874368 /* 18Mb */ 104*d39a76e7Sxw161283 }; 105*d39a76e7Sxw161283 106*d39a76e7Sxw161283 struct pemc5 { 107*d39a76e7Sxw161283 adapter_t *adapter; 108*d39a76e7Sxw161283 unsigned int tcam_size; 109*d39a76e7Sxw161283 unsigned int part_size; 110*d39a76e7Sxw161283 unsigned char part_type; 111*d39a76e7Sxw161283 unsigned char parity_enabled; 112*d39a76e7Sxw161283 unsigned char issue_syn; 113*d39a76e7Sxw161283 unsigned char mode; 114*d39a76e7Sxw161283 struct pemc5_intr_counts intr_counts; 115*d39a76e7Sxw161283 #ifdef SUPPORT_MODE72 116*d39a76e7Sxw161283 u32 lip[MC5_LIP_NUM_OF_ENTRIES]; 117*d39a76e7Sxw161283 unsigned int lip_index; 118*d39a76e7Sxw161283 #endif 119*d39a76e7Sxw161283 }; 120*d39a76e7Sxw161283 121*d39a76e7Sxw161283 #define MAX_WRITE_ATTEMPTS 5 122*d39a76e7Sxw161283 123*d39a76e7Sxw161283 /* 124*d39a76e7Sxw161283 * Issue a command to the TCAM and wait for its completion. The address and 125*d39a76e7Sxw161283 * any data required by the command must have been setup by the caller. 126*d39a76e7Sxw161283 */ 127*d39a76e7Sxw161283 static int mc5_cmd_write(adapter_t *adapter, u32 cmd) 128*d39a76e7Sxw161283 { 129*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_MC5_DBGI_REQ_CMD, cmd); 130*d39a76e7Sxw161283 return t1_wait_op_done(adapter, A_MC5_DBGI_RSP_STATUS, 131*d39a76e7Sxw161283 F_DBGI_RSP_VALID, 1, MAX_WRITE_ATTEMPTS, 1); 132*d39a76e7Sxw161283 } 133*d39a76e7Sxw161283 134*d39a76e7Sxw161283 135*d39a76e7Sxw161283 unsigned int t1_mc5_get_tcam_size(struct pemc5 *mc5) 136*d39a76e7Sxw161283 { 137*d39a76e7Sxw161283 return mc5->tcam_size; 138*d39a76e7Sxw161283 } 139*d39a76e7Sxw161283 140*d39a76e7Sxw161283 static int set_tcam_rtbl_base(struct pemc5 *mc5, unsigned int rtbl_base) 141*d39a76e7Sxw161283 { 142*d39a76e7Sxw161283 if (rtbl_base >= t1_mc5_get_tcam_size(mc5)) return -1; 143*d39a76e7Sxw161283 t1_write_reg_4(mc5->adapter, A_MC5_ROUTING_TABLE_INDEX, rtbl_base); 144*d39a76e7Sxw161283 return 0; 145*d39a76e7Sxw161283 } 146*d39a76e7Sxw161283 147*d39a76e7Sxw161283 unsigned int t1_mc5_get_tcam_rtbl_base(struct pemc5 *mc5) 148*d39a76e7Sxw161283 { 149*d39a76e7Sxw161283 return t1_read_reg_4(mc5->adapter, A_MC5_ROUTING_TABLE_INDEX); 150*d39a76e7Sxw161283 } 151*d39a76e7Sxw161283 152*d39a76e7Sxw161283 unsigned int t1_mc5_get_tcam_rtbl_size(struct pemc5 *mc5) 153*d39a76e7Sxw161283 { 154*d39a76e7Sxw161283 unsigned int tcam_size = t1_mc5_get_tcam_size(mc5); 155*d39a76e7Sxw161283 unsigned int tcam_rtable_base = t1_mc5_get_tcam_rtbl_base(mc5); 156*d39a76e7Sxw161283 157*d39a76e7Sxw161283 return tcam_size - tcam_rtable_base; 158*d39a76e7Sxw161283 } 159*d39a76e7Sxw161283 160*d39a76e7Sxw161283 static int set_tcam_server_base(struct pemc5 *mc5, unsigned int server_base) 161*d39a76e7Sxw161283 { 162*d39a76e7Sxw161283 if (server_base >= t1_mc5_get_tcam_size(mc5)) return -1; 163*d39a76e7Sxw161283 t1_write_reg_4(mc5->adapter, A_MC5_SERVER_INDEX, server_base); 164*d39a76e7Sxw161283 return 0; 165*d39a76e7Sxw161283 } 166*d39a76e7Sxw161283 167*d39a76e7Sxw161283 unsigned int t1_mc5_get_tcam_server_base(struct pemc5 *mc5) 168*d39a76e7Sxw161283 { 169*d39a76e7Sxw161283 return t1_read_reg_4(mc5->adapter, A_MC5_SERVER_INDEX); 170*d39a76e7Sxw161283 } 171*d39a76e7Sxw161283 172*d39a76e7Sxw161283 unsigned int t1_mc5_get_tcam_server_size(struct pemc5 *mc5) 173*d39a76e7Sxw161283 { 174*d39a76e7Sxw161283 unsigned int tcam_rtable_base = t1_mc5_get_tcam_rtbl_base(mc5); 175*d39a76e7Sxw161283 unsigned int tcam_server_base = t1_mc5_get_tcam_server_base(mc5); 176*d39a76e7Sxw161283 177*d39a76e7Sxw161283 return tcam_rtable_base - tcam_server_base; 178*d39a76e7Sxw161283 } 179*d39a76e7Sxw161283 180*d39a76e7Sxw161283 static inline void dbgi_wr_addr3(adapter_t *adapter, u32 v1, u32 v2, u32 v3) 181*d39a76e7Sxw161283 { 182*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_MC5_DBGI_REQ_ADDR0, v1); 183*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_MC5_DBGI_REQ_ADDR1, v2); 184*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_MC5_DBGI_REQ_ADDR2, v3); 185*d39a76e7Sxw161283 } 186*d39a76e7Sxw161283 187*d39a76e7Sxw161283 static inline void dbgi_wr_data3(adapter_t *adapter, u32 v1, u32 v2, u32 v3) 188*d39a76e7Sxw161283 { 189*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_MC5_DBGI_REQ_DATA0, v1); 190*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_MC5_DBGI_REQ_DATA1, v2); 191*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_MC5_DBGI_REQ_DATA2, v3); 192*d39a76e7Sxw161283 } 193*d39a76e7Sxw161283 194*d39a76e7Sxw161283 static inline void dbgi_rd_rsp3(adapter_t *adapter, u32 *v1, u32 *v2, u32 *v3) 195*d39a76e7Sxw161283 { 196*d39a76e7Sxw161283 *v1 = t1_read_reg_4(adapter, A_MC5_DBGI_RSP_DATA0); 197*d39a76e7Sxw161283 *v2 = t1_read_reg_4(adapter, A_MC5_DBGI_RSP_DATA1); 198*d39a76e7Sxw161283 *v3 = t1_read_reg_4(adapter, A_MC5_DBGI_RSP_DATA2); 199*d39a76e7Sxw161283 } 200*d39a76e7Sxw161283 201*d39a76e7Sxw161283 /* 202*d39a76e7Sxw161283 * Write data to the TCAM register at address (0, 0, addr_lo) using the TCAM 203*d39a76e7Sxw161283 * command cmd. The data to be written must have been set up by the caller. 204*d39a76e7Sxw161283 * Returns -1 on failure, 0 on success. 205*d39a76e7Sxw161283 */ 206*d39a76e7Sxw161283 static int mc5_write(adapter_t *adapter, u32 addr_lo, u32 cmd) 207*d39a76e7Sxw161283 { 208*d39a76e7Sxw161283 t1_write_reg_4(adapter, A_MC5_DBGI_REQ_ADDR0, addr_lo); 209*d39a76e7Sxw161283 if (mc5_cmd_write(adapter, cmd) == 0) 210*d39a76e7Sxw161283 return 0; 211*d39a76e7Sxw161283 CH_ERR("%s: MC5 timeout writing to TCAM address 0x%x\n", 212*d39a76e7Sxw161283 adapter_name(adapter), addr_lo); 213*d39a76e7Sxw161283 return -1; 214*d39a76e7Sxw161283 } 215*d39a76e7Sxw161283 216*d39a76e7Sxw161283 static int init_mask_data_array(struct pemc5 *mc5, u32 mask_array_base, 217*d39a76e7Sxw161283 u32 data_array_base, u32 write_cmd) 218*d39a76e7Sxw161283 { 219*d39a76e7Sxw161283 unsigned int i; 220*d39a76e7Sxw161283 adapter_t *adap = mc5->adapter; 221*d39a76e7Sxw161283 222*d39a76e7Sxw161283 /* 223*d39a76e7Sxw161283 * We need the size of the TCAM data and mask arrays in terms of 224*d39a76e7Sxw161283 * 72-bit entries. 225*d39a76e7Sxw161283 */ 226*d39a76e7Sxw161283 unsigned int size72 = tcam_part_size[mc5->part_size] / 72; 227*d39a76e7Sxw161283 unsigned int server_base = t1_mc5_get_tcam_server_base(mc5); 228*d39a76e7Sxw161283 if (mc5->mode == MC5_MODE_144_BIT) 229*d39a76e7Sxw161283 server_base *= 2; /* 1 144-bit entry is 2 72-bit entries */ 230*d39a76e7Sxw161283 231*d39a76e7Sxw161283 /* Clear the data array */ 232*d39a76e7Sxw161283 dbgi_wr_data3(adap, 0, 0, 0); 233*d39a76e7Sxw161283 for (i = 0; i < size72; i++) 234*d39a76e7Sxw161283 if (mc5_write(adap, data_array_base + i, write_cmd)) 235*d39a76e7Sxw161283 return -1; 236*d39a76e7Sxw161283 237*d39a76e7Sxw161283 /* Initialize the mask array. */ 238*d39a76e7Sxw161283 dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff); 239*d39a76e7Sxw161283 for (i = 0; i < size72; i++) { 240*d39a76e7Sxw161283 if (i == server_base) /* entering server or routing region */ 241*d39a76e7Sxw161283 t1_write_reg_4(adap, A_MC5_DBGI_REQ_DATA0, 242*d39a76e7Sxw161283 mc5->mode == MC5_MODE_144_BIT ? 243*d39a76e7Sxw161283 0xfffffff9 : 0xfffffffd); 244*d39a76e7Sxw161283 if (mc5_write(adap, mask_array_base + i, write_cmd)) 245*d39a76e7Sxw161283 return -1; 246*d39a76e7Sxw161283 } 247*d39a76e7Sxw161283 return 0; 248*d39a76e7Sxw161283 } 249*d39a76e7Sxw161283 250*d39a76e7Sxw161283 static int init_lara7000(struct pemc5 *mc5) 251*d39a76e7Sxw161283 { 252*d39a76e7Sxw161283 int i; 253*d39a76e7Sxw161283 adapter_t *adap = mc5->adapter; 254*d39a76e7Sxw161283 255*d39a76e7Sxw161283 t1_write_reg_4(adap, A_MC5_RSP_LATENCY, 256*d39a76e7Sxw161283 t1_is_asic(adap) ? 0x0a0a0a0a : 0x09090909); 257*d39a76e7Sxw161283 258*d39a76e7Sxw161283 if (mc5->parity_enabled) { 259*d39a76e7Sxw161283 t1_write_reg_4(adap, A_MC5_AOPEN_SRCH_CMD, 0x20022); 260*d39a76e7Sxw161283 t1_write_reg_4(adap, A_MC5_SYN_SRCH_CMD, 0x20022); 261*d39a76e7Sxw161283 t1_write_reg_4(adap, A_MC5_ACK_SRCH_CMD, 0x20022); 262*d39a76e7Sxw161283 } 263*d39a76e7Sxw161283 264*d39a76e7Sxw161283 /* Set DBGI command mode for Lara TCAM. */ 265*d39a76e7Sxw161283 t1_write_reg_4(adap, A_MC5_DBGI_CONFIG, DBGI_MODE_LARA_7000); 266*d39a76e7Sxw161283 267*d39a76e7Sxw161283 dbgi_wr_data3(adap, mc5->mode == MC5_MODE_144_BIT ? 268*d39a76e7Sxw161283 MC5_LRA_CMDREG_144KEY_DATA0 : MC5_LRA_CMDREG_72KEY_DATA0, 269*d39a76e7Sxw161283 0, 0); 270*d39a76e7Sxw161283 if (mc5_write(adap, MC5_LRA_CMDREG_ADR0, MC5_LRA_CMD_WRITE)) 271*d39a76e7Sxw161283 goto err; 272*d39a76e7Sxw161283 273*d39a76e7Sxw161283 dbgi_wr_data3(adap, mc5->mode == MC5_MODE_144_BIT ? 274*d39a76e7Sxw161283 MC5_LRA_CFGREG_144KEY_DATA0 : MC5_LRA_CFGREG_72KEY_DATA0, 275*d39a76e7Sxw161283 0, 0); 276*d39a76e7Sxw161283 if (mc5_write(adap, MC5_LRA_CFGREG_ADR0, MC5_LRA_CMD_WRITE)) 277*d39a76e7Sxw161283 goto err; 278*d39a76e7Sxw161283 279*d39a76e7Sxw161283 /* Global Mask Registers (GMR) 0-15 */ 280*d39a76e7Sxw161283 for (i = 0; i < 16; i++) { 281*d39a76e7Sxw161283 if (i == 8 || i == 9) 282*d39a76e7Sxw161283 dbgi_wr_data3(adap, mc5->mode == MC5_MODE_72_BIT ? 283*d39a76e7Sxw161283 0xfffffffd : 0xfffffff9, 0xffffffff, 284*d39a76e7Sxw161283 0xff); 285*d39a76e7Sxw161283 else 286*d39a76e7Sxw161283 dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff); 287*d39a76e7Sxw161283 288*d39a76e7Sxw161283 if (mc5_write(adap, MC5_LRA_GMRREG_BASE_ADR0_1 + i, 289*d39a76e7Sxw161283 MC5_LRA_CMD_WRITE)) 290*d39a76e7Sxw161283 goto err; 291*d39a76e7Sxw161283 } 292*d39a76e7Sxw161283 293*d39a76e7Sxw161283 /* Global Mask Registers (GMR) 16-31 */ 294*d39a76e7Sxw161283 for (i = 0; i < 16; i++) { 295*d39a76e7Sxw161283 if (i <= 1 && mc5->mode == MC5_MODE_72_BIT) 296*d39a76e7Sxw161283 dbgi_wr_data3(adap, 0xfffffffd, 0xffffc003, 0xff); 297*d39a76e7Sxw161283 else if (i == 0) 298*d39a76e7Sxw161283 dbgi_wr_data3(adap, 0xfffffff9, 0xffffffff, 0xff); 299*d39a76e7Sxw161283 else if (i == 1) 300*d39a76e7Sxw161283 dbgi_wr_data3(adap, 0xfffffff9, 0xffff8007, 0xff); 301*d39a76e7Sxw161283 else 302*d39a76e7Sxw161283 dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff); 303*d39a76e7Sxw161283 304*d39a76e7Sxw161283 if (mc5_write(adap, MC5_LRA_GMRREG_BASE_ADR0_2 + i, 305*d39a76e7Sxw161283 MC5_LRA_CMD_WRITE)) 306*d39a76e7Sxw161283 goto err; 307*d39a76e7Sxw161283 } 308*d39a76e7Sxw161283 return init_mask_data_array(mc5, MC5_LRA_MSKARY_BASE_ADR0, 309*d39a76e7Sxw161283 MC5_LRA_DATARY_BASE_ADR0, 310*d39a76e7Sxw161283 MC5_LRA_CMD_WRITE); 311*d39a76e7Sxw161283 err: 312*d39a76e7Sxw161283 return -EIO; 313*d39a76e7Sxw161283 } 314*d39a76e7Sxw161283 315*d39a76e7Sxw161283 static int init_idt52100(struct pemc5 *mc5) 316*d39a76e7Sxw161283 { 317*d39a76e7Sxw161283 int i; 318*d39a76e7Sxw161283 adapter_t *adap = mc5->adapter; 319*d39a76e7Sxw161283 320*d39a76e7Sxw161283 t1_write_reg_4(adap, A_MC5_RSP_LATENCY, 0x151515); 321*d39a76e7Sxw161283 t1_write_reg_4(adap, A_MC5_PART_ID_INDEX, 2); 322*d39a76e7Sxw161283 323*d39a76e7Sxw161283 /* 324*d39a76e7Sxw161283 * Use GMRs 8-9 for ACK and AOPEN searches, GMRs 12-13 for SYN search, 325*d39a76e7Sxw161283 * and GMRs 14-15 for ELOOKUP. 326*d39a76e7Sxw161283 */ 327*d39a76e7Sxw161283 t1_write_reg_4(adap, A_MC5_POPEN_DATA_WR_CMD, MC5_IDT_CMD_WRITE); 328*d39a76e7Sxw161283 t1_write_reg_4(adap, A_MC5_POPEN_MASK_WR_CMD, MC5_IDT_CMD_WRITE); 329*d39a76e7Sxw161283 t1_write_reg_4(adap, A_MC5_AOPEN_SRCH_CMD, MC5_IDT_CMD_SEARCH); 330*d39a76e7Sxw161283 t1_write_reg_4(adap, A_MC5_AOPEN_LRN_CMD, MC5_IDT_CMD_LEARN); 331*d39a76e7Sxw161283 t1_write_reg_4(adap, A_MC5_SYN_SRCH_CMD, MC5_IDT_CMD_SEARCH | 0x6000); 332*d39a76e7Sxw161283 t1_write_reg_4(adap, A_MC5_SYN_LRN_CMD, MC5_IDT_CMD_LEARN); 333*d39a76e7Sxw161283 t1_write_reg_4(adap, A_MC5_ACK_SRCH_CMD, MC5_IDT_CMD_SEARCH); 334*d39a76e7Sxw161283 t1_write_reg_4(adap, A_MC5_ACK_LRN_CMD, MC5_IDT_CMD_LEARN); 335*d39a76e7Sxw161283 t1_write_reg_4(adap, A_MC5_ILOOKUP_CMD, MC5_IDT_CMD_SEARCH); 336*d39a76e7Sxw161283 t1_write_reg_4(adap, A_MC5_ELOOKUP_CMD, MC5_IDT_CMD_SEARCH | 0x7000); 337*d39a76e7Sxw161283 t1_write_reg_4(adap, A_MC5_DATA_WRITE_CMD, MC5_IDT_CMD_WRITE); 338*d39a76e7Sxw161283 t1_write_reg_4(adap, A_MC5_DATA_READ_CMD, MC5_IDT_CMD_READ); 339*d39a76e7Sxw161283 340*d39a76e7Sxw161283 /* Set DBGI command mode for IDT TCAM. */ 341*d39a76e7Sxw161283 t1_write_reg_4(adap, A_MC5_DBGI_CONFIG, DBGI_MODE_IDT_52100); 342*d39a76e7Sxw161283 343*d39a76e7Sxw161283 /* Set up LAR */ 344*d39a76e7Sxw161283 dbgi_wr_data3(adap, MC5_IDT_LAR_MODE144, 0, 0); 345*d39a76e7Sxw161283 if (mc5_write(adap, MC5_IDT_LAR_ADR0, MC5_IDT_CMD_WRITE)) 346*d39a76e7Sxw161283 goto err; 347*d39a76e7Sxw161283 348*d39a76e7Sxw161283 /* Set up SSRs */ 349*d39a76e7Sxw161283 dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0); 350*d39a76e7Sxw161283 if (mc5_write(adap, MC5_IDT_SSR0_ADR0, MC5_IDT_CMD_WRITE) || 351*d39a76e7Sxw161283 mc5_write(adap, MC5_IDT_SSR1_ADR0, MC5_IDT_CMD_WRITE)) 352*d39a76e7Sxw161283 goto err; 353*d39a76e7Sxw161283 354*d39a76e7Sxw161283 /* Set up GMRs */ 355*d39a76e7Sxw161283 for (i = 0; i < 32; ++i) { 356*d39a76e7Sxw161283 if (i >= 12 && i < 15) 357*d39a76e7Sxw161283 dbgi_wr_data3(adap, 0xfffffff9, 0xffffffff, 0xff); 358*d39a76e7Sxw161283 else if (i == 15) 359*d39a76e7Sxw161283 dbgi_wr_data3(adap, 0xfffffff9, 0xffff8007, 0xff); 360*d39a76e7Sxw161283 else 361*d39a76e7Sxw161283 dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff); 362*d39a76e7Sxw161283 363*d39a76e7Sxw161283 if (mc5_write(adap, MC5_IDT_GMR_BASE_ADR0 + i, 364*d39a76e7Sxw161283 MC5_IDT_CMD_WRITE)) 365*d39a76e7Sxw161283 goto err; 366*d39a76e7Sxw161283 } 367*d39a76e7Sxw161283 368*d39a76e7Sxw161283 /* Set up SCR */ 369*d39a76e7Sxw161283 dbgi_wr_data3(adap, 1, 0, 0); 370*d39a76e7Sxw161283 if (mc5_write(adap, MC5_IDT_SCR_ADR0, MC5_IDT_CMD_WRITE)) 371*d39a76e7Sxw161283 goto err; 372*d39a76e7Sxw161283 373*d39a76e7Sxw161283 return init_mask_data_array(mc5, MC5_IDT_MSKARY_BASE_ADR0, 374*d39a76e7Sxw161283 MC5_IDT_DATARY_BASE_ADR0, 375*d39a76e7Sxw161283 MC5_IDT_CMD_WRITE); 376*d39a76e7Sxw161283 err: 377*d39a76e7Sxw161283 return -EIO; 378*d39a76e7Sxw161283 } 379*d39a76e7Sxw161283 380*d39a76e7Sxw161283 /* Put MC5 in DBGI mode. */ 381*d39a76e7Sxw161283 static inline void mc5_dbgi_mode_enable(struct pemc5 *mc5) 382*d39a76e7Sxw161283 { 383*d39a76e7Sxw161283 t1_write_reg_4(mc5->adapter, A_MC5_CONFIG, 384*d39a76e7Sxw161283 V_MODE(mc5->mode == MC5_MODE_72_BIT) | 385*d39a76e7Sxw161283 F_DBGI_ENABLE | V_NUM_LIP(MC5_LIP_NUM_OF_ENTRIES - 1)); 386*d39a76e7Sxw161283 } 387*d39a76e7Sxw161283 388*d39a76e7Sxw161283 /* Put MC5 in M-Bus mode. */ 389*d39a76e7Sxw161283 static void mc5_dbgi_mode_disable(struct pemc5 *mc5) 390*d39a76e7Sxw161283 { 391*d39a76e7Sxw161283 t1_write_reg_4(mc5->adapter, A_MC5_CONFIG, 392*d39a76e7Sxw161283 V_MODE(mc5->mode == MC5_MODE_72_BIT) | 393*d39a76e7Sxw161283 V_COMPRESSION_ENABLE(mc5->mode == MC5_MODE_72_BIT) | 394*d39a76e7Sxw161283 V_PARITY_ENABLE(mc5->parity_enabled) | 395*d39a76e7Sxw161283 V_SYN_ISSUE_MODE(mc5->issue_syn) | F_M_BUS_ENABLE | 396*d39a76e7Sxw161283 V_NUM_LIP(MC5_LIP_NUM_OF_ENTRIES - 1)); 397*d39a76e7Sxw161283 } 398*d39a76e7Sxw161283 399*d39a76e7Sxw161283 /* 400*d39a76e7Sxw161283 * Initialization that requires the OS and protocol layers to already 401*d39a76e7Sxw161283 * be intialized goes here. 402*d39a76e7Sxw161283 */ 403*d39a76e7Sxw161283 int t1_mc5_init(struct pemc5 *mc5, unsigned int nservers, 404*d39a76e7Sxw161283 unsigned int nroutes, int parity, int syn) 405*d39a76e7Sxw161283 { 406*d39a76e7Sxw161283 u32 cfg; 407*d39a76e7Sxw161283 int err = 0; 408*d39a76e7Sxw161283 unsigned int tcam_size = t1_mc5_get_tcam_size(mc5); 409*d39a76e7Sxw161283 adapter_t *adap = mc5->adapter; 410*d39a76e7Sxw161283 411*d39a76e7Sxw161283 /* Reset the TCAM */ 412*d39a76e7Sxw161283 cfg = t1_read_reg_4(adap, A_MC5_CONFIG) & ~F_MODE; 413*d39a76e7Sxw161283 cfg |= V_MODE(mc5->mode == MC5_MODE_72_BIT) | F_TCAM_RESET; 414*d39a76e7Sxw161283 t1_write_reg_4(adap, A_MC5_CONFIG, cfg); 415*d39a76e7Sxw161283 if (t1_wait_op_done(adap, A_MC5_CONFIG, F_TCAM_READY, 1, 500, 0)) { 416*d39a76e7Sxw161283 CH_ERR("%s: TCAM reset timed out\n", adapter_name(adap)); 417*d39a76e7Sxw161283 return -1; 418*d39a76e7Sxw161283 } 419*d39a76e7Sxw161283 420*d39a76e7Sxw161283 if (set_tcam_rtbl_base(mc5, tcam_size - nroutes) || 421*d39a76e7Sxw161283 set_tcam_server_base(mc5, tcam_size - nroutes - nservers)) 422*d39a76e7Sxw161283 return -EINVAL; 423*d39a76e7Sxw161283 424*d39a76e7Sxw161283 #ifdef SUPPORT_MODE72 425*d39a76e7Sxw161283 if (mc5->mode == MC5_MODE_72_BIT) 426*d39a76e7Sxw161283 t1_mc5_lip_write_entries(mc5); 427*d39a76e7Sxw161283 #endif 428*d39a76e7Sxw161283 mc5->issue_syn = (unsigned char)syn; 429*d39a76e7Sxw161283 mc5->parity_enabled = (unsigned char)parity; 430*d39a76e7Sxw161283 431*d39a76e7Sxw161283 /* All the TCAM addresses we access have only the low 32 bits non 0 */ 432*d39a76e7Sxw161283 t1_write_reg_4(adap, A_MC5_DBGI_REQ_ADDR1, 0); 433*d39a76e7Sxw161283 t1_write_reg_4(adap, A_MC5_DBGI_REQ_ADDR2, 0); 434*d39a76e7Sxw161283 435*d39a76e7Sxw161283 mc5_dbgi_mode_enable(mc5); 436*d39a76e7Sxw161283 437*d39a76e7Sxw161283 switch (mc5->part_type) { 438*d39a76e7Sxw161283 case LARA_7000: 439*d39a76e7Sxw161283 err = init_lara7000(mc5); 440*d39a76e7Sxw161283 break; 441*d39a76e7Sxw161283 case IDT75P52100: 442*d39a76e7Sxw161283 err = init_idt52100(mc5); 443*d39a76e7Sxw161283 break; 444*d39a76e7Sxw161283 default: 445*d39a76e7Sxw161283 CH_ERR("%s: unsupported TCAM type\n", adapter_name(adap)); 446*d39a76e7Sxw161283 err = -EINVAL; 447*d39a76e7Sxw161283 break; 448*d39a76e7Sxw161283 } 449*d39a76e7Sxw161283 450*d39a76e7Sxw161283 mc5_dbgi_mode_disable(mc5); 451*d39a76e7Sxw161283 return err; 452*d39a76e7Sxw161283 } 453*d39a76e7Sxw161283 454*d39a76e7Sxw161283 /* 455*d39a76e7Sxw161283 * read_mc5_range - dump a part of the memory managed by MC5 456*d39a76e7Sxw161283 * @mc5: the MC5 handle 457*d39a76e7Sxw161283 * @start: the start address for the dump 458*d39a76e7Sxw161283 * @n: number of 72-bit words to read 459*d39a76e7Sxw161283 * @buf: result buffer 460*d39a76e7Sxw161283 * 461*d39a76e7Sxw161283 * Read n 72-bit words from MC5 memory from the given start location. 462*d39a76e7Sxw161283 */ 463*d39a76e7Sxw161283 int t1_read_mc5_range(struct pemc5 *mc5, unsigned int start, 464*d39a76e7Sxw161283 unsigned int n, u32 *buf) 465*d39a76e7Sxw161283 { 466*d39a76e7Sxw161283 u32 read_cmd; 467*d39a76e7Sxw161283 /* int err = 0; */ 468*d39a76e7Sxw161283 adapter_t *adap = mc5->adapter; 469*d39a76e7Sxw161283 470*d39a76e7Sxw161283 if (mc5->part_type == LARA_7000) 471*d39a76e7Sxw161283 read_cmd = MC5_LRA_CMD_READ; 472*d39a76e7Sxw161283 else if (mc5->part_type == IDT75P52100) 473*d39a76e7Sxw161283 read_cmd = MC5_IDT_CMD_READ; 474*d39a76e7Sxw161283 else 475*d39a76e7Sxw161283 return -EINVAL; 476*d39a76e7Sxw161283 477*d39a76e7Sxw161283 mc5_dbgi_mode_enable(mc5); 478*d39a76e7Sxw161283 479*d39a76e7Sxw161283 while (n--) { 480*d39a76e7Sxw161283 t1_write_reg_4(adap, A_MC5_DBGI_REQ_ADDR0, start++); 481*d39a76e7Sxw161283 if (mc5_cmd_write(adap, read_cmd)) { 482*d39a76e7Sxw161283 /* err = -EIO; */ 483*d39a76e7Sxw161283 break; 484*d39a76e7Sxw161283 } 485*d39a76e7Sxw161283 dbgi_rd_rsp3(adap, buf + 2, buf + 1, buf); 486*d39a76e7Sxw161283 buf += 3; 487*d39a76e7Sxw161283 } 488*d39a76e7Sxw161283 489*d39a76e7Sxw161283 mc5_dbgi_mode_disable(mc5); 490*d39a76e7Sxw161283 return 0; 491*d39a76e7Sxw161283 } 492*d39a76e7Sxw161283 493*d39a76e7Sxw161283 #define MC5_INT_MASK (F_MC5_INT_HIT_OUT_ACTIVE_REGION_ERR | \ 494*d39a76e7Sxw161283 F_MC5_INT_HIT_IN_RT_REGION_ERR | F_MC5_INT_LIP0_ERR | \ 495*d39a76e7Sxw161283 F_MC5_INT_LIP_MISS_ERR | F_MC5_INT_PARITY_ERR | \ 496*d39a76e7Sxw161283 F_MC5_INT_ACTIVE_REGION_FULL | F_MC5_INT_NFA_SRCH_ERR | \ 497*d39a76e7Sxw161283 F_MC5_INT_UNKNOWN_CMD | F_MC5_INT_DEL_ACT_EMPTY) 498*d39a76e7Sxw161283 #define MC5_INT_FATAL (F_MC5_INT_PARITY_ERR | F_MC5_INT_REQUESTQ_PARITY_ERR | \ 499*d39a76e7Sxw161283 F_MC5_INT_DISPATCHQ_PARITY_ERR) 500*d39a76e7Sxw161283 501*d39a76e7Sxw161283 void t1_mc5_intr_enable(struct pemc5 *mc5) 502*d39a76e7Sxw161283 { 503*d39a76e7Sxw161283 u32 mask = MC5_INT_MASK; 504*d39a76e7Sxw161283 505*d39a76e7Sxw161283 if (!mc5->parity_enabled) 506*d39a76e7Sxw161283 mask &= ~F_MC5_INT_PARITY_ERR; 507*d39a76e7Sxw161283 508*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_1G 509*d39a76e7Sxw161283 if (!t1_is_asic(mc5->adapter)) { 510*d39a76e7Sxw161283 /* 511*d39a76e7Sxw161283 * Enable child block for MC5. 512*d39a76e7Sxw161283 * 513*d39a76e7Sxw161283 * NOTE: Assumes TP parent interrupt block is enabled. 514*d39a76e7Sxw161283 * MC5 requires TP parent block to be enabled. 515*d39a76e7Sxw161283 */ 516*d39a76e7Sxw161283 t1_write_reg_4(mc5->adapter, A_MC5_INT_ENABLE, mask); 517*d39a76e7Sxw161283 } else 518*d39a76e7Sxw161283 #endif 519*d39a76e7Sxw161283 { 520*d39a76e7Sxw161283 u32 pl_intr = t1_read_reg_4(mc5->adapter, A_PL_ENABLE); 521*d39a76e7Sxw161283 522*d39a76e7Sxw161283 t1_write_reg_4(mc5->adapter, A_PL_ENABLE, 523*d39a76e7Sxw161283 pl_intr | F_PL_INTR_MC5); 524*d39a76e7Sxw161283 t1_write_reg_4(mc5->adapter, A_MC5_INT_ENABLE, 525*d39a76e7Sxw161283 mask | F_MC5_INT_REQUESTQ_PARITY_ERR | 526*d39a76e7Sxw161283 F_MC5_INT_DISPATCHQ_PARITY_ERR); 527*d39a76e7Sxw161283 } 528*d39a76e7Sxw161283 } 529*d39a76e7Sxw161283 530*d39a76e7Sxw161283 void t1_mc5_intr_disable(struct pemc5 *mc5) 531*d39a76e7Sxw161283 { 532*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_1G 533*d39a76e7Sxw161283 if (!t1_is_asic(mc5->adapter)) 534*d39a76e7Sxw161283 t1_write_reg_4(mc5->adapter, A_MC5_INT_ENABLE, 0); 535*d39a76e7Sxw161283 else 536*d39a76e7Sxw161283 #endif 537*d39a76e7Sxw161283 { 538*d39a76e7Sxw161283 u32 pl_intr = t1_read_reg_4(mc5->adapter, A_PL_ENABLE); 539*d39a76e7Sxw161283 540*d39a76e7Sxw161283 t1_write_reg_4(mc5->adapter, A_PL_ENABLE, 541*d39a76e7Sxw161283 pl_intr & ~F_PL_INTR_MC5); 542*d39a76e7Sxw161283 t1_write_reg_4(mc5->adapter, A_MC5_INT_ENABLE, 0); 543*d39a76e7Sxw161283 } 544*d39a76e7Sxw161283 } 545*d39a76e7Sxw161283 546*d39a76e7Sxw161283 void t1_mc5_intr_clear(struct pemc5 *mc5) 547*d39a76e7Sxw161283 { 548*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_1G 549*d39a76e7Sxw161283 if (!t1_is_asic(mc5->adapter)) { 550*d39a76e7Sxw161283 t1_write_reg_4(mc5->adapter, A_MC5_INT_CAUSE, 0xffffffff); 551*d39a76e7Sxw161283 } else 552*d39a76e7Sxw161283 #endif 553*d39a76e7Sxw161283 { 554*d39a76e7Sxw161283 t1_write_reg_4(mc5->adapter, A_PL_CAUSE, F_PL_INTR_MC5); 555*d39a76e7Sxw161283 t1_write_reg_4(mc5->adapter, A_MC5_INT_CAUSE, 0xffffffff); 556*d39a76e7Sxw161283 } 557*d39a76e7Sxw161283 } 558*d39a76e7Sxw161283 559*d39a76e7Sxw161283 /* 560*d39a76e7Sxw161283 * We don't really do anything with MC5 interrupts, just record them. 561*d39a76e7Sxw161283 */ 562*d39a76e7Sxw161283 void t1_mc5_intr_handler(struct pemc5 *mc5) 563*d39a76e7Sxw161283 { 564*d39a76e7Sxw161283 adapter_t *adap = mc5->adapter; 565*d39a76e7Sxw161283 u32 cause = t1_read_reg_4(adap, A_MC5_INT_CAUSE); 566*d39a76e7Sxw161283 567*d39a76e7Sxw161283 if (cause & F_MC5_INT_HIT_OUT_ACTIVE_REGION_ERR) 568*d39a76e7Sxw161283 mc5->intr_counts.hit_out_active_region_err++; 569*d39a76e7Sxw161283 570*d39a76e7Sxw161283 if (cause & F_MC5_INT_HIT_IN_ACTIVE_REGION_ERR) 571*d39a76e7Sxw161283 mc5->intr_counts.hit_in_active_region_err++; 572*d39a76e7Sxw161283 573*d39a76e7Sxw161283 if (cause & F_MC5_INT_HIT_IN_RT_REGION_ERR) 574*d39a76e7Sxw161283 mc5->intr_counts.hit_in_routing_region_err++; 575*d39a76e7Sxw161283 576*d39a76e7Sxw161283 if (cause & F_MC5_INT_MISS_ERR) 577*d39a76e7Sxw161283 mc5->intr_counts.miss_err++; 578*d39a76e7Sxw161283 579*d39a76e7Sxw161283 if (cause & F_MC5_INT_LIP0_ERR) 580*d39a76e7Sxw161283 mc5->intr_counts.lip_equal_zero_err++; 581*d39a76e7Sxw161283 582*d39a76e7Sxw161283 if (cause & F_MC5_INT_LIP_MISS_ERR) 583*d39a76e7Sxw161283 mc5->intr_counts.lip_miss_err++; 584*d39a76e7Sxw161283 585*d39a76e7Sxw161283 if ((cause & F_MC5_INT_PARITY_ERR) && mc5->parity_enabled) { 586*d39a76e7Sxw161283 CH_ALERT("%s: MC5 parity error\n", adapter_name(adap)); 587*d39a76e7Sxw161283 mc5->intr_counts.parity_err++; 588*d39a76e7Sxw161283 } 589*d39a76e7Sxw161283 590*d39a76e7Sxw161283 if (cause & F_MC5_INT_ACTIVE_REGION_FULL) 591*d39a76e7Sxw161283 mc5->intr_counts.active_region_full_err++; 592*d39a76e7Sxw161283 593*d39a76e7Sxw161283 if (cause & F_MC5_INT_NFA_SRCH_ERR) 594*d39a76e7Sxw161283 mc5->intr_counts.next_free_addr_srch_err++; 595*d39a76e7Sxw161283 596*d39a76e7Sxw161283 if (cause & F_MC5_INT_SYN_COOKIE) 597*d39a76e7Sxw161283 mc5->intr_counts.syn_cookie++; 598*d39a76e7Sxw161283 599*d39a76e7Sxw161283 if (cause & F_MC5_INT_SYN_COOKIE_BAD) 600*d39a76e7Sxw161283 mc5->intr_counts.syn_cookie_bad_message++; 601*d39a76e7Sxw161283 602*d39a76e7Sxw161283 if (cause & F_MC5_INT_SYN_COOKIE_OFF) 603*d39a76e7Sxw161283 mc5->intr_counts.syn_cookie_off_message++; 604*d39a76e7Sxw161283 605*d39a76e7Sxw161283 if (cause & F_MC5_INT_UNKNOWN_CMD) 606*d39a76e7Sxw161283 mc5->intr_counts.receive_unknown_cmd++; 607*d39a76e7Sxw161283 608*d39a76e7Sxw161283 if (cause & F_MC5_INT_REQUESTQ_PARITY_ERR) { 609*d39a76e7Sxw161283 CH_ALERT("%s: MC5 request queue parity error\n", 610*d39a76e7Sxw161283 adapter_name(adap)); 611*d39a76e7Sxw161283 mc5->intr_counts.parity_in_request_q_err++; 612*d39a76e7Sxw161283 } 613*d39a76e7Sxw161283 614*d39a76e7Sxw161283 if (cause & F_MC5_INT_DISPATCHQ_PARITY_ERR) { 615*d39a76e7Sxw161283 CH_ALERT("%s: MC5 dispatch queue parity error\n", 616*d39a76e7Sxw161283 adapter_name(adap)); 617*d39a76e7Sxw161283 mc5->intr_counts.parity_in_dispatch_q_err++; 618*d39a76e7Sxw161283 } 619*d39a76e7Sxw161283 620*d39a76e7Sxw161283 if (cause & F_MC5_INT_DEL_ACT_EMPTY) 621*d39a76e7Sxw161283 mc5->intr_counts.del_and_act_is_empty++; 622*d39a76e7Sxw161283 623*d39a76e7Sxw161283 if (cause & MC5_INT_FATAL) 624*d39a76e7Sxw161283 t1_fatal_err(adap); 625*d39a76e7Sxw161283 626*d39a76e7Sxw161283 t1_write_reg_4(adap, A_MC5_INT_CAUSE, cause); 627*d39a76e7Sxw161283 } 628*d39a76e7Sxw161283 629*d39a76e7Sxw161283 const struct pemc5_intr_counts *t1_mc5_get_intr_counts(struct pemc5 *mc5) 630*d39a76e7Sxw161283 { 631*d39a76e7Sxw161283 return &mc5->intr_counts; 632*d39a76e7Sxw161283 } 633*d39a76e7Sxw161283 634*d39a76e7Sxw161283 struct pemc5 * __devinit t1_mc5_create(adapter_t *adapter, int mode) 635*d39a76e7Sxw161283 { 636*d39a76e7Sxw161283 struct pemc5 *mc5; 637*d39a76e7Sxw161283 u32 cfg, bits_per_entry; 638*d39a76e7Sxw161283 639*d39a76e7Sxw161283 if (mode != MC5_MODE_144_BIT && mode != MC5_MODE_72_BIT) 640*d39a76e7Sxw161283 return NULL; 641*d39a76e7Sxw161283 642*d39a76e7Sxw161283 mc5 = t1_os_malloc_wait_zero(sizeof(*mc5)); 643*d39a76e7Sxw161283 if (!mc5) return NULL; 644*d39a76e7Sxw161283 645*d39a76e7Sxw161283 mc5->adapter = adapter; 646*d39a76e7Sxw161283 mc5->mode = (unsigned char) mode; 647*d39a76e7Sxw161283 648*d39a76e7Sxw161283 cfg = t1_read_reg_4(adapter, A_MC5_CONFIG); 649*d39a76e7Sxw161283 mc5->part_size = G_TCAM_PART_SIZE(cfg); 650*d39a76e7Sxw161283 mc5->part_type = (unsigned char) G_TCAM_PART_TYPE(cfg); 651*d39a76e7Sxw161283 if (cfg & F_TCAM_PART_TYPE_HI) 652*d39a76e7Sxw161283 mc5->part_type |= 4; 653*d39a76e7Sxw161283 654*d39a76e7Sxw161283 /* 655*d39a76e7Sxw161283 * Calculate the size of the TCAM based on the total memory, mode, and 656*d39a76e7Sxw161283 * count information retrieved from the hardware. 657*d39a76e7Sxw161283 */ 658*d39a76e7Sxw161283 bits_per_entry = mode == MC5_MODE_144_BIT ? 144 : 72; 659*d39a76e7Sxw161283 mc5->tcam_size = tcam_part_size[mc5->part_size] / bits_per_entry; 660*d39a76e7Sxw161283 661*d39a76e7Sxw161283 return mc5; 662*d39a76e7Sxw161283 } 663*d39a76e7Sxw161283 664*d39a76e7Sxw161283 void t1_mc5_destroy(struct pemc5 *mc5) 665*d39a76e7Sxw161283 { 666*d39a76e7Sxw161283 t1_os_free((void *)mc5, sizeof(*mc5)); 667*d39a76e7Sxw161283 } 668*d39a76e7Sxw161283 669*d39a76e7Sxw161283 #ifdef SUPPORT_MODE72 670*d39a76e7Sxw161283 static int mc5_cmp(const void *pi, const void *pj) 671*d39a76e7Sxw161283 { 672*d39a76e7Sxw161283 const u32 *pii = (const u32 *)pi; 673*d39a76e7Sxw161283 const u32 *pjj = (const u32 *)pj; 674*d39a76e7Sxw161283 675*d39a76e7Sxw161283 if (*pii < *pjj) 676*d39a76e7Sxw161283 return -1; 677*d39a76e7Sxw161283 678*d39a76e7Sxw161283 return *pii > *pjj; 679*d39a76e7Sxw161283 } 680*d39a76e7Sxw161283 681*d39a76e7Sxw161283 /* 682*d39a76e7Sxw161283 * DESC: Write local IP addresses to the TCAM 683*d39a76e7Sxw161283 * 684*d39a76e7Sxw161283 * NOTES: IP addresses should be in host byte order. So, an IP address: 685*d39a76e7Sxw161283 * of 10.0.0.140 == (data = 0x0A00008C) 686*d39a76e7Sxw161283 */ 687*d39a76e7Sxw161283 static int mc5_set_lip_entries(struct pemc5 *mc5, u32 *p, 688*d39a76e7Sxw161283 int num_of_lip_addresses) 689*d39a76e7Sxw161283 { 690*d39a76e7Sxw161283 int i; 691*d39a76e7Sxw161283 692*d39a76e7Sxw161283 /* 693*d39a76e7Sxw161283 * Disable compression and M bus mode so that the TP core 694*d39a76e7Sxw161283 * doesn't access the TCAM while we are writing. 695*d39a76e7Sxw161283 */ 696*d39a76e7Sxw161283 u32 cfg = t1_read_reg_4(mc5->adapter, A_MC5_CONFIG); 697*d39a76e7Sxw161283 t1_write_reg_4(mc5->adapter, A_MC5_CONFIG, 698*d39a76e7Sxw161283 cfg & ~(F_M_BUS_ENABLE | F_COMPRESSION_ENABLE)); 699*d39a76e7Sxw161283 700*d39a76e7Sxw161283 /* MC5 should now be ready to program the LIP addresses. */ 701*d39a76e7Sxw161283 for (i = 0; i < num_of_lip_addresses; i++) { 702*d39a76e7Sxw161283 t1_write_reg_4(mc5->adapter, A_MC5_LIP_RAM_DATA, p[i]); 703*d39a76e7Sxw161283 t1_write_reg_4(mc5->adapter, A_MC5_LIP_RAM_ADDR, 0x100 + i); 704*d39a76e7Sxw161283 } 705*d39a76e7Sxw161283 706*d39a76e7Sxw161283 /* Restore MC5 mode. */ 707*d39a76e7Sxw161283 t1_write_reg_4(mc5->adapter, A_MC5_CONFIG, cfg | F_COMPRESSION_ENABLE); 708*d39a76e7Sxw161283 return 0; 709*d39a76e7Sxw161283 } 710*d39a76e7Sxw161283 711*d39a76e7Sxw161283 /* 712*d39a76e7Sxw161283 * The purpose of this routine is to write all of the local IP addresses 713*d39a76e7Sxw161283 * into the TCAM in sorted order. This is a requirement from the TCAM. 714*d39a76e7Sxw161283 */ 715*d39a76e7Sxw161283 void t1_mc5_lip_write_entries(struct pemc5 *mc5) 716*d39a76e7Sxw161283 { 717*d39a76e7Sxw161283 u32 filler = 0; 718*d39a76e7Sxw161283 int i; 719*d39a76e7Sxw161283 720*d39a76e7Sxw161283 if (mc5->lip_index) { 721*d39a76e7Sxw161283 qsort(mc5->lip, mc5->lip_index, sizeof(u32), mc5_cmp); 722*d39a76e7Sxw161283 filler = mc5->lip[mc5->lip_index - 1]; 723*d39a76e7Sxw161283 } 724*d39a76e7Sxw161283 for (i = mc5->lip_index; i < MC5_LIP_NUM_OF_ENTRIES; i++) 725*d39a76e7Sxw161283 mc5->lip[i] = filler; 726*d39a76e7Sxw161283 mc5_set_lip_entries(mc5, mc5->lip, MC5_LIP_NUM_OF_ENTRIES); 727*d39a76e7Sxw161283 } 728*d39a76e7Sxw161283 729*d39a76e7Sxw161283 void t1_mc5_lip_clear_entries(struct pemc5 *mc5) 730*d39a76e7Sxw161283 { 731*d39a76e7Sxw161283 mc5->lip_index = 0; 732*d39a76e7Sxw161283 } 733*d39a76e7Sxw161283 734*d39a76e7Sxw161283 /* 735*d39a76e7Sxw161283 * Add a local IP address to the LIP table. 736*d39a76e7Sxw161283 */ 737*d39a76e7Sxw161283 int t1_mc5_lip_add_entry(struct pemc5 *mc5, u32 lip) 738*d39a76e7Sxw161283 { 739*d39a76e7Sxw161283 if (mc5->lip_index >= MC5_LIP_NUM_OF_ENTRIES) return 1; 740*d39a76e7Sxw161283 mc5->lip[mc5->lip_index++] = lip; 741*d39a76e7Sxw161283 return 0; 742*d39a76e7Sxw161283 } 743*d39a76e7Sxw161283 #endif 744