diff options
Diffstat (limited to 'drivers/scsi/bfa/bfa_ioc_ct.c')
-rw-r--r-- | drivers/scsi/bfa/bfa_ioc_ct.c | 422 |
1 files changed, 422 insertions, 0 deletions
diff --git a/drivers/scsi/bfa/bfa_ioc_ct.c b/drivers/scsi/bfa/bfa_ioc_ct.c new file mode 100644 index 000000000000..5de9c24efacf --- /dev/null +++ b/drivers/scsi/bfa/bfa_ioc_ct.c | |||
@@ -0,0 +1,422 @@ | |||
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 | } | ||