Merge tag 'reset-for-v5.3' of git://git.pengutronix.de/git/pza/linux into arm/drivers
[sfrench/cifs-2.6.git] / drivers / net / ethernet / oki-semi / pch_gbe / pch_gbe_param.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 1999 - 2010 Intel Corporation.
4  * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD.
5  *
6  * This code was derived from the Intel e1000e Linux driver.
7  */
8
9 #include "pch_gbe.h"
10 #include <linux/module.h>       /* for __MODULE_STRING */
11
12 #define OPTION_UNSET   -1
13 #define OPTION_DISABLED 0
14 #define OPTION_ENABLED  1
15
16 /**
17  * TxDescriptors - Transmit Descriptor Count
18  * @Valid Range:   PCH_GBE_MIN_TXD - PCH_GBE_MAX_TXD
19  * @Default Value: PCH_GBE_DEFAULT_TXD
20  */
21 static int TxDescriptors = OPTION_UNSET;
22 module_param(TxDescriptors, int, 0);
23 MODULE_PARM_DESC(TxDescriptors, "Number of transmit descriptors");
24
25 /**
26  * RxDescriptors -Receive Descriptor Count
27  * @Valid Range:   PCH_GBE_MIN_RXD - PCH_GBE_MAX_RXD
28  * @Default Value: PCH_GBE_DEFAULT_RXD
29  */
30 static int RxDescriptors = OPTION_UNSET;
31 module_param(RxDescriptors, int, 0);
32 MODULE_PARM_DESC(RxDescriptors, "Number of receive descriptors");
33
34 /**
35  * Speed - User Specified Speed Override
36  * @Valid Range: 0, 10, 100, 1000
37  *   - 0:    auto-negotiate at all supported speeds
38  *   - 10:   only link at 10 Mbps
39  *   - 100:  only link at 100 Mbps
40  *   - 1000: only link at 1000 Mbps
41  * @Default Value: 0
42  */
43 static int Speed = OPTION_UNSET;
44 module_param(Speed, int, 0);
45 MODULE_PARM_DESC(Speed, "Speed setting");
46
47 /**
48  * Duplex - User Specified Duplex Override
49  * @Valid Range: 0-2
50  *   - 0:  auto-negotiate for duplex
51  *   - 1:  only link at half duplex
52  *   - 2:  only link at full duplex
53  * @Default Value: 0
54  */
55 static int Duplex = OPTION_UNSET;
56 module_param(Duplex, int, 0);
57 MODULE_PARM_DESC(Duplex, "Duplex setting");
58
59 #define HALF_DUPLEX 1
60 #define FULL_DUPLEX 2
61
62 /**
63  * AutoNeg - Auto-negotiation Advertisement Override
64  * @Valid Range: 0x01-0x0F, 0x20-0x2F
65  *
66  *       The AutoNeg value is a bit mask describing which speed and duplex
67  *       combinations should be advertised during auto-negotiation.
68  *       The supported speed and duplex modes are listed below
69  *
70  *       Bit           7     6     5      4      3     2     1      0
71  *       Speed (Mbps)  N/A   N/A   1000   N/A    100   100   10     10
72  *       Duplex                    Full          Full  Half  Full   Half
73  *
74  * @Default Value: 0x2F (copper)
75  */
76 static int AutoNeg = OPTION_UNSET;
77 module_param(AutoNeg, int, 0);
78 MODULE_PARM_DESC(AutoNeg, "Advertised auto-negotiation setting");
79
80 #define PHY_ADVERTISE_10_HALF      0x0001
81 #define PHY_ADVERTISE_10_FULL      0x0002
82 #define PHY_ADVERTISE_100_HALF     0x0004
83 #define PHY_ADVERTISE_100_FULL     0x0008
84 #define PHY_ADVERTISE_1000_HALF    0x0010 /* Not used, just FYI */
85 #define PHY_ADVERTISE_1000_FULL    0x0020
86 #define PCH_AUTONEG_ADVERTISE_DEFAULT   0x2F
87
88 /**
89  * FlowControl - User Specified Flow Control Override
90  * @Valid Range: 0-3
91  *    - 0:  No Flow Control
92  *    - 1:  Rx only, respond to PAUSE frames but do not generate them
93  *    - 2:  Tx only, generate PAUSE frames but ignore them on receive
94  *    - 3:  Full Flow Control Support
95  * @Default Value: Read flow control settings from the EEPROM
96  */
97 static int FlowControl = OPTION_UNSET;
98 module_param(FlowControl, int, 0);
99 MODULE_PARM_DESC(FlowControl, "Flow Control setting");
100
101 /*
102  * XsumRX - Receive Checksum Offload Enable/Disable
103  * @Valid Range: 0, 1
104  *    - 0:  disables all checksum offload
105  *    - 1:  enables receive IP/TCP/UDP checksum offload
106  * @Default Value: PCH_GBE_DEFAULT_RX_CSUM
107  */
108 static int XsumRX = OPTION_UNSET;
109 module_param(XsumRX, int, 0);
110 MODULE_PARM_DESC(XsumRX, "Disable or enable Receive Checksum offload");
111
112 #define PCH_GBE_DEFAULT_RX_CSUM             true        /* trueorfalse */
113
114 /*
115  * XsumTX - Transmit Checksum Offload Enable/Disable
116  * @Valid Range: 0, 1
117  *    - 0:  disables all checksum offload
118  *    - 1:  enables transmit IP/TCP/UDP checksum offload
119  * @Default Value: PCH_GBE_DEFAULT_TX_CSUM
120  */
121 static int XsumTX = OPTION_UNSET;
122 module_param(XsumTX, int, 0);
123 MODULE_PARM_DESC(XsumTX, "Disable or enable Transmit Checksum offload");
124
125 #define PCH_GBE_DEFAULT_TX_CSUM             true        /* trueorfalse */
126
127 /**
128  * pch_gbe_option - Force the MAC's flow control settings
129  * @hw:             Pointer to the HW structure
130  * Returns:
131  *      0:                      Successful.
132  *      Negative value:         Failed.
133  */
134 struct pch_gbe_option {
135         enum { enable_option, range_option, list_option } type;
136         char *name;
137         char *err;
138         int  def;
139         union {
140                 struct { /* range_option info */
141                         int min;
142                         int max;
143                 } r;
144                 struct { /* list_option info */
145                         int nr;
146                         const struct pch_gbe_opt_list { int i; char *str; } *p;
147                 } l;
148         } arg;
149 };
150
151 static const struct pch_gbe_opt_list speed_list[] = {
152         { 0, "" },
153         { SPEED_10, "" },
154         { SPEED_100, "" },
155         { SPEED_1000, "" }
156 };
157
158 static const struct pch_gbe_opt_list dplx_list[] = {
159         { 0, "" },
160         { HALF_DUPLEX, "" },
161         { FULL_DUPLEX, "" }
162 };
163
164 static const struct pch_gbe_opt_list an_list[] =
165         #define AA "AutoNeg advertising "
166         {{ 0x01, AA "10/HD" },
167          { 0x02, AA "10/FD" },
168          { 0x03, AA "10/FD, 10/HD" },
169          { 0x04, AA "100/HD" },
170          { 0x05, AA "100/HD, 10/HD" },
171          { 0x06, AA "100/HD, 10/FD" },
172          { 0x07, AA "100/HD, 10/FD, 10/HD" },
173          { 0x08, AA "100/FD" },
174          { 0x09, AA "100/FD, 10/HD" },
175          { 0x0a, AA "100/FD, 10/FD" },
176          { 0x0b, AA "100/FD, 10/FD, 10/HD" },
177          { 0x0c, AA "100/FD, 100/HD" },
178          { 0x0d, AA "100/FD, 100/HD, 10/HD" },
179          { 0x0e, AA "100/FD, 100/HD, 10/FD" },
180          { 0x0f, AA "100/FD, 100/HD, 10/FD, 10/HD" },
181          { 0x20, AA "1000/FD" },
182          { 0x21, AA "1000/FD, 10/HD" },
183          { 0x22, AA "1000/FD, 10/FD" },
184          { 0x23, AA "1000/FD, 10/FD, 10/HD" },
185          { 0x24, AA "1000/FD, 100/HD" },
186          { 0x25, AA "1000/FD, 100/HD, 10/HD" },
187          { 0x26, AA "1000/FD, 100/HD, 10/FD" },
188          { 0x27, AA "1000/FD, 100/HD, 10/FD, 10/HD" },
189          { 0x28, AA "1000/FD, 100/FD" },
190          { 0x29, AA "1000/FD, 100/FD, 10/HD" },
191          { 0x2a, AA "1000/FD, 100/FD, 10/FD" },
192          { 0x2b, AA "1000/FD, 100/FD, 10/FD, 10/HD" },
193          { 0x2c, AA "1000/FD, 100/FD, 100/HD" },
194          { 0x2d, AA "1000/FD, 100/FD, 100/HD, 10/HD" },
195          { 0x2e, AA "1000/FD, 100/FD, 100/HD, 10/FD" },
196          { 0x2f, AA "1000/FD, 100/FD, 100/HD, 10/FD, 10/HD" }
197 };
198
199 static const struct pch_gbe_opt_list fc_list[] = {
200         { PCH_GBE_FC_NONE, "Flow Control Disabled" },
201         { PCH_GBE_FC_RX_PAUSE, "Flow Control Receive Only" },
202         { PCH_GBE_FC_TX_PAUSE, "Flow Control Transmit Only" },
203         { PCH_GBE_FC_FULL, "Flow Control Enabled" }
204 };
205
206 /**
207  * pch_gbe_validate_option - Validate option
208  * @value:    value
209  * @opt:      option
210  * @adapter:  Board private structure
211  * Returns:
212  *      0:                      Successful.
213  *      Negative value:         Failed.
214  */
215 static int pch_gbe_validate_option(int *value,
216                                     const struct pch_gbe_option *opt,
217                                     struct pch_gbe_adapter *adapter)
218 {
219         if (*value == OPTION_UNSET) {
220                 *value = opt->def;
221                 return 0;
222         }
223
224         switch (opt->type) {
225         case enable_option:
226                 switch (*value) {
227                 case OPTION_ENABLED:
228                         netdev_dbg(adapter->netdev, "%s Enabled\n", opt->name);
229                         return 0;
230                 case OPTION_DISABLED:
231                         netdev_dbg(adapter->netdev, "%s Disabled\n", opt->name);
232                         return 0;
233                 }
234                 break;
235         case range_option:
236                 if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) {
237                         netdev_dbg(adapter->netdev, "%s set to %i\n",
238                                    opt->name, *value);
239                         return 0;
240                 }
241                 break;
242         case list_option: {
243                 int i;
244                 const struct pch_gbe_opt_list *ent;
245
246                 for (i = 0; i < opt->arg.l.nr; i++) {
247                         ent = &opt->arg.l.p[i];
248                         if (*value == ent->i) {
249                                 if (ent->str[0] != '\0')
250                                         netdev_dbg(adapter->netdev, "%s\n",
251                                                    ent->str);
252                                 return 0;
253                         }
254                 }
255         }
256                 break;
257         default:
258                 BUG();
259         }
260
261         netdev_dbg(adapter->netdev, "Invalid %s value specified (%i) %s\n",
262                    opt->name, *value, opt->err);
263         *value = opt->def;
264         return -1;
265 }
266
267 /**
268  * pch_gbe_check_copper_options - Range Checking for Link Options, Copper Version
269  * @adapter:  Board private structure
270  */
271 static void pch_gbe_check_copper_options(struct pch_gbe_adapter *adapter)
272 {
273         struct pch_gbe_hw *hw = &adapter->hw;
274         int speed, dplx;
275
276         { /* Speed */
277                 static const struct pch_gbe_option opt = {
278                         .type = list_option,
279                         .name = "Speed",
280                         .err  = "parameter ignored",
281                         .def  = 0,
282                         .arg  = { .l = { .nr = (int)ARRAY_SIZE(speed_list),
283                                          .p = speed_list } }
284                 };
285                 speed = Speed;
286                 pch_gbe_validate_option(&speed, &opt, adapter);
287         }
288         { /* Duplex */
289                 static const struct pch_gbe_option opt = {
290                         .type = list_option,
291                         .name = "Duplex",
292                         .err  = "parameter ignored",
293                         .def  = 0,
294                         .arg  = { .l = { .nr = (int)ARRAY_SIZE(dplx_list),
295                                          .p = dplx_list } }
296                 };
297                 dplx = Duplex;
298                 pch_gbe_validate_option(&dplx, &opt, adapter);
299         }
300
301         { /* Autoneg */
302                 static const struct pch_gbe_option opt = {
303                         .type = list_option,
304                         .name = "AutoNeg",
305                         .err  = "parameter ignored",
306                         .def  = PCH_AUTONEG_ADVERTISE_DEFAULT,
307                         .arg  = { .l = { .nr = (int)ARRAY_SIZE(an_list),
308                                          .p = an_list} }
309                 };
310                 if (speed || dplx) {
311                         netdev_dbg(adapter->netdev,
312                                    "AutoNeg specified along with Speed or Duplex, AutoNeg parameter ignored\n");
313                         hw->phy.autoneg_advertised = opt.def;
314                 } else {
315                         int tmp = AutoNeg;
316
317                         pch_gbe_validate_option(&tmp, &opt, adapter);
318                         hw->phy.autoneg_advertised = tmp;
319                 }
320         }
321
322         switch (speed + dplx) {
323         case 0:
324                 hw->mac.autoneg = hw->mac.fc_autoneg = 1;
325                 if ((speed || dplx))
326                         netdev_dbg(adapter->netdev,
327                                    "Speed and duplex autonegotiation enabled\n");
328                 hw->mac.link_speed = SPEED_10;
329                 hw->mac.link_duplex = DUPLEX_HALF;
330                 break;
331         case HALF_DUPLEX:
332                 netdev_dbg(adapter->netdev,
333                            "Half Duplex specified without Speed\n");
334                 netdev_dbg(adapter->netdev,
335                            "Using Autonegotiation at Half Duplex only\n");
336                 hw->mac.autoneg = hw->mac.fc_autoneg = 1;
337                 hw->phy.autoneg_advertised = PHY_ADVERTISE_10_HALF |
338                                                 PHY_ADVERTISE_100_HALF;
339                 hw->mac.link_speed = SPEED_10;
340                 hw->mac.link_duplex = DUPLEX_HALF;
341                 break;
342         case FULL_DUPLEX:
343                 netdev_dbg(adapter->netdev,
344                            "Full Duplex specified without Speed\n");
345                 netdev_dbg(adapter->netdev,
346                            "Using Autonegotiation at Full Duplex only\n");
347                 hw->mac.autoneg = hw->mac.fc_autoneg = 1;
348                 hw->phy.autoneg_advertised = PHY_ADVERTISE_10_FULL |
349                                                 PHY_ADVERTISE_100_FULL |
350                                                 PHY_ADVERTISE_1000_FULL;
351                 hw->mac.link_speed = SPEED_10;
352                 hw->mac.link_duplex = DUPLEX_FULL;
353                 break;
354         case SPEED_10:
355                 netdev_dbg(adapter->netdev,
356                            "10 Mbps Speed specified without Duplex\n");
357                 netdev_dbg(adapter->netdev,
358                            "Using Autonegotiation at 10 Mbps only\n");
359                 hw->mac.autoneg = hw->mac.fc_autoneg = 1;
360                 hw->phy.autoneg_advertised = PHY_ADVERTISE_10_HALF |
361                                                 PHY_ADVERTISE_10_FULL;
362                 hw->mac.link_speed = SPEED_10;
363                 hw->mac.link_duplex = DUPLEX_HALF;
364                 break;
365         case SPEED_10 + HALF_DUPLEX:
366                 netdev_dbg(adapter->netdev, "Forcing to 10 Mbps Half Duplex\n");
367                 hw->mac.autoneg = hw->mac.fc_autoneg = 0;
368                 hw->phy.autoneg_advertised = 0;
369                 hw->mac.link_speed = SPEED_10;
370                 hw->mac.link_duplex = DUPLEX_HALF;
371                 break;
372         case SPEED_10 + FULL_DUPLEX:
373                 netdev_dbg(adapter->netdev, "Forcing to 10 Mbps Full Duplex\n");
374                 hw->mac.autoneg = hw->mac.fc_autoneg = 0;
375                 hw->phy.autoneg_advertised = 0;
376                 hw->mac.link_speed = SPEED_10;
377                 hw->mac.link_duplex = DUPLEX_FULL;
378                 break;
379         case SPEED_100:
380                 netdev_dbg(adapter->netdev,
381                            "100 Mbps Speed specified without Duplex\n");
382                 netdev_dbg(adapter->netdev,
383                            "Using Autonegotiation at 100 Mbps only\n");
384                 hw->mac.autoneg = hw->mac.fc_autoneg = 1;
385                 hw->phy.autoneg_advertised = PHY_ADVERTISE_100_HALF |
386                                                 PHY_ADVERTISE_100_FULL;
387                 hw->mac.link_speed = SPEED_100;
388                 hw->mac.link_duplex = DUPLEX_HALF;
389                 break;
390         case SPEED_100 + HALF_DUPLEX:
391                 netdev_dbg(adapter->netdev,
392                            "Forcing to 100 Mbps Half Duplex\n");
393                 hw->mac.autoneg = hw->mac.fc_autoneg = 0;
394                 hw->phy.autoneg_advertised = 0;
395                 hw->mac.link_speed = SPEED_100;
396                 hw->mac.link_duplex = DUPLEX_HALF;
397                 break;
398         case SPEED_100 + FULL_DUPLEX:
399                 netdev_dbg(adapter->netdev,
400                            "Forcing to 100 Mbps Full Duplex\n");
401                 hw->mac.autoneg = hw->mac.fc_autoneg = 0;
402                 hw->phy.autoneg_advertised = 0;
403                 hw->mac.link_speed = SPEED_100;
404                 hw->mac.link_duplex = DUPLEX_FULL;
405                 break;
406         case SPEED_1000:
407                 netdev_dbg(adapter->netdev,
408                            "1000 Mbps Speed specified without Duplex\n");
409                 goto full_duplex_only;
410         case SPEED_1000 + HALF_DUPLEX:
411                 netdev_dbg(adapter->netdev,
412                            "Half Duplex is not supported at 1000 Mbps\n");
413                 /* fall through */
414         case SPEED_1000 + FULL_DUPLEX:
415 full_duplex_only:
416                 netdev_dbg(adapter->netdev,
417                            "Using Autonegotiation at 1000 Mbps Full Duplex only\n");
418                 hw->mac.autoneg = hw->mac.fc_autoneg = 1;
419                 hw->phy.autoneg_advertised = PHY_ADVERTISE_1000_FULL;
420                 hw->mac.link_speed = SPEED_1000;
421                 hw->mac.link_duplex = DUPLEX_FULL;
422                 break;
423         default:
424                 BUG();
425         }
426 }
427
428 /**
429  * pch_gbe_check_options - Range Checking for Command Line Parameters
430  * @adapter:  Board private structure
431  */
432 void pch_gbe_check_options(struct pch_gbe_adapter *adapter)
433 {
434         struct pch_gbe_hw *hw = &adapter->hw;
435         struct net_device *dev = adapter->netdev;
436         int val;
437
438         { /* Transmit Descriptor Count */
439                 static const struct pch_gbe_option opt = {
440                         .type = range_option,
441                         .name = "Transmit Descriptors",
442                         .err  = "using default of "
443                                 __MODULE_STRING(PCH_GBE_DEFAULT_TXD),
444                         .def  = PCH_GBE_DEFAULT_TXD,
445                         .arg  = { .r = { .min = PCH_GBE_MIN_TXD,
446                                          .max = PCH_GBE_MAX_TXD } }
447                 };
448                 struct pch_gbe_tx_ring *tx_ring = adapter->tx_ring;
449                 tx_ring->count = TxDescriptors;
450                 pch_gbe_validate_option(&tx_ring->count, &opt, adapter);
451                 tx_ring->count = roundup(tx_ring->count,
452                                         PCH_GBE_TX_DESC_MULTIPLE);
453         }
454         { /* Receive Descriptor Count */
455                 static const struct pch_gbe_option opt = {
456                         .type = range_option,
457                         .name = "Receive Descriptors",
458                         .err  = "using default of "
459                                 __MODULE_STRING(PCH_GBE_DEFAULT_RXD),
460                         .def  = PCH_GBE_DEFAULT_RXD,
461                         .arg  = { .r = { .min = PCH_GBE_MIN_RXD,
462                                          .max = PCH_GBE_MAX_RXD } }
463                 };
464                 struct pch_gbe_rx_ring *rx_ring = adapter->rx_ring;
465                 rx_ring->count = RxDescriptors;
466                 pch_gbe_validate_option(&rx_ring->count, &opt, adapter);
467                 rx_ring->count = roundup(rx_ring->count,
468                                 PCH_GBE_RX_DESC_MULTIPLE);
469         }
470         { /* Checksum Offload Enable/Disable */
471                 static const struct pch_gbe_option opt = {
472                         .type = enable_option,
473                         .name = "Checksum Offload",
474                         .err  = "defaulting to Enabled",
475                         .def  = PCH_GBE_DEFAULT_RX_CSUM
476                 };
477                 val = XsumRX;
478                 pch_gbe_validate_option(&val, &opt, adapter);
479                 if (!val)
480                         dev->features &= ~NETIF_F_RXCSUM;
481         }
482         { /* Checksum Offload Enable/Disable */
483                 static const struct pch_gbe_option opt = {
484                         .type = enable_option,
485                         .name = "Checksum Offload",
486                         .err  = "defaulting to Enabled",
487                         .def  = PCH_GBE_DEFAULT_TX_CSUM
488                 };
489                 val = XsumTX;
490                 pch_gbe_validate_option(&val, &opt, adapter);
491                 if (!val)
492                         dev->features &= ~NETIF_F_CSUM_MASK;
493         }
494         { /* Flow Control */
495                 static const struct pch_gbe_option opt = {
496                         .type = list_option,
497                         .name = "Flow Control",
498                         .err  = "reading default settings from EEPROM",
499                         .def  = PCH_GBE_FC_DEFAULT,
500                         .arg  = { .l = { .nr = (int)ARRAY_SIZE(fc_list),
501                                          .p = fc_list } }
502                 };
503                 int tmp = FlowControl;
504
505                 pch_gbe_validate_option(&tmp, &opt, adapter);
506                 hw->mac.fc = tmp;
507         }
508
509         pch_gbe_check_copper_options(adapter);
510 }