Commit | Line | Data |
---|---|---|
0a20de44 KG |
1 | /* |
2 | * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. | |
3 | * All rights reserved | |
4 | * www.brocade.com | |
5 | * | |
6 | * Linux driver for Brocade Fibre Channel Host Bus Adapter. | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify it | |
9 | * under the terms of the GNU General Public License (GPL) Version 2 as | |
10 | * published by the Free Software Foundation | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, but | |
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * General Public License for more details. | |
16 | */ | |
17 | ||
18 | #include <bfa.h> | |
19 | #include <bfa_ioc.h> | |
20 | #include <bfa_fwimg_priv.h> | |
21 | #include <cna/bfa_cna_trcmod.h> | |
22 | #include <cs/bfa_debug.h> | |
23 | #include <bfi/bfi_ioc.h> | |
24 | #include <bfi/bfi_ctreg.h> | |
25 | #include <log/bfa_log_hal.h> | |
26 | #include <defs/bfa_defs_pci.h> | |
27 | ||
28 | BFA_TRC_FILE(CNA, IOC_CT); | |
29 | ||
30 | /* | |
31 | * forward declarations | |
32 | */ | |
33 | static bfa_status_t bfa_ioc_ct_pll_init(struct bfa_ioc_s *ioc); | |
34 | static bfa_boolean_t bfa_ioc_ct_firmware_lock(struct bfa_ioc_s *ioc); | |
35 | static void bfa_ioc_ct_firmware_unlock(struct bfa_ioc_s *ioc); | |
36 | static uint32_t* bfa_ioc_ct_fwimg_get_chunk(struct bfa_ioc_s *ioc, | |
37 | uint32_t off); | |
38 | static uint32_t bfa_ioc_ct_fwimg_get_size(struct bfa_ioc_s *ioc); | |
39 | static void bfa_ioc_ct_reg_init(struct bfa_ioc_s *ioc); | |
40 | static void bfa_ioc_ct_map_port(struct bfa_ioc_s *ioc); | |
41 | static void bfa_ioc_ct_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix); | |
42 | static void bfa_ioc_ct_notify_hbfail(struct bfa_ioc_s *ioc); | |
43 | static void bfa_ioc_ct_ownership_reset(struct bfa_ioc_s *ioc); | |
44 | ||
45 | struct bfa_ioc_hwif_s hwif_ct = { | |
46 | bfa_ioc_ct_pll_init, | |
47 | bfa_ioc_ct_firmware_lock, | |
48 | bfa_ioc_ct_firmware_unlock, | |
49 | bfa_ioc_ct_fwimg_get_chunk, | |
50 | bfa_ioc_ct_fwimg_get_size, | |
51 | bfa_ioc_ct_reg_init, | |
52 | bfa_ioc_ct_map_port, | |
53 | bfa_ioc_ct_isr_mode_set, | |
54 | bfa_ioc_ct_notify_hbfail, | |
55 | bfa_ioc_ct_ownership_reset, | |
56 | }; | |
57 | ||
58 | /** | |
59 | * Called from bfa_ioc_attach() to map asic specific calls. | |
60 | */ | |
61 | void | |
62 | bfa_ioc_set_ct_hwif(struct bfa_ioc_s *ioc) | |
63 | { | |
64 | ioc->ioc_hwif = &hwif_ct; | |
65 | } | |
66 | ||
67 | static uint32_t* | |
68 | bfa_ioc_ct_fwimg_get_chunk(struct bfa_ioc_s *ioc, uint32_t off) | |
69 | { | |
70 | return bfi_image_ct_get_chunk(off); | |
71 | } | |
72 | ||
73 | static uint32_t | |
74 | bfa_ioc_ct_fwimg_get_size(struct bfa_ioc_s *ioc) | |
75 | { | |
76 | return bfi_image_ct_size; | |
77 | } | |
78 | ||
79 | /** | |
80 | * Return true if firmware of current driver matches the running firmware. | |
81 | */ | |
82 | static bfa_boolean_t | |
83 | bfa_ioc_ct_firmware_lock(struct bfa_ioc_s *ioc) | |
84 | { | |
85 | enum bfi_ioc_state ioc_fwstate; | |
86 | uint32_t usecnt; | |
87 | struct bfi_ioc_image_hdr_s fwhdr; | |
88 | ||
89 | /** | |
90 | * Firmware match check is relevant only for CNA. | |
91 | */ | |
92 | if (!ioc->cna) | |
93 | return BFA_TRUE; | |
94 | ||
95 | /** | |
96 | * If bios boot (flash based) -- do not increment usage count | |
97 | */ | |
98 | if (bfa_ioc_ct_fwimg_get_size(ioc) < BFA_IOC_FWIMG_MINSZ) | |
99 | return BFA_TRUE; | |
100 | ||
101 | bfa_ioc_sem_get(ioc->ioc_regs.ioc_usage_sem_reg); | |
102 | usecnt = bfa_reg_read(ioc->ioc_regs.ioc_usage_reg); | |
103 | ||
104 | /** | |
105 | * If usage count is 0, always return TRUE. | |
106 | */ | |
107 | if (usecnt == 0) { | |
108 | bfa_reg_write(ioc->ioc_regs.ioc_usage_reg, 1); | |
109 | bfa_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg); | |
110 | bfa_trc(ioc, usecnt); | |
111 | return BFA_TRUE; | |
112 | } | |
113 | ||
114 | ioc_fwstate = bfa_reg_read(ioc->ioc_regs.ioc_fwstate); | |
115 | bfa_trc(ioc, ioc_fwstate); | |
116 | ||
117 | /** | |
118 | * Use count cannot be non-zero and chip in uninitialized state. | |
119 | */ | |
120 | bfa_assert(ioc_fwstate != BFI_IOC_UNINIT); | |
121 | ||
122 | /** | |
123 | * Check if another driver with a different firmware is active | |
124 | */ | |
125 | bfa_ioc_fwver_get(ioc, &fwhdr); | |
126 | if (!bfa_ioc_fwver_cmp(ioc, &fwhdr)) { | |
127 | bfa_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg); | |
128 | bfa_trc(ioc, usecnt); | |
129 | return BFA_FALSE; | |
130 | } | |
131 | ||
132 | /** | |
133 | * Same firmware version. Increment the reference count. | |
134 | */ | |
135 | usecnt++; | |
136 | bfa_reg_write(ioc->ioc_regs.ioc_usage_reg, usecnt); | |
137 | bfa_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg); | |
138 | bfa_trc(ioc, usecnt); | |
139 | return BFA_TRUE; | |
140 | } | |
141 | ||
142 | static void | |
143 | bfa_ioc_ct_firmware_unlock(struct bfa_ioc_s *ioc) | |
144 | { | |
145 | uint32_t usecnt; | |
146 | ||
147 | /** | |
148 | * Firmware lock is relevant only for CNA. | |
149 | * If bios boot (flash based) -- do not decrement usage count | |
150 | */ | |
151 | if (!ioc->cna || bfa_ioc_ct_fwimg_get_size(ioc) < BFA_IOC_FWIMG_MINSZ) | |
152 | return; | |
153 | ||
154 | /** | |
155 | * decrement usage count | |
156 | */ | |
157 | bfa_ioc_sem_get(ioc->ioc_regs.ioc_usage_sem_reg); | |
158 | usecnt = bfa_reg_read(ioc->ioc_regs.ioc_usage_reg); | |
159 | bfa_assert(usecnt > 0); | |
160 | ||
161 | usecnt--; | |
162 | bfa_reg_write(ioc->ioc_regs.ioc_usage_reg, usecnt); | |
163 | bfa_trc(ioc, usecnt); | |
164 | ||
165 | bfa_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg); | |
166 | } | |
167 | ||
168 | /** | |
169 | * Notify other functions on HB failure. | |
170 | */ | |
171 | static void | |
172 | bfa_ioc_ct_notify_hbfail(struct bfa_ioc_s *ioc) | |
173 | { | |
174 | ||
175 | bfa_reg_write(ioc->ioc_regs.ll_halt, __FW_INIT_HALT_P); | |
176 | /* Wait for halt to take effect */ | |
177 | bfa_reg_read(ioc->ioc_regs.ll_halt); | |
178 | } | |
179 | ||
180 | /** | |
181 | * Host to LPU mailbox message addresses | |
182 | */ | |
183 | static struct { uint32_t hfn_mbox, lpu_mbox, hfn_pgn; } iocreg_fnreg[] = { | |
184 | { HOSTFN0_LPU_MBOX0_0, LPU_HOSTFN0_MBOX0_0, HOST_PAGE_NUM_FN0 }, | |
185 | { HOSTFN1_LPU_MBOX0_8, LPU_HOSTFN1_MBOX0_8, HOST_PAGE_NUM_FN1 }, | |
186 | { HOSTFN2_LPU_MBOX0_0, LPU_HOSTFN2_MBOX0_0, HOST_PAGE_NUM_FN2 }, | |
187 | { HOSTFN3_LPU_MBOX0_8, LPU_HOSTFN3_MBOX0_8, HOST_PAGE_NUM_FN3 } | |
188 | }; | |
189 | ||
190 | /** | |
191 | * Host <-> LPU mailbox command/status registers - port 0 | |
192 | */ | |
193 | static struct { uint32_t hfn, lpu; } iocreg_mbcmd_p0[] = { | |
194 | { HOSTFN0_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN0_MBOX0_CMD_STAT }, | |
195 | { HOSTFN1_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN1_MBOX0_CMD_STAT }, | |
196 | { HOSTFN2_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN2_MBOX0_CMD_STAT }, | |
197 | { HOSTFN3_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN3_MBOX0_CMD_STAT } | |
198 | }; | |
199 | ||
200 | /** | |
201 | * Host <-> LPU mailbox command/status registers - port 1 | |
202 | */ | |
203 | static struct { uint32_t hfn, lpu; } iocreg_mbcmd_p1[] = { | |
204 | { HOSTFN0_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN0_MBOX0_CMD_STAT }, | |
205 | { HOSTFN1_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN1_MBOX0_CMD_STAT }, | |
206 | { HOSTFN2_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN2_MBOX0_CMD_STAT }, | |
207 | { HOSTFN3_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN3_MBOX0_CMD_STAT } | |
208 | }; | |
209 | ||
210 | static void | |
211 | bfa_ioc_ct_reg_init(struct bfa_ioc_s *ioc) | |
212 | { | |
213 | bfa_os_addr_t rb; | |
214 | int pcifn = bfa_ioc_pcifn(ioc); | |
215 | ||
216 | rb = bfa_ioc_bar0(ioc); | |
217 | ||
218 | ioc->ioc_regs.hfn_mbox = rb + iocreg_fnreg[pcifn].hfn_mbox; | |
219 | ioc->ioc_regs.lpu_mbox = rb + iocreg_fnreg[pcifn].lpu_mbox; | |
220 | ioc->ioc_regs.host_page_num_fn = rb + iocreg_fnreg[pcifn].hfn_pgn; | |
221 | ||
222 | if (ioc->port_id == 0) { | |
223 | ioc->ioc_regs.heartbeat = rb + BFA_IOC0_HBEAT_REG; | |
224 | ioc->ioc_regs.ioc_fwstate = rb + BFA_IOC0_STATE_REG; | |
225 | ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd_p0[pcifn].hfn; | |
226 | ioc->ioc_regs.lpu_mbox_cmd = rb + iocreg_mbcmd_p0[pcifn].lpu; | |
227 | ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P0; | |
228 | } else { | |
229 | ioc->ioc_regs.heartbeat = (rb + BFA_IOC1_HBEAT_REG); | |
230 | ioc->ioc_regs.ioc_fwstate = (rb + BFA_IOC1_STATE_REG); | |
231 | ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd_p1[pcifn].hfn; | |
232 | ioc->ioc_regs.lpu_mbox_cmd = rb + iocreg_mbcmd_p1[pcifn].lpu; | |
233 | ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P1; | |
234 | } | |
235 | ||
236 | /* | |
237 | * PSS control registers | |
238 | */ | |
239 | ioc->ioc_regs.pss_ctl_reg = (rb + PSS_CTL_REG); | |
240 | ioc->ioc_regs.app_pll_fast_ctl_reg = (rb + APP_PLL_425_CTL_REG); | |
241 | ioc->ioc_regs.app_pll_slow_ctl_reg = (rb + APP_PLL_312_CTL_REG); | |
242 | ||
243 | /* | |
244 | * IOC semaphore registers and serialization | |
245 | */ | |
246 | ioc->ioc_regs.ioc_sem_reg = (rb + HOST_SEM0_REG); | |
247 | ioc->ioc_regs.ioc_usage_sem_reg = (rb + HOST_SEM1_REG); | |
248 | ioc->ioc_regs.ioc_init_sem_reg = (rb + HOST_SEM2_REG); | |
249 | ioc->ioc_regs.ioc_usage_reg = (rb + BFA_FW_USE_COUNT); | |
250 | ||
251 | /** | |
252 | * sram memory access | |
253 | */ | |
254 | ioc->ioc_regs.smem_page_start = (rb + PSS_SMEM_PAGE_START); | |
255 | ioc->ioc_regs.smem_pg0 = BFI_IOC_SMEM_PG0_CT; | |
256 | } | |
257 | ||
258 | /** | |
259 | * Initialize IOC to port mapping. | |
260 | */ | |
261 | ||
262 | #define FNC_PERS_FN_SHIFT(__fn) ((__fn) * 8) | |
263 | static void | |
264 | bfa_ioc_ct_map_port(struct bfa_ioc_s *ioc) | |
265 | { | |
266 | bfa_os_addr_t rb = ioc->pcidev.pci_bar_kva; | |
267 | uint32_t r32; | |
268 | ||
269 | /** | |
270 | * For catapult, base port id on personality register and IOC type | |
271 | */ | |
272 | r32 = bfa_reg_read(rb + FNC_PERS_REG); | |
273 | r32 >>= FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc)); | |
274 | ioc->port_id = (r32 & __F0_PORT_MAP_MK) >> __F0_PORT_MAP_SH; | |
275 | ||
276 | bfa_trc(ioc, bfa_ioc_pcifn(ioc)); | |
277 | bfa_trc(ioc, ioc->port_id); | |
278 | } | |
279 | ||
280 | /** | |
281 | * Set interrupt mode for a function: INTX or MSIX | |
282 | */ | |
283 | static void | |
284 | bfa_ioc_ct_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix) | |
285 | { | |
286 | bfa_os_addr_t rb = ioc->pcidev.pci_bar_kva; | |
287 | uint32_t r32, mode; | |
288 | ||
289 | r32 = bfa_reg_read(rb + FNC_PERS_REG); | |
290 | bfa_trc(ioc, r32); | |
291 | ||
292 | mode = (r32 >> FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc))) & | |
293 | __F0_INTX_STATUS; | |
294 | ||
295 | /** | |
296 | * If already in desired mode, do not change anything | |
297 | */ | |
298 | if (!msix && mode) | |
299 | return; | |
300 | ||
301 | if (msix) | |
302 | mode = __F0_INTX_STATUS_MSIX; | |
303 | else | |
304 | mode = __F0_INTX_STATUS_INTA; | |
305 | ||
306 | r32 &= ~(__F0_INTX_STATUS << FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc))); | |
307 | r32 |= (mode << FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc))); | |
308 | bfa_trc(ioc, r32); | |
309 | ||
310 | bfa_reg_write(rb + FNC_PERS_REG, r32); | |
311 | } | |
312 | ||
313 | static bfa_status_t | |
314 | bfa_ioc_ct_pll_init(struct bfa_ioc_s *ioc) | |
315 | { | |
316 | bfa_os_addr_t rb = ioc->pcidev.pci_bar_kva; | |
317 | uint32_t pll_sclk, pll_fclk, r32; | |
318 | ||
319 | /* | |
320 | * Hold semaphore so that nobody can access the chip during init. | |
321 | */ | |
322 | bfa_ioc_sem_get(ioc->ioc_regs.ioc_init_sem_reg); | |
323 | ||
324 | pll_sclk = __APP_PLL_312_ENABLE | __APP_PLL_312_LRESETN | | |
325 | __APP_PLL_312_RSEL200500 | __APP_PLL_312_P0_1(0U) | | |
326 | __APP_PLL_312_JITLMT0_1(3U) | | |
327 | __APP_PLL_312_CNTLMT0_1(1U); | |
328 | pll_fclk = __APP_PLL_425_ENABLE | __APP_PLL_425_LRESETN | | |
329 | __APP_PLL_425_RSEL200500 | __APP_PLL_425_P0_1(0U) | | |
330 | __APP_PLL_425_JITLMT0_1(3U) | | |
331 | __APP_PLL_425_CNTLMT0_1(1U); | |
332 | ||
333 | /** | |
334 | * For catapult, choose operational mode FC/FCoE | |
335 | */ | |
336 | if (ioc->fcmode) { | |
337 | bfa_reg_write((rb + OP_MODE), 0); | |
338 | bfa_reg_write((rb + ETH_MAC_SER_REG), | |
339 | __APP_EMS_CMLCKSEL | | |
340 | __APP_EMS_REFCKBUFEN2 | | |
341 | __APP_EMS_CHANNEL_SEL); | |
342 | } else { | |
343 | ioc->pllinit = BFA_TRUE; | |
344 | bfa_reg_write((rb + OP_MODE), __GLOBAL_FCOE_MODE); | |
345 | bfa_reg_write((rb + ETH_MAC_SER_REG), | |
346 | __APP_EMS_REFCKBUFEN1); | |
347 | } | |
348 | ||
349 | bfa_reg_write((rb + BFA_IOC0_STATE_REG), BFI_IOC_UNINIT); | |
350 | bfa_reg_write((rb + BFA_IOC1_STATE_REG), BFI_IOC_UNINIT); | |
351 | ||
352 | bfa_reg_write((rb + HOSTFN0_INT_MSK), 0xffffffffU); | |
353 | bfa_reg_write((rb + HOSTFN1_INT_MSK), 0xffffffffU); | |
354 | bfa_reg_write((rb + HOSTFN0_INT_STATUS), 0xffffffffU); | |
355 | bfa_reg_write((rb + HOSTFN1_INT_STATUS), 0xffffffffU); | |
356 | bfa_reg_write((rb + HOSTFN0_INT_MSK), 0xffffffffU); | |
357 | bfa_reg_write((rb + HOSTFN1_INT_MSK), 0xffffffffU); | |
358 | ||
359 | bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg, | |
360 | __APP_PLL_312_LOGIC_SOFT_RESET); | |
361 | bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg, | |
362 | __APP_PLL_312_BYPASS | | |
363 | __APP_PLL_312_LOGIC_SOFT_RESET); | |
364 | bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg, | |
365 | __APP_PLL_425_LOGIC_SOFT_RESET); | |
366 | bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg, | |
367 | __APP_PLL_425_BYPASS | | |
368 | __APP_PLL_425_LOGIC_SOFT_RESET); | |
369 | bfa_os_udelay(2); | |
370 | bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg, | |
371 | __APP_PLL_312_LOGIC_SOFT_RESET); | |
372 | bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg, | |
373 | __APP_PLL_425_LOGIC_SOFT_RESET); | |
374 | ||
375 | bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg, | |
376 | pll_sclk | __APP_PLL_312_LOGIC_SOFT_RESET); | |
377 | bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg, | |
378 | pll_fclk | __APP_PLL_425_LOGIC_SOFT_RESET); | |
379 | ||
380 | /** | |
381 | * Wait for PLLs to lock. | |
382 | */ | |
383 | bfa_os_udelay(2000); | |
384 | bfa_reg_write((rb + HOSTFN0_INT_STATUS), 0xffffffffU); | |
385 | bfa_reg_write((rb + HOSTFN1_INT_STATUS), 0xffffffffU); | |
386 | ||
387 | bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg, pll_sclk); | |
388 | bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg, pll_fclk); | |
389 | ||
390 | bfa_reg_write((rb + MBIST_CTL_REG), __EDRAM_BISTR_START); | |
391 | bfa_os_udelay(1000); | |
392 | r32 = bfa_reg_read((rb + MBIST_STAT_REG)); | |
393 | bfa_trc(ioc, r32); | |
394 | /* | |
395 | * release semaphore. | |
396 | */ | |
397 | bfa_ioc_sem_release(ioc->ioc_regs.ioc_init_sem_reg); | |
398 | ||
399 | return BFA_STATUS_OK; | |
400 | } | |
401 | ||
402 | /** | |
403 | * Cleanup hw semaphore and usecnt registers | |
404 | */ | |
405 | static void | |
406 | bfa_ioc_ct_ownership_reset(struct bfa_ioc_s *ioc) | |
407 | { | |
408 | ||
409 | if (ioc->cna) { | |
410 | bfa_ioc_sem_get(ioc->ioc_regs.ioc_usage_sem_reg); | |
411 | bfa_reg_write(ioc->ioc_regs.ioc_usage_reg, 0); | |
412 | bfa_ioc_sem_release(ioc->ioc_regs.ioc_usage_sem_reg); | |
413 | } | |
414 | ||
415 | /* | |
416 | * Read the hw sem reg to make sure that it is locked | |
417 | * before we clear it. If it is not locked, writing 1 | |
418 | * will lock it instead of clearing it. | |
419 | */ | |
420 | bfa_reg_read(ioc->ioc_regs.ioc_sem_reg); | |
421 | bfa_ioc_hw_sem_release(ioc); | |
422 | } |