From owner-p4-projects@FreeBSD.ORG Wed Nov 1 07:20:25 2006 Return-Path: X-Original-To: p4-projects@freebsd.org Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 1E5AE16A415; Wed, 1 Nov 2006 07:20:25 +0000 (UTC) X-Original-To: perforce@freebsd.org Delivered-To: perforce@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id B6AED16A47C for ; Wed, 1 Nov 2006 07:20:24 +0000 (UTC) (envelope-from jb@freebsd.org) Received: from repoman.freebsd.org (repoman.freebsd.org [216.136.204.115]) by mx1.FreeBSD.org (Postfix) with ESMTP id 722F043D49 for ; Wed, 1 Nov 2006 07:20:24 +0000 (GMT) (envelope-from jb@freebsd.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.13.6/8.13.6) with ESMTP id kA17KOI1041124 for ; Wed, 1 Nov 2006 07:20:24 GMT (envelope-from jb@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.13.6/8.13.4/Submit) id kA17KNnL041121 for perforce@freebsd.org; Wed, 1 Nov 2006 07:20:23 GMT (envelope-from jb@freebsd.org) Date: Wed, 1 Nov 2006 07:20:23 GMT Message-Id: <200611010720.kA17KNnL041121@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to jb@freebsd.org using -f From: John Birrell To: Perforce Change Reviews Cc: Subject: PERFORCE change 108892 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 01 Nov 2006 07:20:25 -0000 http://perforce.freebsd.org/chv.cgi?CH=108892 Change 108892 by jb@jb_freebsd8 on 2006/11/01 07:19:53 Reset these files to match current. I had been keeping a version of the never-ending-updated-by-everyone driver that actually worked on sun4v. It changes faster than I can test it. In my new sun4v branch I've got a driver called 'me' that I can use every time the 'em' from current goes off into no-worky-land. Affected files ... .. //depot/projects/dtrace/src/sys/dev/em/if_em.c#10 integrate .. //depot/projects/dtrace/src/sys/dev/em/if_em.h#6 integrate .. //depot/projects/dtrace/src/sys/dev/em/if_em_hw.c#7 integrate .. //depot/projects/dtrace/src/sys/dev/em/if_em_hw.h#5 integrate .. //depot/projects/dtrace/src/sys/dev/em/if_em_osdep.h#6 integrate Differences ... ==== //depot/projects/dtrace/src/sys/dev/em/if_em.c#10 (text+ko) ==== @@ -1,7 +1,6 @@ -//depot/projects/dtrace/src/sys/dev/em/if_em.c#7 - edit change 102692 (text+ko) /************************************************************************** -Copyright (c) 2001-2005, Intel Corporation +Copyright (c) 2001-2006, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -32,7 +31,7 @@ ***************************************************************************/ -/*$FreeBSD: src/sys/dev/em/if_em.c,v 1.119 2006/07/20 04:18:45 yongari Exp $*/ +/*$FreeBSD: src/sys/dev/em/if_em.c,v 1.160 2006/10/31 17:21:14 jhb Exp $*/ #ifdef HAVE_KERNEL_OPTION_HEADERS #include "opt_device_polling.h" @@ -70,9 +69,11 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -87,7 +88,7 @@ * Driver version *********************************************************************/ -char em_driver_version[] = "Version - 5.1.5"; +char em_driver_version[] = "Version - 6.2.9"; /********************************************************************* @@ -151,6 +152,10 @@ { 0x8086, E1000_DEV_ID_82571EB_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_82571EB_FIBER, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_82571EB_SERDES, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82571EB_QUAD_COPPER, + PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82571EB_QUAD_COPPER_LOWPROFILE, + PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_82572EI_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_82572EI_FIBER, PCI_ANY_ID, PCI_ANY_ID, 0}, @@ -160,10 +165,21 @@ { 0x8086, E1000_DEV_ID_82573E, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_82573E_IAMT, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_82573L, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_80003ES2LAN_COPPER_SPT, + PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_80003ES2LAN_SERDES_SPT, + PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_80003ES2LAN_COPPER_DPT, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_80003ES2LAN_SERDES_DPT, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_ICH8_IGP_M_AMT, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_ICH8_IGP_AMT, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_ICH8_IGP_C, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_ICH8_IFE, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_ICH8_IFE_GT, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_ICH8_IFE_G, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_ICH8_IGP_M, PCI_ANY_ID, PCI_ANY_ID, 0}, /* required last entry */ { 0, 0, 0, 0, 0} @@ -191,64 +207,65 @@ static int em_ioctl(struct ifnet *, u_long, caddr_t); static void em_watchdog(struct ifnet *); static void em_init(void *); -static void em_init_locked(struct em_softc *); +static void em_init_locked(struct adapter *); static void em_stop(void *); static void em_media_status(struct ifnet *, struct ifmediareq *); static int em_media_change(struct ifnet *); -static void em_identify_hardware(struct em_softc *); -static int em_allocate_pci_resources(struct em_softc *); -static int em_allocate_intr(struct em_softc *); -static void em_free_intr(struct em_softc *); -static void em_free_pci_resources(struct em_softc *); +static void em_identify_hardware(struct adapter *); +static int em_allocate_pci_resources(struct adapter *); +static int em_allocate_intr(struct adapter *); +static void em_free_intr(struct adapter *); +static void em_free_pci_resources(struct adapter *); static void em_local_timer(void *); -static int em_hardware_init(struct em_softc *); -static void em_setup_interface(device_t, struct em_softc *); -static int em_setup_transmit_structures(struct em_softc *); -static void em_initialize_transmit_unit(struct em_softc *); -static int em_setup_receive_structures(struct em_softc *); -static void em_initialize_receive_unit(struct em_softc *); -static void em_enable_intr(struct em_softc *); -static void em_disable_intr(struct em_softc *); -static void em_free_transmit_structures(struct em_softc *); -static void em_free_receive_structures(struct em_softc *); -static void em_update_stats_counters(struct em_softc *); -static void em_txeof(struct em_softc *); -static int em_allocate_receive_structures(struct em_softc *); -static int em_allocate_transmit_structures(struct em_softc *); -static int em_rxeof(struct em_softc *, int); +static int em_hardware_init(struct adapter *); +static void em_setup_interface(device_t, struct adapter *); +static void em_setup_transmit_structures(struct adapter *); +static void em_initialize_transmit_unit(struct adapter *); +static int em_setup_receive_structures(struct adapter *); +static void em_initialize_receive_unit(struct adapter *); +static void em_enable_intr(struct adapter *); +static void em_disable_intr(struct adapter *); +static void em_free_transmit_structures(struct adapter *); +static void em_free_receive_structures(struct adapter *); +static void em_update_stats_counters(struct adapter *); +static void em_txeof(struct adapter *); +static int em_allocate_receive_structures(struct adapter *); +static int em_allocate_transmit_structures(struct adapter *); +static int em_rxeof(struct adapter *, int); #ifndef __NO_STRICT_ALIGNMENT -static int em_fixup_rx(struct em_softc *); +static int em_fixup_rx(struct adapter *); #endif -static void em_receive_checksum(struct em_softc *, struct em_rx_desc *, +static void em_receive_checksum(struct adapter *, struct em_rx_desc *, struct mbuf *); -static void em_transmit_checksum_setup(struct em_softc *, struct mbuf *, +static void em_transmit_checksum_setup(struct adapter *, struct mbuf *, + uint32_t *, uint32_t *); +static boolean_t em_tso_setup(struct adapter *, struct mbuf *, uint32_t *, uint32_t *); -static void em_set_promisc(struct em_softc *); -static void em_disable_promisc(struct em_softc *); -static void em_set_multi(struct em_softc *); -static void em_print_hw_stats(struct em_softc *); -static void em_update_link_status(struct em_softc *); -static int em_get_buf(int i, struct em_softc *, struct mbuf *); -static void em_enable_vlans(struct em_softc *); -static void em_disable_vlans(struct em_softc *); -static int em_encap(struct em_softc *, struct mbuf **); -static void em_smartspeed(struct em_softc *); -static int em_82547_fifo_workaround(struct em_softc *, int); -static void em_82547_update_fifo_head(struct em_softc *, int); -static int em_82547_tx_fifo_reset(struct em_softc *); +static void em_set_promisc(struct adapter *); +static void em_disable_promisc(struct adapter *); +static void em_set_multi(struct adapter *); +static void em_print_hw_stats(struct adapter *); +static void em_update_link_status(struct adapter *); +static int em_get_buf(struct adapter *, int); +static void em_enable_vlans(struct adapter *); +static void em_disable_vlans(struct adapter *); +static int em_encap(struct adapter *, struct mbuf **); +static void em_smartspeed(struct adapter *); +static int em_82547_fifo_workaround(struct adapter *, int); +static void em_82547_update_fifo_head(struct adapter *, int); +static int em_82547_tx_fifo_reset(struct adapter *); static void em_82547_move_tail(void *arg); -static void em_82547_move_tail_locked(struct em_softc *); -static int em_dma_malloc(struct em_softc *, bus_size_t, +static int em_dma_malloc(struct adapter *, bus_size_t, struct em_dma_alloc *, int); -static void em_dma_free(struct em_softc *, struct em_dma_alloc *); -static void em_print_debug_info(struct em_softc *); +static void em_dma_free(struct adapter *, struct em_dma_alloc *); +static void em_print_debug_info(struct adapter *); static int em_is_valid_ether_addr(uint8_t *); static int em_sysctl_stats(SYSCTL_HANDLER_ARGS); static int em_sysctl_debug_info(SYSCTL_HANDLER_ARGS); static uint32_t em_fill_descriptors (bus_addr_t address, uint32_t length, PDESC_ARRAY desc_array); static int em_sysctl_int_delay(SYSCTL_HANDLER_ARGS); -static void em_add_int_delay_sysctl(struct em_softc *, const char *, +static void em_add_int_delay_sysctl(struct adapter *, const char *, const char *, struct em_int_delay_info *, int, int); /* @@ -260,7 +277,7 @@ static void em_intr(void *); #else static void em_intr_fast(void *); -static void em_add_int_process_limit(struct em_softc *, const char *, +static void em_add_int_process_limit(struct adapter *, const char *, const char *, int *, int); static void em_handle_rxtx(void *context, int pending); static void em_handle_link(void *context, int pending); @@ -282,7 +299,7 @@ }; static driver_t em_driver = { - "em", em_methods, sizeof(struct em_softc), + "em", em_methods, sizeof(struct adapter), }; static devclass_t em_devclass; @@ -296,6 +313,7 @@ #define E1000_TICKS_TO_USECS(ticks) ((1024 * (ticks) + 500) / 1000) #define E1000_USECS_TO_TICKS(usecs) ((1000 * (usecs) + 512) / 1024) +#define M_TSO_LEN 66 static int em_tx_int_delay_dflt = E1000_TICKS_TO_USECS(EM_TIDV); static int em_rx_int_delay_dflt = E1000_TICKS_TO_USECS(EM_RDTR); @@ -303,6 +321,7 @@ static int em_rx_abs_int_delay_dflt = E1000_TICKS_TO_USECS(EM_RADV); static int em_rxd = EM_DEFAULT_RXD; static int em_txd = EM_DEFAULT_TXD; +static int em_smart_pwr_down = FALSE; TUNABLE_INT("hw.em.tx_int_delay", &em_tx_int_delay_dflt); TUNABLE_INT("hw.em.rx_int_delay", &em_rx_int_delay_dflt); @@ -310,6 +329,7 @@ TUNABLE_INT("hw.em.rx_abs_int_delay", &em_rx_abs_int_delay_dflt); TUNABLE_INT("hw.em.rxd", &em_rxd); TUNABLE_INT("hw.em.txd", &em_txd); +TUNABLE_INT("hw.em.smart_pwr_down", &em_smart_pwr_down); #ifndef DEVICE_POLLING static int em_rx_process_limit = 100; TUNABLE_INT("hw.em.rx_process_limit", &em_rx_process_limit); @@ -379,199 +399,216 @@ static int em_attach(device_t dev) { - struct em_softc *sc; + struct adapter *adapter; int tsize, rsize; int error = 0; INIT_DEBUGOUT("em_attach: begin"); - sc = device_get_softc(dev); - sc->dev = sc->osdep.dev = dev; - EM_LOCK_INIT(sc, device_get_nameunit(dev)); + adapter = device_get_softc(dev); + adapter->dev = adapter->osdep.dev = dev; + EM_LOCK_INIT(adapter, device_get_nameunit(dev)); /* SYSCTL stuff */ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), - OID_AUTO, "debug_info", CTLTYPE_INT|CTLFLAG_RW, sc, 0, + OID_AUTO, "debug_info", CTLTYPE_INT|CTLFLAG_RW, adapter, 0, em_sysctl_debug_info, "I", "Debug Information"); SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), - OID_AUTO, "stats", CTLTYPE_INT|CTLFLAG_RW, sc, 0, + OID_AUTO, "stats", CTLTYPE_INT|CTLFLAG_RW, adapter, 0, em_sysctl_stats, "I", "Statistics"); - callout_init(&sc->timer, CALLOUT_MPSAFE); - callout_init(&sc->tx_fifo_timer, CALLOUT_MPSAFE); + callout_init_mtx(&adapter->timer, &adapter->mtx, 0); + callout_init_mtx(&adapter->tx_fifo_timer, &adapter->mtx, 0); /* Determine hardware revision */ - em_identify_hardware(sc); + em_identify_hardware(adapter); /* Set up some sysctls for the tunable interrupt delays */ - em_add_int_delay_sysctl(sc, "rx_int_delay", - "receive interrupt delay in usecs", &sc->rx_int_delay, - E1000_REG_OFFSET(&sc->hw, RDTR), em_rx_int_delay_dflt); - em_add_int_delay_sysctl(sc, "tx_int_delay", - "transmit interrupt delay in usecs", &sc->tx_int_delay, - E1000_REG_OFFSET(&sc->hw, TIDV), em_tx_int_delay_dflt); - if (sc->hw.mac_type >= em_82540) { - em_add_int_delay_sysctl(sc, "rx_abs_int_delay", + em_add_int_delay_sysctl(adapter, "rx_int_delay", + "receive interrupt delay in usecs", &adapter->rx_int_delay, + E1000_REG_OFFSET(&adapter->hw, RDTR), em_rx_int_delay_dflt); + em_add_int_delay_sysctl(adapter, "tx_int_delay", + "transmit interrupt delay in usecs", &adapter->tx_int_delay, + E1000_REG_OFFSET(&adapter->hw, TIDV), em_tx_int_delay_dflt); + if (adapter->hw.mac_type >= em_82540) { + em_add_int_delay_sysctl(adapter, "rx_abs_int_delay", "receive interrupt delay limit in usecs", - &sc->rx_abs_int_delay, - E1000_REG_OFFSET(&sc->hw, RADV), + &adapter->rx_abs_int_delay, + E1000_REG_OFFSET(&adapter->hw, RADV), em_rx_abs_int_delay_dflt); - em_add_int_delay_sysctl(sc, "tx_abs_int_delay", + em_add_int_delay_sysctl(adapter, "tx_abs_int_delay", "transmit interrupt delay limit in usecs", - &sc->tx_abs_int_delay, - E1000_REG_OFFSET(&sc->hw, TADV), + &adapter->tx_abs_int_delay, + E1000_REG_OFFSET(&adapter->hw, TADV), em_tx_abs_int_delay_dflt); } #ifndef DEVICE_POLLING /* Sysctls for limiting the amount of work done in the taskqueue */ - em_add_int_process_limit(sc, "rx_processing_limit", - "max number of rx packets to process", &sc->rx_process_limit, + em_add_int_process_limit(adapter, "rx_processing_limit", + "max number of rx packets to process", &adapter->rx_process_limit, em_rx_process_limit); #endif /* * Validate number of transmit and receive descriptors. It * must not exceed hardware maximum, and must be multiple - * of E1000_DBA_ALIGN. + * of EM_DBA_ALIGN. */ - if (((em_txd * sizeof(struct em_tx_desc)) % E1000_DBA_ALIGN) != 0 || - (sc->hw.mac_type >= em_82544 && em_txd > EM_MAX_TXD) || - (sc->hw.mac_type < em_82544 && em_txd > EM_MAX_TXD_82543) || + if (((em_txd * sizeof(struct em_tx_desc)) % EM_DBA_ALIGN) != 0 || + (adapter->hw.mac_type >= em_82544 && em_txd > EM_MAX_TXD) || + (adapter->hw.mac_type < em_82544 && em_txd > EM_MAX_TXD_82543) || (em_txd < EM_MIN_TXD)) { device_printf(dev, "Using %d TX descriptors instead of %d!\n", EM_DEFAULT_TXD, em_txd); - sc->num_tx_desc = EM_DEFAULT_TXD; + adapter->num_tx_desc = EM_DEFAULT_TXD; } else - sc->num_tx_desc = em_txd; - if (((em_rxd * sizeof(struct em_rx_desc)) % E1000_DBA_ALIGN) != 0 || - (sc->hw.mac_type >= em_82544 && em_rxd > EM_MAX_RXD) || - (sc->hw.mac_type < em_82544 && em_rxd > EM_MAX_RXD_82543) || + adapter->num_tx_desc = em_txd; + if (((em_rxd * sizeof(struct em_rx_desc)) % EM_DBA_ALIGN) != 0 || + (adapter->hw.mac_type >= em_82544 && em_rxd > EM_MAX_RXD) || + (adapter->hw.mac_type < em_82544 && em_rxd > EM_MAX_RXD_82543) || (em_rxd < EM_MIN_RXD)) { device_printf(dev, "Using %d RX descriptors instead of %d!\n", EM_DEFAULT_RXD, em_rxd); - sc->num_rx_desc = EM_DEFAULT_RXD; + adapter->num_rx_desc = EM_DEFAULT_RXD; } else - sc->num_rx_desc = em_rxd; + adapter->num_rx_desc = em_rxd; - sc->hw.autoneg = DO_AUTO_NEG; - sc->hw.wait_autoneg_complete = WAIT_FOR_AUTO_NEG_DEFAULT; - sc->hw.autoneg_advertised = AUTONEG_ADV_DEFAULT; - sc->hw.tbi_compatibility_en = TRUE; - sc->rx_buffer_len = EM_RXBUFFER_2048; + adapter->hw.autoneg = DO_AUTO_NEG; + adapter->hw.wait_autoneg_complete = WAIT_FOR_AUTO_NEG_DEFAULT; + adapter->hw.autoneg_advertised = AUTONEG_ADV_DEFAULT; + adapter->hw.tbi_compatibility_en = TRUE; + adapter->rx_buffer_len = EM_RXBUFFER_2048; - sc->hw.phy_init_script = 1; - sc->hw.phy_reset_disable = FALSE; + adapter->hw.phy_init_script = 1; + adapter->hw.phy_reset_disable = FALSE; #ifndef EM_MASTER_SLAVE - sc->hw.master_slave = em_ms_hw_default; + adapter->hw.master_slave = em_ms_hw_default; #else - sc->hw.master_slave = EM_MASTER_SLAVE; + adapter->hw.master_slave = EM_MASTER_SLAVE; #endif /* * Set the max frame size assuming standard ethernet * sized frames. */ - sc->hw.max_frame_size = ETHERMTU + ETHER_HDR_LEN + ETHER_CRC_LEN; + adapter->hw.max_frame_size = ETHERMTU + ETHER_HDR_LEN + ETHER_CRC_LEN; - sc->hw.min_frame_size = MINIMUM_ETHERNET_PACKET_SIZE + ETHER_CRC_LEN; + adapter->hw.min_frame_size = MINIMUM_ETHERNET_PACKET_SIZE + ETHER_CRC_LEN; /* * This controls when hardware reports transmit completion * status. */ - sc->hw.report_tx_early = 1; - if (em_allocate_pci_resources(sc)) { + adapter->hw.report_tx_early = 1; + if (em_allocate_pci_resources(adapter)) { device_printf(dev, "Allocation of PCI resources failed\n"); error = ENXIO; goto err_pci; } /* Initialize eeprom parameters */ - em_init_eeprom_params(&sc->hw); + em_init_eeprom_params(&adapter->hw); - tsize = roundup2(sc->num_tx_desc * sizeof(struct em_tx_desc), - E1000_DBA_ALIGN); + tsize = roundup2(adapter->num_tx_desc * sizeof(struct em_tx_desc), + EM_DBA_ALIGN); /* Allocate Transmit Descriptor ring */ - if (em_dma_malloc(sc, tsize, &sc->txdma, BUS_DMA_NOWAIT)) { + if (em_dma_malloc(adapter, tsize, &adapter->txdma, BUS_DMA_NOWAIT)) { device_printf(dev, "Unable to allocate tx_desc memory\n"); error = ENOMEM; goto err_tx_desc; } - sc->tx_desc_base = (struct em_tx_desc *)sc->txdma.dma_vaddr; + adapter->tx_desc_base = (struct em_tx_desc *)adapter->txdma.dma_vaddr; - rsize = roundup2(sc->num_rx_desc * sizeof(struct em_rx_desc), - E1000_DBA_ALIGN); + rsize = roundup2(adapter->num_rx_desc * sizeof(struct em_rx_desc), + EM_DBA_ALIGN); /* Allocate Receive Descriptor ring */ - if (em_dma_malloc(sc, rsize, &sc->rxdma, BUS_DMA_NOWAIT)) { + if (em_dma_malloc(adapter, rsize, &adapter->rxdma, BUS_DMA_NOWAIT)) { device_printf(dev, "Unable to allocate rx_desc memory\n"); error = ENOMEM; goto err_rx_desc; } - sc->rx_desc_base = (struct em_rx_desc *)sc->rxdma.dma_vaddr; + adapter->rx_desc_base = (struct em_rx_desc *)adapter->rxdma.dma_vaddr; /* Initialize the hardware */ - if (em_hardware_init(sc)) { + if (em_hardware_init(adapter)) { device_printf(dev, "Unable to initialize the hardware\n"); error = EIO; goto err_hw_init; } /* Copy the permanent MAC address out of the EEPROM */ - if (em_read_mac_addr(&sc->hw) < 0) { + if (em_read_mac_addr(&adapter->hw) < 0) { device_printf(dev, "EEPROM read error while reading MAC" " address\n"); error = EIO; goto err_hw_init; } - if (!em_is_valid_ether_addr(sc->hw.mac_addr)) { + if (!em_is_valid_ether_addr(adapter->hw.mac_addr)) { device_printf(dev, "Invalid MAC address\n"); error = EIO; goto err_hw_init; } + /* Allocate transmit descriptors and buffers */ + if (em_allocate_transmit_structures(adapter)) { + device_printf(dev, "Could not setup transmit structures\n"); + error = ENOMEM; + goto err_tx_struct; + } + + /* Allocate receive descriptors and buffers */ + if (em_allocate_receive_structures(adapter)) { + device_printf(dev, "Could not setup receive structures\n"); + error = ENOMEM; + goto err_rx_struct; + } + /* Setup OS specific network interface */ - em_setup_interface(dev, sc); + em_setup_interface(dev, adapter); - em_allocate_intr(sc); + em_allocate_intr(adapter); /* Initialize statistics */ - em_clear_hw_cntrs(&sc->hw); - em_update_stats_counters(sc); - sc->hw.get_link_status = 1; - em_update_link_status(sc); + em_clear_hw_cntrs(&adapter->hw); + em_update_stats_counters(adapter); + adapter->hw.get_link_status = 1; + em_update_link_status(adapter); /* Indicate SOL/IDER usage */ - if (em_check_phy_reset_block(&sc->hw)) + if (em_check_phy_reset_block(&adapter->hw)) device_printf(dev, "PHY reset is blocked due to SOL/IDER session.\n"); /* Identify 82544 on PCIX */ - em_get_bus_info(&sc->hw); - if(sc->hw.bus_type == em_bus_type_pcix && sc->hw.mac_type == em_82544) - sc->pcix_82544 = TRUE; + em_get_bus_info(&adapter->hw); + if(adapter->hw.bus_type == em_bus_type_pcix && adapter->hw.mac_type == em_82544) + adapter->pcix_82544 = TRUE; else - sc->pcix_82544 = FALSE; + adapter->pcix_82544 = FALSE; INIT_DEBUGOUT("em_attach: end"); return (0); +err_rx_struct: + em_free_transmit_structures(adapter); +err_tx_struct: err_hw_init: - em_dma_free(sc, &sc->rxdma); + em_dma_free(adapter, &adapter->rxdma); err_rx_desc: - em_dma_free(sc, &sc->txdma); + em_dma_free(adapter, &adapter->txdma); err_tx_desc: err_pci: - em_free_intr(sc); - em_free_pci_resources(sc); - EM_LOCK_DESTROY(sc); + em_free_intr(adapter); + em_free_pci_resources(adapter); + EM_LOCK_DESTROY(adapter); return (error); } @@ -589,8 +626,8 @@ static int em_detach(device_t dev) { - struct em_softc *sc = device_get_softc(dev); - struct ifnet *ifp = sc->ifp; + struct adapter *adapter = device_get_softc(dev); + struct ifnet *ifp = adapter->ifp; INIT_DEBUGOUT("em_detach: begin"); @@ -599,31 +636,37 @@ ether_poll_deregister(ifp); #endif - em_free_intr(sc); - EM_LOCK(sc); - sc->in_detach = 1; - em_stop(sc); - em_phy_hw_reset(&sc->hw); - EM_UNLOCK(sc); - ether_ifdetach(sc->ifp); + em_free_intr(adapter); + EM_LOCK(adapter); + adapter->in_detach = 1; + em_stop(adapter); + em_phy_hw_reset(&adapter->hw); + EM_UNLOCK(adapter); + ether_ifdetach(adapter->ifp); + + callout_drain(&adapter->timer); + callout_drain(&adapter->tx_fifo_timer); - em_free_pci_resources(sc); + em_free_pci_resources(adapter); bus_generic_detach(dev); if_free(ifp); + em_free_transmit_structures(adapter); + em_free_receive_structures(adapter); + /* Free Transmit Descriptor ring */ - if (sc->tx_desc_base) { - em_dma_free(sc, &sc->txdma); - sc->tx_desc_base = NULL; + if (adapter->tx_desc_base) { + em_dma_free(adapter, &adapter->txdma); + adapter->tx_desc_base = NULL; } /* Free Receive Descriptor ring */ - if (sc->rx_desc_base) { - em_dma_free(sc, &sc->rxdma); - sc->rx_desc_base = NULL; + if (adapter->rx_desc_base) { + em_dma_free(adapter, &adapter->rxdma); + adapter->rx_desc_base = NULL; } - EM_LOCK_DESTROY(sc); + EM_LOCK_DESTROY(adapter); return (0); } @@ -637,10 +680,10 @@ static int em_shutdown(device_t dev) { - struct em_softc *sc = device_get_softc(dev); - EM_LOCK(sc); - em_stop(sc); - EM_UNLOCK(sc); + struct adapter *adapter = device_get_softc(dev); + EM_LOCK(adapter); + em_stop(adapter); + EM_UNLOCK(adapter); return (0); } @@ -650,11 +693,11 @@ static int em_suspend(device_t dev) { - struct em_softc *sc = device_get_softc(dev); + struct adapter *adapter = device_get_softc(dev); - EM_LOCK(sc); - em_stop(sc); - EM_UNLOCK(sc); + EM_LOCK(adapter); + em_stop(adapter); + EM_UNLOCK(adapter); return bus_generic_suspend(dev); } @@ -662,15 +705,15 @@ static int em_resume(device_t dev) { - struct em_softc *sc = device_get_softc(dev); - struct ifnet *ifp = sc->ifp; + struct adapter *adapter = device_get_softc(dev); + struct ifnet *ifp = adapter->ifp; - EM_LOCK(sc); - em_init_locked(sc); + EM_LOCK(adapter); + em_init_locked(adapter); if ((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING)) em_start_locked(ifp); - EM_UNLOCK(sc); + EM_UNLOCK(adapter); return bus_generic_resume(dev); } @@ -689,15 +732,15 @@ static void em_start_locked(struct ifnet *ifp) { - struct em_softc *sc = ifp->if_softc; + struct adapter *adapter = ifp->if_softc; struct mbuf *m_head; - EM_LOCK_ASSERT(sc); + EM_LOCK_ASSERT(adapter); if ((ifp->if_drv_flags & (IFF_DRV_RUNNING|IFF_DRV_OACTIVE)) != IFF_DRV_RUNNING) return; - if (!sc->link_active) + if (!adapter->link_active) return; while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) { @@ -709,7 +752,7 @@ * em_encap() can modify our pointer, and or make it NULL on * failure. In that event, we can't requeue. */ - if (em_encap(sc, &m_head)) { + if (em_encap(adapter, &m_head)) { if (m_head == NULL) break; ifp->if_drv_flags |= IFF_DRV_OACTIVE; @@ -728,12 +771,12 @@ static void em_start(struct ifnet *ifp) { - struct em_softc *sc = ifp->if_softc; + struct adapter *adapter = ifp->if_softc; - EM_LOCK(sc); + EM_LOCK(adapter); if (ifp->if_drv_flags & IFF_DRV_RUNNING) em_start_locked(ifp); - EM_UNLOCK(sc); + EM_UNLOCK(adapter); } /********************************************************************* @@ -748,12 +791,12 @@ static int em_ioctl(struct ifnet *ifp, u_long command, caddr_t data) { - struct em_softc *sc = ifp->if_softc; + struct adapter *adapter = ifp->if_softc; struct ifreq *ifr = (struct ifreq *)data; struct ifaddr *ifa = (struct ifaddr *)data; int error = 0; - if (sc->in_detach) + if (adapter->in_detach) return (error); switch (command) { @@ -769,9 +812,9 @@ */ ifp->if_flags |= IFF_UP; if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { - EM_LOCK(sc); - em_init_locked(sc); - EM_UNLOCK(sc); + EM_LOCK(adapter); + em_init_locked(adapter); + EM_UNLOCK(adapter); } arp_ifinit(ifp, ifa); } else @@ -784,14 +827,14 @@ IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFMTU (Set Interface MTU)"); - EM_LOCK(sc); - switch (sc->hw.mac_type) { + EM_LOCK(adapter); + switch (adapter->hw.mac_type) { case em_82573: /* * 82573 only supports jumbo frames * if ASPM is disabled. */ - em_read_eeprom(&sc->hw, EEPROM_INIT_3GIO_3, 1, + em_read_eeprom(&adapter->hw, EEPROM_INIT_3GIO_3, 1, &eeprom_data); if (eeprom_data & EEPROM_WORD1A_ASPM_MASK) { max_frame_size = ETHER_MAX_LEN; @@ -803,64 +846,77 @@ case em_80003es2lan: /* Limit Jumbo Frame size */ max_frame_size = 9234; break; + case em_ich8lan: + /* ICH8 does not support jumbo frames */ + max_frame_size = ETHER_MAX_LEN; + break; default: max_frame_size = MAX_JUMBO_FRAME_SIZE; } if (ifr->ifr_mtu > max_frame_size - ETHER_HDR_LEN - ETHER_CRC_LEN) { - EM_UNLOCK(sc); + EM_UNLOCK(adapter); error = EINVAL; break; } ifp->if_mtu = ifr->ifr_mtu; - sc->hw.max_frame_size = - ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN; - em_init_locked(sc); - EM_UNLOCK(sc); + adapter->hw.max_frame_size = + ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN; + em_init_locked(adapter); + EM_UNLOCK(adapter); break; } case SIOCSIFFLAGS: IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFFLAGS (Set Interface Flags)"); - EM_LOCK(sc); + EM_LOCK(adapter); if (ifp->if_flags & IFF_UP) { if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) { - if ((ifp->if_flags ^ sc->if_flags) & + if ((ifp->if_flags ^ adapter->if_flags) & IFF_PROMISC) { - em_disable_promisc(sc); - em_set_promisc(sc); + em_disable_promisc(adapter); + em_set_promisc(adapter); } } else - em_init_locked(sc); + em_init_locked(adapter); } else { if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - em_stop(sc); + em_stop(adapter); } } - sc->if_flags = ifp->if_flags; - EM_UNLOCK(sc); + adapter->if_flags = ifp->if_flags; + EM_UNLOCK(adapter); break; case SIOCADDMULTI: case SIOCDELMULTI: IOCTL_DEBUGOUT("ioctl rcv'd: SIOC(ADD|DEL)MULTI"); if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - EM_LOCK(sc); - em_disable_intr(sc); - em_set_multi(sc); - if (sc->hw.mac_type == em_82542_rev2_0) { - em_initialize_receive_unit(sc); + EM_LOCK(adapter); + em_disable_intr(adapter); + em_set_multi(adapter); + if (adapter->hw.mac_type == em_82542_rev2_0) { + em_initialize_receive_unit(adapter); } #ifdef DEVICE_POLLING if (!(ifp->if_capenable & IFCAP_POLLING)) #endif - em_enable_intr(sc); - EM_UNLOCK(sc); + em_enable_intr(adapter); + EM_UNLOCK(adapter); } break; case SIOCSIFMEDIA: + /* Check SOL/IDER usage */ + EM_LOCK(adapter); + if (em_check_phy_reset_block(&adapter->hw)) { + EM_UNLOCK(adapter); + device_printf(adapter->dev, "Media change is" + "blocked due to SOL/IDER session.\n"); + break; + } + EM_UNLOCK(adapter); case SIOCGIFMEDIA: IOCTL_DEBUGOUT("ioctl rcv'd: SIOCxIFMEDIA (Get/Set Interface Media)"); - error = ifmedia_ioctl(ifp, ifr, &sc->media, command); + error = ifmedia_ioctl(ifp, ifr, &adapter->media, command); break; case SIOCSIFCAP: { @@ -875,17 +931,17 @@ error = ether_poll_register(em_poll, ifp); if (error) return (error); - EM_LOCK(sc); - em_disable_intr(sc); + EM_LOCK(adapter); + em_disable_intr(adapter); ifp->if_capenable |= IFCAP_POLLING; - EM_UNLOCK(sc); + EM_UNLOCK(adapter); } else { error = ether_poll_deregister(ifp); /* Enable interrupt even in error case */ - EM_LOCK(sc); - em_enable_intr(sc); + EM_LOCK(adapter); + em_enable_intr(adapter); ifp->if_capenable &= ~IFCAP_POLLING; - EM_UNLOCK(sc); + EM_UNLOCK(adapter); } } #endif @@ -893,12 +949,16 @@ ifp->if_capenable ^= IFCAP_HWCSUM; reinit = 1; } + if (mask & IFCAP_TSO4) { + ifp->if_capenable ^= IFCAP_TSO4; + reinit = 1; + } if (mask & IFCAP_VLAN_HWTAGGING) { ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; reinit = 1; } if (reinit && (ifp->if_drv_flags & IFF_DRV_RUNNING)) - em_init(sc); + em_init(adapter); VLAN_CAPABILITIES(ifp); break; } @@ -920,26 +980,38 @@ static void em_watchdog(struct ifnet *ifp) { - struct em_softc *sc = ifp->if_softc; + struct adapter *adapter = ifp->if_softc; - EM_LOCK(sc); + EM_LOCK(adapter); /* If we are in this routine because of pause frames, then * don't reset the hardware. */ - if (E1000_READ_REG(&sc->hw, STATUS) & E1000_STATUS_TXOFF) { + if (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_TXOFF) { ifp->if_timer = EM_TX_TIMEOUT; - EM_UNLOCK(sc); + EM_UNLOCK(adapter); + return; + } + + /* + * Reclaim first as there is a possibility of losing Tx completion + * interrupts. Possible cause of missing Tx completion interrupts + * comes from Tx interrupt moderation mechanism(delayed interrupts) + * or chipset bug. + */ + em_txeof(adapter); + if (adapter->num_tx_desc_avail == adapter->num_tx_desc) { + EM_UNLOCK(adapter); return; } - if (em_check_for_link(&sc->hw) == 0) - device_printf(sc->dev, "watchdog timeout -- resetting\n"); + if (em_check_for_link(&adapter->hw) == 0) + device_printf(adapter->dev, "watchdog timeout -- resetting\n"); ifp->if_drv_flags &= ~IFF_DRV_RUNNING; - sc->watchdog_events++; + adapter->watchdog_events++; - em_init_locked(sc); - EM_UNLOCK(sc); + em_init_locked(adapter); + EM_UNLOCK(adapter); } /********************************************************************* @@ -954,33 +1026,39 @@ **********************************************************************/ static void -em_init_locked(struct em_softc *sc) +em_init_locked(struct adapter *adapter) { - struct ifnet *ifp = sc->ifp; - device_t dev = sc->dev; + struct ifnet *ifp = adapter->ifp; + device_t dev = adapter->dev; uint32_t pba; INIT_DEBUGOUT("em_init: begin"); - EM_LOCK_ASSERT(sc); + EM_LOCK_ASSERT(adapter); - em_stop(sc); + em_stop(adapter); /* * Packet Buffer Allocation (PBA) * Writing PBA sets the receive portion of the buffer * the remainder is used for the transmit buffer. + * + * Devices before the 82547 had a Packet Buffer of 64K. + * Default allocation: PBA=48K for Rx, leaving 16K for Tx. + * After the 82547 the buffer was reduced to 40K. + * Default allocation: PBA=30K for Rx, leaving 10K for Tx. + * Note: default does not leave enough room for Jumbo Frame >10k. */ - switch (sc->hw.mac_type) { + switch (adapter->hw.mac_type) { case em_82547: case em_82547_rev_2: /* 82547: Total Packet Buffer is 40K */ - if (sc->hw.max_frame_size > EM_RXBUFFER_8192) + if (adapter->hw.max_frame_size > EM_RXBUFFER_8192) pba = E1000_PBA_22K; /* 22K for Rx, 18K for Tx */ else pba = E1000_PBA_30K; /* 30K for Rx, 10K for Tx */ - sc->tx_fifo_head = 0; - sc->tx_head_addr = pba << EM_TX_HEAD_ADDR_SHIFT; - sc->tx_fifo_size = (E1000_PBA_40K - pba) << EM_PBA_BYTES_SHIFT; + adapter->tx_fifo_head = 0; + adapter->tx_head_addr = pba << EM_TX_HEAD_ADDR_SHIFT; + adapter->tx_fifo_size = (E1000_PBA_40K - pba) << EM_PBA_BYTES_SHIFT; break; case em_80003es2lan: /* 80003es2lan: Total Packet Buffer is 48K */ case em_82571: /* 82571: Total Packet Buffer is 48K */ @@ -991,150 +1069,154 @@ /* Jumbo frames not supported */ pba = E1000_PBA_12K; /* 12K for Rx, 20K for Tx */ break; + case em_ich8lan: + pba = E1000_PBA_8K; + break; default: /* Devices before 82547 had a Packet Buffer of 64K. */ - if(sc->hw.max_frame_size > EM_RXBUFFER_8192) + if(adapter->hw.max_frame_size > EM_RXBUFFER_8192) pba = E1000_PBA_40K; /* 40K for Rx, 24K for Tx */ else pba = E1000_PBA_48K; /* 48K for Rx, 16K for Tx */ } INIT_DEBUGOUT1("em_init: pba=%dK",pba); >>> TRUNCATED FOR MAIL (1000 lines) <<<