if_em.c revision 103895
189857Sobrien/**************************************************************************
289857Sobrien
389857SobrienCopyright (c) 2001-2002, Intel Corporation
489857SobrienAll rights reserved.
589857Sobrien
689857SobrienRedistribution and use in source and binary forms, with or without
777298Sobrienmodification, are permitted provided that the following conditions are met:
877298Sobrien
977298Sobrien 1. Redistributions of source code must retain the above copyright notice,
1077298Sobrien    this list of conditions and the following disclaimer.
1177298Sobrien
1277298Sobrien 2. Redistributions in binary form must reproduce the above copyright
1377298Sobrien    notice, this list of conditions and the following disclaimer in the
1477298Sobrien    documentation and/or other materials provided with the distribution.
1577298Sobrien
1677298Sobrien 3. Neither the name of the Intel Corporation nor the names of its
1777298Sobrien    contributors may be used to endorse or promote products derived from
1877298Sobrien    this software without specific prior written permission.
1977298Sobrien
2077298SobrienTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2177298SobrienAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2277298SobrienIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2377298SobrienARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
2477298SobrienLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2577298SobrienCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2677298SobrienSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2777298SobrienINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2877298SobrienCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2977298SobrienARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3077298SobrienPOSSIBILITY OF SUCH DAMAGE.
3177298Sobrien
3277298Sobrien***************************************************************************/
3377298Sobrien
3477298Sobrien/*$FreeBSD: head/sys/dev/em/if_em.c 103895 2002-09-24 16:27:59Z pdeuskar $*/
3577298Sobrien
3677298Sobrien#include <dev/em/if_em.h>
3777298Sobrien
3877298Sobrien/*********************************************************************
3977298Sobrien *  Set this to one to display debug statistics
4077298Sobrien *********************************************************************/
4177298Sobrienint             em_display_debug_stats = 0;
4277298Sobrien
4377298Sobrien/*********************************************************************
4477298Sobrien *  Linked list of board private structures for all NICs found
4577298Sobrien *********************************************************************/
4677298Sobrien
4777298Sobrienstruct adapter *em_adapter_list = NULL;
4877298Sobrien
4977298Sobrien
5077298Sobrien/*********************************************************************
5177298Sobrien *  Driver version
5277298Sobrien *********************************************************************/
5377298Sobrien
5477298Sobrienchar em_driver_version[] = "1.3.14";
5577298Sobrien
5677298Sobrien
5777298Sobrien/*********************************************************************
5877298Sobrien *  PCI Device ID Table
5977298Sobrien *
6077298Sobrien *  Used by probe to select devices to load on
6177298Sobrien *  Last field stores an index into em_strings
6277298Sobrien *  Last entry must be all 0s
6377298Sobrien *
6477298Sobrien *  { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index }
6577298Sobrien *********************************************************************/
6677298Sobrienstatic em_vendor_info_t em_vendor_info_array[] =
6777298Sobrien{
6877298Sobrien	/* Intel(R) PRO/1000 Network Connection */
6977298Sobrien	{ 0x8086, 0x1000, PCI_ANY_ID, PCI_ANY_ID, 0},
7077298Sobrien	{ 0x8086, 0x1001, PCI_ANY_ID, PCI_ANY_ID, 0},
7177298Sobrien	{ 0x8086, 0x1004, PCI_ANY_ID, PCI_ANY_ID, 0},
7277298Sobrien	{ 0x8086, 0x1008, PCI_ANY_ID, PCI_ANY_ID, 0},
7377298Sobrien	{ 0x8086, 0x1009, PCI_ANY_ID, PCI_ANY_ID, 0},
7477298Sobrien	{ 0x8086, 0x100C, PCI_ANY_ID, PCI_ANY_ID, 0},
7577298Sobrien	{ 0x8086, 0x100D, PCI_ANY_ID, PCI_ANY_ID, 0},
7677298Sobrien	{ 0x8086, 0x100E, PCI_ANY_ID, PCI_ANY_ID, 0},
7777298Sobrien	{ 0x8086, 0x100F, PCI_ANY_ID, PCI_ANY_ID, 0},
7877298Sobrien	{ 0x8086, 0x1010, PCI_ANY_ID, PCI_ANY_ID, 0},
7977298Sobrien	{ 0x8086, 0x1011, PCI_ANY_ID, PCI_ANY_ID, 0},
8077298Sobrien	{ 0x8086, 0x1012, PCI_ANY_ID, PCI_ANY_ID, 0},
8177298Sobrien	/* required last entry */
8277298Sobrien	{ 0, 0, 0, 0, 0}
8377298Sobrien};
8477298Sobrien
8577298Sobrien
8677298Sobrien/*********************************************************************
8777298Sobrien *  Table of branding strings for all supported NICs.
8877298Sobrien *********************************************************************/
8977298Sobrien
9077298Sobrienstatic char *em_strings[] = {
9177298Sobrien	"Intel(R) PRO/1000 Network Connection"
9277298Sobrien};
9377298Sobrien
9477298Sobrien/*********************************************************************
9577298Sobrien *  Function prototypes
9677298Sobrien *********************************************************************/
9777298Sobrienstatic int  em_probe(device_t);
9877298Sobrienstatic int  em_attach(device_t);
9977298Sobrienstatic int  em_detach(device_t);
10077298Sobrienstatic int  em_shutdown(device_t);
10177298Sobrienstatic void em_intr(void *);
10277298Sobrienstatic void em_start(struct ifnet *);
10377298Sobrienstatic int  em_ioctl(struct ifnet *, IOCTL_CMD_TYPE, caddr_t);
10477298Sobrienstatic void em_watchdog(struct ifnet *);
10577298Sobrienstatic void em_init(void *);
10677298Sobrienstatic void em_stop(void *);
10777298Sobrienstatic void em_media_status(struct ifnet *, struct ifmediareq *);
10877298Sobrienstatic int  em_media_change(struct ifnet *);
10977298Sobrienstatic void em_identify_hardware(struct adapter *);
11077298Sobrienstatic int  em_allocate_pci_resources(struct adapter *);
11177298Sobrienstatic void em_free_pci_resources(struct adapter *);
11277298Sobrienstatic void em_local_timer(void *);
11377298Sobrienstatic int  em_hardware_init(struct adapter *);
11477298Sobrienstatic void em_setup_interface(device_t, struct adapter *);
11577298Sobrienstatic int  em_setup_transmit_structures(struct adapter *);
11677298Sobrienstatic void em_initialize_transmit_unit(struct adapter *);
11777298Sobrienstatic int  em_setup_receive_structures(struct adapter *);
11877298Sobrienstatic void em_initialize_receive_unit(struct adapter *);
11977298Sobrienstatic void em_enable_intr(struct adapter *);
12077298Sobrienstatic void em_disable_intr(struct adapter *);
12177298Sobrienstatic void em_free_transmit_structures(struct adapter *);
12277298Sobrienstatic void em_free_receive_structures(struct adapter *);
12377298Sobrienstatic void em_update_stats_counters(struct adapter *);
12477298Sobrienstatic void em_clean_transmit_interrupts(struct adapter *);
12577298Sobrienstatic int  em_allocate_receive_structures(struct adapter *);
12677298Sobrienstatic int  em_allocate_transmit_structures(struct adapter *);
12777298Sobrienstatic void em_process_receive_interrupts(struct adapter *);
12877298Sobrienstatic void em_receive_checksum(struct adapter *,
12977298Sobrien				     struct em_rx_desc * rx_desc,
13077298Sobrien				     struct mbuf *);
13177298Sobrienstatic void em_transmit_checksum_setup(struct adapter *,
13277298Sobrien					    struct mbuf *,
13377298Sobrien					    struct em_tx_buffer *,
13477298Sobrien					    u_int32_t *,
13577298Sobrien					    u_int32_t *);
13677298Sobrienstatic void em_set_promisc(struct adapter *);
13777298Sobrienstatic void em_disable_promisc(struct adapter *);
13877298Sobrienstatic void em_set_multi(struct adapter *);
13977298Sobrienstatic void em_print_hw_stats(struct adapter *);
14077298Sobrienstatic void em_print_link_status(struct adapter *);
14177298Sobrienstatic int  em_get_buf(struct em_rx_buffer *, struct adapter *,
14277298Sobrien			    struct mbuf *);
14377298Sobrienstatic void em_enable_vlans(struct adapter *adapter);
14477298Sobrien
14577298Sobrien/*********************************************************************
14677298Sobrien *  FreeBSD Device Interface Entry Points
14777298Sobrien *********************************************************************/
14877298Sobrien
14977298Sobrienstatic device_method_t em_methods[] = {
15077298Sobrien	/* Device interface */
15177298Sobrien	DEVMETHOD(device_probe, em_probe),
15277298Sobrien	DEVMETHOD(device_attach, em_attach),
15377298Sobrien	DEVMETHOD(device_detach, em_detach),
15477298Sobrien	DEVMETHOD(device_shutdown, em_shutdown),
15577298Sobrien	{0, 0}
15677298Sobrien};
15777298Sobrien
15877298Sobrienstatic driver_t em_driver = {
15977298Sobrien	"em", em_methods, sizeof(struct adapter ),
16077298Sobrien};
16177298Sobrien
16277298Sobrienstatic devclass_t em_devclass;
16377298SobrienDRIVER_MODULE(if_em, pci, em_driver, em_devclass, 0, 0);
16477298Sobrien
16577298Sobrien/*********************************************************************
16677298Sobrien *  Device identification routine
16777298Sobrien *
16877298Sobrien *  em_probe determines if the driver should be loaded on
16977298Sobrien *  adapter based on PCI vendor/device id of the adapter.
17077298Sobrien *
17177298Sobrien *  return 0 on success, positive on failure
17277298Sobrien *********************************************************************/
17377298Sobrien
17477298Sobrienstatic int
17577298Sobrienem_probe(device_t dev)
17677298Sobrien{
17777298Sobrien	em_vendor_info_t *ent;
17877298Sobrien
17977298Sobrien	u_int16_t       pci_vendor_id = 0;
18077298Sobrien	u_int16_t       pci_device_id = 0;
18177298Sobrien	u_int16_t       pci_subvendor_id = 0;
18277298Sobrien	u_int16_t       pci_subdevice_id = 0;
18389857Sobrien	char            adapter_name[60];
18489857Sobrien
18577298Sobrien	INIT_DEBUGOUT("em_probe: begin");
18677298Sobrien
18777298Sobrien	pci_vendor_id = pci_get_vendor(dev);
18877298Sobrien	if (pci_vendor_id != EM_VENDOR_ID)
18977298Sobrien		return(ENXIO);
19077298Sobrien
19177298Sobrien	pci_device_id = pci_get_device(dev);
19277298Sobrien	pci_subvendor_id = pci_get_subvendor(dev);
19377298Sobrien	pci_subdevice_id = pci_get_subdevice(dev);
19477298Sobrien
19577298Sobrien	ent = em_vendor_info_array;
19677298Sobrien	while (ent->vendor_id != 0) {
19777298Sobrien		if ((pci_vendor_id == ent->vendor_id) &&
19877298Sobrien		    (pci_device_id == ent->device_id) &&
19977298Sobrien
20077298Sobrien		    ((pci_subvendor_id == ent->subvendor_id) ||
20177298Sobrien		     (ent->subvendor_id == PCI_ANY_ID)) &&
20277298Sobrien
20377298Sobrien		    ((pci_subdevice_id == ent->subdevice_id) ||
20477298Sobrien		     (ent->subdevice_id == PCI_ANY_ID))) {
20577298Sobrien			sprintf(adapter_name, "%s, Version - %s",
20677298Sobrien				em_strings[ent->index],
20777298Sobrien				em_driver_version);
20877298Sobrien			device_set_desc_copy(dev, adapter_name);
20977298Sobrien			return(0);
21077298Sobrien		}
21177298Sobrien		ent++;
21277298Sobrien	}
21377298Sobrien
21477298Sobrien	return(ENXIO);
21577298Sobrien}
21677298Sobrien
21777298Sobrien/*********************************************************************
21877298Sobrien *  Device initialization routine
21977298Sobrien *
22077298Sobrien *  The attach entry point is called when the driver is being loaded.
22177298Sobrien *  This routine identifies the type of hardware, allocates all resources
22277298Sobrien *  and initializes the hardware.
22377298Sobrien *
22477298Sobrien *  return 0 on success, positive on failure
22577298Sobrien *********************************************************************/
22677298Sobrien
22777298Sobrienstatic int
22877298Sobrienem_attach(device_t dev)
22977298Sobrien{
23077298Sobrien	struct adapter * adapter;
23177298Sobrien	int             s;
23277298Sobrien	int             tsize, rsize;
23377298Sobrien
23477298Sobrien	INIT_DEBUGOUT("em_attach: begin");
23577298Sobrien	s = splimp();
23677298Sobrien
23777298Sobrien	/* Allocate, clear, and link in our adapter structure */
23877298Sobrien	if (!(adapter = device_get_softc(dev))) {
23977298Sobrien		printf("em: adapter structure allocation failed\n");
24077298Sobrien		splx(s);
24177298Sobrien		return(ENOMEM);
24277298Sobrien	}
24377298Sobrien	bzero(adapter, sizeof(struct adapter ));
24477298Sobrien	adapter->dev = dev;
24577298Sobrien	adapter->osdep.dev = dev;
24677298Sobrien	adapter->unit = device_get_unit(dev);
24777298Sobrien
24877298Sobrien	if (em_adapter_list != NULL)
24977298Sobrien		em_adapter_list->prev = adapter;
25077298Sobrien	adapter->next = em_adapter_list;
25177298Sobrien	em_adapter_list = adapter;
25277298Sobrien
25377298Sobrien	callout_handle_init(&adapter->timer_handle);
25477298Sobrien
25577298Sobrien	/* Determine hardware revision */
25677298Sobrien	em_identify_hardware(adapter);
25777298Sobrien
25877298Sobrien	/* Parameters (to be read from user) */
25977298Sobrien	adapter->num_tx_desc = MAX_TXD;
26077298Sobrien	adapter->num_rx_desc = MAX_RXD;
26177298Sobrien	adapter->tx_int_delay = TIDV;
26277298Sobrien	adapter->rx_int_delay = RIDV;
26377298Sobrien	adapter->hw.autoneg = DO_AUTO_NEG;
26477298Sobrien	adapter->hw.wait_autoneg_complete = WAIT_FOR_AUTO_NEG_DEFAULT;
26577298Sobrien	adapter->hw.autoneg_advertised = AUTONEG_ADV_DEFAULT;
26677298Sobrien	adapter->hw.tbi_compatibility_en = TRUE;
26777298Sobrien	adapter->rx_buffer_len = EM_RXBUFFER_2048;
26877298Sobrien
26977298Sobrien	adapter->hw.fc_high_water = FC_DEFAULT_HI_THRESH;
27077298Sobrien	adapter->hw.fc_low_water  = FC_DEFAULT_LO_THRESH;
27177298Sobrien	adapter->hw.fc_pause_time = FC_DEFAULT_TX_TIMER;
27277298Sobrien	adapter->hw.fc_send_xon   = TRUE;
27377298Sobrien	adapter->hw.fc = em_fc_full;
27477298Sobrien
27577298Sobrien	/* Set the max frame size assuming standard ethernet sized frames */
27677298Sobrien	adapter->hw.max_frame_size =
27777298Sobrien	ETHERMTU + ETHER_HDR_LEN + ETHER_CRC_LEN;
27877298Sobrien
27977298Sobrien	adapter->hw.min_frame_size =
28077298Sobrien	MINIMUM_ETHERNET_PACKET_SIZE + ETHER_CRC_LEN;
28177298Sobrien
28277298Sobrien	/* This controls when hardware reports transmit completion status. */
28377298Sobrien	if ((EM_REPORT_TX_EARLY == 0) || (EM_REPORT_TX_EARLY == 1)) {
28477298Sobrien		adapter->hw.report_tx_early = EM_REPORT_TX_EARLY;
28577298Sobrien	} else {
28677298Sobrien		if (adapter->hw.mac_type < em_82543) {
28777298Sobrien			adapter->hw.report_tx_early = 0;
28877298Sobrien		} else {
28977298Sobrien			adapter->hw.report_tx_early = 1;
29077298Sobrien		}
29177298Sobrien	}
29277298Sobrien
29377298Sobrien	if (em_allocate_pci_resources(adapter)) {
29477298Sobrien		printf("em%d: Allocation of PCI resources failed\n",
29577298Sobrien		       adapter->unit);
29677298Sobrien		em_free_pci_resources(adapter);
29777298Sobrien		splx(s);
29877298Sobrien		return(ENXIO);
29977298Sobrien	}
30077298Sobrien
30177298Sobrien	tsize = EM_ROUNDUP(adapter->num_tx_desc *
30277298Sobrien			   sizeof(struct em_tx_desc), 4096);
30377298Sobrien
30477298Sobrien	/* Allocate Transmit Descriptor ring */
30577298Sobrien	if (!(adapter->tx_desc_base = (struct em_tx_desc *)
30677298Sobrien	      contigmalloc(tsize, M_DEVBUF, M_NOWAIT, 0, ~0, PAGE_SIZE, 0))) {
30777298Sobrien		printf("em%d: Unable to allocate TxDescriptor memory\n",
30877298Sobrien		       adapter->unit);
30977298Sobrien		em_free_pci_resources(adapter);
31077298Sobrien		splx(s);
31177298Sobrien		return(ENOMEM);
31277298Sobrien	}
31377298Sobrien
31477298Sobrien	rsize = EM_ROUNDUP(adapter->num_rx_desc *
31577298Sobrien			   sizeof(struct em_rx_desc), 4096);
31677298Sobrien
31777298Sobrien	/* Allocate Receive Descriptor ring */
31877298Sobrien	if (!(adapter->rx_desc_base = (struct em_rx_desc *)
31977298Sobrien	      contigmalloc(rsize, M_DEVBUF, M_NOWAIT, 0, ~0, PAGE_SIZE, 0))) {
32077298Sobrien		printf("em%d: Unable to allocate rx_desc memory\n",
32177298Sobrien		       adapter->unit);
32277298Sobrien		em_free_pci_resources(adapter);
32377298Sobrien		contigfree(adapter->tx_desc_base, tsize, M_DEVBUF);
32477298Sobrien		splx(s);
32577298Sobrien		return(ENOMEM);
32677298Sobrien	}
32777298Sobrien
32877298Sobrien	/* Initialize the hardware */
32977298Sobrien	if (em_hardware_init(adapter)) {
33077298Sobrien		printf("em%d: Unable to initialize the hardware\n",
33177298Sobrien		       adapter->unit);
33277298Sobrien		em_free_pci_resources(adapter);
33377298Sobrien		contigfree(adapter->tx_desc_base, tsize, M_DEVBUF);
33477298Sobrien		contigfree(adapter->rx_desc_base, rsize, M_DEVBUF);
33577298Sobrien		splx(s);
33677298Sobrien		return(EIO);
33777298Sobrien	}
33877298Sobrien
33977298Sobrien	/* Copy the permanent MAC address out of the EEPROM */
34077298Sobrien	if (em_read_mac_addr(&adapter->hw) < 0) {
34177298Sobrien		printf("em%d: EEPROM read error while reading mac address\n",
34277298Sobrien		       adapter->unit);
34377298Sobrien		return(EIO);
34477298Sobrien	}
34577298Sobrien
34677298Sobrien	memcpy(adapter->interface_data.ac_enaddr, adapter->hw.mac_addr,
34777298Sobrien	       ETH_LENGTH_OF_ADDRESS);
34877298Sobrien
34977298Sobrien	/* Setup OS specific network interface */
35077298Sobrien	em_setup_interface(dev, adapter);
35177298Sobrien
35277298Sobrien	/* Initialize statistics */
35377298Sobrien	em_clear_hw_cntrs(&adapter->hw);
35477298Sobrien	em_update_stats_counters(adapter);
35577298Sobrien	adapter->hw.get_link_status = 1;
35677298Sobrien	em_check_for_link(&adapter->hw);
35777298Sobrien
35877298Sobrien	/* Print the link status */
35977298Sobrien	if (adapter->link_active == 1) {
36077298Sobrien		em_get_speed_and_duplex(&adapter->hw, &adapter->link_speed,
36177298Sobrien					&adapter->link_duplex);
36277298Sobrien		printf("em%d:  Speed:%d Mbps  Duplex:%s\n",
36377298Sobrien		       adapter->unit,
36477298Sobrien		       adapter->link_speed,
36577298Sobrien		       adapter->link_duplex == FULL_DUPLEX ? "Full" : "Half");
36677298Sobrien	} else
36777298Sobrien		printf("em%d:  Speed:N/A  Duplex:N/A\n", adapter->unit);
36877298Sobrien
36977298Sobrien
37077298Sobrien	INIT_DEBUGOUT("em_attach: end");
37177298Sobrien	splx(s);
37277298Sobrien	return(0);
37377298Sobrien}
37477298Sobrien
37577298Sobrien/*********************************************************************
37677298Sobrien *  Device removal routine
37777298Sobrien *
37877298Sobrien *  The detach entry point is called when the driver is being removed.
37977298Sobrien *  This routine stops the adapter and deallocates all the resources
38077298Sobrien *  that were allocated for driver operation.
38177298Sobrien *
38277298Sobrien *  return 0 on success, positive on failure
38377298Sobrien *********************************************************************/
38477298Sobrien
38577298Sobrienstatic int
38677298Sobrienem_detach(device_t dev)
38777298Sobrien{
38889857Sobrien	struct adapter * adapter = device_get_softc(dev);
38977298Sobrien	struct ifnet   *ifp = &adapter->interface_data.ac_if;
39077298Sobrien	int             s;
39177298Sobrien	int             size;
39277298Sobrien
39377298Sobrien	INIT_DEBUGOUT("em_detach: begin");
39477298Sobrien	s = splimp();
39577298Sobrien
39677298Sobrien	em_stop(adapter);
39777298Sobrien	em_phy_hw_reset(&adapter->hw);
39877298Sobrien	ether_ifdetach(&adapter->interface_data.ac_if, ETHER_BPF_SUPPORTED);
39977298Sobrien	em_free_pci_resources(adapter);
40077298Sobrien
40177298Sobrien	size = EM_ROUNDUP(adapter->num_tx_desc *
40277298Sobrien			  sizeof(struct em_tx_desc), 4096);
40377298Sobrien
40477298Sobrien	/* Free Transmit Descriptor ring */
40577298Sobrien	if (adapter->tx_desc_base) {
40677298Sobrien		contigfree(adapter->tx_desc_base, size, M_DEVBUF);
40777298Sobrien		adapter->tx_desc_base = NULL;
40877298Sobrien	}
40977298Sobrien
41077298Sobrien	size = EM_ROUNDUP(adapter->num_rx_desc *
41177298Sobrien			  sizeof(struct em_rx_desc), 4096);
41277298Sobrien
41377298Sobrien	/* Free Receive Descriptor ring */
41477298Sobrien	if (adapter->rx_desc_base) {
41577298Sobrien		contigfree(adapter->rx_desc_base, size, M_DEVBUF);
41677298Sobrien		adapter->rx_desc_base = NULL;
41777298Sobrien	}
41877298Sobrien
41977298Sobrien	/* Remove from the adapter list */
42077298Sobrien	if (em_adapter_list == adapter)
42177298Sobrien		em_adapter_list = adapter->next;
42277298Sobrien	if (adapter->next != NULL)
42377298Sobrien		adapter->next->prev = adapter->prev;
42477298Sobrien	if (adapter->prev != NULL)
42577298Sobrien		adapter->prev->next = adapter->next;
42677298Sobrien
42777298Sobrien	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
42877298Sobrien	ifp->if_timer = 0;
42977298Sobrien
43077298Sobrien	splx(s);
43177298Sobrien	return(0);
43277298Sobrien}
43377298Sobrien
43477298Sobrienstatic int
43577298Sobrienem_shutdown(device_t dev)
43677298Sobrien{
43777298Sobrien	struct adapter *adapter = device_get_softc(dev);
43877298Sobrien	em_stop(adapter);
43977298Sobrien	return(0);
44077298Sobrien}
44177298Sobrien
44277298Sobrien
44377298Sobrien/*********************************************************************
44477298Sobrien *  Transmit entry point
44577298Sobrien *
44677298Sobrien *  em_start is called by the stack to initiate a transmit.
44777298Sobrien *  The driver will remain in this routine as long as there are
44877298Sobrien *  packets to transmit and transmit resources are available.
44977298Sobrien *  In case resources are not available stack is notified and
45077298Sobrien *  the packet is requeued.
45177298Sobrien **********************************************************************/
45277298Sobrien
45377298Sobrienstatic void
45477298Sobrienem_start(struct ifnet *ifp)
45577298Sobrien{
45677298Sobrien	int             s;
45777298Sobrien	struct mbuf    *m_head, *mp;
45877298Sobrien	vm_offset_t     virtual_addr;
45977298Sobrien	u_int32_t       txd_upper;
46077298Sobrien	u_int32_t       txd_lower;
46177298Sobrien	struct em_tx_buffer   *tx_buffer;
46277298Sobrien	struct em_tx_desc *current_tx_desc = NULL;
46377298Sobrien	struct adapter * adapter = ifp->if_softc;
46477298Sobrien
46577298Sobrien	if (!adapter->link_active)
46677298Sobrien		return;
46777298Sobrien
46877298Sobrien	s = splimp();
46977298Sobrien	while (ifp->if_snd.ifq_head != NULL) {
47077298Sobrien		struct ifvlan *ifv = NULL;
47177298Sobrien
47277298Sobrien		IF_DEQUEUE(&ifp->if_snd, m_head);
47377298Sobrien
47477298Sobrien		if (m_head == NULL) break;
47577298Sobrien
47677298Sobrien		if (adapter->num_tx_desc_avail <= TX_CLEANUP_THRESHOLD)
47777298Sobrien			em_clean_transmit_interrupts(adapter);
47877298Sobrien
47977298Sobrien		if (adapter->num_tx_desc_avail <= TX_CLEANUP_THRESHOLD) {
48077298Sobrien			ifp->if_flags |= IFF_OACTIVE;
48177298Sobrien			IF_PREPEND(&ifp->if_snd, m_head);
48277298Sobrien			adapter->no_tx_desc_avail++;
48377298Sobrien			break;
48477298Sobrien		}
48577298Sobrien
48677298Sobrien		tx_buffer =  STAILQ_FIRST(&adapter->free_tx_buffer_list);
48777298Sobrien		if (!tx_buffer) {
48877298Sobrien			adapter->no_tx_buffer_avail1++;
48977298Sobrien			/*
49077298Sobrien			 * OK so we should not get here but I've seen it so let
49177298Sobrien			 * us try to clean up and then try to get a tx_buffer
49277298Sobrien			 * again and only break if we still don't get one.
49377298Sobrien			 */
49477298Sobrien			em_clean_transmit_interrupts(adapter);
49577298Sobrien			tx_buffer = STAILQ_FIRST(&adapter->free_tx_buffer_list);
49677298Sobrien			if (!tx_buffer) {
49777298Sobrien				ifp->if_flags |= IFF_OACTIVE;
49877298Sobrien				IF_PREPEND(&ifp->if_snd, m_head);
49977298Sobrien				adapter->no_tx_buffer_avail2++;
50077298Sobrien				break;
50177298Sobrien			}
50277298Sobrien		}
50377298Sobrien		STAILQ_REMOVE_HEAD(&adapter->free_tx_buffer_list, em_tx_entry);
50477298Sobrien
50577298Sobrien		tx_buffer->num_tx_desc_used = 0;
50677298Sobrien		tx_buffer->m_head = m_head;
50777298Sobrien
50877298Sobrien		if (ifp->if_hwassist > 0) {
50977298Sobrien			em_transmit_checksum_setup(adapter,  m_head, tx_buffer,
51077298Sobrien						   &txd_upper, &txd_lower);
51177298Sobrien		} else {
51277298Sobrien			txd_upper = 0;
51377298Sobrien			txd_lower = 0;
51477298Sobrien		}
51577298Sobrien
51677298Sobrien		/* Find out if we are in vlan mode */
51777298Sobrien		if ((m_head->m_flags & (M_PROTO1|M_PKTHDR)) == (M_PROTO1|M_PKTHDR) &&
51877298Sobrien		    m_head->m_pkthdr.rcvif != NULL &&
51977298Sobrien		    m_head->m_pkthdr.rcvif->if_type == IFT_L2VLAN)
52077298Sobrien			ifv = m_head->m_pkthdr.rcvif->if_softc;
52177298Sobrien
52277298Sobrien
52377298Sobrien		for (mp = m_head; mp != NULL; mp = mp->m_next) {
52477298Sobrien			if (mp->m_len == 0)
52577298Sobrien				continue;
52677298Sobrien			current_tx_desc = adapter->next_avail_tx_desc;
52777298Sobrien			virtual_addr = mtod(mp, vm_offset_t);
52877298Sobrien			current_tx_desc->buffer_addr = vtophys(virtual_addr);
52977298Sobrien
53077298Sobrien			current_tx_desc->lower.data = (txd_lower | mp->m_len);
53177298Sobrien			current_tx_desc->upper.data = (txd_upper);
53277298Sobrien
53377298Sobrien			if (current_tx_desc == adapter->last_tx_desc)
53477298Sobrien				adapter->next_avail_tx_desc =
53577298Sobrien				adapter->first_tx_desc;
53677298Sobrien			else
53777298Sobrien				adapter->next_avail_tx_desc++;
53877298Sobrien
53977298Sobrien			adapter->num_tx_desc_avail--;
54077298Sobrien			tx_buffer->num_tx_desc_used++;
54177298Sobrien		}
54277298Sobrien
54377298Sobrien		/* Put this tx_buffer at the end in the "in use" list */
54477298Sobrien		STAILQ_INSERT_TAIL(&adapter->used_tx_buffer_list, tx_buffer,
54577298Sobrien				   em_tx_entry);
54677298Sobrien
54777298Sobrien		if (ifv != NULL) {
54877298Sobrien			/* Tell hardware to add tag */
54977298Sobrien			current_tx_desc->lower.data |= E1000_TXD_CMD_VLE;
55077298Sobrien
55177298Sobrien			/* Set the vlan id */
55277298Sobrien			current_tx_desc->upper.fields.special = ifv->ifv_tag;
55377298Sobrien		}
55477298Sobrien
55577298Sobrien		/*
55677298Sobrien		 * Last Descriptor of Packet needs End Of Packet (EOP), Report Status
55777298Sobrien		 * (RS) and append Ethernet CRC (IFCS) bits set.
55877298Sobrien		 */
55977298Sobrien		current_tx_desc->lower.data |= (adapter->txd_cmd | E1000_TXD_CMD_EOP);
56077298Sobrien
56177298Sobrien		/* Send a copy of the frame to the BPF listener */
56277298Sobrien		if (ifp->if_bpf)
56377298Sobrien			bpf_mtap(ifp, m_head);
56477298Sobrien
56577298Sobrien		/*
56677298Sobrien		 * Advance the Transmit Descriptor Tail (Tdt), this tells the E1000
56777298Sobrien		 * that this frame is available to transmit.
56877298Sobrien		 */
56977298Sobrien		E1000_WRITE_REG(&adapter->hw, TDT,
57077298Sobrien				(((uintptr_t) adapter->next_avail_tx_desc -
57177298Sobrien				  (uintptr_t) adapter->first_tx_desc) >> 4));
57277298Sobrien	} /* end of while loop */
57377298Sobrien
57477298Sobrien	splx(s);
57577298Sobrien
57677298Sobrien	/* Set timeout in case chip has problems transmitting */
57777298Sobrien	ifp->if_timer = EM_TX_TIMEOUT;
57877298Sobrien
57977298Sobrien	return;
58077298Sobrien}
58177298Sobrien
58277298Sobrien/*********************************************************************
58377298Sobrien *  Ioctl entry point
58477298Sobrien *
58577298Sobrien *  em_ioctl is called when the user wants to configure the
58677298Sobrien *  interface.
58777298Sobrien *
58877298Sobrien *  return 0 on success, positive on failure
58977298Sobrien **********************************************************************/
59077298Sobrien
59177298Sobrienstatic int
59277298Sobrienem_ioctl(struct ifnet *ifp, IOCTL_CMD_TYPE command, caddr_t data)
59377298Sobrien{
59477298Sobrien	int             s, mask, error = 0;
59577298Sobrien	struct ifreq   *ifr = (struct ifreq *) data;
59677298Sobrien	struct adapter * adapter = ifp->if_softc;
59777298Sobrien
59877298Sobrien	s = splimp();
59977298Sobrien	switch (command) {
60077298Sobrien	case SIOCSIFADDR:
60177298Sobrien	case SIOCGIFADDR:
60277298Sobrien		IOCTL_DEBUGOUT("ioctl rcv'd: SIOCxIFADDR (Get/Set Interface Addr)");
60377298Sobrien		ether_ioctl(ifp, command, data);
60477298Sobrien		break;
60577298Sobrien	case SIOCSIFMTU:
60677298Sobrien		IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFMTU (Set Interface MTU)");
60777298Sobrien		if (ifr->ifr_mtu > MAX_JUMBO_FRAME_SIZE - ETHER_HDR_LEN) {
60877298Sobrien			error = EINVAL;
60977298Sobrien		} else {
61077298Sobrien			ifp->if_mtu = ifr->ifr_mtu;
61177298Sobrien			adapter->hw.max_frame_size =
61277298Sobrien			ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN;
61377298Sobrien			em_init(adapter);
61477298Sobrien		}
61577298Sobrien		break;
61677298Sobrien	case SIOCSIFFLAGS:
61777298Sobrien		IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFFLAGS (Set Interface Flags)");
61877298Sobrien		if (ifp->if_flags & IFF_UP) {
61977298Sobrien			if (ifp->if_flags & IFF_RUNNING &&
62077298Sobrien			    ifp->if_flags & IFF_PROMISC) {
62177298Sobrien				em_set_promisc(adapter);
62277298Sobrien			} else if (ifp->if_flags & IFF_RUNNING &&
62377298Sobrien				   !(ifp->if_flags & IFF_PROMISC)) {
62477298Sobrien				em_disable_promisc(adapter);
62577298Sobrien			} else
62677298Sobrien				em_init(adapter);
62777298Sobrien		} else {
62877298Sobrien			if (ifp->if_flags & IFF_RUNNING) {
62977298Sobrien				em_stop(adapter);
63077298Sobrien			}
63177298Sobrien		}
63277298Sobrien		break;
63377298Sobrien	case SIOCADDMULTI:
63477298Sobrien	case SIOCDELMULTI:
63577298Sobrien		IOCTL_DEBUGOUT("ioctl rcv'd: SIOC(ADD|DEL)MULTI");
63677298Sobrien		if (ifp->if_flags & IFF_RUNNING) {
63777298Sobrien			em_disable_intr(adapter);
63877298Sobrien			em_set_multi(adapter);
63977298Sobrien			if (adapter->hw.mac_type == em_82542_rev2_0)
64077298Sobrien				em_initialize_receive_unit(adapter);
64177298Sobrien			em_enable_intr(adapter);
64277298Sobrien		}
64377298Sobrien		break;
64477298Sobrien	case SIOCSIFMEDIA:
64577298Sobrien	case SIOCGIFMEDIA:
64677298Sobrien		IOCTL_DEBUGOUT("ioctl rcv'd: SIOCxIFMEDIA (Get/Set Interface Media)");
64777298Sobrien		error = ifmedia_ioctl(ifp, ifr, &adapter->media, command);
64877298Sobrien		break;
64977298Sobrien	case SIOCSIFCAP:
65077298Sobrien		IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFCAP (Set Capabilities)");
65177298Sobrien		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
65277298Sobrien		if (mask & IFCAP_HWCSUM) {
65377298Sobrien			if (IFCAP_HWCSUM & ifp->if_capenable)
65477298Sobrien				ifp->if_capenable &= ~IFCAP_HWCSUM;
65577298Sobrien			else
65677298Sobrien				ifp->if_capenable |= IFCAP_HWCSUM;
65777298Sobrien			if (ifp->if_flags & IFF_RUNNING)
65877298Sobrien				em_init(adapter);
65977298Sobrien		}
66077298Sobrien		break;
66177298Sobrien	default:
66277298Sobrien		IOCTL_DEBUGOUT1("ioctl received: UNKNOWN (0x%d)\n", (int)command);
66377298Sobrien		error = EINVAL;
66477298Sobrien	}
66577298Sobrien
66677298Sobrien	splx(s);
66777298Sobrien	return(error);
66877298Sobrien}
66977298Sobrien
67077298Sobrienstatic void
67177298Sobrienem_set_promisc(struct adapter * adapter)
67277298Sobrien{
67377298Sobrien
67477298Sobrien	u_int32_t       reg_rctl;
67577298Sobrien	struct ifnet   *ifp = &adapter->interface_data.ac_if;
67677298Sobrien
67777298Sobrien	reg_rctl = E1000_READ_REG(&adapter->hw, RCTL);
67877298Sobrien
67977298Sobrien	if (ifp->if_flags & IFF_PROMISC) {
68077298Sobrien		reg_rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
68177298Sobrien		E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
68277298Sobrien	} else if (ifp->if_flags & IFF_ALLMULTI) {
68377298Sobrien		reg_rctl |= E1000_RCTL_MPE;
68477298Sobrien		reg_rctl &= ~E1000_RCTL_UPE;
68577298Sobrien		E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
68677298Sobrien	}
68777298Sobrien
68877298Sobrien	return;
68977298Sobrien}
69077298Sobrien
69177298Sobrienstatic void
69277298Sobrienem_disable_promisc(struct adapter * adapter)
69377298Sobrien{
69477298Sobrien	u_int32_t       reg_rctl;
69577298Sobrien
69677298Sobrien	reg_rctl = E1000_READ_REG(&adapter->hw, RCTL);
69777298Sobrien
69877298Sobrien	reg_rctl &=  (~E1000_RCTL_UPE);
69977298Sobrien	reg_rctl &=  (~E1000_RCTL_MPE);
70077298Sobrien	E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
70177298Sobrien
70277298Sobrien	return;
70377298Sobrien}
70477298Sobrien
70577298Sobrien
70677298Sobrien/*********************************************************************
70777298Sobrien *  Multicast Update
70877298Sobrien *
70977298Sobrien *  This routine is called whenever multicast address list is updated.
71077298Sobrien *
71177298Sobrien **********************************************************************/
71277298Sobrien
71377298Sobrienstatic void
71477298Sobrienem_set_multi(struct adapter * adapter)
71577298Sobrien{
71677298Sobrien	u_int32_t reg_rctl = 0;
71777298Sobrien	u_int8_t  mta[MAX_NUM_MULTICAST_ADDRESSES * ETH_LENGTH_OF_ADDRESS];
71877298Sobrien	u_int16_t pci_cmd_word;
71977298Sobrien	struct ifmultiaddr  *ifma;
72077298Sobrien	int mcnt = 0;
72177298Sobrien	struct ifnet   *ifp = &adapter->interface_data.ac_if;
72277298Sobrien
72377298Sobrien	IOCTL_DEBUGOUT("em_set_multi: begin");
72477298Sobrien
72577298Sobrien	if (adapter->hw.mac_type == em_82542_rev2_0) {
72677298Sobrien		reg_rctl = E1000_READ_REG(&adapter->hw, RCTL);
72777298Sobrien		if (adapter->hw.pci_cmd_word & CMD_MEM_WRT_INVALIDATE) {
72877298Sobrien			pci_cmd_word = adapter->hw.pci_cmd_word &
72977298Sobrien				       ~CMD_MEM_WRT_INVALIDATE;
73077298Sobrien			pci_write_config(adapter->dev, PCIR_COMMAND, pci_cmd_word, 2);
73177298Sobrien		}
73277298Sobrien		reg_rctl |= E1000_RCTL_RST;
73377298Sobrien		E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
73477298Sobrien		msec_delay(5);
73577298Sobrien	}
73677298Sobrien
73777298Sobrien#if __FreeBSD_version < 500000
73877298Sobrien	LIST_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
73977298Sobrien#else
74077298Sobrien	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
74177298Sobrien#endif
74277298Sobrien		if (ifma->ifma_addr->sa_family != AF_LINK)
74377298Sobrien			continue;
74477298Sobrien
74577298Sobrien		bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
74677298Sobrien		      &mta[mcnt*ETH_LENGTH_OF_ADDRESS], ETH_LENGTH_OF_ADDRESS);
74777298Sobrien		mcnt++;
74877298Sobrien	}
74977298Sobrien
75077298Sobrien	if (mcnt > MAX_NUM_MULTICAST_ADDRESSES) {
75177298Sobrien		reg_rctl = E1000_READ_REG(&adapter->hw, RCTL);
75277298Sobrien		reg_rctl |= E1000_RCTL_MPE;
75377298Sobrien		E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
75477298Sobrien	} else
75577298Sobrien		em_mc_addr_list_update(&adapter->hw, mta, mcnt, 0);
75677298Sobrien
75777298Sobrien	if (adapter->hw.mac_type == em_82542_rev2_0) {
75877298Sobrien		reg_rctl = E1000_READ_REG(&adapter->hw, RCTL);
75977298Sobrien		reg_rctl &= ~E1000_RCTL_RST;
76077298Sobrien		E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
76177298Sobrien		msec_delay(5);
76277298Sobrien		if (adapter->hw.pci_cmd_word & CMD_MEM_WRT_INVALIDATE) {
76377298Sobrien			pci_write_config(adapter->dev, PCIR_COMMAND,
76477298Sobrien					 adapter->hw.pci_cmd_word, 2);
76577298Sobrien		}
76677298Sobrien	}
76777298Sobrien
76877298Sobrien	return;
76977298Sobrien}
77077298Sobrien
77177298Sobrien/*********************************************************************
77277298Sobrien *  Watchdog entry point
77377298Sobrien *
77477298Sobrien *  This routine is called whenever hardware quits transmitting.
77577298Sobrien *
77677298Sobrien **********************************************************************/
77777298Sobrien
77877298Sobrienstatic void
77977298Sobrienem_watchdog(struct ifnet *ifp)
78077298Sobrien{
78177298Sobrien	struct adapter * adapter;
78277298Sobrien	adapter = ifp->if_softc;
78377298Sobrien
78477298Sobrien	/* If we are in this routine because of pause frames, then
78577298Sobrien	 * don't reset the hardware.
78677298Sobrien	 */
78777298Sobrien	if (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_TXOFF) {
78877298Sobrien		ifp->if_timer = EM_TX_TIMEOUT;
78977298Sobrien		return;
79077298Sobrien	}
79177298Sobrien
79277298Sobrien	printf("em%d: watchdog timeout -- resetting\n", adapter->unit);
79377298Sobrien
79477298Sobrien	ifp->if_flags &= ~IFF_RUNNING;
79577298Sobrien
79677298Sobrien	em_stop(adapter);
79777298Sobrien	em_init(adapter);
79877298Sobrien
79977298Sobrien	ifp->if_oerrors++;
80077298Sobrien	return;
80177298Sobrien}
80277298Sobrien
80377298Sobrien/*********************************************************************
80477298Sobrien *  Timer routine
80577298Sobrien *
80677298Sobrien *  This routine checks for link status and updates statistics.
80777298Sobrien *
80877298Sobrien **********************************************************************/
80977298Sobrien
81077298Sobrienstatic void
81177298Sobrienem_local_timer(void *arg)
81277298Sobrien{
81377298Sobrien	int s;
81477298Sobrien	struct ifnet   *ifp;
81577298Sobrien	struct adapter * adapter = arg;
81677298Sobrien	ifp = &adapter->interface_data.ac_if;
81777298Sobrien
81877298Sobrien	s = splimp();
81977298Sobrien
82077298Sobrien	em_check_for_link(&adapter->hw);
82177298Sobrien	em_print_link_status(adapter);
82277298Sobrien	em_update_stats_counters(adapter);
82377298Sobrien	if (em_display_debug_stats && ifp->if_flags & IFF_RUNNING) {
82477298Sobrien		em_print_hw_stats(adapter);
82577298Sobrien	}
82677298Sobrien	adapter->timer_handle = timeout(em_local_timer, adapter, 2*hz);
82777298Sobrien
82877298Sobrien	splx(s);
82977298Sobrien	return;
83077298Sobrien}
83177298Sobrien
83277298Sobrienstatic void
83377298Sobrienem_print_link_status(struct adapter * adapter)
83477298Sobrien{
83577298Sobrien	if (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU) {
83677298Sobrien		if (adapter->link_active == 0) {
83777298Sobrien			em_get_speed_and_duplex(&adapter->hw,
83877298Sobrien						&adapter->link_speed,
83977298Sobrien						&adapter->link_duplex);
84077298Sobrien			printf("em%d: Link is up %d Mbps %s\n",
84177298Sobrien			       adapter->unit,
84277298Sobrien			       adapter->link_speed,
84377298Sobrien			       ((adapter->link_duplex == FULL_DUPLEX) ?
84477298Sobrien				"Full Duplex" : "Half Duplex"));
84577298Sobrien			adapter->link_active = 1;
84677298Sobrien		}
84777298Sobrien	} else {
84877298Sobrien		if (adapter->link_active == 1) {
84977298Sobrien			adapter->link_speed = 0;
85077298Sobrien			adapter->link_duplex = 0;
85177298Sobrien			printf("em%d: Link is Down\n", adapter->unit);
85277298Sobrien			adapter->link_active = 0;
85377298Sobrien		}
85477298Sobrien	}
85577298Sobrien
85677298Sobrien	return;
85777298Sobrien}
85877298Sobrien
85977298Sobrien/*********************************************************************
86077298Sobrien *  Init entry point
86177298Sobrien *
86277298Sobrien *  This routine is used in two ways. It is used by the stack as
86377298Sobrien *  init entry point in network interface structure. It is also used
86477298Sobrien *  by the driver as a hw/sw initialization routine to get to a
86577298Sobrien *  consistent state.
86677298Sobrien *
86777298Sobrien *  return 0 on success, positive on failure
86877298Sobrien **********************************************************************/
86977298Sobrien
87077298Sobrienstatic void
87177298Sobrienem_init(void *arg)
87277298Sobrien{
87377298Sobrien	int             s;
87477298Sobrien	struct ifnet   *ifp;
87577298Sobrien	struct adapter * adapter = arg;
87677298Sobrien
87777298Sobrien	INIT_DEBUGOUT("em_init: begin");
87877298Sobrien
87977298Sobrien	s = splimp();
88077298Sobrien
88177298Sobrien	em_stop(adapter);
88277298Sobrien
88377298Sobrien	/* Initialize the hardware */
88477298Sobrien	if (em_hardware_init(adapter)) {
88577298Sobrien		printf("em%d: Unable to initialize the hardware\n",
88677298Sobrien		       adapter->unit);
88777298Sobrien		splx(s);
88877298Sobrien		return;
88977298Sobrien	}
89077298Sobrien
89177298Sobrien	em_enable_vlans(adapter);
89277298Sobrien
89377298Sobrien	/* Prepare transmit descriptors and buffers */
89477298Sobrien	if (em_setup_transmit_structures(adapter)) {
89577298Sobrien		printf("em%d: Could not setup transmit structures\n",
89677298Sobrien		       adapter->unit);
89777298Sobrien		em_stop(adapter);
89877298Sobrien		splx(s);
89977298Sobrien		return;
90077298Sobrien	}
90177298Sobrien	em_initialize_transmit_unit(adapter);
90277298Sobrien
90377298Sobrien	/* Setup Multicast table */
90477298Sobrien	em_set_multi(adapter);
90577298Sobrien
90677298Sobrien	/* Prepare receive descriptors and buffers */
90777298Sobrien	if (em_setup_receive_structures(adapter)) {
90877298Sobrien		printf("em%d: Could not setup receive structures\n",
90977298Sobrien		       adapter->unit);
91077298Sobrien		em_stop(adapter);
91177298Sobrien		splx(s);
91277298Sobrien		return;
91377298Sobrien	}
91477298Sobrien	em_initialize_receive_unit(adapter);
91577298Sobrien
91677298Sobrien	ifp = &adapter->interface_data.ac_if;
91777298Sobrien	ifp->if_flags |= IFF_RUNNING;
91877298Sobrien	ifp->if_flags &= ~IFF_OACTIVE;
91977298Sobrien
92077298Sobrien	if (adapter->hw.mac_type >= em_82543) {
92177298Sobrien		if (ifp->if_capenable & IFCAP_TXCSUM)
92277298Sobrien			ifp->if_hwassist = EM_CHECKSUM_FEATURES;
92377298Sobrien		else
92477298Sobrien			ifp->if_hwassist = 0;
92577298Sobrien	}
92677298Sobrien
92777298Sobrien	adapter->timer_handle = timeout(em_local_timer, adapter, 2*hz);
92877298Sobrien	em_clear_hw_cntrs(&adapter->hw);
92977298Sobrien	em_enable_intr(adapter);
93077298Sobrien
93177298Sobrien	splx(s);
93277298Sobrien	return;
93377298Sobrien}
93477298Sobrien
93577298Sobrien
93677298Sobrien/*********************************************************************
93777298Sobrien *
93877298Sobrien *  This routine disables all traffic on the adapter by issuing a
93977298Sobrien *  global reset on the MAC and deallocates TX/RX buffers.
94077298Sobrien *
94177298Sobrien **********************************************************************/
94277298Sobrien
94377298Sobrienstatic void
94477298Sobrienem_stop(void *arg)
94577298Sobrien{
94677298Sobrien	struct ifnet   *ifp;
94777298Sobrien	struct adapter * adapter = arg;
94877298Sobrien	ifp = &adapter->interface_data.ac_if;
94977298Sobrien
95077298Sobrien	INIT_DEBUGOUT("em_stop: begin\n");
95177298Sobrien	em_disable_intr(adapter);
95277298Sobrien	em_reset_hw(&adapter->hw);
95377298Sobrien	untimeout(em_local_timer, adapter, adapter->timer_handle);
95477298Sobrien	em_free_transmit_structures(adapter);
95577298Sobrien	em_free_receive_structures(adapter);
95677298Sobrien
95777298Sobrien
95877298Sobrien	/* Tell the stack that the interface is no longer active */
95977298Sobrien	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
96077298Sobrien
96177298Sobrien	return;
96277298Sobrien}
96377298Sobrien
96477298Sobrien/*********************************************************************
96577298Sobrien *
96677298Sobrien *  Interrupt Service routine
96777298Sobrien *
96877298Sobrien **********************************************************************/
96977298Sobrien
97077298Sobrienstatic void
97177298Sobrienem_intr(void *arg)
97277298Sobrien{
97377298Sobrien	u_int32_t       loop_cnt = EM_MAX_INTR;
97477298Sobrien	u_int32_t       reg_icr;
97577298Sobrien	struct ifnet    *ifp;
97677298Sobrien	struct adapter  *adapter = arg;
97777298Sobrien
97877298Sobrien	ifp = &adapter->interface_data.ac_if;
97977298Sobrien
98077298Sobrien	em_disable_intr(adapter);
98177298Sobrien	while (loop_cnt > 0 &&
98277298Sobrien	       (reg_icr = E1000_READ_REG(&adapter->hw, ICR)) != 0) {
98377298Sobrien
98477298Sobrien		/* Link status change */
98577298Sobrien		if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
98677298Sobrien			untimeout(em_local_timer, adapter,
98777298Sobrien				  adapter->timer_handle);
98877298Sobrien			adapter->hw.get_link_status = 1;
98977298Sobrien			em_check_for_link(&adapter->hw);
99077298Sobrien			em_print_link_status(adapter);
99177298Sobrien			adapter->timer_handle =
99277298Sobrien			timeout(em_local_timer, adapter, 2*hz);
99377298Sobrien		}
99477298Sobrien
99577298Sobrien		if (ifp->if_flags & IFF_RUNNING) {
99677298Sobrien			em_process_receive_interrupts(adapter);
99777298Sobrien			em_clean_transmit_interrupts(adapter);
99877298Sobrien		}
99977298Sobrien		loop_cnt--;
100077298Sobrien	}
100177298Sobrien
100277298Sobrien	em_enable_intr(adapter);
100377298Sobrien
100477298Sobrien	if (ifp->if_flags & IFF_RUNNING && ifp->if_snd.ifq_head != NULL)
100577298Sobrien		em_start(ifp);
100677298Sobrien
100777298Sobrien	return;
100877298Sobrien}
100977298Sobrien
101077298Sobrien
101177298Sobrien/*********************************************************************
101277298Sobrien *
101377298Sobrien *  Media Ioctl callback
101477298Sobrien *
101577298Sobrien *  This routine is called whenever the user queries the status of
101677298Sobrien *  the interface using ifconfig.
101777298Sobrien *
101877298Sobrien **********************************************************************/
101977298Sobrienstatic void
102077298Sobrienem_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
102177298Sobrien{
102277298Sobrien	struct adapter * adapter = ifp->if_softc;
102377298Sobrien
102477298Sobrien	INIT_DEBUGOUT("em_media_status: begin");
102577298Sobrien
102677298Sobrien	em_check_for_link(&adapter->hw);
102777298Sobrien	if (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU) {
102877298Sobrien		if (adapter->link_active == 0) {
102977298Sobrien			em_get_speed_and_duplex(&adapter->hw,
103077298Sobrien						&adapter->link_speed,
103177298Sobrien						&adapter->link_duplex);
103277298Sobrien			adapter->link_active = 1;
103377298Sobrien		}
103477298Sobrien	} else {
103577298Sobrien		if (adapter->link_active == 1) {
103677298Sobrien			adapter->link_speed = 0;
103777298Sobrien			adapter->link_duplex = 0;
103877298Sobrien			adapter->link_active = 0;
103977298Sobrien		}
104077298Sobrien	}
104177298Sobrien
104277298Sobrien	ifmr->ifm_status = IFM_AVALID;
104377298Sobrien	ifmr->ifm_active = IFM_ETHER;
104477298Sobrien
104577298Sobrien	if (!adapter->link_active)
104677298Sobrien		return;
104777298Sobrien
104877298Sobrien	ifmr->ifm_status |= IFM_ACTIVE;
104977298Sobrien
105077298Sobrien	if (adapter->hw.media_type == em_media_type_fiber) {
105177298Sobrien		ifmr->ifm_active |= IFM_1000_SX | IFM_FDX;
105277298Sobrien	} else {
105377298Sobrien		switch (adapter->link_speed) {
105477298Sobrien		case 10:
105577298Sobrien			ifmr->ifm_active |= IFM_10_T;
105677298Sobrien			break;
105777298Sobrien		case 100:
105877298Sobrien			ifmr->ifm_active |= IFM_100_TX;
105977298Sobrien			break;
106077298Sobrien		case 1000:
106177298Sobrien#if __FreeBSD_version < 500000
106277298Sobrien			ifmr->ifm_active |= IFM_1000_TX;
106377298Sobrien#else
106477298Sobrien			ifmr->ifm_active |= IFM_1000_T;
106577298Sobrien#endif
106677298Sobrien			break;
106777298Sobrien		}
106877298Sobrien		if (adapter->link_duplex == FULL_DUPLEX)
106977298Sobrien			ifmr->ifm_active |= IFM_FDX;
107077298Sobrien		else
107177298Sobrien			ifmr->ifm_active |= IFM_HDX;
107277298Sobrien	}
107377298Sobrien	return;
107477298Sobrien}
107577298Sobrien
107677298Sobrien/*********************************************************************
107777298Sobrien *
107877298Sobrien *  Media Ioctl callback
107977298Sobrien *
108077298Sobrien *  This routine is called when the user changes speed/duplex using
108177298Sobrien *  media/mediopt option with ifconfig.
108277298Sobrien *
108389857Sobrien **********************************************************************/
108477298Sobrienstatic int
108577298Sobrienem_media_change(struct ifnet *ifp)
108689857Sobrien{
108777298Sobrien	struct adapter * adapter = ifp->if_softc;
108877298Sobrien	struct ifmedia  *ifm = &adapter->media;
108977298Sobrien
109077298Sobrien	INIT_DEBUGOUT("em_media_change: begin");
109177298Sobrien
109277298Sobrien	if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
109377298Sobrien		return(EINVAL);
109477298Sobrien
109577298Sobrien	switch (IFM_SUBTYPE(ifm->ifm_media)) {
109677298Sobrien	case IFM_AUTO:
109777298Sobrien		adapter->hw.autoneg = DO_AUTO_NEG;
109877298Sobrien		adapter->hw.autoneg_advertised = AUTONEG_ADV_DEFAULT;
109977298Sobrien		break;
110077298Sobrien	case IFM_1000_SX:
110177298Sobrien#if __FreeBSD_version < 500000
110277298Sobrien	case IFM_1000_TX:
110377298Sobrien#else
110477298Sobrien	case IFM_1000_T:
110577298Sobrien#endif
110677298Sobrien		adapter->hw.autoneg = DO_AUTO_NEG;
110777298Sobrien		adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
110889857Sobrien		break;
110977298Sobrien	case IFM_100_TX:
111077298Sobrien		adapter->hw.autoneg = FALSE;
111177298Sobrien		adapter->hw.autoneg_advertised = 0;
111277298Sobrien		if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX)
111377298Sobrien			adapter->hw.forced_speed_duplex = em_100_full;
111477298Sobrien		else
111577298Sobrien			adapter->hw.forced_speed_duplex	= em_100_half;
111677298Sobrien		break;
111777298Sobrien	case IFM_10_T:
111877298Sobrien		adapter->hw.autoneg = FALSE;
111977298Sobrien		adapter->hw.autoneg_advertised = 0;
112077298Sobrien		if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX)
112177298Sobrien			adapter->hw.forced_speed_duplex = em_10_full;
112277298Sobrien		else
112377298Sobrien			adapter->hw.forced_speed_duplex	= em_10_half;
112477298Sobrien		break;
112577298Sobrien	default:
112677298Sobrien		printf("em%d: Unsupported media type\n", adapter->unit);
112777298Sobrien	}
112877298Sobrien
112977298Sobrien	em_init(adapter);
113077298Sobrien
113177298Sobrien	return(0);
113277298Sobrien}
113377298Sobrien/* Section end: Other registered entry points */
113477298Sobrien
113577298Sobrien
113677298Sobrien/*********************************************************************
113777298Sobrien *
113877298Sobrien *  Determine hardware revision.
113977298Sobrien *
114077298Sobrien **********************************************************************/
114177298Sobrienstatic void
114277298Sobrienem_identify_hardware(struct adapter * adapter)
114377298Sobrien{
114477298Sobrien	device_t dev = adapter->dev;
114577298Sobrien
114677298Sobrien	/* Make sure our PCI config space has the necessary stuff set */
114777298Sobrien	adapter->hw.pci_cmd_word = pci_read_config(dev, PCIR_COMMAND, 2);
114877298Sobrien	if (!((adapter->hw.pci_cmd_word & PCIM_CMD_BUSMASTEREN) &&
114977298Sobrien	      (adapter->hw.pci_cmd_word & PCIM_CMD_MEMEN))) {
115077298Sobrien		printf("em%d: Memory Access and/or Bus Master bits were not set!\n",
115177298Sobrien		       adapter->unit);
115277298Sobrien		adapter->hw.pci_cmd_word |=
115377298Sobrien		(PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN);
115477298Sobrien		pci_write_config(dev, PCIR_COMMAND, adapter->hw.pci_cmd_word, 2);
115577298Sobrien	}
115677298Sobrien
115777298Sobrien	/* Save off the information about this board */
115877298Sobrien	adapter->hw.vendor_id = pci_get_vendor(dev);
115977298Sobrien	adapter->hw.device_id = pci_get_device(dev);
116077298Sobrien	adapter->hw.revision_id = pci_read_config(dev, PCIR_REVID, 1);
116177298Sobrien	adapter->hw.subsystem_vendor_id = pci_read_config(dev, PCIR_SUBVEND_0, 2);
116277298Sobrien	adapter->hw.subsystem_id = pci_read_config(dev, PCIR_SUBDEV_0, 2);
116377298Sobrien
116477298Sobrien
116577298Sobrien	/* Set MacType, etc. based on this PCI info */
116677298Sobrien	switch (adapter->hw.device_id) {
116777298Sobrien	case E1000_DEV_ID_82542:
116877298Sobrien		adapter->hw.mac_type = (adapter->hw.revision_id == 3) ?
116977298Sobrien				       em_82542_rev2_1 : em_82542_rev2_0;
117077298Sobrien		break;
117177298Sobrien	case E1000_DEV_ID_82543GC_FIBER:
117277298Sobrien	case E1000_DEV_ID_82543GC_COPPER:
117377298Sobrien		adapter->hw.mac_type = em_82543;
117477298Sobrien		break;
117577298Sobrien	case E1000_DEV_ID_82544EI_FIBER:
117677298Sobrien	case E1000_DEV_ID_82544EI_COPPER:
117777298Sobrien	case E1000_DEV_ID_82544GC_COPPER:
117877298Sobrien	case E1000_DEV_ID_82544GC_LOM:
117977298Sobrien		adapter->hw.mac_type = em_82544;
118077298Sobrien		break;
118177298Sobrien	case E1000_DEV_ID_82540EM:
118277298Sobrien		adapter->hw.mac_type = em_82540;
118377298Sobrien		break;
118477298Sobrien	case E1000_DEV_ID_82545EM_FIBER:
118577298Sobrien	case E1000_DEV_ID_82545EM_COPPER:
118677298Sobrien		adapter->hw.mac_type = em_82545;
118777298Sobrien		break;
118877298Sobrien	case E1000_DEV_ID_82546EB_FIBER:
118977298Sobrien	case E1000_DEV_ID_82546EB_COPPER:
119077298Sobrien		adapter->hw.mac_type = em_82546;
119177298Sobrien		break;
119277298Sobrien	default:
119377298Sobrien		INIT_DEBUGOUT1("Unknown device id 0x%x", adapter->hw.device_id);
119477298Sobrien	}
119577298Sobrien	return;
119677298Sobrien}
119777298Sobrien
119877298Sobrienstatic int
119977298Sobrienem_allocate_pci_resources(struct adapter * adapter)
120077298Sobrien{
120177298Sobrien	int             i, val, rid;
120277298Sobrien	device_t        dev = adapter->dev;
120377298Sobrien
120477298Sobrien	rid = EM_MMBA;
120577298Sobrien	adapter->res_memory = bus_alloc_resource(dev, SYS_RES_MEMORY,
120677298Sobrien						 &rid, 0, ~0, 1,
120777298Sobrien						 RF_ACTIVE);
120877298Sobrien	if (!(adapter->res_memory)) {
120977298Sobrien		printf("em%d: Unable to allocate bus resource: memory\n",
121077298Sobrien		       adapter->unit);
121177298Sobrien		return(ENXIO);
121277298Sobrien	}
121377298Sobrien	adapter->osdep.mem_bus_space_tag =
121477298Sobrien	rman_get_bustag(adapter->res_memory);
121577298Sobrien	adapter->osdep.mem_bus_space_handle =
121677298Sobrien	rman_get_bushandle(adapter->res_memory);
121777298Sobrien	adapter->hw.hw_addr = (uint8_t *)&adapter->osdep.mem_bus_space_handle;
121877298Sobrien
121977298Sobrien
122077298Sobrien	if (adapter->hw.mac_type > em_82543) {
122177298Sobrien		/* Figure our where our IO BAR is ? */
122277298Sobrien		rid = EM_MMBA;
122377298Sobrien		for (i = 0; i < 5; i++) {
122477298Sobrien			val = pci_read_config(dev, rid, 4);
122577298Sobrien			if (val & 0x00000001) {
122677298Sobrien				adapter->io_rid = rid;
122777298Sobrien				break;
122877298Sobrien			}
122977298Sobrien			rid += 4;
123077298Sobrien		}
123177298Sobrien
123277298Sobrien		adapter->res_ioport = bus_alloc_resource(dev, SYS_RES_IOPORT,
123377298Sobrien							 &adapter->io_rid, 0, ~0, 1,
123477298Sobrien							 RF_ACTIVE);
123577298Sobrien		if (!(adapter->res_ioport)) {
123677298Sobrien			printf("em%d: Unable to allocate bus resource: ioport\n",
123777298Sobrien			       adapter->unit);
123877298Sobrien			return(ENXIO);
123977298Sobrien		}
124077298Sobrien
124177298Sobrien		adapter->hw.io_base =
124277298Sobrien		rman_get_start(adapter->res_ioport);
124377298Sobrien	}
124477298Sobrien
124577298Sobrien	rid = 0x0;
124677298Sobrien	adapter->res_interrupt = bus_alloc_resource(dev, SYS_RES_IRQ,
124777298Sobrien						    &rid, 0, ~0, 1,
124877298Sobrien						    RF_SHAREABLE | RF_ACTIVE);
124977298Sobrien	if (!(adapter->res_interrupt)) {
125077298Sobrien		printf("em%d: Unable to allocate bus resource: interrupt\n",
125177298Sobrien		       adapter->unit);
125277298Sobrien		return(ENXIO);
125377298Sobrien	}
125477298Sobrien	if (bus_setup_intr(dev, adapter->res_interrupt, INTR_TYPE_NET,
125577298Sobrien			   (void (*)(void *)) em_intr, adapter,
125677298Sobrien			   &adapter->int_handler_tag)) {
125777298Sobrien		printf("em%d: Error registering interrupt handler!\n",
125877298Sobrien		       adapter->unit);
125977298Sobrien		return(ENXIO);
126077298Sobrien	}
126177298Sobrien
126277298Sobrien	adapter->hw.back = &adapter->osdep;
126377298Sobrien
126477298Sobrien	return(0);
126577298Sobrien}
126677298Sobrien
126777298Sobrienstatic void
126877298Sobrienem_free_pci_resources(struct adapter * adapter)
126977298Sobrien{
127077298Sobrien	device_t dev = adapter->dev;
127177298Sobrien
127277298Sobrien	if (adapter->res_interrupt != NULL) {
127377298Sobrien		bus_teardown_intr(dev, adapter->res_interrupt,
127477298Sobrien				  adapter->int_handler_tag);
127577298Sobrien		bus_release_resource(dev, SYS_RES_IRQ, 0,
127677298Sobrien				     adapter->res_interrupt);
127777298Sobrien	}
127877298Sobrien	if (adapter->res_memory != NULL) {
127977298Sobrien		bus_release_resource(dev, SYS_RES_MEMORY, EM_MMBA,
128077298Sobrien				     adapter->res_memory);
128177298Sobrien	}
128277298Sobrien
128377298Sobrien	if (adapter->res_ioport != NULL) {
128477298Sobrien		bus_release_resource(dev, SYS_RES_IOPORT, adapter->io_rid,
128577298Sobrien				     adapter->res_ioport);
128677298Sobrien	}
128777298Sobrien	return;
128877298Sobrien}
128977298Sobrien
129077298Sobrien/*********************************************************************
129177298Sobrien *
129277298Sobrien *  Initialize the hardware to a configuration as specified by the
129377298Sobrien *  adapter structure. The controller is reset, the EEPROM is
129477298Sobrien *  verified, the MAC address is set, then the shared initialization
129577298Sobrien *  routines are called.
129677298Sobrien *
129777298Sobrien **********************************************************************/
129877298Sobrienstatic int
129977298Sobrienem_hardware_init(struct adapter * adapter)
130077298Sobrien{
130177298Sobrien	/* Issue a global reset */
130277298Sobrien	em_reset_hw(&adapter->hw);
130377298Sobrien
130477298Sobrien	/* Make sure we have a good EEPROM before we read from it */
130577298Sobrien	if (em_validate_eeprom_checksum(&adapter->hw) < 0) {
130677298Sobrien		printf("em%d: The EEPROM Checksum Is Not Valid\n",
130777298Sobrien		       adapter->unit);
130877298Sobrien		return(EIO);
130977298Sobrien	}
131077298Sobrien
131177298Sobrien	if (em_read_part_num(&adapter->hw, &(adapter->part_num)) < 0) {
131277298Sobrien		printf("em%d: EEPROM read error while reading part number\n",
131377298Sobrien		       adapter->unit);
131477298Sobrien		return(EIO);
131577298Sobrien	}
131677298Sobrien
131777298Sobrien	if (em_init_hw(&adapter->hw) < 0) {
131877298Sobrien		printf("em%d: Hardware Initialization Failed",
131977298Sobrien		       adapter->unit);
132077298Sobrien		return(EIO);
132177298Sobrien	}
132277298Sobrien
132377298Sobrien	em_check_for_link(&adapter->hw);
132477298Sobrien	if (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU)
132577298Sobrien		adapter->link_active = 1;
132677298Sobrien	else
132777298Sobrien		adapter->link_active = 0;
132877298Sobrien
132977298Sobrien	if (adapter->link_active) {
133077298Sobrien		em_get_speed_and_duplex(&adapter->hw,
133177298Sobrien					&adapter->link_speed,
133277298Sobrien					&adapter->link_duplex);
133377298Sobrien	} else {
133477298Sobrien		adapter->link_speed = 0;
133577298Sobrien		adapter->link_duplex = 0;
133677298Sobrien	}
133777298Sobrien
133877298Sobrien	return(0);
133977298Sobrien}
134077298Sobrien
134177298Sobrien/*********************************************************************
134277298Sobrien *
134377298Sobrien *  Setup networking device structure and register an interface.
134477298Sobrien *
134577298Sobrien **********************************************************************/
134677298Sobrienstatic void
134777298Sobrienem_setup_interface(device_t dev, struct adapter * adapter)
134877298Sobrien{
134977298Sobrien	struct ifnet   *ifp;
135077298Sobrien	INIT_DEBUGOUT("em_setup_interface: begin");
135177298Sobrien
135277298Sobrien	ifp = &adapter->interface_data.ac_if;
135377298Sobrien	ifp->if_unit = adapter->unit;
135477298Sobrien	ifp->if_name = "em";
135577298Sobrien	ifp->if_mtu = ETHERMTU;
135677298Sobrien	ifp->if_output = ether_output;
135777298Sobrien	ifp->if_baudrate = 1000000000;
135877298Sobrien	ifp->if_init =  em_init;
135977298Sobrien	ifp->if_softc = adapter;
136077298Sobrien	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
136177298Sobrien	ifp->if_ioctl = em_ioctl;
136277298Sobrien	ifp->if_start = em_start;
136377298Sobrien	ifp->if_watchdog = em_watchdog;
136477298Sobrien	ifp->if_snd.ifq_maxlen = adapter->num_tx_desc - 1;
136577298Sobrien	ether_ifattach(ifp, ETHER_BPF_SUPPORTED);
136677298Sobrien
136777298Sobrien	if (adapter->hw.mac_type >= em_82543) {
136877298Sobrien		ifp->if_capabilities = IFCAP_HWCSUM;
136977298Sobrien		ifp->if_capenable = ifp->if_capabilities;
137077298Sobrien	}
137177298Sobrien
137277298Sobrien	/*
137377298Sobrien	 * Specify the media types supported by this adapter and register
137477298Sobrien	 * callbacks to update media and link information
137577298Sobrien	 */
137677298Sobrien	ifmedia_init(&adapter->media, IFM_IMASK, em_media_change,
137777298Sobrien		     em_media_status);
137877298Sobrien	if (adapter->hw.media_type == em_media_type_fiber) {
137977298Sobrien		ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_SX | IFM_FDX,
138077298Sobrien			    0, NULL);
138177298Sobrien		ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_SX,
138277298Sobrien			    0, NULL);
138377298Sobrien	} else {
138477298Sobrien		ifmedia_add(&adapter->media, IFM_ETHER | IFM_10_T, 0, NULL);
138577298Sobrien		ifmedia_add(&adapter->media, IFM_ETHER | IFM_10_T | IFM_FDX,
138677298Sobrien			    0, NULL);
138777298Sobrien		ifmedia_add(&adapter->media, IFM_ETHER | IFM_100_TX,
138877298Sobrien			    0, NULL);
138977298Sobrien		ifmedia_add(&adapter->media, IFM_ETHER | IFM_100_TX | IFM_FDX,
139077298Sobrien			    0, NULL);
139177298Sobrien#if __FreeBSD_version < 500000
139277298Sobrien		ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_TX | IFM_FDX,
139377298Sobrien			    0, NULL);
139477298Sobrien		ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_TX, 0, NULL);
139577298Sobrien#else
139677298Sobrien		ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_T | IFM_FDX,
139777298Sobrien			    0, NULL);
139877298Sobrien		ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_T, 0, NULL);
139977298Sobrien#endif
140077298Sobrien	}
140177298Sobrien	ifmedia_add(&adapter->media, IFM_ETHER | IFM_AUTO, 0, NULL);
140277298Sobrien	ifmedia_set(&adapter->media, IFM_ETHER | IFM_AUTO);
140377298Sobrien
140477298Sobrien	return;
140577298Sobrien}
140677298Sobrien
140777298Sobrien
140877298Sobrien/*********************************************************************
140977298Sobrien *
141077298Sobrien *  Allocate memory for tx_buffer structures. The tx_buffer stores all
141177298Sobrien *  the information needed to transmit a packet on the wire.
141277298Sobrien *
141377298Sobrien **********************************************************************/
141477298Sobrienstatic int
141577298Sobrienem_allocate_transmit_structures(struct adapter * adapter)
141677298Sobrien{
141777298Sobrien	if (!(adapter->tx_buffer_area =
141877298Sobrien	      (struct em_tx_buffer *) malloc(sizeof(struct em_tx_buffer) *
141977298Sobrien					     adapter->num_tx_desc, M_DEVBUF,
142077298Sobrien					     M_NOWAIT))) {
142177298Sobrien		printf("em%d: Unable to allocate tx_buffer memory\n",
142277298Sobrien		       adapter->unit);
142377298Sobrien		return ENOMEM;
142477298Sobrien	}
142577298Sobrien
142677298Sobrien	bzero(adapter->tx_buffer_area,
142777298Sobrien	      sizeof(struct em_tx_buffer) * adapter->num_tx_desc);
142877298Sobrien
142977298Sobrien	return 0;
143077298Sobrien}
143177298Sobrien
143277298Sobrien/*********************************************************************
143377298Sobrien *
143477298Sobrien *  Allocate and initialize transmit structures.
143577298Sobrien *
143677298Sobrien **********************************************************************/
143777298Sobrienstatic int
143877298Sobrienem_setup_transmit_structures(struct adapter * adapter)
143977298Sobrien{
144077298Sobrien	struct em_tx_buffer   *tx_buffer;
144177298Sobrien	int             i;
144277298Sobrien
144377298Sobrien	if (em_allocate_transmit_structures(adapter))
144477298Sobrien		return ENOMEM;
144577298Sobrien
144677298Sobrien	adapter->first_tx_desc = adapter->tx_desc_base;
144777298Sobrien	adapter->last_tx_desc =
144877298Sobrien	adapter->first_tx_desc + (adapter->num_tx_desc - 1);
144977298Sobrien
145077298Sobrien
145177298Sobrien	STAILQ_INIT(&adapter->free_tx_buffer_list);
145277298Sobrien	STAILQ_INIT(&adapter->used_tx_buffer_list);
145377298Sobrien
145477298Sobrien	tx_buffer = adapter->tx_buffer_area;
145577298Sobrien
145677298Sobrien	/* Setup the linked list of the tx_buffer's */
145777298Sobrien	for (i = 0; i < adapter->num_tx_desc; i++, tx_buffer++) {
145877298Sobrien		bzero((void *) tx_buffer, sizeof(struct em_tx_buffer));
145977298Sobrien		STAILQ_INSERT_TAIL(&adapter->free_tx_buffer_list,
146077298Sobrien				   tx_buffer, em_tx_entry);
146177298Sobrien	}
146277298Sobrien
146377298Sobrien	bzero((void *) adapter->first_tx_desc,
146477298Sobrien	      (sizeof(struct em_tx_desc)) * adapter->num_tx_desc);
146577298Sobrien
146677298Sobrien	/* Setup TX descriptor pointers */
146777298Sobrien	adapter->next_avail_tx_desc = adapter->first_tx_desc;
146877298Sobrien	adapter->oldest_used_tx_desc = adapter->first_tx_desc;
146977298Sobrien
147077298Sobrien	/* Set number of descriptors available */
147177298Sobrien	adapter->num_tx_desc_avail = adapter->num_tx_desc;
147277298Sobrien
147377298Sobrien	/* Set checksum context */
147477298Sobrien	adapter->active_checksum_context = OFFLOAD_NONE;
147577298Sobrien
147677298Sobrien	return 0;
147777298Sobrien}
147877298Sobrien
147977298Sobrien/*********************************************************************
148077298Sobrien *
148177298Sobrien *  Enable transmit unit.
148277298Sobrien *
148377298Sobrien **********************************************************************/
148477298Sobrienstatic void
148577298Sobrienem_initialize_transmit_unit(struct adapter * adapter)
148677298Sobrien{
148777298Sobrien	u_int32_t       reg_tctl;
148877298Sobrien	u_int32_t       reg_tipg = 0;
148977298Sobrien
149077298Sobrien	/* Setup the Base and Length of the Tx Descriptor Ring */
149177298Sobrien	E1000_WRITE_REG(&adapter->hw, TDBAL,
149277298Sobrien			vtophys((vm_offset_t) adapter->tx_desc_base));
149377298Sobrien	E1000_WRITE_REG(&adapter->hw, TDBAH, 0);
149477298Sobrien	E1000_WRITE_REG(&adapter->hw, TDLEN,
149577298Sobrien			adapter->num_tx_desc *
149677298Sobrien			sizeof(struct em_tx_desc));
149777298Sobrien
149877298Sobrien	/* Setup the HW Tx Head and Tail descriptor pointers */
149977298Sobrien	E1000_WRITE_REG(&adapter->hw, TDH, 0);
150077298Sobrien	E1000_WRITE_REG(&adapter->hw, TDT, 0);
150177298Sobrien
150277298Sobrien
150377298Sobrien	HW_DEBUGOUT2("Base = %x, Length = %x\n",
150477298Sobrien		     E1000_READ_REG(&adapter->hw, TDBAL),
150577298Sobrien		     E1000_READ_REG(&adapter->hw, TDLEN));
150677298Sobrien
150777298Sobrien
150877298Sobrien	/* Set the default values for the Tx Inter Packet Gap timer */
150977298Sobrien	switch (adapter->hw.mac_type) {
151077298Sobrien	case em_82543:
151177298Sobrien	case em_82544:
151277298Sobrien	case em_82540:
151377298Sobrien	case em_82545:
151477298Sobrien	case em_82546:
151577298Sobrien		if (adapter->hw.media_type == em_media_type_fiber)
151677298Sobrien			reg_tipg = DEFAULT_82543_TIPG_IPGT_FIBER;
151777298Sobrien		else
151877298Sobrien			reg_tipg = DEFAULT_82543_TIPG_IPGT_COPPER;
151977298Sobrien		reg_tipg |= DEFAULT_82543_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT;
152077298Sobrien		reg_tipg |= DEFAULT_82543_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT;
152177298Sobrien		break;
152277298Sobrien	case em_82542_rev2_0:
152377298Sobrien	case em_82542_rev2_1:
152477298Sobrien		reg_tipg = DEFAULT_82542_TIPG_IPGT;
152577298Sobrien		reg_tipg |= DEFAULT_82542_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT;
152677298Sobrien		reg_tipg |= DEFAULT_82542_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT;
152777298Sobrien		break;
152877298Sobrien	default:
152977298Sobrien		printf("em%d: Invalid mac type detected\n", adapter->unit);
153077298Sobrien	}
153177298Sobrien	E1000_WRITE_REG(&adapter->hw, TIPG, reg_tipg);
153277298Sobrien	E1000_WRITE_REG(&adapter->hw, TIDV, adapter->tx_int_delay);
153377298Sobrien
153477298Sobrien	/* Program the Transmit Control Register */
153577298Sobrien	reg_tctl = E1000_TCTL_PSP | E1000_TCTL_EN |
153677298Sobrien		   (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);
153777298Sobrien	if (adapter->link_duplex == 1) {
153877298Sobrien		reg_tctl |= E1000_FDX_COLLISION_DISTANCE << E1000_COLD_SHIFT;
153977298Sobrien	} else {
154077298Sobrien		reg_tctl |= E1000_HDX_COLLISION_DISTANCE << E1000_COLD_SHIFT;
154177298Sobrien	}
154277298Sobrien	E1000_WRITE_REG(&adapter->hw, TCTL, reg_tctl);
154377298Sobrien
154477298Sobrien	/* Setup Transmit Descriptor Settings for this adapter */
154577298Sobrien	adapter->txd_cmd = E1000_TXD_CMD_IFCS;
154677298Sobrien
154777298Sobrien	if (adapter->tx_int_delay > 0)
154877298Sobrien		adapter->txd_cmd |= E1000_TXD_CMD_IDE;
154977298Sobrien
155077298Sobrien	if (adapter->hw.report_tx_early == 1)
155177298Sobrien		adapter->txd_cmd |= E1000_TXD_CMD_RS;
155277298Sobrien	else
155377298Sobrien		adapter->txd_cmd |= E1000_TXD_CMD_RPS;
155477298Sobrien
155577298Sobrien	return;
155677298Sobrien}
155777298Sobrien
155877298Sobrien/*********************************************************************
155977298Sobrien *
156077298Sobrien *  Free all transmit related data structures.
156177298Sobrien *
156277298Sobrien **********************************************************************/
156377298Sobrienstatic void
156477298Sobrienem_free_transmit_structures(struct adapter * adapter)
156577298Sobrien{
156677298Sobrien	struct em_tx_buffer   *tx_buffer;
156777298Sobrien	int             i;
156877298Sobrien
156977298Sobrien	INIT_DEBUGOUT("free_transmit_structures: begin");
157077298Sobrien
157177298Sobrien	if (adapter->tx_buffer_area != NULL) {
157277298Sobrien		tx_buffer = adapter->tx_buffer_area;
157377298Sobrien		for (i = 0; i < adapter->num_tx_desc; i++, tx_buffer++) {
157477298Sobrien			if (tx_buffer->m_head != NULL)
157577298Sobrien				m_freem(tx_buffer->m_head);
157677298Sobrien			tx_buffer->m_head = NULL;
157777298Sobrien		}
157877298Sobrien	}
157977298Sobrien	if (adapter->tx_buffer_area != NULL) {
158077298Sobrien		free(adapter->tx_buffer_area, M_DEVBUF);
158177298Sobrien		adapter->tx_buffer_area = NULL;
158277298Sobrien	}
158377298Sobrien	return;
158477298Sobrien}
158577298Sobrien
158677298Sobrien/*********************************************************************
158777298Sobrien *
158877298Sobrien *  The offload context needs to be set when we transfer the first
158977298Sobrien *  packet of a particular protocol (TCP/UDP). We change the
159077298Sobrien *  context only if the protocol type changes.
159177298Sobrien *
159277298Sobrien **********************************************************************/
159377298Sobrienstatic void
159477298Sobrienem_transmit_checksum_setup(struct adapter * adapter,
159577298Sobrien			   struct mbuf *mp,
159677298Sobrien			   struct em_tx_buffer *tx_buffer,
159777298Sobrien			   u_int32_t *txd_upper,
159877298Sobrien			   u_int32_t *txd_lower)
159977298Sobrien{
160077298Sobrien	struct em_context_desc *TXD;
160177298Sobrien	struct em_tx_desc * current_tx_desc;
160277298Sobrien
160377298Sobrien	if (mp->m_pkthdr.csum_flags) {
160477298Sobrien
160577298Sobrien		if (mp->m_pkthdr.csum_flags & CSUM_TCP) {
160677298Sobrien			*txd_upper = E1000_TXD_POPTS_TXSM << 8;
160777298Sobrien			*txd_lower = E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D;
160877298Sobrien			if (adapter->active_checksum_context == OFFLOAD_TCP_IP)
160977298Sobrien				return;
161077298Sobrien			else
161177298Sobrien				adapter->active_checksum_context = OFFLOAD_TCP_IP;
161277298Sobrien
161377298Sobrien		} else if (mp->m_pkthdr.csum_flags & CSUM_UDP) {
161477298Sobrien			*txd_upper = E1000_TXD_POPTS_TXSM << 8;
161577298Sobrien			*txd_lower = E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D;
161677298Sobrien			if (adapter->active_checksum_context == OFFLOAD_UDP_IP)
161777298Sobrien				return;
161877298Sobrien			else
161977298Sobrien				adapter->active_checksum_context = OFFLOAD_UDP_IP;
162077298Sobrien		} else {
162177298Sobrien			*txd_upper = 0;
162277298Sobrien			*txd_lower = 0;
162377298Sobrien			return;
162477298Sobrien		}
162577298Sobrien	} else {
162677298Sobrien		*txd_upper = 0;
162777298Sobrien		*txd_lower = 0;
162877298Sobrien		return;
162977298Sobrien	}
163077298Sobrien
163177298Sobrien	/* If we reach this point, the checksum offload context
163277298Sobrien	 * needs to be reset.
163377298Sobrien	 */
163477298Sobrien	current_tx_desc = adapter->next_avail_tx_desc;
163577298Sobrien	TXD = (struct em_context_desc *)current_tx_desc;
163677298Sobrien
163777298Sobrien	TXD->lower_setup.ip_fields.ipcss = ETHER_HDR_LEN;
163877298Sobrien	TXD->lower_setup.ip_fields.ipcso =
163977298Sobrien	ETHER_HDR_LEN + offsetof(struct ip, ip_sum);
164077298Sobrien	TXD->lower_setup.ip_fields.ipcse =
164177298Sobrien	ETHER_HDR_LEN + sizeof(struct ip) - 1;
164277298Sobrien
164377298Sobrien	TXD->upper_setup.tcp_fields.tucss =
164477298Sobrien	ETHER_HDR_LEN + sizeof(struct ip);
164577298Sobrien	TXD->upper_setup.tcp_fields.tucse = 0;
164677298Sobrien
164777298Sobrien	if (adapter->active_checksum_context == OFFLOAD_TCP_IP) {
164877298Sobrien		TXD->upper_setup.tcp_fields.tucso =
164977298Sobrien		ETHER_HDR_LEN + sizeof(struct ip) +
165077298Sobrien		offsetof(struct tcphdr, th_sum);
165177298Sobrien	} else if (adapter->active_checksum_context == OFFLOAD_UDP_IP) {
165277298Sobrien		TXD->upper_setup.tcp_fields.tucso =
165377298Sobrien		ETHER_HDR_LEN + sizeof(struct ip) +
165477298Sobrien		offsetof(struct udphdr, uh_sum);
165577298Sobrien	}
165677298Sobrien
165777298Sobrien	TXD->tcp_seg_setup.data = 0;
165877298Sobrien	TXD->cmd_and_length = E1000_TXD_CMD_DEXT;
165977298Sobrien
166077298Sobrien	if (current_tx_desc == adapter->last_tx_desc)
166177298Sobrien		adapter->next_avail_tx_desc = adapter->first_tx_desc;
166277298Sobrien	else
166377298Sobrien		adapter->next_avail_tx_desc++;
166477298Sobrien
166577298Sobrien	adapter->num_tx_desc_avail--;
166677298Sobrien
166777298Sobrien	tx_buffer->num_tx_desc_used++;
166877298Sobrien	return;
166977298Sobrien}
167077298Sobrien
167177298Sobrien
167277298Sobrien/*********************************************************************
167377298Sobrien *
167477298Sobrien *  Get a buffer from system mbuf buffer pool.
167577298Sobrien *
167677298Sobrien **********************************************************************/
167777298Sobrienstatic int
167877298Sobrienem_get_buf(struct em_rx_buffer *rx_buffer, struct adapter *adapter,
167989857Sobrien	   struct mbuf *mp)
168077298Sobrien{
168189857Sobrien	struct mbuf    *nmp;
168277298Sobrien	struct ifnet   *ifp;
168377298Sobrien
168477298Sobrien	ifp = &adapter->interface_data.ac_if;
168577298Sobrien
168677298Sobrien	if (mp == NULL) {
168777298Sobrien		MGETHDR(nmp, M_DONTWAIT, MT_DATA);
168877298Sobrien		if (nmp == NULL) {
168977298Sobrien			adapter->mbuf_alloc_failed++;
169077298Sobrien			return(ENOBUFS);
169177298Sobrien		}
169277298Sobrien		MCLGET(nmp, M_DONTWAIT);
169377298Sobrien		if ((nmp->m_flags & M_EXT) == 0) {
169477298Sobrien			m_freem(nmp);
169577298Sobrien			adapter->mbuf_cluster_failed++;
169677298Sobrien			return(ENOBUFS);
169777298Sobrien		}
169877298Sobrien		nmp->m_len = nmp->m_pkthdr.len = MCLBYTES;
169977298Sobrien	} else {
170077298Sobrien		nmp = mp;
170177298Sobrien		nmp->m_len = nmp->m_pkthdr.len = MCLBYTES;
170277298Sobrien		nmp->m_data = nmp->m_ext.ext_buf;
170377298Sobrien		nmp->m_next = NULL;
170477298Sobrien	}
170577298Sobrien
170677298Sobrien	if (ifp->if_mtu <= ETHERMTU) {
170777298Sobrien		m_adj(nmp, ETHER_ALIGN);
170877298Sobrien	}
170977298Sobrien
171077298Sobrien	rx_buffer->m_head = nmp;
171177298Sobrien	rx_buffer->buffer_addr = vtophys(mtod(nmp, vm_offset_t));
171277298Sobrien
171377298Sobrien	return(0);
171477298Sobrien}
171577298Sobrien
171677298Sobrien/*********************************************************************
171777298Sobrien *
171877298Sobrien *  Allocate memory for rx_buffer structures. Since we use one
171977298Sobrien *  rx_buffer per received packet, the maximum number of rx_buffer's
172077298Sobrien *  that we'll need is equal to the number of receive descriptors
172177298Sobrien *  that we've allocated.
172277298Sobrien *
172377298Sobrien **********************************************************************/
172477298Sobrienstatic int
172577298Sobrienem_allocate_receive_structures(struct adapter * adapter)
172677298Sobrien{
172777298Sobrien	int             i;
172877298Sobrien	struct em_rx_buffer   *rx_buffer;
172977298Sobrien
173077298Sobrien	if (!(adapter->rx_buffer_area =
173177298Sobrien	      (struct em_rx_buffer *) malloc(sizeof(struct em_rx_buffer) *
173277298Sobrien					     adapter->num_rx_desc, M_DEVBUF,
173377298Sobrien					     M_NOWAIT))) {
173477298Sobrien		printf("em%d: Unable to allocate rx_buffer memory\n",
173577298Sobrien		       adapter->unit);
173677298Sobrien		return(ENOMEM);
173777298Sobrien	}
173877298Sobrien
173977298Sobrien	bzero(adapter->rx_buffer_area,
174077298Sobrien	      sizeof(struct em_rx_buffer) * adapter->num_rx_desc);
174177298Sobrien
174277298Sobrien	for (i = 0, rx_buffer = adapter->rx_buffer_area;
174377298Sobrien	    i < adapter->num_rx_desc; i++, rx_buffer++) {
174477298Sobrien
174577298Sobrien		if (em_get_buf(rx_buffer, adapter, NULL) == ENOBUFS) {
174677298Sobrien			rx_buffer->m_head = NULL;
174777298Sobrien			return(ENOBUFS);
174877298Sobrien		}
174977298Sobrien	}
175077298Sobrien
175177298Sobrien	return(0);
175277298Sobrien}
175377298Sobrien
175477298Sobrien/*********************************************************************
175577298Sobrien *
175677298Sobrien *  Allocate and initialize receive structures.
175777298Sobrien *
175877298Sobrien **********************************************************************/
175977298Sobrienstatic int
176077298Sobrienem_setup_receive_structures(struct adapter * adapter)
176177298Sobrien{
176277298Sobrien	struct em_rx_buffer   *rx_buffer;
176377298Sobrien	struct em_rx_desc     *rx_desc;
176477298Sobrien	int             i;
176577298Sobrien
176677298Sobrien	if (em_allocate_receive_structures(adapter))
176777298Sobrien		return ENOMEM;
176877298Sobrien
176977298Sobrien	STAILQ_INIT(&adapter->rx_buffer_list);
177077298Sobrien
177177298Sobrien	adapter->first_rx_desc =
177277298Sobrien	(struct em_rx_desc *) adapter->rx_desc_base;
177377298Sobrien	adapter->last_rx_desc =
177477298Sobrien	adapter->first_rx_desc + (adapter->num_rx_desc - 1);
177577298Sobrien
177677298Sobrien	rx_buffer = (struct em_rx_buffer *) adapter->rx_buffer_area;
177777298Sobrien
177877298Sobrien	bzero((void *) adapter->first_rx_desc,
177977298Sobrien	      (sizeof(struct em_rx_desc)) * adapter->num_rx_desc);
178077298Sobrien
178189857Sobrien	/* Build a linked list of rx_buffer's */
178277298Sobrien	for (i = 0, rx_desc = adapter->first_rx_desc;
178377298Sobrien	    i < adapter->num_rx_desc;
178477298Sobrien	    i++, rx_buffer++, rx_desc++) {
178577298Sobrien		if (rx_buffer->m_head == NULL)
178677298Sobrien			printf("em%d: Receive buffer memory not allocated",
178777298Sobrien			       adapter->unit);
178877298Sobrien		else {
178977298Sobrien			rx_desc->buffer_addr = rx_buffer->buffer_addr;
179077298Sobrien			STAILQ_INSERT_TAIL(&adapter->rx_buffer_list,
179189857Sobrien					   rx_buffer, em_rx_entry);
179277298Sobrien		}
179377298Sobrien	}
179477298Sobrien
179577298Sobrien	/* Setup our descriptor pointers */
179677298Sobrien	adapter->next_rx_desc_to_check = adapter->first_rx_desc;
179777298Sobrien
179877298Sobrien	return(0);
179977298Sobrien}
180077298Sobrien
180177298Sobrien/*********************************************************************
180277298Sobrien *
180377298Sobrien *  Enable receive unit.
180477298Sobrien *
180577298Sobrien **********************************************************************/
180677298Sobrienstatic void
180777298Sobrienem_initialize_receive_unit(struct adapter * adapter)
180877298Sobrien{
180977298Sobrien	u_int32_t       reg_rctl;
181077298Sobrien	u_int32_t       reg_rxcsum;
181177298Sobrien	struct ifnet    *ifp;
181277298Sobrien
181377298Sobrien	ifp = &adapter->interface_data.ac_if;
181489857Sobrien
181577298Sobrien	/* Make sure receives are disabled while setting up the descriptor ring */
181677298Sobrien	E1000_WRITE_REG(&adapter->hw, RCTL, 0);
181777298Sobrien
181877298Sobrien	/* Set the Receive Delay Timer Register */
181977298Sobrien	E1000_WRITE_REG(&adapter->hw, RDTR,
182077298Sobrien			adapter->rx_int_delay | E1000_RDT_FPDB);
182177298Sobrien
182277298Sobrien	/* Setup the Base and Length of the Rx Descriptor Ring */
182377298Sobrien	E1000_WRITE_REG(&adapter->hw, RDBAL,
182477298Sobrien			vtophys((vm_offset_t) adapter->rx_desc_base));
182577298Sobrien	E1000_WRITE_REG(&adapter->hw, RDBAH, 0);
182677298Sobrien	E1000_WRITE_REG(&adapter->hw, RDLEN, adapter->num_rx_desc *
182777298Sobrien			sizeof(struct em_rx_desc));
182877298Sobrien
182977298Sobrien	/* Setup the HW Rx Head and Tail Descriptor Pointers */
183077298Sobrien	E1000_WRITE_REG(&adapter->hw, RDH, 0);
183177298Sobrien	E1000_WRITE_REG(&adapter->hw, RDT,
183277298Sobrien			(((uintptr_t) adapter->last_rx_desc -
183377298Sobrien			  (uintptr_t) adapter->first_rx_desc) >> 4));
183477298Sobrien
183577298Sobrien	/* Setup the Receive Control Register */
183677298Sobrien	reg_rctl = E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_LBM_NO |
183777298Sobrien		   E1000_RCTL_RDMTS_HALF |
183877298Sobrien		   (adapter->hw.mc_filter_type << E1000_RCTL_MO_SHIFT);
183977298Sobrien
184077298Sobrien	if (adapter->hw.tbi_compatibility_on == TRUE)
184177298Sobrien		reg_rctl |= E1000_RCTL_SBP;
184277298Sobrien
184377298Sobrien
184477298Sobrien	switch (adapter->rx_buffer_len) {
184577298Sobrien	default:
184677298Sobrien	case EM_RXBUFFER_2048:
184777298Sobrien		reg_rctl |= E1000_RCTL_SZ_2048;
184877298Sobrien		break;
184977298Sobrien	case EM_RXBUFFER_4096:
185077298Sobrien		reg_rctl |= E1000_RCTL_SZ_4096 | E1000_RCTL_BSEX | E1000_RCTL_LPE;
185177298Sobrien		break;
185277298Sobrien	case EM_RXBUFFER_8192:
185377298Sobrien		reg_rctl |= E1000_RCTL_SZ_8192 | E1000_RCTL_BSEX | E1000_RCTL_LPE;
185477298Sobrien		break;
185577298Sobrien	case EM_RXBUFFER_16384:
185677298Sobrien		reg_rctl |= E1000_RCTL_SZ_16384 | E1000_RCTL_BSEX | E1000_RCTL_LPE;
185777298Sobrien		break;
185877298Sobrien	}
185977298Sobrien
186077298Sobrien	if (ifp->if_mtu > ETHERMTU)
186177298Sobrien		reg_rctl |= E1000_RCTL_LPE;
186277298Sobrien
186377298Sobrien	/* Enable 82543 Receive Checksum Offload for TCP and UDP */
186477298Sobrien	if ((adapter->hw.mac_type >= em_82543) &&
186577298Sobrien	    (ifp->if_capenable & IFCAP_RXCSUM)) {
186677298Sobrien		reg_rxcsum = E1000_READ_REG(&adapter->hw, RXCSUM);
186777298Sobrien		reg_rxcsum |= (E1000_RXCSUM_IPOFL | E1000_RXCSUM_TUOFL);
186877298Sobrien		E1000_WRITE_REG(&adapter->hw, RXCSUM, reg_rxcsum);
186977298Sobrien	}
187077298Sobrien
187177298Sobrien	/* Enable Receives */
187277298Sobrien	E1000_WRITE_REG(&adapter->hw, RCTL, reg_rctl);
187377298Sobrien
187477298Sobrien	return;
187577298Sobrien}
187677298Sobrien
187777298Sobrien/*********************************************************************
187889857Sobrien *
187977298Sobrien *  Free receive related data structures.
188077298Sobrien *
188177298Sobrien **********************************************************************/
188289857Sobrienstatic void
188377298Sobrienem_free_receive_structures(struct adapter * adapter)
188477298Sobrien{
188577298Sobrien	struct em_rx_buffer   *rx_buffer;
188677298Sobrien	int             i;
188777298Sobrien
188877298Sobrien	INIT_DEBUGOUT("free_receive_structures: begin");
188989857Sobrien
189077298Sobrien	if (adapter->rx_buffer_area != NULL) {
189177298Sobrien		rx_buffer = adapter->rx_buffer_area;
189277298Sobrien		for (i = 0; i < adapter->num_rx_desc; i++, rx_buffer++) {
189377298Sobrien			if (rx_buffer->m_head != NULL)
189477298Sobrien				m_freem(rx_buffer->m_head);
189577298Sobrien			rx_buffer->m_head = NULL;
189677298Sobrien		}
189777298Sobrien	}
189877298Sobrien	if (adapter->rx_buffer_area != NULL) {
189977298Sobrien		free(adapter->rx_buffer_area, M_DEVBUF);
190077298Sobrien		adapter->rx_buffer_area = NULL;
190177298Sobrien	}
190277298Sobrien	return;
190377298Sobrien}
190477298Sobrien
190577298Sobrien/*********************************************************************
190689857Sobrien *
190777298Sobrien *  This routine executes in interrupt context. It replenishes
190877298Sobrien *  the mbufs in the descriptor and sends data which has been
190977298Sobrien *  dma'ed into host memory to upper layer.
191089857Sobrien *
191177298Sobrien *********************************************************************/
191277298Sobrienstatic void
191377298Sobrienem_process_receive_interrupts(struct adapter * adapter)
191477298Sobrien{
191589857Sobrien	struct mbuf         *mp;
191677298Sobrien	struct ifnet        *ifp;
191777298Sobrien	struct ether_header *eh;
191877298Sobrien	u_int16_t           len;
191977298Sobrien	u_int8_t            last_byte;
192077298Sobrien	u_int8_t            accept_frame = 0;
192177298Sobrien	u_int8_t            eop = 0;
192277298Sobrien	u_int32_t           pkt_len = 0;
192377298Sobrien
192477298Sobrien	/* Pointer to the receive descriptor being examined. */
192577298Sobrien	struct em_rx_desc   *current_desc;
192677298Sobrien	struct em_rx_desc   *last_desc_processed;
192777298Sobrien	struct em_rx_buffer *rx_buffer;
192877298Sobrien
192977298Sobrien	ifp = &adapter->interface_data.ac_if;
193077298Sobrien	current_desc = adapter->next_rx_desc_to_check;
193177298Sobrien
193277298Sobrien	if (!((current_desc->status) & E1000_RXD_STAT_DD)) {
193377298Sobrien#ifdef DBG_STATS
193477298Sobrien		adapter->no_pkts_avail++;
193577298Sobrien#endif
193677298Sobrien		return;
193777298Sobrien	}
193877298Sobrien
193977298Sobrien	while (current_desc->status & E1000_RXD_STAT_DD) {
194077298Sobrien
194177298Sobrien		/* Get a pointer to the actual receive buffer */
194277298Sobrien		rx_buffer = STAILQ_FIRST(&adapter->rx_buffer_list);
194377298Sobrien
194477298Sobrien		if (rx_buffer == NULL) {
194577298Sobrien			printf("em%d: Found null rx_buffer\n", adapter->unit);
194677298Sobrien			return;
194777298Sobrien		}
194877298Sobrien
194977298Sobrien		mp = rx_buffer->m_head;
195077298Sobrien		accept_frame = 1;
195177298Sobrien
195277298Sobrien		if (current_desc->status & E1000_RXD_STAT_EOP) {
195377298Sobrien			eop = 1;
195477298Sobrien			len = current_desc->length - ETHER_CRC_LEN;
195577298Sobrien		} else {
195677298Sobrien			eop = 0;
195777298Sobrien			len = current_desc->length;
195877298Sobrien		}
195977298Sobrien
196077298Sobrien		if (current_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK) {
196177298Sobrien
196277298Sobrien			/* Compute packet length for tbi_accept macro */
196377298Sobrien			pkt_len = current_desc->length;
196477298Sobrien			if (adapter->fmp != NULL) {
196577298Sobrien				pkt_len += adapter->fmp->m_pkthdr.len;
196677298Sobrien			}
196777298Sobrien
196877298Sobrien			last_byte = *(mtod(rx_buffer->m_head,caddr_t) +
196977298Sobrien				      current_desc->length - 1);
197077298Sobrien
197177298Sobrien			if (TBI_ACCEPT(&adapter->hw, current_desc->status,
197277298Sobrien				       current_desc->errors,
197377298Sobrien				       pkt_len, last_byte)) {
197477298Sobrien				em_tbi_adjust_stats(&adapter->hw,
197577298Sobrien						    &adapter->stats,
197677298Sobrien						    pkt_len,
197777298Sobrien						    adapter->hw.mac_addr);
197877298Sobrien				len--;
197977298Sobrien			} else {
198077298Sobrien				accept_frame = 0;
198177298Sobrien			}
198277298Sobrien		}
198377298Sobrien
198477298Sobrien		if (accept_frame) {
198577298Sobrien
198677298Sobrien			if (em_get_buf(rx_buffer, adapter, NULL) == ENOBUFS) {
198777298Sobrien				adapter->dropped_pkts++;
198877298Sobrien				em_get_buf(rx_buffer, adapter, mp);
198977298Sobrien				if (adapter->fmp != NULL) m_freem(adapter->fmp);
199077298Sobrien				adapter->fmp = NULL;
199177298Sobrien				adapter->lmp = NULL;
199277298Sobrien				break;
199377298Sobrien			}
199477298Sobrien
199577298Sobrien			/* Assign correct length to the current fragment */
199677298Sobrien			mp->m_len = len;
199777298Sobrien
199877298Sobrien			if (adapter->fmp == NULL) {
199977298Sobrien				mp->m_pkthdr.len = len;
200077298Sobrien				adapter->fmp = mp;	 /* Store the first mbuf */
200177298Sobrien				adapter->lmp = mp;
200277298Sobrien			} else {
200377298Sobrien				/* Chain mbuf's together */
200477298Sobrien				mp->m_flags &= ~M_PKTHDR;
200577298Sobrien				adapter->lmp->m_next = mp;
200677298Sobrien				adapter->lmp = adapter->lmp->m_next;
200777298Sobrien				adapter->fmp->m_pkthdr.len += len;
200877298Sobrien			}
200977298Sobrien
201077298Sobrien			if (eop) {
201177298Sobrien				adapter->fmp->m_pkthdr.rcvif = ifp;
201277298Sobrien
201377298Sobrien				eh = mtod(adapter->fmp, struct ether_header *);
201477298Sobrien
201577298Sobrien				/* Remove ethernet header from mbuf */
201677298Sobrien				m_adj(adapter->fmp, sizeof(struct ether_header));
201777298Sobrien				em_receive_checksum(adapter, current_desc,
201877298Sobrien						    adapter->fmp);
201977298Sobrien				if (current_desc->status & E1000_RXD_STAT_VP)
202077298Sobrien					VLAN_INPUT_TAG(eh, adapter->fmp,
202177298Sobrien						       current_desc->special);
202277298Sobrien				else
202377298Sobrien					ether_input(ifp, eh, adapter->fmp);
202477298Sobrien
202577298Sobrien				adapter->fmp = NULL;
202677298Sobrien				adapter->lmp = NULL;
202777298Sobrien			}
202877298Sobrien		} else {
202977298Sobrien			adapter->dropped_pkts++;
203077298Sobrien			em_get_buf(rx_buffer, adapter, mp);
203177298Sobrien			if (adapter->fmp != NULL) m_freem(adapter->fmp);
203277298Sobrien			adapter->fmp = NULL;
203377298Sobrien			adapter->lmp = NULL;
203477298Sobrien		}
203577298Sobrien
203677298Sobrien		/* Zero out the receive descriptors status  */
203777298Sobrien		current_desc->status = 0;
203877298Sobrien
203977298Sobrien		if (rx_buffer->m_head != NULL) {
204077298Sobrien			current_desc->buffer_addr = rx_buffer->buffer_addr;
204177298Sobrien		}
204277298Sobrien
204377298Sobrien		/* Advance our pointers to the next descriptor (checking for wrap). */
204477298Sobrien		if (current_desc == adapter->last_rx_desc)
204577298Sobrien			adapter->next_rx_desc_to_check = adapter->first_rx_desc;
204677298Sobrien		else
204777298Sobrien			((adapter)->next_rx_desc_to_check)++;
204877298Sobrien
204977298Sobrien		last_desc_processed = current_desc;
205077298Sobrien		current_desc = adapter->next_rx_desc_to_check;
205177298Sobrien		/*
205277298Sobrien		 * Put the buffer that we just indicated back at the end of our list
205377298Sobrien		 */
205477298Sobrien		STAILQ_REMOVE_HEAD(&adapter->rx_buffer_list, em_rx_entry);
205577298Sobrien		STAILQ_INSERT_TAIL(&adapter->rx_buffer_list,
205677298Sobrien				   rx_buffer, em_rx_entry);
205777298Sobrien
205877298Sobrien		/* Advance the E1000's Receive Queue #0  "Tail Pointer". */
205977298Sobrien		E1000_WRITE_REG(&adapter->hw, RDT,
206077298Sobrien				(((u_long) last_desc_processed -
206177298Sobrien				  (u_long) adapter->first_rx_desc) >> 4));
206277298Sobrien	}
206377298Sobrien	return;
206477298Sobrien}
206577298Sobrien
206677298Sobrien/*********************************************************************
206777298Sobrien *
206877298Sobrien *  Verify that the hardware indicated that the checksum is valid.
206977298Sobrien *  Inform the stack about the status of checksum so that stack
207077298Sobrien *  doesn't spend time verifying the checksum.
207177298Sobrien *
207277298Sobrien *********************************************************************/
207377298Sobrienstatic void
207477298Sobrienem_receive_checksum(struct adapter *adapter,
207577298Sobrien		    struct em_rx_desc *rx_desc,
207677298Sobrien		    struct mbuf *mp)
207777298Sobrien{
207877298Sobrien	/* 82543 or newer only */
207977298Sobrien	if ((adapter->hw.mac_type < em_82543) ||
208077298Sobrien	    /* Ignore Checksum bit is set */
208177298Sobrien	    (rx_desc->status & E1000_RXD_STAT_IXSM)) {
208277298Sobrien		mp->m_pkthdr.csum_flags = 0;
208377298Sobrien		return;
208477298Sobrien	}
208577298Sobrien
208677298Sobrien	if (rx_desc->status & E1000_RXD_STAT_IPCS) {
208777298Sobrien		/* Did it pass? */
208877298Sobrien		if (!(rx_desc->errors & E1000_RXD_ERR_IPE)) {
208977298Sobrien			/* IP Checksum Good */
209077298Sobrien			mp->m_pkthdr.csum_flags = CSUM_IP_CHECKED;
209177298Sobrien			mp->m_pkthdr.csum_flags |= CSUM_IP_VALID;
209277298Sobrien
209377298Sobrien		} else {
209477298Sobrien			mp->m_pkthdr.csum_flags = 0;
209577298Sobrien		}
209677298Sobrien	}
209777298Sobrien
209877298Sobrien	if (rx_desc->status & E1000_RXD_STAT_TCPCS) {
209977298Sobrien		/* Did it pass? */
210077298Sobrien		if (!(rx_desc->errors & E1000_RXD_ERR_TCPE)) {
210177298Sobrien			mp->m_pkthdr.csum_flags |=
210277298Sobrien			(CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
210377298Sobrien			mp->m_pkthdr.csum_data = htons(0xffff);
210477298Sobrien		}
210577298Sobrien	}
210677298Sobrien
210777298Sobrien	return;
210877298Sobrien}
210977298Sobrien
211077298Sobrien
211177298Sobrienstatic void em_enable_vlans(struct adapter *adapter)
211277298Sobrien{
211377298Sobrien	uint32_t ctrl;
211477298Sobrien
211577298Sobrien	E1000_WRITE_REG(&adapter->hw, VET, QTAG_TYPE);
211677298Sobrien
211777298Sobrien	ctrl = E1000_READ_REG(&adapter->hw, CTRL);
211877298Sobrien	ctrl |= E1000_CTRL_VME;
211977298Sobrien	E1000_WRITE_REG(&adapter->hw, CTRL, ctrl);
212077298Sobrien
212177298Sobrien	return;
212277298Sobrien}
212377298Sobrien
212477298Sobrienstatic void
212577298Sobrienem_enable_intr(struct adapter * adapter)
212677298Sobrien{
212777298Sobrien	E1000_WRITE_REG(&adapter->hw, IMS, (IMS_ENABLE_MASK));
212877298Sobrien	return;
212977298Sobrien}
213077298Sobrien
213177298Sobrienstatic void
213277298Sobrienem_disable_intr(struct adapter *adapter)
213377298Sobrien{
213477298Sobrien	E1000_WRITE_REG(&adapter->hw, IMC,
213577298Sobrien			(0xffffffff & ~E1000_IMC_RXSEQ));
213677298Sobrien	return;
213777298Sobrien}
213877298Sobrien
213977298Sobrienvoid em_write_pci_cfg(struct em_hw *hw,
214077298Sobrien		      uint32_t reg,
214177298Sobrien		      uint16_t *value)
214277298Sobrien{
214377298Sobrien	pci_write_config(((struct em_osdep *)hw->back)->dev, reg,
214477298Sobrien			 *value, 2);
214577298Sobrien}
214677298Sobrien
214777298Sobrienvoid em_read_pci_cfg(struct em_hw *hw, uint32_t reg,
214877298Sobrien		     uint16_t *value)
214977298Sobrien{
215077298Sobrien	*value = pci_read_config(((struct em_osdep *)hw->back)->dev,
215177298Sobrien				 reg, 2);
215277298Sobrien	return;
215377298Sobrien}
215477298Sobrien
215577298Sobrienuint32_t em_io_read(struct em_hw *hw, uint32_t port)
215677298Sobrien{
215777298Sobrien	return(inl(port));
215877298Sobrien}
215977298Sobrien
216077298Sobrienvoid em_io_write(struct em_hw *hw, uint32_t port, uint32_t value)
216177298Sobrien{
216277298Sobrien	outl(port, value);
216377298Sobrien	return;
216477298Sobrien}
216577298Sobrien
216677298Sobrien/**********************************************************************
216777298Sobrien *
216877298Sobrien *  Update the board statistics counters.
216977298Sobrien *
217077298Sobrien **********************************************************************/
217177298Sobrienstatic void
217277298Sobrienem_update_stats_counters(struct adapter *adapter)
217377298Sobrien{
217477298Sobrien	struct ifnet   *ifp;
217577298Sobrien
217677298Sobrien	adapter->stats.crcerrs += E1000_READ_REG(&adapter->hw, CRCERRS);
217777298Sobrien	adapter->stats.symerrs += E1000_READ_REG(&adapter->hw, SYMERRS);
217877298Sobrien	adapter->stats.mpc += E1000_READ_REG(&adapter->hw, MPC);
217977298Sobrien	adapter->stats.scc += E1000_READ_REG(&adapter->hw, SCC);
218077298Sobrien	adapter->stats.ecol += E1000_READ_REG(&adapter->hw, ECOL);
218177298Sobrien	adapter->stats.mcc += E1000_READ_REG(&adapter->hw, MCC);
218277298Sobrien	adapter->stats.latecol += E1000_READ_REG(&adapter->hw, LATECOL);
218377298Sobrien	adapter->stats.colc += E1000_READ_REG(&adapter->hw, COLC);
218477298Sobrien	adapter->stats.dc += E1000_READ_REG(&adapter->hw, DC);
218577298Sobrien	adapter->stats.sec += E1000_READ_REG(&adapter->hw, SEC);
218677298Sobrien	adapter->stats.rlec += E1000_READ_REG(&adapter->hw, RLEC);
218777298Sobrien	adapter->stats.xonrxc += E1000_READ_REG(&adapter->hw, XONRXC);
218877298Sobrien	adapter->stats.xontxc += E1000_READ_REG(&adapter->hw, XONTXC);
218977298Sobrien	adapter->stats.xoffrxc += E1000_READ_REG(&adapter->hw, XOFFRXC);
219077298Sobrien	adapter->stats.xofftxc += E1000_READ_REG(&adapter->hw, XOFFTXC);
219177298Sobrien	adapter->stats.fcruc += E1000_READ_REG(&adapter->hw, FCRUC);
219277298Sobrien	adapter->stats.prc64 += E1000_READ_REG(&adapter->hw, PRC64);
219377298Sobrien	adapter->stats.prc127 += E1000_READ_REG(&adapter->hw, PRC127);
219477298Sobrien	adapter->stats.prc255 += E1000_READ_REG(&adapter->hw, PRC255);
219577298Sobrien	adapter->stats.prc511 += E1000_READ_REG(&adapter->hw, PRC511);
219677298Sobrien	adapter->stats.prc1023 += E1000_READ_REG(&adapter->hw, PRC1023);
219777298Sobrien	adapter->stats.prc1522 += E1000_READ_REG(&adapter->hw, PRC1522);
219877298Sobrien	adapter->stats.gprc += E1000_READ_REG(&adapter->hw, GPRC);
219977298Sobrien	adapter->stats.bprc += E1000_READ_REG(&adapter->hw, BPRC);
220077298Sobrien	adapter->stats.mprc += E1000_READ_REG(&adapter->hw, MPRC);
220177298Sobrien	adapter->stats.gptc += E1000_READ_REG(&adapter->hw, GPTC);
220277298Sobrien
220377298Sobrien	/* For the 64-bit byte counters the low dword must be read first. */
220477298Sobrien	/* Both registers clear on the read of the high dword */
220577298Sobrien
220677298Sobrien	adapter->stats.gorcl += E1000_READ_REG(&adapter->hw, GORCL);
220777298Sobrien	adapter->stats.gorch += E1000_READ_REG(&adapter->hw, GORCH);
220877298Sobrien	adapter->stats.gotcl += E1000_READ_REG(&adapter->hw, GOTCL);
220977298Sobrien	adapter->stats.gotch += E1000_READ_REG(&adapter->hw, GOTCH);
221077298Sobrien
221177298Sobrien	adapter->stats.rnbc += E1000_READ_REG(&adapter->hw, RNBC);
221277298Sobrien	adapter->stats.ruc += E1000_READ_REG(&adapter->hw, RUC);
221377298Sobrien	adapter->stats.rfc += E1000_READ_REG(&adapter->hw, RFC);
221477298Sobrien	adapter->stats.roc += E1000_READ_REG(&adapter->hw, ROC);
221577298Sobrien	adapter->stats.rjc += E1000_READ_REG(&adapter->hw, RJC);
221677298Sobrien
221777298Sobrien	adapter->stats.torl += E1000_READ_REG(&adapter->hw, TORL);
221877298Sobrien	adapter->stats.torh += E1000_READ_REG(&adapter->hw, TORH);
221977298Sobrien	adapter->stats.totl += E1000_READ_REG(&adapter->hw, TOTL);
222077298Sobrien	adapter->stats.toth += E1000_READ_REG(&adapter->hw, TOTH);
222177298Sobrien
222277298Sobrien	adapter->stats.tpr += E1000_READ_REG(&adapter->hw, TPR);
222377298Sobrien	adapter->stats.tpt += E1000_READ_REG(&adapter->hw, TPT);
222477298Sobrien	adapter->stats.ptc64 += E1000_READ_REG(&adapter->hw, PTC64);
222577298Sobrien	adapter->stats.ptc127 += E1000_READ_REG(&adapter->hw, PTC127);
222677298Sobrien	adapter->stats.ptc255 += E1000_READ_REG(&adapter->hw, PTC255);
222777298Sobrien	adapter->stats.ptc511 += E1000_READ_REG(&adapter->hw, PTC511);
222877298Sobrien	adapter->stats.ptc1023 += E1000_READ_REG(&adapter->hw, PTC1023);
222977298Sobrien	adapter->stats.ptc1522 += E1000_READ_REG(&adapter->hw, PTC1522);
223077298Sobrien	adapter->stats.mptc += E1000_READ_REG(&adapter->hw, MPTC);
223177298Sobrien	adapter->stats.bptc += E1000_READ_REG(&adapter->hw, BPTC);
223277298Sobrien
223377298Sobrien	if (adapter->hw.mac_type >= em_82543) {
223477298Sobrien		adapter->stats.algnerrc +=
223577298Sobrien		E1000_READ_REG(&adapter->hw, ALGNERRC);
223677298Sobrien		adapter->stats.rxerrc +=
223777298Sobrien		E1000_READ_REG(&adapter->hw, RXERRC);
223877298Sobrien		adapter->stats.tncrs +=
223977298Sobrien		E1000_READ_REG(&adapter->hw, TNCRS);
224077298Sobrien		adapter->stats.cexterr +=
224177298Sobrien		E1000_READ_REG(&adapter->hw, CEXTERR);
224277298Sobrien		adapter->stats.tsctc +=
224377298Sobrien		E1000_READ_REG(&adapter->hw, TSCTC);
224477298Sobrien		adapter->stats.tsctfc +=
224577298Sobrien		E1000_READ_REG(&adapter->hw, TSCTFC);
224677298Sobrien	}
224777298Sobrien	ifp = &adapter->interface_data.ac_if;
224877298Sobrien
224977298Sobrien	/* Fill out the OS statistics structure */
225077298Sobrien	ifp->if_ipackets = adapter->stats.gprc;
225177298Sobrien	ifp->if_opackets = adapter->stats.gptc;
225277298Sobrien	ifp->if_ibytes = adapter->stats.gorcl;
225377298Sobrien	ifp->if_obytes = adapter->stats.gotcl;
225477298Sobrien	ifp->if_imcasts = adapter->stats.mprc;
225577298Sobrien	ifp->if_collisions = adapter->stats.colc;
225677298Sobrien
225777298Sobrien	/* Rx Errors */
225877298Sobrien	ifp->if_ierrors =
225977298Sobrien	adapter->dropped_pkts +
226077298Sobrien	adapter->stats.rxerrc +
226177298Sobrien	adapter->stats.crcerrs +
226277298Sobrien	adapter->stats.algnerrc +
226377298Sobrien	adapter->stats.rlec + adapter->stats.rnbc +
226477298Sobrien	adapter->stats.mpc + adapter->stats.cexterr;
226577298Sobrien
226677298Sobrien	/* Tx Errors */
226777298Sobrien	ifp->if_oerrors = adapter->stats.ecol + adapter->stats.latecol;
226877298Sobrien
226977298Sobrien}
227077298Sobrien
227177298Sobrien
227277298Sobrien/**********************************************************************
227377298Sobrien *
227477298Sobrien *  This routine is called only when em_display_debug_stats is enabled.
227577298Sobrien *  This routine provides a way to take a look at important statistics
227677298Sobrien *  maintained by the driver and hardware.
227777298Sobrien *
227877298Sobrien **********************************************************************/
227977298Sobrienstatic void
228077298Sobrienem_print_hw_stats(struct adapter *adapter)
228177298Sobrien{
228277298Sobrien	int unit = adapter->unit;
228377298Sobrien
228477298Sobrien#ifdef DBG_STATS
228577298Sobrien	printf("em%d: Packets not Avail = %ld\n", unit,
228677298Sobrien	       adapter->no_pkts_avail);
228777298Sobrien	printf("em%d: CleanTxInterrupts = %ld\n", unit,
228877298Sobrien	       adapter->clean_tx_interrupts);
228977298Sobrien#endif
229077298Sobrien
229177298Sobrien	printf("em%d: Tx Descriptors not Avail = %ld\n", unit,
229277298Sobrien	       adapter->no_tx_desc_avail);
229377298Sobrien	printf("em%d: Tx Buffer not avail1 = %ld\n", unit,
229477298Sobrien	       adapter->no_tx_buffer_avail1);
229577298Sobrien	printf("em%d: Tx Buffer not avail2 = %ld\n", unit,
229677298Sobrien	       adapter->no_tx_buffer_avail2);
229777298Sobrien	printf("em%d: Std Mbuf Failed = %ld\n",unit,
229877298Sobrien	       adapter->mbuf_alloc_failed);
229977298Sobrien	printf("em%d: Std Cluster Failed = %ld\n",unit,
230077298Sobrien	       adapter->mbuf_cluster_failed);
230177298Sobrien
230277298Sobrien	printf("em%d: Symbol errors = %lld\n", unit,
230377298Sobrien	       (long long)adapter->stats.symerrs);
230477298Sobrien	printf("em%d: Sequence errors = %lld\n", unit,
230577298Sobrien	       (long long)adapter->stats.sec);
230677298Sobrien	printf("em%d: Defer count = %lld\n", unit,
230777298Sobrien	       (long long)adapter->stats.dc);
230877298Sobrien
230977298Sobrien	printf("em%d: Missed Packets = %lld\n", unit,
231077298Sobrien	       (long long)adapter->stats.mpc);
231177298Sobrien	printf("em%d: Receive No Buffers = %lld\n", unit,
231277298Sobrien	       (long long)adapter->stats.rnbc);
231377298Sobrien	printf("em%d: Receive length errors = %lld\n", unit,
231477298Sobrien	       (long long)adapter->stats.rlec);
231577298Sobrien	printf("em%d: Receive errors = %lld\n", unit,
231677298Sobrien	       (long long)adapter->stats.rxerrc);
231777298Sobrien	printf("em%d: Crc errors = %lld\n", unit,
231877298Sobrien	       (long long)adapter->stats.crcerrs);
231977298Sobrien	printf("em%d: Alignment errors = %lld\n", unit,
232077298Sobrien	       (long long)adapter->stats.algnerrc);
232177298Sobrien	printf("em%d: Carrier extension errors = %lld\n", unit,
232277298Sobrien	       (long long)adapter->stats.cexterr);
232377298Sobrien	printf("em%d: Driver dropped packets = %ld\n", unit,
232477298Sobrien	       adapter->dropped_pkts);
232577298Sobrien
232677298Sobrien	printf("em%d: XON Rcvd = %lld\n", unit,
232777298Sobrien	       (long long)adapter->stats.xonrxc);
232877298Sobrien	printf("em%d: XON Xmtd = %lld\n", unit,
232977298Sobrien	       (long long)adapter->stats.xontxc);
233077298Sobrien	printf("em%d: XOFF Rcvd = %lld\n", unit,
233177298Sobrien	       (long long)adapter->stats.xoffrxc);
233277298Sobrien	printf("em%d: XOFF Xmtd = %lld\n", unit,
233377298Sobrien	       (long long)adapter->stats.xofftxc);
233477298Sobrien
233577298Sobrien	printf("em%d: Good Packets Rcvd = %lld\n", unit,
233677298Sobrien	       (long long)adapter->stats.gprc);
233777298Sobrien	printf("em%d: Good Packets Xmtd = %lld\n", unit,
233877298Sobrien	       (long long)adapter->stats.gptc);
233977298Sobrien
234077298Sobrien	return;
234177298Sobrien}
234277298Sobrien
234377298Sobrien
234477298Sobrien/**********************************************************************
234577298Sobrien *
234677298Sobrien *  Examine each tx_buffer in the used queue. If the hardware is done
234777298Sobrien *  processing the packet then free associated resources. The
234877298Sobrien *  tx_buffer is put back on the free queue.
234977298Sobrien *
235077298Sobrien **********************************************************************/
235177298Sobrienstatic void
235277298Sobrienem_clean_transmit_interrupts(struct adapter * adapter)
235377298Sobrien{
235477298Sobrien	struct em_tx_buffer *tx_buffer;
235577298Sobrien	struct em_tx_desc   *tx_desc;
235677298Sobrien	int             s;
235777298Sobrien	struct ifnet   *ifp;
235877298Sobrien
235977298Sobrien	s = splimp();
236077298Sobrien#ifdef DBG_STATS
236177298Sobrien	adapter->clean_tx_interrupts++;
236277298Sobrien#endif
236377298Sobrien
236477298Sobrien	for (tx_buffer = STAILQ_FIRST(&adapter->used_tx_buffer_list);
236577298Sobrien	    tx_buffer;
236677298Sobrien	    tx_buffer = STAILQ_FIRST(&adapter->used_tx_buffer_list)) {
236777298Sobrien
236877298Sobrien		/*
236977298Sobrien		 * Get hold of the next descriptor that the em will report status
237077298Sobrien		 * back to (this will be the last descriptor of a given tx_buffer). We
237177298Sobrien		 * only want to free the tx_buffer (and it resources) if the driver is
237277298Sobrien		 * done with ALL of the descriptors.  If the driver is done with the
237377298Sobrien		 * last one then it is done with all of them.
237477298Sobrien		 */
237577298Sobrien
237677298Sobrien		tx_desc = adapter->oldest_used_tx_desc +
237777298Sobrien			  (tx_buffer->num_tx_desc_used - 1);
237877298Sobrien
237977298Sobrien		/* Check for wrap case */
238077298Sobrien		if (tx_desc > adapter->last_tx_desc)
238177298Sobrien			tx_desc -= adapter->num_tx_desc;
238277298Sobrien
238377298Sobrien
238477298Sobrien		/*
238577298Sobrien		 * If the descriptor done bit is set free tx_buffer and associated
238677298Sobrien		 * resources
238777298Sobrien		 */
238877298Sobrien		if (tx_desc->upper.fields.status & E1000_TXD_STAT_DD) {
238977298Sobrien
239077298Sobrien			STAILQ_REMOVE_HEAD(&adapter->used_tx_buffer_list,
239177298Sobrien					   em_tx_entry);
239277298Sobrien
239377298Sobrien			if ((tx_desc == adapter->last_tx_desc))
239477298Sobrien				adapter->oldest_used_tx_desc =
239577298Sobrien				adapter->first_tx_desc;
239677298Sobrien			else
239777298Sobrien				adapter->oldest_used_tx_desc = (tx_desc + 1);
239877298Sobrien
239977298Sobrien			/* Make available the descriptors that were previously used */
240077298Sobrien			adapter->num_tx_desc_avail +=
240177298Sobrien			tx_buffer->num_tx_desc_used;
240277298Sobrien
240377298Sobrien			tx_buffer->num_tx_desc_used = 0;
240477298Sobrien
240577298Sobrien			if (tx_buffer->m_head) {
240677298Sobrien				m_freem(tx_buffer->m_head);
240777298Sobrien				tx_buffer->m_head = NULL;
240877298Sobrien			}
240977298Sobrien			/* Return this "Software packet" back to the "free" list */
241077298Sobrien			STAILQ_INSERT_TAIL(&adapter->free_tx_buffer_list,
241177298Sobrien					   tx_buffer, em_tx_entry);
241277298Sobrien		} else {
241377298Sobrien			/*
241477298Sobrien			 * Found a tx_buffer that the em is not done with then there is
241577298Sobrien			 * no reason to check the rest of the queue.
241677298Sobrien			 */
241777298Sobrien			break;
241877298Sobrien		}
241977298Sobrien	}		      /* end for each tx_buffer */
242077298Sobrien
242177298Sobrien	ifp = &adapter->interface_data.ac_if;
242277298Sobrien
242377298Sobrien	/* Tell the stack that it is OK to send packets */
242477298Sobrien	if (adapter->num_tx_desc_avail > TX_CLEANUP_THRESHOLD) {
242577298Sobrien		ifp->if_timer = 0;
242677298Sobrien		ifp->if_flags &= ~IFF_OACTIVE;
242777298Sobrien	}
242877298Sobrien	splx(s);
242977298Sobrien	return;
243077298Sobrien}
243177298Sobrien
243277298Sobrien