# This is a BitKeeper generated patch for the following project: # Project Name: Linux kernel tree # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet 1.1334 -> 1.1338 # drivers/net/e100/e100_phy.c 1.13 -> 1.14 # drivers/net/e1000/e1000.h 1.29 -> 1.32 # drivers/net/tulip/de4x5.c 1.25.1.1 -> 1.27 # drivers/net/e1000/Makefile 1.8 -> 1.9 # drivers/net/myri_sbus.c 1.14 -> 1.15 # drivers/net/fmv18x.c 1.10 -> 1.11 # drivers/net/fec.c 1.6 -> 1.7 # include/linux/arcdevice.h 1.1.1.1 -> 1.3 # drivers/net/fc/iph5526.c 1.20.1.1 -> 1.22 # drivers/net/e100/e100.h 1.27 -> 1.30 # drivers/net/wan/lmc/lmc_main.c 1.13 -> 1.14 # drivers/net/macmace.c 1.10.1.1 -> 1.12 # drivers/net/e1000/e1000_main.c 1.65 -> 1.70 # drivers/net/sunqe.c 1.13 -> 1.14 # drivers/net/irda/sa1100_ir.c 1.9.1.3 -> 1.11 # drivers/net/ppp_synctty.c 1.8 -> 1.9 # drivers/net/e100/e100_test.c 1.9 -> 1.10 # drivers/net/e1000/e1000_ethtool.c 1.23 -> 1.26 # drivers/net/e100/e100_main.c 1.62 -> 1.72 # drivers/net/arcnet/arcnet.c 1.9.1.2 -> 1.12 # drivers/net/seeq8005.c 1.10 -> 1.11 # drivers/net/hamradio/scc.c 1.21 -> 1.22 # drivers/net/sun3lance.c 1.13.1.1 -> 1.15 # drivers/net/e1000/e1000_hw.h 1.13 -> 1.16 # drivers/net/wireless/airport.c 1.12 -> 1.13 # drivers/net/e1000/e1000_hw.c 1.16 -> 1.18 # drivers/net/tokenring/lanstreamer.c 1.16 -> 1.17 # drivers/net/apne.c 1.7.1.1 -> 1.9 # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 03/05/25 jgarzik@redhat.com 1.1335 # Merge redhat.com:/garz/repo/linus-2.5 # into redhat.com:/garz/repo/net-drivers-2.5 # -------------------------------------------- # 03/05/25 scott.feldman@intel.com 1.1336 # [PATCH] full stop/start on ethtool set speed/duplex/autoneg # # * Cleanup ethtool/mii_ioctl sets of speed/duplex/autoneg by # stop/set/start driver to ensure sets stick. Must hold # xmit_lock around stop/start. # -------------------------------------------- # 03/05/25 paulus@samba.org 1.1337 # [PATCH] module owner for ppp_synctty.c # # This patch fixes ppp_synctty.c (used for doing PPP over some synchronous # serial HDLC links) so that it sets the owner field of the tty line # discipline it exports, rather than using MOD_INC/DEC_USE_COUNT. This # is more or less from Stephen Hemminger. # # Please apply. # # Thanks, # Paul. # -------------------------------------------- # 03/05/25 paulus@samba.org 1.1338 # [PATCH] module refcounts for airport driver # # This patch takes out the MOD_INC/DEC_USE_COUNT in the airport (Apple # wireless ethernet) driver. The driver already does SET_MODULE_OWNER # on the netdevice, so the MOD_INC/DEC_USE_COUNT are unnecessary and # just cause warnings. # # Please apply. # # Thanks, # Paul. # -------------------------------------------- # diff -Nru a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c --- a/drivers/net/arcnet/arcnet.c Sun May 25 20:17:20 2003 +++ b/drivers/net/arcnet/arcnet.c Sun May 25 20:17:20 2003 @@ -671,7 +671,7 @@ * interrupts. Establish which device needs attention, and call the correct * chipset interrupt handler. */ -void arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = dev_id; struct arcnet_local *lp; @@ -696,7 +696,7 @@ ACOMMAND(CFLAGScmd | RESETclear); AINTMASK(0); spin_unlock(&arcnet_lock); - return; + return IRQ_HANDLED; } BUGMSG(D_DURING, "in arcnet_inthandler (status=%Xh, intmask=%Xh)\n", @@ -864,6 +864,7 @@ AINTMASK(lp->intmask); spin_unlock(&arcnet_lock); + return IRQ_RETVAL(didsomething); } diff -Nru a/drivers/net/e100/e100.h b/drivers/net/e100/e100.h --- a/drivers/net/e100/e100.h Sun May 25 20:17:19 2003 +++ b/drivers/net/e100/e100.h Sun May 25 20:17:19 2003 @@ -60,7 +60,14 @@ #include #include -#define E100_REGS_LEN 1 +#define E100_CABLE_UNKNOWN 0 +#define E100_CABLE_OK 1 +#define E100_CABLE_OPEN_NEAR 2 /* Open Circuit Near End */ +#define E100_CABLE_OPEN_FAR 3 /* Open Circuit Far End */ +#define E100_CABLE_SHORT_NEAR 4 /* Short Circuit Near End */ +#define E100_CABLE_SHORT_FAR 5 /* Short Circuit Far End */ + +#define E100_REGS_LEN 2 /* * Configure parameters for buffers per controller. * If the machine this is being used on is a faster machine (i.e. > 150MHz) @@ -105,8 +112,6 @@ #define E100_MAX_CU_IDLE_WAIT 50 /* Max udelays in wait_cus_idle */ /* HWI feature related constant */ -#define HWI_MAX_LOOP 100 -#define MAX_SAME_RESULTS 3 #define HWI_REGISTER_GRANULARITY 80 /* register granularity = 80 Cm */ #define HWI_NEAR_END_BOUNDARY 1000 /* Near end is defined as < 10 meters */ @@ -942,7 +947,6 @@ #ifdef CONFIG_PM u32 pci_state[16]; #endif - char ifname[IFNAMSIZ]; #ifdef E100_CU_DEBUG u8 last_cmd; u8 last_sub_cmd; @@ -956,7 +960,10 @@ #define E100_SPEED_100_FULL 4 /********* function prototypes *************/ +extern int e100_open(struct net_device *); +extern int e100_close(struct net_device *); extern void e100_isolate_driver(struct e100_private *bdp); +extern unsigned char e100_hw_init(struct e100_private *); extern void e100_sw_reset(struct e100_private *bdp, u32 reset_cmd); extern u8 e100_start_cu(struct e100_private *bdp, tcb_t *tcb); extern void e100_free_non_tx_cmd(struct e100_private *bdp, @@ -981,14 +988,13 @@ #define TEST_TIMEOUT 0x08 enum test_offsets { - E100_EEPROM_TEST_FAIL = 0, - E100_CHIP_TIMEOUT, - E100_ROM_TEST_FAIL, - E100_REG_TEST_FAIL, - E100_MAC_TEST_FAIL, - E100_LPBK_MAC_FAIL, - E100_LPBK_PHY_FAIL, - E100_MAX_TEST_RES + test_link, + test_eeprom, + test_self_test, + test_loopback_mac, + test_loopback_phy, + cable_diag, + max_test_res, /* must be last */ }; #endif diff -Nru a/drivers/net/e100/e100_main.c b/drivers/net/e100/e100_main.c --- a/drivers/net/e100/e100_main.c Sun May 25 20:17:20 2003 +++ b/drivers/net/e100/e100_main.c Sun May 25 20:17:20 2003 @@ -46,6 +46,24 @@ /* Change Log * + * 2.3.13 05/08/03 + * o Feature remove: /proc/net/PRO_LAN_Adapters support gone completely + * o Feature remove: IDIAG support (use ethtool -t instead) + * o Cleanup: fixed spelling mistakes found by community + * o Feature add: ethtool cable diag test + * o Feature add: ethtool parameter support (ring size, xsum, flow ctrl) + * o Cleanup: move e100_asf_enable under CONFIG_PM to avoid warning + * [Stephen Rothwell (sfr@canb.auug.org.au)] + * o Bug fix: don't call any netif_carrier_* until netdev registered. + * [Andrew Morton (akpm@digeo.com)] + * o Cleanup: replace (skb->len - skb->data_len) with skb_headlen(skb) + * [jmorris@intercode.com.au] + * o Bug fix: cleanup of Tx skbs after running ethtool diags + * o Bug fix: incorrect reporting of ethtool diag overall results + * o Bug fix: must hold xmit_lock before stopping queue in ethtool + * operations that require reset h/w and driver structures. + * o Bug fix: statistic command failure would stop statistic collection. + * * 2.2.21 02/11/03 * o Removed marketing brand strings. Instead, Using generic string * "Intel(R) PRO/100 Network Connection" for all adapters. @@ -61,21 +79,6 @@ * o New feature: added ICH5 support * * 2.1.27 11/20/02 - * o Bug fix: Device command timeout due to SMBus processing during init - * o Bug fix: Not setting/clearing I (Interrupt) bit in tcb correctly - * o Bug fix: Not using EEPROM WoL setting as default in ethtool - * o Bug fix: Not able to set autoneg on using ethtool when interface down - * o Bug fix: Not able to change speed/duplex using ethtool/mii - * when interface up - * o Bug fix: Ethtool shows autoneg on when forced to 100/Full - * o Bug fix: Compiler error when CONFIG_PROC_FS not defined - * o Bug fix: 2.5.44 e100 doesn't load with preemptive kernel enabled - * (sleep while holding spinlock) - * o Bug fix: 2.1.24-k1 doesn't display complete statistics - * o Bug fix: System panic due to NULL watchdog timer dereference during - * ifconfig down, rmmod and insmod - * - * 2.1.24 10/7/02 */ #include @@ -121,14 +124,13 @@ extern u32 e100_run_diag(struct net_device *dev, u64 *test_info, u32 flags); static int e100_ethtool_test(struct net_device *, struct ifreq *); static int e100_ethtool_gstrings(struct net_device *, struct ifreq *); -static char *test_strings[] = { - "E100_EEPROM_TEST_FAIL", - "E100_CHIP_TIMEOUT", - "E100_ROM_TEST_FAIL", - "E100_REG_TEST_FAIL", - "E100_MAC_TEST_FAIL", - "E100_LPBK_MAC_FAIL", - "E100_LPBK_PHY_FAIL" +static char test_strings[][ETH_GSTRING_LEN] = { + "Link test (on/offline)", + "Eeprom test (on/offline)", + "Self test (offline)", + "Mac loopback (offline)", + "Phy loopback (offline)", + "Cable diagnostic (offline)" }; static int e100_ethtool_led_blink(struct net_device *, struct ifreq *); @@ -139,10 +141,10 @@ nxmit_cb_entry_t *); static void e100_free_nontx_list(struct e100_private *); static void e100_non_tx_background(unsigned long); - +static inline void e100_tx_skb_free(struct e100_private *bdp, tcb_t *tcb); /* Global Data structures and variables */ char e100_copyright[] __devinitdata = "Copyright (c) 2003 Intel Corporation"; -char e100_driver_version[]="2.2.21-k1"; +char e100_driver_version[]="2.3.13-k1"; const char *e100_full_driver_name = "Intel(R) PRO/100 Network Driver"; char e100_short_driver_name[] = "e100"; static int e100nics = 0; @@ -155,6 +157,7 @@ static int e100_notify_reboot(struct notifier_block *, unsigned long event, void *ptr); static int e100_suspend(struct pci_dev *pcid, u32 state); static int e100_resume(struct pci_dev *pcid); +static unsigned char e100_asf_enabled(struct e100_private *bdp); struct notifier_block e100_notifier_reboot = { .notifier_call = e100_notify_reboot, .next = NULL, @@ -182,8 +185,6 @@ static u8 e100_D101M_checksum(struct e100_private *, struct sk_buff *); static u8 e100_D102_check_checksum(rfd_t *); static int e100_ioctl(struct net_device *, struct ifreq *, int); -static int e100_open(struct net_device *); -static int e100_close(struct net_device *); static int e100_change_mtu(struct net_device *, int); static int e100_xmit_frame(struct sk_buff *, struct net_device *); static unsigned char e100_init(struct e100_private *); @@ -193,7 +194,6 @@ static irqreturn_t e100intr(int, void *, struct pt_regs *); static void e100_print_brd_conf(struct e100_private *); static void e100_set_multi(struct net_device *); -void e100_set_speed_duplex(struct e100_private *); static u8 e100_pci_setup(struct pci_dev *, struct e100_private *); static u8 e100_sw_init(struct e100_private *); @@ -215,7 +215,6 @@ static unsigned char e100_clr_cntrs(struct e100_private *); static unsigned char e100_load_microcode(struct e100_private *); -static unsigned char e100_hw_init(struct e100_private *); static unsigned char e100_setup_iaaddr(struct e100_private *, u8 *); static unsigned char e100_update_stats(struct e100_private *bdp); @@ -228,7 +227,6 @@ char *); unsigned char e100_wait_exec_cmplx(struct e100_private *, u32, u8, u8); void e100_exec_cmplx(struct e100_private *, u32, u8); -static unsigned char e100_asf_enabled(struct e100_private *bdp); /** * e100_get_rx_struct - retrieve cell to hold skb buff from the pool @@ -616,6 +614,10 @@ goto err_dealloc; } + if ((rc = register_netdev(dev)) != 0) { + goto err_pci; + } + if (((bdp->pdev->device > 0x1030) && (bdp->pdev->device < 0x103F)) || ((bdp->pdev->device >= 0x1050) @@ -645,7 +647,7 @@ printk(KERN_ERR "e100: Failed to initialize, instance #%d\n", e100nics); rc = -ENODEV; - goto err_pci; + goto err_unregister_netdev; } /* Check if checksum is valid */ @@ -655,7 +657,7 @@ printk(KERN_ERR "e100: Corrupted EEPROM on instance #%d\n", e100nics); rc = -ENODEV; - goto err_pci; + goto err_unregister_netdev; } dev->vlan_rx_register = e100_vlan_rx_register; @@ -679,12 +681,6 @@ e100_get_speed_duplex_caps(bdp); - if ((rc = register_netdev(dev)) != 0) { - goto err_pci; - } - memcpy(bdp->ifname, dev->name, IFNAMSIZ); - bdp->ifname[IFNAMSIZ-1] = 0; - printk(KERN_NOTICE "e100: %s: %s\n", bdp->device->name, "Intel(R) PRO/100 Network Connection"); @@ -709,6 +705,8 @@ goto out; +err_unregister_netdev: + unregister_netdev(dev); err_pci: iounmap(bdp->scb); pci_release_regions(pcid); @@ -974,7 +972,7 @@ } } -static int +int e100_open(struct net_device *dev) { struct e100_private *bdp; @@ -1012,7 +1010,11 @@ mod_timer(&(bdp->watchdog_timer), jiffies + (2 * HZ)); - netif_start_queue(dev); + if (dev->flags & IFF_UP) + /* Otherwise process may sleep forever */ + netif_wake_queue(dev); + else + netif_start_queue(dev); e100_start_ru(bdp); if ((rc = request_irq(dev->irq, &e100intr, SA_SHIRQ, @@ -1033,7 +1035,7 @@ return rc; } -static int +int e100_close(struct net_device *dev) { struct e100_private *bdp = dev->priv; @@ -1074,7 +1076,8 @@ goto exit2; } - if (!TCBS_AVAIL(bdp->tcb_pool) || + /* tcb list may be empty temporarily during releasing resources */ + if (!TCBS_AVAIL(bdp->tcb_pool) || (bdp->tcb_phys == 0) || (bdp->non_tx_command_state != E100_NON_TX_IDLE)) { notify_stop = true; rc = 1; @@ -1285,10 +1288,8 @@ /* read NIC's part number */ e100_rd_pwa_no(bdp); - if (!e100_hw_init(bdp)) { - printk(KERN_ERR "e100: hw init failed\n"); + if (!e100_hw_init(bdp)) return false; - } /* Interrupts are enabled after device reset */ e100_disable_clear_intr(bdp); @@ -1330,6 +1331,8 @@ spin_lock_init(&(bdp->bd_non_tx_lock)); spin_lock_init(&(bdp->config_lock)); spin_lock_init(&(bdp->mdi_access_lock)); + /* Initialize configuration data */ + e100_config_init(bdp); return 1; } @@ -1384,11 +1387,11 @@ * true - If the adapter was initialized * false - If the adapter failed initialization */ -unsigned char __devinit +unsigned char e100_hw_init(struct e100_private *bdp) { if (!e100_phy_init(bdp)) - return false; + goto err; e100_sw_reset(bdp, PORT_SELECTIVE_RESET); @@ -1398,27 +1401,25 @@ /* Load the CU BASE (set to 0, because we use linear mode) */ if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE, 0)) - return false; + goto err; if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE, 0)) - return false; + goto err; /* Load interrupt microcode */ if (e100_load_microcode(bdp)) { bdp->flags |= DF_UCODE_LOADED; } - e100_config_init(bdp); - if (!e100_config(bdp)) { - return false; - } + if (!e100_config(bdp)) + goto err; if (!e100_setup_iaaddr(bdp, bdp->device->dev_addr)) - return false; + goto err; /* Clear the internal counters */ if (!e100_clr_cntrs(bdp)) - return false; + goto err; /* Change for 82558 enhancement */ /* If 82558/9 and if the user has enabled flow control, set up the @@ -1431,6 +1432,9 @@ } return true; +err: + printk(KERN_ERR "e100: hw init failed\n"); + return false; } /** @@ -1591,9 +1595,22 @@ void e100_free_tcb_pool(struct e100_private *bdp) { + tcb_t *tcb; + int i; + /* Return tx skbs */ + for (i = 0; i < bdp->params.TxDescriptors; i++) { + tcb = bdp->tcb_pool.data; + tcb += bdp->tcb_pool.head; + e100_tx_skb_free(bdp, tcb); + if (NEXT_TCB_TOUSE(bdp->tcb_pool.head) == bdp->tcb_pool.tail) + break; + bdp->tcb_pool.head = NEXT_TCB_TOUSE(bdp->tcb_pool.head); + } pci_free_consistent(bdp->pdev, sizeof (tcb_t) * bdp->params.TxDescriptors, bdp->tcb_pool.data, bdp->tcb_phys); + bdp->tcb_pool.head = 0; + bdp->tcb_pool.tail = 1; bdp->tcb_phys = 0; } @@ -1747,12 +1764,10 @@ e100_set_multi(dev); } } - - /* Update the statistics needed by the upper interface */ - /* This should be the last statistic related command - * as it's async. now */ - e100_dump_stats_cntrs(bdp); } + /* Issue command to dump statistics from device. */ + /* Check for command completion on next watchdog timer. */ + e100_dump_stats_cntrs(bdp); wmb(); @@ -2544,6 +2559,7 @@ pcmd_complete = e100_cmd_complete_location(bdp); if (*pcmd_complete != le32_to_cpu(DUMP_RST_STAT_COMPLETED) && *pcmd_complete != le32_to_cpu(DUMP_STAT_COMPLETED)) { + *pcmd_complete = 0; return false; } @@ -3041,23 +3057,6 @@ e100_sw_reset(bdp, PORT_SELECTIVE_RESET); } -void -e100_set_speed_duplex(struct e100_private *bdp) -{ - int carrier_ok; - /* Device may lose link with some siwtches when */ - /* changing speed/duplex to non-autoneg. e100 */ - /* needs to remember carrier state in order to */ - /* start watchdog timer for recovering link */ - if ((carrier_ok = netif_carrier_ok(bdp->device))) - e100_isolate_driver(bdp); - e100_phy_set_speed_duplex(bdp, true); - e100_config_fc(bdp); /* re-config flow-control if necessary */ - e100_config(bdp); - if (carrier_ok) - e100_deisolate_driver(bdp, false); -} - static void e100_tcb_add_C_bit(struct e100_private *bdp) { @@ -3213,6 +3212,144 @@ case ETHTOOL_PHYS_ID: rc = e100_ethtool_led_blink(dev,ifr); break; +#ifdef ETHTOOL_GRINGPARAM + case ETHTOOL_GRINGPARAM: { + struct ethtool_ringparam ering; + struct e100_private *bdp = dev->priv; + memset((void *) &ering, 0, sizeof(ering)); + ering.rx_max_pending = E100_MAX_RFD; + ering.tx_max_pending = E100_MAX_TCB; + ering.rx_pending = bdp->params.RxDescriptors; + ering.tx_pending = bdp->params.TxDescriptors; + rc = copy_to_user(ifr->ifr_data, &ering, sizeof(ering)) + ? -EFAULT : 0; + return rc; + } +#endif +#ifdef ETHTOOL_SRINGPARAM + case ETHTOOL_SRINGPARAM: { + struct ethtool_ringparam ering; + struct e100_private *bdp = dev->priv; + if (copy_from_user(&ering, ifr->ifr_data, sizeof(ering))) + return -EFAULT; + if (ering.rx_pending > E100_MAX_RFD + || ering.rx_pending < E100_MIN_RFD) + return -EINVAL; + if (ering.tx_pending > E100_MAX_TCB + || ering.tx_pending < E100_MIN_TCB) + return -EINVAL; + if (netif_running(dev)) { + spin_lock_bh(&dev->xmit_lock); + e100_close(dev); + spin_unlock_bh(&dev->xmit_lock); + /* Use new values to open interface */ + bdp->params.RxDescriptors = ering.rx_pending; + bdp->params.TxDescriptors = ering.tx_pending; + e100_hw_init(bdp); + e100_open(dev); + } + else { + bdp->params.RxDescriptors = ering.rx_pending; + bdp->params.TxDescriptors = ering.tx_pending; + } + return 0; + } +#endif +#ifdef ETHTOOL_GPAUSEPARAM + case ETHTOOL_GPAUSEPARAM: { + struct ethtool_pauseparam epause; + struct e100_private *bdp = dev->priv; + memset((void *) &epause, 0, sizeof(epause)); + if ((bdp->flags & IS_BACHELOR) + && (bdp->params.b_params & PRM_FC)) { + epause.autoneg = 1; + if (bdp->flags && DF_LINK_FC_CAP) { + epause.rx_pause = 1; + epause.tx_pause = 1; + } + if (bdp->flags && DF_LINK_FC_TX_ONLY) + epause.tx_pause = 1; + } + rc = copy_to_user(ifr->ifr_data, &epause, sizeof(epause)) + ? -EFAULT : 0; + return rc; + } +#endif +#ifdef ETHTOOL_SPAUSEPARAM + case ETHTOOL_SPAUSEPARAM: { + struct ethtool_pauseparam epause; + struct e100_private *bdp = dev->priv; + if (!(bdp->flags & IS_BACHELOR)) + return -EINVAL; + if (copy_from_user(&epause, ifr->ifr_data, sizeof(epause))) + return -EFAULT; + if (epause.autoneg == 1) + bdp->params.b_params |= PRM_FC; + else + bdp->params.b_params &= ~PRM_FC; + if (netif_running(dev)) { + spin_lock_bh(&dev->xmit_lock); + e100_close(dev); + spin_unlock_bh(&dev->xmit_lock); + e100_hw_init(bdp); + e100_open(dev); + } + return 0; + } +#endif +#ifdef ETHTOOL_GRXCSUM + case ETHTOOL_GRXCSUM: + case ETHTOOL_GTXCSUM: + case ETHTOOL_GSG: + { struct ethtool_value eval; + struct e100_private *bdp = dev->priv; + memset((void *) &eval, 0, sizeof(eval)); + if ((ecmd.cmd == ETHTOOL_GRXCSUM) + && (bdp->params.b_params & PRM_XSUMRX)) + eval.data = 1; + else + eval.data = 0; + rc = copy_to_user(ifr->ifr_data, &eval, sizeof(eval)) + ? -EFAULT : 0; + return rc; + } +#endif +#ifdef ETHTOOL_SRXCSUM + case ETHTOOL_SRXCSUM: + case ETHTOOL_STXCSUM: + case ETHTOOL_SSG: + { struct ethtool_value eval; + struct e100_private *bdp = dev->priv; + if (copy_from_user(&eval, ifr->ifr_data, sizeof(eval))) + return -EFAULT; + if (ecmd.cmd == ETHTOOL_SRXCSUM) { + if (eval.data == 1) { + if (bdp->rev_id >= D101MA_REV_ID) + bdp->params.b_params |= PRM_XSUMRX; + else + return -EINVAL; + } else { + if (bdp->rev_id >= D101MA_REV_ID) + bdp->params.b_params &= ~PRM_XSUMRX; + else + return 0; + } + } else { + if (eval.data == 1) + return -EINVAL; + else + return 0; + } + if (netif_running(dev)) { + spin_lock_bh(&dev->xmit_lock); + e100_close(dev); + spin_unlock_bh(&dev->xmit_lock); + e100_hw_init(bdp); + e100_open(dev); + } + return 0; + } +#endif default: break; } //switch @@ -3298,7 +3435,13 @@ if ((ecmd.autoneg == AUTONEG_ENABLE) && (bdp->speed_duplex_caps & SUPPORTED_Autoneg)) { bdp->params.e100_speed_duplex = E100_AUTONEG; - e100_set_speed_duplex(bdp); + if (netif_running(dev)) { + spin_lock_bh(&dev->xmit_lock); + e100_close(dev); + spin_unlock_bh(&dev->xmit_lock); + e100_hw_init(bdp); + e100_open(dev); + } } else { if (ecmd.speed == SPEED_10) { if (ecmd.duplex == DUPLEX_HALF) { @@ -3329,7 +3472,13 @@ if (bdp->speed_duplex_caps & ethtool_new_speed_duplex) { bdp->params.e100_speed_duplex = e100_new_speed_duplex; - e100_set_speed_duplex(bdp); + if (netif_running(dev)) { + spin_lock_bh(&dev->xmit_lock); + e100_close(dev); + spin_unlock_bh(&dev->xmit_lock); + e100_hw_init(bdp); + e100_open(dev); + } } else { return -EOPNOTSUPP; } @@ -3364,14 +3513,14 @@ struct ethtool_test *info; int rc = -EFAULT; - info = kmalloc(sizeof(*info) + E100_MAX_TEST_RES * sizeof(u64), + info = kmalloc(sizeof(*info) + max_test_res * sizeof(u64), GFP_ATOMIC); if (!info) return -ENOMEM; memset((void *) info, 0, sizeof(*info) + - E100_MAX_TEST_RES * sizeof(u64)); + max_test_res * sizeof(u64)); if (copy_from_user(info, ifr->ifr_data, sizeof(*info))) goto exit; @@ -3379,7 +3528,7 @@ info->flags = e100_run_diag(dev, info->data, info->flags); if (!copy_to_user(ifr->ifr_data, info, - sizeof(*info) + E100_MAX_TEST_RES * sizeof(u64))) + sizeof(*info) + max_test_res * sizeof(u64))) rc = 0; exit: kfree(info); @@ -3393,6 +3542,7 @@ u32 regs_buff[E100_REGS_LEN]; struct ethtool_regs regs = {ETHTOOL_GREGS}; void *addr = ifr->ifr_data; + u16 mdi_reg; if (!capable(CAP_NET_ADMIN)) return -EPERM; @@ -3405,6 +3555,8 @@ regs_buff[0] = readb(&(bdp->scb->scb_cmd_hi)) << 24 | readb(&(bdp->scb->scb_cmd_low)) << 16 | readw(&(bdp->scb->scb_status)); + e100_mdi_read(bdp, MII_NCONFIG, bdp->phy_addr, &mdi_reg); + regs_buff[1] = mdi_reg; if(copy_to_user(addr, ®s, sizeof(regs))) return -EFAULT; @@ -3428,7 +3580,13 @@ if ((bdp->speed_duplex_caps & SUPPORTED_Autoneg) && (bdp->params.e100_speed_duplex == E100_AUTONEG)) { - e100_set_speed_duplex(bdp); + if (netif_running(dev)) { + spin_lock_bh(&dev->xmit_lock); + e100_close(dev); + spin_unlock_bh(&dev->xmit_lock); + e100_hw_init(bdp); + e100_open(dev); + } } else { return -EFAULT; } @@ -3454,7 +3612,7 @@ info.n_stats = E100_STATS_LEN; info.regdump_len = E100_REGS_LEN * sizeof(u32); info.eedump_len = (bdp->eeprom_size << 1); - info.testinfo_len = E100_MAX_TEST_RES; + info.testinfo_len = max_test_res; if (copy_to_user(ifr->ifr_data, &info, sizeof (info))) return -EFAULT; @@ -3804,15 +3962,15 @@ switch (info.string_set) { case ETH_SS_TEST: { int ret = 0; - if (info.len > E100_MAX_TEST_RES) - info.len = E100_MAX_TEST_RES; + if (info.len > max_test_res) + info.len = max_test_res; strings = kmalloc(info.len * ETH_GSTRING_LEN, GFP_ATOMIC); if (!strings) return -ENOMEM; memset(strings, 0, info.len * ETH_GSTRING_LEN); for (i = 0; i < info.len; i++) { - sprintf(strings + i * ETH_GSTRING_LEN, "%-31s", + sprintf(strings + i * ETH_GSTRING_LEN, "%s", test_strings[i]); } if (copy_to_user(ifr->ifr_data, &info, sizeof (info))) @@ -3881,7 +4039,13 @@ bdp->params.e100_speed_duplex = E100_SPEED_10_FULL; else bdp->params.e100_speed_duplex = E100_SPEED_10_HALF; - e100_set_speed_duplex(bdp); + if (netif_running(dev)) { + spin_lock_bh(&dev->xmit_lock); + e100_close(dev); + spin_unlock_bh(&dev->xmit_lock); + e100_hw_init(bdp); + e100_open(dev); + } } else /* Only allows changing speed/duplex */ @@ -4164,7 +4328,6 @@ return 0; } -#endif /* CONFIG_PM */ /** * e100_asf_enabled - checks if ASF is configured on the current adaper @@ -4190,6 +4353,7 @@ } return false; } +#endif /* CONFIG_PM */ #ifdef E100_CU_DEBUG unsigned char diff -Nru a/drivers/net/e100/e100_phy.c b/drivers/net/e100/e100_phy.c --- a/drivers/net/e100/e100_phy.c Sun May 25 20:17:19 2003 +++ b/drivers/net/e100/e100_phy.c Sun May 25 20:17:19 2003 @@ -628,8 +628,6 @@ u16 control; unsigned long expires; - e100_phy_reset(bdp); - bdp->flags |= DF_SPEED_FORCED; e100_mdi_read(bdp, MII_BMCR, bdp->phy_addr, &control); @@ -912,6 +910,10 @@ u16 ctrl_reg; ctrl_reg = BMCR_RESET; e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg); + /* ieee 802.3 : The reset process shall be completed */ + /* within 0.5 seconds from the settting of PHY reset bit. */ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ / 2); } unsigned char __devinit @@ -928,6 +930,7 @@ bdp->PhyDelay = 0; bdp->zlock_state = ZLOCK_INITIAL; + e100_phy_reset(bdp); e100_phy_set_speed_duplex(bdp, false); e100_fix_polarity(bdp); diff -Nru a/drivers/net/e100/e100_test.c b/drivers/net/e100/e100_test.c --- a/drivers/net/e100/e100_test.c Sun May 25 20:17:20 2003 +++ b/drivers/net/e100/e100_test.c Sun May 25 20:17:20 2003 @@ -25,7 +25,7 @@ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *******************************************************************************/ -#include "e100.h" +#include "e100_phy.h" #include "e100_config.h" extern u16 e100_eeprom_read(struct e100_private *, u16); @@ -46,6 +46,7 @@ static void e100_diag_loopback_cu_ru_exec(struct e100_private *); static u8 e100_diag_check_pkt(u8 *); static void e100_diag_loopback_free(struct e100_private *); +static int e100_cable_diag(struct e100_private *bdp); #define LB_PACKET_SIZE 1500 @@ -60,46 +61,52 @@ e100_run_diag(struct net_device *dev, u64 *test_info, u32 flags) { struct e100_private* bdp = dev->priv; - u8 test_result = true; - - e100_isolate_driver(bdp); + u8 test_result = 0; + if (!e100_get_link_state(bdp)) { + test_result = ETH_TEST_FL_FAILED; + test_info[test_link] = true; + } + if (!e100_diag_eeprom(dev)) { + test_result = ETH_TEST_FL_FAILED; + test_info[test_eeprom] = true; + } if (flags & ETH_TEST_FL_OFFLINE) { u8 fail_mask; - - fail_mask = e100_diag_selftest(dev); - if (fail_mask) { - test_result = false; - if (fail_mask & REGISTER_TEST_FAIL) - test_info [E100_REG_TEST_FAIL] = true; - if (fail_mask & ROM_TEST_FAIL) - test_info [E100_ROM_TEST_FAIL] = true; - if (fail_mask & SELF_TEST_FAIL) - test_info [E100_MAC_TEST_FAIL] = true; - if (fail_mask & TEST_TIMEOUT) - test_info [E100_CHIP_TIMEOUT] = true; + if (netif_running(dev)) { + spin_lock_bh(&dev->xmit_lock); + e100_close(dev); + spin_unlock_bh(&dev->xmit_lock); + } + if (e100_diag_selftest(dev)) { + test_result = ETH_TEST_FL_FAILED; + test_info[test_self_test] = true; } fail_mask = e100_diag_loopback(dev); if (fail_mask) { - test_result = false; + test_result = ETH_TEST_FL_FAILED; if (fail_mask & PHY_LOOPBACK) - test_info [E100_LPBK_PHY_FAIL] = true; + test_info[test_loopback_phy] = true; if (fail_mask & MAC_LOOPBACK) - test_info [E100_LPBK_MAC_FAIL] = true; + test_info[test_loopback_mac] = true; } - } - if (!e100_diag_eeprom(dev)) { - test_result = false; - test_info [E100_EEPROM_TEST_FAIL] = true; + test_info[cable_diag] = e100_cable_diag(bdp); + /* Need hw init regardless of netif_running */ + e100_hw_init(bdp); + if (netif_running(dev)) { + e100_open(dev); + } + } + else { + test_info[test_self_test] = false; + test_info[test_loopback_phy] = false; + test_info[test_loopback_mac] = false; + test_info[cable_diag] = false; } - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ * 2); - e100_deisolate_driver(bdp, false); - - return flags | (test_result ? 0 : ETH_TEST_FL_FAILED); + return flags | test_result; } /** @@ -126,8 +133,6 @@ } } - e100_configure_device(bdp); - return retval; } @@ -165,14 +170,14 @@ u8 rc = 0; printk(KERN_DEBUG "%s: PHY loopback test starts\n", dev->name); - e100_sw_reset(dev->priv, PORT_SELECTIVE_RESET); + e100_hw_init(dev->priv); if (!e100_diag_one_loopback(dev, PHY_LOOPBACK)) { rc |= PHY_LOOPBACK; } printk(KERN_DEBUG "%s: PHY loopback test ends\n", dev->name); printk(KERN_DEBUG "%s: MAC loopback test starts\n", dev->name); - e100_sw_reset(dev->priv, PORT_SELECTIVE_RESET); + e100_hw_init(dev->priv); if (!e100_diag_one_loopback(dev, MAC_LOOPBACK)) { rc |= MAC_LOOPBACK; } @@ -257,15 +262,10 @@ if (set_loopback) /* Set PHY loopback mode */ e100_phy_set_loopback(bdp); - else { /* Back to normal speed and duplex */ - if (bdp->params.e100_speed_duplex == E100_AUTONEG) - /* Reset PHY and do autoneg */ - e100_phy_autoneg(bdp); - else - /* Reset PHY and force speed and duplex */ - e100_force_speed_duplex(bdp); - } - /* Wait for PHY state change */ + else + /* Reset PHY loopback mode */ + e100_phy_reset(bdp); + /* Wait for PHY state change */ set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ); } else { /* For MAC loopback wait 500 msec to take effect */ @@ -348,10 +348,6 @@ e100_diag_loopback_cu_ru_exec(struct e100_private *bdp) { /*load CU & RU base */ - if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE, 0)) - printk(KERN_ERR "e100: SCB_CUC_LOAD_BASE failed\n"); - if(!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE, 0)) - printk(KERN_ERR "e100: SCB_RUC_LOAD_BASE failed!\n"); if(!e100_wait_exec_cmplx(bdp, bdp->loopback.dma_handle, SCB_RUC_START, 0)) printk(KERN_ERR "e100: SCB_RUC_START failed!\n"); @@ -431,5 +427,74 @@ pci_free_consistent(bdp->pdev, sizeof(rfd_t), bdp->loopback.rfd, bdp->loopback.dma_handle); +} + +static int +e100_cable_diag(struct e100_private *bdp) +{ + int saved_open_circut = 0xffff; + int saved_short_circut = 0xffff; + int saved_distance = 0xffff; + int saved_same = 0; + int cable_status = E100_CABLE_UNKNOWN; + int i; + + /* If we have link, */ + if (e100_get_link_state(bdp)) + return E100_CABLE_OK; + + if (bdp->rev_id < D102_REV_ID) + return E100_CABLE_UNKNOWN; + + /* Disable MDI/MDI-X auto switching */ + e100_mdi_write(bdp, MII_NCONFIG, bdp->phy_addr, + MDI_MDIX_RESET_ALL_MASK); + /* Set to 100 Full as required by cable test */ + e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, + BMCR_SPEED100 | BMCR_FULLDPLX); + + /* Test up to 100 times */ + for (i = 0; i < 100; i++) { + u16 ctrl_reg; + int distance, open_circut, short_circut, near_end; + + /* Enable and execute cable test */ + e100_mdi_write(bdp, HWI_CONTROL_REG, bdp->phy_addr, + (HWI_TEST_ENABLE | HWI_TEST_EXECUTE)); + /* Wait for cable test finished */ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ/100 + 1); + /* Read results */ + e100_mdi_read(bdp, HWI_CONTROL_REG, bdp->phy_addr, &ctrl_reg); + distance = ctrl_reg & HWI_TEST_DISTANCE; + open_circut = ctrl_reg & HWI_TEST_HIGHZ_PROBLEM; + short_circut = ctrl_reg & HWI_TEST_LOWZ_PROBLEM; + + if ((distance == saved_distance) && + (open_circut == saved_open_circut) && + (short_circut == saved_short_circut)) + saved_same++; + else { + saved_same = 0; + saved_distance = distance; + saved_open_circut = open_circut; + saved_short_circut = short_circut; + } + /* If results are the same 3 times */ + if (saved_same == 3) { + near_end = ((distance * HWI_REGISTER_GRANULARITY) < + HWI_NEAR_END_BOUNDARY); + if (open_circut) + cable_status = (near_end) ? + E100_CABLE_OPEN_NEAR : E100_CABLE_OPEN_FAR; + if (short_circut) + cable_status = (near_end) ? + E100_CABLE_SHORT_NEAR : E100_CABLE_SHORT_FAR; + break; + } + } + /* Reset cable test */ + e100_mdi_write(bdp, HWI_CONTROL_REG, bdp->phy_addr, HWI_RESET_ALL_MASK); + return cable_status; } diff -Nru a/drivers/net/e1000/Makefile b/drivers/net/e1000/Makefile --- a/drivers/net/e1000/Makefile Sun May 25 20:17:19 2003 +++ b/drivers/net/e1000/Makefile Sun May 25 20:17:19 2003 @@ -1,7 +1,7 @@ ################################################################################ # # -# Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved. +# Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the Free diff -Nru a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h --- a/drivers/net/e1000/e1000.h Sun May 25 20:17:19 2003 +++ b/drivers/net/e1000/e1000.h Sun May 25 20:17:19 2003 @@ -134,6 +134,7 @@ uint64_t dma; unsigned long length; unsigned long time_stamp; + unsigned int next_to_watch; }; struct e1000_desc_ring { @@ -169,7 +170,6 @@ struct timer_list watchdog_timer; struct timer_list phy_info_timer; struct vlan_group *vlgrp; - char *id_string; uint32_t bd_number; uint32_t rx_buffer_len; uint32_t part_num; @@ -218,6 +218,9 @@ struct e1000_phy_info phy_info; struct e1000_phy_stats phy_stats; + uint32_t test_icr; + struct e1000_desc_ring test_tx_ring; + struct e1000_desc_ring test_rx_ring; uint32_t pci_state[16]; diff -Nru a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c --- a/drivers/net/e1000/e1000_ethtool.c Sun May 25 20:17:20 2003 +++ b/drivers/net/e1000/e1000_ethtool.c Sun May 25 20:17:20 2003 @@ -40,15 +40,60 @@ extern void e1000_reset(struct e1000_adapter *adapter); extern int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx); -static char e1000_gstrings_stats[][ETH_GSTRING_LEN] = { - "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors", - "tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions", - "rx_length_errors", "rx_over_errors", "rx_crc_errors", - "rx_frame_errors", "rx_fifo_errors", "rx_missed_errors", - "tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors", - "tx_heartbeat_errors", "tx_window_errors", +struct e1000_stats { + char stat_string[ETH_GSTRING_LEN]; + int sizeof_stat; + int stat_offset; }; -#define E1000_STATS_LEN sizeof(e1000_gstrings_stats) / ETH_GSTRING_LEN + +#define E1000_STAT(m) sizeof(((struct e1000_adapter *)0)->m), \ + offsetof(struct e1000_adapter, m) +static struct e1000_stats e1000_gstrings_stats[] = { + { "rx_packets", E1000_STAT(net_stats.rx_packets) }, + { "tx_packets", E1000_STAT(net_stats.tx_packets) }, + { "rx_bytes", E1000_STAT(net_stats.rx_bytes) }, + { "tx_bytes", E1000_STAT(net_stats.tx_bytes) }, + { "rx_errors", E1000_STAT(net_stats.rx_errors) }, + { "tx_errors", E1000_STAT(net_stats.tx_errors) }, + { "rx_dropped", E1000_STAT(net_stats.rx_dropped) }, + { "tx_dropped", E1000_STAT(net_stats.tx_dropped) }, + { "multicast", E1000_STAT(net_stats.multicast) }, + { "collisions", E1000_STAT(net_stats.collisions) }, + { "rx_length_errors", E1000_STAT(net_stats.rx_length_errors) }, + { "rx_over_errors", E1000_STAT(net_stats.rx_over_errors) }, + { "rx_crc_errors", E1000_STAT(net_stats.rx_crc_errors) }, + { "rx_frame_errors", E1000_STAT(net_stats.rx_frame_errors) }, + { "rx_fifo_errors", E1000_STAT(net_stats.rx_fifo_errors) }, + { "rx_missed_errors", E1000_STAT(net_stats.rx_missed_errors) }, + { "tx_aborted_errors", E1000_STAT(net_stats.tx_aborted_errors) }, + { "tx_carrier_errors", E1000_STAT(net_stats.tx_carrier_errors) }, + { "tx_fifo_errors", E1000_STAT(net_stats.tx_fifo_errors) }, + { "tx_heartbeat_errors", E1000_STAT(net_stats.tx_heartbeat_errors) }, + { "tx_window_errors", E1000_STAT(net_stats.tx_window_errors) }, + { "tx_abort_late_coll", E1000_STAT(stats.latecol) }, + { "tx_deferred_ok", E1000_STAT(stats.dc) }, + { "tx_single_coll_ok", E1000_STAT(stats.scc) }, + { "tx_multi_coll_ok", E1000_STAT(stats.mcc) }, + { "rx_long_length_errors", E1000_STAT(stats.roc) }, + { "rx_short_length_errors", E1000_STAT(stats.ruc) }, + { "rx_align_errors", E1000_STAT(stats.algnerrc) }, + { "tx_tcp_seg_good", E1000_STAT(stats.tsctc) }, + { "tx_tcp_seg_failed", E1000_STAT(stats.tsctfc) }, + { "rx_flow_control_xon", E1000_STAT(stats.xonrxc) }, + { "rx_flow_control_xoff", E1000_STAT(stats.xoffrxc) }, + { "tx_flow_control_xon", E1000_STAT(stats.xontxc) }, + { "tx_flow_control_xoff", E1000_STAT(stats.xofftxc) }, + { "rx_csum_offload_good", E1000_STAT(hw_csum_good) }, + { "rx_csum_offload_errors", E1000_STAT(hw_csum_err) } +}; +#define E1000_STATS_LEN \ + sizeof(e1000_gstrings_stats) / sizeof(struct e1000_stats) +static char e1000_gstrings_test[][ETH_GSTRING_LEN] = { + "Register test (offline)", "Eeprom test (offline)", + "Interrupt test (offline)", "Loopback test (offline)", + "Link test (on/offline)" +}; +#define E1000_TEST_LEN sizeof(e1000_gstrings_test) / ETH_GSTRING_LEN static void e1000_ethtool_gset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd) @@ -154,6 +199,7 @@ strncpy(drvinfo->fw_version, "N/A", 32); strncpy(drvinfo->bus_info, adapter->pdev->slot_name, 32); drvinfo->n_stats = E1000_STATS_LEN; + drvinfo->testinfo_len = E1000_TEST_LEN; #define E1000_REGS_LEN 32 drvinfo->regdump_len = E1000_REGS_LEN * sizeof(uint32_t); drvinfo->eedump_len = adapter->hw.eeprom.word_size * 2; @@ -164,6 +210,7 @@ struct ethtool_regs *regs, uint32_t *regs_buff) { struct e1000_hw *hw = &adapter->hw; + uint16_t phy_data; regs->version = (1 << 24) | (hw->revision_id << 16) | hw->device_id; @@ -182,6 +229,62 @@ regs_buff[10] = E1000_READ_REG(hw, TDT); regs_buff[11] = E1000_READ_REG(hw, TIDV); + regs_buff[12] = adapter->hw.phy_type; /* PHY type (IGP=1, M88=0) */ + if(hw->phy_type == e1000_phy_igp) { + e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, + IGP01E1000_PHY_AGC_A); + e1000_read_phy_reg(hw, IGP01E1000_PHY_AGC_A & + IGP01E1000_PHY_PAGE_SELECT, &phy_data); + regs_buff[13] = (uint32_t)phy_data; /* cable length */ + e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, + IGP01E1000_PHY_AGC_B); + e1000_read_phy_reg(hw, IGP01E1000_PHY_AGC_B & + IGP01E1000_PHY_PAGE_SELECT, &phy_data); + regs_buff[14] = (uint32_t)phy_data; /* cable length */ + e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, + IGP01E1000_PHY_AGC_C); + e1000_read_phy_reg(hw, IGP01E1000_PHY_AGC_C & + IGP01E1000_PHY_PAGE_SELECT, &phy_data); + regs_buff[15] = (uint32_t)phy_data; /* cable length */ + e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, + IGP01E1000_PHY_AGC_D); + e1000_read_phy_reg(hw, IGP01E1000_PHY_AGC_D & + IGP01E1000_PHY_PAGE_SELECT, &phy_data); + regs_buff[16] = (uint32_t)phy_data; /* cable length */ + regs_buff[17] = 0; /* extended 10bt distance (not needed) */ + e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0); + e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS & + IGP01E1000_PHY_PAGE_SELECT, &phy_data); + regs_buff[18] = (uint32_t)phy_data; /* cable polarity */ + e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, + IGP01E1000_PHY_PCS_INIT_REG); + e1000_read_phy_reg(hw, IGP01E1000_PHY_PCS_INIT_REG & + IGP01E1000_PHY_PAGE_SELECT, &phy_data); + regs_buff[19] = (uint32_t)phy_data; /* cable polarity */ + regs_buff[20] = 0; /* polarity correction enabled (always) */ + regs_buff[22] = 0; /* phy receive errors (unavailable) */ + regs_buff[23] = regs_buff[18]; /* mdix mode */ + e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0); + } else { + e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); + regs_buff[13] = (uint32_t)phy_data; /* cable length */ + regs_buff[14] = 0; /* Dummy (to align w/ IGP phy reg dump) */ + regs_buff[15] = 0; /* Dummy (to align w/ IGP phy reg dump) */ + regs_buff[16] = 0; /* Dummy (to align w/ IGP phy reg dump) */ + e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); + regs_buff[17] = (uint32_t)phy_data; /* extended 10bt distance */ + regs_buff[18] = regs_buff[13]; /* cable polarity */ + regs_buff[19] = 0; /* Dummy (to align w/ IGP phy reg dump) */ + regs_buff[20] = regs_buff[17]; /* polarity correction */ + /* phy receive errors */ + regs_buff[22] = adapter->phy_stats.receive_errors; + regs_buff[23] = regs_buff[13]; /* mdix mode */ + } + regs_buff[21] = adapter->phy_stats.idle_errors; /* phy idle errors */ + e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data); + regs_buff[24] = (uint32_t)phy_data; /* phy local receiver status */ + regs_buff[25] = regs_buff[24]; /* phy remote receiver status */ + return; } @@ -219,7 +322,7 @@ uint16_t i; for (i = 0; i < last_word - first_word + 1; i++) if((ret_val = e1000_read_eeprom(hw, first_word + i, 1, - &eeprom_buff[i]))) + &eeprom_buff[i]))) break; } geeprom_error: @@ -249,7 +352,7 @@ first_word = eeprom->offset >> 1; last_word = (eeprom->offset + eeprom->len - 1) >> 1; eeprom_buff = kmalloc(max_len, GFP_KERNEL); - if(eeprom_buff == NULL) + if(!eeprom_buff) return -ENOMEM; ptr = (void *)eeprom_buff; @@ -284,6 +387,765 @@ return ret_val; } +#define REG_PATTERN_TEST(R, M, W) \ +{ \ + uint32_t pat, value; \ + uint32_t test[] = \ + {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF}; \ + for(pat = 0; pat < sizeof(test)/sizeof(test[0]); pat++) { \ + E1000_WRITE_REG(&adapter->hw, R, (test[pat] & W)); \ + value = E1000_READ_REG(&adapter->hw, R); \ + if(value != (test[pat] & W & M)) { \ + *data = (adapter->hw.mac_type < e1000_82543) ? \ + E1000_82542_##R : E1000_##R; \ + return 1; \ + } \ + } \ +} + +#define REG_SET_AND_CHECK(R, M, W) \ +{ \ + uint32_t value; \ + E1000_WRITE_REG(&adapter->hw, R, W & M); \ + value = E1000_READ_REG(&adapter->hw, R); \ + if ((W & M) != (value & M)) { \ + *data = (adapter->hw.mac_type < e1000_82543) ? \ + E1000_82542_##R : E1000_##R; \ + return 1; \ + } \ +} + +static int +e1000_reg_test(struct e1000_adapter *adapter, uint64_t *data) +{ + uint32_t value; + uint32_t i; + + /* The status register is Read Only, so a write should fail. + * Some bits that get toggled are ignored. + */ + value = (E1000_READ_REG(&adapter->hw, STATUS) & (0xFFFFF833)); + E1000_WRITE_REG(&adapter->hw, STATUS, (0xFFFFFFFF)); + if(value != (E1000_READ_REG(&adapter->hw, STATUS) & (0xFFFFF833))) { + *data = 1; + return 1; + } + + REG_PATTERN_TEST(FCAL, 0xFFFFFFFF, 0xFFFFFFFF); + REG_PATTERN_TEST(FCAH, 0x0000FFFF, 0xFFFFFFFF); + REG_PATTERN_TEST(FCT, 0x0000FFFF, 0xFFFFFFFF); + REG_PATTERN_TEST(VET, 0x0000FFFF, 0xFFFFFFFF); + REG_PATTERN_TEST(RDTR, 0x0000FFFF, 0xFFFFFFFF); + REG_PATTERN_TEST(RDBAH, 0xFFFFFFFF, 0xFFFFFFFF); + REG_PATTERN_TEST(RDLEN, 0x000FFF80, 0x000FFFFF); + REG_PATTERN_TEST(RDH, 0x0000FFFF, 0x0000FFFF); + REG_PATTERN_TEST(RDT, 0x0000FFFF, 0x0000FFFF); + REG_PATTERN_TEST(FCRTH, 0x0000FFF8, 0x0000FFF8); + REG_PATTERN_TEST(FCTTV, 0x0000FFFF, 0x0000FFFF); + REG_PATTERN_TEST(TIPG, 0x3FFFFFFF, 0x3FFFFFFF); + REG_PATTERN_TEST(TDBAH, 0xFFFFFFFF, 0xFFFFFFFF); + REG_PATTERN_TEST(TDLEN, 0x000FFF80, 0x000FFFFF); + + REG_SET_AND_CHECK(RCTL, 0xFFFFFFFF, 0x00000000); + REG_SET_AND_CHECK(RCTL, 0x06DFB3FE, 0x003FFFFB); + REG_SET_AND_CHECK(TCTL, 0xFFFFFFFF, 0x00000000); + + if(adapter->hw.mac_type >= e1000_82543) { + + REG_SET_AND_CHECK(RCTL, 0x06DFB3FE, 0xFFFFFFFF); + REG_PATTERN_TEST(RDBAL, 0xFFFFFFF0, 0xFFFFFFFF); + REG_PATTERN_TEST(TXCW, 0xC000FFFF, 0x0000FFFF); + REG_PATTERN_TEST(TDBAL, 0xFFFFFFF0, 0xFFFFFFFF); + REG_PATTERN_TEST(TIDV, 0x0000FFFF, 0x0000FFFF); + + for(i = 0; i < E1000_RAR_ENTRIES; i++) { + REG_PATTERN_TEST(RA + ((i << 1) << 2), 0xFFFFFFFF, + 0xFFFFFFFF); + REG_PATTERN_TEST(RA + (((i << 1) + 1) << 2), 0x8003FFFF, + 0xFFFFFFFF); + } + + } else { + + REG_SET_AND_CHECK(RCTL, 0xFFFFFFFF, 0x01FFFFFF); + REG_PATTERN_TEST(RDBAL, 0xFFFFF000, 0xFFFFFFFF); + REG_PATTERN_TEST(TXCW, 0x0000FFFF, 0x0000FFFF); + REG_PATTERN_TEST(TDBAL, 0xFFFFF000, 0xFFFFFFFF); + + } + + for(i = 0; i < E1000_MC_TBL_SIZE; i++) + REG_PATTERN_TEST(MTA + (i << 2), 0xFFFFFFFF, 0xFFFFFFFF); + + return 0; +} + +static int +e1000_eeprom_test(struct e1000_adapter *adapter, uint64_t *data) +{ + uint16_t temp; + uint16_t checksum = 0; + uint16_t i; + + *data = 0; + /* Read and add up the contents of the EEPROM */ + for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) { + if((e1000_read_eeprom(&adapter->hw, i, 1, &temp)) < 0) { + *data = 1; + break; + } + checksum += temp; + } + + /* If Checksum is not Correct return error else test passed */ + if((checksum != (uint16_t) EEPROM_SUM) && !(*data)) + *data = 2; + + return *data; +} + +static irqreturn_t +e1000_test_intr(int irq, + void *data, + struct pt_regs *regs) +{ + struct net_device *netdev = (struct net_device *) data; + struct e1000_adapter *adapter = netdev->priv; + + adapter->test_icr |= E1000_READ_REG(&adapter->hw, ICR); + + return IRQ_HANDLED; +} + +static int +e1000_intr_test(struct e1000_adapter *adapter, uint64_t *data) +{ + struct net_device *netdev = adapter->netdev; + uint32_t icr, mask, i=0; + + *data = 0; + + /* Hook up test interrupt handler just for this test */ + if(request_irq + (netdev->irq, &e1000_test_intr, SA_SHIRQ, netdev->name, netdev)) { + *data = 1; + return -1; + } + + /* Disable all the interrupts */ + E1000_WRITE_REG(&adapter->hw, IMC, 0xFFFFFFFF); + msec_delay(10); + + /* Interrupts are disabled, so read interrupt cause + * register (icr) twice to verify that there are no interrupts + * pending. icr is clear on read. + */ + icr = E1000_READ_REG(&adapter->hw, ICR); + icr = E1000_READ_REG(&adapter->hw, ICR); + + if(icr != 0) { + /* if icr is non-zero, there is no point + * running other interrupt tests. + */ + *data = 2; + i = 10; + } + + /* Test each interrupt */ + for(; i < 10; i++) { + + /* Interrupt to test */ + mask = 1 << i; + + /* Disable the interrupt to be reported in + * the cause register and then force the same + * interrupt and see if one gets posted. If + * an interrupt was posted to the bus, the + * test failed. + */ + adapter->test_icr = 0; + E1000_WRITE_REG(&adapter->hw, IMC, mask); + E1000_WRITE_REG(&adapter->hw, ICS, mask); + msec_delay(10); + + if(adapter->test_icr & mask) { + *data = 3; + break; + } + + /* Enable the interrupt to be reported in + * the cause register and then force the same + * interrupt and see if one gets posted. If + * an interrupt was not posted to the bus, the + * test failed. + */ + adapter->test_icr = 0; + E1000_WRITE_REG(&adapter->hw, IMS, mask); + E1000_WRITE_REG(&adapter->hw, ICS, mask); + msec_delay(10); + + if(!(adapter->test_icr & mask)) { + *data = 4; + break; + } + + /* Disable the other interrupts to be reported in + * the cause register and then force the other + * interrupts and see if any get posted. If + * an interrupt was posted to the bus, the + * test failed. + */ + adapter->test_icr = 0; + E1000_WRITE_REG(&adapter->hw, IMC, ~mask); + E1000_WRITE_REG(&adapter->hw, ICS, ~mask); + msec_delay(10); + + if(adapter->test_icr) { + *data = 5; + break; + } + } + + /* Disable all the interrupts */ + E1000_WRITE_REG(&adapter->hw, IMC, 0xFFFFFFFF); + msec_delay(10); + + /* Unhook test interrupt handler */ + free_irq(netdev->irq, netdev); + + return *data; +} + +static void +e1000_free_desc_rings(struct e1000_adapter *adapter) +{ + struct e1000_desc_ring *txdr = &adapter->test_tx_ring; + struct e1000_desc_ring *rxdr = &adapter->test_rx_ring; + struct pci_dev *pdev = adapter->pdev; + int i; + + if(txdr->desc && txdr->buffer_info) { + for(i = 0; i < txdr->count; i++) { + if(txdr->buffer_info[i].dma) + pci_unmap_single(pdev, txdr->buffer_info[i].dma, + txdr->buffer_info[i].length, + PCI_DMA_TODEVICE); + if(txdr->buffer_info[i].skb) + dev_kfree_skb(txdr->buffer_info[i].skb); + } + } + + if(rxdr->desc && rxdr->buffer_info) { + for(i = 0; i < rxdr->count; i++) { + if(rxdr->buffer_info[i].dma) + pci_unmap_single(pdev, rxdr->buffer_info[i].dma, + rxdr->buffer_info[i].length, + PCI_DMA_FROMDEVICE); + if(rxdr->buffer_info[i].skb) + dev_kfree_skb(rxdr->buffer_info[i].skb); + } + } + + if(txdr->desc) + pci_free_consistent(pdev, txdr->size, txdr->desc, txdr->dma); + if(rxdr->desc) + pci_free_consistent(pdev, rxdr->size, rxdr->desc, rxdr->dma); + + if(txdr->buffer_info) + kfree(txdr->buffer_info); + if(rxdr->buffer_info) + kfree(rxdr->buffer_info); + + return; +} + +static int +e1000_setup_desc_rings(struct e1000_adapter *adapter) +{ + struct e1000_desc_ring *txdr = &adapter->test_tx_ring; + struct e1000_desc_ring *rxdr = &adapter->test_rx_ring; + struct pci_dev *pdev = adapter->pdev; + uint32_t rctl; + int size, i, ret_val; + + /* Setup Tx descriptor ring and Tx buffers */ + + txdr->count = 80; + + size = txdr->count * sizeof(struct e1000_buffer); + if(!(txdr->buffer_info = kmalloc(size, GFP_KERNEL))) { + ret_val = 1; + goto err_nomem; + } + memset(txdr->buffer_info, 0, size); + + txdr->size = txdr->count * sizeof(struct e1000_tx_desc); + E1000_ROUNDUP(txdr->size, 4096); + if(!(txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma))) { + ret_val = 2; + goto err_nomem; + } + memset(txdr->desc, 0, txdr->size); + txdr->next_to_use = txdr->next_to_clean = 0; + + E1000_WRITE_REG(&adapter->hw, TDBAL, + ((uint64_t) txdr->dma & 0x00000000FFFFFFFF)); + E1000_WRITE_REG(&adapter->hw, TDBAH, ((uint64_t) txdr->dma >> 32)); + E1000_WRITE_REG(&adapter->hw, TDLEN, + txdr->count * sizeof(struct e1000_tx_desc)); + E1000_WRITE_REG(&adapter->hw, TDH, 0); + E1000_WRITE_REG(&adapter->hw, TDT, 0); + E1000_WRITE_REG(&adapter->hw, TCTL, + E1000_TCTL_PSP | E1000_TCTL_EN | + E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT | + E1000_FDX_COLLISION_DISTANCE << E1000_COLD_SHIFT); + + for(i = 0; i < txdr->count; i++) { + struct e1000_tx_desc *tx_desc = E1000_TX_DESC(*txdr, i); + struct sk_buff *skb; + unsigned int size = 1024; + + if(!(skb = alloc_skb(size, GFP_KERNEL))) { + ret_val = 3; + goto err_nomem; + } + skb_put(skb, size); + txdr->buffer_info[i].skb = skb; + txdr->buffer_info[i].length = skb->len; + txdr->buffer_info[i].dma = + pci_map_single(pdev, skb->data, skb->len, + PCI_DMA_TODEVICE); + tx_desc->buffer_addr = cpu_to_le64(txdr->buffer_info[i].dma); + tx_desc->lower.data = cpu_to_le32(skb->len); + tx_desc->lower.data |= E1000_TXD_CMD_EOP; + tx_desc->lower.data |= E1000_TXD_CMD_IFCS; + tx_desc->lower.data |= E1000_TXD_CMD_RPS; + tx_desc->upper.data = 0; + } + + /* Setup Rx descriptor ring and Rx buffers */ + + rxdr->count = 80; + + size = rxdr->count * sizeof(struct e1000_buffer); + if(!(rxdr->buffer_info = kmalloc(size, GFP_KERNEL))) { + ret_val = 4; + goto err_nomem; + } + memset(rxdr->buffer_info, 0, size); + + rxdr->size = rxdr->count * sizeof(struct e1000_rx_desc); + if(!(rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma))) { + ret_val = 5; + goto err_nomem; + } + memset(rxdr->desc, 0, rxdr->size); + rxdr->next_to_use = rxdr->next_to_clean = 0; + + rctl = E1000_READ_REG(&adapter->hw, RCTL); + E1000_WRITE_REG(&adapter->hw, RCTL, rctl & ~E1000_RCTL_EN); + E1000_WRITE_REG(&adapter->hw, RDBAL, + ((uint64_t) rxdr->dma & 0xFFFFFFFF)); + E1000_WRITE_REG(&adapter->hw, RDBAH, ((uint64_t) rxdr->dma >> 32)); + E1000_WRITE_REG(&adapter->hw, RDLEN, rxdr->size); + E1000_WRITE_REG(&adapter->hw, RDH, 0); + E1000_WRITE_REG(&adapter->hw, RDT, 0); + rctl = E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_SZ_2048 | + E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF | + (adapter->hw.mc_filter_type << E1000_RCTL_MO_SHIFT); + E1000_WRITE_REG(&adapter->hw, RCTL, rctl); + + for(i = 0; i < rxdr->count; i++) { + struct e1000_rx_desc *rx_desc = E1000_RX_DESC(*rxdr, i); + struct sk_buff *skb; + + if(!(skb = alloc_skb(E1000_RXBUFFER_2048 + 2, GFP_KERNEL))) { + ret_val = 6; + goto err_nomem; + } + skb_reserve(skb, 2); + rxdr->buffer_info[i].skb = skb; + rxdr->buffer_info[i].length = E1000_RXBUFFER_2048; + rxdr->buffer_info[i].dma = + pci_map_single(pdev, skb->data, E1000_RXBUFFER_2048, + PCI_DMA_FROMDEVICE); + rx_desc->buffer_addr = cpu_to_le64(rxdr->buffer_info[i].dma); + memset(skb->data, 0x00, skb->len); + } + + return 0; + + err_nomem: + e1000_free_desc_rings(adapter); + return ret_val; +} + +static void +e1000_phy_disable_receiver(struct e1000_adapter *adapter) +{ + /* Write out to PHY registers 29 and 30 to disable the Receiver. */ + e1000_write_phy_reg(&adapter->hw, 29, 0x001F); + e1000_write_phy_reg(&adapter->hw, 30, 0x8FFC); + e1000_write_phy_reg(&adapter->hw, 29, 0x001A); + e1000_write_phy_reg(&adapter->hw, 30, 0x8FF0); + + return; +} + +static void +e1000_phy_reset_clk_and_crs(struct e1000_adapter *adapter) +{ + uint16_t phy_reg; + + /* Because we reset the PHY above, we need to re-force TX_CLK in the + * Extended PHY Specific Control Register to 25MHz clock. This + * value defaults back to a 2.5MHz clock when the PHY is reset. + */ + e1000_read_phy_reg(&adapter->hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_reg); + phy_reg |= M88E1000_EPSCR_TX_CLK_25; + e1000_write_phy_reg(&adapter->hw, + M88E1000_EXT_PHY_SPEC_CTRL, phy_reg); + + /* In addition, because of the s/w reset above, we need to enable + * CRS on TX. This must be set for both full and half duplex + * operation. + */ + e1000_read_phy_reg(&adapter->hw, M88E1000_PHY_SPEC_CTRL, &phy_reg); + phy_reg |= M88E1000_PSCR_ASSERT_CRS_ON_TX; + e1000_write_phy_reg(&adapter->hw, + M88E1000_PHY_SPEC_CTRL, phy_reg); +} + +static int +e1000_nonintegrated_phy_loopback(struct e1000_adapter *adapter) +{ + uint32_t ctrl_reg; + uint16_t phy_reg; + + /* Setup the Device Control Register for PHY loopback test. */ + + ctrl_reg = E1000_READ_REG(&adapter->hw, CTRL); + ctrl_reg |= (E1000_CTRL_ILOS | /* Invert Loss-Of-Signal */ + E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */ + E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */ + E1000_CTRL_SPD_1000 | /* Force Speed to 1000 */ + E1000_CTRL_FD); /* Force Duplex to FULL */ + + E1000_WRITE_REG(&adapter->hw, CTRL, ctrl_reg); + + /* Read the PHY Specific Control Register (0x10) */ + e1000_read_phy_reg(&adapter->hw, M88E1000_PHY_SPEC_CTRL, &phy_reg); + + /* Clear Auto-Crossover bits in PHY Specific Control Register + * (bits 6:5). + */ + phy_reg &= ~M88E1000_PSCR_AUTO_X_MODE; + e1000_write_phy_reg(&adapter->hw, M88E1000_PHY_SPEC_CTRL, phy_reg); + + /* Perform software reset on the PHY */ + e1000_phy_reset(&adapter->hw); + + /* Have to setup TX_CLK and TX_CRS after software reset */ + e1000_phy_reset_clk_and_crs(adapter); + + e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x8100); + + /* Wait for reset to complete. */ + udelay(500); + + /* Have to setup TX_CLK and TX_CRS after software reset */ + e1000_phy_reset_clk_and_crs(adapter); + + /* Write out to PHY registers 29 and 30 to disable the Receiver. */ + e1000_phy_disable_receiver(adapter); + + /* Set the loopback bit in the PHY control register. */ + e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &phy_reg); + phy_reg |= MII_CR_LOOPBACK; + e1000_write_phy_reg(&adapter->hw, PHY_CTRL, phy_reg); + + /* Setup TX_CLK and TX_CRS one more time. */ + e1000_phy_reset_clk_and_crs(adapter); + + /* Check Phy Configuration */ + e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &phy_reg); + if(phy_reg != 0x4100) + return 9; + + e1000_read_phy_reg(&adapter->hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_reg); + if(phy_reg != 0x0070) + return 10; + + e1000_read_phy_reg(&adapter->hw, 29, &phy_reg); + if(phy_reg != 0x001A) + return 11; + + return 0; +} + +static int +e1000_integrated_phy_loopback(struct e1000_adapter *adapter) +{ + uint32_t ctrl_reg = 0; + uint32_t stat_reg = 0; + + adapter->hw.autoneg = FALSE; + + if(adapter->hw.phy_type == e1000_phy_m88) { + /* Auto-MDI/MDIX Off */ + e1000_write_phy_reg(&adapter->hw, + M88E1000_PHY_SPEC_CTRL, 0x0808); + /* reset to update Auto-MDI/MDIX */ + e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x9140); + /* autoneg off */ + e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x8140); + } + /* force 1000, set loopback */ + e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x4140); + + /* Now set up the MAC to the same speed/duplex as the PHY. */ + ctrl_reg = E1000_READ_REG(&adapter->hw, CTRL); + ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */ + ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */ + E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */ + E1000_CTRL_SPD_1000 |/* Force Speed to 1000 */ + E1000_CTRL_FD); /* Force Duplex to FULL */ + + if(adapter->hw.media_type == e1000_media_type_copper && + adapter->hw.phy_type == e1000_phy_m88) { + ctrl_reg |= E1000_CTRL_ILOS; /* Invert Loss of Signal */ + } else { + /* Set the ILOS bit on the fiber Nic is half + * duplex link is detected. */ + stat_reg = E1000_READ_REG(&adapter->hw, STATUS); + if((stat_reg & E1000_STATUS_FD) == 0) + ctrl_reg |= (E1000_CTRL_ILOS | E1000_CTRL_SLU); + } + + E1000_WRITE_REG(&adapter->hw, CTRL, ctrl_reg); + + /* Disable the receiver on the PHY so when a cable is plugged in, the + * PHY does not begin to autoneg when a cable is reconnected to the NIC. + */ + if(adapter->hw.phy_type == e1000_phy_m88) + e1000_phy_disable_receiver(adapter); + + udelay(500); + + return 0; +} + +static int +e1000_set_phy_loopback(struct e1000_adapter *adapter) +{ + uint16_t phy_reg = 0; + uint16_t count = 0; + + switch (adapter->hw.mac_type) { + case e1000_82543: + if(adapter->hw.media_type == e1000_media_type_copper) { + /* Attempt to setup Loopback mode on Non-integrated PHY. + * Some PHY registers get corrupted at random, so + * attempt this 10 times. + */ + while(e1000_nonintegrated_phy_loopback(adapter) && + count++ < 10); + if(count < 11) + return 0; + } + break; + + case e1000_82544: + case e1000_82540: + case e1000_82545: + case e1000_82546: + case e1000_82541: + case e1000_82547: + return e1000_integrated_phy_loopback(adapter); + break; + + default: + /* Default PHY loopback work is to read the MII + * control register and assert bit 14 (loopback mode). + */ + e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &phy_reg); + phy_reg |= MII_CR_LOOPBACK; + e1000_write_phy_reg(&adapter->hw, PHY_CTRL, phy_reg); + return 0; + break; + } + + return 8; +} + +static int +e1000_setup_loopback_test(struct e1000_adapter *adapter) +{ + uint32_t rctl; + + if(adapter->hw.media_type == e1000_media_type_fiber) { + if(adapter->hw.mac_type == e1000_82545 || + adapter->hw.mac_type == e1000_82546) + return e1000_set_phy_loopback(adapter); + else { + rctl = E1000_READ_REG(&adapter->hw, RCTL); + rctl |= E1000_RCTL_LBM_TCVR; + E1000_WRITE_REG(&adapter->hw, RCTL, rctl); + return 0; + } + } else if(adapter->hw.media_type == e1000_media_type_copper) + return e1000_set_phy_loopback(adapter); + + return 7; +} + +static void +e1000_loopback_cleanup(struct e1000_adapter *adapter) +{ + uint32_t rctl; + uint16_t phy_reg; + + rctl = E1000_READ_REG(&adapter->hw, RCTL); + rctl &= ~(E1000_RCTL_LBM_TCVR | E1000_RCTL_LBM_MAC); + E1000_WRITE_REG(&adapter->hw, RCTL, rctl); + + if(adapter->hw.media_type == e1000_media_type_copper || + (adapter->hw.media_type == e1000_media_type_fiber && + (adapter->hw.mac_type == e1000_82545 || + adapter->hw.mac_type == e1000_82546))) { + adapter->hw.autoneg = TRUE; + e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &phy_reg); + if(phy_reg & MII_CR_LOOPBACK) { + phy_reg &= ~MII_CR_LOOPBACK; + e1000_write_phy_reg(&adapter->hw, PHY_CTRL, phy_reg); + e1000_phy_reset(&adapter->hw); + } + } +} + +static void +e1000_create_lbtest_frame(struct sk_buff *skb, unsigned int frame_size) +{ + memset(skb->data, 0xFF, frame_size); + frame_size = (frame_size % 2) ? (frame_size - 1) : frame_size; + memset(&skb->data[frame_size / 2], 0xAA, frame_size / 2 - 1); + memset(&skb->data[frame_size / 2 + 10], 0xBE, 1); + memset(&skb->data[frame_size / 2 + 12], 0xAF, 1); +} + +static int +e1000_check_lbtest_frame(struct sk_buff *skb, unsigned int frame_size) +{ + frame_size = (frame_size % 2) ? (frame_size - 1) : frame_size; + if(*(skb->data + 3) == 0xFF) { + if((*(skb->data + frame_size / 2 + 10) == 0xBE) && + (*(skb->data + frame_size / 2 + 12) == 0xAF)) { + return 0; + } + } + return 13; +} + +static int +e1000_run_loopback_test(struct e1000_adapter *adapter) +{ + struct e1000_desc_ring *txdr = &adapter->test_tx_ring; + struct e1000_desc_ring *rxdr = &adapter->test_rx_ring; + struct pci_dev *pdev = adapter->pdev; + int i; + + E1000_WRITE_REG(&adapter->hw, RDT, rxdr->count - 1); + + for(i = 0; i < 64; i++) { + e1000_create_lbtest_frame(txdr->buffer_info[i].skb, 1024); + pci_dma_sync_single(pdev, txdr->buffer_info[i].dma, + txdr->buffer_info[i].length, + PCI_DMA_TODEVICE); + } + E1000_WRITE_REG(&adapter->hw, TDT, i); + + msec_delay(200); + + pci_dma_sync_single(pdev, rxdr->buffer_info[0].dma, + rxdr->buffer_info[0].length, PCI_DMA_FROMDEVICE); + + return e1000_check_lbtest_frame(rxdr->buffer_info[0].skb, 1024); +} + +static int +e1000_loopback_test(struct e1000_adapter *adapter, uint64_t *data) +{ + if((*data = e1000_setup_desc_rings(adapter))) goto err_loopback; + if((*data = e1000_setup_loopback_test(adapter))) goto err_loopback; + *data = e1000_run_loopback_test(adapter); + e1000_loopback_cleanup(adapter); + e1000_free_desc_rings(adapter); +err_loopback: + return *data; +} + +static int +e1000_link_test(struct e1000_adapter *adapter, uint64_t *data) +{ + *data = 0; + e1000_check_for_link(&adapter->hw); + + if(!(E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU)) { + *data = 1; + } + return *data; +} + +static int +e1000_ethtool_test(struct e1000_adapter *adapter, + struct ethtool_test *eth_test, uint64_t *data) +{ + boolean_t if_running = netif_running(adapter->netdev); + + if(eth_test->flags == ETH_TEST_FL_OFFLINE) { + /* Offline tests */ + + /* Link test performed before hardware reset so autoneg doesn't + * interfere with test result */ + if(e1000_link_test(adapter, &data[4])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + if(if_running) + e1000_down(adapter); + + e1000_reset(adapter); + if(e1000_reg_test(adapter, &data[0])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + e1000_reset(adapter); + if(e1000_eeprom_test(adapter, &data[1])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + e1000_reset(adapter); + if(e1000_intr_test(adapter, &data[2])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + e1000_reset(adapter); + if(e1000_loopback_test(adapter, &data[3])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + e1000_reset(adapter); + if(if_running) + e1000_up(adapter); + } else { + /* Online tests */ + if(e1000_link_test(adapter, &data[4])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + /* Offline tests aren't run; pass by default */ + data[0] = 0; + data[1] = 0; + data[2] = 0; + data[3] = 0; + } + return 0; +} + static void e1000_ethtool_gwol(struct e1000_adapter *adapter, struct ethtool_wolinfo *wol) { @@ -443,24 +1305,46 @@ case ETHTOOL_GSTRINGS: { struct ethtool_gstrings gstrings = { ETHTOOL_GSTRINGS }; char *strings = NULL; + int err = 0; if(copy_from_user(&gstrings, addr, sizeof(gstrings))) return -EFAULT; switch(gstrings.string_set) { - case ETH_SS_STATS: + case ETH_SS_TEST: + gstrings.len = E1000_TEST_LEN; + strings = kmalloc(E1000_TEST_LEN * ETH_GSTRING_LEN, + GFP_KERNEL); + if(!strings) + return -ENOMEM; + memcpy(strings, e1000_gstrings_test, E1000_TEST_LEN * + ETH_GSTRING_LEN); + break; + case ETH_SS_STATS: { + int i; gstrings.len = E1000_STATS_LEN; - strings = *e1000_gstrings_stats; + strings = kmalloc(E1000_STATS_LEN * ETH_GSTRING_LEN, + GFP_KERNEL); + if(!strings) + return -ENOMEM; + for(i=0; i < E1000_STATS_LEN; i++) { + memcpy(&strings[i * ETH_GSTRING_LEN], + e1000_gstrings_stats[i].stat_string, + ETH_GSTRING_LEN); + } break; + } default: return -EOPNOTSUPP; } if(copy_to_user(addr, &gstrings, sizeof(gstrings))) - return -EFAULT; + err = -EFAULT; addr += offsetof(struct ethtool_gstrings, data); - if(copy_to_user(addr, strings, + if(!err && copy_to_user(addr, strings, gstrings.len * ETH_GSTRING_LEN)) - return -EFAULT; - return 0; + err = -EFAULT; + + kfree(strings); + return err; } case ETHTOOL_GREGS: { struct ethtool_regs regs = {ETHTOOL_GREGS}; @@ -522,16 +1406,14 @@ void *ptr; int err = 0; + if(copy_from_user(&eeprom, addr, sizeof(eeprom))) + return -EFAULT; + eeprom_buff = kmalloc(hw->eeprom.word_size * 2, GFP_KERNEL); - if(eeprom_buff == NULL) + if(!eeprom_buff) return -ENOMEM; - if(copy_from_user(&eeprom, addr, sizeof(eeprom))) { - err = -EFAULT; - goto err_geeprom_ioctl; - } - if((err = e1000_ethtool_geeprom(adapter, &eeprom, eeprom_buff))) goto err_geeprom_ioctl; @@ -565,15 +1447,42 @@ } case ETHTOOL_GSTATS: { struct { - struct ethtool_stats cmd; + struct ethtool_stats eth_stats; uint64_t data[E1000_STATS_LEN]; } stats = { {ETHTOOL_GSTATS, E1000_STATS_LEN} }; int i; for(i = 0; i < E1000_STATS_LEN; i++) - stats.data[i] = - ((unsigned long *)&adapter->net_stats)[i]; + stats.data[i] = (e1000_gstrings_stats[i].sizeof_stat == + sizeof(uint64_t)) ? + *(uint64_t *)((char *)adapter + + e1000_gstrings_stats[i].stat_offset) : + *(uint32_t *)((char *)adapter + + e1000_gstrings_stats[i].stat_offset); if(copy_to_user(addr, &stats, sizeof(stats))) + return -EFAULT; + return 0; + } + case ETHTOOL_TEST: { + struct { + struct ethtool_test eth_test; + uint64_t data[E1000_TEST_LEN]; + } test = { {ETHTOOL_TEST} }; + int err; + + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + + if(copy_from_user(&test.eth_test, addr, sizeof(test.eth_test))) + return -EFAULT; + + test.eth_test.len = E1000_TEST_LEN; + + if((err = e1000_ethtool_test(adapter, &test.eth_test, + test.data))) + return err; + + if(copy_to_user(addr, &test, sizeof(test)) != 0) return -EFAULT; return 0; } diff -Nru a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c --- a/drivers/net/e1000/e1000_hw.c Sun May 25 20:17:20 2003 +++ b/drivers/net/e1000/e1000_hw.c Sun May 25 20:17:20 2003 @@ -185,6 +185,7 @@ break; case E1000_DEV_ID_82546EB_COPPER: case E1000_DEV_ID_82546EB_FIBER: + case E1000_DEV_ID_82546EB_QUAD_COPPER: hw->mac_type = e1000_82546; break; case E1000_DEV_ID_82541EI: @@ -288,9 +289,7 @@ /* Configure activity LED after PHY reset */ led_ctrl = E1000_READ_REG(hw, LEDCTL); led_ctrl &= IGP_ACTIVITY_LED_MASK; - led_ctrl |= IGP_ACTIVITY_LED_ENABLE; - if(hw->mac_type == e1000_82547) - led_ctrl |= IGP_LED3_MODE; + led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE); E1000_WRITE_REG(hw, LEDCTL, led_ctrl); } @@ -737,9 +736,7 @@ /* Configure activity LED after PHY reset */ led_ctrl = E1000_READ_REG(hw, LEDCTL); led_ctrl &= IGP_ACTIVITY_LED_MASK; - led_ctrl |= IGP_ACTIVITY_LED_ENABLE; - if(hw->mac_type == e1000_82547) - led_ctrl |= IGP_LED3_MODE; + led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE); E1000_WRITE_REG(hw, LEDCTL, led_ctrl); if(hw->autoneg_advertised == ADVERTISE_1000_FULL) { @@ -2293,9 +2290,7 @@ /* Configure activity LED after PHY reset */ led_ctrl = E1000_READ_REG(hw, LEDCTL); led_ctrl &= IGP_ACTIVITY_LED_MASK; - led_ctrl |= IGP_ACTIVITY_LED_ENABLE; - if(hw->mac_type == e1000_82547) - led_ctrl |= IGP_LED3_MODE; + led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE); E1000_WRITE_REG(hw, LEDCTL, led_ctrl); } } @@ -3801,6 +3796,7 @@ case E1000_DEV_ID_82540EM_LOM: case E1000_DEV_ID_82545EM_COPPER: case E1000_DEV_ID_82546EB_COPPER: + case E1000_DEV_ID_82546EB_QUAD_COPPER: case E1000_DEV_ID_82541EI: case E1000_DEV_ID_82541EP: case E1000_DEV_ID_82547EI: @@ -3842,6 +3838,7 @@ case E1000_DEV_ID_82545EM_FIBER: case E1000_DEV_ID_82546EB_COPPER: case E1000_DEV_ID_82546EB_FIBER: + case E1000_DEV_ID_82546EB_QUAD_COPPER: case E1000_DEV_ID_82541EI: case E1000_DEV_ID_82541EP: case E1000_DEV_ID_82547EI: @@ -3896,6 +3893,7 @@ case E1000_DEV_ID_82540EM_LOM: case E1000_DEV_ID_82545EM_COPPER: case E1000_DEV_ID_82546EB_COPPER: + case E1000_DEV_ID_82546EB_QUAD_COPPER: case E1000_DEV_ID_82541EI: case E1000_DEV_ID_82541EP: case E1000_DEV_ID_82547EI: @@ -3949,6 +3947,7 @@ case E1000_DEV_ID_82540EM_LOM: case E1000_DEV_ID_82545EM_COPPER: case E1000_DEV_ID_82546EB_COPPER: + case E1000_DEV_ID_82546EB_QUAD_COPPER: case E1000_DEV_ID_82541EI: case E1000_DEV_ID_82541EP: case E1000_DEV_ID_82547EI: @@ -4206,7 +4205,11 @@ status = E1000_READ_REG(hw, STATUS); hw->bus_type = (status & E1000_STATUS_PCIX_MODE) ? e1000_bus_type_pcix : e1000_bus_type_pci; - if(hw->bus_type == e1000_bus_type_pci) { + + if(hw->device_id == E1000_DEV_ID_82546EB_QUAD_COPPER) { + hw->bus_speed = (hw->bus_type == e1000_bus_type_pci) ? + e1000_bus_speed_66 : e1000_bus_speed_120; + } else if(hw->bus_type == e1000_bus_type_pci) { hw->bus_speed = (status & E1000_STATUS_PCI66) ? e1000_bus_speed_66 : e1000_bus_speed_33; } else { diff -Nru a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h --- a/drivers/net/e1000/e1000_hw.h Sun May 25 20:17:20 2003 +++ b/drivers/net/e1000/e1000_hw.h Sun May 25 20:17:20 2003 @@ -99,6 +99,7 @@ e1000_bus_speed_33, e1000_bus_speed_66, e1000_bus_speed_100, + e1000_bus_speed_120, e1000_bus_speed_133, e1000_bus_speed_reserved } e1000_bus_speed; @@ -314,10 +315,11 @@ #define E1000_DEV_ID_82545EM_FIBER 0x1011 #define E1000_DEV_ID_82546EB_COPPER 0x1010 #define E1000_DEV_ID_82546EB_FIBER 0x1012 +#define E1000_DEV_ID_82546EB_QUAD_COPPER 0x101D #define E1000_DEV_ID_82541EI 0x1013 #define E1000_DEV_ID_82541EP 0x1018 #define E1000_DEV_ID_82547EI 0x1019 -#define NUM_DEV_IDS 19 +#define NUM_DEV_IDS 20 #define NODE_ADDRESS_SIZE 6 #define ETH_LENGTH_OF_ADDRESS 6 @@ -601,7 +603,7 @@ #define E1000_EECD 0x00010 /* EEPROM/Flash Control - RW */ #define E1000_EERD 0x00014 /* EEPROM Read - RW */ #define E1000_CTRL_EXT 0x00018 /* Extended Device Control - RW */ -#define E1000_FLA 0x0001C /* Flash Access Register - RW */ +#define E1000_FLA 0x0001C /* Flash Access - RW */ #define E1000_MDIC 0x00020 /* MDI Control - RW */ #define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */ #define E1000_FCAH 0x0002C /* Flow Control Address High -RW */ @@ -730,6 +732,7 @@ * the registers function in the same manner. */ #define E1000_82542_CTRL E1000_CTRL +#define E1000_82542_CTRL_DUP E1000_CTRL_DUP #define E1000_82542_STATUS E1000_STATUS #define E1000_82542_EECD E1000_EECD #define E1000_82542_EERD E1000_EERD @@ -1485,7 +1488,6 @@ #define E1000_COLLISION_DISTANCE 64 #define E1000_FDX_COLLISION_DISTANCE E1000_COLLISION_DISTANCE #define E1000_HDX_COLLISION_DISTANCE E1000_COLLISION_DISTANCE -#define E1000_GB_HDX_COLLISION_DISTANCE 512 #define E1000_COLD_SHIFT 12 /* The number of Transmit and Receive Descriptors must be a multiple of 8 */ diff -Nru a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c --- a/drivers/net/e1000/e1000_main.c Sun May 25 20:17:19 2003 +++ b/drivers/net/e1000/e1000_main.c Sun May 25 20:17:19 2003 @@ -30,7 +30,14 @@ /* Change Log * - * 5.0.43 3/5/03 + * 5.1.11 5/6/03 + * o Feature: Added support for 82546EB (Quad-port) hardware. + * o Feature: Added support for Diagnostics through Ethtool. + * o Cleanup: Removed /proc support. + * o Cleanup: Removed proprietary IDIAG interface. + * o Bug fix: TSO bug fixes. + * + * 5.0.42 3/5/03 * o Feature: Added support for 82541 and 82547 hardware. * o Feature: Added support for Intel Gigabit PHY (IGP) and a variety of * eeproms. @@ -46,51 +53,22 @@ * shared interrupt instances. * * 4.4.18 11/27/02 - * o Feature: Added user-settable knob for interrupt throttle rate (ITR). - * o Cleanup: removed large static array allocations. - * o Cleanup: C99 struct initializer format. - * o Bug fix: restore VLAN settings when interface is brought up. - * o Bug fix: return cleanly in probe if error in detecting MAC type. - * o Bug fix: Wake up on magic packet by default only if enabled in eeprom. - * o Bug fix: Validate MAC address in set_mac. - * o Bug fix: Throw away zero-length Tx skbs. - * o Bug fix: Make ethtool EEPROM acceses work on older versions of ethtool. - * - * 4.4.12 10/15/02 */ char e1000_driver_name[] = "e1000"; char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver"; -char e1000_driver_version[] = "5.0.43-k3"; +char e1000_driver_version[] = "5.1.11-k1"; char e1000_copyright[] = "Copyright (c) 1999-2003 Intel Corporation."; /* e1000_pci_tbl - PCI Device ID Table * - * Private driver_data field (last one) stores an index into e1000_strings * Wildcard entries (PCI_ANY_ID) should come last * Last entry must be all 0s * * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, - * Class, Class Mask, String Index } + * Class, Class Mask, private data (not used) } */ static struct pci_device_id e1000_pci_tbl[] __devinitdata = { - /* Intel(R) PRO/1000 Network Connection */ - {0x8086, 0x1000, 0x8086, 0x1000, 0, 0, 0}, - {0x8086, 0x1001, 0x8086, 0x1003, 0, 0, 0}, - {0x8086, 0x1004, 0x8086, 0x1004, 0, 0, 0}, - {0x8086, 0x1008, 0x8086, 0x1107, 0, 0, 0}, - {0x8086, 0x1009, 0x8086, 0x1109, 0, 0, 0}, - {0x8086, 0x100C, 0x8086, 0x1112, 0, 0, 0}, - {0x8086, 0x100E, 0x8086, 0x001E, 0, 0, 0}, - /* Compaq Gigabit Ethernet Server Adapter */ - {0x8086, 0x1000, 0x0E11, PCI_ANY_ID, 0, 0, 1}, - {0x8086, 0x1001, 0x0E11, PCI_ANY_ID, 0, 0, 1}, - {0x8086, 0x1004, 0x0E11, PCI_ANY_ID, 0, 0, 1}, - /* IBM Mobile, Desktop & Server Adapters */ - {0x8086, 0x1000, 0x1014, PCI_ANY_ID, 0, 0, 2}, - {0x8086, 0x1001, 0x1014, PCI_ANY_ID, 0, 0, 2}, - {0x8086, 0x1004, 0x1014, PCI_ANY_ID, 0, 0, 2}, - /* Generic */ {0x8086, 0x1000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0x8086, 0x1001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0x8086, 0x1004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, @@ -106,6 +84,7 @@ {0x8086, 0x1016, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0x8086, 0x1017, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0x8086, 0x101E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0x8086, 0x101D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0x8086, 0x1013, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0x8086, 0x1019, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* required last entry */ @@ -114,12 +93,6 @@ MODULE_DEVICE_TABLE(pci, e1000_pci_tbl); -static char *e1000_strings[] = { - "Intel(R) PRO/1000 Network Connection", - "HP Gigabit Ethernet Server Adapter", - "IBM Mobile, Desktop & Server Adapters" -}; - /* Local Function Prototypes */ int e1000_up(struct e1000_adapter *adapter); @@ -130,7 +103,7 @@ static int e1000_init_module(void); static void e1000_exit_module(void); static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent); -static void e1000_remove(struct pci_dev *pdev); +static void __devexit e1000_remove(struct pci_dev *pdev); static int e1000_sw_init(struct e1000_adapter *adapter); static int e1000_open(struct net_device *netdev); static int e1000_close(struct net_device *netdev); @@ -195,7 +168,6 @@ .priority = 0 }; - /* Exported from other modules */ extern void e1000_check_options(struct e1000_adapter *adapter); @@ -234,8 +206,9 @@ printk(KERN_INFO "%s\n", e1000_copyright); ret = pci_module_init(&e1000_driver); - if(ret >= 0) + if(ret >= 0) { register_reboot_notifier(&e1000_notifier_reboot); + } return ret; } @@ -439,7 +412,6 @@ netdev->base_addr = adapter->hw.io_base; adapter->bd_number = cards_found; - adapter->id_string = e1000_strings[ent->driver_data]; /* setup the private structure */ @@ -500,15 +472,14 @@ (void (*)(void *))e1000_tx_timeout_task, netdev); register_netdev(netdev); - memcpy(adapter->ifname, netdev->name, IFNAMSIZ); - adapter->ifname[IFNAMSIZ-1] = 0; /* we're going to reset, so assume we have no link for now */ netif_carrier_off(netdev); netif_stop_queue(netdev); - printk(KERN_INFO "%s: %s\n", netdev->name, adapter->id_string); + printk(KERN_INFO "%s: Intel(R) PRO/1000 Network Connection\n", + netdev->name); e1000_check_options(adapter); /* Initial Wake on LAN setting @@ -568,7 +539,6 @@ e1000_phy_hw_reset(&adapter->hw); - iounmap(adapter->hw.hw_addr); pci_release_regions(pdev); @@ -831,8 +801,9 @@ e1000_config_collision_dist(&adapter->hw); - /* Setup Transmit Descriptor Settings for this adapter */ - adapter->txd_cmd = E1000_TXD_CMD_IFCS | E1000_TXD_CMD_IDE; + /* Setup Transmit Descriptor Settings for eop descriptor */ + adapter->txd_cmd = E1000_TXD_CMD_IDE | E1000_TXD_CMD_EOP | + E1000_TXD_CMD_IFCS; if(adapter->hw.report_tx_early == 1) adapter->txd_cmd |= E1000_TXD_CMD_RS; @@ -1435,7 +1406,7 @@ #define E1000_TX_FLAGS_VLAN_SHIFT 16 static inline boolean_t -e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb, int tx_flags) +e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb) { #ifdef NETIF_F_TSO struct e1000_context_desc *context_desc; @@ -1471,7 +1442,7 @@ context_desc->upper_setup.tcp_fields.tucse = cpu_to_le16(tucse); context_desc->tcp_seg_setup.fields.mss = cpu_to_le16(mss); context_desc->tcp_seg_setup.fields.hdr_len = hdr_len; - context_desc->cmd_and_length = cpu_to_le32(adapter->txd_cmd | + context_desc->cmd_and_length = cpu_to_le32( E1000_TXD_CMD_DEXT | E1000_TXD_CMD_TSE | E1000_TXD_CMD_IP | E1000_TXD_CMD_TCP | (skb->len - (hdr_len))); @@ -1504,8 +1475,7 @@ context_desc->upper_setup.tcp_fields.tucso = cso; context_desc->upper_setup.tcp_fields.tucse = 0; context_desc->tcp_seg_setup.data = 0; - context_desc->cmd_and_length = - cpu_to_le32(adapter->txd_cmd | E1000_TXD_CMD_DEXT); + context_desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT); if(++i == adapter->tx_ring.count) i = 0; adapter->tx_ring.next_to_use = i; @@ -1520,7 +1490,8 @@ #define E1000_MAX_DATA_PER_TXD (1<tx_ring; int len = skb->len, offset = 0, size, count = 0, i; @@ -1588,6 +1559,7 @@ } if(--i < 0) i = tx_ring->count - 1; tx_ring->buffer_info[i].skb = skb; + tx_ring->buffer_info[first].next_to_watch = i; return count; } @@ -1597,12 +1569,9 @@ { struct e1000_desc_ring *tx_ring = &adapter->tx_ring; struct e1000_tx_desc *tx_desc = NULL; - uint32_t txd_upper, txd_lower; + uint32_t txd_upper = 0, txd_lower = E1000_TXD_CMD_IFCS; int i; - txd_upper = 0; - txd_lower = adapter->txd_cmd; - if(tx_flags & E1000_TX_FLAGS_TSO) { txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D | E1000_TXD_CMD_TSE; @@ -1630,7 +1599,7 @@ if(++i == tx_ring->count) i = 0; } - tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP); + tx_desc->lower.data |= cpu_to_le32(adapter->txd_cmd); /* Force memory writes to complete before letting h/w * know there are new descriptors to fetch. (Only @@ -1690,6 +1659,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) { struct e1000_adapter *adapter = netdev->priv; + unsigned int first; int tx_flags = 0; if(skb->len <= 0) { @@ -1715,12 +1685,14 @@ tx_flags |= (vlan_tx_tag_get(skb) << E1000_TX_FLAGS_VLAN_SHIFT); } - if(e1000_tso(adapter, skb, tx_flags)) + first = adapter->tx_ring.next_to_use; + + if(e1000_tso(adapter, skb)) tx_flags |= E1000_TX_FLAGS_TSO; else if(e1000_tx_csum(adapter, skb)) tx_flags |= E1000_TX_FLAGS_CSUM; - e1000_tx_queue(adapter, e1000_tx_map(adapter, skb), tx_flags); + e1000_tx_queue(adapter, e1000_tx_map(adapter, skb, first), tx_flags); netdev->trans_start = jiffies; @@ -1952,6 +1924,7 @@ } if((hw->mac_type <= e1000_82546) && + (hw->phy_type == e1000_phy_m88) && !e1000_read_phy_reg(hw, M88E1000_RX_ERR_CNTR, &phy_tmp)) adapter->phy_stats.receive_errors += phy_tmp; } @@ -2069,39 +2042,47 @@ struct e1000_desc_ring *tx_ring = &adapter->tx_ring; struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; - struct e1000_tx_desc *tx_desc; - int i, cleaned = FALSE; + struct e1000_tx_desc *tx_desc, *eop_desc; + struct e1000_buffer *buffer_info; + int i, eop, cleaned = FALSE; i = tx_ring->next_to_clean; - tx_desc = E1000_TX_DESC(*tx_ring, i); + eop = tx_ring->buffer_info[i].next_to_watch; + eop_desc = E1000_TX_DESC(*tx_ring, eop); - while(tx_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) { + while(eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) { - cleaned = TRUE; + for(cleaned = FALSE; !cleaned; ) { + tx_desc = E1000_TX_DESC(*tx_ring, i); + buffer_info = &tx_ring->buffer_info[i]; - if(tx_ring->buffer_info[i].dma) { + if(buffer_info->dma) { - pci_unmap_page(pdev, - tx_ring->buffer_info[i].dma, - tx_ring->buffer_info[i].length, - PCI_DMA_TODEVICE); + pci_unmap_page(pdev, + buffer_info->dma, + buffer_info->length, + PCI_DMA_TODEVICE); - tx_ring->buffer_info[i].dma = 0; - } + buffer_info->dma = 0; + } - if(tx_ring->buffer_info[i].skb) { + if(buffer_info->skb) { - dev_kfree_skb_any(tx_ring->buffer_info[i].skb); + dev_kfree_skb_any(buffer_info->skb); - tx_ring->buffer_info[i].skb = NULL; - } + buffer_info->skb = NULL; + } - tx_desc->buffer_addr = 0; - tx_desc->lower.data = 0; - tx_desc->upper.data = 0; + tx_desc->buffer_addr = 0; + tx_desc->lower.data = 0; + tx_desc->upper.data = 0; - if(++i == tx_ring->count) i = 0; - tx_desc = E1000_TX_DESC(*tx_ring, i); + cleaned = (i == eop); + if(++i == tx_ring->count) i = 0; + } + + eop = tx_ring->buffer_info[i].next_to_watch; + eop_desc = E1000_TX_DESC(*tx_ring, eop); } tx_ring->next_to_clean = i; @@ -2224,7 +2205,6 @@ netif_rx(skb); } #endif /* CONFIG_E1000_NAPI */ - netdev->last_rx = jiffies; rx_desc->status = 0; @@ -2676,7 +2656,6 @@ } return NOTIFY_DONE; } - static int e1000_suspend(struct pci_dev *pdev, uint32_t state) diff -Nru a/drivers/net/fc/iph5526.c b/drivers/net/fc/iph5526.c --- a/drivers/net/fc/iph5526.c Sun May 25 20:17:19 2003 +++ b/drivers/net/fc/iph5526.c Sun May 25 20:17:19 2003 @@ -134,7 +134,7 @@ {0,} }; -static void tachyon_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t tachyon_interrupt(int irq, void *dev_id, struct pt_regs *regs); static void tachyon_interrupt_handler(int irq, void* dev_id, struct pt_regs* regs); static int initialize_register_pointers(struct fc_info *fi); @@ -623,7 +623,7 @@ } -static void tachyon_interrupt(int irq, void* dev_id, struct pt_regs* regs) +static irqreturn_t tachyon_interrupt(int irq, void* dev_id, struct pt_regs* regs) { struct Scsi_Host *host = dev_id; struct iph5526_hostdata *hostdata = (struct iph5526_hostdata *)host->hostdata; @@ -632,6 +632,7 @@ spin_lock_irqsave(&fi->fc_lock, flags); tachyon_interrupt_handler(irq, dev_id, regs); spin_unlock_irqrestore(&fi->fc_lock, flags); + return IRQ_HANDLED; } static void tachyon_interrupt_handler(int irq, void* dev_id, struct pt_regs* regs) @@ -3720,12 +3721,13 @@ int iph5526_detect(Scsi_Host_Template *tmpt) { -struct Scsi_Host *host = NULL; -struct iph5526_hostdata *hostdata; -struct fc_info *fi = NULL; -int no_of_hosts = 0, timeout, i, j, count = 0; -u_int pci_maddr = 0; -struct pci_dev *pdev = NULL; + struct Scsi_Host *host = NULL; + struct iph5526_hostdata *hostdata; + struct fc_info *fi = NULL; + int no_of_hosts = 0, i, j, count = 0; + u_int pci_maddr = 0; + struct pci_dev *pdev = NULL; + unsigned long timeout; tmpt->proc_name = "iph5526"; if (pci_present() == 0) { diff -Nru a/drivers/net/fec.c b/drivers/net/fec.c --- a/drivers/net/fec.c Sun May 25 20:17:19 2003 +++ b/drivers/net/fec.c Sun May 25 20:17:19 2003 @@ -188,7 +188,7 @@ static int fec_enet_open(struct net_device *dev); static int fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev); static void fec_enet_mii(struct net_device *dev); -static void fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs); +static irqreturn_t fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs); static void fec_enet_tx(struct net_device *dev); static void fec_enet_rx(struct net_device *dev); static int fec_enet_close(struct net_device *dev); @@ -393,12 +393,13 @@ /* The interrupt handler. * This is called from the MPC core interrupt. */ -static void +static irqreturn_t fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs) { struct net_device *dev = dev_id; volatile fec_t *fecp; uint int_events; + int handled = 0; fecp = (volatile fec_t*)dev->base_addr; @@ -413,20 +414,27 @@ /* Handle receive event in its own function. */ - if (int_events & FEC_ENET_RXF) + if (int_events & FEC_ENET_RXF) { + handled = 1; fec_enet_rx(dev); + } /* Transmit OK, or non-fatal error. Update the buffer descriptors. FEC handles all errors, we just discover them as part of the transmit process. */ - if (int_events & FEC_ENET_TXF) + if (int_events & FEC_ENET_TXF) { + handled = 1; fec_enet_tx(dev); + } - if (int_events & FEC_ENET_MII) + if (int_events & FEC_ENET_MII) { + handled = 1; fec_enet_mii(dev); + } } + return IRQ_RETVAL(handled); } diff -Nru a/drivers/net/fmv18x.c b/drivers/net/fmv18x.c --- a/drivers/net/fmv18x.c Sun May 25 20:17:19 2003 +++ b/drivers/net/fmv18x.c Sun May 25 20:17:19 2003 @@ -114,7 +114,7 @@ static int fmv18x_probe1(struct net_device *dev, short ioaddr); static int net_open(struct net_device *dev); static int net_send_packet(struct sk_buff *skb, struct net_device *dev); -static void net_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t net_interrupt(int irq, void *dev_id, struct pt_regs *regs); static void net_rx(struct net_device *dev); static void net_timeout(struct net_device *dev); static int net_close(struct net_device *dev); @@ -423,7 +423,7 @@ /* The typical workload of the driver: Handle the network interface interrupts. */ -static void +static irqreturn_t net_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = dev_id; @@ -476,7 +476,7 @@ spin_unlock(&lp->lock); } } - return; + return IRQ_RETVAL(status); } /* We have a good packet(s), get it/them out of the buffers. */ diff -Nru a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c --- a/drivers/net/hamradio/scc.c Sun May 25 20:17:20 2003 +++ b/drivers/net/hamradio/scc.c Sun May 25 20:17:20 2003 @@ -199,7 +199,7 @@ static void init_channel(struct scc_channel *scc); static void scc_key_trx (struct scc_channel *scc, char tx); -static void scc_isr(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs *regs); static void scc_init_timer(struct scc_channel *scc); static int scc_net_setup(struct scc_channel *scc, unsigned char *name, int addev); @@ -625,7 +625,7 @@ #define SCC_IRQTIMEOUT 30000 -static void scc_isr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs *regs) { unsigned char vector; struct scc_channel *scc; @@ -653,7 +653,7 @@ if (k == SCC_IRQTIMEOUT) printk(KERN_WARNING "z8530drv: endless loop in scc_isr()?\n"); - return; + return IRQ_HANDLED; } /* Find the SCC generating the interrupt by polling all attached SCCs @@ -701,6 +701,7 @@ } else ctrl++; } + return IRQ_HANDLED; } diff -Nru a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c --- a/drivers/net/myri_sbus.c Sun May 25 20:17:19 2003 +++ b/drivers/net/myri_sbus.c Sun May 25 20:17:19 2003 @@ -541,6 +541,7 @@ struct myri_channel *chan = &mp->shmem->channel; unsigned long flags; u32 status; + int handled = 0; spin_lock_irqsave(&mp->irq_lock, flags); @@ -549,6 +550,7 @@ if (status & ISTAT_HOST) { u32 softstate; + handled = 1; DIRQ(("IRQ_DISAB ")); myri_disable_irq(lregs, mp->cregs); softstate = sbus_readl(&chan->state); @@ -568,7 +570,7 @@ spin_unlock_irqrestore(&mp->irq_lock, flags); - return IRQ_HANDLED; + return IRQ_RETVAL(handled); } static int myri_open(struct net_device *dev) diff -Nru a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c --- a/drivers/net/ppp_synctty.c Sun May 25 20:17:20 2003 +++ b/drivers/net/ppp_synctty.c Sun May 25 20:17:20 2003 @@ -202,7 +202,6 @@ struct syncppp *ap; int err; - MOD_INC_USE_COUNT; ap = kmalloc(sizeof(*ap), GFP_KERNEL); err = -ENOMEM; if (ap == 0) @@ -236,7 +235,6 @@ out_free: kfree(ap); out: - MOD_DEC_USE_COUNT; return err; } @@ -276,7 +274,6 @@ if (ap->tpkt != 0) kfree_skb(ap->tpkt); kfree(ap); - MOD_DEC_USE_COUNT; } /* @@ -404,6 +401,7 @@ static struct tty_ldisc ppp_sync_ldisc = { + .owner = THIS_MODULE, .magic = TTY_LDISC_MAGIC, .name = "pppsync", .open = ppp_sync_open, diff -Nru a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c --- a/drivers/net/seeq8005.c Sun May 25 20:17:20 2003 +++ b/drivers/net/seeq8005.c Sun May 25 20:17:20 2003 @@ -84,7 +84,7 @@ static int seeq8005_open(struct net_device *dev); static void seeq8005_timeout(struct net_device *dev); static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev); -static void seeq8005_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t seeq8005_interrupt(int irq, void *dev_id, struct pt_regs *regs); static void seeq8005_rx(struct net_device *dev); static int seeq8005_close(struct net_device *dev); static struct net_device_stats *seeq8005_get_stats(struct net_device *dev); @@ -400,11 +400,12 @@ /* The typical workload of the driver: Handle the network interface interrupts. */ -static void seeq8005_interrupt(int irq, void *dev_id, struct pt_regs * regs) +static irqreturn_t seeq8005_interrupt(int irq, void *dev_id, struct pt_regs * regs) { struct net_device *dev = dev_id; struct net_local *lp; int ioaddr, status, boguscount = 0; + int handled = 0; ioaddr = dev->base_addr; lp = (struct net_local *)dev->priv; @@ -416,17 +417,20 @@ } if (status & SEEQSTAT_WINDOW_INT) { + handled = 1; outw( SEEQCMD_WINDOW_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD); if (net_debug) { printk("%s: window int!\n",dev->name); } } if (status & SEEQSTAT_TX_INT) { + handled = 1; outw( SEEQCMD_TX_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD); lp->stats.tx_packets++; netif_wake_queue(dev); /* Inform upper layers. */ } if (status & SEEQSTAT_RX_INT) { + handled = 1; /* Got a packet(s). */ seeq8005_rx(dev); } @@ -436,6 +440,7 @@ if(net_debug>2) { printk("%s: eoi\n",dev->name); } + return IRQ_RETVAL(handled); } /* We have a good packet(s), get it/them out of the buffers. */ diff -Nru a/drivers/net/sunqe.c b/drivers/net/sunqe.c --- a/drivers/net/sunqe.c Sun May 25 20:17:19 2003 +++ b/drivers/net/sunqe.c Sun May 25 20:17:19 2003 @@ -124,6 +124,7 @@ qb->qe_rxd[i].rx_flags = (RXD_OWN | ((RXD_PKT_SZ) & RXD_LENGTH)); } + return IRQ_HANDLED; } static int qe_init(struct sunqe *qep, int from_irq) diff -Nru a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c --- a/drivers/net/tokenring/lanstreamer.c Sun May 25 20:17:20 2003 +++ b/drivers/net/tokenring/lanstreamer.c Sun May 25 20:17:20 2003 @@ -201,7 +201,7 @@ static int streamer_xmit(struct sk_buff *skb, struct net_device *dev); static int streamer_close(struct net_device *dev); static void streamer_set_rx_mode(struct net_device *dev); -static void streamer_interrupt(int irq, void *dev_id, +static irqreturn_t streamer_interrupt(int irq, void *dev_id, struct pt_regs *regs); static struct net_device_stats *streamer_get_stats(struct net_device *dev); static int streamer_set_mac_address(struct net_device *dev, void *addr); @@ -1021,7 +1021,7 @@ } /* end for all completed rx descriptors */ } -static void streamer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t streamer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_id; struct streamer_private *streamer_priv = @@ -1142,6 +1142,7 @@ } /* while() */ spin_unlock(&streamer_priv->streamer_lock) ; + return IRQ_HANDLED; } static int streamer_xmit(struct sk_buff *skb, struct net_device *dev) diff -Nru a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c --- a/drivers/net/tulip/de4x5.c Sun May 25 20:17:19 2003 +++ b/drivers/net/tulip/de4x5.c Sun May 25 20:17:19 2003 @@ -2027,7 +2027,7 @@ } } - return; + return IRQ_HANDLED; } /* diff -Nru a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c --- a/drivers/net/wan/lmc/lmc_main.c Sun May 25 20:17:19 2003 +++ b/drivers/net/wan/lmc/lmc_main.c Sun May 25 20:17:19 2003 @@ -117,7 +117,7 @@ static int lmc_open(struct net_device *dev); static int lmc_close(struct net_device *dev); static struct net_device_stats *lmc_get_stats(struct net_device *dev); -static void lmc_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +static irqreturn_t lmc_interrupt(int irq, void *dev_instance, struct pt_regs *regs); static int lmc_set_config(struct net_device *dev, struct ifmap *map); static void lmc_initcsrs(lmc_softc_t * const sc, lmc_csrptr_t csr_base, size_t csr_size); static void lmc_softreset(lmc_softc_t * const); @@ -1388,7 +1388,7 @@ /* Interrupt handling routine. This will take an incoming packet, or clean * up after a trasmit. */ -static void lmc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) /*fold00*/ +static irqreturn_t lmc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) /*fold00*/ { struct net_device *dev = (struct net_device *) dev_instance; lmc_softc_t *sc; @@ -1398,6 +1398,7 @@ unsigned int badtx; u32 firstcsr; int max_work = LMC_RXDESCS; + int handled = 0; lmc_trace(dev, "lmc_interrupt in"); @@ -1421,6 +1422,8 @@ /* always go through this loop at least once */ while (csr & sc->lmc_intrmask) { + handled = 1; + /* * Clear interrupt bits, we handle all case below */ @@ -1580,6 +1583,7 @@ spin_unlock(&sc->lmc_lock); lmc_trace(dev, "lmc_interrupt out"); + return IRQ_RETVAL(handled); } static int lmc_start_xmit (struct sk_buff *skb, struct net_device *dev) /*fold00*/ diff -Nru a/drivers/net/wireless/airport.c b/drivers/net/wireless/airport.c --- a/drivers/net/wireless/airport.c Sun May 25 20:17:20 2003 +++ b/drivers/net/wireless/airport.c Sun May 25 20:17:20 2003 @@ -275,14 +275,10 @@ printk(KERN_DEBUG "%s\n", version); - MOD_INC_USE_COUNT; - /* Lookup card in device tree */ airport_node = find_devices("radio"); if (airport_node && !strcmp(airport_node->parent->name, "mac-io")) airport_dev = airport_attach(airport_node); - - MOD_DEC_USE_COUNT; return airport_dev ? 0 : -ENODEV; } diff -Nru a/include/linux/arcdevice.h b/include/linux/arcdevice.h --- a/include/linux/arcdevice.h Sun May 25 20:17:19 2003 +++ b/include/linux/arcdevice.h Sun May 25 20:17:19 2003 @@ -329,7 +329,7 @@ #endif void arcnet_unregister_proto(struct ArcProto *proto); -void arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs); +irqreturn_t arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs); void arcdev_setup(struct net_device *dev); void arcnet_rx(struct net_device *dev, int bufnum);