if_em.c revision 121816
184865Sobrien/**************************************************************************
2218822Sdim
384865SobrienCopyright (c) 2001-2003, Intel Corporation
4218822SdimAll rights reserved.
584865Sobrien
684865SobrienRedistribution and use in source and binary forms, with or without
784865Sobrienmodification, are permitted provided that the following conditions are met:
884865Sobrien
984865Sobrien 1. Redistributions of source code must retain the above copyright notice,
1084865Sobrien    this list of conditions and the following disclaimer.
1184865Sobrien
1284865Sobrien 2. Redistributions in binary form must reproduce the above copyright
1384865Sobrien    notice, this list of conditions and the following disclaimer in the
1484865Sobrien    documentation and/or other materials provided with the distribution.
1584865Sobrien
1684865Sobrien 3. Neither the name of the Intel Corporation nor the names of its
1784865Sobrien    contributors may be used to endorse or promote products derived from
1884865Sobrien    this software without specific prior written permission.
1984865Sobrien
2084865SobrienTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2184865SobrienAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22218822SdimIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2384865SobrienARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24218822SdimLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2584865SobrienCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2689857SobrienSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2784865SobrienINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2884865SobrienCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2989857SobrienARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3084865SobrienPOSSIBILITY OF SUCH DAMAGE.
3184865Sobrien
3289857Sobrien***************************************************************************/
3384865Sobrien
34130561Sobrien/*$FreeBSD: head/sys/dev/em/if_em.c 121816 2003-10-31 18:32:15Z brooks $*/
35130561Sobrien
36130561Sobrien#include <dev/em/if_em.h>
37130561Sobrien
38130561Sobrien/*********************************************************************
39130561Sobrien *  Set this to one to display debug statistics
4089857Sobrien *********************************************************************/
4189857Sobrienint             em_display_debug_stats = 0;
42130561Sobrien
43130561Sobrien/*********************************************************************
44130561Sobrien *  Linked list of board private structures for all NICs found
45130561Sobrien *********************************************************************/
46130561Sobrien
47130561Sobrienstruct adapter *em_adapter_list = NULL;
48130561Sobrien
49130561Sobrien
50130561Sobrien/*********************************************************************
51130561Sobrien *  Driver version
52130561Sobrien *********************************************************************/
5389857Sobrien
54130561Sobrienchar em_driver_version[] = "1.7.16";
55130561Sobrien
56130561Sobrien
57218822Sdim/*********************************************************************
58130561Sobrien *  PCI Device ID Table
59130561Sobrien *
60130561Sobrien *  Used by probe to select devices to load on
61130561Sobrien *  Last field stores an index into em_strings
62130561Sobrien *  Last entry must be all 0s
63130561Sobrien *
64130561Sobrien *  { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index }
65130561Sobrien *********************************************************************/
66130561Sobrien
67130561Sobrienstatic em_vendor_info_t em_vendor_info_array[] =
68130561Sobrien{
69130561Sobrien        /* Intel(R) PRO/1000 Network Connection */
7089857Sobrien        { 0x8086, 0x1000, PCI_ANY_ID, PCI_ANY_ID, 0},
71104834Sobrien        { 0x8086, 0x1001, PCI_ANY_ID, PCI_ANY_ID, 0},
72130561Sobrien        { 0x8086, 0x1004, PCI_ANY_ID, PCI_ANY_ID, 0},
73130561Sobrien        { 0x8086, 0x1008, PCI_ANY_ID, PCI_ANY_ID, 0},
7489857Sobrien        { 0x8086, 0x1009, PCI_ANY_ID, PCI_ANY_ID, 0},
7589857Sobrien        { 0x8086, 0x100C, PCI_ANY_ID, PCI_ANY_ID, 0},
7689857Sobrien        { 0x8086, 0x100D, PCI_ANY_ID, PCI_ANY_ID, 0},
7789857Sobrien        { 0x8086, 0x100E, PCI_ANY_ID, PCI_ANY_ID, 0},
7889857Sobrien        { 0x8086, 0x100F, PCI_ANY_ID, PCI_ANY_ID, 0},
7989857Sobrien        { 0x8086, 0x1010, PCI_ANY_ID, PCI_ANY_ID, 0},
8089857Sobrien        { 0x8086, 0x1011, PCI_ANY_ID, PCI_ANY_ID, 0},
8189857Sobrien        { 0x8086, 0x1012, PCI_ANY_ID, PCI_ANY_ID, 0},
8289857Sobrien        { 0x8086, 0x1013, PCI_ANY_ID, PCI_ANY_ID, 0},
8389857Sobrien        { 0x8086, 0x1014, PCI_ANY_ID, PCI_ANY_ID, 0},
8489857Sobrien        { 0x8086, 0x1015, PCI_ANY_ID, PCI_ANY_ID, 0},
8589857Sobrien        { 0x8086, 0x1016, PCI_ANY_ID, PCI_ANY_ID, 0},
8689857Sobrien        { 0x8086, 0x1017, PCI_ANY_ID, PCI_ANY_ID, 0},
8789857Sobrien        { 0x8086, 0x1018, PCI_ANY_ID, PCI_ANY_ID, 0},
8889857Sobrien        { 0x8086, 0x1019, PCI_ANY_ID, PCI_ANY_ID, 0},
8989857Sobrien        { 0x8086, 0x101A, PCI_ANY_ID, PCI_ANY_ID, 0},
9089857Sobrien	{ 0x8086, 0x101D, PCI_ANY_ID, PCI_ANY_ID, 0},
91104834Sobrien	{ 0x8086, 0x101E, PCI_ANY_ID, PCI_ANY_ID, 0},
9289857Sobrien	{ 0x8086, 0x1026, PCI_ANY_ID, PCI_ANY_ID, 0},
9389857Sobrien        { 0x8086, 0x1027, PCI_ANY_ID, PCI_ANY_ID, 0},
9489857Sobrien        { 0x8086, 0x1028, PCI_ANY_ID, PCI_ANY_ID, 0},
9589857Sobrien        { 0x8086, 0x1075, PCI_ANY_ID, PCI_ANY_ID, 0},
96218822Sdim        { 0x8086, 0x1076, PCI_ANY_ID, PCI_ANY_ID, 0},
9789857Sobrien        { 0x8086, 0x1077, PCI_ANY_ID, PCI_ANY_ID, 0},
98130561Sobrien        { 0x8086, 0x1078, PCI_ANY_ID, PCI_ANY_ID, 0},
99130561Sobrien        { 0x8086, 0x1079, PCI_ANY_ID, PCI_ANY_ID, 0},
100130561Sobrien        { 0x8086, 0x107A, PCI_ANY_ID, PCI_ANY_ID, 0},
101104834Sobrien        { 0x8086, 0x107B, PCI_ANY_ID, PCI_ANY_ID, 0},
102130561Sobrien        /* required last entry */
103130561Sobrien        { 0, 0, 0, 0, 0}
104130561Sobrien};
105130561Sobrien
10689857Sobrien/*********************************************************************
10789857Sobrien *  Table of branding strings for all supported NICs.
10889857Sobrien *********************************************************************/
10989857Sobrien
11089857Sobrienstatic char *em_strings[] = {
11189857Sobrien	"Intel(R) PRO/1000 Network Connection"
11289857Sobrien};
11389857Sobrien
11489857Sobrien/*********************************************************************
11589857Sobrien *  Function prototypes
11689857Sobrien *********************************************************************/
11789857Sobrienstatic int  em_probe(device_t);
11889857Sobrienstatic int  em_attach(device_t);
11989857Sobrienstatic int  em_detach(device_t);
12089857Sobrienstatic int  em_shutdown(device_t);
12189857Sobrienstatic void em_intr(void *);
12289857Sobrienstatic void em_start(struct ifnet *);
12389857Sobrienstatic int  em_ioctl(struct ifnet *, u_long, caddr_t);
12489857Sobrienstatic void em_watchdog(struct ifnet *);
12589857Sobrienstatic void em_init(void *);
126104834Sobrienstatic void em_init_locked(struct adapter *);
127104834Sobrienstatic void em_stop(void *);
128104834Sobrienstatic void em_media_status(struct ifnet *, struct ifmediareq *);
12989857Sobrienstatic int  em_media_change(struct ifnet *);
13089857Sobrienstatic void em_identify_hardware(struct adapter *);
13189857Sobrienstatic int  em_allocate_pci_resources(struct adapter *);
13284865Sobrienstatic void em_free_pci_resources(struct adapter *);
13384865Sobrienstatic void em_local_timer(void *);
134130561Sobrienstatic int  em_hardware_init(struct adapter *);
135130561Sobrienstatic void em_setup_interface(device_t, struct adapter *);
136130561Sobrienstatic int  em_setup_transmit_structures(struct adapter *);
13789857Sobrienstatic void em_initialize_transmit_unit(struct adapter *);
138130561Sobrienstatic int  em_setup_receive_structures(struct adapter *);
13989857Sobrienstatic void em_initialize_receive_unit(struct adapter *);
140130561Sobrienstatic void em_enable_intr(struct adapter *);
141130561Sobrienstatic void em_disable_intr(struct adapter *);
142130561Sobrienstatic void em_free_transmit_structures(struct adapter *);
143130561Sobrienstatic void em_free_receive_structures(struct adapter *);
14489857Sobrienstatic void em_update_stats_counters(struct adapter *);
14589857Sobrienstatic void em_clean_transmit_interrupts(struct adapter *);
14689857Sobrienstatic int  em_allocate_receive_structures(struct adapter *);
14789857Sobrienstatic int  em_allocate_transmit_structures(struct adapter *);
14889857Sobrienstatic void em_process_receive_interrupts(struct adapter *, int);
14989857Sobrienstatic void em_receive_checksum(struct adapter *,
15089857Sobrien				struct em_rx_desc *,
15189857Sobrien				struct mbuf *);
15289857Sobrienstatic void em_transmit_checksum_setup(struct adapter *,
15389857Sobrien				       struct mbuf *,
15489857Sobrien				       u_int32_t *,
15589857Sobrien				       u_int32_t *);
156130561Sobrienstatic void em_set_promisc(struct adapter *);
15789857Sobrienstatic void em_disable_promisc(struct adapter *);
15889857Sobrienstatic void em_set_multi(struct adapter *);
159130561Sobrienstatic void em_print_hw_stats(struct adapter *);
16089857Sobrienstatic void em_print_link_status(struct adapter *);
16189857Sobrienstatic int  em_get_buf(int i, struct adapter *,
16289857Sobrien		       struct mbuf *);
16389857Sobrienstatic void em_enable_vlans(struct adapter *);
164130561Sobrienstatic int  em_encap(struct adapter *, struct mbuf *);
165130561Sobrienstatic void em_smartspeed(struct adapter *);
166130561Sobrienstatic int  em_82547_fifo_workaround(struct adapter *, int);
167130561Sobrienstatic void em_82547_update_fifo_head(struct adapter *, int);
16889857Sobrienstatic int  em_82547_tx_fifo_reset(struct adapter *);
16989857Sobrienstatic void em_82547_move_tail(void *arg);
17089857Sobrienstatic void em_82547_move_tail_locked(struct adapter *);
17189857Sobrienstatic int  em_dma_malloc(struct adapter *, bus_size_t,
172130561Sobrien			  struct em_dma_alloc *, int);
173130561Sobrienstatic void em_dma_free(struct adapter *, struct em_dma_alloc *);
174130561Sobrienstatic void em_print_debug_info(struct adapter *);
175130561Sobrienstatic int  em_is_valid_ether_addr(u_int8_t *);
176130561Sobrienstatic int  em_sysctl_stats(SYSCTL_HANDLER_ARGS);
177130561Sobrienstatic int  em_sysctl_debug_info(SYSCTL_HANDLER_ARGS);
178130561Sobrienstatic u_int32_t em_fill_descriptors (u_int64_t address,
179218822Sdim				      u_int32_t length,
18084865Sobrien				      PDESC_ARRAY desc_array);
181104834Sobrienstatic int  em_sysctl_int_delay(SYSCTL_HANDLER_ARGS);
182130561Sobrienstatic void em_add_int_delay_sysctl(struct adapter *, const char *,
183130561Sobrien				    const char *, struct em_int_delay_info *,
18489857Sobrien				    int, int);
185130561Sobrien
186104834Sobrien/*********************************************************************
187130561Sobrien *  FreeBSD Device Interface Entry Points
188104834Sobrien *********************************************************************/
189130561Sobrien
190104834Sobrienstatic device_method_t em_methods[] = {
191130561Sobrien	/* Device interface */
192104834Sobrien	DEVMETHOD(device_probe, em_probe),
193104834Sobrien	DEVMETHOD(device_attach, em_attach),
194130561Sobrien	DEVMETHOD(device_detach, em_detach),
195104834Sobrien	DEVMETHOD(device_shutdown, em_shutdown),
196104834Sobrien	{0, 0}
197130561Sobrien};
198130561Sobrien
199130561Sobrienstatic driver_t em_driver = {
200130561Sobrien	"em", em_methods, sizeof(struct adapter ),
201104834Sobrien};
202130561Sobrien
203130561Sobrienstatic devclass_t em_devclass;
204130561SobrienDRIVER_MODULE(em, pci, em_driver, em_devclass, 0, 0);
205130561SobrienMODULE_DEPEND(em, pci, 1, 1, 1);
206130561SobrienMODULE_DEPEND(em, ether, 1, 1, 1);
207130561Sobrien
208130561Sobrien/*********************************************************************
209130561Sobrien *  Tunable default values.
210130561Sobrien *********************************************************************/
211130561Sobrien
212104834Sobrien#define E1000_TICKS_TO_USECS(ticks)	((1024 * (ticks) + 500) / 1000)
213130561Sobrien#define E1000_USECS_TO_TICKS(usecs)	((1000 * (usecs) + 512) / 1024)
214130561Sobrien
215130561Sobrienstatic int em_tx_int_delay_dflt = E1000_TICKS_TO_USECS(EM_TIDV);
216130561Sobrienstatic int em_rx_int_delay_dflt = E1000_TICKS_TO_USECS(EM_RDTR);
217104834Sobrienstatic int em_tx_abs_int_delay_dflt = E1000_TICKS_TO_USECS(EM_TADV);
218104834Sobrienstatic int em_rx_abs_int_delay_dflt = E1000_TICKS_TO_USECS(EM_RADV);
219130561Sobrien
220104834SobrienTUNABLE_INT("hw.em.tx_int_delay", &em_tx_int_delay_dflt);
221130561SobrienTUNABLE_INT("hw.em.rx_int_delay", &em_rx_int_delay_dflt);
222130561SobrienTUNABLE_INT("hw.em.tx_abs_int_delay", &em_tx_abs_int_delay_dflt);
223130561SobrienTUNABLE_INT("hw.em.rx_abs_int_delay", &em_rx_abs_int_delay_dflt);
224130561Sobrien
225104834Sobrien/*********************************************************************
226104834Sobrien *  Device identification routine
227130561Sobrien *
228104834Sobrien *  em_probe determines if the driver should be loaded on
229104834Sobrien *  adapter based on PCI vendor/device id of the adapter.
230104834Sobrien *
231104834Sobrien *  return 0 on success, positive on failure
232104834Sobrien *********************************************************************/
233104834Sobrien
234104834Sobrienstatic int
235104834Sobrienem_probe(device_t dev)
23684865Sobrien{
23784865Sobrien	em_vendor_info_t *ent;
23884865Sobrien
239130561Sobrien	u_int16_t       pci_vendor_id = 0;
24084865Sobrien	u_int16_t       pci_device_id = 0;
24184865Sobrien	u_int16_t       pci_subvendor_id = 0;
24284865Sobrien	u_int16_t       pci_subdevice_id = 0;
24384865Sobrien	char            adapter_name[60];
24489857Sobrien
24584865Sobrien	INIT_DEBUGOUT("em_probe: begin");
24689857Sobrien
24784865Sobrien	pci_vendor_id = pci_get_vendor(dev);
248130561Sobrien	if (pci_vendor_id != EM_VENDOR_ID)
24984865Sobrien		return(ENXIO);
25084865Sobrien
25184865Sobrien	pci_device_id = pci_get_device(dev);
25284865Sobrien	pci_subvendor_id = pci_get_subvendor(dev);
25384865Sobrien	pci_subdevice_id = pci_get_subdevice(dev);
25484865Sobrien
25584865Sobrien	ent = em_vendor_info_array;
25684865Sobrien	while (ent->vendor_id != 0) {
25784865Sobrien		if ((pci_vendor_id == ent->vendor_id) &&
25884865Sobrien		    (pci_device_id == ent->device_id) &&
25984865Sobrien
26084865Sobrien		    ((pci_subvendor_id == ent->subvendor_id) ||
26184865Sobrien		     (ent->subvendor_id == PCI_ANY_ID)) &&
26284865Sobrien
26384865Sobrien		    ((pci_subdevice_id == ent->subdevice_id) ||
26489857Sobrien		     (ent->subdevice_id == PCI_ANY_ID))) {
265104834Sobrien			sprintf(adapter_name, "%s, Version - %s",
26689857Sobrien				em_strings[ent->index],
267130561Sobrien				em_driver_version);
26884865Sobrien			device_set_desc_copy(dev, adapter_name);
26984865Sobrien			return(0);
27084865Sobrien		}
27184865Sobrien		ent++;
272130561Sobrien	}
27384865Sobrien
27484865Sobrien	return(ENXIO);
27584865Sobrien}
27684865Sobrien
27784865Sobrien/*********************************************************************
27884865Sobrien *  Device initialization routine
27984865Sobrien *
28084865Sobrien *  The attach entry point is called when the driver is being loaded.
281130561Sobrien *  This routine identifies the type of hardware, allocates all resources
28284865Sobrien *  and initializes the hardware.
28384865Sobrien *
28484865Sobrien *  return 0 on success, positive on failure
28584865Sobrien *********************************************************************/
28684865Sobrien
28784865Sobrienstatic int
28884865Sobrienem_attach(device_t dev)
28984865Sobrien{
29084865Sobrien	struct adapter * adapter;
29184865Sobrien	int             tsize, rsize;
29284865Sobrien	int		error = 0;
29384865Sobrien
29484865Sobrien	INIT_DEBUGOUT("em_attach: begin");
29584865Sobrien
29684865Sobrien	/* Allocate, clear, and link in our adapter structure */
29784865Sobrien	if (!(adapter = device_get_softc(dev))) {
29884865Sobrien		printf("em: adapter structure allocation failed\n");
29984865Sobrien		return(ENOMEM);
30084865Sobrien	}
30184865Sobrien	bzero(adapter, sizeof(struct adapter ));
30284865Sobrien	adapter->dev = dev;
30384865Sobrien	adapter->osdep.dev = dev;
30484865Sobrien	adapter->unit = device_get_unit(dev);
30584865Sobrien	EM_LOCK_INIT(adapter, device_get_nameunit(dev));
306104834Sobrien
307104834Sobrien	if (em_adapter_list != NULL)
30884865Sobrien		em_adapter_list->prev = adapter;
30984865Sobrien	adapter->next = em_adapter_list;
31084865Sobrien	em_adapter_list = adapter;
31184865Sobrien
312130561Sobrien	/* SYSCTL stuff */
31384865Sobrien        sysctl_ctx_init(&adapter->sysctl_ctx);
31484865Sobrien        adapter->sysctl_tree = SYSCTL_ADD_NODE(&adapter->sysctl_ctx,
31584865Sobrien                                               SYSCTL_STATIC_CHILDREN(_hw),
31684865Sobrien                                               OID_AUTO,
31784865Sobrien                                               device_get_nameunit(dev),
31884865Sobrien                                               CTLFLAG_RD,
31984865Sobrien                                               0, "");
320130561Sobrien        if (adapter->sysctl_tree == NULL) {
32184865Sobrien                error = EIO;
32284865Sobrien                goto err_sysctl;
32384865Sobrien        }
32484865Sobrien
325130561Sobrien        SYSCTL_ADD_PROC(&adapter->sysctl_ctx,
32684865Sobrien                        SYSCTL_CHILDREN(adapter->sysctl_tree),
32784865Sobrien                        OID_AUTO, "debug_info", CTLTYPE_INT|CTLFLAG_RW,
32884865Sobrien                        (void *)adapter, 0,
32984865Sobrien                        em_sysctl_debug_info, "I", "Debug Information");
330130561Sobrien
33184865Sobrien        SYSCTL_ADD_PROC(&adapter->sysctl_ctx,
33284865Sobrien                        SYSCTL_CHILDREN(adapter->sysctl_tree),
33384865Sobrien                        OID_AUTO, "stats", CTLTYPE_INT|CTLFLAG_RW,
33484865Sobrien                        (void *)adapter, 0,
33589857Sobrien                        em_sysctl_stats, "I", "Statistics");
33684865Sobrien
33784865Sobrien	callout_init(&adapter->timer, CALLOUT_MPSAFE);
33884865Sobrien	callout_init(&adapter->tx_fifo_timer, CALLOUT_MPSAFE);
339130561Sobrien
34084865Sobrien	/* Determine hardware revision */
34184865Sobrien	em_identify_hardware(adapter);
34284865Sobrien
34384865Sobrien	/* Set up some sysctls for the tunable interrupt delays */
34489857Sobrien	em_add_int_delay_sysctl(adapter, "rx_int_delay",
34584865Sobrien	    "receive interrupt delay in usecs", &adapter->rx_int_delay,
34684865Sobrien	    E1000_REG_OFFSET(&adapter->hw, RDTR), em_rx_int_delay_dflt);
34789857Sobrien	em_add_int_delay_sysctl(adapter, "tx_int_delay",
34889857Sobrien	    "transmit interrupt delay in usecs", &adapter->tx_int_delay,
34989857Sobrien	    E1000_REG_OFFSET(&adapter->hw, TIDV), em_tx_int_delay_dflt);
35089857Sobrien	if (adapter->hw.mac_type >= em_82540) {
35189857Sobrien		em_add_int_delay_sysctl(adapter, "rx_abs_int_delay",
35284865Sobrien		    "receive interrupt delay limit in usecs",
35384865Sobrien		    &adapter->rx_abs_int_delay,
35484865Sobrien		    E1000_REG_OFFSET(&adapter->hw, RADV),
35584865Sobrien		    em_rx_abs_int_delay_dflt);
356130561Sobrien		em_add_int_delay_sysctl(adapter, "tx_abs_int_delay",
357130561Sobrien		    "transmit interrupt delay limit in usecs",
358130561Sobrien		    &adapter->tx_abs_int_delay,
35984865Sobrien		    E1000_REG_OFFSET(&adapter->hw, TADV),
36084865Sobrien		    em_tx_abs_int_delay_dflt);
36184865Sobrien	}
36284865Sobrien
36384865Sobrien	/* Parameters (to be read from user) */
36484865Sobrien        adapter->num_tx_desc = EM_MAX_TXD;
365130561Sobrien        adapter->num_rx_desc = EM_MAX_RXD;
36684865Sobrien        adapter->hw.autoneg = DO_AUTO_NEG;
36784865Sobrien        adapter->hw.wait_autoneg_complete = WAIT_FOR_AUTO_NEG_DEFAULT;
36884865Sobrien        adapter->hw.autoneg_advertised = AUTONEG_ADV_DEFAULT;
36989857Sobrien        adapter->hw.tbi_compatibility_en = TRUE;
37089857Sobrien        adapter->rx_buffer_len = EM_RXBUFFER_2048;
37184865Sobrien
37284865Sobrien	/*
37389857Sobrien         * These parameters control the automatic generation(Tx) and
37489857Sobrien         * response(Rx) to Ethernet PAUSE frames.
37589857Sobrien         */
37689857Sobrien        adapter->hw.fc_high_water = FC_DEFAULT_HI_THRESH;
37789857Sobrien        adapter->hw.fc_low_water  = FC_DEFAULT_LO_THRESH;
37884865Sobrien        adapter->hw.fc_pause_time = FC_DEFAULT_TX_TIMER;
37984865Sobrien        adapter->hw.fc_send_xon   = TRUE;
38084865Sobrien        adapter->hw.fc = em_fc_full;
38184865Sobrien
38284865Sobrien	adapter->hw.phy_init_script = 1;
383130561Sobrien	adapter->hw.phy_reset_disable = FALSE;
384130561Sobrien
385130561Sobrien#ifndef EM_MASTER_SLAVE
386130561Sobrien	adapter->hw.master_slave = em_ms_hw_default;
387130561Sobrien#else
388130561Sobrien	adapter->hw.master_slave = EM_MASTER_SLAVE;
389130561Sobrien#endif
39084865Sobrien	/*
39189857Sobrien	 * Set the max frame size assuming standard ethernet
39284865Sobrien	 * sized frames
39384865Sobrien	 */
39489857Sobrien	adapter->hw.max_frame_size =
39589857Sobrien		ETHERMTU + ETHER_HDR_LEN + ETHER_CRC_LEN;
39684865Sobrien
39789857Sobrien	adapter->hw.min_frame_size =
39889857Sobrien		MINIMUM_ETHERNET_PACKET_SIZE + ETHER_CRC_LEN;
39984865Sobrien
40084865Sobrien	/*
40189857Sobrien	 * This controls when hardware reports transmit completion
40289857Sobrien	 * status.
40389857Sobrien	 */
40489857Sobrien	adapter->hw.report_tx_early = 1;
40589857Sobrien
40689857Sobrien
40789857Sobrien	if (em_allocate_pci_resources(adapter)) {
40889857Sobrien		printf("em%d: Allocation of PCI resources failed\n",
40989857Sobrien		       adapter->unit);
41089857Sobrien                error = ENXIO;
41189857Sobrien                goto err_pci;
41289857Sobrien	}
41389857Sobrien
41489857Sobrien
41589857Sobrien	/* Initialize eeprom parameters */
41684865Sobrien        em_init_eeprom_params(&adapter->hw);
41784865Sobrien
41884865Sobrien	tsize = EM_ROUNDUP(adapter->num_tx_desc *
41984865Sobrien			   sizeof(struct em_tx_desc), 4096);
42084865Sobrien
42184865Sobrien	/* Allocate Transmit Descriptor ring */
42284865Sobrien        if (em_dma_malloc(adapter, tsize, &adapter->txdma, BUS_DMA_NOWAIT)) {
42389857Sobrien                printf("em%d: Unable to allocate tx_desc memory\n",
42489857Sobrien                       adapter->unit);
42589857Sobrien		error = ENOMEM;
42684865Sobrien                goto err_tx_desc;
42784865Sobrien        }
42884865Sobrien        adapter->tx_desc_base = (struct em_tx_desc *) adapter->txdma.dma_vaddr;
42989857Sobrien
43089857Sobrien	rsize = EM_ROUNDUP(adapter->num_rx_desc *
43189857Sobrien			   sizeof(struct em_rx_desc), 4096);
43289857Sobrien
43384865Sobrien	/* Allocate Receive Descriptor ring */
43484865Sobrien        if (em_dma_malloc(adapter, rsize, &adapter->rxdma, BUS_DMA_NOWAIT)) {
43584865Sobrien                printf("em%d: Unable to allocate rx_desc memory\n",
43684865Sobrien                        adapter->unit);
43784865Sobrien		error = ENOMEM;
43884865Sobrien                goto err_rx_desc;
43984865Sobrien        }
44089857Sobrien        adapter->rx_desc_base = (struct em_rx_desc *) adapter->rxdma.dma_vaddr;
44189857Sobrien
44289857Sobrien	/* Initialize the hardware */
44389857Sobrien	if (em_hardware_init(adapter)) {
44489857Sobrien		printf("em%d: Unable to initialize the hardware\n",
44584865Sobrien		       adapter->unit);
446130561Sobrien		error = EIO;
44784865Sobrien                goto err_hw_init;
44884865Sobrien	}
44984865Sobrien
45084865Sobrien	/* Copy the permanent MAC address out of the EEPROM */
45184865Sobrien	if (em_read_mac_addr(&adapter->hw) < 0) {
45284865Sobrien		printf("em%d: EEPROM read error while reading mac address\n",
45384865Sobrien		       adapter->unit);
45484865Sobrien		error = EIO;
45584865Sobrien                goto err_mac_addr;
45689857Sobrien	}
45789857Sobrien
45884865Sobrien	if (!em_is_valid_ether_addr(adapter->hw.mac_addr)) {
45984865Sobrien                printf("em%d: Invalid mac address\n", adapter->unit);
46084865Sobrien                error = EIO;
46189857Sobrien                goto err_mac_addr;
46289857Sobrien        }
46389857Sobrien
46489857Sobrien	bcopy(adapter->hw.mac_addr, adapter->interface_data.ac_enaddr,
46584865Sobrien	      ETHER_ADDR_LEN);
46684865Sobrien
46784865Sobrien	/* Setup OS specific network interface */
46884865Sobrien	em_setup_interface(dev, adapter);
46989857Sobrien
47084865Sobrien	/* Initialize statistics */
47189857Sobrien	em_clear_hw_cntrs(&adapter->hw);
47284865Sobrien	em_update_stats_counters(adapter);
47389857Sobrien	adapter->hw.get_link_status = 1;
47484865Sobrien	em_check_for_link(&adapter->hw);
47589857Sobrien
47684865Sobrien	/* Print the link status */
47784865Sobrien	if (adapter->link_active == 1) {
47889857Sobrien		em_get_speed_and_duplex(&adapter->hw, &adapter->link_speed,
47989857Sobrien					&adapter->link_duplex);
48089857Sobrien		printf("em%d:  Speed:%d Mbps  Duplex:%s\n",
48189857Sobrien		       adapter->unit,
48289857Sobrien		       adapter->link_speed,
48389857Sobrien		       adapter->link_duplex == FULL_DUPLEX ? "Full" : "Half");
48489857Sobrien	} else
48589857Sobrien		printf("em%d:  Speed:N/A  Duplex:N/A\n", adapter->unit);
48689857Sobrien
48789857Sobrien	/* Identify 82544 on PCIX */
48889857Sobrien        em_get_bus_info(&adapter->hw);
48989857Sobrien        if(adapter->hw.bus_type == em_bus_type_pcix &&
49089857Sobrien           adapter->hw.mac_type == em_82544) {
49189857Sobrien                adapter->pcix_82544 = TRUE;
49284865Sobrien        }
49384865Sobrien        else {
49484865Sobrien                adapter->pcix_82544 = FALSE;
49589857Sobrien        }
496130561Sobrien	INIT_DEBUGOUT("em_attach: end");
497130561Sobrien	return(0);
49889857Sobrien
49984865Sobrienerr_mac_addr:
50084865Sobrienerr_hw_init:
50189857Sobrien        em_dma_free(adapter, &adapter->rxdma);
50289857Sobrienerr_rx_desc:
50384865Sobrien        em_dma_free(adapter, &adapter->txdma);
50484865Sobrienerr_tx_desc:
50584865Sobrienerr_pci:
50684865Sobrien        em_free_pci_resources(adapter);
50789857Sobrien        sysctl_ctx_free(&adapter->sysctl_ctx);
50884865Sobrienerr_sysctl:
50984865Sobrien        return(error);
51084865Sobrien
51184865Sobrien}
512130561Sobrien
51384865Sobrien/*********************************************************************
51484865Sobrien *  Device removal routine
51589857Sobrien *
51689857Sobrien *  The detach entry point is called when the driver is being removed.
51789857Sobrien *  This routine stops the adapter and deallocates all the resources
51889857Sobrien *  that were allocated for driver operation.
51989857Sobrien *
52089857Sobrien *  return 0 on success, positive on failure
52189857Sobrien *********************************************************************/
52289857Sobrien
52389857Sobrienstatic int
52489857Sobrienem_detach(device_t dev)
52589857Sobrien{
52684865Sobrien	struct adapter * adapter = device_get_softc(dev);
52789857Sobrien	struct ifnet   *ifp = &adapter->interface_data.ac_if;
52889857Sobrien
52989857Sobrien	INIT_DEBUGOUT("em_detach: begin");
53089857Sobrien
53189857Sobrien	EM_LOCK(adapter);
53289857Sobrien	em_stop(adapter);
53389857Sobrien	em_phy_hw_reset(&adapter->hw);
53489857Sobrien	EM_UNLOCK(adapter);
53589857Sobrien#if __FreeBSD_version < 500000
53689857Sobrien        ether_ifdetach(&adapter->interface_data.ac_if, ETHER_BPF_SUPPORTED);
53789857Sobrien#else
53889857Sobrien        ether_ifdetach(&adapter->interface_data.ac_if);
53989857Sobrien#endif
54089857Sobrien	em_free_pci_resources(adapter);
54189857Sobrien
54289857Sobrien	/* Free Transmit Descriptor ring */
54389857Sobrien        if (adapter->tx_desc_base) {
54489857Sobrien                em_dma_free(adapter, &adapter->txdma);
54584865Sobrien                adapter->tx_desc_base = NULL;
54689857Sobrien        }
54789857Sobrien
54889857Sobrien        /* Free Receive Descriptor ring */
54989857Sobrien        if (adapter->rx_desc_base) {
55089857Sobrien                em_dma_free(adapter, &adapter->rxdma);
55189857Sobrien                adapter->rx_desc_base = NULL;
55289857Sobrien        }
55389857Sobrien
55489857Sobrien	/* Free the sysctl tree */
55589857Sobrien	sysctl_ctx_free(&adapter->sysctl_ctx);
55689857Sobrien
55784865Sobrien	/* Remove from the adapter list */
55884865Sobrien	if (em_adapter_list == adapter)
55989857Sobrien		em_adapter_list = adapter->next;
56089857Sobrien	if (adapter->next != NULL)
56184865Sobrien		adapter->next->prev = adapter->prev;
56284865Sobrien	if (adapter->prev != NULL)
56384865Sobrien		adapter->prev->next = adapter->next;
56489857Sobrien
56589857Sobrien	EM_LOCK_DESTROY(adapter);
56689857Sobrien
56789857Sobrien	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
56884865Sobrien	ifp->if_timer = 0;
56984865Sobrien
57084865Sobrien	return(0);
57189857Sobrien}
57289857Sobrien
57389857Sobrien/*********************************************************************
57489857Sobrien *
57589857Sobrien *  Shutdown entry point
57689857Sobrien *
57789857Sobrien **********************************************************************/
57889857Sobrien
57984865Sobrienstatic int
58084865Sobrienem_shutdown(device_t dev)
58184865Sobrien{
58289857Sobrien	struct adapter *adapter = device_get_softc(dev);
58384865Sobrien	EM_LOCK(adapter);
58484865Sobrien	em_stop(adapter);
58589857Sobrien	EM_UNLOCK(adapter);
58689857Sobrien	return(0);
58789857Sobrien}
58889857Sobrien
58984865Sobrien
59084865Sobrien/*********************************************************************
59184865Sobrien *  Transmit entry point
59284865Sobrien *
59384865Sobrien *  em_start is called by the stack to initiate a transmit.
59489857Sobrien *  The driver will remain in this routine as long as there are
59589857Sobrien *  packets to transmit and transmit resources are available.
59684865Sobrien *  In case resources are not available stack is notified and
59784865Sobrien *  the packet is requeued.
59884865Sobrien **********************************************************************/
59984865Sobrien
60084865Sobrienstatic void
60184865Sobrienem_start_locked(struct ifnet *ifp)
60284865Sobrien{
60384865Sobrien        struct mbuf    *m_head;
60484865Sobrien        struct adapter *adapter = ifp->if_softc;
60584865Sobrien
60684865Sobrien	mtx_assert(&adapter->mtx, MA_OWNED);
607130561Sobrien
608130561Sobrien        if (!adapter->link_active)
609130561Sobrien                return;
610130561Sobrien
611130561Sobrien        while (ifp->if_snd.ifq_head != NULL) {
612130561Sobrien
61384865Sobrien                IF_DEQUEUE(&ifp->if_snd, m_head);
614130561Sobrien
615130561Sobrien                if (m_head == NULL) break;
616130561Sobrien
617130561Sobrien		if (em_encap(adapter, m_head)) {
618130561Sobrien			ifp->if_flags |= IFF_OACTIVE;
619130561Sobrien			IF_PREPEND(&ifp->if_snd, m_head);
62084865Sobrien			break;
62184865Sobrien                }
622130561Sobrien
623130561Sobrien		/* Send a copy of the frame to the BPF listener */
624130561Sobrien#if __FreeBSD_version < 500000
625130561Sobrien                if (ifp->if_bpf)
626130561Sobrien                        bpf_mtap(ifp, m_head);
627130561Sobrien#else
62884865Sobrien		BPF_MTAP(ifp, m_head);
629130561Sobrien#endif
630130561Sobrien
631130561Sobrien                /* Set timeout in case hardware has problems transmitting */
632130561Sobrien                ifp->if_timer = EM_TX_TIMEOUT;
633130561Sobrien
634130561Sobrien        }
63584865Sobrien        return;
63684865Sobrien}
637130561Sobrien
638130561Sobrienstatic void
639130561Sobrienem_start(struct ifnet *ifp)
640130561Sobrien{
641130561Sobrien	struct adapter *adapter = ifp->if_softc;
642130561Sobrien
64384865Sobrien	EM_LOCK(adapter);
644130561Sobrien	em_start_locked(ifp);
645130561Sobrien	EM_UNLOCK(adapter);
646130561Sobrien	return;
647130561Sobrien}
648130561Sobrien
649130561Sobrien/*********************************************************************
65084865Sobrien *  Ioctl entry point
65184865Sobrien *
652130561Sobrien *  em_ioctl is called when the user wants to configure the
653130561Sobrien *  interface.
654130561Sobrien *
655130561Sobrien *  return 0 on success, positive on failure
656130561Sobrien **********************************************************************/
657130561Sobrien
65884865Sobrienstatic int
659130561Sobrienem_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
660130561Sobrien{
661130561Sobrien	int             mask, error = 0;
662130561Sobrien	struct ifreq   *ifr = (struct ifreq *) data;
663130561Sobrien	struct adapter * adapter = ifp->if_softc;
664130561Sobrien
66584865Sobrien	switch (command) {
66684865Sobrien	case SIOCSIFADDR:
667130561Sobrien	case SIOCGIFADDR:
668130561Sobrien		IOCTL_DEBUGOUT("ioctl rcv'd: SIOCxIFADDR (Get/Set Interface Addr)");
669130561Sobrien		ether_ioctl(ifp, command, data);
670130561Sobrien		break;
671130561Sobrien	case SIOCSIFMTU:
672130561Sobrien		IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFMTU (Set Interface MTU)");
67384865Sobrien		if (ifr->ifr_mtu > MAX_JUMBO_FRAME_SIZE - ETHER_HDR_LEN) {
674130561Sobrien			error = EINVAL;
675130561Sobrien		} else {
676130561Sobrien			EM_LOCK(adapter);
677130561Sobrien			ifp->if_mtu = ifr->ifr_mtu;
678130561Sobrien			adapter->hw.max_frame_size =
679130561Sobrien			ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN;
68084865Sobrien			em_init_locked(adapter);
68184865Sobrien			EM_UNLOCK(adapter);
682130561Sobrien		}
683130561Sobrien		break;
684104834Sobrien	case SIOCSIFFLAGS:
685130561Sobrien		IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFFLAGS (Set Interface Flags)");
686130561Sobrien		EM_LOCK(adapter);
687130561Sobrien		if (ifp->if_flags & IFF_UP) {
68884865Sobrien			if (!(ifp->if_flags & IFF_RUNNING)) {
689130561Sobrien				bcopy(IF_LLADDR(ifp), adapter->hw.mac_addr,
690130561Sobrien				      ETHER_ADDR_LEN);
691130561Sobrien				em_init_locked(adapter);
692130561Sobrien			}
693130561Sobrien
694130561Sobrien			em_disable_promisc(adapter);
69584865Sobrien			em_set_promisc(adapter);
696130561Sobrien		} else {
697130561Sobrien			if (ifp->if_flags & IFF_RUNNING) {
698130561Sobrien				em_stop(adapter);
699104834Sobrien			}
700130561Sobrien		}
701130561Sobrien		EM_UNLOCK(adapter);
702130561Sobrien		break;
70384865Sobrien	case SIOCADDMULTI:
704130561Sobrien	case SIOCDELMULTI:
705130561Sobrien		IOCTL_DEBUGOUT("ioctl rcv'd: SIOC(ADD|DEL)MULTI");
706130561Sobrien		if (ifp->if_flags & IFF_RUNNING) {
707130561Sobrien			EM_LOCK(adapter);
708130561Sobrien			em_disable_intr(adapter);
709130561Sobrien			em_set_multi(adapter);
71084865Sobrien			if (adapter->hw.mac_type == em_82542_rev2_0) {
71184865Sobrien				em_initialize_receive_unit(adapter);
71284865Sobrien			}
71384865Sobrien#ifdef DEVICE_POLLING
714130561Sobrien                        if (!(ifp->if_ipending & IFF_POLLING))
715130561Sobrien#endif
716130561Sobrien				em_enable_intr(adapter);
717130561Sobrien			EM_UNLOCK(adapter);
718130561Sobrien		}
719130561Sobrien		break;
72084865Sobrien	case SIOCSIFMEDIA:
721130561Sobrien	case SIOCGIFMEDIA:
722130561Sobrien		IOCTL_DEBUGOUT("ioctl rcv'd: SIOCxIFMEDIA (Get/Set Interface Media)");
723130561Sobrien		error = ifmedia_ioctl(ifp, ifr, &adapter->media, command);
724104834Sobrien		break;
725104834Sobrien	case SIOCSIFCAP:
726130561Sobrien		IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFCAP (Set Capabilities)");
72784865Sobrien		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
72884865Sobrien		if (mask & IFCAP_HWCSUM) {
72984865Sobrien			if (IFCAP_HWCSUM & ifp->if_capenable)
73084865Sobrien				ifp->if_capenable &= ~IFCAP_HWCSUM;
731130561Sobrien			else
732130561Sobrien				ifp->if_capenable |= IFCAP_HWCSUM;
733130561Sobrien			if (ifp->if_flags & IFF_RUNNING)
734130561Sobrien				em_init(adapter);
735130561Sobrien		}
736130561Sobrien		break;
73784865Sobrien	default:
738130561Sobrien		IOCTL_DEBUGOUT1("ioctl received: UNKNOWN (0x%x)\n", (int)command);
739130561Sobrien		error = EINVAL;
740130561Sobrien	}
741130561Sobrien
742130561Sobrien	return(error);
743130561Sobrien}
74484865Sobrien
74584865Sobrien/*********************************************************************
74684865Sobrien *  Watchdog entry point
74784865Sobrien *
748130561Sobrien *  This routine is called whenever hardware quits transmitting.
749130561Sobrien *
750104834Sobrien **********************************************************************/
751130561Sobrien
752130561Sobrienstatic void
753130561Sobrienem_watchdog(struct ifnet *ifp)
75484865Sobrien{
755130561Sobrien	struct adapter * adapter;
756130561Sobrien	adapter = ifp->if_softc;
757130561Sobrien
758130561Sobrien	/* If we are in this routine because of pause frames, then
759130561Sobrien	 * don't reset the hardware.
760130561Sobrien	 */
76184865Sobrien	if (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_TXOFF) {
76284865Sobrien		ifp->if_timer = EM_TX_TIMEOUT;
763130561Sobrien		return;
764130561Sobrien	}
765104834Sobrien
766130561Sobrien	printf("em%d: watchdog timeout -- resetting\n", adapter->unit);
767130561Sobrien
768130561Sobrien	ifp->if_flags &= ~IFF_RUNNING;
76984865Sobrien
770130561Sobrien	em_stop(adapter);
771130561Sobrien	em_init(adapter);
772130561Sobrien
773130561Sobrien	ifp->if_oerrors++;
774130561Sobrien	return;
775130561Sobrien}
77684865Sobrien
77784865Sobrien/*********************************************************************
77884865Sobrien *  Init entry point
77984865Sobrien *
780130561Sobrien *  This routine is used in two ways. It is used by the stack as
781130561Sobrien *  init entry point in network interface structure. It is also used
782130561Sobrien *  by the driver as a hw/sw initialization routine to get to a
783130561Sobrien *  consistent state.
784130561Sobrien *
785130561Sobrien *  return 0 on success, positive on failure
786104834Sobrien **********************************************************************/
787130561Sobrien
788130561Sobrienstatic void
789130561Sobrienem_init_locked(struct adapter * adapter)
790130561Sobrien{
791130561Sobrien	struct ifnet   *ifp;
792130561Sobrien
79384865Sobrien	INIT_DEBUGOUT("em_init: begin");
79484865Sobrien
79584865Sobrien	mtx_assert(&adapter->mtx, MA_OWNED);
79684865Sobrien
79784865Sobrien	em_stop(adapter);
798130561Sobrien
799130561Sobrien	/* Initialize the hardware */
800104834Sobrien	if (em_hardware_init(adapter)) {
801130561Sobrien		printf("em%d: Unable to initialize the hardware\n",
802130561Sobrien		       adapter->unit);
803130561Sobrien		return;
80484865Sobrien	}
805130561Sobrien
806130561Sobrien	em_enable_vlans(adapter);
807130561Sobrien
808130561Sobrien	/* Prepare transmit descriptors and buffers */
809130561Sobrien	if (em_setup_transmit_structures(adapter)) {
810130561Sobrien		printf("em%d: Could not setup transmit structures\n",
81184865Sobrien		       adapter->unit);
81284865Sobrien		em_stop(adapter);
813130561Sobrien		return;
814130561Sobrien	}
815104834Sobrien	em_initialize_transmit_unit(adapter);
816130561Sobrien
817130561Sobrien	/* Setup Multicast table */
818130561Sobrien	em_set_multi(adapter);
81984865Sobrien
820130561Sobrien	/* Prepare receive descriptors and buffers */
821130561Sobrien	if (em_setup_receive_structures(adapter)) {
822130561Sobrien		printf("em%d: Could not setup receive structures\n",
823130561Sobrien		       adapter->unit);
824130561Sobrien		em_stop(adapter);
825130561Sobrien		return;
82684865Sobrien	}
82784865Sobrien	em_initialize_receive_unit(adapter);
828130561Sobrien
829130561Sobrien	ifp = &adapter->interface_data.ac_if;
830130561Sobrien	ifp->if_flags |= IFF_RUNNING;
831130561Sobrien	ifp->if_flags &= ~IFF_OACTIVE;
832130561Sobrien
833130561Sobrien	if (adapter->hw.mac_type >= em_82543) {
83484865Sobrien		if (ifp->if_capenable & IFCAP_TXCSUM)
835130561Sobrien			ifp->if_hwassist = EM_CHECKSUM_FEATURES;
836130561Sobrien		else
837130561Sobrien			ifp->if_hwassist = 0;
838130561Sobrien	}
839130561Sobrien
840130561Sobrien	callout_reset(&adapter->timer, 2*hz, em_local_timer, adapter);
84184865Sobrien	em_clear_hw_cntrs(&adapter->hw);
84284865Sobrien#ifdef DEVICE_POLLING
843130561Sobrien        /*
844130561Sobrien         * Only enable interrupts if we are not polling, make sure
845130561Sobrien         * they are off otherwise.
846130561Sobrien         */
847130561Sobrien        if (ifp->if_ipending & IFF_POLLING)
848130561Sobrien                em_disable_intr(adapter);
84984865Sobrien        else
850130561Sobrien#endif /* DEVICE_POLLING */
851130561Sobrien		em_enable_intr(adapter);
852130561Sobrien
853130561Sobrien	return;
854130561Sobrien}
855130561Sobrien
85684865Sobrienstatic void
85784865Sobrienem_init(void *arg)
858130561Sobrien{
859130561Sobrien	struct adapter * adapter = arg;
860104834Sobrien
861130561Sobrien	EM_LOCK(adapter);
862130561Sobrien	em_init_locked(adapter);
863130561Sobrien	EM_UNLOCK(adapter);
86484865Sobrien	return;
865130561Sobrien}
866130561Sobrien
867130561Sobrien
868130561Sobrien#ifdef DEVICE_POLLING
869130561Sobrienstatic poll_handler_t em_poll;
870130561Sobrien
87184865Sobrienstatic void
87284865Sobrienem_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count)
873130561Sobrien{
874130561Sobrien        struct adapter *adapter = ifp->if_softc;
875104834Sobrien        u_int32_t reg_icr;
876130561Sobrien
877130561Sobrien	mtx_assert(&adapter->mtx, MA_OWNED);
878130561Sobrien
87984865Sobrien        if (cmd == POLL_DEREGISTER) {       /* final call, enable interrupts */
880130561Sobrien                em_enable_intr(adapter);
881130561Sobrien                return;
882130561Sobrien        }
883130561Sobrien        if (cmd == POLL_AND_CHECK_STATUS) {
884130561Sobrien                reg_icr = E1000_READ_REG(&adapter->hw, ICR);
885130561Sobrien                if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
88684865Sobrien			callout_stop(&adapter->timer);
88784865Sobrien                        adapter->hw.get_link_status = 1;
888130561Sobrien                        em_check_for_link(&adapter->hw);
889130561Sobrien                        em_print_link_status(adapter);
890130561Sobrien			callout_reset(&adapter->timer, 2*hz, em_local_timer, adapter);
891130561Sobrien                }
892130561Sobrien        }
893130561Sobrien        if (ifp->if_flags & IFF_RUNNING) {
89484865Sobrien                em_process_receive_interrupts(adapter, count);
895130561Sobrien                em_clean_transmit_interrupts(adapter);
896130561Sobrien        }
897130561Sobrien
898104834Sobrien        if (ifp->if_flags & IFF_RUNNING && ifp->if_snd.ifq_head != NULL)
899104834Sobrien                em_start_locked(ifp);
900130561Sobrien}
90184865Sobrien
90284865Sobrienstatic void
903130561Sobrienem_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
904130561Sobrien{
905130561Sobrien        struct adapter *adapter = ifp->if_softc;
906130561Sobrien
907130561Sobrien	EM_LOCK(adapter);
908130561Sobrien	em_poll_locked(ifp, cmd, count);
90984865Sobrien	EM_UNLOCK(adapter);
910130561Sobrien}
911130561Sobrien#endif /* DEVICE_POLLING */
912130561Sobrien
913104834Sobrien/*********************************************************************
914104834Sobrien *
915130561Sobrien *  Interrupt Service routine
91684865Sobrien *
91784865Sobrien **********************************************************************/
918130561Sobrienstatic void
919130561Sobrienem_intr(void *arg)
920130561Sobrien{
921130561Sobrien        u_int32_t       loop_cnt = EM_MAX_INTR;
922130561Sobrien        u_int32_t       reg_icr;
923130561Sobrien        struct ifnet    *ifp;
92484865Sobrien        struct adapter  *adapter = arg;
925130561Sobrien
926130561Sobrien	EM_LOCK(adapter);
927130561Sobrien
928104834Sobrien        ifp = &adapter->interface_data.ac_if;
929104834Sobrien
930130561Sobrien#ifdef DEVICE_POLLING
93184865Sobrien        if (ifp->if_ipending & IFF_POLLING) {
93284865Sobrien		EM_UNLOCK(adapter);
933130561Sobrien                return;
934130561Sobrien	}
935104834Sobrien
936130561Sobrien        if (ether_poll_register(em_poll, ifp)) {
937130561Sobrien                em_disable_intr(adapter);
938130561Sobrien                em_poll_locked(ifp, 0, 1);
93984865Sobrien		EM_UNLOCK(adapter);
940130561Sobrien                return;
941130561Sobrien        }
942130561Sobrien#endif /* DEVICE_POLLING */
943130561Sobrien
944130561Sobrien	reg_icr = E1000_READ_REG(&adapter->hw, ICR);
945130561Sobrien        if (!reg_icr) {
94689857Sobrien		EM_UNLOCK(adapter);
947104834Sobrien                return;
948130561Sobrien        }
949130561Sobrien
950130561Sobrien        /* Link status change */
951130561Sobrien        if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
952130561Sobrien		callout_stop(&adapter->timer);
953130561Sobrien                adapter->hw.get_link_status = 1;
954104834Sobrien                em_check_for_link(&adapter->hw);
955130561Sobrien                em_print_link_status(adapter);
956130561Sobrien		callout_reset(&adapter->timer, 2*hz, em_local_timer, adapter);
957130561Sobrien        }
958130561Sobrien
959130561Sobrien        while (loop_cnt > 0) {
960130561Sobrien                if (ifp->if_flags & IFF_RUNNING) {
96184865Sobrien                        em_process_receive_interrupts(adapter, -1);
962104834Sobrien                        em_clean_transmit_interrupts(adapter);
963130561Sobrien                }
964130561Sobrien                loop_cnt--;
965130561Sobrien        }
966130561Sobrien
967130561Sobrien        if (ifp->if_flags & IFF_RUNNING && ifp->if_snd.ifq_head != NULL)
968130561Sobrien                em_start_locked(ifp);
969104834Sobrien
970130561Sobrien	EM_UNLOCK(adapter);
971130561Sobrien        return;
972130561Sobrien}
973130561Sobrien
974130561Sobrien
975130561Sobrien
976104834Sobrien/*********************************************************************
977104834Sobrien *
978130561Sobrien *  Media Ioctl callback
979130561Sobrien *
980130561Sobrien *  This routine is called whenever the user queries the status of
981130561Sobrien *  the interface using ifconfig.
982130561Sobrien *
983130561Sobrien **********************************************************************/
984104834Sobrienstatic void
985130561Sobrienem_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
986130561Sobrien{
987130561Sobrien	struct adapter * adapter = ifp->if_softc;
988130561Sobrien
989130561Sobrien	INIT_DEBUGOUT("em_media_status: begin");
990130561Sobrien
991104834Sobrien	em_check_for_link(&adapter->hw);
99284865Sobrien	if (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU) {
99384865Sobrien		if (adapter->link_active == 0) {
99484865Sobrien			em_get_speed_and_duplex(&adapter->hw,
995104834Sobrien						&adapter->link_speed,
99684865Sobrien						&adapter->link_duplex);
99784865Sobrien			adapter->link_active = 1;
99884865Sobrien		}
999104834Sobrien	} else {
100089857Sobrien		if (adapter->link_active == 1) {
100184865Sobrien			adapter->link_speed = 0;
1002104834Sobrien			adapter->link_duplex = 0;
1003104834Sobrien			adapter->link_active = 0;
1004130561Sobrien		}
1005130561Sobrien	}
1006104834Sobrien
1007104834Sobrien	ifmr->ifm_status = IFM_AVALID;
1008130561Sobrien	ifmr->ifm_active = IFM_ETHER;
1009104834Sobrien
1010130561Sobrien	if (!adapter->link_active)
1011104834Sobrien		return;
1012130561Sobrien
1013104834Sobrien	ifmr->ifm_status |= IFM_ACTIVE;
1014104834Sobrien
1015130561Sobrien	if (adapter->hw.media_type == em_media_type_fiber) {
101684865Sobrien		ifmr->ifm_active |= IFM_1000_SX | IFM_FDX;
101784865Sobrien	} else {
101884865Sobrien		switch (adapter->link_speed) {
101984865Sobrien		case 10:
102084865Sobrien			ifmr->ifm_active |= IFM_10_T;
102184865Sobrien			break;
102284865Sobrien		case 100:
1023104834Sobrien			ifmr->ifm_active |= IFM_100_TX;
102484865Sobrien			break;
102584865Sobrien		case 1000:
102684865Sobrien#if __FreeBSD_version < 500000
102784865Sobrien			ifmr->ifm_active |= IFM_1000_TX;
102884865Sobrien#else
102984865Sobrien			ifmr->ifm_active |= IFM_1000_T;
103084865Sobrien#endif
103184865Sobrien			break;
103284865Sobrien		}
103384865Sobrien		if (adapter->link_duplex == FULL_DUPLEX)
103484865Sobrien			ifmr->ifm_active |= IFM_FDX;
103584865Sobrien		else
1036104834Sobrien			ifmr->ifm_active |= IFM_HDX;
1037104834Sobrien	}
103884865Sobrien	return;
103984865Sobrien}
104084865Sobrien
104184865Sobrien/*********************************************************************
104284865Sobrien *
104384865Sobrien *  Media Ioctl callback
104484865Sobrien *
104584865Sobrien *  This routine is called when the user changes speed/duplex using
104684865Sobrien *  media/mediopt option with ifconfig.
104784865Sobrien *
104884865Sobrien **********************************************************************/
104989857Sobrienstatic int
1050218822Sdimem_media_change(struct ifnet *ifp)
1051218822Sdim{
1052218822Sdim	struct adapter * adapter = ifp->if_softc;
1053218822Sdim	struct ifmedia  *ifm = &adapter->media;
1054218822Sdim
1055218822Sdim	INIT_DEBUGOUT("em_media_change: begin");
1056218822Sdim
1057218822Sdim	if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
1058218822Sdim		return(EINVAL);
1059218822Sdim
1060218822Sdim	switch (IFM_SUBTYPE(ifm->ifm_media)) {
1061218822Sdim	case IFM_AUTO:
1062218822Sdim		adapter->hw.autoneg = DO_AUTO_NEG;
1063218822Sdim		adapter->hw.autoneg_advertised = AUTONEG_ADV_DEFAULT;
1064218822Sdim		break;
106584865Sobrien	case IFM_1000_SX:
106684865Sobrien#if __FreeBSD_version < 500000
106784865Sobrien	case IFM_1000_TX:
106884865Sobrien#else
106984865Sobrien	case IFM_1000_T:
107084865Sobrien#endif
107184865Sobrien		adapter->hw.autoneg = DO_AUTO_NEG;
107284865Sobrien		adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
107384865Sobrien		break;
107484865Sobrien	case IFM_100_TX:
107584865Sobrien		adapter->hw.autoneg = FALSE;
107684865Sobrien		adapter->hw.autoneg_advertised = 0;
107784865Sobrien		if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX)
107884865Sobrien			adapter->hw.forced_speed_duplex = em_100_full;
107984865Sobrien		else
108084865Sobrien			adapter->hw.forced_speed_duplex	= em_100_half;
108184865Sobrien		break;
108284865Sobrien	case IFM_10_T:
108384865Sobrien		adapter->hw.autoneg = FALSE;
108484865Sobrien		adapter->hw.autoneg_advertised = 0;
108584865Sobrien		if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX)
108684865Sobrien			adapter->hw.forced_speed_duplex = em_10_full;
108784865Sobrien		else
108884865Sobrien			adapter->hw.forced_speed_duplex	= em_10_half;
108984865Sobrien		break;
109084865Sobrien	default:
109184865Sobrien		printf("em%d: Unsupported media type\n", adapter->unit);
109284865Sobrien	}
109384865Sobrien
109484865Sobrien	em_init(adapter);
109584865Sobrien
109684865Sobrien	return(0);
109784865Sobrien}
109884865Sobrien
109984865Sobrienstatic void
110084865Sobrienem_tx_cb(void *arg, bus_dma_segment_t *seg, int nsegs, bus_size_t mapsize, int error)
110184865Sobrien{
110284865Sobrien        struct em_q *q = arg;
110384865Sobrien
110484865Sobrien        if (error)
110584865Sobrien                return;
110684865Sobrien        KASSERT(nsegs <= EM_MAX_SCATTER,
110784865Sobrien                ("Too many DMA segments returned when mapping tx packet"));
110884865Sobrien        q->nsegs = nsegs;
110984865Sobrien        bcopy(seg, q->segs, nsegs * sizeof(seg[0]));
111084865Sobrien}
1111104834Sobrien
111284865Sobrien#define EM_FIFO_HDR              0x10
1113130561Sobrien#define EM_82547_PKT_THRESH      0x3e0
1114104834Sobrien#define EM_82547_TX_FIFO_SIZE    0x2800
1115104834Sobrien#define EM_82547_TX_FIFO_BEGIN   0xf00
1116104834Sobrien/*********************************************************************
1117104834Sobrien *
1118104834Sobrien *  This routine maps the mbufs to tx descriptors.
1119130561Sobrien *
1120104834Sobrien *  return 0 on success, positive on failure
1121104834Sobrien **********************************************************************/
112284865Sobrienstatic int
112384865Sobrienem_encap(struct adapter *adapter, struct mbuf *m_head)
112484865Sobrien{
1125130561Sobrien        u_int32_t       txd_upper;
112684865Sobrien        u_int32_t       txd_lower, txd_used = 0, txd_saved = 0;
112784865Sobrien        int             i, j, error;
112884865Sobrien        u_int64_t       address;
112984865Sobrien
113084865Sobrien	/* For 82544 Workaround */
113184865Sobrien	DESC_ARRAY              desc_array;
113284865Sobrien	u_int32_t               array_elements;
113384865Sobrien	u_int32_t               counter;
113484865Sobrien
113584865Sobrien#if __FreeBSD_version < 500000
113684865Sobrien        struct ifvlan *ifv = NULL;
113784865Sobrien#else
113884865Sobrien        struct m_tag    *mtag;
1139130561Sobrien#endif
1140130561Sobrien        struct em_q      q;
114184865Sobrien        struct em_buffer   *tx_buffer = NULL;
114284865Sobrien        struct em_tx_desc *current_tx_desc = NULL;
114384865Sobrien        struct ifnet   *ifp = &adapter->interface_data.ac_if;
114484865Sobrien
114584865Sobrien        /*
114684865Sobrien         * Force a cleanup if number of TX descriptors
114784865Sobrien         * available hits the threshold
114884865Sobrien         */
114984865Sobrien        if (adapter->num_tx_desc_avail <= EM_TX_CLEANUP_THRESHOLD) {
115084865Sobrien                em_clean_transmit_interrupts(adapter);
1151130561Sobrien                if (adapter->num_tx_desc_avail <= EM_TX_CLEANUP_THRESHOLD) {
1152130561Sobrien                        adapter->no_tx_desc_avail1++;
115384865Sobrien                        return(ENOBUFS);
115484865Sobrien                }
115584865Sobrien        }
1156130561Sobrien
115784865Sobrien        /*
115884865Sobrien         * Map the packet for DMA.
115989857Sobrien         */
116089857Sobrien        if (bus_dmamap_create(adapter->txtag, BUS_DMA_NOWAIT, &q.map)) {
1161130561Sobrien                adapter->no_tx_map_avail++;
116284865Sobrien                return (ENOMEM);
116384865Sobrien        }
116484865Sobrien        error = bus_dmamap_load_mbuf(adapter->txtag, q.map,
116589857Sobrien                                     m_head, em_tx_cb, &q, BUS_DMA_NOWAIT);
116689857Sobrien        if (error != 0) {
1167130561Sobrien                adapter->no_tx_dma_setup++;
116884865Sobrien                bus_dmamap_destroy(adapter->txtag, q.map);
116984865Sobrien                return (error);
117084865Sobrien        }
117184865Sobrien        KASSERT(q.nsegs != 0, ("em_encap: empty packet"));
117284865Sobrien
117384865Sobrien        if (q.nsegs > adapter->num_tx_desc_avail) {
1174130561Sobrien                adapter->no_tx_desc_avail2++;
117589857Sobrien                bus_dmamap_destroy(adapter->txtag, q.map);
1176130561Sobrien                return (ENOBUFS);
117784865Sobrien        }
117884865Sobrien
117989857Sobrien
118084865Sobrien        if (ifp->if_hwassist > 0) {
118184865Sobrien                em_transmit_checksum_setup(adapter,  m_head,
118284865Sobrien                                           &txd_upper, &txd_lower);
118384865Sobrien        } else
1184130561Sobrien                txd_upper = txd_lower = 0;
118584865Sobrien
118684865Sobrien
118789857Sobrien        /* Find out if we are in vlan mode */
118889857Sobrien#if __FreeBSD_version < 500000
118984865Sobrien        if ((m_head->m_flags & (M_PROTO1|M_PKTHDR)) == (M_PROTO1|M_PKTHDR) &&
1190130561Sobrien            m_head->m_pkthdr.rcvif != NULL &&
119184865Sobrien            m_head->m_pkthdr.rcvif->if_type == IFT_L2VLAN)
119284865Sobrien                ifv = m_head->m_pkthdr.rcvif->if_softc;
119384865Sobrien#else
119484865Sobrien        mtag = VLAN_OUTPUT_TAG(ifp, m_head);
119584865Sobrien#endif
119689857Sobrien
119784865Sobrien        i = adapter->next_avail_tx_desc;
119884865Sobrien	if (adapter->pcix_82544) {
119984865Sobrien		txd_saved = i;
120084865Sobrien		txd_used = 0;
120184865Sobrien	}
120284865Sobrien        for (j = 0; j < q.nsegs; j++) {
120384865Sobrien		/* If adapter is 82544 and on PCIX bus */
120484865Sobrien		if(adapter->pcix_82544) {
120584865Sobrien			array_elements = 0;
1206130561Sobrien			address = htole64(q.segs[j].ds_addr);
1207130561Sobrien			/*
120884865Sobrien			 * Check the Address and Length combination and
120984865Sobrien			 * split the data accordingly
121084865Sobrien			 */
1211130561Sobrien                        array_elements = em_fill_descriptors(address,
121284865Sobrien							     htole32(q.segs[j].ds_len),
121384865Sobrien							     &desc_array);
121489857Sobrien			for (counter = 0; counter < array_elements; counter++) {
121584865Sobrien                                if (txd_used == adapter->num_tx_desc_avail) {
1216130561Sobrien                                         adapter->next_avail_tx_desc = txd_saved;
121784865Sobrien                                          adapter->no_tx_desc_avail2++;
121884865Sobrien					  bus_dmamap_destroy(adapter->txtag, q.map);
121984865Sobrien                                          return (ENOBUFS);
122089857Sobrien                                }
122189857Sobrien                                tx_buffer = &adapter->tx_buffer_area[i];
1222130561Sobrien                                current_tx_desc = &adapter->tx_desc_base[i];
122384865Sobrien                                current_tx_desc->buffer_addr = htole64(
122484865Sobrien					desc_array.descriptor[counter].address);
122584865Sobrien                                current_tx_desc->lower.data = htole32(
122684865Sobrien					(adapter->txd_cmd | txd_lower |
122784865Sobrien					 (u_int16_t)desc_array.descriptor[counter].length));
122884865Sobrien                                current_tx_desc->upper.data = htole32((txd_upper));
122984865Sobrien                                if (++i == adapter->num_tx_desc)
123084865Sobrien                                         i = 0;
123184865Sobrien
1232130561Sobrien                                tx_buffer->m_head = NULL;
123389857Sobrien                                txd_used++;
1234130561Sobrien                        }
123584865Sobrien		} else {
123684865Sobrien			tx_buffer = &adapter->tx_buffer_area[i];
123789857Sobrien			current_tx_desc = &adapter->tx_desc_base[i];
123884865Sobrien
123984865Sobrien			current_tx_desc->buffer_addr = htole64(q.segs[j].ds_addr);
124084865Sobrien			current_tx_desc->lower.data = htole32(
124184865Sobrien				adapter->txd_cmd | txd_lower | q.segs[j].ds_len);
1242130561Sobrien			current_tx_desc->upper.data = htole32(txd_upper);
124384865Sobrien
124484865Sobrien			if (++i == adapter->num_tx_desc)
124589857Sobrien				i = 0;
124689857Sobrien
124784865Sobrien			tx_buffer->m_head = NULL;
1248130561Sobrien		}
124984865Sobrien        }
125084865Sobrien
125184865Sobrien	adapter->next_avail_tx_desc = i;
125284865Sobrien	if (adapter->pcix_82544) {
125384865Sobrien		adapter->num_tx_desc_avail -= txd_used;
125489857Sobrien	}
125584865Sobrien	else {
125684865Sobrien		adapter->num_tx_desc_avail -= q.nsegs;
125784865Sobrien	}
125884865Sobrien
125984865Sobrien#if __FreeBSD_version < 500000
126084865Sobrien        if (ifv != NULL) {
126184865Sobrien                /* Set the vlan id */
126284865Sobrien                current_tx_desc->upper.fields.special = htole16(ifv->ifv_tag);
126384865Sobrien#else
126484865Sobrien        if (mtag != NULL) {
126584865Sobrien                /* Set the vlan id */
1266130561Sobrien                current_tx_desc->upper.fields.special = htole16(VLAN_TAG_VALUE(mtag));
126784865Sobrien#endif
126884865Sobrien
126984865Sobrien                /* Tell hardware to add tag */
127084865Sobrien                current_tx_desc->lower.data |= htole32(E1000_TXD_CMD_VLE);
127184865Sobrien        }
1272130561Sobrien
127384865Sobrien        tx_buffer->m_head = m_head;
1274130561Sobrien        tx_buffer->map = q.map;
127584865Sobrien        bus_dmamap_sync(adapter->txtag, q.map, BUS_DMASYNC_PREWRITE);
127684865Sobrien
127784865Sobrien        /*
127884865Sobrien         * Last Descriptor of Packet needs End Of Packet (EOP)
127984865Sobrien         */
128084865Sobrien        current_tx_desc->lower.data |= htole32(E1000_TXD_CMD_EOP);
128184865Sobrien
128284865Sobrien        /*
1283104834Sobrien         * Advance the Transmit Descriptor Tail (Tdt), this tells the E1000
128484865Sobrien         * that this frame is available to transmit.
1285104834Sobrien         */
128684865Sobrien        if (adapter->hw.mac_type == em_82547 &&
1287104834Sobrien            adapter->link_duplex == HALF_DUPLEX) {
128884865Sobrien                em_82547_move_tail_locked(adapter);
128984865Sobrien        } else {
129084865Sobrien                E1000_WRITE_REG(&adapter->hw, TDT, i);
129184865Sobrien                if (adapter->hw.mac_type == em_82547) {
129284865Sobrien                        em_82547_update_fifo_head(adapter, m_head->m_pkthdr.len);
129384865Sobrien                }
129484865Sobrien        }
129584865Sobrien
129684865Sobrien        return(0);
129784865Sobrien}
129884865Sobrien
129984865Sobrien/*********************************************************************
130084865Sobrien *
1301104834Sobrien * 82547 workaround to avoid controller hang in half-duplex environment.
1302104834Sobrien * The workaround is to avoid queuing a large packet that would span
130389857Sobrien * the internal Tx FIFO ring boundary. We need to reset the FIFO pointers
1304104834Sobrien * in this case. We do that only when FIFO is quiescent.
130584865Sobrien *
1306104834Sobrien **********************************************************************/
130784865Sobrienstatic void
1308218822Sdimem_82547_move_tail_locked(struct adapter *adapter)
1309218822Sdim{
1310218822Sdim	uint16_t hw_tdt;
1311218822Sdim	uint16_t sw_tdt;
1312218822Sdim	struct em_tx_desc *tx_desc;
1313218822Sdim	uint16_t length = 0;
131484865Sobrien	boolean_t eop = 0;
131584865Sobrien
131684865Sobrien	EM_LOCK_ASSERT(adapter);
131784865Sobrien
131884865Sobrien	hw_tdt = E1000_READ_REG(&adapter->hw, TDT);
131984865Sobrien	sw_tdt = adapter->next_avail_tx_desc;
132084865Sobrien
132184865Sobrien	while (hw_tdt != sw_tdt) {
132284865Sobrien		tx_desc = &adapter->tx_desc_base[hw_tdt];
132384865Sobrien		length += tx_desc->lower.flags.length;
132484865Sobrien		eop = tx_desc->lower.data & E1000_TXD_CMD_EOP;
1325104834Sobrien		if(++hw_tdt == adapter->num_tx_desc)
1326104834Sobrien			hw_tdt = 0;
132784865Sobrien
132884865Sobrien		if(eop) {
132984865Sobrien			if (em_82547_fifo_workaround(adapter, length)) {
1330104834Sobrien				adapter->tx_fifo_wrk++;
133184865Sobrien				callout_reset(&adapter->tx_fifo_timer, 1,
133284865Sobrien					em_82547_move_tail, adapter);
133384865Sobrien				break;
133484865Sobrien			}
133584865Sobrien			E1000_WRITE_REG(&adapter->hw, TDT, hw_tdt);
133689857Sobrien			em_82547_update_fifo_head(adapter, length);
133789857Sobrien			length = 0;
133884865Sobrien		}
1339104834Sobrien	}
134084865Sobrien	return;
134184865Sobrien}
134284865Sobrien
134384865Sobrienstatic void
134484865Sobrienem_82547_move_tail(void *arg)
134584865Sobrien{
134684865Sobrien        struct adapter *adapter = arg;
134784865Sobrien
134884865Sobrien        EM_LOCK(adapter);
134984865Sobrien        em_82547_move_tail_locked(adapter);
135084865Sobrien        EM_UNLOCK(adapter);
135184865Sobrien}
1352104834Sobrien
1353104834Sobrienstatic int
135484865Sobrienem_82547_fifo_workaround(struct adapter *adapter, int len)
135584865Sobrien{
135684865Sobrien	int fifo_space, fifo_pkt_len;
1357104834Sobrien
135884865Sobrien	fifo_pkt_len = EM_ROUNDUP(len + EM_FIFO_HDR, EM_FIFO_HDR);
135984865Sobrien
1360104834Sobrien	if (adapter->link_duplex == HALF_DUPLEX) {
1361104834Sobrien		fifo_space = EM_82547_TX_FIFO_SIZE - adapter->tx_fifo_head;
1362104834Sobrien
136384865Sobrien		if (fifo_pkt_len >= (EM_82547_PKT_THRESH + fifo_space)) {
136489857Sobrien			if (em_82547_tx_fifo_reset(adapter)) {
136589857Sobrien				return(0);
136684865Sobrien			}
1367104834Sobrien			else {
136884865Sobrien				return(1);
136984865Sobrien			}
137084865Sobrien		}
137184865Sobrien	}
137284865Sobrien
137384865Sobrien	return(0);
1374104834Sobrien}
137584865Sobrien
1376104834Sobrienstatic void
1377104834Sobrienem_82547_update_fifo_head(struct adapter *adapter, int len)
137884865Sobrien{
137984865Sobrien	int fifo_pkt_len = EM_ROUNDUP(len + EM_FIFO_HDR, EM_FIFO_HDR);
138084865Sobrien
138184865Sobrien	/* tx_fifo_head is always 16 byte aligned */
138284865Sobrien	adapter->tx_fifo_head += fifo_pkt_len;
138384865Sobrien	if (adapter->tx_fifo_head >= EM_82547_TX_FIFO_SIZE) {
138484865Sobrien		adapter->tx_fifo_head -= EM_82547_TX_FIFO_SIZE;
138584865Sobrien	}
138684865Sobrien
138784865Sobrien	return;
138884865Sobrien}
138984865Sobrien
139089857Sobrien
139184865Sobrienstatic int
139289857Sobrienem_82547_tx_fifo_reset(struct adapter *adapter)
139384865Sobrien{
139489857Sobrien	uint32_t tctl;
139584865Sobrien
139684865Sobrien	if ( (E1000_READ_REG(&adapter->hw, TDT) ==
139784865Sobrien	      E1000_READ_REG(&adapter->hw, TDH)) &&
139884865Sobrien	     (E1000_READ_REG(&adapter->hw, TDFT) ==
139984865Sobrien	      E1000_READ_REG(&adapter->hw, TDFH)) &&
140084865Sobrien	     (E1000_READ_REG(&adapter->hw, TDFTS) ==
140184865Sobrien	      E1000_READ_REG(&adapter->hw, TDFHS)) &&
140284865Sobrien	     (E1000_READ_REG(&adapter->hw, TDFPC) == 0)) {
140389857Sobrien
140489857Sobrien		/* Disable TX unit */
140584865Sobrien		tctl = E1000_READ_REG(&adapter->hw, TCTL);
140684865Sobrien		E1000_WRITE_REG(&adapter->hw, TCTL, tctl & ~E1000_TCTL_EN);
140784865Sobrien
140884865Sobrien		/* Reset FIFO pointers */
140984865Sobrien		E1000_WRITE_REG(&adapter->hw, TDFT, EM_82547_TX_FIFO_BEGIN);
141084865Sobrien		E1000_WRITE_REG(&adapter->hw, TDFH, EM_82547_TX_FIFO_BEGIN);
141189857Sobrien		E1000_WRITE_REG(&adapter->hw, TDFTS, EM_82547_TX_FIFO_BEGIN);
141289857Sobrien		E1000_WRITE_REG(&adapter->hw, TDFHS, EM_82547_TX_FIFO_BEGIN);
141384865Sobrien
141484865Sobrien		/* Re-enable TX unit */
141584865Sobrien		E1000_WRITE_REG(&adapter->hw, TCTL, tctl);
141684865Sobrien		E1000_WRITE_FLUSH(&adapter->hw);
141784865Sobrien
141884865Sobrien		adapter->tx_fifo_head = 0;
141989857Sobrien		adapter->tx_fifo_reset++;
142084865Sobrien
142184865Sobrien		return(TRUE);
142284865Sobrien	}
142384865Sobrien	else {
142484865Sobrien		return(FALSE);
142584865Sobrien	}
142684865Sobrien}
142784865Sobrien
142884865Sobrienstatic void
142984865Sobrienem_set_promisc(struct adapter * adapter)
143084865Sobrien{
143184865Sobrien
143284865Sobrien	u_int32_t       reg_rctl;
143384865Sobrien	struct ifnet   *ifp = &adapter->interface_data.ac_if;
143484865Sobrien
143589857Sobrien	reg_rctl = E1000_READ_REG(&adapter->hw, RCTL);
143684865Sobrien
143784865Sobrien	if (ifp->if_flags & IFF_PROMISC) {
143884865Sobrien		reg_rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
143984865Sobrien		E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
144084865Sobrien	} else if (ifp->if_flags & IFF_ALLMULTI) {
144184865Sobrien		reg_rctl |= E1000_RCTL_MPE;
144284865Sobrien		reg_rctl &= ~E1000_RCTL_UPE;
144389857Sobrien		E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
144489857Sobrien	}
144584865Sobrien
144684865Sobrien	return;
144784865Sobrien}
144884865Sobrien
144984865Sobrienstatic void
145084865Sobrienem_disable_promisc(struct adapter * adapter)
145189857Sobrien{
145284865Sobrien	u_int32_t       reg_rctl;
145384865Sobrien
145484865Sobrien	reg_rctl = E1000_READ_REG(&adapter->hw, RCTL);
145584865Sobrien
145684865Sobrien	reg_rctl &=  (~E1000_RCTL_UPE);
145784865Sobrien	reg_rctl &=  (~E1000_RCTL_MPE);
145884865Sobrien	E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
145984865Sobrien
146084865Sobrien	return;
146184865Sobrien}
146284865Sobrien
146384865Sobrien
146484865Sobrien/*********************************************************************
146584865Sobrien *  Multicast Update
146684865Sobrien *
146789857Sobrien *  This routine is called whenever multicast address list is updated.
146884865Sobrien *
146984865Sobrien **********************************************************************/
147084865Sobrien
147184865Sobrienstatic void
147284865Sobrienem_set_multi(struct adapter * adapter)
147384865Sobrien{
147484865Sobrien        u_int32_t reg_rctl = 0;
147584865Sobrien        u_int8_t  mta[MAX_NUM_MULTICAST_ADDRESSES * ETH_LENGTH_OF_ADDRESS];
147684865Sobrien        struct ifmultiaddr  *ifma;
147784865Sobrien        int mcnt = 0;
147884865Sobrien        struct ifnet   *ifp = &adapter->interface_data.ac_if;
147984865Sobrien
148084865Sobrien        IOCTL_DEBUGOUT("em_set_multi: begin");
148184865Sobrien
148284865Sobrien        if (adapter->hw.mac_type == em_82542_rev2_0) {
148384865Sobrien                reg_rctl = E1000_READ_REG(&adapter->hw, RCTL);
148484865Sobrien                if (adapter->hw.pci_cmd_word & CMD_MEM_WRT_INVALIDATE) {
148584865Sobrien                        em_pci_clear_mwi(&adapter->hw);
148684865Sobrien                }
148784865Sobrien                reg_rctl |= E1000_RCTL_RST;
148884865Sobrien                E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
148984865Sobrien                msec_delay(5);
149084865Sobrien        }
149184865Sobrien
149284865Sobrien#if __FreeBSD_version < 500000
149384865Sobrien        LIST_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
149484865Sobrien#else
149584865Sobrien        TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
149684865Sobrien#endif
149784865Sobrien                if (ifma->ifma_addr->sa_family != AF_LINK)
149884865Sobrien                        continue;
149984865Sobrien
150084865Sobrien		if (mcnt == MAX_NUM_MULTICAST_ADDRESSES) break;
150184865Sobrien
150284865Sobrien                bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
150384865Sobrien                      &mta[mcnt*ETH_LENGTH_OF_ADDRESS], ETH_LENGTH_OF_ADDRESS);
150484865Sobrien                mcnt++;
150584865Sobrien        }
150684865Sobrien
150784865Sobrien        if (mcnt >= MAX_NUM_MULTICAST_ADDRESSES) {
150884865Sobrien                reg_rctl = E1000_READ_REG(&adapter->hw, RCTL);
150984865Sobrien                reg_rctl |= E1000_RCTL_MPE;
151084865Sobrien                E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
151184865Sobrien        } else
151284865Sobrien                em_mc_addr_list_update(&adapter->hw, mta, mcnt, 0);
151384865Sobrien
151484865Sobrien        if (adapter->hw.mac_type == em_82542_rev2_0) {
151584865Sobrien                reg_rctl = E1000_READ_REG(&adapter->hw, RCTL);
151684865Sobrien                reg_rctl &= ~E1000_RCTL_RST;
151784865Sobrien                E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
151884865Sobrien                msec_delay(5);
151984865Sobrien                if (adapter->hw.pci_cmd_word & CMD_MEM_WRT_INVALIDATE) {
152084865Sobrien                        em_pci_set_mwi(&adapter->hw);
152184865Sobrien                }
152284865Sobrien        }
152384865Sobrien
152484865Sobrien        return;
152584865Sobrien}
152684865Sobrien
152784865Sobrien
152884865Sobrien/*********************************************************************
152984865Sobrien *  Timer routine
153084865Sobrien *
153184865Sobrien *  This routine checks for link status and updates statistics.
153284865Sobrien *
153384865Sobrien **********************************************************************/
153484865Sobrien
153584865Sobrienstatic void
153684865Sobrienem_local_timer(void *arg)
153792828Sobrien{
153884865Sobrien	struct ifnet   *ifp;
153984865Sobrien	struct adapter * adapter = arg;
154084865Sobrien	ifp = &adapter->interface_data.ac_if;
154184865Sobrien
154284865Sobrien	EM_LOCK(adapter);
154384865Sobrien
154484865Sobrien	em_check_for_link(&adapter->hw);
154584865Sobrien	em_print_link_status(adapter);
154684865Sobrien	em_update_stats_counters(adapter);
154792828Sobrien	if (em_display_debug_stats && ifp->if_flags & IFF_RUNNING) {
154884865Sobrien		em_print_hw_stats(adapter);
154984865Sobrien	}
155084865Sobrien	em_smartspeed(adapter);
1551251227Spfg
155284865Sobrien	callout_reset(&adapter->timer, 2*hz, em_local_timer, adapter);
155384865Sobrien
155484865Sobrien	EM_UNLOCK(adapter);
155584865Sobrien	return;
155684865Sobrien}
155784865Sobrien
155884865Sobrienstatic void
155984865Sobrienem_print_link_status(struct adapter * adapter)
156084865Sobrien{
1561251227Spfg	if (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU) {
156284865Sobrien		if (adapter->link_active == 0) {
156384865Sobrien			em_get_speed_and_duplex(&adapter->hw,
156484865Sobrien						&adapter->link_speed,
156584865Sobrien						&adapter->link_duplex);
156684865Sobrien			printf("em%d: Link is up %d Mbps %s\n",
156784865Sobrien			       adapter->unit,
156884865Sobrien			       adapter->link_speed,
156984865Sobrien			       ((adapter->link_duplex == FULL_DUPLEX) ?
157084865Sobrien				"Full Duplex" : "Half Duplex"));
157184865Sobrien			adapter->link_active = 1;
157284865Sobrien			adapter->smartspeed = 0;
157384865Sobrien		}
157484865Sobrien	} else {
157584865Sobrien		if (adapter->link_active == 1) {
157684865Sobrien			adapter->link_speed = 0;
157784865Sobrien			adapter->link_duplex = 0;
157884865Sobrien			printf("em%d: Link is Down\n", adapter->unit);
157984865Sobrien			adapter->link_active = 0;
158084865Sobrien		}
158184865Sobrien	}
158284865Sobrien
158384865Sobrien	return;
158484865Sobrien}
158584865Sobrien
158684865Sobrien/*********************************************************************
158784865Sobrien *
158884865Sobrien *  This routine disables all traffic on the adapter by issuing a
158984865Sobrien *  global reset on the MAC and deallocates TX/RX buffers.
159084865Sobrien *
1591130561Sobrien **********************************************************************/
159284865Sobrien
159384865Sobrienstatic void
159484865Sobrienem_stop(void *arg)
159584865Sobrien{
159684865Sobrien	struct ifnet   *ifp;
159784865Sobrien	struct adapter * adapter = arg;
159884865Sobrien	ifp = &adapter->interface_data.ac_if;
159984865Sobrien
160084865Sobrien	mtx_assert(&adapter->mtx, MA_OWNED);
160184865Sobrien
160284865Sobrien	INIT_DEBUGOUT("em_stop: begin");
160384865Sobrien	em_disable_intr(adapter);
160484865Sobrien	em_reset_hw(&adapter->hw);
160584865Sobrien	callout_stop(&adapter->timer);
160684865Sobrien	callout_stop(&adapter->tx_fifo_timer);
160784865Sobrien	em_free_transmit_structures(adapter);
160884865Sobrien	em_free_receive_structures(adapter);
160989857Sobrien
161084865Sobrien
161184865Sobrien	/* Tell the stack that the interface is no longer active */
161284865Sobrien	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
161384865Sobrien
161484865Sobrien	return;
161584865Sobrien}
161684865Sobrien
161784865Sobrien
161884865Sobrien/*********************************************************************
161984865Sobrien *
162084865Sobrien *  Determine hardware revision.
162189857Sobrien *
162289857Sobrien **********************************************************************/
162389857Sobrienstatic void
162489857Sobrienem_identify_hardware(struct adapter * adapter)
1625130561Sobrien{
162684865Sobrien	device_t dev = adapter->dev;
162789857Sobrien
162889857Sobrien	/* Make sure our PCI config space has the necessary stuff set */
1629130561Sobrien	adapter->hw.pci_cmd_word = pci_read_config(dev, PCIR_COMMAND, 2);
163084865Sobrien	if (!((adapter->hw.pci_cmd_word & PCIM_CMD_BUSMASTEREN) &&
163184865Sobrien	      (adapter->hw.pci_cmd_word & PCIM_CMD_MEMEN))) {
163284865Sobrien		printf("em%d: Memory Access and/or Bus Master bits were not set!\n",
163384865Sobrien		       adapter->unit);
163484865Sobrien		adapter->hw.pci_cmd_word |=
163584865Sobrien		(PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN);
163684865Sobrien		pci_write_config(dev, PCIR_COMMAND, adapter->hw.pci_cmd_word, 2);
163784865Sobrien	}
163889857Sobrien
163984865Sobrien	/* Save off the information about this board */
164089857Sobrien	adapter->hw.vendor_id = pci_get_vendor(dev);
164189857Sobrien	adapter->hw.device_id = pci_get_device(dev);
1642130561Sobrien	adapter->hw.revision_id = pci_read_config(dev, PCIR_REVID, 1);
164384865Sobrien	adapter->hw.subsystem_vendor_id = pci_read_config(dev, PCIR_SUBVEND_0, 2);
164484865Sobrien	adapter->hw.subsystem_id = pci_read_config(dev, PCIR_SUBDEV_0, 2);
164584865Sobrien
164689857Sobrien	/* Identify the MAC */
164784865Sobrien        if (em_set_mac_type(&adapter->hw))
164884865Sobrien                printf("em%d: Unknown MAC Type\n", adapter->unit);
164984865Sobrien
165084865Sobrien	if(adapter->hw.mac_type == em_82541 ||
165184865Sobrien	   adapter->hw.mac_type == em_82541_rev_2 ||
1652218822Sdim	   adapter->hw.mac_type == em_82547 ||
165384865Sobrien	   adapter->hw.mac_type == em_82547_rev_2)
165484865Sobrien		adapter->hw.phy_init_script = TRUE;
165584865Sobrien
165684865Sobrien        return;
165784865Sobrien}
165884865Sobrien
165984865Sobrienstatic int
166084865Sobrienem_allocate_pci_resources(struct adapter * adapter)
166184865Sobrien{
166289857Sobrien	int             i, val, rid;
1663130561Sobrien	device_t        dev = adapter->dev;
166484865Sobrien
166584865Sobrien	rid = EM_MMBA;
166684865Sobrien	adapter->res_memory = bus_alloc_resource(dev, SYS_RES_MEMORY,
166784865Sobrien						 &rid, 0, ~0, 1,
166884865Sobrien						 RF_ACTIVE);
166984865Sobrien	if (!(adapter->res_memory)) {
167084865Sobrien		printf("em%d: Unable to allocate bus resource: memory\n",
167189857Sobrien		       adapter->unit);
1672130561Sobrien		return(ENXIO);
167384865Sobrien	}
167484865Sobrien	adapter->osdep.mem_bus_space_tag =
1675130561Sobrien	rman_get_bustag(adapter->res_memory);
167684865Sobrien	adapter->osdep.mem_bus_space_handle =
167784865Sobrien	rman_get_bushandle(adapter->res_memory);
167889857Sobrien	adapter->hw.hw_addr = (uint8_t *)&adapter->osdep.mem_bus_space_handle;
167989857Sobrien
168089857Sobrien
168189857Sobrien	if (adapter->hw.mac_type > em_82543) {
168289857Sobrien		/* Figure our where our IO BAR is ? */
168389857Sobrien		rid = EM_MMBA;
168489857Sobrien		for (i = 0; i < 5; i++) {
168589857Sobrien			val = pci_read_config(dev, rid, 4);
168689857Sobrien			if (val & 0x00000001) {
168789857Sobrien				adapter->io_rid = rid;
168889857Sobrien				break;
1689130561Sobrien			}
169089857Sobrien			rid += 4;
169189857Sobrien		}
169289857Sobrien
169389857Sobrien		adapter->res_ioport = bus_alloc_resource(dev, SYS_RES_IOPORT,
169489857Sobrien							 &adapter->io_rid, 0, ~0, 1,
169589857Sobrien							 RF_ACTIVE);
169689857Sobrien		if (!(adapter->res_ioport)) {
1697130561Sobrien			printf("em%d: Unable to allocate bus resource: ioport\n",
169889857Sobrien			       adapter->unit);
169989857Sobrien			return(ENXIO);
170089857Sobrien		}
170189857Sobrien
170289857Sobrien		adapter->hw.io_base =
170389857Sobrien		rman_get_start(adapter->res_ioport);
1704130561Sobrien	}
1705104834Sobrien
1706104834Sobrien	rid = 0x0;
1707104834Sobrien	adapter->res_interrupt = bus_alloc_resource(dev, SYS_RES_IRQ,
1708104834Sobrien						    &rid, 0, ~0, 1,
1709104834Sobrien						    RF_SHAREABLE | RF_ACTIVE);
1710104834Sobrien	if (!(adapter->res_interrupt)) {
1711104834Sobrien		printf("em%d: Unable to allocate bus resource: interrupt\n",
1712104834Sobrien		       adapter->unit);
1713130561Sobrien		return(ENXIO);
1714104834Sobrien	}
1715104834Sobrien	if (bus_setup_intr(dev, adapter->res_interrupt,
1716104834Sobrien			   INTR_TYPE_NET | INTR_MPSAFE,
1717130561Sobrien			   (void (*)(void *)) em_intr, adapter,
1718104834Sobrien			   &adapter->int_handler_tag)) {
1719130561Sobrien		printf("em%d: Error registering interrupt handler!\n",
1720104834Sobrien		       adapter->unit);
1721104834Sobrien		return(ENXIO);
1722130561Sobrien	}
1723104834Sobrien
1724104834Sobrien	adapter->hw.back = &adapter->osdep;
1725104834Sobrien
1726104834Sobrien	return(0);
1727104834Sobrien}
1728104834Sobrien
1729104834Sobrienstatic void
1730104834Sobrienem_free_pci_resources(struct adapter * adapter)
1731130561Sobrien{
1732104834Sobrien	device_t dev = adapter->dev;
1733104834Sobrien
1734104834Sobrien	if (adapter->res_interrupt != NULL) {
1735104834Sobrien		bus_teardown_intr(dev, adapter->res_interrupt,
1736104834Sobrien				  adapter->int_handler_tag);
1737104834Sobrien		bus_release_resource(dev, SYS_RES_IRQ, 0,
1738104834Sobrien				     adapter->res_interrupt);
1739130561Sobrien	}
1740104834Sobrien	if (adapter->res_memory != NULL) {
1741104834Sobrien		bus_release_resource(dev, SYS_RES_MEMORY, EM_MMBA,
1742104834Sobrien				     adapter->res_memory);
1743104834Sobrien	}
1744104834Sobrien
1745104834Sobrien	if (adapter->res_ioport != NULL) {
1746130561Sobrien		bus_release_resource(dev, SYS_RES_IOPORT, adapter->io_rid,
1747104834Sobrien				     adapter->res_ioport);
1748130561Sobrien	}
1749104834Sobrien	return;
1750104834Sobrien}
1751130561Sobrien
1752104834Sobrien/*********************************************************************
1753104834Sobrien *
1754130561Sobrien *  Initialize the hardware to a configuration as specified by the
1755104834Sobrien *  adapter structure. The controller is reset, the EEPROM is
1756104834Sobrien *  verified, the MAC address is set, then the shared initialization
1757104834Sobrien *  routines are called.
1758218822Sdim *
1759104834Sobrien **********************************************************************/
1760104834Sobrienstatic int
1761104834Sobrienem_hardware_init(struct adapter * adapter)
1762104834Sobrien{
1763104834Sobrien        INIT_DEBUGOUT("em_hardware_init: begin");
1764104834Sobrien	/* Issue a global reset */
1765104834Sobrien	em_reset_hw(&adapter->hw);
1766104834Sobrien
1767104834Sobrien	/* When hardware is reset, fifo_head is also reset */
1768104834Sobrien	adapter->tx_fifo_head = 0;
1769104834Sobrien
1770104834Sobrien	/* Make sure we have a good EEPROM before we read from it */
1771104834Sobrien	if (em_validate_eeprom_checksum(&adapter->hw) < 0) {
1772104834Sobrien		printf("em%d: The EEPROM Checksum Is Not Valid\n",
1773104834Sobrien		       adapter->unit);
1774130561Sobrien		return(EIO);
1775104834Sobrien	}
1776104834Sobrien
1777104834Sobrien	if (em_read_part_num(&adapter->hw, &(adapter->part_num)) < 0) {
1778104834Sobrien		printf("em%d: EEPROM read error while reading part number\n",
1779130561Sobrien		       adapter->unit);
1780104834Sobrien		return(EIO);
1781104834Sobrien	}
1782130561Sobrien
178389857Sobrien	if (em_init_hw(&adapter->hw) < 0) {
178484865Sobrien		printf("em%d: Hardware Initialization Failed",
178589857Sobrien		       adapter->unit);
178684865Sobrien		return(EIO);
178784865Sobrien	}
178889857Sobrien
178984865Sobrien	em_check_for_link(&adapter->hw);
179089857Sobrien	if (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU)
179189857Sobrien		adapter->link_active = 1;
179284865Sobrien	else
179389857Sobrien		adapter->link_active = 0;
179489857Sobrien
1795218822Sdim	if (adapter->link_active) {
1796130561Sobrien		em_get_speed_and_duplex(&adapter->hw,
179789857Sobrien					&adapter->link_speed,
179889857Sobrien					&adapter->link_duplex);
179989857Sobrien	} else {
180084865Sobrien		adapter->link_speed = 0;
180189857Sobrien		adapter->link_duplex = 0;
180289857Sobrien	}
180389857Sobrien
180489857Sobrien	return(0);
180589857Sobrien}
180689857Sobrien
180789857Sobrien/*********************************************************************
180889857Sobrien *
180989857Sobrien *  Setup networking device structure and register an interface.
181084865Sobrien *
181189857Sobrien **********************************************************************/
181289857Sobrienstatic void
181389857Sobrienem_setup_interface(device_t dev, struct adapter * adapter)
181489857Sobrien{
181589857Sobrien	struct ifnet   *ifp;
181689857Sobrien	INIT_DEBUGOUT("em_setup_interface: begin");
181789857Sobrien
181889857Sobrien	ifp = &adapter->interface_data.ac_if;
181989857Sobrien	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
182089857Sobrien	ifp->if_mtu = ETHERMTU;
182189857Sobrien	ifp->if_output = ether_output;
182289857Sobrien	ifp->if_baudrate = 1000000000;
1823218822Sdim	ifp->if_init =  em_init;
182489857Sobrien	ifp->if_softc = adapter;
182589857Sobrien	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
182689857Sobrien	ifp->if_ioctl = em_ioctl;
182784865Sobrien	ifp->if_start = em_start;
182889857Sobrien	ifp->if_watchdog = em_watchdog;
182989857Sobrien	ifp->if_snd.ifq_maxlen = adapter->num_tx_desc - 1;
183089857Sobrien
183189857Sobrien#if __FreeBSD_version < 500000
183284865Sobrien        ether_ifattach(ifp, ETHER_BPF_SUPPORTED);
183389857Sobrien#else
183484865Sobrien        ether_ifattach(ifp, adapter->interface_data.ac_enaddr);
183589857Sobrien#endif
183689857Sobrien
183789857Sobrien	if (adapter->hw.mac_type >= em_82543) {
183884865Sobrien		ifp->if_capabilities = IFCAP_HWCSUM;
183989857Sobrien		ifp->if_capenable = ifp->if_capabilities;
184089857Sobrien	}
1841130561Sobrien
1842130561Sobrien	/*
1843130561Sobrien	 * Tell the upper layer(s) we support long frames.
184489857Sobrien	 */
1845130561Sobrien	ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
1846130561Sobrien#if __FreeBSD_version >= 500000
1847130561Sobrien        ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU;
1848130561Sobrien#endif
1849130561Sobrien
1850130561Sobrien
1851130561Sobrien	/*
1852130561Sobrien	 * Specify the media types supported by this adapter and register
1853130561Sobrien	 * callbacks to update media and link information
1854130561Sobrien	 */
1855130561Sobrien	ifmedia_init(&adapter->media, IFM_IMASK, em_media_change,
1856130561Sobrien		     em_media_status);
1857130561Sobrien	if (adapter->hw.media_type == em_media_type_fiber) {
1858130561Sobrien		ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_SX | IFM_FDX,
1859130561Sobrien			    0, NULL);
186089857Sobrien		ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_SX,
186189857Sobrien			    0, NULL);
1862130561Sobrien	} else {
186384865Sobrien		ifmedia_add(&adapter->media, IFM_ETHER | IFM_10_T, 0, NULL);
186489857Sobrien		ifmedia_add(&adapter->media, IFM_ETHER | IFM_10_T | IFM_FDX,
1865218822Sdim			    0, NULL);
1866218822Sdim		ifmedia_add(&adapter->media, IFM_ETHER | IFM_100_TX,
186789857Sobrien			    0, NULL);
186884865Sobrien		ifmedia_add(&adapter->media, IFM_ETHER | IFM_100_TX | IFM_FDX,
1869130561Sobrien			    0, NULL);
187089857Sobrien#if __FreeBSD_version < 500000
187189857Sobrien		ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_TX | IFM_FDX,
1872130561Sobrien			    0, NULL);
1873130561Sobrien		ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_TX, 0, NULL);
187489857Sobrien#else
187589857Sobrien		ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_T | IFM_FDX,
1876218822Sdim			    0, NULL);
187789857Sobrien		ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_T, 0, NULL);
1878130561Sobrien#endif
187989857Sobrien	}
188089857Sobrien	ifmedia_add(&adapter->media, IFM_ETHER | IFM_AUTO, 0, NULL);
1881130561Sobrien	ifmedia_set(&adapter->media, IFM_ETHER | IFM_AUTO);
188289857Sobrien
1883130561Sobrien	return;
188489857Sobrien}
188589857Sobrien
188684865Sobrien
188789857Sobrien/*********************************************************************
188884865Sobrien *
188989857Sobrien *  Workaround for SmartSpeed on 82541 and 82547 controllers
189089857Sobrien *
189189857Sobrien **********************************************************************/
189289857Sobrienstatic void
189389857Sobrienem_smartspeed(struct adapter *adapter)
189489857Sobrien{
189584865Sobrien        uint16_t phy_tmp;
189689857Sobrien
189789857Sobrien	if(adapter->link_active || (adapter->hw.phy_type != em_phy_igp) ||
189889857Sobrien	   !adapter->hw.autoneg || !(adapter->hw.autoneg_advertised & ADVERTISE_1000_FULL))
189984865Sobrien		return;
190089857Sobrien
190189857Sobrien        if(adapter->smartspeed == 0) {
1902130561Sobrien                /* If Master/Slave config fault is asserted twice,
190389857Sobrien                 * we assume back-to-back */
190489857Sobrien                em_read_phy_reg(&adapter->hw, PHY_1000T_STATUS, &phy_tmp);
190589857Sobrien                if(!(phy_tmp & SR_1000T_MS_CONFIG_FAULT)) return;
190689857Sobrien                em_read_phy_reg(&adapter->hw, PHY_1000T_STATUS, &phy_tmp);
190789857Sobrien                if(phy_tmp & SR_1000T_MS_CONFIG_FAULT) {
190889857Sobrien                        em_read_phy_reg(&adapter->hw, PHY_1000T_CTRL,
190989857Sobrien					&phy_tmp);
191089857Sobrien                        if(phy_tmp & CR_1000T_MS_ENABLE) {
191189857Sobrien                                phy_tmp &= ~CR_1000T_MS_ENABLE;
191289857Sobrien                                em_write_phy_reg(&adapter->hw,
191389857Sobrien                                                    PHY_1000T_CTRL, phy_tmp);
191489857Sobrien                                adapter->smartspeed++;
191589857Sobrien                                if(adapter->hw.autoneg &&
191689857Sobrien                                   !em_phy_setup_autoneg(&adapter->hw) &&
191789857Sobrien				   !em_read_phy_reg(&adapter->hw, PHY_CTRL,
191889857Sobrien                                                       &phy_tmp)) {
191989857Sobrien                                        phy_tmp |= (MII_CR_AUTO_NEG_EN |
192089857Sobrien                                                    MII_CR_RESTART_AUTO_NEG);
192189857Sobrien                                        em_write_phy_reg(&adapter->hw,
192289857Sobrien							 PHY_CTRL, phy_tmp);
192389857Sobrien                                }
192489857Sobrien                        }
192589857Sobrien                }
192689857Sobrien                return;
1927218822Sdim        } else if(adapter->smartspeed == EM_SMARTSPEED_DOWNSHIFT) {
192889857Sobrien                /* If still no link, perhaps using 2/3 pair cable */
192989857Sobrien                em_read_phy_reg(&adapter->hw, PHY_1000T_CTRL, &phy_tmp);
193089857Sobrien                phy_tmp |= CR_1000T_MS_ENABLE;
193184865Sobrien                em_write_phy_reg(&adapter->hw, PHY_1000T_CTRL, phy_tmp);
193289857Sobrien                if(adapter->hw.autoneg &&
193389857Sobrien                   !em_phy_setup_autoneg(&adapter->hw) &&
193489857Sobrien                   !em_read_phy_reg(&adapter->hw, PHY_CTRL, &phy_tmp)) {
193589857Sobrien                        phy_tmp |= (MII_CR_AUTO_NEG_EN |
193689857Sobrien                                    MII_CR_RESTART_AUTO_NEG);
193789857Sobrien                        em_write_phy_reg(&adapter->hw, PHY_CTRL, phy_tmp);
193889857Sobrien                }
193989857Sobrien        }
194089857Sobrien        /* Restart process after EM_SMARTSPEED_MAX iterations */
194189857Sobrien        if(adapter->smartspeed++ == EM_SMARTSPEED_MAX)
194289857Sobrien                adapter->smartspeed = 0;
194389857Sobrien
194489857Sobrien	return;
194589857Sobrien}
194689857Sobrien
194789857Sobrien
1948218822Sdim/*
194989857Sobrien * Manage DMA'able memory.
195089857Sobrien */
195189857Sobrienstatic void
195284865Sobrienem_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
195389857Sobrien{
195489857Sobrien        if (error)
195589857Sobrien                return;
195689857Sobrien        *(bus_addr_t*) arg = segs->ds_addr;
195789857Sobrien        return;
195889857Sobrien}
195984865Sobrien
1960130561Sobrienstatic int
196189857Sobrienem_dma_malloc(struct adapter *adapter, bus_size_t size,
1962130561Sobrien        struct em_dma_alloc *dma, int mapflags)
1963130561Sobrien{
196484865Sobrien        int r;
196589857Sobrien
1966218822Sdim        r = bus_dma_tag_create(NULL,                    /* parent */
1967218822Sdim                               PAGE_SIZE, 0,            /* alignment, bounds */
196889857Sobrien                               BUS_SPACE_MAXADDR,       /* lowaddr */
196984865Sobrien                               BUS_SPACE_MAXADDR,       /* highaddr */
1970130561Sobrien                               NULL, NULL,              /* filter, filterarg */
197189857Sobrien                               size,                    /* maxsize */
197289857Sobrien                               1,                       /* nsegments */
1973130561Sobrien                               size,                    /* maxsegsize */
1974130561Sobrien                               BUS_DMA_ALLOCNOW,        /* flags */
197589857Sobrien			       NULL,			/* lockfunc */
197689857Sobrien			       NULL,			/* lockarg */
1977218822Sdim                               &dma->dma_tag);
197889857Sobrien        if (r != 0) {
1979130561Sobrien                printf("em%d: em_dma_malloc: bus_dma_tag_create failed; "
198084865Sobrien                        "error %u\n", adapter->unit, r);
198189857Sobrien                goto fail_0;
198284865Sobrien        }
198389857Sobrien
198489857Sobrien        r = bus_dmamap_create(dma->dma_tag, BUS_DMA_NOWAIT, &dma->dma_map);
198589857Sobrien        if (r != 0) {
198689857Sobrien                printf("em%d: em_dma_malloc: bus_dmamap_create failed; "
198789857Sobrien                        "error %u\n", adapter->unit, r);
198889857Sobrien                goto fail_1;
198989857Sobrien        }
199089857Sobrien
199184865Sobrien        r = bus_dmamem_alloc(dma->dma_tag, (void**) &dma->dma_vaddr,
199289857Sobrien                             BUS_DMA_NOWAIT, &dma->dma_map);
199389857Sobrien        if (r != 0) {
199489857Sobrien                printf("em%d: em_dma_malloc: bus_dmammem_alloc failed; "
199589857Sobrien                        "size %ju, error %d\n", adapter->unit,
199689857Sobrien			(uintmax_t)size, r);
199789857Sobrien                goto fail_2;
1998130561Sobrien        }
199989857Sobrien
200089857Sobrien        r = bus_dmamap_load(dma->dma_tag, dma->dma_map, dma->dma_vaddr,
200189857Sobrien                            size,
200289857Sobrien                            em_dmamap_cb,
200389857Sobrien                            &dma->dma_paddr,
200489857Sobrien                            mapflags | BUS_DMA_NOWAIT);
200589857Sobrien        if (r != 0) {
200684865Sobrien                printf("em%d: em_dma_malloc: bus_dmamap_load failed; "
200789857Sobrien                        "error %u\n", adapter->unit, r);
200889857Sobrien                goto fail_3;
200989857Sobrien        }
201089857Sobrien
201189857Sobrien        dma->dma_size = size;
201289857Sobrien        return (0);
201389857Sobrien
201489857Sobrienfail_3:
201589857Sobrien        bus_dmamap_unload(dma->dma_tag, dma->dma_map);
201689857Sobrienfail_2:
201789857Sobrien        bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map);
201889857Sobrienfail_1:
201989857Sobrien        bus_dmamap_destroy(dma->dma_tag, dma->dma_map);
202089857Sobrien        bus_dma_tag_destroy(dma->dma_tag);
202189857Sobrienfail_0:
202289857Sobrien        dma->dma_map = NULL;
2023218822Sdim        dma->dma_tag = NULL;
202489857Sobrien        return (r);
202589857Sobrien}
202684865Sobrien
202789857Sobrienstatic void
202889857Sobrienem_dma_free(struct adapter *adapter, struct em_dma_alloc *dma)
202989857Sobrien{
203089857Sobrien        bus_dmamap_unload(dma->dma_tag, dma->dma_map);
203189857Sobrien        bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map);
203289857Sobrien        bus_dmamap_destroy(dma->dma_tag, dma->dma_map);
203389857Sobrien        bus_dma_tag_destroy(dma->dma_tag);
203484865Sobrien}
203589857Sobrien
203689857Sobrien
203789857Sobrien/*********************************************************************
203889857Sobrien *
203989857Sobrien *  Allocate memory for tx_buffer structures. The tx_buffer stores all
204089857Sobrien *  the information needed to transmit a packet on the wire.
204189857Sobrien *
204289857Sobrien **********************************************************************/
204389857Sobrienstatic int
2044218822Sdimem_allocate_transmit_structures(struct adapter * adapter)
204589857Sobrien{
204689857Sobrien	if (!(adapter->tx_buffer_area =
204784865Sobrien	      (struct em_buffer *) malloc(sizeof(struct em_buffer) *
204884865Sobrien					     adapter->num_tx_desc, M_DEVBUF,
204989857Sobrien					     M_NOWAIT))) {
205084865Sobrien		printf("em%d: Unable to allocate tx_buffer memory\n",
205189857Sobrien		       adapter->unit);
205289857Sobrien		return ENOMEM;
205389857Sobrien	}
205489857Sobrien
2055130561Sobrien	bzero(adapter->tx_buffer_area,
205689857Sobrien	      sizeof(struct em_buffer) * adapter->num_tx_desc);
2057130561Sobrien
2058130561Sobrien	return 0;
205984865Sobrien}
206084865Sobrien
2061130561Sobrien/*********************************************************************
206284865Sobrien *
206384865Sobrien *  Allocate and initialize transmit structures.
206484865Sobrien *
206584865Sobrien **********************************************************************/
206684865Sobrienstatic int
206784865Sobrienem_setup_transmit_structures(struct adapter * adapter)
206884865Sobrien{
206984865Sobrien        /*
207084865Sobrien         * Setup DMA descriptor areas.
207184865Sobrien         */
207284865Sobrien        if (bus_dma_tag_create(NULL,                    /* parent */
207384865Sobrien                               PAGE_SIZE, 0,            /* alignment, bounds */
207484865Sobrien                               BUS_SPACE_MAXADDR,       /* lowaddr */
207584865Sobrien                               BUS_SPACE_MAXADDR,       /* highaddr */
207684865Sobrien                               NULL, NULL,              /* filter, filterarg */
207784865Sobrien                               MCLBYTES * 8,            /* maxsize */
2078130561Sobrien                               EM_MAX_SCATTER,          /* nsegments */
207984865Sobrien                               MCLBYTES * 8,            /* maxsegsize */
208084865Sobrien                               BUS_DMA_ALLOCNOW,        /* flags */
208184865Sobrien			       NULL,			/* lockfunc */
208284865Sobrien			       NULL,			/* lockarg */
208389857Sobrien                               &adapter->txtag)) {
208489857Sobrien                printf("em%d: Unable to allocate TX DMA tag\n", adapter->unit);
208584865Sobrien                return (ENOMEM);
2086130561Sobrien        }
2087130561Sobrien
2088218822Sdim        if (em_allocate_transmit_structures(adapter))
208984865Sobrien                return (ENOMEM);
209089857Sobrien
209184865Sobrien        bzero((void *) adapter->tx_desc_base,
209284865Sobrien              (sizeof(struct em_tx_desc)) * adapter->num_tx_desc);
209384865Sobrien
209489857Sobrien        adapter->next_avail_tx_desc = 0;
209584865Sobrien        adapter->oldest_used_tx_desc = 0;
209684865Sobrien
2097218822Sdim        /* Set number of descriptors available */
209884865Sobrien        adapter->num_tx_desc_avail = adapter->num_tx_desc;
209984865Sobrien
210084865Sobrien        /* Set checksum context */
210184865Sobrien        adapter->active_checksum_context = OFFLOAD_NONE;
210284865Sobrien
2103218822Sdim        return (0);
210484865Sobrien}
210584865Sobrien
210684865Sobrien/*********************************************************************
210784865Sobrien *
210884865Sobrien *  Enable transmit unit.
210984865Sobrien *
2110130561Sobrien **********************************************************************/
211184865Sobrienstatic void
211289857Sobrienem_initialize_transmit_unit(struct adapter * adapter)
2113130561Sobrien{
211484865Sobrien	u_int32_t       reg_tctl;
211584865Sobrien	u_int32_t       reg_tipg = 0;
2116130561Sobrien	u_int64_t	bus_addr;
211784865Sobrien
211884865Sobrien         INIT_DEBUGOUT("em_initialize_transmit_unit: begin");
2119218822Sdim	/* Setup the Base and Length of the Tx Descriptor Ring */
2120218822Sdim	bus_addr = adapter->txdma.dma_paddr;
2121218822Sdim	E1000_WRITE_REG(&adapter->hw, TDBAL, (u_int32_t)bus_addr);
212284865Sobrien	E1000_WRITE_REG(&adapter->hw, TDBAH, (u_int32_t)(bus_addr >> 32));
212384865Sobrien	E1000_WRITE_REG(&adapter->hw, TDLEN,
212489857Sobrien			adapter->num_tx_desc *
212584865Sobrien			sizeof(struct em_tx_desc));
212684865Sobrien
212784865Sobrien	/* Setup the HW Tx Head and Tail descriptor pointers */
212884865Sobrien	E1000_WRITE_REG(&adapter->hw, TDH, 0);
212984865Sobrien	E1000_WRITE_REG(&adapter->hw, TDT, 0);
213084865Sobrien
2131130561Sobrien
213284865Sobrien	HW_DEBUGOUT2("Base = %x, Length = %x\n",
213384865Sobrien		     E1000_READ_REG(&adapter->hw, TDBAL),
213484865Sobrien		     E1000_READ_REG(&adapter->hw, TDLEN));
213584865Sobrien
213684865Sobrien	/* Set the default values for the Tx Inter Packet Gap timer */
213784865Sobrien	switch (adapter->hw.mac_type) {
213884865Sobrien	case em_82542_rev2_0:
213984865Sobrien        case em_82542_rev2_1:
214084865Sobrien                reg_tipg = DEFAULT_82542_TIPG_IPGT;
214184865Sobrien                reg_tipg |= DEFAULT_82542_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT;
214284865Sobrien                reg_tipg |= DEFAULT_82542_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT;
214384865Sobrien                break;
214484865Sobrien        default:
214584865Sobrien                if (adapter->hw.media_type == em_media_type_fiber)
214684865Sobrien                        reg_tipg = DEFAULT_82543_TIPG_IPGT_FIBER;
214784865Sobrien                else
214884865Sobrien                        reg_tipg = DEFAULT_82543_TIPG_IPGT_COPPER;
214984865Sobrien                reg_tipg |= DEFAULT_82543_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT;
215084865Sobrien                reg_tipg |= DEFAULT_82543_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT;
2151130561Sobrien        }
215284865Sobrien
215384865Sobrien	E1000_WRITE_REG(&adapter->hw, TIPG, reg_tipg);
215484865Sobrien	E1000_WRITE_REG(&adapter->hw, TIDV, adapter->tx_int_delay.value);
2155251227Spfg	if(adapter->hw.mac_type >= em_82540)
215684865Sobrien		E1000_WRITE_REG(&adapter->hw, TADV,
215784865Sobrien		    adapter->tx_abs_int_delay.value);
215884865Sobrien
215984865Sobrien	/* Program the Transmit Control Register */
216084865Sobrien	reg_tctl = E1000_TCTL_PSP | E1000_TCTL_EN |
216184865Sobrien		   (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);
216289857Sobrien	if (adapter->link_duplex == 1) {
216389857Sobrien		reg_tctl |= E1000_FDX_COLLISION_DISTANCE << E1000_COLD_SHIFT;
216484865Sobrien	} else {
2165130561Sobrien		reg_tctl |= E1000_HDX_COLLISION_DISTANCE << E1000_COLD_SHIFT;
216684865Sobrien	}
216784865Sobrien	E1000_WRITE_REG(&adapter->hw, TCTL, reg_tctl);
216884865Sobrien
216984865Sobrien	/* Setup Transmit Descriptor Settings for this adapter */
217084865Sobrien	adapter->txd_cmd = E1000_TXD_CMD_IFCS | E1000_TXD_CMD_RS;
217184865Sobrien
217284865Sobrien	if (adapter->tx_int_delay.value > 0)
217384865Sobrien		adapter->txd_cmd |= E1000_TXD_CMD_IDE;
217484865Sobrien
2175130561Sobrien	return;
217689857Sobrien}
217784865Sobrien
217884865Sobrien/*********************************************************************
217984865Sobrien *
218084865Sobrien *  Free all transmit related data structures.
218184865Sobrien *
218284865Sobrien **********************************************************************/
218384865Sobrienstatic void
218484865Sobrienem_free_transmit_structures(struct adapter * adapter)
218584865Sobrien{
218684865Sobrien        struct em_buffer   *tx_buffer;
218784865Sobrien        int             i;
218884865Sobrien
218984865Sobrien        INIT_DEBUGOUT("free_transmit_structures: begin");
219084865Sobrien
219184865Sobrien        if (adapter->tx_buffer_area != NULL) {
219284865Sobrien                tx_buffer = adapter->tx_buffer_area;
219384865Sobrien                for (i = 0; i < adapter->num_tx_desc; i++, tx_buffer++) {
219484865Sobrien                        if (tx_buffer->m_head != NULL) {
219584865Sobrien                                bus_dmamap_unload(adapter->txtag, tx_buffer->map);
219684865Sobrien                                bus_dmamap_destroy(adapter->txtag, tx_buffer->map);
219784865Sobrien                                m_freem(tx_buffer->m_head);
219889857Sobrien                        }
219989857Sobrien                        tx_buffer->m_head = NULL;
2200130561Sobrien                }
2201130561Sobrien        }
2202130561Sobrien        if (adapter->tx_buffer_area != NULL) {
2203130561Sobrien                free(adapter->tx_buffer_area, M_DEVBUF);
220484865Sobrien                adapter->tx_buffer_area = NULL;
220584865Sobrien        }
2206130561Sobrien        if (adapter->txtag != NULL) {
220784865Sobrien                bus_dma_tag_destroy(adapter->txtag);
2208104834Sobrien                adapter->txtag = NULL;
2209130561Sobrien        }
2210130561Sobrien        return;
2211104834Sobrien}
2212130561Sobrien
221384865Sobrien/*********************************************************************
221484865Sobrien *
221584865Sobrien *  The offload context needs to be set when we transfer the first
221684865Sobrien *  packet of a particular protocol (TCP/UDP). We change the
221784865Sobrien *  context only if the protocol type changes.
221884865Sobrien *
221984865Sobrien **********************************************************************/
222084865Sobrienstatic void
222184865Sobrienem_transmit_checksum_setup(struct adapter * adapter,
222284865Sobrien			   struct mbuf *mp,
2223104834Sobrien			   u_int32_t *txd_upper,
2224104834Sobrien			   u_int32_t *txd_lower)
2225104834Sobrien{
222684865Sobrien	struct em_context_desc *TXD;
222784865Sobrien	struct em_buffer *tx_buffer;
222884865Sobrien	int curr_txd;
222984865Sobrien
223084865Sobrien	if (mp->m_pkthdr.csum_flags) {
223184865Sobrien
223284865Sobrien		if (mp->m_pkthdr.csum_flags & CSUM_TCP) {
223384865Sobrien			*txd_upper = E1000_TXD_POPTS_TXSM << 8;
223489857Sobrien			*txd_lower = E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D;
223589857Sobrien			if (adapter->active_checksum_context == OFFLOAD_TCP_IP)
223684865Sobrien				return;
223784865Sobrien			else
223884865Sobrien				adapter->active_checksum_context = OFFLOAD_TCP_IP;
223984865Sobrien
224084865Sobrien		} else if (mp->m_pkthdr.csum_flags & CSUM_UDP) {
224184865Sobrien			*txd_upper = E1000_TXD_POPTS_TXSM << 8;
224284865Sobrien			*txd_lower = E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D;
224384865Sobrien			if (adapter->active_checksum_context == OFFLOAD_UDP_IP)
224484865Sobrien				return;
224584865Sobrien			else
224684865Sobrien				adapter->active_checksum_context = OFFLOAD_UDP_IP;
224784865Sobrien		} else {
224884865Sobrien			*txd_upper = 0;
224984865Sobrien			*txd_lower = 0;
225084865Sobrien			return;
225184865Sobrien		}
225289857Sobrien	} else {
225389857Sobrien		*txd_upper = 0;
225489857Sobrien		*txd_lower = 0;
225584865Sobrien		return;
2256130561Sobrien	}
225784865Sobrien
225884865Sobrien	/* If we reach this point, the checksum offload context
225989857Sobrien	 * needs to be reset.
226089857Sobrien	 */
2261130561Sobrien	curr_txd = adapter->next_avail_tx_desc;
226289857Sobrien	tx_buffer = &adapter->tx_buffer_area[curr_txd];
226384865Sobrien	TXD = (struct em_context_desc *) &adapter->tx_desc_base[curr_txd];
226484865Sobrien
2265130561Sobrien	TXD->lower_setup.ip_fields.ipcss = ETHER_HDR_LEN;
226689857Sobrien	TXD->lower_setup.ip_fields.ipcso =
2267130561Sobrien		ETHER_HDR_LEN + offsetof(struct ip, ip_sum);
226884865Sobrien	TXD->lower_setup.ip_fields.ipcse =
2269218822Sdim		htole16(ETHER_HDR_LEN + sizeof(struct ip) - 1);
227084865Sobrien
227184865Sobrien	TXD->upper_setup.tcp_fields.tucss =
227289857Sobrien		ETHER_HDR_LEN + sizeof(struct ip);
227384865Sobrien	TXD->upper_setup.tcp_fields.tucse = htole16(0);
227484865Sobrien
227584865Sobrien	if (adapter->active_checksum_context == OFFLOAD_TCP_IP) {
227689857Sobrien		TXD->upper_setup.tcp_fields.tucso =
2277130561Sobrien			ETHER_HDR_LEN + sizeof(struct ip) +
227884865Sobrien			offsetof(struct tcphdr, th_sum);
227984865Sobrien	} else if (adapter->active_checksum_context == OFFLOAD_UDP_IP) {
2280104834Sobrien		TXD->upper_setup.tcp_fields.tucso =
2281130561Sobrien			ETHER_HDR_LEN + sizeof(struct ip) +
228284865Sobrien			offsetof(struct udphdr, uh_sum);
228384865Sobrien	}
228484865Sobrien
228584865Sobrien	TXD->tcp_seg_setup.data = htole32(0);
228684865Sobrien	TXD->cmd_and_length = htole32(adapter->txd_cmd | E1000_TXD_CMD_DEXT);
228784865Sobrien
228884865Sobrien	tx_buffer->m_head = NULL;
228984865Sobrien
229084865Sobrien	if (++curr_txd == adapter->num_tx_desc)
229184865Sobrien		curr_txd = 0;
2292130561Sobrien
229384865Sobrien	adapter->num_tx_desc_avail--;
229484865Sobrien	adapter->next_avail_tx_desc = curr_txd;
229584865Sobrien
229684865Sobrien	return;
229784865Sobrien}
229884865Sobrien
229984865Sobrien/**********************************************************************
230084865Sobrien *
230184865Sobrien *  Examine each tx_buffer in the used queue. If the hardware is done
230284865Sobrien *  processing the packet then free associated resources. The
230389857Sobrien *  tx_buffer is put back on the free queue.
230489857Sobrien *
2305130561Sobrien **********************************************************************/
230684865Sobrienstatic void
2307130561Sobrienem_clean_transmit_interrupts(struct adapter * adapter)
230884865Sobrien{
230984865Sobrien        int i, num_avail;
2310130561Sobrien        struct em_buffer *tx_buffer;
231184865Sobrien        struct em_tx_desc   *tx_desc;
231284865Sobrien	struct ifnet   *ifp = &adapter->interface_data.ac_if;
231384865Sobrien
231484865Sobrien	mtx_assert(&adapter->mtx, MA_OWNED);
231589857Sobrien
231689857Sobrien        if (adapter->num_tx_desc_avail == adapter->num_tx_desc)
231784865Sobrien                return;
2318130561Sobrien
2319130561Sobrien#ifdef DBG_STATS
2320218822Sdim        adapter->clean_tx_interrupts++;
232189857Sobrien#endif
232289857Sobrien        num_avail = adapter->num_tx_desc_avail;
232389857Sobrien        i = adapter->oldest_used_tx_desc;
232484865Sobrien
2325218822Sdim        tx_buffer = &adapter->tx_buffer_area[i];
232689857Sobrien        tx_desc = &adapter->tx_desc_base[i];
232784865Sobrien
2328104834Sobrien        while (tx_desc->upper.fields.status & E1000_TXD_STAT_DD) {
232989857Sobrien
233084865Sobrien                tx_desc->upper.data = 0;
2331104834Sobrien                num_avail++;
2332130561Sobrien
2333130561Sobrien                if (tx_buffer->m_head) {
2334104834Sobrien			ifp->if_opackets++;
2335104834Sobrien                        bus_dmamap_sync(adapter->txtag, tx_buffer->map,
2336130561Sobrien                                        BUS_DMASYNC_POSTWRITE);
2337130561Sobrien                        bus_dmamap_unload(adapter->txtag, tx_buffer->map);
2338130561Sobrien                        bus_dmamap_destroy(adapter->txtag, tx_buffer->map);
2339218822Sdim
2340104834Sobrien                        m_freem(tx_buffer->m_head);
2341104834Sobrien                        tx_buffer->m_head = NULL;
234289857Sobrien                }
2343104834Sobrien
2344104834Sobrien                if (++i == adapter->num_tx_desc)
2345104834Sobrien                        i = 0;
2346130561Sobrien
2347104834Sobrien                tx_buffer = &adapter->tx_buffer_area[i];
2348104834Sobrien                tx_desc = &adapter->tx_desc_base[i];
234989857Sobrien        }
235089857Sobrien
235184865Sobrien        adapter->oldest_used_tx_desc = i;
235289857Sobrien
235389857Sobrien        /*
2354130561Sobrien         * If we have enough room, clear IFF_OACTIVE to tell the stack
235584865Sobrien         * that it is OK to send packets.
235684865Sobrien         * If there are no pending descriptors, clear the timeout. Otherwise,
235784865Sobrien         * if some descriptors have been freed, restart the timeout.
235884865Sobrien         */
2359130561Sobrien        if (num_avail > EM_TX_CLEANUP_THRESHOLD) {
2360130561Sobrien                ifp->if_flags &= ~IFF_OACTIVE;
2361218822Sdim                if (num_avail == adapter->num_tx_desc)
236284865Sobrien                        ifp->if_timer = 0;
236384865Sobrien                else if (num_avail == adapter->num_tx_desc_avail)
236489857Sobrien                        ifp->if_timer = EM_TX_TIMEOUT;
236584865Sobrien        }
236684865Sobrien        adapter->num_tx_desc_avail = num_avail;
236784865Sobrien        return;
236889857Sobrien}
236984865Sobrien
237084865Sobrien/*********************************************************************
237189857Sobrien *
237289857Sobrien *  Get a buffer from system mbuf buffer pool.
237384865Sobrien *
237484865Sobrien **********************************************************************/
237584865Sobrienstatic int
237684865Sobrienem_get_buf(int i, struct adapter *adapter,
237784865Sobrien           struct mbuf *nmp)
237884865Sobrien{
237984865Sobrien        register struct mbuf    *mp = nmp;
238084865Sobrien        struct em_buffer *rx_buffer;
238184865Sobrien        struct ifnet   *ifp;
2382130561Sobrien        bus_addr_t paddr;
238389857Sobrien        int error;
238489857Sobrien
238584865Sobrien        ifp = &adapter->interface_data.ac_if;
238684865Sobrien
2387130561Sobrien        if (mp == NULL) {
238884865Sobrien                mp = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
238984865Sobrien                if (mp == NULL) {
239089857Sobrien                        adapter->mbuf_cluster_failed++;
2391251227Spfg                        return(ENOBUFS);
239289857Sobrien                }
239389857Sobrien                mp->m_len = mp->m_pkthdr.len = MCLBYTES;
239489857Sobrien        } else {
239584865Sobrien                mp->m_len = mp->m_pkthdr.len = MCLBYTES;
239689857Sobrien                mp->m_data = mp->m_ext.ext_buf;
239784865Sobrien                mp->m_next = NULL;
239889857Sobrien        }
239989857Sobrien
240089857Sobrien        if (ifp->if_mtu <= ETHERMTU) {
2401130561Sobrien                m_adj(mp, ETHER_ALIGN);
240284865Sobrien        }
240384865Sobrien
240489857Sobrien        rx_buffer = &adapter->rx_buffer_area[i];
240584865Sobrien
240684865Sobrien        /*
240789857Sobrien         * Using memory from the mbuf cluster pool, invoke the
240889857Sobrien         * bus_dma machinery to arrange the memory mapping.
240984865Sobrien         */
241084865Sobrien        error = bus_dmamap_load(adapter->rxtag, rx_buffer->map,
2411130561Sobrien                                mtod(mp, void *), mp->m_len,
241289857Sobrien                                em_dmamap_cb, &paddr, 0);
241384865Sobrien        if (error) {
241489857Sobrien                m_free(mp);
241584865Sobrien                return(error);
241684865Sobrien        }
241784865Sobrien        rx_buffer->m_head = mp;
241884865Sobrien        adapter->rx_desc_base[i].buffer_addr = htole64(paddr);
241984865Sobrien        bus_dmamap_sync(adapter->rxtag, rx_buffer->map, BUS_DMASYNC_PREREAD);
242084865Sobrien
242184865Sobrien        return(0);
2422104834Sobrien}
2423104834Sobrien
2424104834Sobrien/*********************************************************************
2425104834Sobrien *
2426130561Sobrien *  Allocate memory for rx_buffer structures. Since we use one
2427104834Sobrien *  rx_buffer per received packet, the maximum number of rx_buffer's
2428130561Sobrien *  that we'll need is equal to the number of receive descriptors
2429104834Sobrien *  that we've allocated.
243084865Sobrien *
243184865Sobrien **********************************************************************/
243284865Sobrienstatic int
243384865Sobrienem_allocate_receive_structures(struct adapter * adapter)
243484865Sobrien{
243589857Sobrien        int             i, error;
243684865Sobrien        struct em_buffer *rx_buffer;
243789857Sobrien
243889857Sobrien        if (!(adapter->rx_buffer_area =
243989857Sobrien              (struct em_buffer *) malloc(sizeof(struct em_buffer) *
2440130561Sobrien                                          adapter->num_rx_desc, M_DEVBUF,
244189857Sobrien                                          M_NOWAIT))) {
2442130561Sobrien                printf("em%d: Unable to allocate rx_buffer memory\n",
244384865Sobrien                       adapter->unit);
244489857Sobrien                return(ENOMEM);
2445130561Sobrien        }
244684865Sobrien
2447104834Sobrien        bzero(adapter->rx_buffer_area,
2448130561Sobrien              sizeof(struct em_buffer) * adapter->num_rx_desc);
2449130561Sobrien
2450104834Sobrien        error = bus_dma_tag_create(NULL,                /* parent */
2451130561Sobrien                               PAGE_SIZE, 0,            /* alignment, bounds */
2452104834Sobrien                               BUS_SPACE_MAXADDR,       /* lowaddr */
245384865Sobrien                               BUS_SPACE_MAXADDR,       /* highaddr */
2454104834Sobrien                               NULL, NULL,              /* filter, filterarg */
2455104834Sobrien                               MCLBYTES,                /* maxsize */
2456104834Sobrien                               1,                       /* nsegments */
2457104834Sobrien                               MCLBYTES,                /* maxsegsize */
245884865Sobrien                               BUS_DMA_ALLOCNOW,        /* flags */
245984865Sobrien			       NULL,			/* lockfunc */
2460130561Sobrien			       NULL,			/* lockarg */
2461130561Sobrien                               &adapter->rxtag);
246284865Sobrien        if (error != 0) {
246389857Sobrien                printf("em%d: em_allocate_receive_structures: "
2464130561Sobrien                        "bus_dma_tag_create failed; error %u\n",
2465130561Sobrien                       adapter->unit, error);
2466130561Sobrien                goto fail_0;
2467130561Sobrien        }
2468130561Sobrien
2469130561Sobrien        rx_buffer = adapter->rx_buffer_area;
2470130561Sobrien        for (i = 0; i < adapter->num_rx_desc; i++, rx_buffer++) {
2471130561Sobrien                error = bus_dmamap_create(adapter->rxtag, BUS_DMA_NOWAIT,
2472130561Sobrien                                          &rx_buffer->map);
247389857Sobrien                if (error != 0) {
2474130561Sobrien                        printf("em%d: em_allocate_receive_structures: "
2475130561Sobrien                                "bus_dmamap_create failed; error %u\n",
2476130561Sobrien                                adapter->unit, error);
2477130561Sobrien                        goto fail_1;
2478130561Sobrien                }
247989857Sobrien        }
248089857Sobrien
248184865Sobrien        for (i = 0; i < adapter->num_rx_desc; i++) {
248284865Sobrien                error = em_get_buf(i, adapter, NULL);
248389857Sobrien                if (error != 0) {
248489857Sobrien                        adapter->rx_buffer_area[i].m_head = NULL;
248589857Sobrien                        adapter->rx_desc_base[i].buffer_addr = 0;
248689857Sobrien                        return(error);
248789857Sobrien                }
248884865Sobrien        }
248989857Sobrien
2490218822Sdim        return(0);
249189857Sobrien
2492130561Sobrienfail_1:
249384865Sobrien        bus_dma_tag_destroy(adapter->rxtag);
249489857Sobrienfail_0:
249584865Sobrien        adapter->rxtag = NULL;
2496104834Sobrien        free(adapter->rx_buffer_area, M_DEVBUF);
2497104834Sobrien        adapter->rx_buffer_area = NULL;
2498104834Sobrien        return (error);
2499130561Sobrien}
250089857Sobrien
250184865Sobrien/*********************************************************************
250289857Sobrien *
250389857Sobrien *  Allocate and initialize receive structures.
250489857Sobrien *
250589857Sobrien **********************************************************************/
250689857Sobrienstatic int
250789857Sobrienem_setup_receive_structures(struct adapter * adapter)
250889857Sobrien{
2509130561Sobrien	bzero((void *) adapter->rx_desc_base,
251089857Sobrien              (sizeof(struct em_rx_desc)) * adapter->num_rx_desc);
251189857Sobrien
251289857Sobrien	if (em_allocate_receive_structures(adapter))
251384865Sobrien		return ENOMEM;
251489857Sobrien
251589857Sobrien	/* Setup our descriptor pointers */
251689857Sobrien        adapter->next_rx_desc_to_check = 0;
251789857Sobrien	return(0);
251889857Sobrien}
251989857Sobrien
252089857Sobrien/*********************************************************************
252184865Sobrien *
2522130561Sobrien *  Enable receive unit.
252384865Sobrien *
252489857Sobrien **********************************************************************/
252589857Sobrienstatic void
252684865Sobrienem_initialize_receive_unit(struct adapter * adapter)
252789857Sobrien{
2528218822Sdim	u_int32_t       reg_rctl;
2529218822Sdim	u_int32_t       reg_rxcsum;
2530218822Sdim	struct ifnet    *ifp;
253184865Sobrien	u_int64_t	bus_addr;
253284865Sobrien
253384865Sobrien        INIT_DEBUGOUT("em_initialize_receive_unit: begin");
253484865Sobrien	ifp = &adapter->interface_data.ac_if;
253589857Sobrien
2536130561Sobrien	/* Make sure receives are disabled while setting up the descriptor ring */
253789857Sobrien	E1000_WRITE_REG(&adapter->hw, RCTL, 0);
253884865Sobrien
2539130561Sobrien	/* Set the Receive Delay Timer Register */
254089857Sobrien	E1000_WRITE_REG(&adapter->hw, RDTR,
2541130561Sobrien			adapter->rx_int_delay.value | E1000_RDT_FPDB);
254284865Sobrien
254389857Sobrien	if(adapter->hw.mac_type >= em_82540) {
254484865Sobrien		E1000_WRITE_REG(&adapter->hw, RADV,
254589857Sobrien		    adapter->rx_abs_int_delay.value);
254689857Sobrien
254789857Sobrien                /* Set the interrupt throttling rate.  Value is calculated
254889857Sobrien                 * as DEFAULT_ITR = 1/(MAX_INTS_PER_SEC * 256ns) */
254989857Sobrien#define MAX_INTS_PER_SEC        8000
255084865Sobrien#define DEFAULT_ITR             1000000000/(MAX_INTS_PER_SEC * 256)
255184865Sobrien                E1000_WRITE_REG(&adapter->hw, ITR, DEFAULT_ITR);
2552130561Sobrien        }
255389857Sobrien
255484865Sobrien	/* Setup the Base and Length of the Rx Descriptor Ring */
255584865Sobrien	bus_addr = adapter->rxdma.dma_paddr;
255684865Sobrien	E1000_WRITE_REG(&adapter->hw, RDBAL, (u_int32_t)bus_addr);
255789857Sobrien	E1000_WRITE_REG(&adapter->hw, RDBAH, (u_int32_t)(bus_addr >> 32));
255889857Sobrien	E1000_WRITE_REG(&adapter->hw, RDLEN, adapter->num_rx_desc *
255989857Sobrien			sizeof(struct em_rx_desc));
2560130561Sobrien
256184865Sobrien	/* Setup the HW Rx Head and Tail Descriptor Pointers */
256284865Sobrien	E1000_WRITE_REG(&adapter->hw, RDH, 0);
2563130561Sobrien	E1000_WRITE_REG(&adapter->hw, RDT, adapter->num_rx_desc - 1);
256484865Sobrien
256584865Sobrien	/* Setup the Receive Control Register */
256684865Sobrien	reg_rctl = E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_LBM_NO |
256784865Sobrien		   E1000_RCTL_RDMTS_HALF |
256884865Sobrien		   (adapter->hw.mc_filter_type << E1000_RCTL_MO_SHIFT);
2569130561Sobrien
257089857Sobrien	if (adapter->hw.tbi_compatibility_on == TRUE)
2571130561Sobrien		reg_rctl |= E1000_RCTL_SBP;
2572130561Sobrien
2573130561Sobrien
257484865Sobrien	switch (adapter->rx_buffer_len) {
257584865Sobrien	default:
2576130561Sobrien	case EM_RXBUFFER_2048:
257784865Sobrien		reg_rctl |= E1000_RCTL_SZ_2048;
257884865Sobrien		break;
257984865Sobrien	case EM_RXBUFFER_4096:
258084865Sobrien		reg_rctl |= E1000_RCTL_SZ_4096 | E1000_RCTL_BSEX | E1000_RCTL_LPE;
258184865Sobrien		break;
258284865Sobrien	case EM_RXBUFFER_8192:
258384865Sobrien		reg_rctl |= E1000_RCTL_SZ_8192 | E1000_RCTL_BSEX | E1000_RCTL_LPE;
258484865Sobrien		break;
258584865Sobrien	case EM_RXBUFFER_16384:
258684865Sobrien		reg_rctl |= E1000_RCTL_SZ_16384 | E1000_RCTL_BSEX | E1000_RCTL_LPE;
258784865Sobrien		break;
258884865Sobrien	}
258984865Sobrien
2590218822Sdim	if (ifp->if_mtu > ETHERMTU)
2591218822Sdim		reg_rctl |= E1000_RCTL_LPE;
259284865Sobrien
259384865Sobrien	/* Enable 82543 Receive Checksum Offload for TCP and UDP */
259484865Sobrien	if ((adapter->hw.mac_type >= em_82543) &&
259584865Sobrien	    (ifp->if_capenable & IFCAP_RXCSUM)) {
259684865Sobrien		reg_rxcsum = E1000_READ_REG(&adapter->hw, RXCSUM);
259784865Sobrien		reg_rxcsum |= (E1000_RXCSUM_IPOFL | E1000_RXCSUM_TUOFL);
259884865Sobrien		E1000_WRITE_REG(&adapter->hw, RXCSUM, reg_rxcsum);
259984865Sobrien	}
260084865Sobrien
260184865Sobrien	/* Enable Receives */
260284865Sobrien	E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
260389857Sobrien
260489857Sobrien        em_set_promisc(adapter);
260589857Sobrien	return;
260689857Sobrien}
260789857Sobrien
260889857Sobrien/*********************************************************************
260989857Sobrien *
261089857Sobrien *  Free receive related data structures.
261189857Sobrien *
261289857Sobrien **********************************************************************/
261389857Sobrienstatic void
261489857Sobrienem_free_receive_structures(struct adapter *adapter)
261589857Sobrien{
261689857Sobrien        struct em_buffer   *rx_buffer;
261789857Sobrien        int             i;
261889857Sobrien
261989857Sobrien        INIT_DEBUGOUT("free_receive_structures: begin");
262089857Sobrien
262189857Sobrien        if (adapter->rx_buffer_area != NULL) {
262289857Sobrien                rx_buffer = adapter->rx_buffer_area;
262389857Sobrien                for (i = 0; i < adapter->num_rx_desc; i++, rx_buffer++) {
262489857Sobrien                        if (rx_buffer->map != NULL) {
262589857Sobrien                                bus_dmamap_unload(adapter->rxtag, rx_buffer->map);
262689857Sobrien                                bus_dmamap_destroy(adapter->rxtag, rx_buffer->map);
262789857Sobrien                        }
262889857Sobrien                        if (rx_buffer->m_head != NULL)
262989857Sobrien                                m_freem(rx_buffer->m_head);
263089857Sobrien                        rx_buffer->m_head = NULL;
263189857Sobrien                }
263289857Sobrien        }
263389857Sobrien        if (adapter->rx_buffer_area != NULL) {
263489857Sobrien                free(adapter->rx_buffer_area, M_DEVBUF);
263589857Sobrien                adapter->rx_buffer_area = NULL;
263689857Sobrien        }
263789857Sobrien        if (adapter->rxtag != NULL) {
263889857Sobrien                bus_dma_tag_destroy(adapter->rxtag);
263989857Sobrien                adapter->rxtag = NULL;
264089857Sobrien        }
264189857Sobrien        return;
264289857Sobrien}
264389857Sobrien
264489857Sobrien/*********************************************************************
264589857Sobrien *
264689857Sobrien *  This routine executes in interrupt context. It replenishes
264789857Sobrien *  the mbufs in the descriptor and sends data which has been
264889857Sobrien *  dma'ed into host memory to upper layer.
264989857Sobrien *
265089857Sobrien *  We loop at most count times if count is > 0, or until done if
265189857Sobrien *  count < 0.
265289857Sobrien *
265389857Sobrien *********************************************************************/
265489857Sobrienstatic void
265589857Sobrienem_process_receive_interrupts(struct adapter * adapter, int count)
265689857Sobrien{
265789857Sobrien	struct ifnet        *ifp;
265889857Sobrien	struct mbuf         *mp;
265989857Sobrien#if __FreeBSD_version < 500000
266089857Sobrien        struct ether_header *eh;
266189857Sobrien#endif
266289857Sobrien	u_int8_t            accept_frame = 0;
266389857Sobrien 	u_int8_t            eop = 0;
266489857Sobrien        u_int16_t           len, desc_len;
266589857Sobrien	int                 i;
266689857Sobrien
266789857Sobrien	/* Pointer to the receive descriptor being examined. */
266889857Sobrien	struct em_rx_desc   *current_desc;
266989857Sobrien
267089857Sobrien	mtx_assert(&adapter->mtx, MA_OWNED);
267189857Sobrien
267289857Sobrien	ifp = &adapter->interface_data.ac_if;
267389857Sobrien	i = adapter->next_rx_desc_to_check;
267489857Sobrien        current_desc = &adapter->rx_desc_base[i];
267589857Sobrien
267689857Sobrien	if (!((current_desc->status) & E1000_RXD_STAT_DD)) {
267789857Sobrien#ifdef DBG_STATS
267889857Sobrien		adapter->no_pkts_avail++;
267989857Sobrien#endif
268089857Sobrien		return;
268189857Sobrien	}
268289857Sobrien
268389857Sobrien	while ((current_desc->status & E1000_RXD_STAT_DD) && (count != 0)) {
268489857Sobrien
268589857Sobrien		mp = adapter->rx_buffer_area[i].m_head;
268689857Sobrien		bus_dmamap_sync(adapter->rxtag, adapter->rx_buffer_area[i].map,
268789857Sobrien				BUS_DMASYNC_POSTREAD);
268889857Sobrien
268989857Sobrien		accept_frame = 1;
269089857Sobrien                desc_len = le16toh(current_desc->length);
269189857Sobrien		if (current_desc->status & E1000_RXD_STAT_EOP) {
269289857Sobrien			count--;
269389857Sobrien			eop = 1;
269489857Sobrien			len = desc_len - ETHER_CRC_LEN;
269589857Sobrien		} else {
269689857Sobrien			eop = 0;
269789857Sobrien			len = desc_len;
269889857Sobrien		}
2699104834Sobrien
2700104834Sobrien		if (current_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK) {
2701104834Sobrien			u_int8_t            last_byte;
2702104834Sobrien			u_int32_t           pkt_len = desc_len;
2703104834Sobrien
2704104834Sobrien			if (adapter->fmp != NULL)
2705104834Sobrien				pkt_len += adapter->fmp->m_pkthdr.len;
2706104834Sobrien
2707104834Sobrien			last_byte = *(mtod(mp, caddr_t) + desc_len - 1);
2708104834Sobrien
2709104834Sobrien			if (TBI_ACCEPT(&adapter->hw, current_desc->status,
2710104834Sobrien				       current_desc->errors,
2711104834Sobrien				       pkt_len, last_byte)) {
2712104834Sobrien				em_tbi_adjust_stats(&adapter->hw,
2713104834Sobrien						    &adapter->stats,
2714104834Sobrien						    pkt_len,
2715104834Sobrien						    adapter->hw.mac_addr);
2716104834Sobrien				len--;
2717104834Sobrien			}
2718104834Sobrien			else {
2719104834Sobrien				accept_frame = 0;
2720104834Sobrien			}
2721104834Sobrien		}
2722104834Sobrien
2723104834Sobrien		if (accept_frame) {
2724104834Sobrien
2725104834Sobrien			if (em_get_buf(i, adapter, NULL) == ENOBUFS) {
2726104834Sobrien				adapter->dropped_pkts++;
2727104834Sobrien				em_get_buf(i, adapter, mp);
2728104834Sobrien				if (adapter->fmp != NULL)
2729104834Sobrien					m_freem(adapter->fmp);
2730104834Sobrien				adapter->fmp = NULL;
2731104834Sobrien				adapter->lmp = NULL;
2732104834Sobrien				break;
273389857Sobrien			}
273489857Sobrien
273589857Sobrien			/* Assign correct length to the current fragment */
273689857Sobrien			mp->m_len = len;
273789857Sobrien
273889857Sobrien			if (adapter->fmp == NULL) {
273989857Sobrien				mp->m_pkthdr.len = len;
274089857Sobrien				adapter->fmp = mp;	 /* Store the first mbuf */
274189857Sobrien				adapter->lmp = mp;
274289857Sobrien			} else {
274389857Sobrien				/* Chain mbuf's together */
274489857Sobrien				mp->m_flags &= ~M_PKTHDR;
274589857Sobrien				adapter->lmp->m_next = mp;
274689857Sobrien				adapter->lmp = adapter->lmp->m_next;
274789857Sobrien				adapter->fmp->m_pkthdr.len += len;
274889857Sobrien			}
274989857Sobrien
275089857Sobrien                        if (eop) {
275189857Sobrien                                adapter->fmp->m_pkthdr.rcvif = ifp;
275289857Sobrien                                 ifp->if_ipackets++;
275389857Sobrien
275489857Sobrien#if __FreeBSD_version < 500000
275589857Sobrien                                eh = mtod(adapter->fmp, struct ether_header *);
275689857Sobrien                                /* Remove ethernet header from mbuf */
275789857Sobrien                                m_adj(adapter->fmp, sizeof(struct ether_header));
275889857Sobrien                                em_receive_checksum(adapter, current_desc,
275989857Sobrien                                                    adapter->fmp);
276089857Sobrien                                if (current_desc->status & E1000_RXD_STAT_VP)
276189857Sobrien                                        VLAN_INPUT_TAG(eh, adapter->fmp,
276289857Sobrien                                                       (current_desc->special &
276389857Sobrien							E1000_RXD_SPC_VLAN_MASK));
276489857Sobrien                                else
276589857Sobrien                                        ether_input(ifp, eh, adapter->fmp);
2766130561Sobrien#else
2767130561Sobrien
2768104834Sobrien                                em_receive_checksum(adapter, current_desc,
2769104834Sobrien                                                    adapter->fmp);
2770104834Sobrien                                if (current_desc->status & E1000_RXD_STAT_VP)
2771104834Sobrien                                        VLAN_INPUT_TAG(ifp, adapter->fmp,
2772104834Sobrien                                                       (current_desc->special &
2773104834Sobrien							E1000_RXD_SPC_VLAN_MASK),
2774104834Sobrien						       adapter->fmp = NULL);
2775104834Sobrien
2776104834Sobrien                                if (adapter->fmp != NULL) {
2777104834Sobrien					EM_UNLOCK(adapter);
2778104834Sobrien                                        (*ifp->if_input)(ifp, adapter->fmp);
2779104834Sobrien					EM_LOCK(adapter);
2780130561Sobrien				}
2781104834Sobrien#endif
278289857Sobrien                                adapter->fmp = NULL;
2783130561Sobrien                                adapter->lmp = NULL;
2784130561Sobrien                        }
2785104834Sobrien		} else {
2786104834Sobrien			adapter->dropped_pkts++;
2787104834Sobrien			em_get_buf(i, adapter, mp);
2788104834Sobrien			if (adapter->fmp != NULL)
2789104834Sobrien				m_freem(adapter->fmp);
2790104834Sobrien			adapter->fmp = NULL;
2791104834Sobrien			adapter->lmp = NULL;
2792104834Sobrien		}
2793104834Sobrien
2794104834Sobrien		/* Zero out the receive descriptors status  */
2795104834Sobrien		current_desc->status = 0;
2796104834Sobrien
2797104834Sobrien		/* Advance the E1000's Receive Queue #0  "Tail Pointer". */
2798104834Sobrien                E1000_WRITE_REG(&adapter->hw, RDT, i);
2799104834Sobrien
2800104834Sobrien                /* Advance our pointers to the next descriptor */
2801130561Sobrien                if (++i == adapter->num_rx_desc) {
2802104834Sobrien                        i = 0;
2803104834Sobrien                        current_desc = adapter->rx_desc_base;
2804130561Sobrien                } else
2805130561Sobrien			current_desc++;
2806104834Sobrien	}
2807104834Sobrien	adapter->next_rx_desc_to_check = i;
2808104834Sobrien	return;
2809104834Sobrien}
2810104834Sobrien
2811104834Sobrien/*********************************************************************
2812104834Sobrien *
2813104834Sobrien *  Verify that the hardware indicated that the checksum is valid.
2814104834Sobrien *  Inform the stack about the status of checksum so that stack
2815104834Sobrien *  doesn't spend time verifying the checksum.
2816104834Sobrien *
2817104834Sobrien *********************************************************************/
2818104834Sobrienstatic void
2819130561Sobrienem_receive_checksum(struct adapter *adapter,
2820104834Sobrien		    struct em_rx_desc *rx_desc,
2821104834Sobrien		    struct mbuf *mp)
2822130561Sobrien{
2823130561Sobrien	/* 82543 or newer only */
2824104834Sobrien	if ((adapter->hw.mac_type < em_82543) ||
2825104834Sobrien	    /* Ignore Checksum bit is set */
2826104834Sobrien	    (rx_desc->status & E1000_RXD_STAT_IXSM)) {
2827104834Sobrien		mp->m_pkthdr.csum_flags = 0;
2828104834Sobrien		return;
2829104834Sobrien	}
2830104834Sobrien
2831104834Sobrien	if (rx_desc->status & E1000_RXD_STAT_IPCS) {
2832104834Sobrien		/* Did it pass? */
2833104834Sobrien		if (!(rx_desc->errors & E1000_RXD_ERR_IPE)) {
2834104834Sobrien			/* IP Checksum Good */
2835104834Sobrien			mp->m_pkthdr.csum_flags = CSUM_IP_CHECKED;
2836104834Sobrien			mp->m_pkthdr.csum_flags |= CSUM_IP_VALID;
2837130561Sobrien
2838104834Sobrien		} else {
2839104834Sobrien			mp->m_pkthdr.csum_flags = 0;
2840130561Sobrien		}
2841130561Sobrien	}
2842104834Sobrien
2843104834Sobrien	if (rx_desc->status & E1000_RXD_STAT_TCPCS) {
2844104834Sobrien		/* Did it pass? */
2845104834Sobrien		if (!(rx_desc->errors & E1000_RXD_ERR_TCPE)) {
2846104834Sobrien			mp->m_pkthdr.csum_flags |=
2847104834Sobrien			(CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
2848104834Sobrien			mp->m_pkthdr.csum_data = htons(0xffff);
2849104834Sobrien		}
2850104834Sobrien	}
2851104834Sobrien
2852104834Sobrien	return;
2853104834Sobrien}
2854130561Sobrien
2855104834Sobrien
2856104834Sobrienstatic void
2857104834Sobrienem_enable_vlans(struct adapter *adapter)
2858104834Sobrien{
2859104834Sobrien	uint32_t ctrl;
2860104834Sobrien
2861104834Sobrien	E1000_WRITE_REG(&adapter->hw, VET, ETHERTYPE_VLAN);
2862130561Sobrien
2863104834Sobrien	ctrl = E1000_READ_REG(&adapter->hw, CTRL);
2864104834Sobrien	ctrl |= E1000_CTRL_VME;
2865130561Sobrien	E1000_WRITE_REG(&adapter->hw, CTRL, ctrl);
2866130561Sobrien
2867104834Sobrien	return;
2868104834Sobrien}
2869104834Sobrien
2870104834Sobrienstatic void
2871104834Sobrienem_enable_intr(struct adapter * adapter)
2872104834Sobrien{
2873104834Sobrien	E1000_WRITE_REG(&adapter->hw, IMS, (IMS_ENABLE_MASK));
2874104834Sobrien	return;
2875104834Sobrien}
2876104834Sobrien
2877104834Sobrienstatic void
2878104834Sobrienem_disable_intr(struct adapter *adapter)
2879104834Sobrien{
2880104834Sobrien	E1000_WRITE_REG(&adapter->hw, IMC,
2881130561Sobrien			(0xffffffff & ~E1000_IMC_RXSEQ));
2882130561Sobrien	return;
2883104834Sobrien}
2884104834Sobrien
2885104834Sobrienstatic int
2886104834Sobrienem_is_valid_ether_addr(u_int8_t *addr)
2887104834Sobrien{
2888104834Sobrien        char zero_addr[6] = { 0, 0, 0, 0, 0, 0 };
2889104834Sobrien
2890104834Sobrien        if ((addr[0] & 1) || (!bcmp(addr, zero_addr, ETHER_ADDR_LEN))) {
2891104834Sobrien                return (FALSE);
2892104834Sobrien        }
2893104834Sobrien
2894104834Sobrien        return(TRUE);
2895130561Sobrien}
2896104834Sobrien
2897130561Sobrienvoid
2898104834Sobrienem_write_pci_cfg(struct em_hw *hw,
2899104834Sobrien		      uint32_t reg,
2900104834Sobrien		      uint16_t *value)
2901104834Sobrien{
2902130561Sobrien	pci_write_config(((struct em_osdep *)hw->back)->dev, reg,
2903104834Sobrien			 *value, 2);
2904104834Sobrien}
2905130561Sobrien
2906104834Sobrienvoid
2907104834Sobrienem_read_pci_cfg(struct em_hw *hw, uint32_t reg,
2908130561Sobrien		     uint16_t *value)
2909130561Sobrien{
2910104834Sobrien	*value = pci_read_config(((struct em_osdep *)hw->back)->dev,
2911104834Sobrien				 reg, 2);
2912104834Sobrien	return;
2913104834Sobrien}
2914104834Sobrien
2915104834Sobrienvoid
2916104834Sobrienem_pci_set_mwi(struct em_hw *hw)
2917104834Sobrien{
2918104834Sobrien        pci_write_config(((struct em_osdep *)hw->back)->dev,
2919104834Sobrien                         PCIR_COMMAND,
2920104834Sobrien                         (hw->pci_cmd_word | CMD_MEM_WRT_INVALIDATE), 2);
2921104834Sobrien        return;
2922104834Sobrien}
2923104834Sobrien
2924104834Sobrienvoid
2925104834Sobrienem_pci_clear_mwi(struct em_hw *hw)
2926104834Sobrien{
2927130561Sobrien        pci_write_config(((struct em_osdep *)hw->back)->dev,
2928104834Sobrien                         PCIR_COMMAND,
2929104834Sobrien                         (hw->pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE), 2);
2930130561Sobrien        return;
2931130561Sobrien}
2932104834Sobrien
2933104834Sobrienuint32_t
2934104834Sobrienem_io_read(struct em_hw *hw, uint32_t port)
2935104834Sobrien{
2936104834Sobrien	return(inl(port));
2937104834Sobrien}
2938104834Sobrien
2939104834Sobrienvoid
2940104834Sobrienem_io_write(struct em_hw *hw, uint32_t port, uint32_t value)
2941104834Sobrien{
2942104834Sobrien	outl(port, value);
2943104834Sobrien	return;
2944104834Sobrien}
2945104834Sobrien
2946130561Sobrien/*********************************************************************
2947130561Sobrien* 82544 Coexistence issue workaround.
2948104834Sobrien*    There are 2 issues.
2949104834Sobrien*       1. Transmit Hang issue.
2950104834Sobrien*    To detect this issue, following equation can be used...
2951104834Sobrien*          SIZE[3:0] + ADDR[2:0] = SUM[3:0].
2952104834Sobrien*          If SUM[3:0] is in between 1 to 4, we will have this issue.
2953104834Sobrien*
2954104834Sobrien*       2. DAC issue.
2955104834Sobrien*    To detect this issue, following equation can be used...
2956104834Sobrien*          SIZE[3:0] + ADDR[2:0] = SUM[3:0].
2957104834Sobrien*          If SUM[3:0] is in between 9 to c, we will have this issue.
2958130561Sobrien*
2959130561Sobrien*
2960218822Sdim*    WORKAROUND:
2961104834Sobrien*          Make sure we do not have ending address as 1,2,3,4(Hang) or 9,a,b,c (DAC)
2962104834Sobrien*
2963104834Sobrien*** *********************************************************************/
2964130561Sobrienstatic u_int32_t
2965104834Sobrienem_fill_descriptors (u_int64_t address,
2966104834Sobrien                              u_int32_t length,
2967130561Sobrien                              PDESC_ARRAY desc_array)
2968104834Sobrien{
2969104834Sobrien        /* Since issue is sensitive to length and address.*/
2970104834Sobrien        /* Let us first check the address...*/
2971104834Sobrien        u_int32_t safe_terminator;
2972130561Sobrien        if (length <= 4) {
2973130561Sobrien                desc_array->descriptor[0].address = address;
2974130561Sobrien                desc_array->descriptor[0].length = length;
2975130561Sobrien                desc_array->elements = 1;
2976130561Sobrien                return desc_array->elements;
2977104834Sobrien        }
2978104834Sobrien        safe_terminator = (u_int32_t)((((u_int32_t)address & 0x7) + (length & 0xF)) & 0xF);
2979130561Sobrien        /* if it does not fall between 0x1 to 0x4 and 0x9 to 0xC then return */
2980130561Sobrien        if (safe_terminator == 0   ||
2981130561Sobrien        (safe_terminator > 4   &&
2982130561Sobrien        safe_terminator < 9)   ||
2983130561Sobrien        (safe_terminator > 0xC &&
2984130561Sobrien        safe_terminator <= 0xF)) {
2985104834Sobrien                desc_array->descriptor[0].address = address;
2986104834Sobrien                desc_array->descriptor[0].length = length;
2987104834Sobrien                desc_array->elements = 1;
2988130561Sobrien                return desc_array->elements;
2989104834Sobrien        }
2990130561Sobrien
2991104834Sobrien        desc_array->descriptor[0].address = address;
2992130561Sobrien        desc_array->descriptor[0].length = length - 4;
2993104834Sobrien        desc_array->descriptor[1].address = address + (length - 4);
2994104834Sobrien        desc_array->descriptor[1].length = 4;
2995130561Sobrien        desc_array->elements = 2;
2996130561Sobrien        return desc_array->elements;
2997104834Sobrien}
2998104834Sobrien
2999104834Sobrien/**********************************************************************
3000104834Sobrien *
3001104834Sobrien *  Update the board statistics counters.
3002130561Sobrien *
3003104834Sobrien **********************************************************************/
3004104834Sobrienstatic void
3005104834Sobrienem_update_stats_counters(struct adapter *adapter)
3006130561Sobrien{
3007104834Sobrien	struct ifnet   *ifp;
3008104834Sobrien
3009130561Sobrien	if(adapter->hw.media_type == em_media_type_copper ||
3010130561Sobrien	   (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU)) {
3011104834Sobrien		adapter->stats.symerrs += E1000_READ_REG(&adapter->hw, SYMERRS);
3012104834Sobrien		adapter->stats.sec += E1000_READ_REG(&adapter->hw, SEC);
3013104834Sobrien	}
3014104834Sobrien	adapter->stats.crcerrs += E1000_READ_REG(&adapter->hw, CRCERRS);
3015104834Sobrien	adapter->stats.mpc += E1000_READ_REG(&adapter->hw, MPC);
3016104834Sobrien	adapter->stats.scc += E1000_READ_REG(&adapter->hw, SCC);
3017104834Sobrien	adapter->stats.ecol += E1000_READ_REG(&adapter->hw, ECOL);
3018104834Sobrien
3019104834Sobrien	adapter->stats.mcc += E1000_READ_REG(&adapter->hw, MCC);
3020104834Sobrien	adapter->stats.latecol += E1000_READ_REG(&adapter->hw, LATECOL);
3021104834Sobrien	adapter->stats.colc += E1000_READ_REG(&adapter->hw, COLC);
3022104834Sobrien	adapter->stats.dc += E1000_READ_REG(&adapter->hw, DC);
3023130561Sobrien	adapter->stats.rlec += E1000_READ_REG(&adapter->hw, RLEC);
3024104834Sobrien	adapter->stats.xonrxc += E1000_READ_REG(&adapter->hw, XONRXC);
3025104834Sobrien	adapter->stats.xontxc += E1000_READ_REG(&adapter->hw, XONTXC);
3026104834Sobrien	adapter->stats.xoffrxc += E1000_READ_REG(&adapter->hw, XOFFRXC);
3027104834Sobrien	adapter->stats.xofftxc += E1000_READ_REG(&adapter->hw, XOFFTXC);
3028104834Sobrien	adapter->stats.fcruc += E1000_READ_REG(&adapter->hw, FCRUC);
3029104834Sobrien	adapter->stats.prc64 += E1000_READ_REG(&adapter->hw, PRC64);
3030104834Sobrien	adapter->stats.prc127 += E1000_READ_REG(&adapter->hw, PRC127);
3031104834Sobrien	adapter->stats.prc255 += E1000_READ_REG(&adapter->hw, PRC255);
3032104834Sobrien	adapter->stats.prc511 += E1000_READ_REG(&adapter->hw, PRC511);
3033130561Sobrien	adapter->stats.prc1023 += E1000_READ_REG(&adapter->hw, PRC1023);
3034104834Sobrien	adapter->stats.prc1522 += E1000_READ_REG(&adapter->hw, PRC1522);
3035104834Sobrien	adapter->stats.gprc += E1000_READ_REG(&adapter->hw, GPRC);
3036130561Sobrien	adapter->stats.bprc += E1000_READ_REG(&adapter->hw, BPRC);
3037130561Sobrien	adapter->stats.mprc += E1000_READ_REG(&adapter->hw, MPRC);
3038104834Sobrien	adapter->stats.gptc += E1000_READ_REG(&adapter->hw, GPTC);
3039104834Sobrien
3040104834Sobrien	/* For the 64-bit byte counters the low dword must be read first. */
3041104834Sobrien	/* Both registers clear on the read of the high dword */
3042104834Sobrien
3043130561Sobrien	adapter->stats.gorcl += E1000_READ_REG(&adapter->hw, GORCL);
3044104834Sobrien	adapter->stats.gorch += E1000_READ_REG(&adapter->hw, GORCH);
3045104834Sobrien	adapter->stats.gotcl += E1000_READ_REG(&adapter->hw, GOTCL);
3046130561Sobrien	adapter->stats.gotch += E1000_READ_REG(&adapter->hw, GOTCH);
3047130561Sobrien
3048104834Sobrien	adapter->stats.rnbc += E1000_READ_REG(&adapter->hw, RNBC);
3049104834Sobrien	adapter->stats.ruc += E1000_READ_REG(&adapter->hw, RUC);
3050104834Sobrien	adapter->stats.rfc += E1000_READ_REG(&adapter->hw, RFC);
3051130561Sobrien	adapter->stats.roc += E1000_READ_REG(&adapter->hw, ROC);
3052104834Sobrien	adapter->stats.rjc += E1000_READ_REG(&adapter->hw, RJC);
3053104834Sobrien
3054104834Sobrien	adapter->stats.torl += E1000_READ_REG(&adapter->hw, TORL);
3055130561Sobrien	adapter->stats.torh += E1000_READ_REG(&adapter->hw, TORH);
3056104834Sobrien	adapter->stats.totl += E1000_READ_REG(&adapter->hw, TOTL);
3057104834Sobrien	adapter->stats.toth += E1000_READ_REG(&adapter->hw, TOTH);
3058104834Sobrien
3059104834Sobrien	adapter->stats.tpr += E1000_READ_REG(&adapter->hw, TPR);
3060104834Sobrien	adapter->stats.tpt += E1000_READ_REG(&adapter->hw, TPT);
3061104834Sobrien	adapter->stats.ptc64 += E1000_READ_REG(&adapter->hw, PTC64);
3062104834Sobrien	adapter->stats.ptc127 += E1000_READ_REG(&adapter->hw, PTC127);
3063104834Sobrien	adapter->stats.ptc255 += E1000_READ_REG(&adapter->hw, PTC255);
3064104834Sobrien	adapter->stats.ptc511 += E1000_READ_REG(&adapter->hw, PTC511);
3065104834Sobrien	adapter->stats.ptc1023 += E1000_READ_REG(&adapter->hw, PTC1023);
3066104834Sobrien	adapter->stats.ptc1522 += E1000_READ_REG(&adapter->hw, PTC1522);
3067104834Sobrien	adapter->stats.mptc += E1000_READ_REG(&adapter->hw, MPTC);
3068104834Sobrien	adapter->stats.bptc += E1000_READ_REG(&adapter->hw, BPTC);
3069104834Sobrien
3070104834Sobrien	if (adapter->hw.mac_type >= em_82543) {
3071130561Sobrien		adapter->stats.algnerrc +=
3072104834Sobrien		E1000_READ_REG(&adapter->hw, ALGNERRC);
3073104834Sobrien		adapter->stats.rxerrc +=
3074104834Sobrien		E1000_READ_REG(&adapter->hw, RXERRC);
3075104834Sobrien		adapter->stats.tncrs +=
3076104834Sobrien		E1000_READ_REG(&adapter->hw, TNCRS);
3077104834Sobrien		adapter->stats.cexterr +=
3078104834Sobrien		E1000_READ_REG(&adapter->hw, CEXTERR);
3079104834Sobrien		adapter->stats.tsctc +=
3080104834Sobrien		E1000_READ_REG(&adapter->hw, TSCTC);
3081104834Sobrien		adapter->stats.tsctfc +=
3082104834Sobrien		E1000_READ_REG(&adapter->hw, TSCTFC);
3083130561Sobrien	}
3084104834Sobrien	ifp = &adapter->interface_data.ac_if;
3085104834Sobrien
3086104834Sobrien	/* Fill out the OS statistics structure */
3087104834Sobrien	ifp->if_ibytes = adapter->stats.gorcl;
3088104834Sobrien	ifp->if_obytes = adapter->stats.gotcl;
3089104834Sobrien	ifp->if_imcasts = adapter->stats.mprc;
3090104834Sobrien	ifp->if_collisions = adapter->stats.colc;
3091104834Sobrien
3092104834Sobrien	/* Rx Errors */
3093104834Sobrien	ifp->if_ierrors =
3094130561Sobrien	adapter->dropped_pkts +
3095104834Sobrien	adapter->stats.rxerrc +
3096104834Sobrien	adapter->stats.crcerrs +
3097130561Sobrien	adapter->stats.algnerrc +
3098104834Sobrien	adapter->stats.rlec + adapter->stats.rnbc +
3099130561Sobrien	adapter->stats.mpc + adapter->stats.cexterr;
3100104834Sobrien
3101104834Sobrien	/* Tx Errors */
3102104834Sobrien	ifp->if_oerrors = adapter->stats.ecol + adapter->stats.latecol;
3103104834Sobrien
3104104834Sobrien}
3105104834Sobrien
3106104834Sobrien
3107130561Sobrien/**********************************************************************
3108130561Sobrien *
3109104834Sobrien *  This routine is called only when em_display_debug_stats is enabled.
3110104834Sobrien *  This routine provides a way to take a look at important statistics
3111104834Sobrien *  maintained by the driver and hardware.
3112104834Sobrien *
3113104834Sobrien **********************************************************************/
3114104834Sobrienstatic void
3115104834Sobrienem_print_debug_info(struct adapter *adapter)
3116130561Sobrien{
3117104834Sobrien        int unit = adapter->unit;
3118130561Sobrien
3119130561Sobrien#ifdef DBG_STATS
3120104834Sobrien        printf("em%d: Packets not Avail = %ld\n", unit,
3121104834Sobrien               adapter->no_pkts_avail);
3122130561Sobrien        printf("em%d: CleanTxInterrupts = %ld\n", unit,
3123130561Sobrien               adapter->clean_tx_interrupts);
3124104834Sobrien#endif
3125104834Sobrien        printf("em%d: fifo workaround = %lld, fifo_reset = %lld\n", unit,
3126104834Sobrien               (long long)adapter->tx_fifo_wrk,
3127104834Sobrien               (long long)adapter->tx_fifo_reset);
3128104834Sobrien        printf("em%d: hw tdh = %d, hw tdt = %d\n", unit,
3129104834Sobrien               E1000_READ_REG(&adapter->hw, TDH),
3130104834Sobrien               E1000_READ_REG(&adapter->hw, TDT));
3131130561Sobrien        printf("em%d: Num Tx descriptors avail = %d\n", unit,
3132104834Sobrien               adapter->num_tx_desc_avail);
3133104834Sobrien        printf("em%d: Tx Descriptors not avail1 = %ld\n", unit,
3134104834Sobrien               adapter->no_tx_desc_avail1);
3135104834Sobrien        printf("em%d: Tx Descriptors not avail2 = %ld\n", unit,
3136104834Sobrien               adapter->no_tx_desc_avail2);
3137104834Sobrien        printf("em%d: Std mbuf failed = %ld\n", unit,
3138104834Sobrien               adapter->mbuf_alloc_failed);
3139104834Sobrien        printf("em%d: Std mbuf cluster failed = %ld\n", unit,
3140104834Sobrien               adapter->mbuf_cluster_failed);
3141104834Sobrien        printf("em%d: Driver dropped packets = %ld\n", unit,
3142130561Sobrien               adapter->dropped_pkts);
3143104834Sobrien
3144104834Sobrien        return;
3145104834Sobrien}
3146104834Sobrien
3147104834Sobrienstatic void
3148104834Sobrienem_print_hw_stats(struct adapter *adapter)
3149130561Sobrien{
3150130561Sobrien        int unit = adapter->unit;
3151104834Sobrien
3152104834Sobrien        printf("em%d: Excessive collisions = %lld\n", unit,
3153104834Sobrien               (long long)adapter->stats.ecol);
3154104834Sobrien        printf("em%d: Symbol errors = %lld\n", unit,
3155104834Sobrien               (long long)adapter->stats.symerrs);
3156104834Sobrien        printf("em%d: Sequence errors = %lld\n", unit,
3157104834Sobrien               (long long)adapter->stats.sec);
3158104834Sobrien        printf("em%d: Defer count = %lld\n", unit,
3159104834Sobrien               (long long)adapter->stats.dc);
3160104834Sobrien
3161104834Sobrien        printf("em%d: Missed Packets = %lld\n", unit,
3162104834Sobrien               (long long)adapter->stats.mpc);
3163130561Sobrien        printf("em%d: Receive No Buffers = %lld\n", unit,
3164104834Sobrien               (long long)adapter->stats.rnbc);
3165130561Sobrien        printf("em%d: Receive length errors = %lld\n", unit,
3166104834Sobrien               (long long)adapter->stats.rlec);
3167104834Sobrien        printf("em%d: Receive errors = %lld\n", unit,
3168130561Sobrien               (long long)adapter->stats.rxerrc);
3169104834Sobrien        printf("em%d: Crc errors = %lld\n", unit,
3170104834Sobrien               (long long)adapter->stats.crcerrs);
3171104834Sobrien        printf("em%d: Alignment errors = %lld\n", unit,
3172104834Sobrien               (long long)adapter->stats.algnerrc);
3173104834Sobrien        printf("em%d: Carrier extension errors = %lld\n", unit,
3174104834Sobrien               (long long)adapter->stats.cexterr);
3175104834Sobrien
3176104834Sobrien        printf("em%d: XON Rcvd = %lld\n", unit,
3177104834Sobrien               (long long)adapter->stats.xonrxc);
3178104834Sobrien        printf("em%d: XON Xmtd = %lld\n", unit,
3179130561Sobrien               (long long)adapter->stats.xontxc);
3180130561Sobrien        printf("em%d: XOFF Rcvd = %lld\n", unit,
3181130561Sobrien               (long long)adapter->stats.xoffrxc);
3182104834Sobrien        printf("em%d: XOFF Xmtd = %lld\n", unit,
3183104834Sobrien               (long long)adapter->stats.xofftxc);
3184130561Sobrien
3185130561Sobrien        printf("em%d: Good Packets Rcvd = %lld\n", unit,
3186104834Sobrien               (long long)adapter->stats.gprc);
3187104834Sobrien        printf("em%d: Good Packets Xmtd = %lld\n", unit,
3188104834Sobrien               (long long)adapter->stats.gptc);
3189130561Sobrien
3190104834Sobrien        return;
3191104834Sobrien}
3192104834Sobrien
3193130561Sobrienstatic int
3194104834Sobrienem_sysctl_debug_info(SYSCTL_HANDLER_ARGS)
3195104834Sobrien{
3196104834Sobrien        int error;
3197104834Sobrien        int result;
3198104834Sobrien        struct adapter *adapter;
3199104834Sobrien
3200104834Sobrien        result = -1;
3201104834Sobrien        error = sysctl_handle_int(oidp, &result, 0, req);
3202104834Sobrien
3203104834Sobrien        if (error || !req->newptr)
3204104834Sobrien                return (error);
3205104834Sobrien
3206104834Sobrien        if (result == 1) {
3207104834Sobrien                adapter = (struct adapter *)arg1;
3208104834Sobrien                em_print_debug_info(adapter);
3209104834Sobrien        }
3210104834Sobrien
3211104834Sobrien        return error;
3212104834Sobrien}
3213104834Sobrien
3214104834Sobrien
3215104834Sobrienstatic int
3216104834Sobrienem_sysctl_stats(SYSCTL_HANDLER_ARGS)
3217104834Sobrien{
3218130561Sobrien        int error;
3219130561Sobrien        int result;
3220130561Sobrien        struct adapter *adapter;
3221104834Sobrien
3222104834Sobrien        result = -1;
322389857Sobrien        error = sysctl_handle_int(oidp, &result, 0, req);
322489857Sobrien
3225130561Sobrien        if (error || !req->newptr)
322689857Sobrien                return (error);
3227104834Sobrien
3228104834Sobrien        if (result == 1) {
3229104834Sobrien                adapter = (struct adapter *)arg1;
3230104834Sobrien                em_print_hw_stats(adapter);
3231130561Sobrien        }
3232104834Sobrien
3233130561Sobrien        return error;
3234104834Sobrien}
3235104834Sobrien
3236104834Sobrienstatic int
3237104834Sobrienem_sysctl_int_delay(SYSCTL_HANDLER_ARGS)
3238130561Sobrien{
3239104834Sobrien	struct em_int_delay_info *info;
3240104834Sobrien	struct adapter *adapter;
3241104834Sobrien	u_int32_t regval;
3242104834Sobrien	int error;
3243130561Sobrien	int usecs;
3244104834Sobrien	int ticks;
3245104834Sobrien	int s;
3246104834Sobrien
3247104834Sobrien	info = (struct em_int_delay_info *)arg1;
3248104834Sobrien	adapter = info->adapter;
3249104834Sobrien	usecs = info->value;
3250104834Sobrien	error = sysctl_handle_int(oidp, &usecs, 0, req);
3251130561Sobrien	if (error != 0 || req->newptr == NULL)
3252104834Sobrien		return error;
3253104834Sobrien	if (usecs < 0 || usecs > E1000_TICKS_TO_USECS(65535))
3254104834Sobrien		return EINVAL;
3255104834Sobrien	info->value = usecs;
3256104834Sobrien	ticks = E1000_USECS_TO_TICKS(usecs);
3257104834Sobrien
3258104834Sobrien	s = splimp();
3259104834Sobrien	regval = E1000_READ_OFFSET(&adapter->hw, info->offset);
3260104834Sobrien	regval = (regval & ~0xffff) | (ticks & 0xffff);
3261104834Sobrien	/* Handle a few special cases. */
3262104834Sobrien	switch (info->offset) {
3263104834Sobrien	case E1000_RDTR:
3264104834Sobrien	case E1000_82542_RDTR:
3265104834Sobrien		regval |= E1000_RDT_FPDB;
3266104834Sobrien		break;
3267104834Sobrien	case E1000_TIDV:
3268104834Sobrien	case E1000_82542_TIDV:
3269130561Sobrien		if (ticks == 0) {
3270104834Sobrien			adapter->txd_cmd &= ~E1000_TXD_CMD_IDE;
3271104834Sobrien			/* Don't write 0 into the TIDV register. */
3272104834Sobrien			regval++;
3273130561Sobrien		} else
3274104834Sobrien			adapter->txd_cmd |= E1000_TXD_CMD_IDE;
3275104834Sobrien		break;
3276104834Sobrien	}
3277104834Sobrien	E1000_WRITE_OFFSET(&adapter->hw, info->offset, regval);
3278130561Sobrien	splx(s);
3279104834Sobrien	return 0;
3280104834Sobrien}
3281104834Sobrien
3282104834Sobrienstatic void
3283104834Sobrienem_add_int_delay_sysctl(struct adapter *adapter, const char *name,
3284104834Sobrien    const char *description, struct em_int_delay_info *info,
3285104834Sobrien    int offset, int value)
3286104834Sobrien{
3287104834Sobrien	info->adapter = adapter;
3288130561Sobrien	info->offset = offset;
3289104834Sobrien	info->value = value;
3290104834Sobrien	SYSCTL_ADD_PROC(&adapter->sysctl_ctx,
3291104834Sobrien	    SYSCTL_CHILDREN(adapter->sysctl_tree),
3292104834Sobrien	    OID_AUTO, name, CTLTYPE_INT|CTLFLAG_RW,
3293130561Sobrien	    info, 0, em_sysctl_int_delay, "I", description);
3294130561Sobrien}
3295104834Sobrien