1 /*******************************************************************************
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  *
21  * Copyright 2014 QLogic Corporation
22  * The contents of this file are subject to the terms of the
23  * QLogic End User License (the "License").
24  * You may not use this file except in compliance with the License.
25  *
26  * You can obtain a copy of the License at
27  * http://www.qlogic.com/Resources/Documents/DriverDownloadHelp/
28  * QLogic_End_User_Software_License.txt
29  * See the License for the specific language governing permissions
30  * and limitations under the License.
31  *
32  *
33  * Module Description:
34  *
35  *
36  * History:
37  *    28/06/11 Shay Haroush    Inception.
38  ******************************************************************************/
39 
40 #include "lm5710.h"
41 #include "lm_dcbx_mp.h"
42 
43 /*******************************************************************************
44  * Constants.
45  ******************************************************************************/
46 #define MAX_NUM_OF_ACTIVE_ETH_CONS_PER_COS(_pdev)	LM_SB_CNT(_pdev)
47 #define ETH_CHAIN_COS0_START_OFFSET(_pdev)              (0)
48 #define ETH_CHAIN_COS1_START_OFFSET(_pdev)              (ETH_CHAIN_COS0_START_OFFSET(_pdev) + LM_SB_CNT(_pdev) + MAX_NON_RSS_CHAINS)
49 #define ETH_CHAIN_COS2_START_OFFSET(_pdev)              (ETH_CHAIN_COS1_START_OFFSET(_pdev) + LM_SB_CNT(_pdev))
50 
51 /*******************************************************************************
52  * Defines.
53  ******************************************************************************/
54 #define ETH_IS_CHAIN_IN_COS0_RANGE(_pdev, _chain)   ( lm_mp_eth_is_chain_in_cosx_range(_pdev, _chain, ETH_CHAIN_COS0_START_OFFSET(_pdev)))
55 #define ETH_IS_CHAIN_IN_COS1_RANGE(_pdev, _chain)   ( lm_mp_eth_is_chain_in_cosx_range(_pdev, _chain, ETH_CHAIN_COS1_START_OFFSET(_pdev)))
56 #define ETH_IS_CHAIN_IN_COS2_RANGE(_pdev, _chain)   ( lm_mp_eth_is_chain_in_cosx_range(_pdev, _chain, ETH_CHAIN_COS2_START_OFFSET(_pdev)))
57 #define ETH_CID_COSX_END_OFFSET(_pdev, _val)        (_val + MAX_NUM_OF_ACTIVE_ETH_CONS_PER_COS(pdev))
58 
59 /**
60  * @description
61  * Check if chain is in COS range based on COS start offset.
62  * @param chain
63  * @param cos_start_offset
64  *
65  * @return u8_t
66  */
67 STATIC u8_t
lm_mp_eth_is_chain_in_cosx_range(IN lm_device_t * pdev,IN const u32_t chain,IN const u32_t cos_start_offset)68 lm_mp_eth_is_chain_in_cosx_range(
69     IN lm_device_t  *pdev,
70     IN const u32_t  chain,
71     IN const u32_t  cos_start_offset)
72 {
73     if((cos_start_offset <= chain) &&
74       (chain < ETH_CID_COSX_END_OFFSET(pdev, cos_start_offset)))
75     {
76         return TRUE;
77     }
78     else
79     {
80         return FALSE;
81     }
82 }
83 /**
84  * @description
85  * Get COS number based on chain.
86  * If the chain doesn't belong to a specific COS (e.g. ISCSI L2
87  * chain)
88  * @param pdev
89  * @param chain
90  *
91  * @return u8_t
92  */
93 u8_t
lm_mp_cos_from_chain(IN struct _lm_device_t * pdev,IN const u32_t chain)94 lm_mp_cos_from_chain(IN struct _lm_device_t *pdev,
95                      IN const u32_t         chain)
96 {
97     // Cos 0 is the default
98     u8_t cos = ETH_MP_MAX_COS_SUPPORTED;
99 
100     if (ETH_IS_CHAIN_IN_COS0_RANGE(pdev, chain) )
101     {
102         cos = 0;
103     }
104     else if (ETH_IS_CHAIN_IN_COS1_RANGE(pdev, chain) )
105     {
106         cos = 1;
107     }
108     else if (ETH_IS_CHAIN_IN_COS2_RANGE(pdev, chain) )
109     {
110         cos = 2;
111     }
112     else
113     {
114         DbgMessage(pdev, INFORMi|INFORMl2sp, " lm_mp_cos_from_chain:  ");
115     }
116     return cos;
117 }
118 /**
119  * @description
120  * Return chain type.
121  * @param pdev
122  * @param chain
123  *
124  * @return lm_chain_type_t
125  */
126 lm_chain_type_t
lm_mp_get_chain_type(IN struct _lm_device_t * pdev,IN const u32_t chain)127 lm_mp_get_chain_type(IN struct _lm_device_t   *pdev,
128                      IN const u32_t           chain)
129 {
130     const u8_t cos = lm_mp_cos_from_chain(pdev, chain);
131 
132     if (0 == cos)
133     {
134         return lm_chain_type_cos_reg;
135     }
136     else if (cos < ETH_MP_MAX_COS_SUPPORTED)
137     {
138         return lm_chain_type_cos_tx_only;
139     }
140     else
141     {
142         return lm_chain_type_not_cos;
143     }
144 }
145 /**
146  * @description
147  * GET L2 chain COS start offset.
148  * @param pdev
149  * @param cos
150  *
151  * @return u8_t
152  */
153 STATIC u8_t
lm_mp_get_eth_chain_cosx_start_offset(IN struct _lm_device_t * pdev,IN const u8_t cos)154 lm_mp_get_eth_chain_cosx_start_offset(IN struct _lm_device_t    *pdev,
155                                       IN const u8_t             cos)
156 {
157     u8_t cosx_start_offset = 0;
158 
159     switch(cos)
160     {
161     case 0:
162         cosx_start_offset = ETH_CHAIN_COS0_START_OFFSET(pdev);
163         break;
164     case 1:
165         cosx_start_offset = ETH_CHAIN_COS1_START_OFFSET(pdev);
166         break;
167     case 2:
168         cosx_start_offset = ETH_CHAIN_COS2_START_OFFSET(pdev);
169         break;
170     default:
171         DbgBreakMsg("invalid cos");
172         cosx_start_offset = ETH_CHAIN_COS0_START_OFFSET(pdev);
173     }
174 
175     return cosx_start_offset;
176 }
177 /**
178  * @description
179  * Get regular chain from chain.
180  * If chain isn't a COS chain(e.g. ISCSI L2) than return
181  * original value.
182  * @param pdev
183  * @param chain
184  *
185  * @return u32_t
186  */
187 u32_t
lm_mp_get_reg_chain_from_chain(IN struct _lm_device_t * pdev,IN u32_t chain)188 lm_mp_get_reg_chain_from_chain(IN struct _lm_device_t   *pdev,
189                                IN u32_t                 chain)
190 {
191     const u8_t cos          = lm_mp_cos_from_chain(pdev, chain);
192     u8_t cosx_start_offset  = 0;
193 
194     if( cos >= ETH_MP_MAX_COS_SUPPORTED)
195     {
196         return chain;
197     }
198 
199     cosx_start_offset =
200         lm_mp_get_eth_chain_cosx_start_offset(pdev,cos);
201 
202     chain -= cosx_start_offset;
203 
204     return chain;
205 }
206 /**
207  * @description
208  * Get COS chain from regular chain.
209  * @param pdev
210  * @param chain
211  * @param cos
212  *
213  * @return u32_t
214  */
215 u8_t
lm_mp_get_cos_chain_from_reg_chain(IN struct _lm_device_t * pdev,INOUT u8_t chain,INOUT const u8_t cos)216 lm_mp_get_cos_chain_from_reg_chain(
217     IN struct _lm_device_t  *pdev,
218     INOUT u8_t              chain,
219     INOUT const u8_t        cos)
220 {
221     u8_t cosx_start_offset = 0;
222 
223     if( cos >= ETH_MP_MAX_COS_SUPPORTED)
224     {
225         return chain;
226     }
227 
228     cosx_start_offset =
229         lm_mp_get_eth_chain_cosx_start_offset(pdev,cos);
230 
231     chain += cosx_start_offset;
232 
233     return chain;
234 }
235 /**
236  * @description
237  * Get max cos chain used.
238  * @param pdev
239  *
240  * @return u32_t
241  */
242 u8_t
lm_mp_max_cos_chain_used(IN struct _lm_device_t * pdev)243 lm_mp_max_cos_chain_used(
244     IN struct _lm_device_t  *pdev)
245 {
246     const u8_t max_num_cos = lm_dcbx_cos_max_num(pdev);
247     const u8_t cosx_start_offset =
248         lm_mp_get_eth_chain_cosx_start_offset(pdev, max_num_cos -1);
249     const u8_t max_chain_used = ETH_CID_COSX_END_OFFSET(pdev, cosx_start_offset);
250 
251     DbgBreakIf(FALSE == MM_DCB_MP_L2_IS_ENABLE(pdev));
252     DbgBreakIf(1 == max_num_cos);
253 
254     return max_chain_used;
255 }
256