brintos

brintos / linux-shallow public Read only

0
0
Text · 14.6 KiB · 81fc5a6 Raw
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