1*d14abf15SRobert Mustacchi /*******************************************************************************
2*d14abf15SRobert Mustacchi * CDDL HEADER START
3*d14abf15SRobert Mustacchi *
4*d14abf15SRobert Mustacchi * The contents of this file are subject to the terms of the
5*d14abf15SRobert Mustacchi * Common Development and Distribution License (the "License").
6*d14abf15SRobert Mustacchi * You may not use this file except in compliance with the License.
7*d14abf15SRobert Mustacchi *
8*d14abf15SRobert Mustacchi * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*d14abf15SRobert Mustacchi * or http://www.opensolaris.org/os/licensing.
10*d14abf15SRobert Mustacchi * See the License for the specific language governing permissions
11*d14abf15SRobert Mustacchi * and limitations under the License.
12*d14abf15SRobert Mustacchi *
13*d14abf15SRobert Mustacchi * When distributing Covered Code, include this CDDL HEADER in each
14*d14abf15SRobert Mustacchi * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*d14abf15SRobert Mustacchi * If applicable, add the following below this CDDL HEADER, with the
16*d14abf15SRobert Mustacchi * fields enclosed by brackets "[]" replaced with your own identifying
17*d14abf15SRobert Mustacchi * information: Portions Copyright [yyyy] [name of copyright owner]
18*d14abf15SRobert Mustacchi *
19*d14abf15SRobert Mustacchi * CDDL HEADER END
20*d14abf15SRobert Mustacchi *
21*d14abf15SRobert Mustacchi * Copyright 2014 QLogic Corporation
22*d14abf15SRobert Mustacchi * The contents of this file are subject to the terms of the
23*d14abf15SRobert Mustacchi * QLogic End User License (the "License").
24*d14abf15SRobert Mustacchi * You may not use this file except in compliance with the License.
25*d14abf15SRobert Mustacchi *
26*d14abf15SRobert Mustacchi * You can obtain a copy of the License at
27*d14abf15SRobert Mustacchi * http://www.qlogic.com/Resources/Documents/DriverDownloadHelp/
28*d14abf15SRobert Mustacchi * QLogic_End_User_Software_License.txt
29*d14abf15SRobert Mustacchi * See the License for the specific language governing permissions
30*d14abf15SRobert Mustacchi * and limitations under the License.
31*d14abf15SRobert Mustacchi *
32*d14abf15SRobert Mustacchi *
33*d14abf15SRobert Mustacchi * Module Description:
34*d14abf15SRobert Mustacchi *
35*d14abf15SRobert Mustacchi *
36*d14abf15SRobert Mustacchi * History:
37*d14abf15SRobert Mustacchi * 11/26/07 Alon Elhanani Inception.
38*d14abf15SRobert Mustacchi ******************************************************************************/
39*d14abf15SRobert Mustacchi
40*d14abf15SRobert Mustacchi #include "lm5710.h"
41*d14abf15SRobert Mustacchi #include "license.h"
42*d14abf15SRobert Mustacchi #include "mcp_shmem.h"
43*d14abf15SRobert Mustacchi #include "debug.h"
44*d14abf15SRobert Mustacchi
45*d14abf15SRobert Mustacchi #define MCP_EMUL_TIMEOUT 200000 /* 200 ms (in us) */
46*d14abf15SRobert Mustacchi #define MCP_TIMEOUT 5000000 /* 5 seconds (in us) */
47*d14abf15SRobert Mustacchi #define MCP_ONE_TIMEOUT 100000 /* 100 ms (in us) */
48*d14abf15SRobert Mustacchi
49*d14abf15SRobert Mustacchi /**
50*d14abf15SRobert Mustacchi * Waits for MCP_ONE_TIMEOUT or MCP_ONE_TIMEOUT*10,
51*d14abf15SRobert Mustacchi * depending on the HW type.
52*d14abf15SRobert Mustacchi *
53*d14abf15SRobert Mustacchi * @param pdev
54*d14abf15SRobert Mustacchi */
lm_mcp_wait_one(IN struct _lm_device_t * pdev)55*d14abf15SRobert Mustacchi static __inline void lm_mcp_wait_one (
56*d14abf15SRobert Mustacchi IN struct _lm_device_t * pdev
57*d14abf15SRobert Mustacchi )
58*d14abf15SRobert Mustacchi {
59*d14abf15SRobert Mustacchi /* special handling for emulation and FPGA,
60*d14abf15SRobert Mustacchi wait 10 times longer */
61*d14abf15SRobert Mustacchi if (CHIP_REV_IS_SLOW(pdev)) {
62*d14abf15SRobert Mustacchi mm_wait(pdev, MCP_ONE_TIMEOUT*10);
63*d14abf15SRobert Mustacchi } else {
64*d14abf15SRobert Mustacchi mm_wait(pdev, MCP_ONE_TIMEOUT);
65*d14abf15SRobert Mustacchi }
66*d14abf15SRobert Mustacchi }
67*d14abf15SRobert Mustacchi
68*d14abf15SRobert Mustacchi
69*d14abf15SRobert Mustacchi #if !defined(b710)
70*d14abf15SRobert Mustacchi
71*d14abf15SRobert Mustacchi /**
72*d14abf15SRobert Mustacchi * Prepare CLP to MCP reset.
73*d14abf15SRobert Mustacchi *
74*d14abf15SRobert Mustacchi * @param pdev Device handle
75*d14abf15SRobert Mustacchi * @param magic_val Old value of `magic' bit.
76*d14abf15SRobert Mustacchi */
lm_clp_reset_prep(IN struct _lm_device_t * pdev,OUT u32_t * magic_val)77*d14abf15SRobert Mustacchi void lm_clp_reset_prep(
78*d14abf15SRobert Mustacchi IN struct _lm_device_t * pdev,
79*d14abf15SRobert Mustacchi OUT u32_t * magic_val
80*d14abf15SRobert Mustacchi )
81*d14abf15SRobert Mustacchi {
82*d14abf15SRobert Mustacchi u32_t val = 0;
83*d14abf15SRobert Mustacchi u32_t offset;
84*d14abf15SRobert Mustacchi
85*d14abf15SRobert Mustacchi #define SHARED_MF_CLP_MAGIC 0x80000000 /* `magic' bit */
86*d14abf15SRobert Mustacchi
87*d14abf15SRobert Mustacchi ASSERT_STATIC(sizeof(struct mf_cfg) % sizeof(u32_t) == 0);
88*d14abf15SRobert Mustacchi
89*d14abf15SRobert Mustacchi /* Do some magic... */
90*d14abf15SRobert Mustacchi offset = OFFSETOF(mf_cfg_t, shared_mf_config.clp_mb);
91*d14abf15SRobert Mustacchi LM_MFCFG_READ(pdev, offset, &val);
92*d14abf15SRobert Mustacchi *magic_val = val & SHARED_MF_CLP_MAGIC;
93*d14abf15SRobert Mustacchi LM_MFCFG_WRITE(pdev, offset, val | SHARED_MF_CLP_MAGIC);
94*d14abf15SRobert Mustacchi }
95*d14abf15SRobert Mustacchi
96*d14abf15SRobert Mustacchi /**
97*d14abf15SRobert Mustacchi * Restore the value of the `magic' bit.
98*d14abf15SRobert Mustacchi *
99*d14abf15SRobert Mustacchi * @param pdev Device handle.
100*d14abf15SRobert Mustacchi * @param magic_val Old value of the `magic' bit.
101*d14abf15SRobert Mustacchi */
lm_clp_reset_done(IN struct _lm_device_t * pdev,IN u32_t magic_val)102*d14abf15SRobert Mustacchi void lm_clp_reset_done(
103*d14abf15SRobert Mustacchi IN struct _lm_device_t * pdev,
104*d14abf15SRobert Mustacchi IN u32_t magic_val
105*d14abf15SRobert Mustacchi )
106*d14abf15SRobert Mustacchi {
107*d14abf15SRobert Mustacchi u32_t val = 0;
108*d14abf15SRobert Mustacchi u32_t offset;
109*d14abf15SRobert Mustacchi
110*d14abf15SRobert Mustacchi /* Restore the `magic' bit value... */
111*d14abf15SRobert Mustacchi offset = OFFSETOF(mf_cfg_t, shared_mf_config.clp_mb);
112*d14abf15SRobert Mustacchi LM_MFCFG_READ(pdev, offset, &val);
113*d14abf15SRobert Mustacchi LM_MFCFG_WRITE(pdev, offset, (val & (~SHARED_MF_CLP_MAGIC)) | magic_val);
114*d14abf15SRobert Mustacchi }
115*d14abf15SRobert Mustacchi
116*d14abf15SRobert Mustacchi #endif // !b710
117*d14abf15SRobert Mustacchi
lm_is_mcp_detected(IN struct _lm_device_t * pdev)118*d14abf15SRobert Mustacchi u8_t lm_is_mcp_detected(
119*d14abf15SRobert Mustacchi IN struct _lm_device_t *pdev
120*d14abf15SRobert Mustacchi )
121*d14abf15SRobert Mustacchi {
122*d14abf15SRobert Mustacchi return pdev->hw_info.mcp_detected;
123*d14abf15SRobert Mustacchi }
124*d14abf15SRobert Mustacchi
125*d14abf15SRobert Mustacchi /**
126*d14abf15SRobert Mustacchi * @Description
127*d14abf15SRobert Mustacchi * Prepares for MCP reset: takes care of CLP configurations
128*d14abf15SRobert Mustacchi * (saves it aside to resotre later) .
129*d14abf15SRobert Mustacchi *
130*d14abf15SRobert Mustacchi * @param pdev
131*d14abf15SRobert Mustacchi * @param magic_val Old value of 'magic' bit.
132*d14abf15SRobert Mustacchi */
lm_reset_mcp_prep(lm_device_t * pdev,u32_t * magic_val)133*d14abf15SRobert Mustacchi lm_status_t lm_reset_mcp_prep(lm_device_t *pdev, u32_t * magic_val)
134*d14abf15SRobert Mustacchi {
135*d14abf15SRobert Mustacchi u32_t shmem;
136*d14abf15SRobert Mustacchi u32_t validity_offset;
137*d14abf15SRobert Mustacchi
138*d14abf15SRobert Mustacchi /* Set `magic' bit in order to save MF config */
139*d14abf15SRobert Mustacchi if (!CHIP_IS_E1(pdev))
140*d14abf15SRobert Mustacchi {
141*d14abf15SRobert Mustacchi lm_clp_reset_prep(pdev, magic_val);
142*d14abf15SRobert Mustacchi }
143*d14abf15SRobert Mustacchi
144*d14abf15SRobert Mustacchi /* Get shmem offset */
145*d14abf15SRobert Mustacchi shmem = REG_RD(pdev, MISC_REG_SHARED_MEM_ADDR);
146*d14abf15SRobert Mustacchi validity_offset = OFFSETOF(shmem_region_t, validity_map[0]);
147*d14abf15SRobert Mustacchi
148*d14abf15SRobert Mustacchi /* Clear validity map flags */
149*d14abf15SRobert Mustacchi if( shmem > 0 )
150*d14abf15SRobert Mustacchi {
151*d14abf15SRobert Mustacchi REG_WR(pdev, shmem + validity_offset, 0);
152*d14abf15SRobert Mustacchi }
153*d14abf15SRobert Mustacchi
154*d14abf15SRobert Mustacchi return LM_STATUS_SUCCESS;
155*d14abf15SRobert Mustacchi }
156*d14abf15SRobert Mustacchi
lm_reset_mcp_comp(lm_device_t * pdev,u32_t magic_val)157*d14abf15SRobert Mustacchi lm_status_t lm_reset_mcp_comp(lm_device_t *pdev, u32_t magic_val)
158*d14abf15SRobert Mustacchi {
159*d14abf15SRobert Mustacchi lm_status_t lm_status = LM_STATUS_SUCCESS;
160*d14abf15SRobert Mustacchi u32_t shmem_sig_timeout = 0;
161*d14abf15SRobert Mustacchi u32_t validity_offset = 0;
162*d14abf15SRobert Mustacchi u32_t shmem = 0;
163*d14abf15SRobert Mustacchi u32_t val = 0;
164*d14abf15SRobert Mustacchi u32_t cnt = 0;
165*d14abf15SRobert Mustacchi
166*d14abf15SRobert Mustacchi #ifdef _VBD_CMD_
167*d14abf15SRobert Mustacchi return LM_STATUS_SUCCESS;
168*d14abf15SRobert Mustacchi #endif
169*d14abf15SRobert Mustacchi
170*d14abf15SRobert Mustacchi /* Get shmem offset */
171*d14abf15SRobert Mustacchi shmem = REG_RD(pdev, MISC_REG_SHARED_MEM_ADDR);
172*d14abf15SRobert Mustacchi if( shmem == 0 ) {
173*d14abf15SRobert Mustacchi DbgMessage(pdev, FATAL, "Shmem 0 return failure\n");
174*d14abf15SRobert Mustacchi lm_status = LM_STATUS_FAILURE;
175*d14abf15SRobert Mustacchi goto exit_lbl;
176*d14abf15SRobert Mustacchi }
177*d14abf15SRobert Mustacchi
178*d14abf15SRobert Mustacchi ASSERT_STATIC(0 != MCP_ONE_TIMEOUT);
179*d14abf15SRobert Mustacchi
180*d14abf15SRobert Mustacchi if (CHIP_REV_IS_EMUL(pdev))
181*d14abf15SRobert Mustacchi shmem_sig_timeout = MCP_EMUL_TIMEOUT / MCP_ONE_TIMEOUT; // 200ms
182*d14abf15SRobert Mustacchi else
183*d14abf15SRobert Mustacchi shmem_sig_timeout = MCP_TIMEOUT / MCP_ONE_TIMEOUT; // 5sec
184*d14abf15SRobert Mustacchi
185*d14abf15SRobert Mustacchi validity_offset = OFFSETOF(shmem_region_t, validity_map[0]);
186*d14abf15SRobert Mustacchi
187*d14abf15SRobert Mustacchi /* Wait for MCP to come up */
188*d14abf15SRobert Mustacchi for(cnt = 0; cnt < shmem_sig_timeout; cnt++)
189*d14abf15SRobert Mustacchi {
190*d14abf15SRobert Mustacchi /* TBD: its best to check validity map of last port. currently checks on port 0. */
191*d14abf15SRobert Mustacchi val = REG_RD(pdev, shmem + validity_offset);
192*d14abf15SRobert Mustacchi DbgMessage(pdev, INFORM, "shmem 0x%x validity map(0x%x)=0x%x\n", shmem, shmem + validity_offset, val);
193*d14abf15SRobert Mustacchi
194*d14abf15SRobert Mustacchi /* check that shared memory is valid. */
195*d14abf15SRobert Mustacchi if((val & (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB)) ==
196*d14abf15SRobert Mustacchi (SHR_MEM_VALIDITY_DEV_INFO|SHR_MEM_VALIDITY_MB)) {
197*d14abf15SRobert Mustacchi break;
198*d14abf15SRobert Mustacchi }
199*d14abf15SRobert Mustacchi
200*d14abf15SRobert Mustacchi lm_mcp_wait_one(pdev);
201*d14abf15SRobert Mustacchi }
202*d14abf15SRobert Mustacchi
203*d14abf15SRobert Mustacchi DbgMessage(pdev, INFORM , "Cnt=%d Shmem validity map 0x%x\n",cnt, val);
204*d14abf15SRobert Mustacchi
205*d14abf15SRobert Mustacchi /* Check that shared memory is valid. This indicates that MCP is up. */
206*d14abf15SRobert Mustacchi if((val & (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB)) !=
207*d14abf15SRobert Mustacchi (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB))
208*d14abf15SRobert Mustacchi {
209*d14abf15SRobert Mustacchi DbgMessage(pdev, FATAL, "Shmem signature not present. MCP is not up !!\n");
210*d14abf15SRobert Mustacchi lm_status = LM_STATUS_FAILURE;
211*d14abf15SRobert Mustacchi goto exit_lbl;
212*d14abf15SRobert Mustacchi }
213*d14abf15SRobert Mustacchi
214*d14abf15SRobert Mustacchi exit_lbl:
215*d14abf15SRobert Mustacchi
216*d14abf15SRobert Mustacchi if (!CHIP_IS_E1(pdev))
217*d14abf15SRobert Mustacchi {
218*d14abf15SRobert Mustacchi /* Restore `magic' bit value */
219*d14abf15SRobert Mustacchi lm_clp_reset_done(pdev, magic_val);
220*d14abf15SRobert Mustacchi }
221*d14abf15SRobert Mustacchi
222*d14abf15SRobert Mustacchi return lm_status;
223*d14abf15SRobert Mustacchi }
224*d14abf15SRobert Mustacchi
lm_reset_mcp(IN struct _lm_device_t * pdev)225*d14abf15SRobert Mustacchi lm_status_t lm_reset_mcp(
226*d14abf15SRobert Mustacchi IN struct _lm_device_t *pdev
227*d14abf15SRobert Mustacchi )
228*d14abf15SRobert Mustacchi {
229*d14abf15SRobert Mustacchi
230*d14abf15SRobert Mustacchi u32_t magic_val = 0;
231*d14abf15SRobert Mustacchi u32_t val, retries=0;
232*d14abf15SRobert Mustacchi lm_status_t lm_status = LM_STATUS_SUCCESS;
233*d14abf15SRobert Mustacchi
234*d14abf15SRobert Mustacchi DbgMessage(pdev, VERBOSE, "Entered lm_reset_mcp\n");
235*d14abf15SRobert Mustacchi
236*d14abf15SRobert Mustacchi lm_reset_mcp_prep(pdev, &magic_val);
237*d14abf15SRobert Mustacchi
238*d14abf15SRobert Mustacchi /* wait up to 3 seconds to get all locks. Whatsoever, reset mcp afterwards */
239*d14abf15SRobert Mustacchi do {
240*d14abf15SRobert Mustacchi REG_WR(pdev, MISC_REG_DRIVER_CONTROL_15 + 4, 0xffffffff);
241*d14abf15SRobert Mustacchi val = REG_RD(pdev, MISC_REG_DRIVER_CONTROL_15);
242*d14abf15SRobert Mustacchi mm_wait(pdev, 1);
243*d14abf15SRobert Mustacchi } while ((val != 0xffffffff) && (++retries < 3000000));
244*d14abf15SRobert Mustacchi
245*d14abf15SRobert Mustacchi /* Reset the MCP */
246*d14abf15SRobert Mustacchi REG_WR(pdev, GRCBASE_MISC+ MISC_REGISTERS_RESET_REG_2_CLEAR,
247*d14abf15SRobert Mustacchi MISC_REGISTERS_RESET_REG_2_RST_MCP_N_RESET_REG_HARD_CORE |
248*d14abf15SRobert Mustacchi MISC_REGISTERS_RESET_REG_2_RST_MCP_N_HARD_CORE_RST_B |
249*d14abf15SRobert Mustacchi MISC_REGISTERS_RESET_REG_2_RST_MCP_N_RESET_CMN_CPU |
250*d14abf15SRobert Mustacchi MISC_REGISTERS_RESET_REG_2_RST_MCP_N_RESET_CMN_CORE);
251*d14abf15SRobert Mustacchi
252*d14abf15SRobert Mustacchi /* release the locks taken */
253*d14abf15SRobert Mustacchi REG_WR(pdev, MISC_REG_DRIVER_CONTROL_15, 0xffffffff);
254*d14abf15SRobert Mustacchi
255*d14abf15SRobert Mustacchi mm_wait(pdev, 100000);
256*d14abf15SRobert Mustacchi
257*d14abf15SRobert Mustacchi // No need to wait here a minimum time, since the mcp_comp will
258*d14abf15SRobert Mustacchi // returns only when mcp is ready.
259*d14abf15SRobert Mustacchi lm_status = lm_reset_mcp_comp(pdev, magic_val);
260*d14abf15SRobert Mustacchi
261*d14abf15SRobert Mustacchi return lm_status;
262*d14abf15SRobert Mustacchi }
263*d14abf15SRobert Mustacchi
264*d14abf15SRobert Mustacchi //acquire split MCP access lock register
265*d14abf15SRobert Mustacchi lm_status_t
acquire_split_alr(lm_device_t * pdev)266*d14abf15SRobert Mustacchi acquire_split_alr(
267*d14abf15SRobert Mustacchi lm_device_t *pdev)
268*d14abf15SRobert Mustacchi {
269*d14abf15SRobert Mustacchi lm_status_t lm_status;
270*d14abf15SRobert Mustacchi u32_t j, cnt;
271*d14abf15SRobert Mustacchi u32_t val_wr, val_rd;
272*d14abf15SRobert Mustacchi
273*d14abf15SRobert Mustacchi DbgMessage(pdev, INFORM, "acquire_split_alr() - %d START!\n", FUNC_ID(pdev) );
274*d14abf15SRobert Mustacchi
275*d14abf15SRobert Mustacchi //Adjust timeout for our emulation needs
276*d14abf15SRobert Mustacchi cnt = 30000 * 100;
277*d14abf15SRobert Mustacchi val_wr = 1UL << 31;
278*d14abf15SRobert Mustacchi val_rd = 0;
279*d14abf15SRobert Mustacchi
280*d14abf15SRobert Mustacchi //acquire lock using mcpr_access_lock SPLIT register
281*d14abf15SRobert Mustacchi
282*d14abf15SRobert Mustacchi for(j = 0; j < cnt*10; j++)
283*d14abf15SRobert Mustacchi {
284*d14abf15SRobert Mustacchi REG_WR(pdev, GRCBASE_MCP + 0x9c, val_wr);
285*d14abf15SRobert Mustacchi val_rd = REG_RD(pdev, GRCBASE_MCP + 0x9c);
286*d14abf15SRobert Mustacchi if (val_rd & (1UL << 31))
287*d14abf15SRobert Mustacchi {
288*d14abf15SRobert Mustacchi break;
289*d14abf15SRobert Mustacchi }
290*d14abf15SRobert Mustacchi
291*d14abf15SRobert Mustacchi mm_wait(pdev, 5);
292*d14abf15SRobert Mustacchi }
293*d14abf15SRobert Mustacchi
294*d14abf15SRobert Mustacchi if(val_rd & (1UL << 31))
295*d14abf15SRobert Mustacchi {
296*d14abf15SRobert Mustacchi lm_status = LM_STATUS_SUCCESS;
297*d14abf15SRobert Mustacchi }
298*d14abf15SRobert Mustacchi else
299*d14abf15SRobert Mustacchi {
300*d14abf15SRobert Mustacchi DbgBreakMsg("Cannot get access to nvram interface.\n");
301*d14abf15SRobert Mustacchi
302*d14abf15SRobert Mustacchi lm_status = LM_STATUS_BUSY;
303*d14abf15SRobert Mustacchi }
304*d14abf15SRobert Mustacchi
305*d14abf15SRobert Mustacchi DbgMessage(pdev, INFORM, "acquire_split_alr() - %d END!\n", FUNC_ID(pdev) );
306*d14abf15SRobert Mustacchi
307*d14abf15SRobert Mustacchi return lm_status;
308*d14abf15SRobert Mustacchi }
309*d14abf15SRobert Mustacchi
310*d14abf15SRobert Mustacchi //Release split MCP access lock register
311*d14abf15SRobert Mustacchi void
release_split_alr(lm_device_t * pdev)312*d14abf15SRobert Mustacchi release_split_alr(
313*d14abf15SRobert Mustacchi lm_device_t *pdev)
314*d14abf15SRobert Mustacchi {
315*d14abf15SRobert Mustacchi u32_t val = 0;
316*d14abf15SRobert Mustacchi
317*d14abf15SRobert Mustacchi DbgMessage(pdev, INFORM, "release_split_alr() - %d START!\n", FUNC_ID(pdev) );
318*d14abf15SRobert Mustacchi
319*d14abf15SRobert Mustacchi //This is only a sanity check, can remove later in free build.
320*d14abf15SRobert Mustacchi val= REG_RD(pdev, GRCBASE_MCP + 0x9c);
321*d14abf15SRobert Mustacchi DbgBreakIf(!(val & (1L << 31)));
322*d14abf15SRobert Mustacchi
323*d14abf15SRobert Mustacchi val = 0;
324*d14abf15SRobert Mustacchi
325*d14abf15SRobert Mustacchi //release mcpr_access_lock SPLIT register
326*d14abf15SRobert Mustacchi REG_WR(pdev, GRCBASE_MCP + 0x9c, val);
327*d14abf15SRobert Mustacchi DbgMessage(pdev, INFORM, "release_split_alr() - %d END!\n", FUNC_ID(pdev) );
328*d14abf15SRobert Mustacchi } /* release_nvram_lock */
329*d14abf15SRobert Mustacchi
330*d14abf15SRobert Mustacchi /*******************************************************************************
331*d14abf15SRobert Mustacchi * Description:
332*d14abf15SRobert Mustacchi * sends the mcp a keepalive to known registers
333*d14abf15SRobert Mustacchi * Return:
334*d14abf15SRobert Mustacchi ******************************************************************************/
lm_send_driver_pulse(lm_device_t * pdev)335*d14abf15SRobert Mustacchi lm_status_t lm_send_driver_pulse( lm_device_t* pdev )
336*d14abf15SRobert Mustacchi {
337*d14abf15SRobert Mustacchi u32_t msg_code = 0;
338*d14abf15SRobert Mustacchi u32_t drv_pulse = 0;
339*d14abf15SRobert Mustacchi u32_t mcp_pulse = 0;
340*d14abf15SRobert Mustacchi
341*d14abf15SRobert Mustacchi if CHK_NULL(pdev)
342*d14abf15SRobert Mustacchi {
343*d14abf15SRobert Mustacchi return LM_STATUS_INVALID_PARAMETER ;
344*d14abf15SRobert Mustacchi }
345*d14abf15SRobert Mustacchi
346*d14abf15SRobert Mustacchi if GET_FLAGS(pdev->params.test_mode, TEST_MODE_NO_MCP)
347*d14abf15SRobert Mustacchi {
348*d14abf15SRobert Mustacchi return LM_STATUS_SUCCESS ;
349*d14abf15SRobert Mustacchi }
350*d14abf15SRobert Mustacchi
351*d14abf15SRobert Mustacchi ++pdev->vars.drv_pulse_wr_seq;
352*d14abf15SRobert Mustacchi msg_code = pdev->vars.drv_pulse_wr_seq & DRV_PULSE_SEQ_MASK;
353*d14abf15SRobert Mustacchi if (GET_FLAGS(pdev->params.test_mode, TEST_MODE_DRIVER_PULSE_ALWAYS_ALIVE)
354*d14abf15SRobert Mustacchi || IS_DRIVER_PULSE_ALWAYS_ALIVE(pdev))
355*d14abf15SRobert Mustacchi {
356*d14abf15SRobert Mustacchi SET_FLAGS( msg_code, DRV_PULSE_ALWAYS_ALIVE ) ;
357*d14abf15SRobert Mustacchi }
358*d14abf15SRobert Mustacchi
359*d14abf15SRobert Mustacchi drv_pulse = msg_code;
360*d14abf15SRobert Mustacchi
361*d14abf15SRobert Mustacchi LM_SHMEM_WRITE(pdev,
362*d14abf15SRobert Mustacchi OFFSETOF(shmem_region_t,
363*d14abf15SRobert Mustacchi func_mb[FUNC_MAILBOX_ID(pdev)].drv_pulse_mb),msg_code);
364*d14abf15SRobert Mustacchi LM_SHMEM_READ(pdev,
365*d14abf15SRobert Mustacchi OFFSETOF(shmem_region_t,
366*d14abf15SRobert Mustacchi func_mb[FUNC_MAILBOX_ID(pdev)].mcp_pulse_mb),
367*d14abf15SRobert Mustacchi &mcp_pulse);
368*d14abf15SRobert Mustacchi
369*d14abf15SRobert Mustacchi mcp_pulse&= MCP_PULSE_SEQ_MASK ;
370*d14abf15SRobert Mustacchi /* The delta between driver pulse and mcp response
371*d14abf15SRobert Mustacchi * should be 1 (before mcp response) or 0 (after mcp response)
372*d14abf15SRobert Mustacchi */
373*d14abf15SRobert Mustacchi if ((drv_pulse != mcp_pulse) &&
374*d14abf15SRobert Mustacchi (drv_pulse != ((mcp_pulse + 1) & MCP_PULSE_SEQ_MASK)))
375*d14abf15SRobert Mustacchi {
376*d14abf15SRobert Mustacchi DbgMessage(pdev, FATAL, "drv_pulse (0x%x) != mcp_pulse (0x%x)\n", drv_pulse, mcp_pulse );
377*d14abf15SRobert Mustacchi return LM_STATUS_FAILURE ;
378*d14abf15SRobert Mustacchi }
379*d14abf15SRobert Mustacchi DbgMessage(pdev, INFORMi , "Sent driver pulse cmd to MCP\n");
380*d14abf15SRobert Mustacchi return LM_STATUS_SUCCESS ;
381*d14abf15SRobert Mustacchi }
382*d14abf15SRobert Mustacchi /*******************************************************************************
383*d14abf15SRobert Mustacchi * Description:
384*d14abf15SRobert Mustacchi * Set driver pulse to MCP to always alive
385*d14abf15SRobert Mustacchi * Return:
386*d14abf15SRobert Mustacchi ******************************************************************************/
lm_driver_pulse_always_alive(struct _lm_device_t * pdev)387*d14abf15SRobert Mustacchi void lm_driver_pulse_always_alive(struct _lm_device_t* pdev)
388*d14abf15SRobert Mustacchi {
389*d14abf15SRobert Mustacchi if CHK_NULL(pdev)
390*d14abf15SRobert Mustacchi {
391*d14abf15SRobert Mustacchi return;
392*d14abf15SRobert Mustacchi }
393*d14abf15SRobert Mustacchi if GET_FLAGS(pdev->params.test_mode, TEST_MODE_NO_MCP)
394*d14abf15SRobert Mustacchi {
395*d14abf15SRobert Mustacchi return ;
396*d14abf15SRobert Mustacchi }
397*d14abf15SRobert Mustacchi // Reset the MCP pulse to always alive
398*d14abf15SRobert Mustacchi LM_SHMEM_WRITE( pdev,
399*d14abf15SRobert Mustacchi OFFSETOF(shmem_region_t,
400*d14abf15SRobert Mustacchi func_mb[FUNC_MAILBOX_ID(pdev)].drv_pulse_mb),
401*d14abf15SRobert Mustacchi DRV_PULSE_ALWAYS_ALIVE );
402*d14abf15SRobert Mustacchi }
403*d14abf15SRobert Mustacchi // entry that represents a function in the loader objcet
404*d14abf15SRobert Mustacchi typedef struct _lm_loader_func_entry_t
405*d14abf15SRobert Mustacchi {
406*d14abf15SRobert Mustacchi u8_t b_loaded ; // does this function was loaded
407*d14abf15SRobert Mustacchi } lm_loader_func_entry_t ;
408*d14abf15SRobert Mustacchi // global object represents MCP - should be one per CHIP (boards)
409*d14abf15SRobert Mustacchi typedef struct _lm_loader_path_obj_t
410*d14abf15SRobert Mustacchi {
411*d14abf15SRobert Mustacchi u32_t* lock_ctx ; // reserved - lock object context (currently not in use)
412*d14abf15SRobert Mustacchi lm_loader_func_entry_t func_arr[E1H_FUNC_MAX] ; // array of function entries
413*d14abf15SRobert Mustacchi } lm_loader_path_obj_t ;
414*d14abf15SRobert Mustacchi
415*d14abf15SRobert Mustacchi typedef struct _lm_loader_obj_t
416*d14abf15SRobert Mustacchi {
417*d14abf15SRobert Mustacchi u8_t lock_owner ; // is a function acquire the lock? (1 based)
418*d14abf15SRobert Mustacchi lm_loader_path_obj_t path_arr[MAX_PATH_NUM] ;
419*d14abf15SRobert Mustacchi } lm_loader_obj_t ;
420*d14abf15SRobert Mustacchi
421*d14abf15SRobert Mustacchi lm_loader_obj_t g_lm_loader = {0};
422*d14abf15SRobert Mustacchi
423*d14abf15SRobert Mustacchi // TRUE if the function is first on the port
424*d14abf15SRobert Mustacchi #define LM_LOADER_IS_FIRST_ON_PORT(_pdev,_path_idx,_port_idx) \
425*d14abf15SRobert Mustacchi ( (FALSE == g_lm_loader.path_arr[_path_idx].func_arr[_port_idx+0].b_loaded) && \
426*d14abf15SRobert Mustacchi (FALSE == g_lm_loader.path_arr[_path_idx].func_arr[_port_idx+2].b_loaded) && \
427*d14abf15SRobert Mustacchi (FALSE == g_lm_loader.path_arr[_path_idx].func_arr[_port_idx+4].b_loaded) && \
428*d14abf15SRobert Mustacchi (FALSE == g_lm_loader.path_arr[_path_idx].func_arr[_port_idx+6].b_loaded) )
429*d14abf15SRobert Mustacchi
430*d14abf15SRobert Mustacchi // TRUE if the function is last on the port
431*d14abf15SRobert Mustacchi #define LM_LOADER_IS_LAST_ON_PORT(_pdev,_path_idx,_port_idx) \
432*d14abf15SRobert Mustacchi ( ( ( FUNC_ID(_pdev) == (_port_idx+0) ) ? TRUE : (FALSE == g_lm_loader.path_arr[_path_idx].func_arr[(_port_idx+0)].b_loaded) ) && \
433*d14abf15SRobert Mustacchi ( ( FUNC_ID(_pdev) == (_port_idx+2) ) ? TRUE : (FALSE == g_lm_loader.path_arr[_path_idx].func_arr[(_port_idx+2)].b_loaded) ) && \
434*d14abf15SRobert Mustacchi ( ( FUNC_ID(_pdev) == (_port_idx+4) ) ? TRUE : (FALSE == g_lm_loader.path_arr[_path_idx].func_arr[(_port_idx+4)].b_loaded) ) && \
435*d14abf15SRobert Mustacchi ( ( FUNC_ID(_pdev) == (_port_idx+6) ) ? TRUE : (_port_idx == 0)?(FALSE == g_lm_loader.path_arr[_path_idx].func_arr[6].b_loaded):(FALSE == g_lm_loader.path_arr[_path_idx].func_arr[7].b_loaded) ) )
436*d14abf15SRobert Mustacchi
437*d14abf15SRobert Mustacchi
438*d14abf15SRobert Mustacchi #define LM_LOADER_IS_FIRST_ON_COMMON(_pdev,_path_idx) (LM_LOADER_IS_FIRST_ON_PORT(_pdev,_path_idx,0) && LM_LOADER_IS_FIRST_ON_PORT(_pdev,_path_idx,1))
439*d14abf15SRobert Mustacchi #define LM_LOADER_IS_LAST_ON_COMMON(_pdev,_path_idx) (LM_LOADER_IS_LAST_ON_PORT(_pdev,_path_idx,0) && LM_LOADER_IS_LAST_ON_PORT(_pdev,_path_idx,1))
440*d14abf15SRobert Mustacchi
441*d14abf15SRobert Mustacchi #define LM_LOADER_IS_FIRST_ON_CHIP(_pdev) (LM_LOADER_IS_FIRST_ON_COMMON(_pdev,0) && LM_LOADER_IS_FIRST_ON_COMMON(_pdev,1))
442*d14abf15SRobert Mustacchi #define LM_LOADER_IS_LAST_ON_CHIP(_pdev) (LM_LOADER_IS_LAST_ON_COMMON(_pdev,0) && LM_LOADER_IS_LAST_ON_COMMON(_pdev,1))
443*d14abf15SRobert Mustacchi
444*d14abf15SRobert Mustacchi // Accessed only with lock!
445*d14abf15SRobert Mustacchi // TRUE if any device is currently locked
446*d14abf15SRobert Mustacchi #define LM_LOADER_IS_LOCKED(_chip_idx) ( (FALSE != g_lm_loader.lock_owner) )
447*d14abf15SRobert Mustacchi
448*d14abf15SRobert Mustacchi /*
449*d14abf15SRobert Mustacchi *Function Name:lm_loader_opcode_to_mcp_msg
450*d14abf15SRobert Mustacchi *
451*d14abf15SRobert Mustacchi *Parameters:
452*d14abf15SRobert Mustacchi * b_lock - true if it is lock false if unlock
453*d14abf15SRobert Mustacchi *Description:
454*d14abf15SRobert Mustacchi * LM_LOADER_OPCODE_XXX-->DRV_MSG_CODE_XXX
455*d14abf15SRobert Mustacchi *Returns:
456*d14abf15SRobert Mustacchi *
457*d14abf15SRobert Mustacchi */
lm_loader_opcode_to_mcp_msg(lm_loader_opcode opcode,u8_t b_lock)458*d14abf15SRobert Mustacchi static u32_t lm_loader_opcode_to_mcp_msg( lm_loader_opcode opcode, u8_t b_lock )
459*d14abf15SRobert Mustacchi {
460*d14abf15SRobert Mustacchi u32_t mcp_msg = 0xffffffff ;
461*d14abf15SRobert Mustacchi
462*d14abf15SRobert Mustacchi switch(opcode)
463*d14abf15SRobert Mustacchi {
464*d14abf15SRobert Mustacchi case LM_LOADER_OPCODE_LOAD:
465*d14abf15SRobert Mustacchi mcp_msg = b_lock ? DRV_MSG_CODE_LOAD_REQ : DRV_MSG_CODE_LOAD_DONE ;
466*d14abf15SRobert Mustacchi break;
467*d14abf15SRobert Mustacchi case LM_LOADER_OPCODE_UNLOAD_WOL_EN:
468*d14abf15SRobert Mustacchi mcp_msg = b_lock ? DRV_MSG_CODE_UNLOAD_REQ_WOL_EN : DRV_MSG_CODE_UNLOAD_DONE ;
469*d14abf15SRobert Mustacchi break;
470*d14abf15SRobert Mustacchi case LM_LOADER_OPCODE_UNLOAD_WOL_DIS:
471*d14abf15SRobert Mustacchi mcp_msg = b_lock ? DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS : DRV_MSG_CODE_UNLOAD_DONE ;
472*d14abf15SRobert Mustacchi break;
473*d14abf15SRobert Mustacchi case LM_LOADER_OPCODE_UNLOAD_WOL_MCP:
474*d14abf15SRobert Mustacchi mcp_msg = b_lock ? DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP : DRV_MSG_CODE_UNLOAD_DONE ;
475*d14abf15SRobert Mustacchi break;
476*d14abf15SRobert Mustacchi default:
477*d14abf15SRobert Mustacchi DbgBreakIf(1) ;
478*d14abf15SRobert Mustacchi break;
479*d14abf15SRobert Mustacchi }
480*d14abf15SRobert Mustacchi return mcp_msg ;
481*d14abf15SRobert Mustacchi }
482*d14abf15SRobert Mustacchi /*
483*d14abf15SRobert Mustacchi *Function Name:mcp_resp_to_lm_loader_resp
484*d14abf15SRobert Mustacchi *
485*d14abf15SRobert Mustacchi *Parameters:
486*d14abf15SRobert Mustacchi *
487*d14abf15SRobert Mustacchi *Description:
488*d14abf15SRobert Mustacchi * Translates mcp response to loader response FW_MSG_CODE_DRV_XXX->LM_LOADER_RESPONSE_XX
489*d14abf15SRobert Mustacchi *Returns:
490*d14abf15SRobert Mustacchi *
491*d14abf15SRobert Mustacchi */
mcp_resp_to_lm_loader_resp(u32_t mcp_resp)492*d14abf15SRobert Mustacchi lm_loader_response mcp_resp_to_lm_loader_resp( u32_t mcp_resp )
493*d14abf15SRobert Mustacchi {
494*d14abf15SRobert Mustacchi lm_loader_response resp = LM_LOADER_RESPONSE_INVALID ;
495*d14abf15SRobert Mustacchi switch(mcp_resp)
496*d14abf15SRobert Mustacchi {
497*d14abf15SRobert Mustacchi case FW_MSG_CODE_DRV_LOAD_COMMON:
498*d14abf15SRobert Mustacchi resp = LM_LOADER_RESPONSE_LOAD_COMMON ;
499*d14abf15SRobert Mustacchi break;
500*d14abf15SRobert Mustacchi case FW_MSG_CODE_DRV_LOAD_COMMON_CHIP:
501*d14abf15SRobert Mustacchi resp = LM_LOADER_RESPONSE_LOAD_COMMON_CHIP ;
502*d14abf15SRobert Mustacchi break;
503*d14abf15SRobert Mustacchi case FW_MSG_CODE_DRV_LOAD_PORT:
504*d14abf15SRobert Mustacchi resp = LM_LOADER_RESPONSE_LOAD_PORT ;
505*d14abf15SRobert Mustacchi break;
506*d14abf15SRobert Mustacchi case FW_MSG_CODE_DRV_LOAD_FUNCTION:
507*d14abf15SRobert Mustacchi resp = LM_LOADER_RESPONSE_LOAD_FUNCTION ;
508*d14abf15SRobert Mustacchi break;
509*d14abf15SRobert Mustacchi case FW_MSG_CODE_DRV_UNLOAD_COMMON:
510*d14abf15SRobert Mustacchi resp = LM_LOADER_RESPONSE_UNLOAD_COMMON ;
511*d14abf15SRobert Mustacchi break;
512*d14abf15SRobert Mustacchi case FW_MSG_CODE_DRV_UNLOAD_PORT:
513*d14abf15SRobert Mustacchi resp = LM_LOADER_RESPONSE_UNLOAD_PORT ;
514*d14abf15SRobert Mustacchi break;
515*d14abf15SRobert Mustacchi case FW_MSG_CODE_DRV_UNLOAD_FUNCTION:
516*d14abf15SRobert Mustacchi resp = LM_LOADER_RESPONSE_UNLOAD_FUNCTION ;
517*d14abf15SRobert Mustacchi break;
518*d14abf15SRobert Mustacchi case FW_MSG_CODE_DRV_LOAD_DONE:
519*d14abf15SRobert Mustacchi resp = LM_LOADER_RESPONSE_LOAD_DONE ;
520*d14abf15SRobert Mustacchi break;
521*d14abf15SRobert Mustacchi case FW_MSG_CODE_DRV_UNLOAD_DONE:
522*d14abf15SRobert Mustacchi resp = LM_LOADER_RESPONSE_UNLOAD_DONE ;
523*d14abf15SRobert Mustacchi break;
524*d14abf15SRobert Mustacchi default:
525*d14abf15SRobert Mustacchi DbgMessage(NULL, FATAL, "mcp_resp=0x%x\n", mcp_resp );
526*d14abf15SRobert Mustacchi DbgBreakIf(1) ;
527*d14abf15SRobert Mustacchi break;
528*d14abf15SRobert Mustacchi }
529*d14abf15SRobert Mustacchi return resp ;
530*d14abf15SRobert Mustacchi }
531*d14abf15SRobert Mustacchi // TBD - should it be the only indication??
532*d14abf15SRobert Mustacchi #define IS_MCP_ON(_pdev) ( TEST_MODE_NO_MCP != GET_FLAGS(_pdev->params.test_mode, TEST_MODE_NO_MCP ) )
533*d14abf15SRobert Mustacchi
534*d14abf15SRobert Mustacchi /*
535*d14abf15SRobert Mustacchi *Function Name:lm_loader_lock
536*d14abf15SRobert Mustacchi *
537*d14abf15SRobert Mustacchi *Parameters:
538*d14abf15SRobert Mustacchi *
539*d14abf15SRobert Mustacchi *Description:
540*d14abf15SRobert Mustacchi * sync loading/unloading of port/funciton
541*d14abf15SRobert Mustacchi *Returns:
542*d14abf15SRobert Mustacchi *
543*d14abf15SRobert Mustacchi */
lm_loader_lock(lm_device_t * pdev,lm_loader_opcode opcode)544*d14abf15SRobert Mustacchi lm_loader_response lm_loader_lock( lm_device_t* pdev, lm_loader_opcode opcode )
545*d14abf15SRobert Mustacchi {
546*d14abf15SRobert Mustacchi u32_t mcp_msg = 0;
547*d14abf15SRobert Mustacchi u32_t param = 0;
548*d14abf15SRobert Mustacchi u32_t fw_resp = 0;
549*d14abf15SRobert Mustacchi lm_loader_response resp = LM_LOADER_RESPONSE_INVALID ;
550*d14abf15SRobert Mustacchi lm_status_t lm_status = LM_STATUS_SUCCESS ;
551*d14abf15SRobert Mustacchi u32_t wait_cnt = 0;
552*d14abf15SRobert Mustacchi u32_t wait_cnt_limit = 5000;
553*d14abf15SRobert Mustacchi const u32_t feature_flags = mm_get_feature_flags( pdev );
554*d14abf15SRobert Mustacchi const u8_t is_suspend = opcode & LM_LOADER_OPCODE_UNLOAD_SUSPEND;
555*d14abf15SRobert Mustacchi
556*d14abf15SRobert Mustacchi opcode &= LM_LOADER_OPCODE_MASK;
557*d14abf15SRobert Mustacchi if( IS_MCP_ON(pdev) )
558*d14abf15SRobert Mustacchi {
559*d14abf15SRobert Mustacchi mcp_msg = lm_loader_opcode_to_mcp_msg( opcode, TRUE ) ;
560*d14abf15SRobert Mustacchi
561*d14abf15SRobert Mustacchi // in case it is load (and not unload)
562*d14abf15SRobert Mustacchi // send mfw LFA param
563*d14abf15SRobert Mustacchi if ( DRV_MSG_CODE_LOAD_REQ == mcp_msg )
564*d14abf15SRobert Mustacchi {
565*d14abf15SRobert Mustacchi SET_FLAGS(param, DRV_MSG_CODE_LOAD_REQ_WITH_LFA );
566*d14abf15SRobert Mustacchi
567*d14abf15SRobert Mustacchi // in case BFS, set FORCE_LFA flag on
568*d14abf15SRobert Mustacchi if( GET_FLAGS( feature_flags, FEATURE_ETH_BOOTMODE_PXE ) ||
569*d14abf15SRobert Mustacchi GET_FLAGS( feature_flags, FEATURE_ETH_BOOTMODE_ISCSI ) ||
570*d14abf15SRobert Mustacchi GET_FLAGS( feature_flags, FEATURE_ETH_BOOTMODE_FCOE ) )
571*d14abf15SRobert Mustacchi {
572*d14abf15SRobert Mustacchi SET_FLAGS( param, DRV_MSG_CODE_LOAD_REQ_FORCE_LFA );
573*d14abf15SRobert Mustacchi }
574*d14abf15SRobert Mustacchi
575*d14abf15SRobert Mustacchi }
576*d14abf15SRobert Mustacchi else if (is_suspend)
577*d14abf15SRobert Mustacchi {
578*d14abf15SRobert Mustacchi SET_FLAGS( param, DRV_MSG_CODE_UNLOAD_NON_D3_POWER ); //temporary
579*d14abf15SRobert Mustacchi }
580*d14abf15SRobert Mustacchi
581*d14abf15SRobert Mustacchi //we do this with no locks because acquiring the loader lock may take a long time (e.g in case another function takes a
582*d14abf15SRobert Mustacchi //long time to initialize we will only get a response from the MCP when it's done). We don't need a lock because interrupts
583*d14abf15SRobert Mustacchi //are disabled at this point and we won't get any IOCTLs.
584*d14abf15SRobert Mustacchi lm_status = lm_mcp_cmd_send_recieve_non_atomic( pdev, lm_mcp_mb_header, mcp_msg, param, MCP_CMD_DEFAULT_TIMEOUT, &fw_resp ) ;
585*d14abf15SRobert Mustacchi if ( LM_STATUS_SUCCESS == lm_status )
586*d14abf15SRobert Mustacchi {
587*d14abf15SRobert Mustacchi resp = mcp_resp_to_lm_loader_resp( fw_resp ) ;
588*d14abf15SRobert Mustacchi pdev->vars.b_in_init_reset_flow = TRUE;
589*d14abf15SRobert Mustacchi }
590*d14abf15SRobert Mustacchi }
591*d14abf15SRobert Mustacchi else // MCP_SIM
592*d14abf15SRobert Mustacchi {
593*d14abf15SRobert Mustacchi if( ERR_IF(PORT_ID(pdev) > 1) || ERR_IF(( FUNC_ID(pdev)) >= ARRSIZE(g_lm_loader.path_arr[PATH_ID(pdev)].func_arr)) )
594*d14abf15SRobert Mustacchi {
595*d14abf15SRobert Mustacchi DbgBreakMsg("Invalid PORT_ID/FUNC_ID\n");
596*d14abf15SRobert Mustacchi return resp ;
597*d14abf15SRobert Mustacchi }
598*d14abf15SRobert Mustacchi do
599*d14abf15SRobert Mustacchi {
600*d14abf15SRobert Mustacchi MM_ACQUIRE_LOADER_LOCK();
601*d14abf15SRobert Mustacchi if( LM_LOADER_IS_LOCKED(PATH_ID(pdev)) )
602*d14abf15SRobert Mustacchi {
603*d14abf15SRobert Mustacchi MM_RELEASE_LOADER_LOCK();
604*d14abf15SRobert Mustacchi mm_wait(pdev,20) ;
605*d14abf15SRobert Mustacchi DbgBreakIfAll( ++wait_cnt > wait_cnt_limit ) ;
606*d14abf15SRobert Mustacchi }
607*d14abf15SRobert Mustacchi else
608*d14abf15SRobert Mustacchi {
609*d14abf15SRobert Mustacchi // we'll release the lock when we are finish the work
610*d14abf15SRobert Mustacchi break;
611*d14abf15SRobert Mustacchi }
612*d14abf15SRobert Mustacchi }while(1) ;
613*d14abf15SRobert Mustacchi // Verify no one hold the lock, if so - it's a bug!
614*d14abf15SRobert Mustacchi DbgBreakIf( 0 != g_lm_loader.lock_owner ) ;
615*d14abf15SRobert Mustacchi
616*d14abf15SRobert Mustacchi // mark our current function id as owner
617*d14abf15SRobert Mustacchi g_lm_loader.lock_owner = FUNC_ID(pdev)+1 ;
618*d14abf15SRobert Mustacchi
619*d14abf15SRobert Mustacchi switch( opcode )
620*d14abf15SRobert Mustacchi {
621*d14abf15SRobert Mustacchi case LM_LOADER_OPCODE_LOAD:
622*d14abf15SRobert Mustacchi if( LM_LOADER_IS_FIRST_ON_CHIP(pdev) )
623*d14abf15SRobert Mustacchi {
624*d14abf15SRobert Mustacchi resp = LM_LOADER_RESPONSE_LOAD_COMMON_CHIP;
625*d14abf15SRobert Mustacchi }
626*d14abf15SRobert Mustacchi else if( LM_LOADER_IS_FIRST_ON_COMMON(pdev,PATH_ID(pdev)) )
627*d14abf15SRobert Mustacchi {
628*d14abf15SRobert Mustacchi resp = LM_LOADER_RESPONSE_LOAD_COMMON ;
629*d14abf15SRobert Mustacchi }
630*d14abf15SRobert Mustacchi else if( LM_LOADER_IS_FIRST_ON_PORT( pdev, PATH_ID(pdev), PORT_ID(pdev) ) )
631*d14abf15SRobert Mustacchi {
632*d14abf15SRobert Mustacchi resp = LM_LOADER_RESPONSE_LOAD_PORT ;
633*d14abf15SRobert Mustacchi }
634*d14abf15SRobert Mustacchi else
635*d14abf15SRobert Mustacchi {
636*d14abf15SRobert Mustacchi resp = LM_LOADER_RESPONSE_LOAD_FUNCTION ;
637*d14abf15SRobert Mustacchi }
638*d14abf15SRobert Mustacchi break;
639*d14abf15SRobert Mustacchi case LM_LOADER_OPCODE_UNLOAD_WOL_EN:
640*d14abf15SRobert Mustacchi case LM_LOADER_OPCODE_UNLOAD_WOL_DIS:
641*d14abf15SRobert Mustacchi case LM_LOADER_OPCODE_UNLOAD_WOL_MCP:
642*d14abf15SRobert Mustacchi if( LM_LOADER_IS_LAST_ON_COMMON(pdev,PATH_ID(pdev)) )
643*d14abf15SRobert Mustacchi {
644*d14abf15SRobert Mustacchi resp = LM_LOADER_RESPONSE_UNLOAD_COMMON ;
645*d14abf15SRobert Mustacchi }
646*d14abf15SRobert Mustacchi else if( LM_LOADER_IS_LAST_ON_PORT( pdev, PATH_ID(pdev), PORT_ID(pdev) ) )
647*d14abf15SRobert Mustacchi {
648*d14abf15SRobert Mustacchi resp = LM_LOADER_RESPONSE_UNLOAD_PORT ;
649*d14abf15SRobert Mustacchi }
650*d14abf15SRobert Mustacchi else
651*d14abf15SRobert Mustacchi {
652*d14abf15SRobert Mustacchi resp = LM_LOADER_RESPONSE_UNLOAD_FUNCTION ;
653*d14abf15SRobert Mustacchi }
654*d14abf15SRobert Mustacchi break;
655*d14abf15SRobert Mustacchi default:
656*d14abf15SRobert Mustacchi DbgBreakIf(1) ;
657*d14abf15SRobert Mustacchi break;
658*d14abf15SRobert Mustacchi } // switch
659*d14abf15SRobert Mustacchi pdev->vars.b_in_init_reset_flow = TRUE;
660*d14abf15SRobert Mustacchi MM_RELEASE_LOADER_LOCK();
661*d14abf15SRobert Mustacchi } // MCP_SIM
662*d14abf15SRobert Mustacchi return resp ;
663*d14abf15SRobert Mustacchi }
664*d14abf15SRobert Mustacchi /*
665*d14abf15SRobert Mustacchi *Function Name:lm_loader_unlock
666*d14abf15SRobert Mustacchi *
667*d14abf15SRobert Mustacchi *Parameters:
668*d14abf15SRobert Mustacchi *
669*d14abf15SRobert Mustacchi *Description:
670*d14abf15SRobert Mustacchi * sync loading/unloading of port/funciton
671*d14abf15SRobert Mustacchi *Returns:
672*d14abf15SRobert Mustacchi *
673*d14abf15SRobert Mustacchi */
lm_loader_unlock(struct _lm_device_t * pdev,lm_loader_opcode opcode,OPTIONAL const u32_t * IN p_param)674*d14abf15SRobert Mustacchi lm_loader_response lm_loader_unlock( struct _lm_device_t *pdev, lm_loader_opcode opcode, OPTIONAL const u32_t* IN p_param )
675*d14abf15SRobert Mustacchi {
676*d14abf15SRobert Mustacchi u32_t mcp_msg = 0 ;
677*d14abf15SRobert Mustacchi u32_t param = p_param ? (*p_param) : 0 ;
678*d14abf15SRobert Mustacchi lm_loader_response resp = LM_LOADER_RESPONSE_INVALID ;
679*d14abf15SRobert Mustacchi u32_t fw_resp = 0 ;
680*d14abf15SRobert Mustacchi lm_status_t lm_status = LM_STATUS_SUCCESS ;
681*d14abf15SRobert Mustacchi u8_t b_new_state = 0xff ;
682*d14abf15SRobert Mustacchi if CHK_NULL(pdev)
683*d14abf15SRobert Mustacchi {
684*d14abf15SRobert Mustacchi return resp ;
685*d14abf15SRobert Mustacchi }
686*d14abf15SRobert Mustacchi opcode &= LM_LOADER_OPCODE_MASK;
687*d14abf15SRobert Mustacchi if( IS_MCP_ON(pdev) )
688*d14abf15SRobert Mustacchi {
689*d14abf15SRobert Mustacchi mcp_msg = lm_loader_opcode_to_mcp_msg( opcode, FALSE );
690*d14abf15SRobert Mustacchi //we do this with no locks because acquiring the loader lock may take a long time (e.g in case another function takes a
691*d14abf15SRobert Mustacchi //long time to initialize we will only get a response from the MCP when it's done). We don't need a lock because interrupts
692*d14abf15SRobert Mustacchi //are disabled at this point and we won't get any IOCTLs.
693*d14abf15SRobert Mustacchi lm_status = lm_mcp_cmd_send_recieve_non_atomic(pdev, lm_mcp_mb_header, mcp_msg, param, MCP_CMD_DEFAULT_TIMEOUT, &fw_resp ) ;
694*d14abf15SRobert Mustacchi if ( LM_STATUS_SUCCESS == lm_status )
695*d14abf15SRobert Mustacchi {
696*d14abf15SRobert Mustacchi resp = mcp_resp_to_lm_loader_resp( fw_resp ) ;
697*d14abf15SRobert Mustacchi pdev->vars.b_in_init_reset_flow = FALSE;
698*d14abf15SRobert Mustacchi }
699*d14abf15SRobert Mustacchi }
700*d14abf15SRobert Mustacchi else // MCP_SIM
701*d14abf15SRobert Mustacchi {
702*d14abf15SRobert Mustacchi MM_ACQUIRE_LOADER_LOCK();
703*d14abf15SRobert Mustacchi
704*d14abf15SRobert Mustacchi // Verify current function id is the owner
705*d14abf15SRobert Mustacchi DbgBreakIf( g_lm_loader.lock_owner != FUNC_ID(pdev)+1 ) ;
706*d14abf15SRobert Mustacchi
707*d14abf15SRobert Mustacchi switch( opcode )
708*d14abf15SRobert Mustacchi {
709*d14abf15SRobert Mustacchi case LM_LOADER_OPCODE_LOAD:
710*d14abf15SRobert Mustacchi b_new_state = TRUE ;
711*d14abf15SRobert Mustacchi resp = LM_LOADER_RESPONSE_LOAD_DONE ;
712*d14abf15SRobert Mustacchi break;
713*d14abf15SRobert Mustacchi case LM_LOADER_OPCODE_UNLOAD_WOL_EN:
714*d14abf15SRobert Mustacchi case LM_LOADER_OPCODE_UNLOAD_WOL_DIS:
715*d14abf15SRobert Mustacchi case LM_LOADER_OPCODE_UNLOAD_WOL_MCP:
716*d14abf15SRobert Mustacchi b_new_state = FALSE ;
717*d14abf15SRobert Mustacchi resp = LM_LOADER_RESPONSE_UNLOAD_DONE ;
718*d14abf15SRobert Mustacchi break;
719*d14abf15SRobert Mustacchi default:
720*d14abf15SRobert Mustacchi DbgBreakIf(1) ;
721*d14abf15SRobert Mustacchi break;
722*d14abf15SRobert Mustacchi } // switch
723*d14abf15SRobert Mustacchi // verify new state differs than current
724*d14abf15SRobert Mustacchi DbgBreakIf(g_lm_loader.path_arr[PATH_ID(pdev)].func_arr[FUNC_ID(pdev)].b_loaded == b_new_state);
725*d14abf15SRobert Mustacchi
726*d14abf15SRobert Mustacchi // assign new state
727*d14abf15SRobert Mustacchi g_lm_loader.path_arr[PATH_ID(pdev)].func_arr[FUNC_ID(pdev)].b_loaded = b_new_state ;
728*d14abf15SRobert Mustacchi
729*d14abf15SRobert Mustacchi // mark we don't own the lock anymore
730*d14abf15SRobert Mustacchi g_lm_loader.lock_owner = FALSE ;
731*d14abf15SRobert Mustacchi
732*d14abf15SRobert Mustacchi pdev->vars.b_in_init_reset_flow = FALSE;
733*d14abf15SRobert Mustacchi MM_RELEASE_LOADER_LOCK();
734*d14abf15SRobert Mustacchi } // MCP_SIM
735*d14abf15SRobert Mustacchi return resp ;
736*d14abf15SRobert Mustacchi }
737*d14abf15SRobert Mustacchi
738*d14abf15SRobert Mustacchi /* Used for simulating a mcp reset where the mcp no longer knows the state of the uploaded drivers... */
lm_loader_reset(struct _lm_device_t * pdev)739*d14abf15SRobert Mustacchi void lm_loader_reset ( struct _lm_device_t *pdev )
740*d14abf15SRobert Mustacchi {
741*d14abf15SRobert Mustacchi mm_memset(&g_lm_loader, 0, sizeof(g_lm_loader));
742*d14abf15SRobert Mustacchi }
743*d14abf15SRobert Mustacchi
744*d14abf15SRobert Mustacchi /*
745*d14abf15SRobert Mustacchi *Function Name:lm_mcp_cmd_init
746*d14abf15SRobert Mustacchi *
747*d14abf15SRobert Mustacchi *Parameters:
748*d14abf15SRobert Mustacchi *
749*d14abf15SRobert Mustacchi *Description:
750*d14abf15SRobert Mustacchi * initiate sequence of mb + verify boot code version
751*d14abf15SRobert Mustacchi *Returns:
752*d14abf15SRobert Mustacchi *
753*d14abf15SRobert Mustacchi */
lm_mcp_cmd_init(struct _lm_device_t * pdev)754*d14abf15SRobert Mustacchi lm_status_t lm_mcp_cmd_init( struct _lm_device_t *pdev)
755*d14abf15SRobert Mustacchi {
756*d14abf15SRobert Mustacchi u32_t val = 0 ;
757*d14abf15SRobert Mustacchi u32_t bc_rev = 0 ;
758*d14abf15SRobert Mustacchi u32_t offset = 0 ;
759*d14abf15SRobert Mustacchi u8_t func_mb_id = 0;
760*d14abf15SRobert Mustacchi
761*d14abf15SRobert Mustacchi DbgMessage(pdev, INFORMi , "### mcp_cmd_init\n");
762*d14abf15SRobert Mustacchi
763*d14abf15SRobert Mustacchi if CHK_NULL(pdev)
764*d14abf15SRobert Mustacchi {
765*d14abf15SRobert Mustacchi return LM_STATUS_FAILURE ;
766*d14abf15SRobert Mustacchi }
767*d14abf15SRobert Mustacchi
768*d14abf15SRobert Mustacchi // we are on NO_MCP mode - nothing to do
769*d14abf15SRobert Mustacchi if( 0 != GET_FLAGS(pdev->params.test_mode, TEST_MODE_NO_MCP ) )
770*d14abf15SRobert Mustacchi {
771*d14abf15SRobert Mustacchi return LM_STATUS_SUCCESS ;
772*d14abf15SRobert Mustacchi }
773*d14abf15SRobert Mustacchi
774*d14abf15SRobert Mustacchi //validtae bc version
775*d14abf15SRobert Mustacchi bc_rev = LM_GET_BC_REV_MAJOR(pdev);
776*d14abf15SRobert Mustacchi
777*d14abf15SRobert Mustacchi if (bc_rev < BC_REV_SUPPORTED)
778*d14abf15SRobert Mustacchi {
779*d14abf15SRobert Mustacchi DbgMessage(pdev, FATAL,"bc version is less than 0x%x equal to 0x%x.\n", BC_REV_SUPPORTED, bc_rev );
780*d14abf15SRobert Mustacchi DbgBreakMsg("Please upgrade the bootcode version.\n");
781*d14abf15SRobert Mustacchi // TODO add event log
782*d14abf15SRobert Mustacchi return LM_STATUS_INVALID_PARAMETER;
783*d14abf15SRobert Mustacchi }
784*d14abf15SRobert Mustacchi
785*d14abf15SRobert Mustacchi // enable optic module verification according to BC version
786*d14abf15SRobert Mustacchi if (bc_rev >= REQ_BC_VER_4_VRFY_FIRST_PHY_OPT_MDL)
787*d14abf15SRobert Mustacchi {
788*d14abf15SRobert Mustacchi SET_FLAGS(pdev->params.link.feature_config_flags, ELINK_FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY);
789*d14abf15SRobert Mustacchi }
790*d14abf15SRobert Mustacchi
791*d14abf15SRobert Mustacchi if (bc_rev >= REQ_BC_VER_4_VRFY_SPECIFIC_PHY_OPT_MDL)
792*d14abf15SRobert Mustacchi {
793*d14abf15SRobert Mustacchi SET_FLAGS(pdev->params.link.feature_config_flags, ELINK_FEATURE_CONFIG_BC_SUPPORTS_DUAL_PHY_OPT_MDL_VRFY);
794*d14abf15SRobert Mustacchi }
795*d14abf15SRobert Mustacchi
796*d14abf15SRobert Mustacchi if (bc_rev >= REQ_BC_VER_4_VRFY_AFEX_SUPPORTED)
797*d14abf15SRobert Mustacchi {
798*d14abf15SRobert Mustacchi SET_FLAGS(pdev->params.link.feature_config_flags, ELINK_FEATURE_CONFIG_BC_SUPPORTS_AFEX);
799*d14abf15SRobert Mustacchi }
800*d14abf15SRobert Mustacchi
801*d14abf15SRobert Mustacchi if (bc_rev >= REQ_BC_VER_4_SFP_TX_DISABLE_SUPPORTED)
802*d14abf15SRobert Mustacchi {
803*d14abf15SRobert Mustacchi SET_FLAGS(pdev->params.link.feature_config_flags, ELINK_FEATURE_CONFIG_BC_SUPPORTS_SFP_TX_DISABLED);
804*d14abf15SRobert Mustacchi }
805*d14abf15SRobert Mustacchi
806*d14abf15SRobert Mustacchi if (bc_rev >= REQ_BC_VER_4_MT_SUPPORTED)
807*d14abf15SRobert Mustacchi {
808*d14abf15SRobert Mustacchi SET_FLAGS(pdev->params.link.feature_config_flags, ELINK_FEATURE_CONFIG_MT_SUPPORT);
809*d14abf15SRobert Mustacchi }
810*d14abf15SRobert Mustacchi
811*d14abf15SRobert Mustacchi // regular MCP mode
812*d14abf15SRobert Mustacchi func_mb_id = pdev->params.pfunc_mb_id;
813*d14abf15SRobert Mustacchi
814*d14abf15SRobert Mustacchi // read first seq number from shared memory
815*d14abf15SRobert Mustacchi offset = OFFSETOF(shmem_region_t, func_mb[func_mb_id].drv_mb_header);
816*d14abf15SRobert Mustacchi LM_SHMEM_READ(pdev, offset, &val);
817*d14abf15SRobert Mustacchi pdev->vars.fw_wr_seq = (u16_t)(val & DRV_MSG_SEQ_NUMBER_MASK);
818*d14abf15SRobert Mustacchi
819*d14abf15SRobert Mustacchi // read current mcp_pulse value
820*d14abf15SRobert Mustacchi offset = OFFSETOF(shmem_region_t,func_mb[func_mb_id].mcp_pulse_mb) ;
821*d14abf15SRobert Mustacchi LM_SHMEM_READ(pdev, offset ,&val);
822*d14abf15SRobert Mustacchi pdev->vars.drv_pulse_wr_seq = (u16_t)(val & MCP_PULSE_SEQ_MASK);
823*d14abf15SRobert Mustacchi
824*d14abf15SRobert Mustacchi return LM_STATUS_SUCCESS;
825*d14abf15SRobert Mustacchi }
826*d14abf15SRobert Mustacchi
lm_mcp_set_mf_bw(struct _lm_device_t * pdev,IN u8_t min_bw,IN u8_t max_bw)827*d14abf15SRobert Mustacchi lm_status_t lm_mcp_set_mf_bw(struct _lm_device_t *pdev, IN u8_t min_bw, IN u8_t max_bw)
828*d14abf15SRobert Mustacchi {
829*d14abf15SRobert Mustacchi u32_t minmax_param = 0;
830*d14abf15SRobert Mustacchi u32_t resp = 0;
831*d14abf15SRobert Mustacchi lm_status_t lm_status = LM_STATUS_SUCCESS;
832*d14abf15SRobert Mustacchi const u32_t bc_rev = LM_GET_BC_REV_MAJOR(pdev);
833*d14abf15SRobert Mustacchi
834*d14abf15SRobert Mustacchi //if in no MCP mode, don't do anything
835*d14abf15SRobert Mustacchi if(!lm_is_mcp_detected(pdev))
836*d14abf15SRobert Mustacchi {
837*d14abf15SRobert Mustacchi DbgMessage(pdev, WARNmi, "No MCP detected.\n");
838*d14abf15SRobert Mustacchi return LM_STATUS_SUCCESS;
839*d14abf15SRobert Mustacchi }
840*d14abf15SRobert Mustacchi //if bootcode is less then REQ_BC_VER_4_SET_MF_BW, fail
841*d14abf15SRobert Mustacchi if( bc_rev < REQ_BC_VER_4_SET_MF_BW )
842*d14abf15SRobert Mustacchi {
843*d14abf15SRobert Mustacchi DbgMessage(pdev, WARNmi, "Invalid bootcode version.\n");
844*d14abf15SRobert Mustacchi return LM_STATUS_INVALID_PARAMETER;
845*d14abf15SRobert Mustacchi }
846*d14abf15SRobert Mustacchi //if not E2 or not MF mode, fail
847*d14abf15SRobert Mustacchi if(CHIP_IS_E1x(pdev) || !IS_MULTI_VNIC(pdev))
848*d14abf15SRobert Mustacchi {
849*d14abf15SRobert Mustacchi DbgMessage(pdev, WARNmi, "Device is E1/E1.5 or in SF mode.\n");
850*d14abf15SRobert Mustacchi return LM_STATUS_INVALID_PARAMETER;
851*d14abf15SRobert Mustacchi }
852*d14abf15SRobert Mustacchi //if the parameters are not valid, fail
853*d14abf15SRobert Mustacchi if (max_bw > 100)
854*d14abf15SRobert Mustacchi {
855*d14abf15SRobert Mustacchi DbgMessage(pdev, WARNmi, "Invalid parameters.\n");
856*d14abf15SRobert Mustacchi return LM_STATUS_INVALID_PARAMETER;
857*d14abf15SRobert Mustacchi }
858*d14abf15SRobert Mustacchi //build MCP command parameter from min_bw/max_bw
859*d14abf15SRobert Mustacchi //we use FUNC_MF_CFG_MIN_BW_SHIFT because the param structure is supposed to
860*d14abf15SRobert Mustacchi //be equivalent for this opcode and for the DCC opcode, but there is no define
861*d14abf15SRobert Mustacchi //for this opcode.
862*d14abf15SRobert Mustacchi ASSERT_STATIC(FUNC_MF_CFG_MIN_BW_MASK == DRV_MSG_CODE_SET_MF_BW_MIN_MASK);
863*d14abf15SRobert Mustacchi ASSERT_STATIC(FUNC_MF_CFG_MAX_BW_MASK == DRV_MSG_CODE_SET_MF_BW_MAX_MASK);
864*d14abf15SRobert Mustacchi minmax_param = (min_bw << FUNC_MF_CFG_MIN_BW_SHIFT)|
865*d14abf15SRobert Mustacchi (max_bw << FUNC_MF_CFG_MAX_BW_SHIFT);
866*d14abf15SRobert Mustacchi
867*d14abf15SRobert Mustacchi //call lm_mcp_cmd_send_recieve with DRV_MSG_CODE_SET_MF_BW opcode and the parameter
868*d14abf15SRobert Mustacchi lm_mcp_cmd_send_recieve(pdev, lm_mcp_mb_header, DRV_MSG_CODE_SET_MF_BW, minmax_param, MCP_CMD_DEFAULT_TIMEOUT, &resp);
869*d14abf15SRobert Mustacchi
870*d14abf15SRobert Mustacchi //make sure that the response is FW_MSG_CODE_SET_MF_BW_SENT
871*d14abf15SRobert Mustacchi if(resp != FW_MSG_CODE_SET_MF_BW_SENT)
872*d14abf15SRobert Mustacchi {
873*d14abf15SRobert Mustacchi DbgBreakIf(resp != FW_MSG_CODE_SET_MF_BW_SENT);
874*d14abf15SRobert Mustacchi return LM_STATUS_FAILURE;
875*d14abf15SRobert Mustacchi }
876*d14abf15SRobert Mustacchi
877*d14abf15SRobert Mustacchi //return what lm_mcp_cmd_send_recieve returned
878*d14abf15SRobert Mustacchi return lm_status;
879*d14abf15SRobert Mustacchi }
880*d14abf15SRobert Mustacchi
881*d14abf15SRobert Mustacchi /*
882*d14abf15SRobert Mustacchi *Function Name:lm_mcp_cmd_send
883*d14abf15SRobert Mustacchi *
884*d14abf15SRobert Mustacchi *Parameters:
885*d14abf15SRobert Mustacchi *
886*d14abf15SRobert Mustacchi *Description:
887*d14abf15SRobert Mustacchi * send
888*d14abf15SRobert Mustacchi *Returns:
889*d14abf15SRobert Mustacchi *
890*d14abf15SRobert Mustacchi */
lm_mcp_cmd_send(struct _lm_device_t * pdev,lm_mcp_mb_type mb_type,u32_t drv_msg,u32_t param)891*d14abf15SRobert Mustacchi lm_status_t lm_mcp_cmd_send( struct _lm_device_t *pdev, lm_mcp_mb_type mb_type, u32_t drv_msg, u32_t param )
892*d14abf15SRobert Mustacchi {
893*d14abf15SRobert Mustacchi u16_t* p_seq = NULL ;
894*d14abf15SRobert Mustacchi u32_t offset = 0 ;
895*d14abf15SRobert Mustacchi u32_t drv_mask = 0 ;
896*d14abf15SRobert Mustacchi const u8_t func_mb_id = pdev->params.pfunc_mb_id;
897*d14abf15SRobert Mustacchi
898*d14abf15SRobert Mustacchi DbgMessage(pdev, INFORMi , "### mcp_cmd_send mb_type=0x%x drv_msg=0x%x param=0x%x\n", mb_type, drv_msg, param );
899*d14abf15SRobert Mustacchi
900*d14abf15SRobert Mustacchi // we are on NO_MCP mode - nothing to do
901*d14abf15SRobert Mustacchi if( 0 != GET_FLAGS(pdev->params.test_mode, TEST_MODE_NO_MCP ) )
902*d14abf15SRobert Mustacchi {
903*d14abf15SRobert Mustacchi return LM_STATUS_SUCCESS ;
904*d14abf15SRobert Mustacchi }
905*d14abf15SRobert Mustacchi
906*d14abf15SRobert Mustacchi switch( mb_type )
907*d14abf15SRobert Mustacchi {
908*d14abf15SRobert Mustacchi case lm_mcp_mb_header:
909*d14abf15SRobert Mustacchi p_seq = &pdev->vars.fw_wr_seq ;
910*d14abf15SRobert Mustacchi drv_mask = DRV_MSG_SEQ_NUMBER_MASK ;
911*d14abf15SRobert Mustacchi offset = OFFSETOF(shmem_region_t, func_mb[func_mb_id].drv_mb_header) ;
912*d14abf15SRobert Mustacchi /* Write the parameter to the mcp */
913*d14abf15SRobert Mustacchi if (p_seq)
914*d14abf15SRobert Mustacchi {
915*d14abf15SRobert Mustacchi LM_SHMEM_WRITE(pdev,OFFSETOF(shmem_region_t, func_mb[func_mb_id].drv_mb_param),param);
916*d14abf15SRobert Mustacchi }
917*d14abf15SRobert Mustacchi break;
918*d14abf15SRobert Mustacchi
919*d14abf15SRobert Mustacchi case lm_mcp_mb_pulse:
920*d14abf15SRobert Mustacchi p_seq = &pdev->vars.drv_pulse_wr_seq ;
921*d14abf15SRobert Mustacchi drv_mask = DRV_PULSE_SEQ_MASK ;
922*d14abf15SRobert Mustacchi offset = OFFSETOF(shmem_region_t, func_mb[func_mb_id].mcp_pulse_mb) ;
923*d14abf15SRobert Mustacchi break;
924*d14abf15SRobert Mustacchi case lm_mcp_mb_param:
925*d14abf15SRobert Mustacchi default:
926*d14abf15SRobert Mustacchi break;
927*d14abf15SRobert Mustacchi }
928*d14abf15SRobert Mustacchi
929*d14abf15SRobert Mustacchi if CHK_NULL( p_seq )
930*d14abf15SRobert Mustacchi {
931*d14abf15SRobert Mustacchi return LM_STATUS_INVALID_PARAMETER ;
932*d14abf15SRobert Mustacchi }
933*d14abf15SRobert Mustacchi
934*d14abf15SRobert Mustacchi // incremant sequence
935*d14abf15SRobert Mustacchi ++(*p_seq);
936*d14abf15SRobert Mustacchi
937*d14abf15SRobert Mustacchi // prepare message
938*d14abf15SRobert Mustacchi drv_msg |= ( (*p_seq) & drv_mask );
939*d14abf15SRobert Mustacchi
940*d14abf15SRobert Mustacchi LM_SHMEM_WRITE(pdev,offset,drv_msg);
941*d14abf15SRobert Mustacchi
942*d14abf15SRobert Mustacchi DbgMessage(pdev, INFORMi , "mcp_cmd_send: Sent driver load cmd to MCP at 0x%x\n", drv_msg);
943*d14abf15SRobert Mustacchi
944*d14abf15SRobert Mustacchi return LM_STATUS_SUCCESS ;
945*d14abf15SRobert Mustacchi }
946*d14abf15SRobert Mustacchi
947*d14abf15SRobert Mustacchi /*
948*d14abf15SRobert Mustacchi *Function Name:lm_mcp_cmd_response
949*d14abf15SRobert Mustacchi *
950*d14abf15SRobert Mustacchi *Parameters:
951*d14abf15SRobert Mustacchi * TBD - add timeout value
952*d14abf15SRobert Mustacchi *Description:
953*d14abf15SRobert Mustacchi * assumption - only one request can be sent simultaneously
954*d14abf15SRobert Mustacchi *Returns:
955*d14abf15SRobert Mustacchi *
956*d14abf15SRobert Mustacchi */
lm_mcp_cmd_response(struct _lm_device_t * pdev,lm_mcp_mb_type mcp_mb_type,u32_t drv_msg,u32_t timeout,OUT u32_t * p_fw_resp)957*d14abf15SRobert Mustacchi lm_status_t lm_mcp_cmd_response( struct _lm_device_t *pdev,
958*d14abf15SRobert Mustacchi lm_mcp_mb_type mcp_mb_type,
959*d14abf15SRobert Mustacchi u32_t drv_msg,
960*d14abf15SRobert Mustacchi u32_t timeout,
961*d14abf15SRobert Mustacchi OUT u32_t* p_fw_resp )
962*d14abf15SRobert Mustacchi {
963*d14abf15SRobert Mustacchi u16_t* p_seq = NULL ;
964*d14abf15SRobert Mustacchi u32_t offset = 0 ;
965*d14abf15SRobert Mustacchi u32_t drv_mask = 0 ;
966*d14abf15SRobert Mustacchi u32_t fw_mask = 0 ;
967*d14abf15SRobert Mustacchi u32_t cnt = 0 ;
968*d14abf15SRobert Mustacchi u32_t wait_itr = 0 ;
969*d14abf15SRobert Mustacchi u32_t resp_mask = 0xffffffff ;
970*d14abf15SRobert Mustacchi lm_status_t lm_status = LM_STATUS_SUCCESS ;
971*d14abf15SRobert Mustacchi const u8_t func_mb_id = pdev->params.pfunc_mb_id;
972*d14abf15SRobert Mustacchi
973*d14abf15SRobert Mustacchi UNREFERENCED_PARAMETER_(timeout);
974*d14abf15SRobert Mustacchi
975*d14abf15SRobert Mustacchi DbgMessage(pdev, INFORMi, "### mcp_cmd_response mb_type=0x%x drv_msg=0x%x\n", mcp_mb_type, drv_msg );
976*d14abf15SRobert Mustacchi
977*d14abf15SRobert Mustacchi if ( CHK_NULL(p_fw_resp) )
978*d14abf15SRobert Mustacchi {
979*d14abf15SRobert Mustacchi return LM_STATUS_FAILURE ;
980*d14abf15SRobert Mustacchi }
981*d14abf15SRobert Mustacchi
982*d14abf15SRobert Mustacchi switch( mcp_mb_type )
983*d14abf15SRobert Mustacchi {
984*d14abf15SRobert Mustacchi case lm_mcp_mb_header:
985*d14abf15SRobert Mustacchi p_seq = &pdev->vars.fw_wr_seq ;
986*d14abf15SRobert Mustacchi drv_mask = DRV_MSG_SEQ_NUMBER_MASK ;
987*d14abf15SRobert Mustacchi fw_mask = FW_MSG_SEQ_NUMBER_MASK ;
988*d14abf15SRobert Mustacchi resp_mask = FW_MSG_CODE_MASK ;
989*d14abf15SRobert Mustacchi offset = OFFSETOF(shmem_region_t, func_mb[func_mb_id].fw_mb_header) ;
990*d14abf15SRobert Mustacchi break;
991*d14abf15SRobert Mustacchi
992*d14abf15SRobert Mustacchi // TBD - is it needed ??
993*d14abf15SRobert Mustacchi case lm_mcp_mb_pulse:
994*d14abf15SRobert Mustacchi p_seq = &pdev->vars.drv_pulse_wr_seq ;
995*d14abf15SRobert Mustacchi drv_mask = DRV_PULSE_SEQ_MASK ;
996*d14abf15SRobert Mustacchi fw_mask = MCP_PULSE_SEQ_MASK ;
997*d14abf15SRobert Mustacchi offset = OFFSETOF(shmem_region_t, func_mb[func_mb_id].mcp_pulse_mb) ;
998*d14abf15SRobert Mustacchi break;
999*d14abf15SRobert Mustacchi
1000*d14abf15SRobert Mustacchi case lm_mcp_mb_param:
1001*d14abf15SRobert Mustacchi default:
1002*d14abf15SRobert Mustacchi break;
1003*d14abf15SRobert Mustacchi }
1004*d14abf15SRobert Mustacchi
1005*d14abf15SRobert Mustacchi if CHK_NULL( p_seq )
1006*d14abf15SRobert Mustacchi {
1007*d14abf15SRobert Mustacchi return LM_STATUS_INVALID_PARAMETER ;
1008*d14abf15SRobert Mustacchi }
1009*d14abf15SRobert Mustacchi
1010*d14abf15SRobert Mustacchi lm_status = LM_STATUS_TIMEOUT ;
1011*d14abf15SRobert Mustacchi
1012*d14abf15SRobert Mustacchi // Wait for reply 5 sec per unloading function
1013*d14abf15SRobert Mustacchi //TODO exponential back off
1014*d14abf15SRobert Mustacchi wait_itr = 240 * FW_ACK_NUM_OF_POLL * PORT_MAX * (u32_t)(IS_MULTI_VNIC(pdev) ? MAX_VNIC_NUM : 1);
1015*d14abf15SRobert Mustacchi for(cnt = 0; cnt < wait_itr; cnt++)
1016*d14abf15SRobert Mustacchi {
1017*d14abf15SRobert Mustacchi mm_wait(pdev, FW_ACK_POLL_TIME_MS * 50);
1018*d14abf15SRobert Mustacchi
1019*d14abf15SRobert Mustacchi LM_SHMEM_READ(pdev, offset, p_fw_resp);
1020*d14abf15SRobert Mustacchi
1021*d14abf15SRobert Mustacchi if(( (*p_fw_resp) & fw_mask) == ( (*p_seq) & drv_mask))
1022*d14abf15SRobert Mustacchi {
1023*d14abf15SRobert Mustacchi lm_status = LM_STATUS_SUCCESS ;
1024*d14abf15SRobert Mustacchi break;
1025*d14abf15SRobert Mustacchi }
1026*d14abf15SRobert Mustacchi }
1027*d14abf15SRobert Mustacchi
1028*d14abf15SRobert Mustacchi *p_fw_resp = (*p_fw_resp & resp_mask);
1029*d14abf15SRobert Mustacchi
1030*d14abf15SRobert Mustacchi return lm_status ;
1031*d14abf15SRobert Mustacchi }
1032*d14abf15SRobert Mustacchi
lm_mcp_cmd_send_recieve_non_atomic(struct _lm_device_t * pdev,lm_mcp_mb_type mcp_mb_type,u32_t drv_msg,u32_t param,u32_t timeout,OUT u32_t * p_fw_resp)1033*d14abf15SRobert Mustacchi lm_status_t lm_mcp_cmd_send_recieve_non_atomic( struct _lm_device_t *pdev,
1034*d14abf15SRobert Mustacchi lm_mcp_mb_type mcp_mb_type,
1035*d14abf15SRobert Mustacchi u32_t drv_msg,
1036*d14abf15SRobert Mustacchi u32_t param,
1037*d14abf15SRobert Mustacchi u32_t timeout,
1038*d14abf15SRobert Mustacchi OUT u32_t* p_fw_resp )
1039*d14abf15SRobert Mustacchi {
1040*d14abf15SRobert Mustacchi lm_status_t lm_status = LM_STATUS_FAILURE;
1041*d14abf15SRobert Mustacchi u32_t val = 0;
1042*d14abf15SRobert Mustacchi
1043*d14abf15SRobert Mustacchi lm_status = lm_mcp_cmd_send( pdev, mcp_mb_type, drv_msg, param) ;
1044*d14abf15SRobert Mustacchi
1045*d14abf15SRobert Mustacchi if( LM_STATUS_SUCCESS != lm_status )
1046*d14abf15SRobert Mustacchi {
1047*d14abf15SRobert Mustacchi val = lm_mcp_check(pdev);
1048*d14abf15SRobert Mustacchi DbgMessage(pdev, FATAL, "mcp_cmd_send_and_recieve: mcp_cmd_send drv_msg=0x%x failed. lm_status=0x%x mcp_check=0x%x\n", drv_msg, lm_status, val);
1049*d14abf15SRobert Mustacchi DbgBreakMsg("mcp_cmd_send_and_recieve: mcp_cmd_send failed!\n");
1050*d14abf15SRobert Mustacchi return lm_status;
1051*d14abf15SRobert Mustacchi }
1052*d14abf15SRobert Mustacchi
1053*d14abf15SRobert Mustacchi DbgMessage(pdev, INFORMi , "mcp_cmd_send_and_recieve: Sent driver cmd=0x%x to MCP\n", drv_msg );
1054*d14abf15SRobert Mustacchi
1055*d14abf15SRobert Mustacchi lm_status = lm_mcp_cmd_response( pdev, mcp_mb_type, drv_msg, timeout, p_fw_resp ) ;
1056*d14abf15SRobert Mustacchi
1057*d14abf15SRobert Mustacchi if( LM_STATUS_SUCCESS != lm_status )
1058*d14abf15SRobert Mustacchi {
1059*d14abf15SRobert Mustacchi val = lm_mcp_check(pdev);
1060*d14abf15SRobert Mustacchi DbgMessage(pdev, FATAL, "mcp_cmd_send_and_recieve: mcp_cmd_response drv_msg=0x%x failed. lm_status=0x%x mcp_check=0x%x\n", drv_msg, lm_status, val);
1061*d14abf15SRobert Mustacchi DbgBreakMsg("mcp_cmd_send_and_recieve: mcp_cmd_response failed!\n");
1062*d14abf15SRobert Mustacchi return lm_status;
1063*d14abf15SRobert Mustacchi }
1064*d14abf15SRobert Mustacchi
1065*d14abf15SRobert Mustacchi DbgMessage(pdev, INFORMi , "mcp_cmd_send_and_recieve: Got response 0x%x from MCP\n", *p_fw_resp );
1066*d14abf15SRobert Mustacchi
1067*d14abf15SRobert Mustacchi return LM_STATUS_SUCCESS;
1068*d14abf15SRobert Mustacchi }
1069*d14abf15SRobert Mustacchi
1070*d14abf15SRobert Mustacchi /*
1071*d14abf15SRobert Mustacchi *Function Name:lm_mcp_cmd_send_recieve
1072*d14abf15SRobert Mustacchi *
1073*d14abf15SRobert Mustacchi *Parameters:
1074*d14abf15SRobert Mustacchi *
1075*d14abf15SRobert Mustacchi *Description:
1076*d14abf15SRobert Mustacchi *
1077*d14abf15SRobert Mustacchi *Returns: lm_status_t
1078*d14abf15SRobert Mustacchi *
1079*d14abf15SRobert Mustacchi */
lm_mcp_cmd_send_recieve(struct _lm_device_t * pdev,lm_mcp_mb_type mcp_mb_type,u32_t drv_msg,u32_t param,u32_t timeout,OUT u32_t * p_fw_resp)1080*d14abf15SRobert Mustacchi lm_status_t lm_mcp_cmd_send_recieve( struct _lm_device_t *pdev,
1081*d14abf15SRobert Mustacchi lm_mcp_mb_type mcp_mb_type,
1082*d14abf15SRobert Mustacchi u32_t drv_msg,
1083*d14abf15SRobert Mustacchi u32_t param,
1084*d14abf15SRobert Mustacchi u32_t timeout,
1085*d14abf15SRobert Mustacchi OUT u32_t* p_fw_resp )
1086*d14abf15SRobert Mustacchi {
1087*d14abf15SRobert Mustacchi lm_status_t lm_status = LM_STATUS_SUCCESS ;
1088*d14abf15SRobert Mustacchi
1089*d14abf15SRobert Mustacchi MM_ACQUIRE_MCP_LOCK(pdev);
1090*d14abf15SRobert Mustacchi
1091*d14abf15SRobert Mustacchi lm_status = lm_mcp_cmd_send_recieve_non_atomic(pdev, mcp_mb_type, drv_msg, param, timeout, p_fw_resp);
1092*d14abf15SRobert Mustacchi
1093*d14abf15SRobert Mustacchi MM_RELEASE_MCP_LOCK(pdev);
1094*d14abf15SRobert Mustacchi
1095*d14abf15SRobert Mustacchi return lm_status ;
1096*d14abf15SRobert Mustacchi }
1097*d14abf15SRobert Mustacchi
1098*d14abf15SRobert Mustacchi
1099*d14abf15SRobert Mustacchi // check if mcp program counter is advancing, In case it doesn't return the value in case it does, return 0
lm_mcp_check(struct _lm_device_t * pdev)1100*d14abf15SRobert Mustacchi u32_t lm_mcp_check( struct _lm_device_t *pdev)
1101*d14abf15SRobert Mustacchi {
1102*d14abf15SRobert Mustacchi static u32_t const offset = MCP_REG_MCPR_CPU_PROGRAM_COUNTER ;
1103*d14abf15SRobert Mustacchi u32_t reg = 0 ;
1104*d14abf15SRobert Mustacchi u32_t i = 0 ;
1105*d14abf15SRobert Mustacchi
1106*d14abf15SRobert Mustacchi reg = REG_RD(pdev, offset);
1107*d14abf15SRobert Mustacchi
1108*d14abf15SRobert Mustacchi for( i = 0; i<4; i++ )
1109*d14abf15SRobert Mustacchi {
1110*d14abf15SRobert Mustacchi if( REG_RD(pdev, offset) != reg )
1111*d14abf15SRobert Mustacchi {
1112*d14abf15SRobert Mustacchi return 0; // OK
1113*d14abf15SRobert Mustacchi }
1114*d14abf15SRobert Mustacchi }
1115*d14abf15SRobert Mustacchi return reg; // mcp is hang on this value as program counter!
1116*d14abf15SRobert Mustacchi }
1117*d14abf15SRobert Mustacchi
1118*d14abf15SRobert Mustacchi /**lm_mcp_cli_idx_to_drv_cap_flag
1119*d14abf15SRobert Mustacchi * Get the flag to set in drv_capabilities_flag for a given LM
1120*d14abf15SRobert Mustacchi * client.
1121*d14abf15SRobert Mustacchi *
1122*d14abf15SRobert Mustacchi * @param cli_id the LM client index.
1123*d14abf15SRobert Mustacchi *
1124*d14abf15SRobert Mustacchi * @return u32_t the appropriate flag for cli_id, or 0 if there
1125*d14abf15SRobert Mustacchi * is no matching flag.
1126*d14abf15SRobert Mustacchi */
lm_mcp_cli_idx_to_drv_cap_flag(IN const lm_cli_idx_t cli_id)1127*d14abf15SRobert Mustacchi static u32_t lm_mcp_cli_idx_to_drv_cap_flag(IN const lm_cli_idx_t cli_id)
1128*d14abf15SRobert Mustacchi {
1129*d14abf15SRobert Mustacchi switch(cli_id)
1130*d14abf15SRobert Mustacchi {
1131*d14abf15SRobert Mustacchi case LM_CLI_IDX_NDIS:
1132*d14abf15SRobert Mustacchi return DRV_FLAGS_CAPABILITIES_LOADED_L2;
1133*d14abf15SRobert Mustacchi case LM_CLI_IDX_ISCSI:
1134*d14abf15SRobert Mustacchi return DRV_FLAGS_CAPABILITIES_LOADED_ISCSI;
1135*d14abf15SRobert Mustacchi case LM_CLI_IDX_FCOE:
1136*d14abf15SRobert Mustacchi return DRV_FLAGS_CAPABILITIES_LOADED_FCOE;
1137*d14abf15SRobert Mustacchi case LM_CLI_IDX_MAX://may happen for UM clients that have no matching LM client, such as diag.
1138*d14abf15SRobert Mustacchi return 0;
1139*d14abf15SRobert Mustacchi case LM_CLI_IDX_FWD://fallthrough - this client has no bind/unbind flow and no matching UM client
1140*d14abf15SRobert Mustacchi case LM_CLI_IDX_OOO://fallthrough - this client has no bind/unbind flow and no matching UM client
1141*d14abf15SRobert Mustacchi default:
1142*d14abf15SRobert Mustacchi DbgBreakMsg("Invalid client type");
1143*d14abf15SRobert Mustacchi return 0;
1144*d14abf15SRobert Mustacchi }
1145*d14abf15SRobert Mustacchi }
1146*d14abf15SRobert Mustacchi
lm_mcp_indicate_client_imp(struct _lm_device_t * pdev,IN const lm_cli_idx_t cli_id,IN const u8_t b_bind)1147*d14abf15SRobert Mustacchi void lm_mcp_indicate_client_imp(struct _lm_device_t *pdev, IN const lm_cli_idx_t cli_id, IN const u8_t b_bind )
1148*d14abf15SRobert Mustacchi {
1149*d14abf15SRobert Mustacchi const u32_t drv_cap_client = lm_mcp_cli_idx_to_drv_cap_flag(cli_id);
1150*d14abf15SRobert Mustacchi const u32_t func_mb_id = FUNC_MAILBOX_ID(pdev);
1151*d14abf15SRobert Mustacchi const u32_t shmem_offset = OFFSETOF(shmem2_region_t, drv_capabilities_flag[func_mb_id]);
1152*d14abf15SRobert Mustacchi u32_t drv_cap_shmem = 0;
1153*d14abf15SRobert Mustacchi
1154*d14abf15SRobert Mustacchi if (CHIP_IS_E1x(pdev) ||
1155*d14abf15SRobert Mustacchi !LM_SHMEM2_HAS(pdev, drv_capabilities_flag))
1156*d14abf15SRobert Mustacchi {
1157*d14abf15SRobert Mustacchi return;
1158*d14abf15SRobert Mustacchi }
1159*d14abf15SRobert Mustacchi
1160*d14abf15SRobert Mustacchi if (0 == drv_cap_client)
1161*d14abf15SRobert Mustacchi {
1162*d14abf15SRobert Mustacchi //this is a client that does not require updating the SHMEM
1163*d14abf15SRobert Mustacchi return;
1164*d14abf15SRobert Mustacchi }
1165*d14abf15SRobert Mustacchi
1166*d14abf15SRobert Mustacchi LM_SHMEM2_READ(pdev, shmem_offset, &drv_cap_shmem);
1167*d14abf15SRobert Mustacchi
1168*d14abf15SRobert Mustacchi if( b_bind )
1169*d14abf15SRobert Mustacchi {
1170*d14abf15SRobert Mustacchi SET_FLAGS( drv_cap_shmem, drv_cap_client );
1171*d14abf15SRobert Mustacchi }
1172*d14abf15SRobert Mustacchi else
1173*d14abf15SRobert Mustacchi {
1174*d14abf15SRobert Mustacchi RESET_FLAGS( drv_cap_shmem, drv_cap_client );
1175*d14abf15SRobert Mustacchi }
1176*d14abf15SRobert Mustacchi
1177*d14abf15SRobert Mustacchi LM_SHMEM2_WRITE(pdev, shmem_offset, drv_cap_shmem);
1178*d14abf15SRobert Mustacchi }
1179*d14abf15SRobert Mustacchi
lm_mcp_indicate_client_bind(struct _lm_device_t * pdev,IN const lm_cli_idx_t cli_id)1180*d14abf15SRobert Mustacchi void lm_mcp_indicate_client_bind(struct _lm_device_t *pdev, IN const lm_cli_idx_t cli_id)
1181*d14abf15SRobert Mustacchi {
1182*d14abf15SRobert Mustacchi lm_mcp_indicate_client_imp(pdev, cli_id, TRUE);
1183*d14abf15SRobert Mustacchi }
1184*d14abf15SRobert Mustacchi
lm_mcp_indicate_client_unbind(struct _lm_device_t * pdev,IN const lm_cli_idx_t cli_id)1185*d14abf15SRobert Mustacchi void lm_mcp_indicate_client_unbind(struct _lm_device_t *pdev, IN const lm_cli_idx_t cli_id)
1186*d14abf15SRobert Mustacchi {
1187*d14abf15SRobert Mustacchi lm_mcp_indicate_client_imp(pdev, cli_id, FALSE);
1188*d14abf15SRobert Mustacchi }
1189