1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (C) 2003-2005 Chelsio Communications. All rights reserved. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" /* espi.c */ 27 28 #include "common.h" 29 #include "regs.h" 30 #include "espi.h" 31 32 struct peespi { 33 adapter_t *adapter; 34 struct espi_intr_counts intr_cnt; 35 u32 misc_ctrl; 36 SPINLOCK lock; 37 }; 38 39 #define ESPI_INTR_MASK (F_DIP4ERR | F_RXDROP | F_TXDROP | F_RXOVERFLOW | \ 40 F_RAMPARITYERR | F_DIP2PARITYERR) 41 #define MON_MASK (V_MONITORED_PORT_NUM(3) | F_MONITORED_DIRECTION \ 42 | F_MONITORED_INTERFACE) 43 44 #define TRICN_CNFG 14 45 #define TRICN_CMD_READ 0x11 46 #define TRICN_CMD_WRITE 0x21 47 #define TRICN_CMD_ATTEMPTS 10 48 49 static int tricn_write(adapter_t *adapter, int bundle_addr, int module_addr, 50 int ch_addr, int reg_offset, u32 wr_data) 51 { 52 int busy; 53 54 t1_write_reg_4(adapter, A_ESPI_CMD_ADDR, V_WRITE_DATA(wr_data) | 55 V_REGISTER_OFFSET(reg_offset) | 56 V_CHANNEL_ADDR(ch_addr) | V_MODULE_ADDR(module_addr) | 57 V_BUNDLE_ADDR(bundle_addr) | 58 V_SPI4_COMMAND(TRICN_CMD_WRITE)); 59 t1_write_reg_4(adapter, A_ESPI_GOSTAT, 0); 60 61 busy = t1_wait_op_done(adapter, A_ESPI_GOSTAT, F_ESPI_CMD_BUSY, 0, 62 TRICN_CMD_ATTEMPTS, 0); 63 64 if (busy) 65 CH_ERR("%s: TRICN write timed out\n", adapter_name(adapter)); 66 67 return busy; 68 } 69 70 #if 0 71 static int tricn_read(adapter_t *adapter, int bundle_addr, int module_addr, 72 int ch_addr, int reg_offset, u8 *rd_data) 73 { 74 int busy, attempts = TRICN_CMD_ATTEMPTS; 75 u32 status; 76 77 t1_write_reg_4(adapter, A_ESPI_CMD_ADDR, 78 V_REGISTER_OFFSET(reg_offset) | 79 V_CHANNEL_ADDR(ch_addr) | V_MODULE_ADDR(module_addr) | 80 V_BUNDLE_ADDR(bundle_addr) | 81 V_SPI4_COMMAND(TRICN_CMD_READ)); 82 t1_write_reg_4(adapter, A_ESPI_GOSTAT, 0); 83 84 do { 85 status = t1_read_reg_4(adapter, A_ESPI_GOSTAT); 86 busy = status & F_ESPI_CMD_BUSY; 87 } while (busy && --attempts); 88 89 if (busy) 90 CH_ERR("%s: TRICN read timed out\n", adapter_name(adapter)); 91 else 92 *rd_data = G_READ_DATA(status); 93 return busy; 94 } 95 #endif 96 97 static int tricn_init(adapter_t *adapter) 98 { 99 int i, sme = 1; 100 101 if (!(t1_read_reg_4(adapter, A_ESPI_RX_RESET) & F_RX_CLK_STATUS)) { 102 CH_ERR("%s: ESPI clock not ready\n", adapter_name(adapter)); 103 return (-1); 104 } 105 106 t1_write_reg_4(adapter, A_ESPI_RX_RESET, F_ESPI_RX_CORE_RST); 107 108 if (sme) { 109 (void) tricn_write(adapter, 0, 0, 0, TRICN_CNFG, 0x81); 110 (void) tricn_write(adapter, 0, 1, 0, TRICN_CNFG, 0x81); 111 (void) tricn_write(adapter, 0, 2, 0, TRICN_CNFG, 0x81); 112 } 113 for (i=1; i<= 8; i++) (void) tricn_write(adapter, 0, 0, i, TRICN_CNFG, 0xf1); 114 for (i=1; i<= 2; i++) (void) tricn_write(adapter, 0, 1, i, TRICN_CNFG, 0xf1); 115 for (i=1; i<= 3; i++) (void) tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0xe1); 116 (void) tricn_write(adapter, 0, 2, 4, TRICN_CNFG, 0xf1); 117 (void) tricn_write(adapter, 0, 2, 5, TRICN_CNFG, 0xe1); 118 (void) tricn_write(adapter, 0, 2, 6, TRICN_CNFG, 0xf1); 119 (void) tricn_write(adapter, 0, 2, 7, TRICN_CNFG, 0x80); 120 (void) tricn_write(adapter, 0, 2, 8, TRICN_CNFG, 0xf1); 121 122 t1_write_reg_4(adapter, A_ESPI_RX_RESET, F_ESPI_RX_CORE_RST | F_ESPI_RX_LNK_RST); 123 124 return 0; 125 } 126 127 void t1_espi_intr_enable(struct peespi *espi) 128 { 129 u32 enable, pl_intr = t1_read_reg_4(espi->adapter, A_PL_ENABLE); 130 131 /* 132 * Cannot enable ESPI interrupts on T1B because HW asserts the 133 * interrupt incorrectly, namely the driver gets ESPI interrupts 134 * but no data is actually dropped (can verify this reading the ESPI 135 * drop registers). Also, once the ESPI interrupt is asserted it 136 * cannot be cleared (HW bug). 137 */ 138 enable = t1_is_T1B(espi->adapter) ? 0 : ESPI_INTR_MASK; 139 t1_write_reg_4(espi->adapter, A_ESPI_INTR_ENABLE, enable); 140 t1_write_reg_4(espi->adapter, A_PL_ENABLE, pl_intr | F_PL_INTR_ESPI); 141 } 142 143 void t1_espi_intr_clear(struct peespi *espi) 144 { 145 (void) t1_read_reg_4(espi->adapter, A_ESPI_DIP2_ERR_COUNT); 146 t1_write_reg_4(espi->adapter, A_ESPI_INTR_STATUS, 0xffffffff); 147 t1_write_reg_4(espi->adapter, A_PL_CAUSE, F_PL_INTR_ESPI); 148 } 149 150 void t1_espi_intr_disable(struct peespi *espi) 151 { 152 u32 pl_intr = t1_read_reg_4(espi->adapter, A_PL_ENABLE); 153 154 t1_write_reg_4(espi->adapter, A_ESPI_INTR_ENABLE, 0); 155 t1_write_reg_4(espi->adapter, A_PL_ENABLE, pl_intr & ~F_PL_INTR_ESPI); 156 } 157 158 int t1_espi_intr_handler(struct peespi *espi) 159 { 160 u32 status = t1_read_reg_4(espi->adapter, A_ESPI_INTR_STATUS); 161 162 if (status & F_DIP4ERR) 163 espi->intr_cnt.DIP4_err++; 164 if (status & F_RXDROP) 165 espi->intr_cnt.rx_drops++; 166 if (status & F_TXDROP) 167 espi->intr_cnt.tx_drops++; 168 if (status & F_RXOVERFLOW) 169 espi->intr_cnt.rx_ovflw++; 170 if (status & F_RAMPARITYERR) 171 espi->intr_cnt.parity_err++; 172 if (status & F_DIP2PARITYERR) { 173 espi->intr_cnt.DIP2_parity_err++; 174 (void) t1_read_reg_4(espi->adapter, A_ESPI_DIP2_ERR_COUNT); 175 } 176 177 /* 178 * For T1B we need to write 1 to clear ESPI interrupts. For T2+ we 179 * write the status as is. 180 */ 181 if (status && t1_is_T1B(espi->adapter)) 182 status = 1; 183 t1_write_reg_4(espi->adapter, A_ESPI_INTR_STATUS, status); 184 return 0; 185 } 186 187 const struct espi_intr_counts *t1_espi_get_intr_counts(struct peespi *espi) 188 { 189 return &espi->intr_cnt; 190 } 191 192 static void espi_setup_for_pm3393(adapter_t *adapter) 193 { 194 u32 wmark = t1_is_T1B(adapter) ? 0x4000 : 0x3200; 195 196 t1_write_reg_4(adapter, A_ESPI_SCH_TOKEN0, 0x1f4); 197 t1_write_reg_4(adapter, A_ESPI_SCH_TOKEN1, 0x1f4); 198 t1_write_reg_4(adapter, A_ESPI_SCH_TOKEN2, 0x1f4); 199 t1_write_reg_4(adapter, A_ESPI_SCH_TOKEN3, 0x1f4); 200 t1_write_reg_4(adapter, A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK, 0x100); 201 t1_write_reg_4(adapter, A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK, wmark); 202 t1_write_reg_4(adapter, A_ESPI_CALENDAR_LENGTH, 3); 203 t1_write_reg_4(adapter, A_ESPI_TRAIN, 0x08000008); 204 t1_write_reg_4(adapter, A_PORT_CONFIG, 205 V_RX_NPORTS(1) | V_TX_NPORTS(1)); 206 } 207 208 static void espi_setup_for_vsc7321(adapter_t *adapter) 209 { 210 #ifdef CONFIG_CHELSIO_T1_COUGAR 211 u32 wmark = t1_is_T1B(adapter) ? 0x4000 : 0x3200; 212 213 t1_write_reg_4(adapter, A_ESPI_SCH_TOKEN0, 0x1f4); 214 t1_write_reg_4(adapter, A_ESPI_SCH_TOKEN1, 0x1f4); 215 t1_write_reg_4(adapter, A_ESPI_SCH_TOKEN2, 0x1f4); 216 t1_write_reg_4(adapter, A_ESPI_SCH_TOKEN3, 0x1f4); 217 t1_write_reg_4(adapter, A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK, 0x100); 218 t1_write_reg_4(adapter, A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK, wmark); 219 t1_write_reg_4(adapter, A_ESPI_CALENDAR_LENGTH, 3); 220 t1_write_reg_4(adapter, A_PORT_CONFIG, 221 V_RX_NPORTS(1) | V_TX_NPORTS(1)); 222 #else 223 t1_write_reg_4(adapter, A_ESPI_SCH_TOKEN0, 0x1f4); 224 t1_write_reg_4(adapter, A_ESPI_SCH_TOKEN1, 0x1f401f4); 225 t1_write_reg_4(adapter, A_ESPI_SCH_TOKEN2, 0x1f4); 226 t1_write_reg_4(adapter, A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK, 0xa00); 227 t1_write_reg_4(adapter, A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK, 0x1ff); 228 t1_write_reg_4(adapter, A_ESPI_CALENDAR_LENGTH, 1); 229 t1_write_reg_4(adapter, A_PORT_CONFIG, 230 V_RX_NPORTS(4) | V_TX_NPORTS(4)); 231 #endif 232 t1_write_reg_4(adapter, A_ESPI_TRAIN, 0x08000008); 233 } 234 235 /* 236 * Note that T1B requires at least 2 ports for IXF1010 due to a HW bug. 237 */ 238 static void espi_setup_for_ixf1010(adapter_t *adapter, int nports) 239 { 240 t1_write_reg_4(adapter, A_ESPI_CALENDAR_LENGTH, 1); 241 if (nports == 4) { 242 if (is_T2(adapter)) { 243 t1_write_reg_4(adapter, A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK, 244 0xf00); 245 t1_write_reg_4(adapter, A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK, 246 0x3c0); 247 } else { 248 t1_write_reg_4(adapter, A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK, 249 0x7ff); 250 t1_write_reg_4(adapter, A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK, 251 0x1ff); 252 } 253 } else { 254 t1_write_reg_4(adapter, A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK, 255 0x1fff); 256 t1_write_reg_4(adapter, A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK, 257 0x7ff); 258 } 259 t1_write_reg_4(adapter, A_PORT_CONFIG, 260 V_RX_NPORTS(nports) | V_TX_NPORTS(nports)); 261 } 262 263 int t1_espi_init(struct peespi *espi, int mac_type, int nports) 264 { 265 u32 status_enable_extra = 0; 266 adapter_t *adapter = espi->adapter; 267 268 /* Disable ESPI training. MACs that can handle it enable it below. */ 269 t1_write_reg_4(adapter, A_ESPI_TRAIN, 0); 270 271 if (is_T2(adapter)) { 272 t1_write_reg_4(adapter, A_ESPI_MISC_CONTROL, 273 V_OUT_OF_SYNC_COUNT(4) | 274 V_DIP2_PARITY_ERR_THRES(3) | V_DIP4_THRES(1)); 275 t1_write_reg_4(adapter, A_ESPI_MAXBURST1_MAXBURST2, 276 nports == 4 ? 0x200040 : 0x1000080); 277 } else 278 t1_write_reg_4(adapter, A_ESPI_MAXBURST1_MAXBURST2, 0x800100); 279 280 if (mac_type == CHBT_MAC_PM3393) 281 espi_setup_for_pm3393(adapter); 282 else if (mac_type == CHBT_MAC_VSC7321) 283 espi_setup_for_vsc7321(adapter); 284 else if (mac_type == CHBT_MAC_IXF1010) { 285 status_enable_extra = F_INTEL1010MODE; 286 espi_setup_for_ixf1010(adapter, nports); 287 } else 288 return -1; 289 290 t1_write_reg_4(adapter, A_ESPI_FIFO_STATUS_ENABLE, 291 status_enable_extra | F_RXSTATUSENABLE); 292 293 if (is_T2(adapter)) { 294 (void) tricn_init(adapter); 295 /* 296 * Always position the control at the 1st port egress IN 297 * (sop,eop) counter to reduce PIOs for T/N210 workaround. 298 */ 299 espi->misc_ctrl = t1_read_reg_4(adapter, A_ESPI_MISC_CONTROL); 300 espi->misc_ctrl &= ~MON_MASK; 301 espi->misc_ctrl |= F_MONITORED_DIRECTION; 302 if (adapter->params.nports == 1) 303 espi->misc_ctrl |= F_MONITORED_INTERFACE; 304 t1_write_reg_4(adapter, A_ESPI_MISC_CONTROL, espi->misc_ctrl); 305 SPIN_LOCK_INIT(espi->lock); 306 } 307 308 return 0; 309 } 310 311 void t1_espi_destroy(struct peespi *espi) 312 { 313 if (is_T2(espi->adapter)) { 314 SPIN_LOCK_DESTROY(espi->lock); 315 } 316 t1_os_free((void *)espi, sizeof(*espi)); 317 } 318 319 struct peespi *t1_espi_create(adapter_t *adapter) 320 { 321 struct peespi *espi = t1_os_malloc_wait_zero(sizeof(*espi)); 322 323 if (espi) 324 espi->adapter = adapter; 325 return espi; 326 } 327 328 void t1_espi_set_misc_ctrl(adapter_t *adapter, u32 val) 329 { 330 struct peespi *espi = adapter->espi; 331 332 if (!is_T2(adapter)) 333 return; 334 SPIN_LOCK(espi->lock); 335 espi->misc_ctrl = (val & ~MON_MASK) | 336 (espi->misc_ctrl & MON_MASK); 337 t1_write_reg_4(adapter, A_ESPI_MISC_CONTROL, espi->misc_ctrl); 338 SPIN_UNLOCK(espi->lock); 339 } 340 341 u32 t1_espi_get_mon(adapter_t *adapter, u32 addr, u8 wait) 342 { 343 struct peespi *espi = adapter->espi; 344 u32 sel; 345 346 if (!is_T2(adapter)) return 0; 347 sel = V_MONITORED_PORT_NUM((addr & 0x3c) >> 2); 348 if (!wait) { 349 if (!SPIN_TRYLOCK(espi->lock)) 350 return 0; 351 } 352 else 353 SPIN_LOCK(espi->lock); 354 if ((sel != (espi->misc_ctrl & MON_MASK))) { 355 t1_write_reg_4(adapter, A_ESPI_MISC_CONTROL, 356 ((espi->misc_ctrl & ~MON_MASK) | sel)); 357 sel = t1_read_reg_4(adapter, A_ESPI_SCH_TOKEN3); 358 t1_write_reg_4(adapter, A_ESPI_MISC_CONTROL, 359 espi->misc_ctrl); 360 } 361 else 362 sel = t1_read_reg_4(adapter, A_ESPI_SCH_TOKEN3); 363 SPIN_UNLOCK(espi->lock); 364 return sel; 365 } 366 367 /* 368 * This function is for T204 only. 369 * compare with t1_espi_get_mon(), it reads espiInTxSop[0 ~ 3] in 370 * one shot, since there is no per port counter on the out side. 371 */ 372 int 373 t1_espi_get_mon_t204(adapter_t *adapter, u32 *valp, u8 wait) 374 { 375 struct peespi *espi = adapter->espi; 376 u8 i, nport = (u8)adapter->params.nports; 377 378 if (!wait) { 379 if (!SPIN_TRYLOCK(espi->lock)) 380 return -1; 381 } else 382 SPIN_LOCK(espi->lock); 383 if ((espi->misc_ctrl & MON_MASK) != F_MONITORED_DIRECTION ) { 384 espi->misc_ctrl = (espi->misc_ctrl & ~MON_MASK) | 385 F_MONITORED_DIRECTION; 386 t1_write_reg_4(adapter, A_ESPI_MISC_CONTROL, espi->misc_ctrl); 387 } 388 for (i = 0 ; i < nport; i++, valp++) { 389 if (i) { 390 t1_write_reg_4(adapter, A_ESPI_MISC_CONTROL, 391 (espi->misc_ctrl | V_MONITORED_PORT_NUM(i))); 392 } 393 *valp = t1_read_reg_4(adapter, A_ESPI_SCH_TOKEN3); 394 } 395 396 t1_write_reg_4(adapter, A_ESPI_MISC_CONTROL, espi->misc_ctrl); 397 398 SPIN_UNLOCK(espi->lock); 399 return 0; 400 } 401