diff options
Diffstat (limited to 'drivers/net/chelsio/espi.c')
-rw-r--r-- | drivers/net/chelsio/espi.c | 205 |
1 files changed, 120 insertions, 85 deletions
diff --git a/drivers/net/chelsio/espi.c b/drivers/net/chelsio/espi.c index 542e5e065c6..4192f0f5b3e 100644 --- a/drivers/net/chelsio/espi.c +++ b/drivers/net/chelsio/espi.c | |||
@@ -81,46 +81,36 @@ static int tricn_write(adapter_t *adapter, int bundle_addr, int module_addr, | |||
81 | return busy; | 81 | return busy; |
82 | } | 82 | } |
83 | 83 | ||
84 | /* 1. Deassert rx_reset_core. */ | ||
85 | /* 2. Program TRICN_CNFG registers. */ | ||
86 | /* 3. Deassert rx_reset_link */ | ||
87 | static int tricn_init(adapter_t *adapter) | 84 | static int tricn_init(adapter_t *adapter) |
88 | { | 85 | { |
89 | int i = 0; | 86 | int i, sme = 1; |
90 | int stat = 0; | ||
91 | int timeout = 0; | ||
92 | int is_ready = 0; | ||
93 | 87 | ||
94 | /* 1 */ | 88 | if (!(readl(adapter->regs + A_ESPI_RX_RESET) & F_RX_CLK_STATUS)) { |
95 | timeout=1000; | 89 | CH_ERR("%s: ESPI clock not ready\n", adapter->name); |
96 | do { | 90 | return -1; |
97 | stat = readl(adapter->regs + A_ESPI_RX_RESET); | ||
98 | is_ready = (stat & 0x4); | ||
99 | timeout--; | ||
100 | udelay(5); | ||
101 | } while (!is_ready || (timeout==0)); | ||
102 | writel(0x2, adapter->regs + A_ESPI_RX_RESET); | ||
103 | if (timeout==0) | ||
104 | { | ||
105 | CH_ERR("ESPI : ERROR : Timeout tricn_init() \n"); | ||
106 | t1_fatal_err(adapter); | ||
107 | } | 91 | } |
108 | 92 | ||
109 | /* 2 */ | 93 | writel(F_ESPI_RX_CORE_RST, adapter->regs + A_ESPI_RX_RESET); |
110 | tricn_write(adapter, 0, 0, 0, TRICN_CNFG, 0x81); | 94 | |
111 | tricn_write(adapter, 0, 1, 0, TRICN_CNFG, 0x81); | 95 | if (sme) { |
112 | tricn_write(adapter, 0, 2, 0, TRICN_CNFG, 0x81); | 96 | tricn_write(adapter, 0, 0, 0, TRICN_CNFG, 0x81); |
113 | for (i=1; i<= 8; i++) tricn_write(adapter, 0, 0, i, TRICN_CNFG, 0xf1); | 97 | tricn_write(adapter, 0, 1, 0, TRICN_CNFG, 0x81); |
114 | for (i=1; i<= 2; i++) tricn_write(adapter, 0, 1, i, TRICN_CNFG, 0xf1); | 98 | tricn_write(adapter, 0, 2, 0, TRICN_CNFG, 0x81); |
115 | for (i=1; i<= 3; i++) tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0xe1); | 99 | } |
116 | for (i=4; i<= 4; i++) tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0xf1); | 100 | for (i = 1; i <= 8; i++) |
117 | for (i=5; i<= 5; i++) tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0xe1); | 101 | tricn_write(adapter, 0, 0, i, TRICN_CNFG, 0xf1); |
118 | for (i=6; i<= 6; i++) tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0xf1); | 102 | for (i = 1; i <= 2; i++) |
119 | for (i=7; i<= 7; i++) tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0x80); | 103 | tricn_write(adapter, 0, 1, i, TRICN_CNFG, 0xf1); |
120 | for (i=8; i<= 8; i++) tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0xf1); | 104 | for (i = 1; i <= 3; i++) |
121 | 105 | tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0xe1); | |
122 | /* 3 */ | 106 | tricn_write(adapter, 0, 2, 4, TRICN_CNFG, 0xf1); |
123 | writel(0x3, adapter->regs + A_ESPI_RX_RESET); | 107 | tricn_write(adapter, 0, 2, 5, TRICN_CNFG, 0xe1); |
108 | tricn_write(adapter, 0, 2, 6, TRICN_CNFG, 0xf1); | ||
109 | tricn_write(adapter, 0, 2, 7, TRICN_CNFG, 0x80); | ||
110 | tricn_write(adapter, 0, 2, 8, TRICN_CNFG, 0xf1); | ||
111 | |||
112 | writel(F_ESPI_RX_CORE_RST | F_ESPI_RX_LNK_RST, | ||
113 | adapter->regs + A_ESPI_RX_RESET); | ||
124 | 114 | ||
125 | return 0; | 115 | return 0; |
126 | } | 116 | } |
@@ -143,6 +133,7 @@ void t1_espi_intr_enable(struct peespi *espi) | |||
143 | 133 | ||
144 | void t1_espi_intr_clear(struct peespi *espi) | 134 | void t1_espi_intr_clear(struct peespi *espi) |
145 | { | 135 | { |
136 | readl(espi->adapter->regs + A_ESPI_DIP2_ERR_COUNT); | ||
146 | writel(0xffffffff, espi->adapter->regs + A_ESPI_INTR_STATUS); | 137 | writel(0xffffffff, espi->adapter->regs + A_ESPI_INTR_STATUS); |
147 | writel(F_PL_INTR_ESPI, espi->adapter->regs + A_PL_CAUSE); | 138 | writel(F_PL_INTR_ESPI, espi->adapter->regs + A_PL_CAUSE); |
148 | } | 139 | } |
@@ -157,7 +148,6 @@ void t1_espi_intr_disable(struct peespi *espi) | |||
157 | 148 | ||
158 | int t1_espi_intr_handler(struct peespi *espi) | 149 | int t1_espi_intr_handler(struct peespi *espi) |
159 | { | 150 | { |
160 | u32 cnt; | ||
161 | u32 status = readl(espi->adapter->regs + A_ESPI_INTR_STATUS); | 151 | u32 status = readl(espi->adapter->regs + A_ESPI_INTR_STATUS); |
162 | 152 | ||
163 | if (status & F_DIP4ERR) | 153 | if (status & F_DIP4ERR) |
@@ -177,7 +167,7 @@ int t1_espi_intr_handler(struct peespi *espi) | |||
177 | * Must read the error count to clear the interrupt | 167 | * Must read the error count to clear the interrupt |
178 | * that it causes. | 168 | * that it causes. |
179 | */ | 169 | */ |
180 | cnt = readl(espi->adapter->regs + A_ESPI_DIP2_ERR_COUNT); | 170 | readl(espi->adapter->regs + A_ESPI_DIP2_ERR_COUNT); |
181 | } | 171 | } |
182 | 172 | ||
183 | /* | 173 | /* |
@@ -192,7 +182,7 @@ int t1_espi_intr_handler(struct peespi *espi) | |||
192 | 182 | ||
193 | const struct espi_intr_counts *t1_espi_get_intr_counts(struct peespi *espi) | 183 | const struct espi_intr_counts *t1_espi_get_intr_counts(struct peespi *espi) |
194 | { | 184 | { |
195 | return &espi->intr_cnt; | 185 | return &espi->intr_cnt; |
196 | } | 186 | } |
197 | 187 | ||
198 | static void espi_setup_for_pm3393(adapter_t *adapter) | 188 | static void espi_setup_for_pm3393(adapter_t *adapter) |
@@ -210,17 +200,45 @@ static void espi_setup_for_pm3393(adapter_t *adapter) | |||
210 | writel(V_RX_NPORTS(1) | V_TX_NPORTS(1), adapter->regs + A_PORT_CONFIG); | 200 | writel(V_RX_NPORTS(1) | V_TX_NPORTS(1), adapter->regs + A_PORT_CONFIG); |
211 | } | 201 | } |
212 | 202 | ||
213 | /* T2 Init part -- */ | 203 | static void espi_setup_for_vsc7321(adapter_t *adapter) |
214 | /* 1. Set T_ESPI_MISCCTRL_ADDR */ | 204 | { |
215 | /* 2. Init ESPI registers. */ | 205 | writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN0); |
216 | /* 3. Init TriCN Hard Macro */ | 206 | writel(0x1f401f4, adapter->regs + A_ESPI_SCH_TOKEN1); |
217 | int t1_espi_init(struct peespi *espi, int mac_type, int nports) | 207 | writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN2); |
208 | writel(0xa00, adapter->regs + A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK); | ||
209 | writel(0x1ff, adapter->regs + A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK); | ||
210 | writel(1, adapter->regs + A_ESPI_CALENDAR_LENGTH); | ||
211 | writel(V_RX_NPORTS(4) | V_TX_NPORTS(4), adapter->regs + A_PORT_CONFIG); | ||
212 | |||
213 | writel(0x08000008, adapter->regs + A_ESPI_TRAIN); | ||
214 | } | ||
215 | |||
216 | /* | ||
217 | * Note that T1B requires at least 2 ports for IXF1010 due to a HW bug. | ||
218 | */ | ||
219 | static void espi_setup_for_ixf1010(adapter_t *adapter, int nports) | ||
218 | { | 220 | { |
219 | u32 cnt; | 221 | writel(1, adapter->regs + A_ESPI_CALENDAR_LENGTH); |
222 | if (nports == 4) { | ||
223 | if (is_T2(adapter)) { | ||
224 | writel(0xf00, adapter->regs + A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK); | ||
225 | writel(0x3c0, adapter->regs + A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK); | ||
226 | } else { | ||
227 | writel(0x7ff, adapter->regs + A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK); | ||
228 | writel(0x1ff, adapter->regs + A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK); | ||
229 | } | ||
230 | } else { | ||
231 | writel(0x1fff, adapter->regs + A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK); | ||
232 | writel(0x7ff, adapter->regs + A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK); | ||
233 | } | ||
234 | writel(V_RX_NPORTS(nports) | V_TX_NPORTS(nports), adapter->regs + A_PORT_CONFIG); | ||
220 | 235 | ||
236 | } | ||
237 | |||
238 | int t1_espi_init(struct peespi *espi, int mac_type, int nports) | ||
239 | { | ||
221 | u32 status_enable_extra = 0; | 240 | u32 status_enable_extra = 0; |
222 | adapter_t *adapter = espi->adapter; | 241 | adapter_t *adapter = espi->adapter; |
223 | u32 status, burstval = 0x800100; | ||
224 | 242 | ||
225 | /* Disable ESPI training. MACs that can handle it enable it below. */ | 243 | /* Disable ESPI training. MACs that can handle it enable it below. */ |
226 | writel(0, adapter->regs + A_ESPI_TRAIN); | 244 | writel(0, adapter->regs + A_ESPI_TRAIN); |
@@ -229,38 +247,20 @@ int t1_espi_init(struct peespi *espi, int mac_type, int nports) | |||
229 | writel(V_OUT_OF_SYNC_COUNT(4) | | 247 | writel(V_OUT_OF_SYNC_COUNT(4) | |
230 | V_DIP2_PARITY_ERR_THRES(3) | | 248 | V_DIP2_PARITY_ERR_THRES(3) | |
231 | V_DIP4_THRES(1), adapter->regs + A_ESPI_MISC_CONTROL); | 249 | V_DIP4_THRES(1), adapter->regs + A_ESPI_MISC_CONTROL); |
232 | if (nports == 4) { | 250 | writel(nports == 4 ? 0x200040 : 0x1000080, |
233 | /* T204: maxburst1 = 0x40, maxburst2 = 0x20 */ | 251 | adapter->regs + A_ESPI_MAXBURST1_MAXBURST2); |
234 | burstval = 0x200040; | 252 | } else |
235 | } | 253 | writel(0x800100, adapter->regs + A_ESPI_MAXBURST1_MAXBURST2); |
236 | } | ||
237 | writel(burstval, adapter->regs + A_ESPI_MAXBURST1_MAXBURST2); | ||
238 | 254 | ||
239 | switch (mac_type) { | 255 | if (mac_type == CHBT_MAC_PM3393) |
240 | case CHBT_MAC_PM3393: | ||
241 | espi_setup_for_pm3393(adapter); | 256 | espi_setup_for_pm3393(adapter); |
242 | break; | 257 | else if (mac_type == CHBT_MAC_VSC7321) |
243 | default: | 258 | espi_setup_for_vsc7321(adapter); |
259 | else if (mac_type == CHBT_MAC_IXF1010) { | ||
260 | status_enable_extra = F_INTEL1010MODE; | ||
261 | espi_setup_for_ixf1010(adapter, nports); | ||
262 | } else | ||
244 | return -1; | 263 | return -1; |
245 | } | ||
246 | |||
247 | /* | ||
248 | * Make sure any pending interrupts from the SPI are | ||
249 | * Cleared before enabling the interrupt. | ||
250 | */ | ||
251 | writel(ESPI_INTR_MASK, espi->adapter->regs + A_ESPI_INTR_ENABLE); | ||
252 | status = readl(espi->adapter->regs + A_ESPI_INTR_STATUS); | ||
253 | if (status & F_DIP2PARITYERR) { | ||
254 | cnt = readl(espi->adapter->regs + A_ESPI_DIP2_ERR_COUNT); | ||
255 | } | ||
256 | |||
257 | /* | ||
258 | * For T1B we need to write 1 to clear ESPI interrupts. For T2+ we | ||
259 | * write the status as is. | ||
260 | */ | ||
261 | if (status && t1_is_T1B(espi->adapter)) | ||
262 | status = 1; | ||
263 | writel(status, espi->adapter->regs + A_ESPI_INTR_STATUS); | ||
264 | 264 | ||
265 | writel(status_enable_extra | F_RXSTATUSENABLE, | 265 | writel(status_enable_extra | F_RXSTATUSENABLE, |
266 | adapter->regs + A_ESPI_FIFO_STATUS_ENABLE); | 266 | adapter->regs + A_ESPI_FIFO_STATUS_ENABLE); |
@@ -271,9 +271,11 @@ int t1_espi_init(struct peespi *espi, int mac_type, int nports) | |||
271 | * Always position the control at the 1st port egress IN | 271 | * Always position the control at the 1st port egress IN |
272 | * (sop,eop) counter to reduce PIOs for T/N210 workaround. | 272 | * (sop,eop) counter to reduce PIOs for T/N210 workaround. |
273 | */ | 273 | */ |
274 | espi->misc_ctrl = (readl(adapter->regs + A_ESPI_MISC_CONTROL) | 274 | espi->misc_ctrl = readl(adapter->regs + A_ESPI_MISC_CONTROL); |
275 | & ~MON_MASK) | (F_MONITORED_DIRECTION | 275 | espi->misc_ctrl &= ~MON_MASK; |
276 | | F_MONITORED_INTERFACE); | 276 | espi->misc_ctrl |= F_MONITORED_DIRECTION; |
277 | if (adapter->params.nports == 1) | ||
278 | espi->misc_ctrl |= F_MONITORED_INTERFACE; | ||
277 | writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL); | 279 | writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL); |
278 | spin_lock_init(&espi->lock); | 280 | spin_lock_init(&espi->lock); |
279 | } | 281 | } |
@@ -299,8 +301,7 @@ void t1_espi_set_misc_ctrl(adapter_t *adapter, u32 val) | |||
299 | { | 301 | { |
300 | struct peespi *espi = adapter->espi; | 302 | struct peespi *espi = adapter->espi; |
301 | 303 | ||
302 | if (!is_T2(adapter)) | 304 | if (!is_T2(adapter)) return; |
303 | return; | ||
304 | spin_lock(&espi->lock); | 305 | spin_lock(&espi->lock); |
305 | espi->misc_ctrl = (val & ~MON_MASK) | | 306 | espi->misc_ctrl = (val & ~MON_MASK) | |
306 | (espi->misc_ctrl & MON_MASK); | 307 | (espi->misc_ctrl & MON_MASK); |
@@ -310,27 +311,61 @@ void t1_espi_set_misc_ctrl(adapter_t *adapter, u32 val) | |||
310 | 311 | ||
311 | u32 t1_espi_get_mon(adapter_t *adapter, u32 addr, u8 wait) | 312 | u32 t1_espi_get_mon(adapter_t *adapter, u32 addr, u8 wait) |
312 | { | 313 | { |
313 | u32 sel; | ||
314 | |||
315 | struct peespi *espi = adapter->espi; | 314 | struct peespi *espi = adapter->espi; |
315 | u32 sel; | ||
316 | 316 | ||
317 | if (!is_T2(adapter)) | 317 | if (!is_T2(adapter)) |
318 | return 0; | 318 | return 0; |
319 | |||
319 | sel = V_MONITORED_PORT_NUM((addr & 0x3c) >> 2); | 320 | sel = V_MONITORED_PORT_NUM((addr & 0x3c) >> 2); |
320 | if (!wait) { | 321 | if (!wait) { |
321 | if (!spin_trylock(&espi->lock)) | 322 | if (!spin_trylock(&espi->lock)) |
322 | return 0; | 323 | return 0; |
323 | } | 324 | } else |
324 | else | ||
325 | spin_lock(&espi->lock); | 325 | spin_lock(&espi->lock); |
326 | |||
326 | if ((sel != (espi->misc_ctrl & MON_MASK))) { | 327 | if ((sel != (espi->misc_ctrl & MON_MASK))) { |
327 | writel(((espi->misc_ctrl & ~MON_MASK) | sel), | 328 | writel(((espi->misc_ctrl & ~MON_MASK) | sel), |
328 | adapter->regs + A_ESPI_MISC_CONTROL); | 329 | adapter->regs + A_ESPI_MISC_CONTROL); |
329 | sel = readl(adapter->regs + A_ESPI_SCH_TOKEN3); | 330 | sel = readl(adapter->regs + A_ESPI_SCH_TOKEN3); |
330 | writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL); | 331 | writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL); |
331 | } | 332 | } else |
332 | else | ||
333 | sel = readl(adapter->regs + A_ESPI_SCH_TOKEN3); | 333 | sel = readl(adapter->regs + A_ESPI_SCH_TOKEN3); |
334 | spin_unlock(&espi->lock); | 334 | spin_unlock(&espi->lock); |
335 | return sel; | 335 | return sel; |
336 | } | 336 | } |
337 | |||
338 | /* | ||
339 | * This function is for T204 only. | ||
340 | * compare with t1_espi_get_mon(), it reads espiInTxSop[0 ~ 3] in | ||
341 | * one shot, since there is no per port counter on the out side. | ||
342 | */ | ||
343 | int | ||
344 | t1_espi_get_mon_t204(adapter_t *adapter, u32 *valp, u8 wait) | ||
345 | { | ||
346 | struct peespi *espi = adapter->espi; | ||
347 | u8 i, nport = (u8)adapter->params.nports; | ||
348 | |||
349 | if (!wait) { | ||
350 | if (!spin_trylock(&espi->lock)) | ||
351 | return -1; | ||
352 | } else | ||
353 | spin_lock(&espi->lock); | ||
354 | |||
355 | if ( (espi->misc_ctrl & MON_MASK) != F_MONITORED_DIRECTION ) { | ||
356 | espi->misc_ctrl = (espi->misc_ctrl & ~MON_MASK) | | ||
357 | F_MONITORED_DIRECTION; | ||
358 | writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL); | ||
359 | } | ||
360 | for (i = 0 ; i < nport; i++, valp++) { | ||
361 | if (i) { | ||
362 | writel(espi->misc_ctrl | V_MONITORED_PORT_NUM(i), | ||
363 | adapter->regs + A_ESPI_MISC_CONTROL); | ||
364 | } | ||
365 | *valp = readl(adapter->regs + A_ESPI_SCH_TOKEN3); | ||
366 | } | ||
367 | |||
368 | writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL); | ||
369 | spin_unlock(&espi->lock); | ||
370 | return 0; | ||
371 | } | ||