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 */
21static int TxDescriptors = OPTION_UNSET;
22module_param(TxDescriptors, int, 0);
23MODULE_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 */
30static int RxDescriptors = OPTION_UNSET;
31module_param(RxDescriptors, int, 0);
32MODULE_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 */
43static int Speed = OPTION_UNSET;
44module_param(Speed, int, 0);
45MODULE_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 */
55static int Duplex = OPTION_UNSET;
56module_param(Duplex, int, 0);
57MODULE_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 */
76static int AutoNeg = OPTION_UNSET;
77module_param(AutoNeg, int, 0);
78MODULE_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 */
97static int FlowControl = OPTION_UNSET;
98module_param(FlowControl, int, 0);
99MODULE_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 */
108static int XsumRX = OPTION_UNSET;
109module_param(XsumRX, int, 0);
110MODULE_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 */
121static int XsumTX = OPTION_UNSET;
122module_param(XsumTX, int, 0);
123MODULE_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 */
134struct 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
151static const struct pch_gbe_opt_list speed_list[] = {
152	{ 0, "" },
153	{ SPEED_10, "" },
154	{ SPEED_100, "" },
155	{ SPEED_1000, "" }
156};
157
158static const struct pch_gbe_opt_list dplx_list[] = {
159	{ 0, "" },
160	{ HALF_DUPLEX, "" },
161	{ FULL_DUPLEX, "" }
162};
163
164static 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
199static 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 */
215static 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 */
271static 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		fallthrough;
414	case SPEED_1000 + FULL_DUPLEX:
415full_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 */
432void 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}
511