38a4493670babd9c48dbc749303ac327a296b731
[deb_dpdk.git] / drivers / net / ixgbe / ixgbe_bypass.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 #include <time.h>
35 #include <rte_atomic.h>
36 #include <rte_ethdev.h>
37 #include "ixgbe_ethdev.h"
38 #include "ixgbe_bypass_api.h"
39 #include "rte_pmd_ixgbe.h"
40
41 #define BYPASS_STATUS_OFF_MASK  3
42
43 /* Macros to check for invlaid function pointers. */
44 #define FUNC_PTR_OR_ERR_RET(func, retval) do {              \
45         if ((func) == NULL) {                               \
46                 PMD_DRV_LOG(ERR, "%s:%d function not supported", \
47                             __func__, __LINE__);            \
48                 return retval;                            \
49         }                                                   \
50 } while (0)
51
52 #define FUNC_PTR_OR_RET(func) do {                          \
53         if ((func) == NULL) {                               \
54                 PMD_DRV_LOG(ERR, "%s:%d function not supported", \
55                             __func__, __LINE__);            \
56                 return;                                     \
57         }                                                   \
58 } while (0)
59
60
61 /**
62  *  ixgbe_bypass_set_time - Set bypass FW time epoc.
63  *
64  *  @hw: pointer to hardware structure
65  *
66  *  This function with sync the FW date stamp with that of the
67  *  system clock.
68  **/
69 static void
70 ixgbe_bypass_set_time(struct ixgbe_adapter *adapter)
71 {
72         u32 mask, value;
73         u32 sec;
74         struct ixgbe_hw *hw = &adapter->hw;
75
76         sec = 0;
77
78         /*
79          * Send the FW our current time and turn on time_valid and
80          * timer_reset bits.
81          */
82         mask = BYPASS_CTL1_TIME_M |
83                BYPASS_CTL1_VALID_M |
84                BYPASS_CTL1_OFFTRST_M;
85         value = (sec & BYPASS_CTL1_TIME_M) |
86                 BYPASS_CTL1_VALID |
87                 BYPASS_CTL1_OFFTRST;
88
89         FUNC_PTR_OR_RET(adapter->bps.ops.bypass_set);
90
91         /* Store FW reset time (in seconds from epoch). */
92         adapter->bps.reset_tm = time(NULL);
93
94         /* reset FW timer. */
95         adapter->bps.ops.bypass_set(hw, BYPASS_PAGE_CTL1, mask, value);
96 }
97
98 /**
99  * ixgbe_bypass_init - Make some environment changes for bypass
100  *
101  * @adapter: pointer to ixgbe_adapter structure for access to state bits
102  *
103  * This function collects all the modifications needed by the bypass
104  * driver.
105  **/
106 void
107 ixgbe_bypass_init(struct rte_eth_dev *dev)
108 {
109         struct ixgbe_adapter *adapter;
110         struct ixgbe_hw *hw;
111
112         adapter = IXGBE_DEV_TO_ADPATER(dev);
113         hw = &adapter->hw;
114
115         /* Only allow BYPASS ops on the first port */
116         if (hw->device_id != IXGBE_DEV_ID_82599_BYPASS ||
117                         hw->bus.func != 0) {
118                 PMD_DRV_LOG(ERR, "bypass function is not supported on that device");
119                 return;
120         }
121
122         /* set bypass ops. */
123         adapter->bps.ops.bypass_rw = &ixgbe_bypass_rw_generic;
124         adapter->bps.ops.bypass_valid_rd = &ixgbe_bypass_valid_rd_generic;
125         adapter->bps.ops.bypass_set = &ixgbe_bypass_set_generic;
126         adapter->bps.ops.bypass_rd_eep = &ixgbe_bypass_rd_eep_generic;
127
128         /* set the time for logging. */
129         ixgbe_bypass_set_time(adapter);
130
131         /* Don't have the SDP to the laser */
132         hw->mac.ops.disable_tx_laser = NULL;
133         hw->mac.ops.enable_tx_laser = NULL;
134         hw->mac.ops.flap_tx_laser = NULL;
135 }
136
137 s32
138 ixgbe_bypass_state_show(struct rte_eth_dev *dev, u32 *state)
139 {
140         struct ixgbe_hw *hw;
141         s32 ret_val;
142         u32 cmd;
143         u32 by_ctl = 0;
144         struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
145
146         hw = &adapter->hw;
147         FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_rw, -ENOTSUP);
148
149         cmd = BYPASS_PAGE_CTL0;
150         ret_val = adapter->bps.ops.bypass_rw(hw, cmd, &by_ctl);
151
152         /* Assume bypass_rw didn't error out, if it did state will
153          * be ignored anyway.
154          */
155         *state = (by_ctl >> BYPASS_STATUS_OFF_SHIFT) &  BYPASS_STATUS_OFF_MASK;
156
157         return ret_val;
158 }
159
160
161 s32
162 ixgbe_bypass_state_store(struct rte_eth_dev *dev, u32 *new_state)
163 {
164         struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
165         struct ixgbe_hw *hw;
166         s32 ret_val;
167
168         hw = &adapter->hw;
169         FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_set, -ENOTSUP);
170
171         /* Set the new state */
172         ret_val = adapter->bps.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
173                                          BYPASS_MODE_OFF_M, *new_state);
174         if (ret_val)
175                 goto exit;
176
177         /* Set AUTO back on so FW can receive events */
178         ret_val = adapter->bps.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
179                                          BYPASS_MODE_OFF_M, BYPASS_AUTO);
180
181 exit:
182         return ret_val;
183
184 }
185
186 s32
187 ixgbe_bypass_event_show(struct rte_eth_dev *dev, u32 event,
188                             u32 *state)
189 {
190         struct ixgbe_hw *hw;
191         s32 ret_val;
192         u32 shift;
193         u32 cmd;
194         u32 by_ctl = 0;
195         struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
196
197         hw = &adapter->hw;
198         FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_rw, -ENOTSUP);
199
200         cmd = BYPASS_PAGE_CTL0;
201         ret_val = adapter->bps.ops.bypass_rw(hw, cmd, &by_ctl);
202
203         /* Assume bypass_rw didn't error out, if it did event will
204          * be ignored anyway.
205          */
206         switch (event) {
207         case BYPASS_EVENT_WDT_TO:
208                 shift = BYPASS_WDTIMEOUT_SHIFT;
209                 break;
210         case BYPASS_EVENT_MAIN_ON:
211                 shift = BYPASS_MAIN_ON_SHIFT;
212                 break;
213         case BYPASS_EVENT_MAIN_OFF:
214                 shift = BYPASS_MAIN_OFF_SHIFT;
215                 break;
216         case BYPASS_EVENT_AUX_ON:
217                 shift = BYPASS_AUX_ON_SHIFT;
218                 break;
219         case BYPASS_EVENT_AUX_OFF:
220                 shift = BYPASS_AUX_OFF_SHIFT;
221                 break;
222         default:
223                 return EINVAL;
224         }
225
226         *state = (by_ctl >> shift) & 0x3;
227
228         return ret_val;
229 }
230
231 s32
232 ixgbe_bypass_event_store(struct rte_eth_dev *dev, u32 event,
233                              u32 state)
234 {
235         struct ixgbe_hw *hw;
236         u32 status;
237         u32 off;
238         s32 ret_val;
239         struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
240
241         hw = &adapter->hw;
242         FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_set, -ENOTSUP);
243
244         switch (event) {
245         case BYPASS_EVENT_WDT_TO:
246                 off = BYPASS_WDTIMEOUT_M;
247                 status = state << BYPASS_WDTIMEOUT_SHIFT;
248                 break;
249         case BYPASS_EVENT_MAIN_ON:
250                 off = BYPASS_MAIN_ON_M;
251                 status = state << BYPASS_MAIN_ON_SHIFT;
252                 break;
253         case BYPASS_EVENT_MAIN_OFF:
254                 off = BYPASS_MAIN_OFF_M;
255                 status = state << BYPASS_MAIN_OFF_SHIFT;
256                 break;
257         case BYPASS_EVENT_AUX_ON:
258                 off = BYPASS_AUX_ON_M;
259                 status = state << BYPASS_AUX_ON_SHIFT;
260                 break;
261         case BYPASS_EVENT_AUX_OFF:
262                 off = BYPASS_AUX_OFF_M;
263                 status = state << BYPASS_AUX_OFF_SHIFT;
264                 break;
265         default:
266                 return EINVAL;
267         }
268
269         ret_val = adapter->bps.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
270                 off, status);
271
272         return ret_val;
273 }
274
275 s32
276 ixgbe_bypass_wd_timeout_store(struct rte_eth_dev *dev, u32 timeout)
277 {
278         struct ixgbe_hw *hw;
279         u32 status;
280         u32 mask;
281         s32 ret_val;
282         struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
283
284         hw = &adapter->hw;
285         FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_set, -ENOTSUP);
286
287         /* disable the timer with timeout of zero */
288         if (timeout == RTE_PMD_IXGBE_BYPASS_TMT_OFF) {
289                 status = 0x0;   /* WDG enable off */
290                 mask = BYPASS_WDT_ENABLE_M;
291         } else {
292                 /* set time out value */
293                 mask = BYPASS_WDT_VALUE_M;
294
295                 /* enable the timer */
296                 status = timeout << BYPASS_WDT_TIME_SHIFT;
297                 status |= 0x1 << BYPASS_WDT_ENABLE_SHIFT;
298                 mask |= BYPASS_WDT_ENABLE_M;
299         }
300
301         ret_val = adapter->bps.ops.bypass_set(hw, BYPASS_PAGE_CTL0,
302                 mask, status);
303
304         return ret_val;
305 }
306
307 s32
308 ixgbe_bypass_ver_show(struct rte_eth_dev *dev, u32 *ver)
309 {
310         struct ixgbe_hw *hw;
311         u32 cmd;
312         u32 status;
313         s32 ret_val;
314         struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
315
316         hw = &adapter->hw;
317         FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_rw, -ENOTSUP);
318
319         cmd = BYPASS_PAGE_CTL2 | BYPASS_WE;
320         cmd |= (BYPASS_EEPROM_VER_ADD << BYPASS_CTL2_OFFSET_SHIFT) &
321                BYPASS_CTL2_OFFSET_M;
322         ret_val = adapter->bps.ops.bypass_rw(hw, cmd, &status);
323         if (ret_val)
324                 goto exit;
325
326         /* wait for the write to stick */
327         msleep(100);
328
329         /* Now read the results */
330         cmd &= ~BYPASS_WE;
331         ret_val = adapter->bps.ops.bypass_rw(hw, cmd, &status);
332         if (ret_val)
333                 goto exit;
334
335         *ver = status & BYPASS_CTL2_DATA_M;      /* only one byte of date */
336
337 exit:
338         return ret_val;
339 }
340
341 s32
342 ixgbe_bypass_wd_timeout_show(struct rte_eth_dev *dev, u32 *wd_timeout)
343 {
344         struct ixgbe_hw *hw;
345         u32 by_ctl = 0;
346         u32 cmd;
347         u32 wdg;
348         s32 ret_val;
349         struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
350
351         hw = &adapter->hw;
352         FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_rw, -ENOTSUP);
353
354         cmd = BYPASS_PAGE_CTL0;
355         ret_val = adapter->bps.ops.bypass_rw(hw, cmd, &by_ctl);
356
357         wdg = by_ctl & BYPASS_WDT_ENABLE_M;
358         if (!wdg)
359                 *wd_timeout = RTE_PMD_IXGBE_BYPASS_TMT_OFF;
360         else
361                 *wd_timeout = (by_ctl >> BYPASS_WDT_TIME_SHIFT) &
362                         BYPASS_WDT_MASK;
363
364         return ret_val;
365 }
366
367 s32
368 ixgbe_bypass_wd_reset(struct rte_eth_dev *dev)
369 {
370         u32 cmd;
371         u32 status;
372         u32 sec;
373         u32 count = 0;
374         s32 ret_val;
375         struct ixgbe_hw *hw;
376         struct ixgbe_adapter *adapter = IXGBE_DEV_TO_ADPATER(dev);
377
378         hw = &adapter->hw;
379
380         FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_rw, -ENOTSUP);
381         FUNC_PTR_OR_ERR_RET(adapter->bps.ops.bypass_valid_rd, -ENOTSUP);
382
383         /* Use the lower level bit-bang functions since we don't need
384          * to read the register first to get it's current state as we
385          * are setting every thing in this write.
386          */
387         /* Set up WD pet */
388         cmd = BYPASS_PAGE_CTL1 | BYPASS_WE | BYPASS_CTL1_WDT_PET;
389
390         /* Resync the FW time while writing to CTL1 anyway */
391         adapter->bps.reset_tm = time(NULL);
392         sec = 0;
393
394         cmd |= (sec & BYPASS_CTL1_TIME_M) | BYPASS_CTL1_VALID;
395
396         /* reset FW timer offset since we are resetting the clock */
397         cmd |= BYPASS_CTL1_OFFTRST;
398
399         ret_val = adapter->bps.ops.bypass_rw(hw, cmd, &status);
400
401         /* Read until it matches what we wrote, or we time out */
402         do {
403                 if (count++ > 10) {
404                         ret_val = IXGBE_BYPASS_FW_WRITE_FAILURE;
405                         break;
406                 }
407
408                 if (adapter->bps.ops.bypass_rw(hw, BYPASS_PAGE_CTL1, &status)) {
409                         ret_val = IXGBE_ERR_INVALID_ARGUMENT;
410                         break;
411                 }
412         } while (!adapter->bps.ops.bypass_valid_rd(cmd, status));
413
414         return ret_val;
415 }