Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 1999 - 2010 Intel Corporation.
0004  * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD.
0005  *
0006  * This code was derived from the Intel e1000e Linux driver.
0007  */
0008 
0009 #include "pch_gbe.h"
0010 #include <linux/module.h>   /* for __MODULE_STRING */
0011 
0012 #define OPTION_UNSET   -1
0013 #define OPTION_DISABLED 0
0014 #define OPTION_ENABLED  1
0015 
0016 /*
0017  * TxDescriptors - Transmit Descriptor Count
0018  * @Valid Range:   PCH_GBE_MIN_TXD - PCH_GBE_MAX_TXD
0019  * @Default Value: PCH_GBE_DEFAULT_TXD
0020  */
0021 static int TxDescriptors = OPTION_UNSET;
0022 module_param(TxDescriptors, int, 0);
0023 MODULE_PARM_DESC(TxDescriptors, "Number of transmit descriptors");
0024 
0025 /*
0026  * RxDescriptors -Receive Descriptor Count
0027  * @Valid Range:   PCH_GBE_MIN_RXD - PCH_GBE_MAX_RXD
0028  * @Default Value: PCH_GBE_DEFAULT_RXD
0029  */
0030 static int RxDescriptors = OPTION_UNSET;
0031 module_param(RxDescriptors, int, 0);
0032 MODULE_PARM_DESC(RxDescriptors, "Number of receive descriptors");
0033 
0034 /*
0035  * Speed - User Specified Speed Override
0036  * @Valid Range: 0, 10, 100, 1000
0037  *   - 0:    auto-negotiate at all supported speeds
0038  *   - 10:   only link at 10 Mbps
0039  *   - 100:  only link at 100 Mbps
0040  *   - 1000: only link at 1000 Mbps
0041  * @Default Value: 0
0042  */
0043 static int Speed = OPTION_UNSET;
0044 module_param(Speed, int, 0);
0045 MODULE_PARM_DESC(Speed, "Speed setting");
0046 
0047 /*
0048  * Duplex - User Specified Duplex Override
0049  * @Valid Range: 0-2
0050  *   - 0:  auto-negotiate for duplex
0051  *   - 1:  only link at half duplex
0052  *   - 2:  only link at full duplex
0053  * @Default Value: 0
0054  */
0055 static int Duplex = OPTION_UNSET;
0056 module_param(Duplex, int, 0);
0057 MODULE_PARM_DESC(Duplex, "Duplex setting");
0058 
0059 #define HALF_DUPLEX 1
0060 #define FULL_DUPLEX 2
0061 
0062 /*
0063  * AutoNeg - Auto-negotiation Advertisement Override
0064  * @Valid Range: 0x01-0x0F, 0x20-0x2F
0065  *
0066  *       The AutoNeg value is a bit mask describing which speed and duplex
0067  *       combinations should be advertised during auto-negotiation.
0068  *       The supported speed and duplex modes are listed below
0069  *
0070  *       Bit           7     6     5      4      3     2     1      0
0071  *       Speed (Mbps)  N/A   N/A   1000   N/A    100   100   10     10
0072  *       Duplex                    Full          Full  Half  Full   Half
0073  *
0074  * @Default Value: 0x2F (copper)
0075  */
0076 static int AutoNeg = OPTION_UNSET;
0077 module_param(AutoNeg, int, 0);
0078 MODULE_PARM_DESC(AutoNeg, "Advertised auto-negotiation setting");
0079 
0080 #define PHY_ADVERTISE_10_HALF      0x0001
0081 #define PHY_ADVERTISE_10_FULL      0x0002
0082 #define PHY_ADVERTISE_100_HALF     0x0004
0083 #define PHY_ADVERTISE_100_FULL     0x0008
0084 #define PHY_ADVERTISE_1000_HALF    0x0010 /* Not used, just FYI */
0085 #define PHY_ADVERTISE_1000_FULL    0x0020
0086 #define PCH_AUTONEG_ADVERTISE_DEFAULT   0x2F
0087 
0088 /*
0089  * FlowControl - User Specified Flow Control Override
0090  * @Valid Range: 0-3
0091  *    - 0:  No Flow Control
0092  *    - 1:  Rx only, respond to PAUSE frames but do not generate them
0093  *    - 2:  Tx only, generate PAUSE frames but ignore them on receive
0094  *    - 3:  Full Flow Control Support
0095  * @Default Value: Read flow control settings from the EEPROM
0096  */
0097 static int FlowControl = OPTION_UNSET;
0098 module_param(FlowControl, int, 0);
0099 MODULE_PARM_DESC(FlowControl, "Flow Control setting");
0100 
0101 /*
0102  * XsumRX - Receive Checksum Offload Enable/Disable
0103  * @Valid Range: 0, 1
0104  *    - 0:  disables all checksum offload
0105  *    - 1:  enables receive IP/TCP/UDP checksum offload
0106  * @Default Value: PCH_GBE_DEFAULT_RX_CSUM
0107  */
0108 static int XsumRX = OPTION_UNSET;
0109 module_param(XsumRX, int, 0);
0110 MODULE_PARM_DESC(XsumRX, "Disable or enable Receive Checksum offload");
0111 
0112 #define PCH_GBE_DEFAULT_RX_CSUM             true    /* trueorfalse */
0113 
0114 /*
0115  * XsumTX - Transmit Checksum Offload Enable/Disable
0116  * @Valid Range: 0, 1
0117  *    - 0:  disables all checksum offload
0118  *    - 1:  enables transmit IP/TCP/UDP checksum offload
0119  * @Default Value: PCH_GBE_DEFAULT_TX_CSUM
0120  */
0121 static int XsumTX = OPTION_UNSET;
0122 module_param(XsumTX, int, 0);
0123 MODULE_PARM_DESC(XsumTX, "Disable or enable Transmit Checksum offload");
0124 
0125 #define PCH_GBE_DEFAULT_TX_CSUM             true    /* trueorfalse */
0126 
0127 /*
0128  * pch_gbe_option - Force the MAC's flow control settings
0129  * @hw:             Pointer to the HW structure
0130  * Returns:
0131  *  0:          Successful.
0132  *  Negative value:     Failed.
0133  */
0134 struct pch_gbe_option {
0135     enum { enable_option, range_option, list_option } type;
0136     char *name;
0137     char *err;
0138     int  def;
0139     union {
0140         struct { /* range_option info */
0141             int min;
0142             int max;
0143         } r;
0144         struct { /* list_option info */
0145             int nr;
0146             const struct pch_gbe_opt_list { int i; char *str; } *p;
0147         } l;
0148     } arg;
0149 };
0150 
0151 static const struct pch_gbe_opt_list speed_list[] = {
0152     { 0, "" },
0153     { SPEED_10, "" },
0154     { SPEED_100, "" },
0155     { SPEED_1000, "" }
0156 };
0157 
0158 static const struct pch_gbe_opt_list dplx_list[] = {
0159     { 0, "" },
0160     { HALF_DUPLEX, "" },
0161     { FULL_DUPLEX, "" }
0162 };
0163 
0164 static const struct pch_gbe_opt_list an_list[] =
0165     #define AA "AutoNeg advertising "
0166     {{ 0x01, AA "10/HD" },
0167      { 0x02, AA "10/FD" },
0168      { 0x03, AA "10/FD, 10/HD" },
0169      { 0x04, AA "100/HD" },
0170      { 0x05, AA "100/HD, 10/HD" },
0171      { 0x06, AA "100/HD, 10/FD" },
0172      { 0x07, AA "100/HD, 10/FD, 10/HD" },
0173      { 0x08, AA "100/FD" },
0174      { 0x09, AA "100/FD, 10/HD" },
0175      { 0x0a, AA "100/FD, 10/FD" },
0176      { 0x0b, AA "100/FD, 10/FD, 10/HD" },
0177      { 0x0c, AA "100/FD, 100/HD" },
0178      { 0x0d, AA "100/FD, 100/HD, 10/HD" },
0179      { 0x0e, AA "100/FD, 100/HD, 10/FD" },
0180      { 0x0f, AA "100/FD, 100/HD, 10/FD, 10/HD" },
0181      { 0x20, AA "1000/FD" },
0182      { 0x21, AA "1000/FD, 10/HD" },
0183      { 0x22, AA "1000/FD, 10/FD" },
0184      { 0x23, AA "1000/FD, 10/FD, 10/HD" },
0185      { 0x24, AA "1000/FD, 100/HD" },
0186      { 0x25, AA "1000/FD, 100/HD, 10/HD" },
0187      { 0x26, AA "1000/FD, 100/HD, 10/FD" },
0188      { 0x27, AA "1000/FD, 100/HD, 10/FD, 10/HD" },
0189      { 0x28, AA "1000/FD, 100/FD" },
0190      { 0x29, AA "1000/FD, 100/FD, 10/HD" },
0191      { 0x2a, AA "1000/FD, 100/FD, 10/FD" },
0192      { 0x2b, AA "1000/FD, 100/FD, 10/FD, 10/HD" },
0193      { 0x2c, AA "1000/FD, 100/FD, 100/HD" },
0194      { 0x2d, AA "1000/FD, 100/FD, 100/HD, 10/HD" },
0195      { 0x2e, AA "1000/FD, 100/FD, 100/HD, 10/FD" },
0196      { 0x2f, AA "1000/FD, 100/FD, 100/HD, 10/FD, 10/HD" }
0197 };
0198 
0199 static const struct pch_gbe_opt_list fc_list[] = {
0200     { PCH_GBE_FC_NONE, "Flow Control Disabled" },
0201     { PCH_GBE_FC_RX_PAUSE, "Flow Control Receive Only" },
0202     { PCH_GBE_FC_TX_PAUSE, "Flow Control Transmit Only" },
0203     { PCH_GBE_FC_FULL, "Flow Control Enabled" }
0204 };
0205 
0206 /**
0207  * pch_gbe_validate_option - Validate option
0208  * @value:    value
0209  * @opt:      option
0210  * @adapter:  Board private structure
0211  * Returns:
0212  *  0:          Successful.
0213  *  Negative value:     Failed.
0214  */
0215 static int pch_gbe_validate_option(int *value,
0216                     const struct pch_gbe_option *opt,
0217                     struct pch_gbe_adapter *adapter)
0218 {
0219     if (*value == OPTION_UNSET) {
0220         *value = opt->def;
0221         return 0;
0222     }
0223 
0224     switch (opt->type) {
0225     case enable_option:
0226         switch (*value) {
0227         case OPTION_ENABLED:
0228             netdev_dbg(adapter->netdev, "%s Enabled\n", opt->name);
0229             return 0;
0230         case OPTION_DISABLED:
0231             netdev_dbg(adapter->netdev, "%s Disabled\n", opt->name);
0232             return 0;
0233         }
0234         break;
0235     case range_option:
0236         if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) {
0237             netdev_dbg(adapter->netdev, "%s set to %i\n",
0238                    opt->name, *value);
0239             return 0;
0240         }
0241         break;
0242     case list_option: {
0243         int i;
0244         const struct pch_gbe_opt_list *ent;
0245 
0246         for (i = 0; i < opt->arg.l.nr; i++) {
0247             ent = &opt->arg.l.p[i];
0248             if (*value == ent->i) {
0249                 if (ent->str[0] != '\0')
0250                     netdev_dbg(adapter->netdev, "%s\n",
0251                            ent->str);
0252                 return 0;
0253             }
0254         }
0255     }
0256         break;
0257     default:
0258         BUG();
0259     }
0260 
0261     netdev_dbg(adapter->netdev, "Invalid %s value specified (%i) %s\n",
0262            opt->name, *value, opt->err);
0263     *value = opt->def;
0264     return -1;
0265 }
0266 
0267 /**
0268  * pch_gbe_check_copper_options - Range Checking for Link Options, Copper Version
0269  * @adapter:  Board private structure
0270  */
0271 static void pch_gbe_check_copper_options(struct pch_gbe_adapter *adapter)
0272 {
0273     struct pch_gbe_hw *hw = &adapter->hw;
0274     int speed, dplx;
0275 
0276     { /* Speed */
0277         static const struct pch_gbe_option opt = {
0278             .type = list_option,
0279             .name = "Speed",
0280             .err  = "parameter ignored",
0281             .def  = 0,
0282             .arg  = { .l = { .nr = (int)ARRAY_SIZE(speed_list),
0283                      .p = speed_list } }
0284         };
0285         speed = Speed;
0286         pch_gbe_validate_option(&speed, &opt, adapter);
0287     }
0288     { /* Duplex */
0289         static const struct pch_gbe_option opt = {
0290             .type = list_option,
0291             .name = "Duplex",
0292             .err  = "parameter ignored",
0293             .def  = 0,
0294             .arg  = { .l = { .nr = (int)ARRAY_SIZE(dplx_list),
0295                      .p = dplx_list } }
0296         };
0297         dplx = Duplex;
0298         pch_gbe_validate_option(&dplx, &opt, adapter);
0299     }
0300 
0301     { /* Autoneg */
0302         static const struct pch_gbe_option opt = {
0303             .type = list_option,
0304             .name = "AutoNeg",
0305             .err  = "parameter ignored",
0306             .def  = PCH_AUTONEG_ADVERTISE_DEFAULT,
0307             .arg  = { .l = { .nr = (int)ARRAY_SIZE(an_list),
0308                      .p = an_list} }
0309         };
0310         if (speed || dplx) {
0311             netdev_dbg(adapter->netdev,
0312                    "AutoNeg specified along with Speed or Duplex, AutoNeg parameter ignored\n");
0313             hw->phy.autoneg_advertised = opt.def;
0314         } else {
0315             int tmp = AutoNeg;
0316 
0317             pch_gbe_validate_option(&tmp, &opt, adapter);
0318             hw->phy.autoneg_advertised = tmp;
0319         }
0320     }
0321 
0322     switch (speed + dplx) {
0323     case 0:
0324         hw->mac.autoneg = hw->mac.fc_autoneg = 1;
0325         if ((speed || dplx))
0326             netdev_dbg(adapter->netdev,
0327                    "Speed and duplex autonegotiation enabled\n");
0328         hw->mac.link_speed = SPEED_10;
0329         hw->mac.link_duplex = DUPLEX_HALF;
0330         break;
0331     case HALF_DUPLEX:
0332         netdev_dbg(adapter->netdev,
0333                "Half Duplex specified without Speed\n");
0334         netdev_dbg(adapter->netdev,
0335                "Using Autonegotiation at Half Duplex only\n");
0336         hw->mac.autoneg = hw->mac.fc_autoneg = 1;
0337         hw->phy.autoneg_advertised = PHY_ADVERTISE_10_HALF |
0338                         PHY_ADVERTISE_100_HALF;
0339         hw->mac.link_speed = SPEED_10;
0340         hw->mac.link_duplex = DUPLEX_HALF;
0341         break;
0342     case FULL_DUPLEX:
0343         netdev_dbg(adapter->netdev,
0344                "Full Duplex specified without Speed\n");
0345         netdev_dbg(adapter->netdev,
0346                "Using Autonegotiation at Full Duplex only\n");
0347         hw->mac.autoneg = hw->mac.fc_autoneg = 1;
0348         hw->phy.autoneg_advertised = PHY_ADVERTISE_10_FULL |
0349                         PHY_ADVERTISE_100_FULL |
0350                         PHY_ADVERTISE_1000_FULL;
0351         hw->mac.link_speed = SPEED_10;
0352         hw->mac.link_duplex = DUPLEX_FULL;
0353         break;
0354     case SPEED_10:
0355         netdev_dbg(adapter->netdev,
0356                "10 Mbps Speed specified without Duplex\n");
0357         netdev_dbg(adapter->netdev,
0358                "Using Autonegotiation at 10 Mbps only\n");
0359         hw->mac.autoneg = hw->mac.fc_autoneg = 1;
0360         hw->phy.autoneg_advertised = PHY_ADVERTISE_10_HALF |
0361                         PHY_ADVERTISE_10_FULL;
0362         hw->mac.link_speed = SPEED_10;
0363         hw->mac.link_duplex = DUPLEX_HALF;
0364         break;
0365     case SPEED_10 + HALF_DUPLEX:
0366         netdev_dbg(adapter->netdev, "Forcing to 10 Mbps Half Duplex\n");
0367         hw->mac.autoneg = hw->mac.fc_autoneg = 0;
0368         hw->phy.autoneg_advertised = 0;
0369         hw->mac.link_speed = SPEED_10;
0370         hw->mac.link_duplex = DUPLEX_HALF;
0371         break;
0372     case SPEED_10 + FULL_DUPLEX:
0373         netdev_dbg(adapter->netdev, "Forcing to 10 Mbps Full Duplex\n");
0374         hw->mac.autoneg = hw->mac.fc_autoneg = 0;
0375         hw->phy.autoneg_advertised = 0;
0376         hw->mac.link_speed = SPEED_10;
0377         hw->mac.link_duplex = DUPLEX_FULL;
0378         break;
0379     case SPEED_100:
0380         netdev_dbg(adapter->netdev,
0381                "100 Mbps Speed specified without Duplex\n");
0382         netdev_dbg(adapter->netdev,
0383                "Using Autonegotiation at 100 Mbps only\n");
0384         hw->mac.autoneg = hw->mac.fc_autoneg = 1;
0385         hw->phy.autoneg_advertised = PHY_ADVERTISE_100_HALF |
0386                         PHY_ADVERTISE_100_FULL;
0387         hw->mac.link_speed = SPEED_100;
0388         hw->mac.link_duplex = DUPLEX_HALF;
0389         break;
0390     case SPEED_100 + HALF_DUPLEX:
0391         netdev_dbg(adapter->netdev,
0392                "Forcing to 100 Mbps Half Duplex\n");
0393         hw->mac.autoneg = hw->mac.fc_autoneg = 0;
0394         hw->phy.autoneg_advertised = 0;
0395         hw->mac.link_speed = SPEED_100;
0396         hw->mac.link_duplex = DUPLEX_HALF;
0397         break;
0398     case SPEED_100 + FULL_DUPLEX:
0399         netdev_dbg(adapter->netdev,
0400                "Forcing to 100 Mbps Full Duplex\n");
0401         hw->mac.autoneg = hw->mac.fc_autoneg = 0;
0402         hw->phy.autoneg_advertised = 0;
0403         hw->mac.link_speed = SPEED_100;
0404         hw->mac.link_duplex = DUPLEX_FULL;
0405         break;
0406     case SPEED_1000:
0407         netdev_dbg(adapter->netdev,
0408                "1000 Mbps Speed specified without Duplex\n");
0409         goto full_duplex_only;
0410     case SPEED_1000 + HALF_DUPLEX:
0411         netdev_dbg(adapter->netdev,
0412                "Half Duplex is not supported at 1000 Mbps\n");
0413         fallthrough;
0414     case SPEED_1000 + FULL_DUPLEX:
0415 full_duplex_only:
0416         netdev_dbg(adapter->netdev,
0417                "Using Autonegotiation at 1000 Mbps Full Duplex only\n");
0418         hw->mac.autoneg = hw->mac.fc_autoneg = 1;
0419         hw->phy.autoneg_advertised = PHY_ADVERTISE_1000_FULL;
0420         hw->mac.link_speed = SPEED_1000;
0421         hw->mac.link_duplex = DUPLEX_FULL;
0422         break;
0423     default:
0424         BUG();
0425     }
0426 }
0427 
0428 /**
0429  * pch_gbe_check_options - Range Checking for Command Line Parameters
0430  * @adapter:  Board private structure
0431  */
0432 void pch_gbe_check_options(struct pch_gbe_adapter *adapter)
0433 {
0434     struct pch_gbe_hw *hw = &adapter->hw;
0435     struct net_device *dev = adapter->netdev;
0436     int val;
0437 
0438     { /* Transmit Descriptor Count */
0439         static const struct pch_gbe_option opt = {
0440             .type = range_option,
0441             .name = "Transmit Descriptors",
0442             .err  = "using default of "
0443                 __MODULE_STRING(PCH_GBE_DEFAULT_TXD),
0444             .def  = PCH_GBE_DEFAULT_TXD,
0445             .arg  = { .r = { .min = PCH_GBE_MIN_TXD,
0446                      .max = PCH_GBE_MAX_TXD } }
0447         };
0448         struct pch_gbe_tx_ring *tx_ring = adapter->tx_ring;
0449         tx_ring->count = TxDescriptors;
0450         pch_gbe_validate_option(&tx_ring->count, &opt, adapter);
0451         tx_ring->count = roundup(tx_ring->count,
0452                     PCH_GBE_TX_DESC_MULTIPLE);
0453     }
0454     { /* Receive Descriptor Count */
0455         static const struct pch_gbe_option opt = {
0456             .type = range_option,
0457             .name = "Receive Descriptors",
0458             .err  = "using default of "
0459                 __MODULE_STRING(PCH_GBE_DEFAULT_RXD),
0460             .def  = PCH_GBE_DEFAULT_RXD,
0461             .arg  = { .r = { .min = PCH_GBE_MIN_RXD,
0462                      .max = PCH_GBE_MAX_RXD } }
0463         };
0464         struct pch_gbe_rx_ring *rx_ring = adapter->rx_ring;
0465         rx_ring->count = RxDescriptors;
0466         pch_gbe_validate_option(&rx_ring->count, &opt, adapter);
0467         rx_ring->count = roundup(rx_ring->count,
0468                 PCH_GBE_RX_DESC_MULTIPLE);
0469     }
0470     { /* Checksum Offload Enable/Disable */
0471         static const struct pch_gbe_option opt = {
0472             .type = enable_option,
0473             .name = "Checksum Offload",
0474             .err  = "defaulting to Enabled",
0475             .def  = PCH_GBE_DEFAULT_RX_CSUM
0476         };
0477         val = XsumRX;
0478         pch_gbe_validate_option(&val, &opt, adapter);
0479         if (!val)
0480             dev->features &= ~NETIF_F_RXCSUM;
0481     }
0482     { /* Checksum Offload Enable/Disable */
0483         static const struct pch_gbe_option opt = {
0484             .type = enable_option,
0485             .name = "Checksum Offload",
0486             .err  = "defaulting to Enabled",
0487             .def  = PCH_GBE_DEFAULT_TX_CSUM
0488         };
0489         val = XsumTX;
0490         pch_gbe_validate_option(&val, &opt, adapter);
0491         if (!val)
0492             dev->features &= ~NETIF_F_CSUM_MASK;
0493     }
0494     { /* Flow Control */
0495         static const struct pch_gbe_option opt = {
0496             .type = list_option,
0497             .name = "Flow Control",
0498             .err  = "reading default settings from EEPROM",
0499             .def  = PCH_GBE_FC_DEFAULT,
0500             .arg  = { .l = { .nr = (int)ARRAY_SIZE(fc_list),
0501                      .p = fc_list } }
0502         };
0503         int tmp = FlowControl;
0504 
0505         pch_gbe_validate_option(&tmp, &opt, adapter);
0506         hw->mac.fc = tmp;
0507     }
0508 
0509     pch_gbe_check_copper_options(adapter);
0510 }