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 }
511