Commit | Line | Data |
---|---|---|
0a20de44 | 1 | /* |
a36c61f9 | 2 | * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. |
0a20de44 KG |
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 | ||
f16a1750 | 18 | #include "bfad_drv.h" |
a36c61f9 | 19 | #include "bfa_ioc.h" |
11189208 | 20 | #include "bfi_reg.h" |
a36c61f9 | 21 | #include "bfa_defs.h" |
0a20de44 KG |
22 | |
23 | BFA_TRC_FILE(CNA, IOC_CB); | |
24 | ||
25 | /* | |
26 | * forward declarations | |
27 | */ | |
0a20de44 KG |
28 | static bfa_boolean_t bfa_ioc_cb_firmware_lock(struct bfa_ioc_s *ioc); |
29 | static void bfa_ioc_cb_firmware_unlock(struct bfa_ioc_s *ioc); | |
0a20de44 KG |
30 | static void bfa_ioc_cb_reg_init(struct bfa_ioc_s *ioc); |
31 | static void bfa_ioc_cb_map_port(struct bfa_ioc_s *ioc); | |
32 | static void bfa_ioc_cb_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix); | |
f1d584d7 | 33 | static void bfa_ioc_cb_notify_fail(struct bfa_ioc_s *ioc); |
0a20de44 | 34 | static void bfa_ioc_cb_ownership_reset(struct bfa_ioc_s *ioc); |
45d7f0cc | 35 | static bfa_boolean_t bfa_ioc_cb_sync_start(struct bfa_ioc_s *ioc); |
f1d584d7 KG |
36 | static void bfa_ioc_cb_sync_join(struct bfa_ioc_s *ioc); |
37 | static void bfa_ioc_cb_sync_leave(struct bfa_ioc_s *ioc); | |
38 | static void bfa_ioc_cb_sync_ack(struct bfa_ioc_s *ioc); | |
39 | static bfa_boolean_t bfa_ioc_cb_sync_complete(struct bfa_ioc_s *ioc); | |
0a20de44 | 40 | |
52f94b6f | 41 | static struct bfa_ioc_hwif_s hwif_cb; |
0a20de44 | 42 | |
5fbe25c7 | 43 | /* |
0a20de44 KG |
44 | * Called from bfa_ioc_attach() to map asic specific calls. |
45 | */ | |
46 | void | |
47 | bfa_ioc_set_cb_hwif(struct bfa_ioc_s *ioc) | |
48 | { | |
293f82d5 JH |
49 | hwif_cb.ioc_pll_init = bfa_ioc_cb_pll_init; |
50 | hwif_cb.ioc_firmware_lock = bfa_ioc_cb_firmware_lock; | |
51 | hwif_cb.ioc_firmware_unlock = bfa_ioc_cb_firmware_unlock; | |
52 | hwif_cb.ioc_reg_init = bfa_ioc_cb_reg_init; | |
53 | hwif_cb.ioc_map_port = bfa_ioc_cb_map_port; | |
54 | hwif_cb.ioc_isr_mode_set = bfa_ioc_cb_isr_mode_set; | |
f1d584d7 | 55 | hwif_cb.ioc_notify_fail = bfa_ioc_cb_notify_fail; |
293f82d5 | 56 | hwif_cb.ioc_ownership_reset = bfa_ioc_cb_ownership_reset; |
45d7f0cc | 57 | hwif_cb.ioc_sync_start = bfa_ioc_cb_sync_start; |
f1d584d7 KG |
58 | hwif_cb.ioc_sync_join = bfa_ioc_cb_sync_join; |
59 | hwif_cb.ioc_sync_leave = bfa_ioc_cb_sync_leave; | |
60 | hwif_cb.ioc_sync_ack = bfa_ioc_cb_sync_ack; | |
61 | hwif_cb.ioc_sync_complete = bfa_ioc_cb_sync_complete; | |
0a20de44 | 62 | |
293f82d5 | 63 | ioc->ioc_hwif = &hwif_cb; |
0a20de44 KG |
64 | } |
65 | ||
8f4bfadd | 66 | /* |
0a20de44 KG |
67 | * Return true if firmware of current driver matches the running firmware. |
68 | */ | |
69 | static bfa_boolean_t | |
70 | bfa_ioc_cb_firmware_lock(struct bfa_ioc_s *ioc) | |
71 | { | |
72 | return BFA_TRUE; | |
73 | } | |
74 | ||
75 | static void | |
76 | bfa_ioc_cb_firmware_unlock(struct bfa_ioc_s *ioc) | |
77 | { | |
78 | } | |
79 | ||
5fbe25c7 | 80 | /* |
0a20de44 KG |
81 | * Notify other functions on HB failure. |
82 | */ | |
83 | static void | |
f1d584d7 | 84 | bfa_ioc_cb_notify_fail(struct bfa_ioc_s *ioc) |
0a20de44 | 85 | { |
11189208 | 86 | writel(~0U, ioc->ioc_regs.err_set); |
53440260 | 87 | readl(ioc->ioc_regs.err_set); |
0a20de44 KG |
88 | } |
89 | ||
5fbe25c7 | 90 | /* |
0a20de44 KG |
91 | * Host to LPU mailbox message addresses |
92 | */ | |
d1c61f8e | 93 | static struct { u32 hfn_mbox, lpu_mbox, hfn_pgn; } iocreg_fnreg[] = { |
0a20de44 KG |
94 | { HOSTFN0_LPU_MBOX0_0, LPU_HOSTFN0_MBOX0_0, HOST_PAGE_NUM_FN0 }, |
95 | { HOSTFN1_LPU_MBOX0_8, LPU_HOSTFN1_MBOX0_8, HOST_PAGE_NUM_FN1 } | |
96 | }; | |
97 | ||
5fbe25c7 | 98 | /* |
0a20de44 KG |
99 | * Host <-> LPU mailbox command/status registers |
100 | */ | |
d1c61f8e | 101 | static struct { u32 hfn, lpu; } iocreg_mbcmd[] = { |
a36c61f9 | 102 | |
0a20de44 KG |
103 | { HOSTFN0_LPU0_CMD_STAT, LPU0_HOSTFN0_CMD_STAT }, |
104 | { HOSTFN1_LPU1_CMD_STAT, LPU1_HOSTFN1_CMD_STAT } | |
105 | }; | |
106 | ||
107 | static void | |
108 | bfa_ioc_cb_reg_init(struct bfa_ioc_s *ioc) | |
109 | { | |
53440260 | 110 | void __iomem *rb; |
0a20de44 KG |
111 | int pcifn = bfa_ioc_pcifn(ioc); |
112 | ||
113 | rb = bfa_ioc_bar0(ioc); | |
114 | ||
115 | ioc->ioc_regs.hfn_mbox = rb + iocreg_fnreg[pcifn].hfn_mbox; | |
116 | ioc->ioc_regs.lpu_mbox = rb + iocreg_fnreg[pcifn].lpu_mbox; | |
117 | ioc->ioc_regs.host_page_num_fn = rb + iocreg_fnreg[pcifn].hfn_pgn; | |
118 | ||
119 | if (ioc->port_id == 0) { | |
120 | ioc->ioc_regs.heartbeat = rb + BFA_IOC0_HBEAT_REG; | |
121 | ioc->ioc_regs.ioc_fwstate = rb + BFA_IOC0_STATE_REG; | |
f1d584d7 | 122 | ioc->ioc_regs.alt_ioc_fwstate = rb + BFA_IOC1_STATE_REG; |
0a20de44 KG |
123 | } else { |
124 | ioc->ioc_regs.heartbeat = (rb + BFA_IOC1_HBEAT_REG); | |
125 | ioc->ioc_regs.ioc_fwstate = (rb + BFA_IOC1_STATE_REG); | |
f1d584d7 | 126 | ioc->ioc_regs.alt_ioc_fwstate = (rb + BFA_IOC0_STATE_REG); |
0a20de44 KG |
127 | } |
128 | ||
5fbe25c7 | 129 | /* |
0a20de44 KG |
130 | * Host <-> LPU mailbox command/status registers |
131 | */ | |
132 | ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd[pcifn].hfn; | |
133 | ioc->ioc_regs.lpu_mbox_cmd = rb + iocreg_mbcmd[pcifn].lpu; | |
134 | ||
135 | /* | |
136 | * PSS control registers | |
137 | */ | |
138 | ioc->ioc_regs.pss_ctl_reg = (rb + PSS_CTL_REG); | |
8b651b42 | 139 | ioc->ioc_regs.pss_err_status_reg = (rb + PSS_ERR_STATUS_REG); |
11189208 KG |
140 | ioc->ioc_regs.app_pll_fast_ctl_reg = (rb + APP_PLL_LCLK_CTL_REG); |
141 | ioc->ioc_regs.app_pll_slow_ctl_reg = (rb + APP_PLL_SCLK_CTL_REG); | |
0a20de44 KG |
142 | |
143 | /* | |
144 | * IOC semaphore registers and serialization | |
145 | */ | |
146 | ioc->ioc_regs.ioc_sem_reg = (rb + HOST_SEM0_REG); | |
147 | ioc->ioc_regs.ioc_init_sem_reg = (rb + HOST_SEM2_REG); | |
148 | ||
5fbe25c7 | 149 | /* |
0a20de44 KG |
150 | * sram memory access |
151 | */ | |
152 | ioc->ioc_regs.smem_page_start = (rb + PSS_SMEM_PAGE_START); | |
153 | ioc->ioc_regs.smem_pg0 = BFI_IOC_SMEM_PG0_CB; | |
154 | ||
155 | /* | |
156 | * err set reg : for notification of hb failure | |
157 | */ | |
158 | ioc->ioc_regs.err_set = (rb + ERR_SET_REG); | |
159 | } | |
160 | ||
5fbe25c7 | 161 | /* |
0a20de44 KG |
162 | * Initialize IOC to port mapping. |
163 | */ | |
a36c61f9 | 164 | |
0a20de44 KG |
165 | static void |
166 | bfa_ioc_cb_map_port(struct bfa_ioc_s *ioc) | |
167 | { | |
5fbe25c7 | 168 | /* |
0a20de44 KG |
169 | * For crossbow, port id is same as pci function. |
170 | */ | |
171 | ioc->port_id = bfa_ioc_pcifn(ioc); | |
a36c61f9 | 172 | |
0a20de44 KG |
173 | bfa_trc(ioc, ioc->port_id); |
174 | } | |
175 | ||
5fbe25c7 | 176 | /* |
0a20de44 KG |
177 | * Set interrupt mode for a function: INTX or MSIX |
178 | */ | |
179 | static void | |
180 | bfa_ioc_cb_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix) | |
181 | { | |
182 | } | |
183 | ||
45d7f0cc JH |
184 | /* |
185 | * Synchronized IOC failure processing routines | |
186 | */ | |
187 | static bfa_boolean_t | |
188 | bfa_ioc_cb_sync_start(struct bfa_ioc_s *ioc) | |
189 | { | |
190 | return bfa_ioc_cb_sync_complete(ioc); | |
191 | } | |
192 | ||
5fbe25c7 | 193 | /* |
a36c61f9 KG |
194 | * Cleanup hw semaphore and usecnt registers |
195 | */ | |
196 | static void | |
197 | bfa_ioc_cb_ownership_reset(struct bfa_ioc_s *ioc) | |
0a20de44 | 198 | { |
0a20de44 KG |
199 | |
200 | /* | |
a36c61f9 KG |
201 | * Read the hw sem reg to make sure that it is locked |
202 | * before we clear it. If it is not locked, writing 1 | |
203 | * will lock it instead of clearing it. | |
0a20de44 | 204 | */ |
53440260 | 205 | readl(ioc->ioc_regs.ioc_sem_reg); |
f7f73812 | 206 | writel(1, ioc->ioc_regs.ioc_sem_reg); |
a36c61f9 KG |
207 | } |
208 | ||
8f4bfadd | 209 | /* |
f1d584d7 KG |
210 | * Synchronized IOC failure processing routines |
211 | */ | |
212 | static void | |
213 | bfa_ioc_cb_sync_join(struct bfa_ioc_s *ioc) | |
214 | { | |
215 | } | |
216 | ||
217 | static void | |
218 | bfa_ioc_cb_sync_leave(struct bfa_ioc_s *ioc) | |
219 | { | |
220 | } | |
221 | ||
222 | static void | |
223 | bfa_ioc_cb_sync_ack(struct bfa_ioc_s *ioc) | |
224 | { | |
225 | writel(BFI_IOC_FAIL, ioc->ioc_regs.ioc_fwstate); | |
226 | } | |
227 | ||
228 | static bfa_boolean_t | |
229 | bfa_ioc_cb_sync_complete(struct bfa_ioc_s *ioc) | |
230 | { | |
231 | uint32_t fwstate, alt_fwstate; | |
232 | fwstate = readl(ioc->ioc_regs.ioc_fwstate); | |
a36c61f9 | 233 | |
8f4bfadd | 234 | /* |
f1d584d7 KG |
235 | * At this point, this IOC is hoding the hw sem in the |
236 | * start path (fwcheck) OR in the disable/enable path | |
237 | * OR to check if the other IOC has acknowledged failure. | |
238 | * | |
239 | * So, this IOC can be in UNINIT, INITING, DISABLED, FAIL | |
240 | * or in MEMTEST states. In a normal scenario, this IOC | |
241 | * can not be in OP state when this function is called. | |
242 | * | |
243 | * However, this IOC could still be in OP state when | |
244 | * the OS driver is starting up, if the OptROM code has | |
245 | * left it in that state. | |
246 | * | |
247 | * If we had marked this IOC's fwstate as BFI_IOC_FAIL | |
248 | * in the failure case and now, if the fwstate is not | |
249 | * BFI_IOC_FAIL it implies that the other PCI fn have | |
250 | * reinitialized the ASIC or this IOC got disabled, so | |
251 | * return TRUE. | |
252 | */ | |
253 | if (fwstate == BFI_IOC_UNINIT || | |
254 | fwstate == BFI_IOC_INITING || | |
255 | fwstate == BFI_IOC_DISABLED || | |
256 | fwstate == BFI_IOC_MEMTEST || | |
257 | fwstate == BFI_IOC_OP) | |
258 | return BFA_TRUE; | |
259 | else { | |
260 | alt_fwstate = readl(ioc->ioc_regs.alt_ioc_fwstate); | |
261 | if (alt_fwstate == BFI_IOC_FAIL || | |
262 | alt_fwstate == BFI_IOC_DISABLED || | |
263 | alt_fwstate == BFI_IOC_UNINIT || | |
264 | alt_fwstate == BFI_IOC_INITING || | |
265 | alt_fwstate == BFI_IOC_MEMTEST) | |
266 | return BFA_TRUE; | |
267 | else | |
268 | return BFA_FALSE; | |
269 | } | |
270 | } | |
a36c61f9 KG |
271 | |
272 | bfa_status_t | |
11189208 | 273 | bfa_ioc_cb_pll_init(void __iomem *rb, enum bfi_asic_mode fcmode) |
a36c61f9 KG |
274 | { |
275 | u32 pll_sclk, pll_fclk; | |
0a20de44 | 276 | |
11189208 KG |
277 | pll_sclk = __APP_PLL_SCLK_ENABLE | __APP_PLL_SCLK_LRESETN | |
278 | __APP_PLL_SCLK_P0_1(3U) | | |
279 | __APP_PLL_SCLK_JITLMT0_1(3U) | | |
280 | __APP_PLL_SCLK_CNTLMT0_1(3U); | |
281 | pll_fclk = __APP_PLL_LCLK_ENABLE | __APP_PLL_LCLK_LRESETN | | |
282 | __APP_PLL_LCLK_RSEL200500 | __APP_PLL_LCLK_P0_1(3U) | | |
283 | __APP_PLL_LCLK_JITLMT0_1(3U) | | |
284 | __APP_PLL_LCLK_CNTLMT0_1(3U); | |
53440260 JH |
285 | writel(BFI_IOC_UNINIT, (rb + BFA_IOC0_STATE_REG)); |
286 | writel(BFI_IOC_UNINIT, (rb + BFA_IOC1_STATE_REG)); | |
287 | writel(0xffffffffU, (rb + HOSTFN0_INT_MSK)); | |
288 | writel(0xffffffffU, (rb + HOSTFN1_INT_MSK)); | |
289 | writel(0xffffffffU, (rb + HOSTFN0_INT_STATUS)); | |
290 | writel(0xffffffffU, (rb + HOSTFN1_INT_STATUS)); | |
291 | writel(0xffffffffU, (rb + HOSTFN0_INT_MSK)); | |
292 | writel(0xffffffffU, (rb + HOSTFN1_INT_MSK)); | |
11189208 KG |
293 | writel(__APP_PLL_SCLK_LOGIC_SOFT_RESET, rb + APP_PLL_SCLK_CTL_REG); |
294 | writel(__APP_PLL_SCLK_BYPASS | __APP_PLL_SCLK_LOGIC_SOFT_RESET, | |
295 | rb + APP_PLL_SCLK_CTL_REG); | |
296 | writel(__APP_PLL_LCLK_LOGIC_SOFT_RESET, rb + APP_PLL_LCLK_CTL_REG); | |
297 | writel(__APP_PLL_LCLK_BYPASS | __APP_PLL_LCLK_LOGIC_SOFT_RESET, | |
298 | rb + APP_PLL_LCLK_CTL_REG); | |
6a18b167 | 299 | udelay(2); |
11189208 KG |
300 | writel(__APP_PLL_SCLK_LOGIC_SOFT_RESET, rb + APP_PLL_SCLK_CTL_REG); |
301 | writel(__APP_PLL_LCLK_LOGIC_SOFT_RESET, rb + APP_PLL_LCLK_CTL_REG); | |
302 | writel(pll_sclk | __APP_PLL_SCLK_LOGIC_SOFT_RESET, | |
303 | rb + APP_PLL_SCLK_CTL_REG); | |
304 | writel(pll_fclk | __APP_PLL_LCLK_LOGIC_SOFT_RESET, | |
305 | rb + APP_PLL_LCLK_CTL_REG); | |
6a18b167 | 306 | udelay(2000); |
53440260 JH |
307 | writel(0xffffffffU, (rb + HOSTFN0_INT_STATUS)); |
308 | writel(0xffffffffU, (rb + HOSTFN1_INT_STATUS)); | |
11189208 KG |
309 | writel(pll_sclk, (rb + APP_PLL_SCLK_CTL_REG)); |
310 | writel(pll_fclk, (rb + APP_PLL_LCLK_CTL_REG)); | |
0a20de44 KG |
311 | |
312 | return BFA_STATUS_OK; | |
313 | } |