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