511 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*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 -113#define OPTION_DISABLED 014#define OPTION_ENABLED 115 16/*17 * TxDescriptors - Transmit Descriptor Count18 * @Valid Range: PCH_GBE_MIN_TXD - PCH_GBE_MAX_TXD19 * @Default Value: PCH_GBE_DEFAULT_TXD20 */21static int TxDescriptors = OPTION_UNSET;22module_param(TxDescriptors, int, 0);23MODULE_PARM_DESC(TxDescriptors, "Number of transmit descriptors");24 25/*26 * RxDescriptors -Receive Descriptor Count27 * @Valid Range: PCH_GBE_MIN_RXD - PCH_GBE_MAX_RXD28 * @Default Value: PCH_GBE_DEFAULT_RXD29 */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 Override36 * @Valid Range: 0, 10, 100, 100037 * - 0: auto-negotiate at all supported speeds38 * - 10: only link at 10 Mbps39 * - 100: only link at 100 Mbps40 * - 1000: only link at 1000 Mbps41 * @Default Value: 042 */43static int Speed = OPTION_UNSET;44module_param(Speed, int, 0);45MODULE_PARM_DESC(Speed, "Speed setting");46 47/*48 * Duplex - User Specified Duplex Override49 * @Valid Range: 0-250 * - 0: auto-negotiate for duplex51 * - 1: only link at half duplex52 * - 2: only link at full duplex53 * @Default Value: 054 */55static int Duplex = OPTION_UNSET;56module_param(Duplex, int, 0);57MODULE_PARM_DESC(Duplex, "Duplex setting");58 59#define HALF_DUPLEX 160#define FULL_DUPLEX 261 62/*63 * AutoNeg - Auto-negotiation Advertisement Override64 * @Valid Range: 0x01-0x0F, 0x20-0x2F65 *66 * The AutoNeg value is a bit mask describing which speed and duplex67 * combinations should be advertised during auto-negotiation.68 * The supported speed and duplex modes are listed below69 *70 * Bit 7 6 5 4 3 2 1 071 * Speed (Mbps) N/A N/A 1000 N/A 100 100 10 1072 * Duplex Full Full Half Full Half73 *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 0x000181#define PHY_ADVERTISE_10_FULL 0x000282#define PHY_ADVERTISE_100_HALF 0x000483#define PHY_ADVERTISE_100_FULL 0x000884#define PHY_ADVERTISE_1000_HALF 0x0010 /* Not used, just FYI */85#define PHY_ADVERTISE_1000_FULL 0x002086#define PCH_AUTONEG_ADVERTISE_DEFAULT 0x2F87 88/*89 * FlowControl - User Specified Flow Control Override90 * @Valid Range: 0-391 * - 0: No Flow Control92 * - 1: Rx only, respond to PAUSE frames but do not generate them93 * - 2: Tx only, generate PAUSE frames but ignore them on receive94 * - 3: Full Flow Control Support95 * @Default Value: Read flow control settings from the EEPROM96 */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/Disable103 * @Valid Range: 0, 1104 * - 0: disables all checksum offload105 * - 1: enables receive IP/TCP/UDP checksum offload106 * @Default Value: PCH_GBE_DEFAULT_RX_CSUM107 */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/Disable116 * @Valid Range: 0, 1117 * - 0: disables all checksum offload118 * - 1: enables transmit IP/TCP/UDP checksum offload119 * @Default Value: PCH_GBE_DEFAULT_TX_CSUM120 */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 settings129 * @hw: Pointer to the HW structure130 * 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 option208 * @value: value209 * @opt: option210 * @adapter: Board private structure211 * 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 Version269 * @adapter: Board private structure270 */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 Parameters430 * @adapter: Board private structure431 */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_CSUM476 };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_CSUM488 };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