1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /* Copyright(c) 1999 - 2006 Intel Corporation. */
3*4882a593Smuzhiyun
4*4882a593Smuzhiyun #include "e1000.h"
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun /* This is the only thing that needs to be changed to adjust the
7*4882a593Smuzhiyun * maximum number of ports that the driver can manage.
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #define E1000_MAX_NIC 32
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #define OPTION_UNSET -1
13*4882a593Smuzhiyun #define OPTION_DISABLED 0
14*4882a593Smuzhiyun #define OPTION_ENABLED 1
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun /* All parameters are treated the same, as an integer array of values.
17*4882a593Smuzhiyun * This macro just reduces the need to repeat the same declaration code
18*4882a593Smuzhiyun * over and over (plus this helps to avoid typo bugs).
19*4882a593Smuzhiyun */
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun #define E1000_PARAM_INIT { [0 ... E1000_MAX_NIC] = OPTION_UNSET }
22*4882a593Smuzhiyun #define E1000_PARAM(X, desc) \
23*4882a593Smuzhiyun static int X[E1000_MAX_NIC+1] = E1000_PARAM_INIT; \
24*4882a593Smuzhiyun static unsigned int num_##X; \
25*4882a593Smuzhiyun module_param_array_named(X, X, int, &num_##X, 0); \
26*4882a593Smuzhiyun MODULE_PARM_DESC(X, desc);
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun /* Transmit Descriptor Count
29*4882a593Smuzhiyun *
30*4882a593Smuzhiyun * Valid Range: 80-256 for 82542 and 82543 gigabit ethernet controllers
31*4882a593Smuzhiyun * Valid Range: 80-4096 for 82544 and newer
32*4882a593Smuzhiyun *
33*4882a593Smuzhiyun * Default Value: 256
34*4882a593Smuzhiyun */
35*4882a593Smuzhiyun E1000_PARAM(TxDescriptors, "Number of transmit descriptors");
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun /* Receive Descriptor Count
38*4882a593Smuzhiyun *
39*4882a593Smuzhiyun * Valid Range: 80-256 for 82542 and 82543 gigabit ethernet controllers
40*4882a593Smuzhiyun * Valid Range: 80-4096 for 82544 and newer
41*4882a593Smuzhiyun *
42*4882a593Smuzhiyun * Default Value: 256
43*4882a593Smuzhiyun */
44*4882a593Smuzhiyun E1000_PARAM(RxDescriptors, "Number of receive descriptors");
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun /* User Specified Speed Override
47*4882a593Smuzhiyun *
48*4882a593Smuzhiyun * Valid Range: 0, 10, 100, 1000
49*4882a593Smuzhiyun * - 0 - auto-negotiate at all supported speeds
50*4882a593Smuzhiyun * - 10 - only link at 10 Mbps
51*4882a593Smuzhiyun * - 100 - only link at 100 Mbps
52*4882a593Smuzhiyun * - 1000 - only link at 1000 Mbps
53*4882a593Smuzhiyun *
54*4882a593Smuzhiyun * Default Value: 0
55*4882a593Smuzhiyun */
56*4882a593Smuzhiyun E1000_PARAM(Speed, "Speed setting");
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun /* User Specified Duplex Override
59*4882a593Smuzhiyun *
60*4882a593Smuzhiyun * Valid Range: 0-2
61*4882a593Smuzhiyun * - 0 - auto-negotiate for duplex
62*4882a593Smuzhiyun * - 1 - only link at half duplex
63*4882a593Smuzhiyun * - 2 - only link at full duplex
64*4882a593Smuzhiyun *
65*4882a593Smuzhiyun * Default Value: 0
66*4882a593Smuzhiyun */
67*4882a593Smuzhiyun E1000_PARAM(Duplex, "Duplex setting");
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun /* Auto-negotiation Advertisement Override
70*4882a593Smuzhiyun *
71*4882a593Smuzhiyun * Valid Range: 0x01-0x0F, 0x20-0x2F (copper); 0x20 (fiber)
72*4882a593Smuzhiyun *
73*4882a593Smuzhiyun * The AutoNeg value is a bit mask describing which speed and duplex
74*4882a593Smuzhiyun * combinations should be advertised during auto-negotiation.
75*4882a593Smuzhiyun * The supported speed and duplex modes are listed below
76*4882a593Smuzhiyun *
77*4882a593Smuzhiyun * Bit 7 6 5 4 3 2 1 0
78*4882a593Smuzhiyun * Speed (Mbps) N/A N/A 1000 N/A 100 100 10 10
79*4882a593Smuzhiyun * Duplex Full Full Half Full Half
80*4882a593Smuzhiyun *
81*4882a593Smuzhiyun * Default Value: 0x2F (copper); 0x20 (fiber)
82*4882a593Smuzhiyun */
83*4882a593Smuzhiyun E1000_PARAM(AutoNeg, "Advertised auto-negotiation setting");
84*4882a593Smuzhiyun #define AUTONEG_ADV_DEFAULT 0x2F
85*4882a593Smuzhiyun #define AUTONEG_ADV_MASK 0x2F
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun /* User Specified Flow Control Override
88*4882a593Smuzhiyun *
89*4882a593Smuzhiyun * Valid Range: 0-3
90*4882a593Smuzhiyun * - 0 - No Flow Control
91*4882a593Smuzhiyun * - 1 - Rx only, respond to PAUSE frames but do not generate them
92*4882a593Smuzhiyun * - 2 - Tx only, generate PAUSE frames but ignore them on receive
93*4882a593Smuzhiyun * - 3 - Full Flow Control Support
94*4882a593Smuzhiyun *
95*4882a593Smuzhiyun * Default Value: Read flow control settings from the EEPROM
96*4882a593Smuzhiyun */
97*4882a593Smuzhiyun E1000_PARAM(FlowControl, "Flow Control setting");
98*4882a593Smuzhiyun #define FLOW_CONTROL_DEFAULT FLOW_CONTROL_FULL
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun /* XsumRX - Receive Checksum Offload Enable/Disable
101*4882a593Smuzhiyun *
102*4882a593Smuzhiyun * Valid Range: 0, 1
103*4882a593Smuzhiyun * - 0 - disables all checksum offload
104*4882a593Smuzhiyun * - 1 - enables receive IP/TCP/UDP checksum offload
105*4882a593Smuzhiyun * on 82543 and newer -based NICs
106*4882a593Smuzhiyun *
107*4882a593Smuzhiyun * Default Value: 1
108*4882a593Smuzhiyun */
109*4882a593Smuzhiyun E1000_PARAM(XsumRX, "Disable or enable Receive Checksum offload");
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun /* Transmit Interrupt Delay in units of 1.024 microseconds
112*4882a593Smuzhiyun * Tx interrupt delay needs to typically be set to something non zero
113*4882a593Smuzhiyun *
114*4882a593Smuzhiyun * Valid Range: 0-65535
115*4882a593Smuzhiyun */
116*4882a593Smuzhiyun E1000_PARAM(TxIntDelay, "Transmit Interrupt Delay");
117*4882a593Smuzhiyun #define DEFAULT_TIDV 8
118*4882a593Smuzhiyun #define MAX_TXDELAY 0xFFFF
119*4882a593Smuzhiyun #define MIN_TXDELAY 0
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun /* Transmit Absolute Interrupt Delay in units of 1.024 microseconds
122*4882a593Smuzhiyun *
123*4882a593Smuzhiyun * Valid Range: 0-65535
124*4882a593Smuzhiyun */
125*4882a593Smuzhiyun E1000_PARAM(TxAbsIntDelay, "Transmit Absolute Interrupt Delay");
126*4882a593Smuzhiyun #define DEFAULT_TADV 32
127*4882a593Smuzhiyun #define MAX_TXABSDELAY 0xFFFF
128*4882a593Smuzhiyun #define MIN_TXABSDELAY 0
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun /* Receive Interrupt Delay in units of 1.024 microseconds
131*4882a593Smuzhiyun * hardware will likely hang if you set this to anything but zero.
132*4882a593Smuzhiyun *
133*4882a593Smuzhiyun * Valid Range: 0-65535
134*4882a593Smuzhiyun */
135*4882a593Smuzhiyun E1000_PARAM(RxIntDelay, "Receive Interrupt Delay");
136*4882a593Smuzhiyun #define DEFAULT_RDTR 0
137*4882a593Smuzhiyun #define MAX_RXDELAY 0xFFFF
138*4882a593Smuzhiyun #define MIN_RXDELAY 0
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun /* Receive Absolute Interrupt Delay in units of 1.024 microseconds
141*4882a593Smuzhiyun *
142*4882a593Smuzhiyun * Valid Range: 0-65535
143*4882a593Smuzhiyun */
144*4882a593Smuzhiyun E1000_PARAM(RxAbsIntDelay, "Receive Absolute Interrupt Delay");
145*4882a593Smuzhiyun #define DEFAULT_RADV 8
146*4882a593Smuzhiyun #define MAX_RXABSDELAY 0xFFFF
147*4882a593Smuzhiyun #define MIN_RXABSDELAY 0
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun /* Interrupt Throttle Rate (interrupts/sec)
150*4882a593Smuzhiyun *
151*4882a593Smuzhiyun * Valid Range: 100-100000 (0=off, 1=dynamic, 3=dynamic conservative)
152*4882a593Smuzhiyun */
153*4882a593Smuzhiyun E1000_PARAM(InterruptThrottleRate, "Interrupt Throttling Rate");
154*4882a593Smuzhiyun #define DEFAULT_ITR 3
155*4882a593Smuzhiyun #define MAX_ITR 100000
156*4882a593Smuzhiyun #define MIN_ITR 100
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun /* Enable Smart Power Down of the PHY
159*4882a593Smuzhiyun *
160*4882a593Smuzhiyun * Valid Range: 0, 1
161*4882a593Smuzhiyun *
162*4882a593Smuzhiyun * Default Value: 0 (disabled)
163*4882a593Smuzhiyun */
164*4882a593Smuzhiyun E1000_PARAM(SmartPowerDownEnable, "Enable PHY smart power down");
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun struct e1000_option {
167*4882a593Smuzhiyun enum { enable_option, range_option, list_option } type;
168*4882a593Smuzhiyun const char *name;
169*4882a593Smuzhiyun const char *err;
170*4882a593Smuzhiyun int def;
171*4882a593Smuzhiyun union {
172*4882a593Smuzhiyun struct { /* range_option info */
173*4882a593Smuzhiyun int min;
174*4882a593Smuzhiyun int max;
175*4882a593Smuzhiyun } r;
176*4882a593Smuzhiyun struct { /* list_option info */
177*4882a593Smuzhiyun int nr;
178*4882a593Smuzhiyun const struct e1000_opt_list { int i; char *str; } *p;
179*4882a593Smuzhiyun } l;
180*4882a593Smuzhiyun } arg;
181*4882a593Smuzhiyun };
182*4882a593Smuzhiyun
e1000_validate_option(unsigned int * value,const struct e1000_option * opt,struct e1000_adapter * adapter)183*4882a593Smuzhiyun static int e1000_validate_option(unsigned int *value,
184*4882a593Smuzhiyun const struct e1000_option *opt,
185*4882a593Smuzhiyun struct e1000_adapter *adapter)
186*4882a593Smuzhiyun {
187*4882a593Smuzhiyun if (*value == OPTION_UNSET) {
188*4882a593Smuzhiyun *value = opt->def;
189*4882a593Smuzhiyun return 0;
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun switch (opt->type) {
193*4882a593Smuzhiyun case enable_option:
194*4882a593Smuzhiyun switch (*value) {
195*4882a593Smuzhiyun case OPTION_ENABLED:
196*4882a593Smuzhiyun e_dev_info("%s Enabled\n", opt->name);
197*4882a593Smuzhiyun return 0;
198*4882a593Smuzhiyun case OPTION_DISABLED:
199*4882a593Smuzhiyun e_dev_info("%s Disabled\n", opt->name);
200*4882a593Smuzhiyun return 0;
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun break;
203*4882a593Smuzhiyun case range_option:
204*4882a593Smuzhiyun if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) {
205*4882a593Smuzhiyun e_dev_info("%s set to %i\n", opt->name, *value);
206*4882a593Smuzhiyun return 0;
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun break;
209*4882a593Smuzhiyun case list_option: {
210*4882a593Smuzhiyun int i;
211*4882a593Smuzhiyun const struct e1000_opt_list *ent;
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun for (i = 0; i < opt->arg.l.nr; i++) {
214*4882a593Smuzhiyun ent = &opt->arg.l.p[i];
215*4882a593Smuzhiyun if (*value == ent->i) {
216*4882a593Smuzhiyun if (ent->str[0] != '\0')
217*4882a593Smuzhiyun e_dev_info("%s\n", ent->str);
218*4882a593Smuzhiyun return 0;
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun }
222*4882a593Smuzhiyun break;
223*4882a593Smuzhiyun default:
224*4882a593Smuzhiyun BUG();
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun e_dev_info("Invalid %s value specified (%i) %s\n",
228*4882a593Smuzhiyun opt->name, *value, opt->err);
229*4882a593Smuzhiyun *value = opt->def;
230*4882a593Smuzhiyun return -1;
231*4882a593Smuzhiyun }
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun static void e1000_check_fiber_options(struct e1000_adapter *adapter);
234*4882a593Smuzhiyun static void e1000_check_copper_options(struct e1000_adapter *adapter);
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun /**
237*4882a593Smuzhiyun * e1000_check_options - Range Checking for Command Line Parameters
238*4882a593Smuzhiyun * @adapter: board private structure
239*4882a593Smuzhiyun *
240*4882a593Smuzhiyun * This routine checks all command line parameters for valid user
241*4882a593Smuzhiyun * input. If an invalid value is given, or if no user specified
242*4882a593Smuzhiyun * value exists, a default value is used. The final value is stored
243*4882a593Smuzhiyun * in a variable in the adapter structure.
244*4882a593Smuzhiyun **/
e1000_check_options(struct e1000_adapter * adapter)245*4882a593Smuzhiyun void e1000_check_options(struct e1000_adapter *adapter)
246*4882a593Smuzhiyun {
247*4882a593Smuzhiyun struct e1000_option opt;
248*4882a593Smuzhiyun int bd = adapter->bd_number;
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun if (bd >= E1000_MAX_NIC) {
251*4882a593Smuzhiyun e_dev_warn("Warning: no configuration for board #%i "
252*4882a593Smuzhiyun "using defaults for all values\n", bd);
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun { /* Transmit Descriptor Count */
256*4882a593Smuzhiyun struct e1000_tx_ring *tx_ring = adapter->tx_ring;
257*4882a593Smuzhiyun int i;
258*4882a593Smuzhiyun e1000_mac_type mac_type = adapter->hw.mac_type;
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun opt = (struct e1000_option) {
261*4882a593Smuzhiyun .type = range_option,
262*4882a593Smuzhiyun .name = "Transmit Descriptors",
263*4882a593Smuzhiyun .err = "using default of "
264*4882a593Smuzhiyun __MODULE_STRING(E1000_DEFAULT_TXD),
265*4882a593Smuzhiyun .def = E1000_DEFAULT_TXD,
266*4882a593Smuzhiyun .arg = { .r = {
267*4882a593Smuzhiyun .min = E1000_MIN_TXD,
268*4882a593Smuzhiyun .max = mac_type < e1000_82544 ? E1000_MAX_TXD : E1000_MAX_82544_TXD
269*4882a593Smuzhiyun }}
270*4882a593Smuzhiyun };
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun if (num_TxDescriptors > bd) {
273*4882a593Smuzhiyun tx_ring->count = TxDescriptors[bd];
274*4882a593Smuzhiyun e1000_validate_option(&tx_ring->count, &opt, adapter);
275*4882a593Smuzhiyun tx_ring->count = ALIGN(tx_ring->count,
276*4882a593Smuzhiyun REQ_TX_DESCRIPTOR_MULTIPLE);
277*4882a593Smuzhiyun } else {
278*4882a593Smuzhiyun tx_ring->count = opt.def;
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun for (i = 0; i < adapter->num_tx_queues; i++)
281*4882a593Smuzhiyun tx_ring[i].count = tx_ring->count;
282*4882a593Smuzhiyun }
283*4882a593Smuzhiyun { /* Receive Descriptor Count */
284*4882a593Smuzhiyun struct e1000_rx_ring *rx_ring = adapter->rx_ring;
285*4882a593Smuzhiyun int i;
286*4882a593Smuzhiyun e1000_mac_type mac_type = adapter->hw.mac_type;
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun opt = (struct e1000_option) {
289*4882a593Smuzhiyun .type = range_option,
290*4882a593Smuzhiyun .name = "Receive Descriptors",
291*4882a593Smuzhiyun .err = "using default of "
292*4882a593Smuzhiyun __MODULE_STRING(E1000_DEFAULT_RXD),
293*4882a593Smuzhiyun .def = E1000_DEFAULT_RXD,
294*4882a593Smuzhiyun .arg = { .r = {
295*4882a593Smuzhiyun .min = E1000_MIN_RXD,
296*4882a593Smuzhiyun .max = mac_type < e1000_82544 ? E1000_MAX_RXD :
297*4882a593Smuzhiyun E1000_MAX_82544_RXD
298*4882a593Smuzhiyun }}
299*4882a593Smuzhiyun };
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun if (num_RxDescriptors > bd) {
302*4882a593Smuzhiyun rx_ring->count = RxDescriptors[bd];
303*4882a593Smuzhiyun e1000_validate_option(&rx_ring->count, &opt, adapter);
304*4882a593Smuzhiyun rx_ring->count = ALIGN(rx_ring->count,
305*4882a593Smuzhiyun REQ_RX_DESCRIPTOR_MULTIPLE);
306*4882a593Smuzhiyun } else {
307*4882a593Smuzhiyun rx_ring->count = opt.def;
308*4882a593Smuzhiyun }
309*4882a593Smuzhiyun for (i = 0; i < adapter->num_rx_queues; i++)
310*4882a593Smuzhiyun rx_ring[i].count = rx_ring->count;
311*4882a593Smuzhiyun }
312*4882a593Smuzhiyun { /* Checksum Offload Enable/Disable */
313*4882a593Smuzhiyun opt = (struct e1000_option) {
314*4882a593Smuzhiyun .type = enable_option,
315*4882a593Smuzhiyun .name = "Checksum Offload",
316*4882a593Smuzhiyun .err = "defaulting to Enabled",
317*4882a593Smuzhiyun .def = OPTION_ENABLED
318*4882a593Smuzhiyun };
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun if (num_XsumRX > bd) {
321*4882a593Smuzhiyun unsigned int rx_csum = XsumRX[bd];
322*4882a593Smuzhiyun e1000_validate_option(&rx_csum, &opt, adapter);
323*4882a593Smuzhiyun adapter->rx_csum = rx_csum;
324*4882a593Smuzhiyun } else {
325*4882a593Smuzhiyun adapter->rx_csum = opt.def;
326*4882a593Smuzhiyun }
327*4882a593Smuzhiyun }
328*4882a593Smuzhiyun { /* Flow Control */
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun static const struct e1000_opt_list fc_list[] = {
331*4882a593Smuzhiyun { E1000_FC_NONE, "Flow Control Disabled" },
332*4882a593Smuzhiyun { E1000_FC_RX_PAUSE, "Flow Control Receive Only" },
333*4882a593Smuzhiyun { E1000_FC_TX_PAUSE, "Flow Control Transmit Only" },
334*4882a593Smuzhiyun { E1000_FC_FULL, "Flow Control Enabled" },
335*4882a593Smuzhiyun { E1000_FC_DEFAULT, "Flow Control Hardware Default" }
336*4882a593Smuzhiyun };
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun opt = (struct e1000_option) {
339*4882a593Smuzhiyun .type = list_option,
340*4882a593Smuzhiyun .name = "Flow Control",
341*4882a593Smuzhiyun .err = "reading default settings from EEPROM",
342*4882a593Smuzhiyun .def = E1000_FC_DEFAULT,
343*4882a593Smuzhiyun .arg = { .l = { .nr = ARRAY_SIZE(fc_list),
344*4882a593Smuzhiyun .p = fc_list }}
345*4882a593Smuzhiyun };
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun if (num_FlowControl > bd) {
348*4882a593Smuzhiyun unsigned int fc = FlowControl[bd];
349*4882a593Smuzhiyun e1000_validate_option(&fc, &opt, adapter);
350*4882a593Smuzhiyun adapter->hw.fc = adapter->hw.original_fc = fc;
351*4882a593Smuzhiyun } else {
352*4882a593Smuzhiyun adapter->hw.fc = adapter->hw.original_fc = opt.def;
353*4882a593Smuzhiyun }
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun { /* Transmit Interrupt Delay */
356*4882a593Smuzhiyun opt = (struct e1000_option) {
357*4882a593Smuzhiyun .type = range_option,
358*4882a593Smuzhiyun .name = "Transmit Interrupt Delay",
359*4882a593Smuzhiyun .err = "using default of " __MODULE_STRING(DEFAULT_TIDV),
360*4882a593Smuzhiyun .def = DEFAULT_TIDV,
361*4882a593Smuzhiyun .arg = { .r = { .min = MIN_TXDELAY,
362*4882a593Smuzhiyun .max = MAX_TXDELAY }}
363*4882a593Smuzhiyun };
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun if (num_TxIntDelay > bd) {
366*4882a593Smuzhiyun adapter->tx_int_delay = TxIntDelay[bd];
367*4882a593Smuzhiyun e1000_validate_option(&adapter->tx_int_delay, &opt,
368*4882a593Smuzhiyun adapter);
369*4882a593Smuzhiyun } else {
370*4882a593Smuzhiyun adapter->tx_int_delay = opt.def;
371*4882a593Smuzhiyun }
372*4882a593Smuzhiyun }
373*4882a593Smuzhiyun { /* Transmit Absolute Interrupt Delay */
374*4882a593Smuzhiyun opt = (struct e1000_option) {
375*4882a593Smuzhiyun .type = range_option,
376*4882a593Smuzhiyun .name = "Transmit Absolute Interrupt Delay",
377*4882a593Smuzhiyun .err = "using default of " __MODULE_STRING(DEFAULT_TADV),
378*4882a593Smuzhiyun .def = DEFAULT_TADV,
379*4882a593Smuzhiyun .arg = { .r = { .min = MIN_TXABSDELAY,
380*4882a593Smuzhiyun .max = MAX_TXABSDELAY }}
381*4882a593Smuzhiyun };
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun if (num_TxAbsIntDelay > bd) {
384*4882a593Smuzhiyun adapter->tx_abs_int_delay = TxAbsIntDelay[bd];
385*4882a593Smuzhiyun e1000_validate_option(&adapter->tx_abs_int_delay, &opt,
386*4882a593Smuzhiyun adapter);
387*4882a593Smuzhiyun } else {
388*4882a593Smuzhiyun adapter->tx_abs_int_delay = opt.def;
389*4882a593Smuzhiyun }
390*4882a593Smuzhiyun }
391*4882a593Smuzhiyun { /* Receive Interrupt Delay */
392*4882a593Smuzhiyun opt = (struct e1000_option) {
393*4882a593Smuzhiyun .type = range_option,
394*4882a593Smuzhiyun .name = "Receive Interrupt Delay",
395*4882a593Smuzhiyun .err = "using default of " __MODULE_STRING(DEFAULT_RDTR),
396*4882a593Smuzhiyun .def = DEFAULT_RDTR,
397*4882a593Smuzhiyun .arg = { .r = { .min = MIN_RXDELAY,
398*4882a593Smuzhiyun .max = MAX_RXDELAY }}
399*4882a593Smuzhiyun };
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun if (num_RxIntDelay > bd) {
402*4882a593Smuzhiyun adapter->rx_int_delay = RxIntDelay[bd];
403*4882a593Smuzhiyun e1000_validate_option(&adapter->rx_int_delay, &opt,
404*4882a593Smuzhiyun adapter);
405*4882a593Smuzhiyun } else {
406*4882a593Smuzhiyun adapter->rx_int_delay = opt.def;
407*4882a593Smuzhiyun }
408*4882a593Smuzhiyun }
409*4882a593Smuzhiyun { /* Receive Absolute Interrupt Delay */
410*4882a593Smuzhiyun opt = (struct e1000_option) {
411*4882a593Smuzhiyun .type = range_option,
412*4882a593Smuzhiyun .name = "Receive Absolute Interrupt Delay",
413*4882a593Smuzhiyun .err = "using default of " __MODULE_STRING(DEFAULT_RADV),
414*4882a593Smuzhiyun .def = DEFAULT_RADV,
415*4882a593Smuzhiyun .arg = { .r = { .min = MIN_RXABSDELAY,
416*4882a593Smuzhiyun .max = MAX_RXABSDELAY }}
417*4882a593Smuzhiyun };
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun if (num_RxAbsIntDelay > bd) {
420*4882a593Smuzhiyun adapter->rx_abs_int_delay = RxAbsIntDelay[bd];
421*4882a593Smuzhiyun e1000_validate_option(&adapter->rx_abs_int_delay, &opt,
422*4882a593Smuzhiyun adapter);
423*4882a593Smuzhiyun } else {
424*4882a593Smuzhiyun adapter->rx_abs_int_delay = opt.def;
425*4882a593Smuzhiyun }
426*4882a593Smuzhiyun }
427*4882a593Smuzhiyun { /* Interrupt Throttling Rate */
428*4882a593Smuzhiyun opt = (struct e1000_option) {
429*4882a593Smuzhiyun .type = range_option,
430*4882a593Smuzhiyun .name = "Interrupt Throttling Rate (ints/sec)",
431*4882a593Smuzhiyun .err = "using default of " __MODULE_STRING(DEFAULT_ITR),
432*4882a593Smuzhiyun .def = DEFAULT_ITR,
433*4882a593Smuzhiyun .arg = { .r = { .min = MIN_ITR,
434*4882a593Smuzhiyun .max = MAX_ITR }}
435*4882a593Smuzhiyun };
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun if (num_InterruptThrottleRate > bd) {
438*4882a593Smuzhiyun adapter->itr = InterruptThrottleRate[bd];
439*4882a593Smuzhiyun switch (adapter->itr) {
440*4882a593Smuzhiyun case 0:
441*4882a593Smuzhiyun e_dev_info("%s turned off\n", opt.name);
442*4882a593Smuzhiyun break;
443*4882a593Smuzhiyun case 1:
444*4882a593Smuzhiyun e_dev_info("%s set to dynamic mode\n",
445*4882a593Smuzhiyun opt.name);
446*4882a593Smuzhiyun adapter->itr_setting = adapter->itr;
447*4882a593Smuzhiyun adapter->itr = 20000;
448*4882a593Smuzhiyun break;
449*4882a593Smuzhiyun case 3:
450*4882a593Smuzhiyun e_dev_info("%s set to dynamic conservative "
451*4882a593Smuzhiyun "mode\n", opt.name);
452*4882a593Smuzhiyun adapter->itr_setting = adapter->itr;
453*4882a593Smuzhiyun adapter->itr = 20000;
454*4882a593Smuzhiyun break;
455*4882a593Smuzhiyun case 4:
456*4882a593Smuzhiyun e_dev_info("%s set to simplified "
457*4882a593Smuzhiyun "(2000-8000) ints mode\n", opt.name);
458*4882a593Smuzhiyun adapter->itr_setting = adapter->itr;
459*4882a593Smuzhiyun break;
460*4882a593Smuzhiyun default:
461*4882a593Smuzhiyun e1000_validate_option(&adapter->itr, &opt,
462*4882a593Smuzhiyun adapter);
463*4882a593Smuzhiyun /* save the setting, because the dynamic bits
464*4882a593Smuzhiyun * change itr.
465*4882a593Smuzhiyun * clear the lower two bits because they are
466*4882a593Smuzhiyun * used as control
467*4882a593Smuzhiyun */
468*4882a593Smuzhiyun adapter->itr_setting = adapter->itr & ~3;
469*4882a593Smuzhiyun break;
470*4882a593Smuzhiyun }
471*4882a593Smuzhiyun } else {
472*4882a593Smuzhiyun adapter->itr_setting = opt.def;
473*4882a593Smuzhiyun adapter->itr = 20000;
474*4882a593Smuzhiyun }
475*4882a593Smuzhiyun }
476*4882a593Smuzhiyun { /* Smart Power Down */
477*4882a593Smuzhiyun opt = (struct e1000_option) {
478*4882a593Smuzhiyun .type = enable_option,
479*4882a593Smuzhiyun .name = "PHY Smart Power Down",
480*4882a593Smuzhiyun .err = "defaulting to Disabled",
481*4882a593Smuzhiyun .def = OPTION_DISABLED
482*4882a593Smuzhiyun };
483*4882a593Smuzhiyun
484*4882a593Smuzhiyun if (num_SmartPowerDownEnable > bd) {
485*4882a593Smuzhiyun unsigned int spd = SmartPowerDownEnable[bd];
486*4882a593Smuzhiyun e1000_validate_option(&spd, &opt, adapter);
487*4882a593Smuzhiyun adapter->smart_power_down = spd;
488*4882a593Smuzhiyun } else {
489*4882a593Smuzhiyun adapter->smart_power_down = opt.def;
490*4882a593Smuzhiyun }
491*4882a593Smuzhiyun }
492*4882a593Smuzhiyun
493*4882a593Smuzhiyun switch (adapter->hw.media_type) {
494*4882a593Smuzhiyun case e1000_media_type_fiber:
495*4882a593Smuzhiyun case e1000_media_type_internal_serdes:
496*4882a593Smuzhiyun e1000_check_fiber_options(adapter);
497*4882a593Smuzhiyun break;
498*4882a593Smuzhiyun case e1000_media_type_copper:
499*4882a593Smuzhiyun e1000_check_copper_options(adapter);
500*4882a593Smuzhiyun break;
501*4882a593Smuzhiyun default:
502*4882a593Smuzhiyun BUG();
503*4882a593Smuzhiyun }
504*4882a593Smuzhiyun }
505*4882a593Smuzhiyun
506*4882a593Smuzhiyun /**
507*4882a593Smuzhiyun * e1000_check_fiber_options - Range Checking for Link Options, Fiber Version
508*4882a593Smuzhiyun * @adapter: board private structure
509*4882a593Smuzhiyun *
510*4882a593Smuzhiyun * Handles speed and duplex options on fiber adapters
511*4882a593Smuzhiyun **/
e1000_check_fiber_options(struct e1000_adapter * adapter)512*4882a593Smuzhiyun static void e1000_check_fiber_options(struct e1000_adapter *adapter)
513*4882a593Smuzhiyun {
514*4882a593Smuzhiyun int bd = adapter->bd_number;
515*4882a593Smuzhiyun if (num_Speed > bd) {
516*4882a593Smuzhiyun e_dev_info("Speed not valid for fiber adapters, parameter "
517*4882a593Smuzhiyun "ignored\n");
518*4882a593Smuzhiyun }
519*4882a593Smuzhiyun
520*4882a593Smuzhiyun if (num_Duplex > bd) {
521*4882a593Smuzhiyun e_dev_info("Duplex not valid for fiber adapters, parameter "
522*4882a593Smuzhiyun "ignored\n");
523*4882a593Smuzhiyun }
524*4882a593Smuzhiyun
525*4882a593Smuzhiyun if ((num_AutoNeg > bd) && (AutoNeg[bd] != 0x20)) {
526*4882a593Smuzhiyun e_dev_info("AutoNeg other than 1000/Full is not valid for fiber"
527*4882a593Smuzhiyun "adapters, parameter ignored\n");
528*4882a593Smuzhiyun }
529*4882a593Smuzhiyun }
530*4882a593Smuzhiyun
531*4882a593Smuzhiyun /**
532*4882a593Smuzhiyun * e1000_check_copper_options - Range Checking for Link Options, Copper Version
533*4882a593Smuzhiyun * @adapter: board private structure
534*4882a593Smuzhiyun *
535*4882a593Smuzhiyun * Handles speed and duplex options on copper adapters
536*4882a593Smuzhiyun **/
e1000_check_copper_options(struct e1000_adapter * adapter)537*4882a593Smuzhiyun static void e1000_check_copper_options(struct e1000_adapter *adapter)
538*4882a593Smuzhiyun {
539*4882a593Smuzhiyun struct e1000_option opt;
540*4882a593Smuzhiyun unsigned int speed, dplx, an;
541*4882a593Smuzhiyun int bd = adapter->bd_number;
542*4882a593Smuzhiyun
543*4882a593Smuzhiyun { /* Speed */
544*4882a593Smuzhiyun static const struct e1000_opt_list speed_list[] = {
545*4882a593Smuzhiyun { 0, "" },
546*4882a593Smuzhiyun { SPEED_10, "" },
547*4882a593Smuzhiyun { SPEED_100, "" },
548*4882a593Smuzhiyun { SPEED_1000, "" }};
549*4882a593Smuzhiyun
550*4882a593Smuzhiyun opt = (struct e1000_option) {
551*4882a593Smuzhiyun .type = list_option,
552*4882a593Smuzhiyun .name = "Speed",
553*4882a593Smuzhiyun .err = "parameter ignored",
554*4882a593Smuzhiyun .def = 0,
555*4882a593Smuzhiyun .arg = { .l = { .nr = ARRAY_SIZE(speed_list),
556*4882a593Smuzhiyun .p = speed_list }}
557*4882a593Smuzhiyun };
558*4882a593Smuzhiyun
559*4882a593Smuzhiyun if (num_Speed > bd) {
560*4882a593Smuzhiyun speed = Speed[bd];
561*4882a593Smuzhiyun e1000_validate_option(&speed, &opt, adapter);
562*4882a593Smuzhiyun } else {
563*4882a593Smuzhiyun speed = opt.def;
564*4882a593Smuzhiyun }
565*4882a593Smuzhiyun }
566*4882a593Smuzhiyun { /* Duplex */
567*4882a593Smuzhiyun static const struct e1000_opt_list dplx_list[] = {
568*4882a593Smuzhiyun { 0, "" },
569*4882a593Smuzhiyun { HALF_DUPLEX, "" },
570*4882a593Smuzhiyun { FULL_DUPLEX, "" }};
571*4882a593Smuzhiyun
572*4882a593Smuzhiyun opt = (struct e1000_option) {
573*4882a593Smuzhiyun .type = list_option,
574*4882a593Smuzhiyun .name = "Duplex",
575*4882a593Smuzhiyun .err = "parameter ignored",
576*4882a593Smuzhiyun .def = 0,
577*4882a593Smuzhiyun .arg = { .l = { .nr = ARRAY_SIZE(dplx_list),
578*4882a593Smuzhiyun .p = dplx_list }}
579*4882a593Smuzhiyun };
580*4882a593Smuzhiyun
581*4882a593Smuzhiyun if (num_Duplex > bd) {
582*4882a593Smuzhiyun dplx = Duplex[bd];
583*4882a593Smuzhiyun e1000_validate_option(&dplx, &opt, adapter);
584*4882a593Smuzhiyun } else {
585*4882a593Smuzhiyun dplx = opt.def;
586*4882a593Smuzhiyun }
587*4882a593Smuzhiyun }
588*4882a593Smuzhiyun
589*4882a593Smuzhiyun if ((num_AutoNeg > bd) && (speed != 0 || dplx != 0)) {
590*4882a593Smuzhiyun e_dev_info("AutoNeg specified along with Speed or Duplex, "
591*4882a593Smuzhiyun "parameter ignored\n");
592*4882a593Smuzhiyun adapter->hw.autoneg_advertised = AUTONEG_ADV_DEFAULT;
593*4882a593Smuzhiyun } else { /* Autoneg */
594*4882a593Smuzhiyun static const struct e1000_opt_list an_list[] =
595*4882a593Smuzhiyun #define AA "AutoNeg advertising "
596*4882a593Smuzhiyun {{ 0x01, AA "10/HD" },
597*4882a593Smuzhiyun { 0x02, AA "10/FD" },
598*4882a593Smuzhiyun { 0x03, AA "10/FD, 10/HD" },
599*4882a593Smuzhiyun { 0x04, AA "100/HD" },
600*4882a593Smuzhiyun { 0x05, AA "100/HD, 10/HD" },
601*4882a593Smuzhiyun { 0x06, AA "100/HD, 10/FD" },
602*4882a593Smuzhiyun { 0x07, AA "100/HD, 10/FD, 10/HD" },
603*4882a593Smuzhiyun { 0x08, AA "100/FD" },
604*4882a593Smuzhiyun { 0x09, AA "100/FD, 10/HD" },
605*4882a593Smuzhiyun { 0x0a, AA "100/FD, 10/FD" },
606*4882a593Smuzhiyun { 0x0b, AA "100/FD, 10/FD, 10/HD" },
607*4882a593Smuzhiyun { 0x0c, AA "100/FD, 100/HD" },
608*4882a593Smuzhiyun { 0x0d, AA "100/FD, 100/HD, 10/HD" },
609*4882a593Smuzhiyun { 0x0e, AA "100/FD, 100/HD, 10/FD" },
610*4882a593Smuzhiyun { 0x0f, AA "100/FD, 100/HD, 10/FD, 10/HD" },
611*4882a593Smuzhiyun { 0x20, AA "1000/FD" },
612*4882a593Smuzhiyun { 0x21, AA "1000/FD, 10/HD" },
613*4882a593Smuzhiyun { 0x22, AA "1000/FD, 10/FD" },
614*4882a593Smuzhiyun { 0x23, AA "1000/FD, 10/FD, 10/HD" },
615*4882a593Smuzhiyun { 0x24, AA "1000/FD, 100/HD" },
616*4882a593Smuzhiyun { 0x25, AA "1000/FD, 100/HD, 10/HD" },
617*4882a593Smuzhiyun { 0x26, AA "1000/FD, 100/HD, 10/FD" },
618*4882a593Smuzhiyun { 0x27, AA "1000/FD, 100/HD, 10/FD, 10/HD" },
619*4882a593Smuzhiyun { 0x28, AA "1000/FD, 100/FD" },
620*4882a593Smuzhiyun { 0x29, AA "1000/FD, 100/FD, 10/HD" },
621*4882a593Smuzhiyun { 0x2a, AA "1000/FD, 100/FD, 10/FD" },
622*4882a593Smuzhiyun { 0x2b, AA "1000/FD, 100/FD, 10/FD, 10/HD" },
623*4882a593Smuzhiyun { 0x2c, AA "1000/FD, 100/FD, 100/HD" },
624*4882a593Smuzhiyun { 0x2d, AA "1000/FD, 100/FD, 100/HD, 10/HD" },
625*4882a593Smuzhiyun { 0x2e, AA "1000/FD, 100/FD, 100/HD, 10/FD" },
626*4882a593Smuzhiyun { 0x2f, AA "1000/FD, 100/FD, 100/HD, 10/FD, 10/HD" }};
627*4882a593Smuzhiyun
628*4882a593Smuzhiyun opt = (struct e1000_option) {
629*4882a593Smuzhiyun .type = list_option,
630*4882a593Smuzhiyun .name = "AutoNeg",
631*4882a593Smuzhiyun .err = "parameter ignored",
632*4882a593Smuzhiyun .def = AUTONEG_ADV_DEFAULT,
633*4882a593Smuzhiyun .arg = { .l = { .nr = ARRAY_SIZE(an_list),
634*4882a593Smuzhiyun .p = an_list }}
635*4882a593Smuzhiyun };
636*4882a593Smuzhiyun
637*4882a593Smuzhiyun if (num_AutoNeg > bd) {
638*4882a593Smuzhiyun an = AutoNeg[bd];
639*4882a593Smuzhiyun e1000_validate_option(&an, &opt, adapter);
640*4882a593Smuzhiyun } else {
641*4882a593Smuzhiyun an = opt.def;
642*4882a593Smuzhiyun }
643*4882a593Smuzhiyun adapter->hw.autoneg_advertised = an;
644*4882a593Smuzhiyun }
645*4882a593Smuzhiyun
646*4882a593Smuzhiyun switch (speed + dplx) {
647*4882a593Smuzhiyun case 0:
648*4882a593Smuzhiyun adapter->hw.autoneg = adapter->fc_autoneg = 1;
649*4882a593Smuzhiyun if ((num_Speed > bd) && (speed != 0 || dplx != 0))
650*4882a593Smuzhiyun e_dev_info("Speed and duplex autonegotiation "
651*4882a593Smuzhiyun "enabled\n");
652*4882a593Smuzhiyun break;
653*4882a593Smuzhiyun case HALF_DUPLEX:
654*4882a593Smuzhiyun e_dev_info("Half Duplex specified without Speed\n");
655*4882a593Smuzhiyun e_dev_info("Using Autonegotiation at Half Duplex only\n");
656*4882a593Smuzhiyun adapter->hw.autoneg = adapter->fc_autoneg = 1;
657*4882a593Smuzhiyun adapter->hw.autoneg_advertised = ADVERTISE_10_HALF |
658*4882a593Smuzhiyun ADVERTISE_100_HALF;
659*4882a593Smuzhiyun break;
660*4882a593Smuzhiyun case FULL_DUPLEX:
661*4882a593Smuzhiyun e_dev_info("Full Duplex specified without Speed\n");
662*4882a593Smuzhiyun e_dev_info("Using Autonegotiation at Full Duplex only\n");
663*4882a593Smuzhiyun adapter->hw.autoneg = adapter->fc_autoneg = 1;
664*4882a593Smuzhiyun adapter->hw.autoneg_advertised = ADVERTISE_10_FULL |
665*4882a593Smuzhiyun ADVERTISE_100_FULL |
666*4882a593Smuzhiyun ADVERTISE_1000_FULL;
667*4882a593Smuzhiyun break;
668*4882a593Smuzhiyun case SPEED_10:
669*4882a593Smuzhiyun e_dev_info("10 Mbps Speed specified without Duplex\n");
670*4882a593Smuzhiyun e_dev_info("Using Autonegotiation at 10 Mbps only\n");
671*4882a593Smuzhiyun adapter->hw.autoneg = adapter->fc_autoneg = 1;
672*4882a593Smuzhiyun adapter->hw.autoneg_advertised = ADVERTISE_10_HALF |
673*4882a593Smuzhiyun ADVERTISE_10_FULL;
674*4882a593Smuzhiyun break;
675*4882a593Smuzhiyun case SPEED_10 + HALF_DUPLEX:
676*4882a593Smuzhiyun e_dev_info("Forcing to 10 Mbps Half Duplex\n");
677*4882a593Smuzhiyun adapter->hw.autoneg = adapter->fc_autoneg = 0;
678*4882a593Smuzhiyun adapter->hw.forced_speed_duplex = e1000_10_half;
679*4882a593Smuzhiyun adapter->hw.autoneg_advertised = 0;
680*4882a593Smuzhiyun break;
681*4882a593Smuzhiyun case SPEED_10 + FULL_DUPLEX:
682*4882a593Smuzhiyun e_dev_info("Forcing to 10 Mbps Full Duplex\n");
683*4882a593Smuzhiyun adapter->hw.autoneg = adapter->fc_autoneg = 0;
684*4882a593Smuzhiyun adapter->hw.forced_speed_duplex = e1000_10_full;
685*4882a593Smuzhiyun adapter->hw.autoneg_advertised = 0;
686*4882a593Smuzhiyun break;
687*4882a593Smuzhiyun case SPEED_100:
688*4882a593Smuzhiyun e_dev_info("100 Mbps Speed specified without Duplex\n");
689*4882a593Smuzhiyun e_dev_info("Using Autonegotiation at 100 Mbps only\n");
690*4882a593Smuzhiyun adapter->hw.autoneg = adapter->fc_autoneg = 1;
691*4882a593Smuzhiyun adapter->hw.autoneg_advertised = ADVERTISE_100_HALF |
692*4882a593Smuzhiyun ADVERTISE_100_FULL;
693*4882a593Smuzhiyun break;
694*4882a593Smuzhiyun case SPEED_100 + HALF_DUPLEX:
695*4882a593Smuzhiyun e_dev_info("Forcing to 100 Mbps Half Duplex\n");
696*4882a593Smuzhiyun adapter->hw.autoneg = adapter->fc_autoneg = 0;
697*4882a593Smuzhiyun adapter->hw.forced_speed_duplex = e1000_100_half;
698*4882a593Smuzhiyun adapter->hw.autoneg_advertised = 0;
699*4882a593Smuzhiyun break;
700*4882a593Smuzhiyun case SPEED_100 + FULL_DUPLEX:
701*4882a593Smuzhiyun e_dev_info("Forcing to 100 Mbps Full Duplex\n");
702*4882a593Smuzhiyun adapter->hw.autoneg = adapter->fc_autoneg = 0;
703*4882a593Smuzhiyun adapter->hw.forced_speed_duplex = e1000_100_full;
704*4882a593Smuzhiyun adapter->hw.autoneg_advertised = 0;
705*4882a593Smuzhiyun break;
706*4882a593Smuzhiyun case SPEED_1000:
707*4882a593Smuzhiyun e_dev_info("1000 Mbps Speed specified without Duplex\n");
708*4882a593Smuzhiyun goto full_duplex_only;
709*4882a593Smuzhiyun case SPEED_1000 + HALF_DUPLEX:
710*4882a593Smuzhiyun e_dev_info("Half Duplex is not supported at 1000 Mbps\n");
711*4882a593Smuzhiyun fallthrough;
712*4882a593Smuzhiyun case SPEED_1000 + FULL_DUPLEX:
713*4882a593Smuzhiyun full_duplex_only:
714*4882a593Smuzhiyun e_dev_info("Using Autonegotiation at 1000 Mbps Full Duplex "
715*4882a593Smuzhiyun "only\n");
716*4882a593Smuzhiyun adapter->hw.autoneg = adapter->fc_autoneg = 1;
717*4882a593Smuzhiyun adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
718*4882a593Smuzhiyun break;
719*4882a593Smuzhiyun default:
720*4882a593Smuzhiyun BUG();
721*4882a593Smuzhiyun }
722*4882a593Smuzhiyun
723*4882a593Smuzhiyun /* Speed, AutoNeg and MDI/MDI-X must all play nice */
724*4882a593Smuzhiyun if (e1000_validate_mdi_setting(&(adapter->hw)) < 0) {
725*4882a593Smuzhiyun e_dev_info("Speed, AutoNeg and MDI-X specs are incompatible. "
726*4882a593Smuzhiyun "Setting MDI-X to a compatible value.\n");
727*4882a593Smuzhiyun }
728*4882a593Smuzhiyun }
729*4882a593Smuzhiyun
730