Commit | Line | Data |
---|---|---|
e78b80b1 DE |
1 | /* Intel PRO/1000 Linux driver |
2 | * Copyright(c) 1999 - 2014 Intel Corporation. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify it | |
5 | * under the terms and conditions of the GNU General Public License, | |
6 | * version 2, as published by the Free Software Foundation. | |
7 | * | |
8 | * This program is distributed in the hope it will be useful, but WITHOUT | |
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
11 | * more details. | |
12 | * | |
13 | * The full GNU General Public License is included in this distribution in | |
14 | * the file called "COPYING". | |
15 | * | |
16 | * Contact Information: | |
17 | * Linux NICS <linux.nics@intel.com> | |
18 | * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> | |
19 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | |
20 | */ | |
bc7f75fa AK |
21 | |
22 | #include <linux/netdevice.h> | |
9d9779e7 | 23 | #include <linux/module.h> |
44defeb3 | 24 | #include <linux/pci.h> |
bc7f75fa AK |
25 | |
26 | #include "e1000.h" | |
27 | ||
e921eb1a | 28 | /* This is the only thing that needs to be changed to adjust the |
bc7f75fa AK |
29 | * maximum number of ports that the driver can manage. |
30 | */ | |
bc7f75fa AK |
31 | #define E1000_MAX_NIC 32 |
32 | ||
33 | #define OPTION_UNSET -1 | |
34 | #define OPTION_DISABLED 0 | |
35 | #define OPTION_ENABLED 1 | |
36 | ||
37 | #define COPYBREAK_DEFAULT 256 | |
38 | unsigned int copybreak = COPYBREAK_DEFAULT; | |
39 | module_param(copybreak, uint, 0644); | |
40 | MODULE_PARM_DESC(copybreak, | |
17e813ec | 41 | "Maximum size of packet that is copied to a new buffer on receive"); |
bc7f75fa | 42 | |
e921eb1a | 43 | /* All parameters are treated the same, as an integer array of values. |
bc7f75fa AK |
44 | * This macro just reduces the need to repeat the same declaration code |
45 | * over and over (plus this helps to avoid typo bugs). | |
46 | */ | |
bc7f75fa | 47 | #define E1000_PARAM_INIT { [0 ... E1000_MAX_NIC] = OPTION_UNSET } |
5a9147bb | 48 | #define E1000_PARAM(X, desc) \ |
55c5f55e | 49 | static int X[E1000_MAX_NIC+1] = E1000_PARAM_INIT; \ |
5a9147bb SH |
50 | static unsigned int num_##X; \ |
51 | module_param_array_named(X, X, int, &num_##X, 0); \ | |
bc7f75fa AK |
52 | MODULE_PARM_DESC(X, desc); |
53 | ||
e921eb1a | 54 | /* Transmit Interrupt Delay in units of 1.024 microseconds |
af667a29 | 55 | * Tx interrupt delay needs to typically be set to something non-zero |
bc7f75fa AK |
56 | * |
57 | * Valid Range: 0-65535 | |
58 | */ | |
59 | E1000_PARAM(TxIntDelay, "Transmit Interrupt Delay"); | |
60 | #define DEFAULT_TIDV 8 | |
61 | #define MAX_TXDELAY 0xFFFF | |
62 | #define MIN_TXDELAY 0 | |
63 | ||
e921eb1a | 64 | /* Transmit Absolute Interrupt Delay in units of 1.024 microseconds |
bc7f75fa AK |
65 | * |
66 | * Valid Range: 0-65535 | |
67 | */ | |
68 | E1000_PARAM(TxAbsIntDelay, "Transmit Absolute Interrupt Delay"); | |
69 | #define DEFAULT_TADV 32 | |
70 | #define MAX_TXABSDELAY 0xFFFF | |
71 | #define MIN_TXABSDELAY 0 | |
72 | ||
e921eb1a | 73 | /* Receive Interrupt Delay in units of 1.024 microseconds |
ad68076e | 74 | * hardware will likely hang if you set this to anything but zero. |
bc7f75fa AK |
75 | * |
76 | * Valid Range: 0-65535 | |
77 | */ | |
78 | E1000_PARAM(RxIntDelay, "Receive Interrupt Delay"); | |
bc7f75fa AK |
79 | #define MAX_RXDELAY 0xFFFF |
80 | #define MIN_RXDELAY 0 | |
81 | ||
e921eb1a | 82 | /* Receive Absolute Interrupt Delay in units of 1.024 microseconds |
bc7f75fa AK |
83 | * |
84 | * Valid Range: 0-65535 | |
85 | */ | |
86 | E1000_PARAM(RxAbsIntDelay, "Receive Absolute Interrupt Delay"); | |
bc7f75fa AK |
87 | #define MAX_RXABSDELAY 0xFFFF |
88 | #define MIN_RXABSDELAY 0 | |
89 | ||
e921eb1a | 90 | /* Interrupt Throttle Rate (interrupts/sec) |
bc7f75fa | 91 | * |
727c356f | 92 | * Valid Range: 100-100000 or one of: 0=off, 1=dynamic, 3=dynamic conservative |
bc7f75fa AK |
93 | */ |
94 | E1000_PARAM(InterruptThrottleRate, "Interrupt Throttling Rate"); | |
95 | #define DEFAULT_ITR 3 | |
96 | #define MAX_ITR 100000 | |
97 | #define MIN_ITR 100 | |
af667a29 | 98 | |
e921eb1a | 99 | /* IntMode (Interrupt Mode) |
b6fbca2a BA |
100 | * |
101 | * Valid Range: varies depending on kernel configuration & hardware support | |
102 | * | |
103 | * legacy=0, MSI=1, MSI-X=2 | |
4662e82b | 104 | * |
b6fbca2a BA |
105 | * When MSI/MSI-X support is enabled in kernel- |
106 | * Default Value: 2 (MSI-X) when supported by hardware, 1 (MSI) otherwise | |
107 | * When MSI/MSI-X support is not enabled in kernel- | |
108 | * Default Value: 0 (legacy) | |
4662e82b | 109 | * |
b6fbca2a BA |
110 | * When a mode is specified that is not allowed/supported, it will be |
111 | * demoted to the most advanced interrupt mode available. | |
4662e82b BA |
112 | */ |
113 | E1000_PARAM(IntMode, "Interrupt Mode"); | |
114 | #define MAX_INTMODE 2 | |
115 | #define MIN_INTMODE 0 | |
bc7f75fa | 116 | |
e921eb1a | 117 | /* Enable Smart Power Down of the PHY |
bc7f75fa AK |
118 | * |
119 | * Valid Range: 0, 1 | |
120 | * | |
121 | * Default Value: 0 (disabled) | |
122 | */ | |
123 | E1000_PARAM(SmartPowerDownEnable, "Enable PHY smart power down"); | |
124 | ||
e921eb1a | 125 | /* Enable Kumeran Lock Loss workaround |
bc7f75fa AK |
126 | * |
127 | * Valid Range: 0, 1 | |
128 | * | |
129 | * Default Value: 1 (enabled) | |
130 | */ | |
131 | E1000_PARAM(KumeranLockLoss, "Enable Kumeran lock loss workaround"); | |
132 | ||
e921eb1a | 133 | /* Write Protect NVM |
4a770358 BA |
134 | * |
135 | * Valid Range: 0, 1 | |
136 | * | |
137 | * Default Value: 1 (enabled) | |
138 | */ | |
c29c3ba5 BA |
139 | E1000_PARAM(WriteProtectNVM, |
140 | "Write-protect NVM [WARNING: disabling this can lead to corrupted NVM]"); | |
4a770358 | 141 | |
e921eb1a | 142 | /* Enable CRC Stripping |
eb7c3adb JK |
143 | * |
144 | * Valid Range: 0, 1 | |
145 | * | |
146 | * Default Value: 1 (enabled) | |
147 | */ | |
6ad65145 BA |
148 | E1000_PARAM(CrcStripping, |
149 | "Enable CRC Stripping, disable if your BMC needs the CRC"); | |
eb7c3adb | 150 | |
bc7f75fa AK |
151 | struct e1000_option { |
152 | enum { enable_option, range_option, list_option } type; | |
5a9147bb SH |
153 | const char *name; |
154 | const char *err; | |
155 | int def; | |
bc7f75fa | 156 | union { |
33550cec BA |
157 | /* range_option info */ |
158 | struct { | |
bc7f75fa AK |
159 | int min; |
160 | int max; | |
161 | } r; | |
33550cec BA |
162 | /* list_option info */ |
163 | struct { | |
bc7f75fa | 164 | int nr; |
bbf44127 BA |
165 | struct e1000_opt_list { |
166 | int i; | |
167 | char *str; | |
168 | } *p; | |
bc7f75fa AK |
169 | } l; |
170 | } arg; | |
171 | }; | |
172 | ||
9f9a12f8 | 173 | static int e1000_validate_option(unsigned int *value, |
1dd06ae8 GKH |
174 | const struct e1000_option *opt, |
175 | struct e1000_adapter *adapter) | |
bc7f75fa AK |
176 | { |
177 | if (*value == OPTION_UNSET) { | |
178 | *value = opt->def; | |
179 | return 0; | |
180 | } | |
181 | ||
182 | switch (opt->type) { | |
183 | case enable_option: | |
184 | switch (*value) { | |
185 | case OPTION_ENABLED: | |
185095fb BA |
186 | dev_info(&adapter->pdev->dev, "%s Enabled\n", |
187 | opt->name); | |
bc7f75fa AK |
188 | return 0; |
189 | case OPTION_DISABLED: | |
185095fb BA |
190 | dev_info(&adapter->pdev->dev, "%s Disabled\n", |
191 | opt->name); | |
bc7f75fa AK |
192 | return 0; |
193 | } | |
194 | break; | |
195 | case range_option: | |
196 | if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) { | |
185095fb BA |
197 | dev_info(&adapter->pdev->dev, "%s set to %i\n", |
198 | opt->name, *value); | |
bc7f75fa AK |
199 | return 0; |
200 | } | |
201 | break; | |
202 | case list_option: { | |
203 | int i; | |
204 | struct e1000_opt_list *ent; | |
205 | ||
206 | for (i = 0; i < opt->arg.l.nr; i++) { | |
207 | ent = &opt->arg.l.p[i]; | |
208 | if (*value == ent->i) { | |
209 | if (ent->str[0] != '\0') | |
185095fb BA |
210 | dev_info(&adapter->pdev->dev, "%s\n", |
211 | ent->str); | |
bc7f75fa AK |
212 | return 0; |
213 | } | |
214 | } | |
215 | } | |
216 | break; | |
217 | default: | |
218 | BUG(); | |
219 | } | |
220 | ||
185095fb BA |
221 | dev_info(&adapter->pdev->dev, "Invalid %s value specified (%i) %s\n", |
222 | opt->name, *value, opt->err); | |
bc7f75fa AK |
223 | *value = opt->def; |
224 | return -1; | |
225 | } | |
226 | ||
227 | /** | |
228 | * e1000e_check_options - Range Checking for Command Line Parameters | |
229 | * @adapter: board private structure | |
230 | * | |
231 | * This routine checks all command line parameters for valid user | |
232 | * input. If an invalid value is given, or if no user specified | |
233 | * value exists, a default value is used. The final value is stored | |
234 | * in a variable in the adapter structure. | |
235 | **/ | |
9f9a12f8 | 236 | void e1000e_check_options(struct e1000_adapter *adapter) |
bc7f75fa AK |
237 | { |
238 | struct e1000_hw *hw = &adapter->hw; | |
bc7f75fa AK |
239 | int bd = adapter->bd_number; |
240 | ||
241 | if (bd >= E1000_MAX_NIC) { | |
185095fb BA |
242 | dev_notice(&adapter->pdev->dev, |
243 | "Warning: no configuration for board #%i\n", bd); | |
244 | dev_notice(&adapter->pdev->dev, | |
245 | "Using defaults for all values\n"); | |
bc7f75fa AK |
246 | } |
247 | ||
33550cec BA |
248 | /* Transmit Interrupt Delay */ |
249 | { | |
6f59d660 | 250 | static const struct e1000_option opt = { |
bc7f75fa AK |
251 | .type = range_option, |
252 | .name = "Transmit Interrupt Delay", | |
253 | .err = "using default of " | |
254 | __MODULE_STRING(DEFAULT_TIDV), | |
255 | .def = DEFAULT_TIDV, | |
256 | .arg = { .r = { .min = MIN_TXDELAY, | |
257 | .max = MAX_TXDELAY } } | |
258 | }; | |
259 | ||
260 | if (num_TxIntDelay > bd) { | |
261 | adapter->tx_int_delay = TxIntDelay[bd]; | |
262 | e1000_validate_option(&adapter->tx_int_delay, &opt, | |
263 | adapter); | |
264 | } else { | |
265 | adapter->tx_int_delay = opt.def; | |
266 | } | |
267 | } | |
33550cec BA |
268 | /* Transmit Absolute Interrupt Delay */ |
269 | { | |
6f59d660 | 270 | static const struct e1000_option opt = { |
bc7f75fa AK |
271 | .type = range_option, |
272 | .name = "Transmit Absolute Interrupt Delay", | |
273 | .err = "using default of " | |
274 | __MODULE_STRING(DEFAULT_TADV), | |
275 | .def = DEFAULT_TADV, | |
276 | .arg = { .r = { .min = MIN_TXABSDELAY, | |
277 | .max = MAX_TXABSDELAY } } | |
278 | }; | |
279 | ||
280 | if (num_TxAbsIntDelay > bd) { | |
281 | adapter->tx_abs_int_delay = TxAbsIntDelay[bd]; | |
282 | e1000_validate_option(&adapter->tx_abs_int_delay, &opt, | |
283 | adapter); | |
284 | } else { | |
285 | adapter->tx_abs_int_delay = opt.def; | |
286 | } | |
287 | } | |
33550cec BA |
288 | /* Receive Interrupt Delay */ |
289 | { | |
4fe4491f | 290 | static struct e1000_option opt = { |
bc7f75fa AK |
291 | .type = range_option, |
292 | .name = "Receive Interrupt Delay", | |
293 | .err = "using default of " | |
294 | __MODULE_STRING(DEFAULT_RDTR), | |
295 | .def = DEFAULT_RDTR, | |
296 | .arg = { .r = { .min = MIN_RXDELAY, | |
297 | .max = MAX_RXDELAY } } | |
298 | }; | |
299 | ||
bc7f75fa AK |
300 | if (num_RxIntDelay > bd) { |
301 | adapter->rx_int_delay = RxIntDelay[bd]; | |
302 | e1000_validate_option(&adapter->rx_int_delay, &opt, | |
303 | adapter); | |
304 | } else { | |
305 | adapter->rx_int_delay = opt.def; | |
306 | } | |
307 | } | |
33550cec BA |
308 | /* Receive Absolute Interrupt Delay */ |
309 | { | |
6f59d660 | 310 | static const struct e1000_option opt = { |
bc7f75fa AK |
311 | .type = range_option, |
312 | .name = "Receive Absolute Interrupt Delay", | |
313 | .err = "using default of " | |
314 | __MODULE_STRING(DEFAULT_RADV), | |
315 | .def = DEFAULT_RADV, | |
316 | .arg = { .r = { .min = MIN_RXABSDELAY, | |
317 | .max = MAX_RXABSDELAY } } | |
318 | }; | |
319 | ||
320 | if (num_RxAbsIntDelay > bd) { | |
321 | adapter->rx_abs_int_delay = RxAbsIntDelay[bd]; | |
322 | e1000_validate_option(&adapter->rx_abs_int_delay, &opt, | |
323 | adapter); | |
324 | } else { | |
325 | adapter->rx_abs_int_delay = opt.def; | |
326 | } | |
327 | } | |
33550cec BA |
328 | /* Interrupt Throttling Rate */ |
329 | { | |
6f59d660 | 330 | static const struct e1000_option opt = { |
bc7f75fa AK |
331 | .type = range_option, |
332 | .name = "Interrupt Throttling Rate (ints/sec)", | |
333 | .err = "using default of " | |
334 | __MODULE_STRING(DEFAULT_ITR), | |
335 | .def = DEFAULT_ITR, | |
336 | .arg = { .r = { .min = MIN_ITR, | |
337 | .max = MAX_ITR } } | |
338 | }; | |
339 | ||
340 | if (num_InterruptThrottleRate > bd) { | |
341 | adapter->itr = InterruptThrottleRate[bd]; | |
2e7d21c5 | 342 | |
e921eb1a | 343 | /* Make sure a message is printed for non-special |
2e7d21c5 JK |
344 | * values. And in case of an invalid option, display |
345 | * warning, use default and go through itr/itr_setting | |
346 | * adjustment logic below | |
347 | */ | |
348 | if ((adapter->itr > 4) && | |
349 | e1000_validate_option(&adapter->itr, &opt, adapter)) | |
350 | adapter->itr = opt.def; | |
bc7f75fa | 351 | } else { |
e921eb1a | 352 | /* If no option specified, use default value and go |
727c356f JK |
353 | * through the logic below to adjust itr/itr_setting |
354 | */ | |
355 | adapter->itr = opt.def; | |
356 | ||
e921eb1a | 357 | /* Make sure a message is printed for non-special |
727c356f JK |
358 | * default values |
359 | */ | |
2e7d21c5 | 360 | if (adapter->itr > 4) |
185095fb BA |
361 | dev_info(&adapter->pdev->dev, |
362 | "%s set to default %d\n", opt.name, | |
363 | adapter->itr); | |
727c356f JK |
364 | } |
365 | ||
366 | adapter->itr_setting = adapter->itr; | |
367 | switch (adapter->itr) { | |
368 | case 0: | |
185095fb BA |
369 | dev_info(&adapter->pdev->dev, "%s turned off\n", |
370 | opt.name); | |
727c356f JK |
371 | break; |
372 | case 1: | |
185095fb BA |
373 | dev_info(&adapter->pdev->dev, |
374 | "%s set to dynamic mode\n", opt.name); | |
727c356f JK |
375 | adapter->itr = 20000; |
376 | break; | |
377 | case 3: | |
185095fb BA |
378 | dev_info(&adapter->pdev->dev, |
379 | "%s set to dynamic conservative mode\n", | |
380 | opt.name); | |
bc7f75fa | 381 | adapter->itr = 20000; |
727c356f JK |
382 | break; |
383 | case 4: | |
185095fb BA |
384 | dev_info(&adapter->pdev->dev, |
385 | "%s set to simplified (2000-8000 ints) mode\n", | |
386 | opt.name); | |
727c356f JK |
387 | break; |
388 | default: | |
e921eb1a | 389 | /* Save the setting, because the dynamic bits |
727c356f JK |
390 | * change itr. |
391 | * | |
392 | * Clear the lower two bits because | |
393 | * they are used as control. | |
394 | */ | |
395 | adapter->itr_setting &= ~3; | |
396 | break; | |
bc7f75fa AK |
397 | } |
398 | } | |
33550cec BA |
399 | /* Interrupt Mode */ |
400 | { | |
4fe4491f | 401 | static struct e1000_option opt = { |
4662e82b BA |
402 | .type = range_option, |
403 | .name = "Interrupt Mode", | |
b6fbca2a BA |
404 | #ifndef CONFIG_PCI_MSI |
405 | .err = "defaulting to 0 (legacy)", | |
406 | .def = E1000E_INT_MODE_LEGACY, | |
407 | .arg = { .r = { .min = 0, | |
408 | .max = 0 } } | |
409 | #endif | |
4662e82b BA |
410 | }; |
411 | ||
b6fbca2a BA |
412 | #ifdef CONFIG_PCI_MSI |
413 | if (adapter->flags & FLAG_HAS_MSIX) { | |
414 | opt.err = kstrdup("defaulting to 2 (MSI-X)", | |
415 | GFP_KERNEL); | |
416 | opt.def = E1000E_INT_MODE_MSIX; | |
417 | opt.arg.r.max = E1000E_INT_MODE_MSIX; | |
418 | } else { | |
419 | opt.err = kstrdup("defaulting to 1 (MSI)", GFP_KERNEL); | |
420 | opt.def = E1000E_INT_MODE_MSI; | |
421 | opt.arg.r.max = E1000E_INT_MODE_MSI; | |
422 | } | |
423 | ||
424 | if (!opt.err) { | |
425 | dev_err(&adapter->pdev->dev, | |
426 | "Failed to allocate memory\n"); | |
427 | return; | |
428 | } | |
429 | #endif | |
430 | ||
4662e82b BA |
431 | if (num_IntMode > bd) { |
432 | unsigned int int_mode = IntMode[bd]; | |
433 | e1000_validate_option(&int_mode, &opt, adapter); | |
434 | adapter->int_mode = int_mode; | |
435 | } else { | |
436 | adapter->int_mode = opt.def; | |
437 | } | |
b6fbca2a BA |
438 | |
439 | #ifdef CONFIG_PCI_MSI | |
440 | kfree(opt.err); | |
441 | #endif | |
4662e82b | 442 | } |
33550cec BA |
443 | /* Smart Power Down */ |
444 | { | |
6f59d660 | 445 | static const struct e1000_option opt = { |
bc7f75fa AK |
446 | .type = enable_option, |
447 | .name = "PHY Smart Power Down", | |
448 | .err = "defaulting to Disabled", | |
449 | .def = OPTION_DISABLED | |
450 | }; | |
451 | ||
452 | if (num_SmartPowerDownEnable > bd) { | |
5a9147bb | 453 | unsigned int spd = SmartPowerDownEnable[bd]; |
bc7f75fa | 454 | e1000_validate_option(&spd, &opt, adapter); |
1860ac84 | 455 | if ((adapter->flags & FLAG_HAS_SMART_POWER_DOWN) && spd) |
bc7f75fa AK |
456 | adapter->flags |= FLAG_SMART_POWER_DOWN; |
457 | } | |
458 | } | |
33550cec BA |
459 | /* CRC Stripping */ |
460 | { | |
6f59d660 | 461 | static const struct e1000_option opt = { |
eb7c3adb JK |
462 | .type = enable_option, |
463 | .name = "CRC Stripping", | |
e9262447 | 464 | .err = "defaulting to Enabled", |
eb7c3adb JK |
465 | .def = OPTION_ENABLED |
466 | }; | |
467 | ||
468 | if (num_CrcStripping > bd) { | |
469 | unsigned int crc_stripping = CrcStripping[bd]; | |
470 | e1000_validate_option(&crc_stripping, &opt, adapter); | |
0184039a | 471 | if (crc_stripping == OPTION_ENABLED) { |
eb7c3adb | 472 | adapter->flags2 |= FLAG2_CRC_STRIPPING; |
0184039a BG |
473 | adapter->flags2 |= FLAG2_DFLT_CRC_STRIPPING; |
474 | } | |
6e50912a BA |
475 | } else { |
476 | adapter->flags2 |= FLAG2_CRC_STRIPPING; | |
0184039a | 477 | adapter->flags2 |= FLAG2_DFLT_CRC_STRIPPING; |
eb7c3adb JK |
478 | } |
479 | } | |
33550cec BA |
480 | /* Kumeran Lock Loss Workaround */ |
481 | { | |
6f59d660 | 482 | static const struct e1000_option opt = { |
bc7f75fa AK |
483 | .type = enable_option, |
484 | .name = "Kumeran Lock Loss Workaround", | |
485 | .err = "defaulting to Enabled", | |
486 | .def = OPTION_ENABLED | |
487 | }; | |
17e813ec | 488 | bool enabled = opt.def; |
bc7f75fa AK |
489 | |
490 | if (num_KumeranLockLoss > bd) { | |
5a9147bb | 491 | unsigned int kmrn_lock_loss = KumeranLockLoss[bd]; |
bc7f75fa | 492 | e1000_validate_option(&kmrn_lock_loss, &opt, adapter); |
17e813ec | 493 | enabled = kmrn_lock_loss; |
bc7f75fa | 494 | } |
17e813ec BA |
495 | |
496 | if (hw->mac.type == e1000_ich8lan) | |
497 | e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw, | |
498 | enabled); | |
bc7f75fa | 499 | } |
33550cec BA |
500 | /* Write-protect NVM */ |
501 | { | |
6f59d660 | 502 | static const struct e1000_option opt = { |
4a770358 BA |
503 | .type = enable_option, |
504 | .name = "Write-protect NVM", | |
505 | .err = "defaulting to Enabled", | |
506 | .def = OPTION_ENABLED | |
507 | }; | |
508 | ||
509 | if (adapter->flags & FLAG_IS_ICH) { | |
510 | if (num_WriteProtectNVM > bd) { | |
c29c3ba5 BA |
511 | unsigned int write_protect_nvm = |
512 | WriteProtectNVM[bd]; | |
4a770358 BA |
513 | e1000_validate_option(&write_protect_nvm, &opt, |
514 | adapter); | |
515 | if (write_protect_nvm) | |
516 | adapter->flags |= FLAG_READ_ONLY_NVM; | |
517 | } else { | |
518 | if (opt.def) | |
519 | adapter->flags |= FLAG_READ_ONLY_NVM; | |
520 | } | |
521 | } | |
522 | } | |
bc7f75fa | 523 | } |