Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at 77b2555b52a894a2e39a42e43d993df875c46a6a 346 lines 11 kB view raw
1/***************************************************************************** 2 * * 3 * File: espi.c * 4 * $Revision: 1.14 $ * 5 * $Date: 2005/05/14 00:59:32 $ * 6 * Description: * 7 * Ethernet SPI functionality. * 8 * part of the Chelsio 10Gb Ethernet Driver. * 9 * * 10 * This program is free software; you can redistribute it and/or modify * 11 * it under the terms of the GNU General Public License, version 2, as * 12 * published by the Free Software Foundation. * 13 * * 14 * You should have received a copy of the GNU General Public License along * 15 * with this program; if not, write to the Free Software Foundation, Inc., * 16 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * 17 * * 18 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * 19 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * 20 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * 21 * * 22 * http://www.chelsio.com * 23 * * 24 * Copyright (c) 2003 - 2005 Chelsio Communications, Inc. * 25 * All rights reserved. * 26 * * 27 * Maintainers: maintainers@chelsio.com * 28 * * 29 * Authors: Dimitrios Michailidis <dm@chelsio.com> * 30 * Tina Yang <tainay@chelsio.com> * 31 * Felix Marti <felix@chelsio.com> * 32 * Scott Bardone <sbardone@chelsio.com> * 33 * Kurt Ottaway <kottaway@chelsio.com> * 34 * Frank DiMambro <frank@chelsio.com> * 35 * * 36 * History: * 37 * * 38 ****************************************************************************/ 39 40#include "common.h" 41#include "regs.h" 42#include "espi.h" 43 44struct peespi { 45 adapter_t *adapter; 46 struct espi_intr_counts intr_cnt; 47 u32 misc_ctrl; 48 spinlock_t lock; 49}; 50 51#define ESPI_INTR_MASK (F_DIP4ERR | F_RXDROP | F_TXDROP | F_RXOVERFLOW | \ 52 F_RAMPARITYERR | F_DIP2PARITYERR) 53#define MON_MASK (V_MONITORED_PORT_NUM(3) | F_MONITORED_DIRECTION \ 54 | F_MONITORED_INTERFACE) 55 56#define TRICN_CNFG 14 57#define TRICN_CMD_READ 0x11 58#define TRICN_CMD_WRITE 0x21 59#define TRICN_CMD_ATTEMPTS 10 60 61static int tricn_write(adapter_t *adapter, int bundle_addr, int module_addr, 62 int ch_addr, int reg_offset, u32 wr_data) 63{ 64 int busy, attempts = TRICN_CMD_ATTEMPTS; 65 66 writel(V_WRITE_DATA(wr_data) | 67 V_REGISTER_OFFSET(reg_offset) | 68 V_CHANNEL_ADDR(ch_addr) | V_MODULE_ADDR(module_addr) | 69 V_BUNDLE_ADDR(bundle_addr) | 70 V_SPI4_COMMAND(TRICN_CMD_WRITE), 71 adapter->regs + A_ESPI_CMD_ADDR); 72 writel(0, adapter->regs + A_ESPI_GOSTAT); 73 74 do { 75 busy = readl(adapter->regs + A_ESPI_GOSTAT) & F_ESPI_CMD_BUSY; 76 } while (busy && --attempts); 77 78 if (busy) 79 CH_ERR("%s: TRICN write timed out\n", adapter->name); 80 81 return busy; 82} 83 84/* 1. Deassert rx_reset_core. */ 85/* 2. Program TRICN_CNFG registers. */ 86/* 3. Deassert rx_reset_link */ 87static int tricn_init(adapter_t *adapter) 88{ 89 int i = 0; 90 int sme = 1; 91 int stat = 0; 92 int timeout = 0; 93 int is_ready = 0; 94 int dynamic_deskew = 0; 95 96 if (dynamic_deskew) 97 sme = 0; 98 99 100 /* 1 */ 101 timeout=1000; 102 do { 103 stat = readl(adapter->regs + A_ESPI_RX_RESET); 104 is_ready = (stat & 0x4); 105 timeout--; 106 udelay(5); 107 } while (!is_ready || (timeout==0)); 108 writel(0x2, adapter->regs + A_ESPI_RX_RESET); 109 if (timeout==0) 110 { 111 CH_ERR("ESPI : ERROR : Timeout tricn_init() \n"); 112 t1_fatal_err(adapter); 113 } 114 115 /* 2 */ 116 if (sme) { 117 tricn_write(adapter, 0, 0, 0, TRICN_CNFG, 0x81); 118 tricn_write(adapter, 0, 1, 0, TRICN_CNFG, 0x81); 119 tricn_write(adapter, 0, 2, 0, TRICN_CNFG, 0x81); 120 } 121 for (i=1; i<= 8; i++) tricn_write(adapter, 0, 0, i, TRICN_CNFG, 0xf1); 122 for (i=1; i<= 2; i++) tricn_write(adapter, 0, 1, i, TRICN_CNFG, 0xf1); 123 for (i=1; i<= 3; i++) tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0xe1); 124 for (i=4; i<= 4; i++) tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0xf1); 125 for (i=5; i<= 5; i++) tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0xe1); 126 for (i=6; i<= 6; i++) tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0xf1); 127 for (i=7; i<= 7; i++) tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0x80); 128 for (i=8; i<= 8; i++) tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0xf1); 129 130 /* 3 */ 131 writel(0x3, adapter->regs + A_ESPI_RX_RESET); 132 133 return 0; 134} 135 136void t1_espi_intr_enable(struct peespi *espi) 137{ 138 u32 enable, pl_intr = readl(espi->adapter->regs + A_PL_ENABLE); 139 140 /* 141 * Cannot enable ESPI interrupts on T1B because HW asserts the 142 * interrupt incorrectly, namely the driver gets ESPI interrupts 143 * but no data is actually dropped (can verify this reading the ESPI 144 * drop registers). Also, once the ESPI interrupt is asserted it 145 * cannot be cleared (HW bug). 146 */ 147 enable = t1_is_T1B(espi->adapter) ? 0 : ESPI_INTR_MASK; 148 writel(enable, espi->adapter->regs + A_ESPI_INTR_ENABLE); 149 writel(pl_intr | F_PL_INTR_ESPI, espi->adapter->regs + A_PL_ENABLE); 150} 151 152void t1_espi_intr_clear(struct peespi *espi) 153{ 154 writel(0xffffffff, espi->adapter->regs + A_ESPI_INTR_STATUS); 155 writel(F_PL_INTR_ESPI, espi->adapter->regs + A_PL_CAUSE); 156} 157 158void t1_espi_intr_disable(struct peespi *espi) 159{ 160 u32 pl_intr = readl(espi->adapter->regs + A_PL_ENABLE); 161 162 writel(0, espi->adapter->regs + A_ESPI_INTR_ENABLE); 163 writel(pl_intr & ~F_PL_INTR_ESPI, espi->adapter->regs + A_PL_ENABLE); 164} 165 166int t1_espi_intr_handler(struct peespi *espi) 167{ 168 u32 cnt; 169 u32 status = readl(espi->adapter->regs + A_ESPI_INTR_STATUS); 170 171 if (status & F_DIP4ERR) 172 espi->intr_cnt.DIP4_err++; 173 if (status & F_RXDROP) 174 espi->intr_cnt.rx_drops++; 175 if (status & F_TXDROP) 176 espi->intr_cnt.tx_drops++; 177 if (status & F_RXOVERFLOW) 178 espi->intr_cnt.rx_ovflw++; 179 if (status & F_RAMPARITYERR) 180 espi->intr_cnt.parity_err++; 181 if (status & F_DIP2PARITYERR) { 182 espi->intr_cnt.DIP2_parity_err++; 183 184 /* 185 * Must read the error count to clear the interrupt 186 * that it causes. 187 */ 188 cnt = readl(espi->adapter->regs + A_ESPI_DIP2_ERR_COUNT); 189 } 190 191 /* 192 * For T1B we need to write 1 to clear ESPI interrupts. For T2+ we 193 * write the status as is. 194 */ 195 if (status && t1_is_T1B(espi->adapter)) 196 status = 1; 197 writel(status, espi->adapter->regs + A_ESPI_INTR_STATUS); 198 return 0; 199} 200 201const struct espi_intr_counts *t1_espi_get_intr_counts(struct peespi *espi) 202{ 203 return &espi->intr_cnt; 204} 205 206static void espi_setup_for_pm3393(adapter_t *adapter) 207{ 208 u32 wmark = t1_is_T1B(adapter) ? 0x4000 : 0x3200; 209 210 writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN0); 211 writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN1); 212 writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN2); 213 writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN3); 214 writel(0x100, adapter->regs + A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK); 215 writel(wmark, adapter->regs + A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK); 216 writel(3, adapter->regs + A_ESPI_CALENDAR_LENGTH); 217 writel(0x08000008, adapter->regs + A_ESPI_TRAIN); 218 writel(V_RX_NPORTS(1) | V_TX_NPORTS(1), adapter->regs + A_PORT_CONFIG); 219} 220 221/* T2 Init part -- */ 222/* 1. Set T_ESPI_MISCCTRL_ADDR */ 223/* 2. Init ESPI registers. */ 224/* 3. Init TriCN Hard Macro */ 225int t1_espi_init(struct peespi *espi, int mac_type, int nports) 226{ 227 u32 cnt; 228 229 u32 status_enable_extra = 0; 230 adapter_t *adapter = espi->adapter; 231 u32 status, burstval = 0x800100; 232 233 /* Disable ESPI training. MACs that can handle it enable it below. */ 234 writel(0, adapter->regs + A_ESPI_TRAIN); 235 236 if (is_T2(adapter)) { 237 writel(V_OUT_OF_SYNC_COUNT(4) | 238 V_DIP2_PARITY_ERR_THRES(3) | 239 V_DIP4_THRES(1), adapter->regs + A_ESPI_MISC_CONTROL); 240 if (nports == 4) { 241 /* T204: maxburst1 = 0x40, maxburst2 = 0x20 */ 242 burstval = 0x200040; 243 } 244 } 245 writel(burstval, adapter->regs + A_ESPI_MAXBURST1_MAXBURST2); 246 247 switch (mac_type) { 248 case CHBT_MAC_PM3393: 249 espi_setup_for_pm3393(adapter); 250 break; 251 default: 252 return -1; 253 } 254 255 /* 256 * Make sure any pending interrupts from the SPI are 257 * Cleared before enabling the interrupt. 258 */ 259 writel(ESPI_INTR_MASK, espi->adapter->regs + A_ESPI_INTR_ENABLE); 260 status = readl(espi->adapter->regs + A_ESPI_INTR_STATUS); 261 if (status & F_DIP2PARITYERR) { 262 cnt = readl(espi->adapter->regs + A_ESPI_DIP2_ERR_COUNT); 263 } 264 265 /* 266 * For T1B we need to write 1 to clear ESPI interrupts. For T2+ we 267 * write the status as is. 268 */ 269 if (status && t1_is_T1B(espi->adapter)) 270 status = 1; 271 writel(status, espi->adapter->regs + A_ESPI_INTR_STATUS); 272 273 writel(status_enable_extra | F_RXSTATUSENABLE, 274 adapter->regs + A_ESPI_FIFO_STATUS_ENABLE); 275 276 if (is_T2(adapter)) { 277 tricn_init(adapter); 278 /* 279 * Always position the control at the 1st port egress IN 280 * (sop,eop) counter to reduce PIOs for T/N210 workaround. 281 */ 282 espi->misc_ctrl = (readl(adapter->regs + A_ESPI_MISC_CONTROL) 283 & ~MON_MASK) | (F_MONITORED_DIRECTION 284 | F_MONITORED_INTERFACE); 285 writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL); 286 spin_lock_init(&espi->lock); 287 } 288 289 return 0; 290} 291 292void t1_espi_destroy(struct peespi *espi) 293{ 294 kfree(espi); 295} 296 297struct peespi *t1_espi_create(adapter_t *adapter) 298{ 299 struct peespi *espi = kmalloc(sizeof(*espi), GFP_KERNEL); 300 301 memset(espi, 0, sizeof(*espi)); 302 303 if (espi) 304 espi->adapter = adapter; 305 return espi; 306} 307 308void t1_espi_set_misc_ctrl(adapter_t *adapter, u32 val) 309{ 310 struct peespi *espi = adapter->espi; 311 312 if (!is_T2(adapter)) 313 return; 314 spin_lock(&espi->lock); 315 espi->misc_ctrl = (val & ~MON_MASK) | 316 (espi->misc_ctrl & MON_MASK); 317 writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL); 318 spin_unlock(&espi->lock); 319} 320 321u32 t1_espi_get_mon(adapter_t *adapter, u32 addr, u8 wait) 322{ 323 u32 sel; 324 325 struct peespi *espi = adapter->espi; 326 327 if (!is_T2(adapter)) 328 return 0; 329 sel = V_MONITORED_PORT_NUM((addr & 0x3c) >> 2); 330 if (!wait) { 331 if (!spin_trylock(&espi->lock)) 332 return 0; 333 } 334 else 335 spin_lock(&espi->lock); 336 if ((sel != (espi->misc_ctrl & MON_MASK))) { 337 writel(((espi->misc_ctrl & ~MON_MASK) | sel), 338 adapter->regs + A_ESPI_MISC_CONTROL); 339 sel = readl(adapter->regs + A_ESPI_SCH_TOKEN3); 340 writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL); 341 } 342 else 343 sel = readl(adapter->regs + A_ESPI_SCH_TOKEN3); 344 spin_unlock(&espi->lock); 345 return sel; 346}