aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/forcedeth.c171
1 files changed, 104 insertions, 67 deletions
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 6364adbd73a1..731d0d7b2f37 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -98,6 +98,7 @@
98 * 0.43: 10 Aug 2005: Add support for tx checksum. 98 * 0.43: 10 Aug 2005: Add support for tx checksum.
99 * 0.44: 20 Aug 2005: Add support for scatter gather and segmentation. 99 * 0.44: 20 Aug 2005: Add support for scatter gather and segmentation.
100 * 0.45: 18 Sep 2005: Remove nv_stop/start_rx from every link check 100 * 0.45: 18 Sep 2005: Remove nv_stop/start_rx from every link check
101 * 0.46: 20 Oct 2005: Add irq optimization modes.
101 * 102 *
102 * Known bugs: 103 * Known bugs:
103 * We suspect that on some hardware no TX done interrupts are generated. 104 * We suspect that on some hardware no TX done interrupts are generated.
@@ -109,7 +110,7 @@
109 * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few 110 * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few
110 * superfluous timer interrupts from the nic. 111 * superfluous timer interrupts from the nic.
111 */ 112 */
112#define FORCEDETH_VERSION "0.45" 113#define FORCEDETH_VERSION "0.46"
113#define DRV_NAME "forcedeth" 114#define DRV_NAME "forcedeth"
114 115
115#include <linux/module.h> 116#include <linux/module.h>
@@ -164,7 +165,8 @@ enum {
164#define NVREG_IRQ_LINK 0x0040 165#define NVREG_IRQ_LINK 0x0040
165#define NVREG_IRQ_TX_ERROR 0x0080 166#define NVREG_IRQ_TX_ERROR 0x0080
166#define NVREG_IRQ_TX1 0x0100 167#define NVREG_IRQ_TX1 0x0100
167#define NVREG_IRQMASK_WANTED 0x00df 168#define NVREG_IRQMASK_THROUGHPUT 0x00df
169#define NVREG_IRQMASK_CPU 0x0040
168 170
169#define NVREG_IRQ_UNKNOWN (~(NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_TX_ERR| \ 171#define NVREG_IRQ_UNKNOWN (~(NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_TX_ERR| \
170 NVREG_IRQ_TX_OK|NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_TX_ERROR| \ 172 NVREG_IRQ_TX_OK|NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_TX_ERROR| \
@@ -178,7 +180,8 @@ enum {
178 * NVREG_POLL_DEFAULT=97 would result in an interval length of 1 ms 180 * NVREG_POLL_DEFAULT=97 would result in an interval length of 1 ms
179 */ 181 */
180 NvRegPollingInterval = 0x00c, 182 NvRegPollingInterval = 0x00c,
181#define NVREG_POLL_DEFAULT 970 183#define NVREG_POLL_DEFAULT_THROUGHPUT 970
184#define NVREG_POLL_DEFAULT_CPU 13
182 NvRegMisc1 = 0x080, 185 NvRegMisc1 = 0x080,
183#define NVREG_MISC1_HD 0x02 186#define NVREG_MISC1_HD 0x02
184#define NVREG_MISC1_FORCE 0x3b0f3c 187#define NVREG_MISC1_FORCE 0x3b0f3c
@@ -539,6 +542,25 @@ struct fe_priv {
539 */ 542 */
540static int max_interrupt_work = 5; 543static int max_interrupt_work = 5;
541 544
545/*
546 * Optimization can be either throuput mode or cpu mode
547 *
548 * Throughput Mode: Every tx and rx packet will generate an interrupt.
549 * CPU Mode: Interrupts are controlled by a timer.
550 */
551#define NV_OPTIMIZATION_MODE_THROUGHPUT 0
552#define NV_OPTIMIZATION_MODE_CPU 1
553static int optimization_mode = NV_OPTIMIZATION_MODE_THROUGHPUT;
554
555/*
556 * Poll interval for timer irq
557 *
558 * This interval determines how frequent an interrupt is generated.
559 * The is value is determined by [(time_in_micro_secs * 100) / (2^10)]
560 * Min = 0, and Max = 65535
561 */
562static int poll_interval = -1;
563
542static inline struct fe_priv *get_nvpriv(struct net_device *dev) 564static inline struct fe_priv *get_nvpriv(struct net_device *dev)
543{ 565{
544 return netdev_priv(dev); 566 return netdev_priv(dev);
@@ -1329,67 +1351,71 @@ static void nv_rx_process(struct net_device *dev)
1329 if (!(Flags & NV_RX_DESCRIPTORVALID)) 1351 if (!(Flags & NV_RX_DESCRIPTORVALID))
1330 goto next_pkt; 1352 goto next_pkt;
1331 1353
1332 if (Flags & NV_RX_MISSEDFRAME) { 1354 if (Flags & NV_RX_ERROR) {
1333 np->stats.rx_missed_errors++; 1355 if (Flags & NV_RX_MISSEDFRAME) {
1334 np->stats.rx_errors++; 1356 np->stats.rx_missed_errors++;
1335 goto next_pkt;
1336 }
1337 if (Flags & (NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3)) {
1338 np->stats.rx_errors++;
1339 goto next_pkt;
1340 }
1341 if (Flags & NV_RX_CRCERR) {
1342 np->stats.rx_crc_errors++;
1343 np->stats.rx_errors++;
1344 goto next_pkt;
1345 }
1346 if (Flags & NV_RX_OVERFLOW) {
1347 np->stats.rx_over_errors++;
1348 np->stats.rx_errors++;
1349 goto next_pkt;
1350 }
1351 if (Flags & NV_RX_ERROR4) {
1352 len = nv_getlen(dev, np->rx_skbuff[i]->data, len);
1353 if (len < 0) {
1354 np->stats.rx_errors++; 1357 np->stats.rx_errors++;
1355 goto next_pkt; 1358 goto next_pkt;
1356 } 1359 }
1357 } 1360 if (Flags & (NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3)) {
1358 /* framing errors are soft errors. */ 1361 np->stats.rx_errors++;
1359 if (Flags & NV_RX_FRAMINGERR) { 1362 goto next_pkt;
1360 if (Flags & NV_RX_SUBSTRACT1) { 1363 }
1361 len--; 1364 if (Flags & NV_RX_CRCERR) {
1365 np->stats.rx_crc_errors++;
1366 np->stats.rx_errors++;
1367 goto next_pkt;
1368 }
1369 if (Flags & NV_RX_OVERFLOW) {
1370 np->stats.rx_over_errors++;
1371 np->stats.rx_errors++;
1372 goto next_pkt;
1373 }
1374 if (Flags & NV_RX_ERROR4) {
1375 len = nv_getlen(dev, np->rx_skbuff[i]->data, len);
1376 if (len < 0) {
1377 np->stats.rx_errors++;
1378 goto next_pkt;
1379 }
1380 }
1381 /* framing errors are soft errors. */
1382 if (Flags & NV_RX_FRAMINGERR) {
1383 if (Flags & NV_RX_SUBSTRACT1) {
1384 len--;
1385 }
1362 } 1386 }
1363 } 1387 }
1364 } else { 1388 } else {
1365 if (!(Flags & NV_RX2_DESCRIPTORVALID)) 1389 if (!(Flags & NV_RX2_DESCRIPTORVALID))
1366 goto next_pkt; 1390 goto next_pkt;
1367 1391
1368 if (Flags & (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3)) { 1392 if (Flags & NV_RX2_ERROR) {
1369 np->stats.rx_errors++; 1393 if (Flags & (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3)) {
1370 goto next_pkt;
1371 }
1372 if (Flags & NV_RX2_CRCERR) {
1373 np->stats.rx_crc_errors++;
1374 np->stats.rx_errors++;
1375 goto next_pkt;
1376 }
1377 if (Flags & NV_RX2_OVERFLOW) {
1378 np->stats.rx_over_errors++;
1379 np->stats.rx_errors++;
1380 goto next_pkt;
1381 }
1382 if (Flags & NV_RX2_ERROR4) {
1383 len = nv_getlen(dev, np->rx_skbuff[i]->data, len);
1384 if (len < 0) {
1385 np->stats.rx_errors++; 1394 np->stats.rx_errors++;
1386 goto next_pkt; 1395 goto next_pkt;
1387 } 1396 }
1388 } 1397 if (Flags & NV_RX2_CRCERR) {
1389 /* framing errors are soft errors */ 1398 np->stats.rx_crc_errors++;
1390 if (Flags & NV_RX2_FRAMINGERR) { 1399 np->stats.rx_errors++;
1391 if (Flags & NV_RX2_SUBSTRACT1) { 1400 goto next_pkt;
1392 len--; 1401 }
1402 if (Flags & NV_RX2_OVERFLOW) {
1403 np->stats.rx_over_errors++;
1404 np->stats.rx_errors++;
1405 goto next_pkt;
1406 }
1407 if (Flags & NV_RX2_ERROR4) {
1408 len = nv_getlen(dev, np->rx_skbuff[i]->data, len);
1409 if (len < 0) {
1410 np->stats.rx_errors++;
1411 goto next_pkt;
1412 }
1413 }
1414 /* framing errors are soft errors */
1415 if (Flags & NV_RX2_FRAMINGERR) {
1416 if (Flags & NV_RX2_SUBSTRACT1) {
1417 len--;
1418 }
1393 } 1419 }
1394 } 1420 }
1395 Flags &= NV_RX2_CHECKSUMMASK; 1421 Flags &= NV_RX2_CHECKSUMMASK;
@@ -1809,22 +1835,18 @@ static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs)
1809 if (!(events & np->irqmask)) 1835 if (!(events & np->irqmask))
1810 break; 1836 break;
1811 1837
1812 if (events & (NVREG_IRQ_TX1|NVREG_IRQ_TX_OK|NVREG_IRQ_TX_ERROR|NVREG_IRQ_TX_ERR)) { 1838 spin_lock(&np->lock);
1839 nv_tx_done(dev);
1840 spin_unlock(&np->lock);
1841
1842 nv_rx_process(dev);
1843 if (nv_alloc_rx(dev)) {
1813 spin_lock(&np->lock); 1844 spin_lock(&np->lock);
1814 nv_tx_done(dev); 1845 if (!np->in_shutdown)
1846 mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
1815 spin_unlock(&np->lock); 1847 spin_unlock(&np->lock);
1816 } 1848 }
1817 1849
1818 if (events & (NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF)) {
1819 nv_rx_process(dev);
1820 if (nv_alloc_rx(dev)) {
1821 spin_lock(&np->lock);
1822 if (!np->in_shutdown)
1823 mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
1824 spin_unlock(&np->lock);
1825 }
1826 }
1827
1828 if (events & NVREG_IRQ_LINK) { 1850 if (events & NVREG_IRQ_LINK) {
1829 spin_lock(&np->lock); 1851 spin_lock(&np->lock);
1830 nv_link_irq(dev); 1852 nv_link_irq(dev);
@@ -2226,7 +2248,14 @@ static int nv_open(struct net_device *dev)
2226 writel(NVREG_RNDSEED_FORCE | (i&NVREG_RNDSEED_MASK), base + NvRegRandomSeed); 2248 writel(NVREG_RNDSEED_FORCE | (i&NVREG_RNDSEED_MASK), base + NvRegRandomSeed);
2227 writel(NVREG_UNKSETUP1_VAL, base + NvRegUnknownSetupReg1); 2249 writel(NVREG_UNKSETUP1_VAL, base + NvRegUnknownSetupReg1);
2228 writel(NVREG_UNKSETUP2_VAL, base + NvRegUnknownSetupReg2); 2250 writel(NVREG_UNKSETUP2_VAL, base + NvRegUnknownSetupReg2);
2229 writel(NVREG_POLL_DEFAULT, base + NvRegPollingInterval); 2251 if (poll_interval == -1) {
2252 if (optimization_mode == NV_OPTIMIZATION_MODE_THROUGHPUT)
2253 writel(NVREG_POLL_DEFAULT_THROUGHPUT, base + NvRegPollingInterval);
2254 else
2255 writel(NVREG_POLL_DEFAULT_CPU, base + NvRegPollingInterval);
2256 }
2257 else
2258 writel(poll_interval & 0xFFFF, base + NvRegPollingInterval);
2230 writel(NVREG_UNKSETUP6_VAL, base + NvRegUnknownSetupReg6); 2259 writel(NVREG_UNKSETUP6_VAL, base + NvRegUnknownSetupReg6);
2231 writel((np->phyaddr << NVREG_ADAPTCTL_PHYSHIFT)|NVREG_ADAPTCTL_PHYVALID|NVREG_ADAPTCTL_RUNNING, 2260 writel((np->phyaddr << NVREG_ADAPTCTL_PHYSHIFT)|NVREG_ADAPTCTL_PHYVALID|NVREG_ADAPTCTL_RUNNING,
2232 base + NvRegAdapterControl); 2261 base + NvRegAdapterControl);
@@ -2511,7 +2540,11 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
2511 } else { 2540 } else {
2512 np->tx_flags = NV_TX2_VALID; 2541 np->tx_flags = NV_TX2_VALID;
2513 } 2542 }
2514 np->irqmask = NVREG_IRQMASK_WANTED; 2543 if (optimization_mode == NV_OPTIMIZATION_MODE_THROUGHPUT)
2544 np->irqmask = NVREG_IRQMASK_THROUGHPUT;
2545 else
2546 np->irqmask = NVREG_IRQMASK_CPU;
2547
2515 if (id->driver_data & DEV_NEED_TIMERIRQ) 2548 if (id->driver_data & DEV_NEED_TIMERIRQ)
2516 np->irqmask |= NVREG_IRQ_TIMER; 2549 np->irqmask |= NVREG_IRQ_TIMER;
2517 if (id->driver_data & DEV_NEED_LINKTIMER) { 2550 if (id->driver_data & DEV_NEED_LINKTIMER) {
@@ -2699,6 +2732,10 @@ static void __exit exit_nic(void)
2699 2732
2700module_param(max_interrupt_work, int, 0); 2733module_param(max_interrupt_work, int, 0);
2701MODULE_PARM_DESC(max_interrupt_work, "forcedeth maximum events handled per interrupt"); 2734MODULE_PARM_DESC(max_interrupt_work, "forcedeth maximum events handled per interrupt");
2735module_param(optimization_mode, int, 0);
2736MODULE_PARM_DESC(optimization_mode, "In throughput mode (0), every tx & rx packet will generate an interrupt. In CPU mode (1), interrupts are controlled by a timer.");
2737module_param(poll_interval, int, 0);
2738MODULE_PARM_DESC(poll_interval, "Interval determines how frequent timer interrupt is generated by [(time_in_micro_secs * 100) / (2^10)]. Min is 0 and Max is 65535.");
2702 2739
2703MODULE_AUTHOR("Manfred Spraul <manfred@colorfullife.com>"); 2740MODULE_AUTHOR("Manfred Spraul <manfred@colorfullife.com>");
2704MODULE_DESCRIPTION("Reverse Engineered nForce ethernet driver"); 2741MODULE_DESCRIPTION("Reverse Engineered nForce ethernet driver");