diff options
Diffstat (limited to 'drivers/scsi/bfa/bfa_ioc_cb.c')
-rw-r--r-- | drivers/scsi/bfa/bfa_ioc_cb.c | 274 |
1 files changed, 274 insertions, 0 deletions
diff --git a/drivers/scsi/bfa/bfa_ioc_cb.c b/drivers/scsi/bfa/bfa_ioc_cb.c new file mode 100644 index 000000000000..3ce85319f739 --- /dev/null +++ b/drivers/scsi/bfa/bfa_ioc_cb.c | |||
@@ -0,0 +1,274 @@ | |||
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_cbreg.h> | ||
25 | #include <log/bfa_log_hal.h> | ||
26 | #include <defs/bfa_defs_pci.h> | ||
27 | |||
28 | BFA_TRC_FILE(CNA, IOC_CB); | ||
29 | |||
30 | /* | ||
31 | * forward declarations | ||
32 | */ | ||
33 | static bfa_status_t bfa_ioc_cb_pll_init(struct bfa_ioc_s *ioc); | ||
34 | static bfa_boolean_t bfa_ioc_cb_firmware_lock(struct bfa_ioc_s *ioc); | ||
35 | static void bfa_ioc_cb_firmware_unlock(struct bfa_ioc_s *ioc); | ||
36 | static u32 *bfa_ioc_cb_fwimg_get_chunk(struct bfa_ioc_s *ioc, u32 off); | ||
37 | static u32 bfa_ioc_cb_fwimg_get_size(struct bfa_ioc_s *ioc); | ||
38 | static void bfa_ioc_cb_reg_init(struct bfa_ioc_s *ioc); | ||
39 | static void bfa_ioc_cb_map_port(struct bfa_ioc_s *ioc); | ||
40 | static void bfa_ioc_cb_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix); | ||
41 | static void bfa_ioc_cb_notify_hbfail(struct bfa_ioc_s *ioc); | ||
42 | static void bfa_ioc_cb_ownership_reset(struct bfa_ioc_s *ioc); | ||
43 | |||
44 | struct bfa_ioc_hwif_s hwif_cb = { | ||
45 | bfa_ioc_cb_pll_init, | ||
46 | bfa_ioc_cb_firmware_lock, | ||
47 | bfa_ioc_cb_firmware_unlock, | ||
48 | bfa_ioc_cb_fwimg_get_chunk, | ||
49 | bfa_ioc_cb_fwimg_get_size, | ||
50 | bfa_ioc_cb_reg_init, | ||
51 | bfa_ioc_cb_map_port, | ||
52 | bfa_ioc_cb_isr_mode_set, | ||
53 | bfa_ioc_cb_notify_hbfail, | ||
54 | bfa_ioc_cb_ownership_reset, | ||
55 | }; | ||
56 | |||
57 | /** | ||
58 | * Called from bfa_ioc_attach() to map asic specific calls. | ||
59 | */ | ||
60 | void | ||
61 | bfa_ioc_set_cb_hwif(struct bfa_ioc_s *ioc) | ||
62 | { | ||
63 | ioc->ioc_hwif = &hwif_cb; | ||
64 | } | ||
65 | |||
66 | static u32 * | ||
67 | bfa_ioc_cb_fwimg_get_chunk(struct bfa_ioc_s *ioc, u32 off) | ||
68 | { | ||
69 | return bfi_image_cb_get_chunk(off); | ||
70 | } | ||
71 | |||
72 | static u32 | ||
73 | bfa_ioc_cb_fwimg_get_size(struct bfa_ioc_s *ioc) | ||
74 | { | ||
75 | return bfi_image_cb_size; | ||
76 | } | ||
77 | |||
78 | /** | ||
79 | * Return true if firmware of current driver matches the running firmware. | ||
80 | */ | ||
81 | static bfa_boolean_t | ||
82 | bfa_ioc_cb_firmware_lock(struct bfa_ioc_s *ioc) | ||
83 | { | ||
84 | return BFA_TRUE; | ||
85 | } | ||
86 | |||
87 | static void | ||
88 | bfa_ioc_cb_firmware_unlock(struct bfa_ioc_s *ioc) | ||
89 | { | ||
90 | } | ||
91 | |||
92 | /** | ||
93 | * Notify other functions on HB failure. | ||
94 | */ | ||
95 | static void | ||
96 | bfa_ioc_cb_notify_hbfail(struct bfa_ioc_s *ioc) | ||
97 | { | ||
98 | bfa_reg_write(ioc->ioc_regs.err_set, __PSS_ERR_STATUS_SET); | ||
99 | bfa_reg_read(ioc->ioc_regs.err_set); | ||
100 | } | ||
101 | |||
102 | /** | ||
103 | * Host to LPU mailbox message addresses | ||
104 | */ | ||
105 | static struct { u32 hfn_mbox, lpu_mbox, hfn_pgn; } iocreg_fnreg[] = { | ||
106 | { HOSTFN0_LPU_MBOX0_0, LPU_HOSTFN0_MBOX0_0, HOST_PAGE_NUM_FN0 }, | ||
107 | { HOSTFN1_LPU_MBOX0_8, LPU_HOSTFN1_MBOX0_8, HOST_PAGE_NUM_FN1 } | ||
108 | }; | ||
109 | |||
110 | /** | ||
111 | * Host <-> LPU mailbox command/status registers | ||
112 | */ | ||
113 | static struct { u32 hfn, lpu; } iocreg_mbcmd[] = { | ||
114 | { HOSTFN0_LPU0_CMD_STAT, LPU0_HOSTFN0_CMD_STAT }, | ||
115 | { HOSTFN1_LPU1_CMD_STAT, LPU1_HOSTFN1_CMD_STAT } | ||
116 | }; | ||
117 | |||
118 | static void | ||
119 | bfa_ioc_cb_reg_init(struct bfa_ioc_s *ioc) | ||
120 | { | ||
121 | bfa_os_addr_t rb; | ||
122 | int pcifn = bfa_ioc_pcifn(ioc); | ||
123 | |||
124 | rb = bfa_ioc_bar0(ioc); | ||
125 | |||
126 | ioc->ioc_regs.hfn_mbox = rb + iocreg_fnreg[pcifn].hfn_mbox; | ||
127 | ioc->ioc_regs.lpu_mbox = rb + iocreg_fnreg[pcifn].lpu_mbox; | ||
128 | ioc->ioc_regs.host_page_num_fn = rb + iocreg_fnreg[pcifn].hfn_pgn; | ||
129 | |||
130 | if (ioc->port_id == 0) { | ||
131 | ioc->ioc_regs.heartbeat = rb + BFA_IOC0_HBEAT_REG; | ||
132 | ioc->ioc_regs.ioc_fwstate = rb + BFA_IOC0_STATE_REG; | ||
133 | } else { | ||
134 | ioc->ioc_regs.heartbeat = (rb + BFA_IOC1_HBEAT_REG); | ||
135 | ioc->ioc_regs.ioc_fwstate = (rb + BFA_IOC1_STATE_REG); | ||
136 | } | ||
137 | |||
138 | /** | ||
139 | * Host <-> LPU mailbox command/status registers | ||
140 | */ | ||
141 | ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd[pcifn].hfn; | ||
142 | ioc->ioc_regs.lpu_mbox_cmd = rb + iocreg_mbcmd[pcifn].lpu; | ||
143 | |||
144 | /* | ||
145 | * PSS control registers | ||
146 | */ | ||
147 | ioc->ioc_regs.pss_ctl_reg = (rb + PSS_CTL_REG); | ||
148 | ioc->ioc_regs.pss_err_status_reg = (rb + PSS_ERR_STATUS_REG); | ||
149 | ioc->ioc_regs.app_pll_fast_ctl_reg = (rb + APP_PLL_400_CTL_REG); | ||
150 | ioc->ioc_regs.app_pll_slow_ctl_reg = (rb + APP_PLL_212_CTL_REG); | ||
151 | |||
152 | /* | ||
153 | * IOC semaphore registers and serialization | ||
154 | */ | ||
155 | ioc->ioc_regs.ioc_sem_reg = (rb + HOST_SEM0_REG); | ||
156 | ioc->ioc_regs.ioc_init_sem_reg = (rb + HOST_SEM2_REG); | ||
157 | |||
158 | /** | ||
159 | * sram memory access | ||
160 | */ | ||
161 | ioc->ioc_regs.smem_page_start = (rb + PSS_SMEM_PAGE_START); | ||
162 | ioc->ioc_regs.smem_pg0 = BFI_IOC_SMEM_PG0_CB; | ||
163 | |||
164 | /* | ||
165 | * err set reg : for notification of hb failure | ||
166 | */ | ||
167 | ioc->ioc_regs.err_set = (rb + ERR_SET_REG); | ||
168 | } | ||
169 | |||
170 | /** | ||
171 | * Initialize IOC to port mapping. | ||
172 | */ | ||
173 | static void | ||
174 | bfa_ioc_cb_map_port(struct bfa_ioc_s *ioc) | ||
175 | { | ||
176 | /** | ||
177 | * For crossbow, port id is same as pci function. | ||
178 | */ | ||
179 | ioc->port_id = bfa_ioc_pcifn(ioc); | ||
180 | bfa_trc(ioc, ioc->port_id); | ||
181 | } | ||
182 | |||
183 | /** | ||
184 | * Set interrupt mode for a function: INTX or MSIX | ||
185 | */ | ||
186 | static void | ||
187 | bfa_ioc_cb_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix) | ||
188 | { | ||
189 | } | ||
190 | |||
191 | static bfa_status_t | ||
192 | bfa_ioc_cb_pll_init(struct bfa_ioc_s *ioc) | ||
193 | { | ||
194 | bfa_os_addr_t rb = ioc->pcidev.pci_bar_kva; | ||
195 | u32 pll_sclk, pll_fclk; | ||
196 | |||
197 | /* | ||
198 | * Hold semaphore so that nobody can access the chip during init. | ||
199 | */ | ||
200 | bfa_ioc_sem_get(ioc->ioc_regs.ioc_init_sem_reg); | ||
201 | |||
202 | pll_sclk = __APP_PLL_212_ENABLE | __APP_PLL_212_LRESETN | | ||
203 | __APP_PLL_212_P0_1(3U) | | ||
204 | __APP_PLL_212_JITLMT0_1(3U) | | ||
205 | __APP_PLL_212_CNTLMT0_1(3U); | ||
206 | pll_fclk = __APP_PLL_400_ENABLE | __APP_PLL_400_LRESETN | | ||
207 | __APP_PLL_400_RSEL200500 | __APP_PLL_400_P0_1(3U) | | ||
208 | __APP_PLL_400_JITLMT0_1(3U) | | ||
209 | __APP_PLL_400_CNTLMT0_1(3U); | ||
210 | |||
211 | bfa_reg_write((rb + BFA_IOC0_STATE_REG), BFI_IOC_UNINIT); | ||
212 | bfa_reg_write((rb + BFA_IOC1_STATE_REG), BFI_IOC_UNINIT); | ||
213 | |||
214 | bfa_reg_write((rb + HOSTFN0_INT_MSK), 0xffffffffU); | ||
215 | bfa_reg_write((rb + HOSTFN1_INT_MSK), 0xffffffffU); | ||
216 | bfa_reg_write((rb + HOSTFN0_INT_STATUS), 0xffffffffU); | ||
217 | bfa_reg_write((rb + HOSTFN1_INT_STATUS), 0xffffffffU); | ||
218 | bfa_reg_write((rb + HOSTFN0_INT_MSK), 0xffffffffU); | ||
219 | bfa_reg_write((rb + HOSTFN1_INT_MSK), 0xffffffffU); | ||
220 | |||
221 | bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg, | ||
222 | __APP_PLL_212_LOGIC_SOFT_RESET); | ||
223 | bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg, | ||
224 | __APP_PLL_212_BYPASS | | ||
225 | __APP_PLL_212_LOGIC_SOFT_RESET); | ||
226 | bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg, | ||
227 | __APP_PLL_400_LOGIC_SOFT_RESET); | ||
228 | bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg, | ||
229 | __APP_PLL_400_BYPASS | | ||
230 | __APP_PLL_400_LOGIC_SOFT_RESET); | ||
231 | bfa_os_udelay(2); | ||
232 | bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg, | ||
233 | __APP_PLL_212_LOGIC_SOFT_RESET); | ||
234 | bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg, | ||
235 | __APP_PLL_400_LOGIC_SOFT_RESET); | ||
236 | |||
237 | bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg, | ||
238 | pll_sclk | __APP_PLL_212_LOGIC_SOFT_RESET); | ||
239 | bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg, | ||
240 | pll_fclk | __APP_PLL_400_LOGIC_SOFT_RESET); | ||
241 | |||
242 | /** | ||
243 | * Wait for PLLs to lock. | ||
244 | */ | ||
245 | bfa_os_udelay(2000); | ||
246 | bfa_reg_write((rb + HOSTFN0_INT_STATUS), 0xffffffffU); | ||
247 | bfa_reg_write((rb + HOSTFN1_INT_STATUS), 0xffffffffU); | ||
248 | |||
249 | bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg, pll_sclk); | ||
250 | bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg, pll_fclk); | ||
251 | |||
252 | /* | ||
253 | * release semaphore. | ||
254 | */ | ||
255 | bfa_ioc_sem_release(ioc->ioc_regs.ioc_init_sem_reg); | ||
256 | |||
257 | return BFA_STATUS_OK; | ||
258 | } | ||
259 | |||
260 | /** | ||
261 | * Cleanup hw semaphore and usecnt registers | ||
262 | */ | ||
263 | static void | ||
264 | bfa_ioc_cb_ownership_reset(struct bfa_ioc_s *ioc) | ||
265 | { | ||
266 | |||
267 | /* | ||
268 | * Read the hw sem reg to make sure that it is locked | ||
269 | * before we clear it. If it is not locked, writing 1 | ||
270 | * will lock it instead of clearing it. | ||
271 | */ | ||
272 | bfa_reg_read(ioc->ioc_regs.ioc_sem_reg); | ||
273 | bfa_ioc_hw_sem_release(ioc); | ||
274 | } | ||