110393SSaurabh.Mishra@Sun.COM /*
210393SSaurabh.Mishra@Sun.COM * CDDL HEADER START
310393SSaurabh.Mishra@Sun.COM *
410393SSaurabh.Mishra@Sun.COM * The contents of this file are subject to the terms of the
510393SSaurabh.Mishra@Sun.COM * Common Development and Distribution License (the "License").
610393SSaurabh.Mishra@Sun.COM * You may not use this file except in compliance with the License.
710393SSaurabh.Mishra@Sun.COM *
810393SSaurabh.Mishra@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
910393SSaurabh.Mishra@Sun.COM * or http://www.opensolaris.org/os/licensing.
1010393SSaurabh.Mishra@Sun.COM * See the License for the specific language governing permissions
1110393SSaurabh.Mishra@Sun.COM * and limitations under the License.
1210393SSaurabh.Mishra@Sun.COM *
1310393SSaurabh.Mishra@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
1410393SSaurabh.Mishra@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1510393SSaurabh.Mishra@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
1610393SSaurabh.Mishra@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
1710393SSaurabh.Mishra@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
1810393SSaurabh.Mishra@Sun.COM *
1910393SSaurabh.Mishra@Sun.COM * CDDL HEADER END
2010393SSaurabh.Mishra@Sun.COM */
2110393SSaurabh.Mishra@Sun.COM
2210393SSaurabh.Mishra@Sun.COM /*
23*12398Sgdamore@opensolaris.org * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
2410393SSaurabh.Mishra@Sun.COM */
2510393SSaurabh.Mishra@Sun.COM
2610393SSaurabh.Mishra@Sun.COM #include <sys/types.h>
2710393SSaurabh.Mishra@Sun.COM #include <sys/stream.h>
2810393SSaurabh.Mishra@Sun.COM #include <sys/strsun.h>
2910393SSaurabh.Mishra@Sun.COM #include <sys/stat.h>
3010393SSaurabh.Mishra@Sun.COM #include <sys/modctl.h>
3110393SSaurabh.Mishra@Sun.COM #include <sys/kstat.h>
3210393SSaurabh.Mishra@Sun.COM #include <sys/ethernet.h>
3310393SSaurabh.Mishra@Sun.COM #include <sys/devops.h>
3410393SSaurabh.Mishra@Sun.COM #include <sys/debug.h>
3510393SSaurabh.Mishra@Sun.COM #include <sys/conf.h>
3610393SSaurabh.Mishra@Sun.COM #include <sys/mii.h>
3710393SSaurabh.Mishra@Sun.COM #include <sys/miiregs.h>
3810393SSaurabh.Mishra@Sun.COM #include <sys/mac.h>
3910393SSaurabh.Mishra@Sun.COM #include <sys/mac_provider.h>
4010393SSaurabh.Mishra@Sun.COM #include <sys/mac_ether.h>
4110393SSaurabh.Mishra@Sun.COM #include <sys/sysmacros.h>
4210393SSaurabh.Mishra@Sun.COM #include <sys/dditypes.h>
4310393SSaurabh.Mishra@Sun.COM #include <sys/ddi.h>
4410393SSaurabh.Mishra@Sun.COM #include <sys/sunddi.h>
4510393SSaurabh.Mishra@Sun.COM #include <sys/byteorder.h>
4610393SSaurabh.Mishra@Sun.COM #include <sys/note.h>
4710393SSaurabh.Mishra@Sun.COM #include <sys/vlan.h>
4810393SSaurabh.Mishra@Sun.COM #include <sys/strsubr.h>
4910393SSaurabh.Mishra@Sun.COM #include <sys/crc32.h>
5010393SSaurabh.Mishra@Sun.COM #include <sys/sdt.h>
5110393SSaurabh.Mishra@Sun.COM #include <sys/pci.h>
5210393SSaurabh.Mishra@Sun.COM #include <sys/pci_cap.h>
5310393SSaurabh.Mishra@Sun.COM
5410393SSaurabh.Mishra@Sun.COM #include "atge.h"
5510393SSaurabh.Mishra@Sun.COM #include "atge_cmn_reg.h"
5610393SSaurabh.Mishra@Sun.COM #include "atge_l1e_reg.h"
5711353SSaurabh.Mishra@Sun.COM #include "atge_l1_reg.h"
5810393SSaurabh.Mishra@Sun.COM
5910393SSaurabh.Mishra@Sun.COM
6010393SSaurabh.Mishra@Sun.COM /*
6110393SSaurabh.Mishra@Sun.COM * Atheros/Attansic Ethernet chips are of three types - L1, L2 and L1E.
6211353SSaurabh.Mishra@Sun.COM * This driver is for L1E/L1 but can be extended to support other chips.
6311353SSaurabh.Mishra@Sun.COM * L1E comes in 1Gigabit and Fast Ethernet flavors. L1 comes in 1Gigabit
6411353SSaurabh.Mishra@Sun.COM * flavors only.
6510393SSaurabh.Mishra@Sun.COM *
6610393SSaurabh.Mishra@Sun.COM * Atheros/Attansic Ethernet controllers have descriptor based TX and RX
6710393SSaurabh.Mishra@Sun.COM * with an exception of L1E. L1E's RX side is not descriptor based ring.
6810393SSaurabh.Mishra@Sun.COM * The L1E's RX uses pages (not to be confused with MMU pages) for
6910393SSaurabh.Mishra@Sun.COM * receiving pkts. The header has four fields :
7010393SSaurabh.Mishra@Sun.COM *
7110393SSaurabh.Mishra@Sun.COM * uint32_t seqno; Sequence number of the frame.
7210393SSaurabh.Mishra@Sun.COM * uint32_t length; Length of the frame.
7310393SSaurabh.Mishra@Sun.COM * uint32_t flags; Flags
7410393SSaurabh.Mishra@Sun.COM * uint32_t vtag; We don't use hardware VTAG.
7510393SSaurabh.Mishra@Sun.COM *
7610393SSaurabh.Mishra@Sun.COM * We use only one queue for RX (each queue can have two pages) and each
7710393SSaurabh.Mishra@Sun.COM * page is L1E_RX_PAGE_SZ large in bytes. That's the reason we don't
7810393SSaurabh.Mishra@Sun.COM * use zero-copy RX because we are limited to two pages and each page
7910393SSaurabh.Mishra@Sun.COM * accomodates large number of pkts.
8010393SSaurabh.Mishra@Sun.COM *
8110393SSaurabh.Mishra@Sun.COM * The TX side on all three chips is descriptor based ring; and all the
8210393SSaurabh.Mishra@Sun.COM * more reason to have one driver for these chips.
8310393SSaurabh.Mishra@Sun.COM *
8410393SSaurabh.Mishra@Sun.COM * We use two locks - atge_intr_lock and atge_tx_lock. Both the locks
8510393SSaurabh.Mishra@Sun.COM * should be held if the operation has impact on the driver instance.
8610393SSaurabh.Mishra@Sun.COM *
8710393SSaurabh.Mishra@Sun.COM * All the three chips have hash-based multicast filter.
8810393SSaurabh.Mishra@Sun.COM *
8910393SSaurabh.Mishra@Sun.COM * We use CMB (Coalescing Message Block) for RX but not for TX as there
9010393SSaurabh.Mishra@Sun.COM * are some issues with TX. RX CMB is used to get the last descriptor
9110393SSaurabh.Mishra@Sun.COM * posted by the chip. Each CMB is for a RX page (one queue can have two
9210393SSaurabh.Mishra@Sun.COM * pages) and are uint32_t (4 bytes) long.
9310393SSaurabh.Mishra@Sun.COM *
9410393SSaurabh.Mishra@Sun.COM * The descriptor table should have 32-bit physical address limit due to
9510393SSaurabh.Mishra@Sun.COM * the limitation of having same high address for TX/RX/SMB/CMB. The
9610393SSaurabh.Mishra@Sun.COM * TX/RX buffers can be 64-bit.
9710393SSaurabh.Mishra@Sun.COM *
9810393SSaurabh.Mishra@Sun.COM * Every DMA memory in atge is represented by atge_dma_t be it TX/RX Buffers
9910393SSaurabh.Mishra@Sun.COM * or TX/RX descriptor table or SMB/CMB. To keep the code simple, we have
10010393SSaurabh.Mishra@Sun.COM * kept sgl as 1 so that we get contingous pages from root complex.
10111353SSaurabh.Mishra@Sun.COM *
10211353SSaurabh.Mishra@Sun.COM * L1 chip (0x1048) uses descriptor based TX and RX ring. Most of registers are
10311353SSaurabh.Mishra@Sun.COM * common with L1E chip (0x1026).
10410393SSaurabh.Mishra@Sun.COM */
10510393SSaurabh.Mishra@Sun.COM
10610393SSaurabh.Mishra@Sun.COM /*
10710393SSaurabh.Mishra@Sun.COM * Function Prototypes for debugging.
10810393SSaurabh.Mishra@Sun.COM */
10910393SSaurabh.Mishra@Sun.COM void atge_error(dev_info_t *, char *, ...);
11010393SSaurabh.Mishra@Sun.COM void atge_debug_func(char *, ...);
11110393SSaurabh.Mishra@Sun.COM
11210393SSaurabh.Mishra@Sun.COM /*
11310393SSaurabh.Mishra@Sun.COM * Function Prototypes for driver operations.
11410393SSaurabh.Mishra@Sun.COM */
11510393SSaurabh.Mishra@Sun.COM static int atge_resume(dev_info_t *);
11610393SSaurabh.Mishra@Sun.COM static int atge_add_intr(atge_t *);
11710393SSaurabh.Mishra@Sun.COM static int atge_alloc_dma(atge_t *);
11810393SSaurabh.Mishra@Sun.COM static void atge_remove_intr(atge_t *);
11910393SSaurabh.Mishra@Sun.COM static void atge_free_dma(atge_t *);
12010393SSaurabh.Mishra@Sun.COM static void atge_device_reset(atge_t *);
12110393SSaurabh.Mishra@Sun.COM static void atge_device_init(atge_t *);
12210393SSaurabh.Mishra@Sun.COM static void atge_device_start(atge_t *);
12310393SSaurabh.Mishra@Sun.COM static void atge_disable_intrs(atge_t *);
12410393SSaurabh.Mishra@Sun.COM atge_dma_t *atge_alloc_a_dma_blk(atge_t *, ddi_dma_attr_t *, int, int);
12510393SSaurabh.Mishra@Sun.COM void atge_free_a_dma_blk(atge_dma_t *);
12610393SSaurabh.Mishra@Sun.COM static void atge_rxfilter(atge_t *);
12710393SSaurabh.Mishra@Sun.COM static void atge_device_reset_l1_l1e(atge_t *);
12810393SSaurabh.Mishra@Sun.COM void atge_program_ether(atge_t *atgep);
12910393SSaurabh.Mishra@Sun.COM void atge_device_restart(atge_t *);
13011353SSaurabh.Mishra@Sun.COM void atge_device_stop(atge_t *);
13110393SSaurabh.Mishra@Sun.COM static int atge_send_a_packet(atge_t *, mblk_t *);
13210393SSaurabh.Mishra@Sun.COM static uint32_t atge_ether_crc(const uint8_t *, int);
13310393SSaurabh.Mishra@Sun.COM
13410393SSaurabh.Mishra@Sun.COM
13510393SSaurabh.Mishra@Sun.COM /*
13611353SSaurabh.Mishra@Sun.COM * L1E/L2E specific functions.
13710393SSaurabh.Mishra@Sun.COM */
13810393SSaurabh.Mishra@Sun.COM void atge_l1e_device_reset(atge_t *);
13910393SSaurabh.Mishra@Sun.COM void atge_l1e_stop_mac(atge_t *);
14010393SSaurabh.Mishra@Sun.COM int atge_l1e_alloc_dma(atge_t *);
14110393SSaurabh.Mishra@Sun.COM void atge_l1e_free_dma(atge_t *);
14210393SSaurabh.Mishra@Sun.COM void atge_l1e_init_tx_ring(atge_t *);
14310393SSaurabh.Mishra@Sun.COM void atge_l1e_init_rx_pages(atge_t *);
14410393SSaurabh.Mishra@Sun.COM void atge_l1e_program_dma(atge_t *);
14511353SSaurabh.Mishra@Sun.COM void atge_l1e_send_packet(atge_ring_t *);
14610393SSaurabh.Mishra@Sun.COM mblk_t *atge_l1e_receive(atge_t *);
14711353SSaurabh.Mishra@Sun.COM uint_t atge_l1e_interrupt(caddr_t, caddr_t);
14810393SSaurabh.Mishra@Sun.COM void atge_l1e_gather_stats(atge_t *);
14910393SSaurabh.Mishra@Sun.COM void atge_l1e_clear_stats(atge_t *);
15010393SSaurabh.Mishra@Sun.COM
15110393SSaurabh.Mishra@Sun.COM /*
15211353SSaurabh.Mishra@Sun.COM * L1 specific functions.
15311353SSaurabh.Mishra@Sun.COM */
15411353SSaurabh.Mishra@Sun.COM int atge_l1_alloc_dma(atge_t *);
15511353SSaurabh.Mishra@Sun.COM void atge_l1_init_tx_ring(atge_t *);
15611353SSaurabh.Mishra@Sun.COM void atge_l1_init_rx_ring(atge_t *);
15711353SSaurabh.Mishra@Sun.COM void atge_l1_init_rr_ring(atge_t *);
15811353SSaurabh.Mishra@Sun.COM void atge_l1_init_cmb(atge_t *);
15911353SSaurabh.Mishra@Sun.COM void atge_l1_init_smb(atge_t *);
16011353SSaurabh.Mishra@Sun.COM void atge_l1_program_dma(atge_t *);
16111353SSaurabh.Mishra@Sun.COM void atge_l1_stop_tx_mac(atge_t *);
16211353SSaurabh.Mishra@Sun.COM void atge_l1_stop_rx_mac(atge_t *);
16311353SSaurabh.Mishra@Sun.COM uint_t atge_l1_interrupt(caddr_t, caddr_t);
16411353SSaurabh.Mishra@Sun.COM void atge_l1_send_packet(atge_ring_t *);
16511353SSaurabh.Mishra@Sun.COM
16611353SSaurabh.Mishra@Sun.COM
16711353SSaurabh.Mishra@Sun.COM /*
16810393SSaurabh.Mishra@Sun.COM * Function prototyps for MII operations.
16910393SSaurabh.Mishra@Sun.COM */
17010393SSaurabh.Mishra@Sun.COM uint16_t atge_mii_read(void *, uint8_t, uint8_t);
17110393SSaurabh.Mishra@Sun.COM void atge_mii_write(void *, uint8_t, uint8_t, uint16_t);
17210393SSaurabh.Mishra@Sun.COM void atge_l1e_mii_reset(void *);
17311353SSaurabh.Mishra@Sun.COM void atge_l1_mii_reset(void *);
17410393SSaurabh.Mishra@Sun.COM static void atge_mii_notify(void *, link_state_t);
17511353SSaurabh.Mishra@Sun.COM void atge_tx_reclaim(atge_t *atgep, int cons);
17611353SSaurabh.Mishra@Sun.COM
17711353SSaurabh.Mishra@Sun.COM /*
17811353SSaurabh.Mishra@Sun.COM * L1E/L2E chip.
17911353SSaurabh.Mishra@Sun.COM */
18010393SSaurabh.Mishra@Sun.COM static mii_ops_t atge_l1e_mii_ops = {
18110393SSaurabh.Mishra@Sun.COM MII_OPS_VERSION,
18210393SSaurabh.Mishra@Sun.COM atge_mii_read,
18310393SSaurabh.Mishra@Sun.COM atge_mii_write,
18410393SSaurabh.Mishra@Sun.COM atge_mii_notify,
18510393SSaurabh.Mishra@Sun.COM atge_l1e_mii_reset
18610393SSaurabh.Mishra@Sun.COM };
18710393SSaurabh.Mishra@Sun.COM
18810393SSaurabh.Mishra@Sun.COM /*
18911353SSaurabh.Mishra@Sun.COM * L1 chip.
19011353SSaurabh.Mishra@Sun.COM */
19111353SSaurabh.Mishra@Sun.COM static mii_ops_t atge_l1_mii_ops = {
19211353SSaurabh.Mishra@Sun.COM MII_OPS_VERSION,
19311353SSaurabh.Mishra@Sun.COM atge_mii_read,
19411353SSaurabh.Mishra@Sun.COM atge_mii_write,
19511353SSaurabh.Mishra@Sun.COM atge_mii_notify,
19611353SSaurabh.Mishra@Sun.COM atge_l1_mii_reset
19711353SSaurabh.Mishra@Sun.COM };
19811353SSaurabh.Mishra@Sun.COM
19911353SSaurabh.Mishra@Sun.COM /*
20010393SSaurabh.Mishra@Sun.COM * Function Prototypes for MAC callbacks.
20110393SSaurabh.Mishra@Sun.COM */
20210393SSaurabh.Mishra@Sun.COM static int atge_m_stat(void *, uint_t, uint64_t *);
20310393SSaurabh.Mishra@Sun.COM static int atge_m_start(void *);
20410393SSaurabh.Mishra@Sun.COM static void atge_m_stop(void *);
20510393SSaurabh.Mishra@Sun.COM static int atge_m_getprop(void *, const char *, mac_prop_id_t, uint_t,
20611878SVenu.Iyer@Sun.COM void *);
20710393SSaurabh.Mishra@Sun.COM static int atge_m_setprop(void *, const char *, mac_prop_id_t, uint_t,
20810393SSaurabh.Mishra@Sun.COM const void *);
20911878SVenu.Iyer@Sun.COM static void atge_m_propinfo(void *, const char *, mac_prop_id_t,
21011878SVenu.Iyer@Sun.COM mac_prop_info_handle_t);
21110393SSaurabh.Mishra@Sun.COM static int atge_m_unicst(void *, const uint8_t *);
21210393SSaurabh.Mishra@Sun.COM static int atge_m_multicst(void *, boolean_t, const uint8_t *);
21310393SSaurabh.Mishra@Sun.COM static int atge_m_promisc(void *, boolean_t);
21410393SSaurabh.Mishra@Sun.COM static mblk_t *atge_m_tx(void *, mblk_t *);
21510393SSaurabh.Mishra@Sun.COM
21610393SSaurabh.Mishra@Sun.COM static mac_callbacks_t atge_m_callbacks = {
21711878SVenu.Iyer@Sun.COM MC_SETPROP | MC_GETPROP | MC_PROPINFO,
21810393SSaurabh.Mishra@Sun.COM atge_m_stat,
21910393SSaurabh.Mishra@Sun.COM atge_m_start,
22010393SSaurabh.Mishra@Sun.COM atge_m_stop,
22110393SSaurabh.Mishra@Sun.COM atge_m_promisc,
22210393SSaurabh.Mishra@Sun.COM atge_m_multicst,
22310393SSaurabh.Mishra@Sun.COM atge_m_unicst,
22410393SSaurabh.Mishra@Sun.COM atge_m_tx,
22511878SVenu.Iyer@Sun.COM NULL, /* mc_reserved */
22610393SSaurabh.Mishra@Sun.COM NULL, /* mc_ioctl */
22710393SSaurabh.Mishra@Sun.COM NULL, /* mc_getcapab */
22810393SSaurabh.Mishra@Sun.COM NULL, /* mc_open */
22910393SSaurabh.Mishra@Sun.COM NULL, /* mc_close */
23010393SSaurabh.Mishra@Sun.COM atge_m_setprop,
23110393SSaurabh.Mishra@Sun.COM atge_m_getprop,
23211878SVenu.Iyer@Sun.COM atge_m_propinfo
23310393SSaurabh.Mishra@Sun.COM };
23410393SSaurabh.Mishra@Sun.COM
23510393SSaurabh.Mishra@Sun.COM /*
23610393SSaurabh.Mishra@Sun.COM * DMA Data access requirements.
23710393SSaurabh.Mishra@Sun.COM */
23810393SSaurabh.Mishra@Sun.COM static struct ddi_device_acc_attr atge_dev_attr = {
23910393SSaurabh.Mishra@Sun.COM DDI_DEVICE_ATTR_V0,
24010393SSaurabh.Mishra@Sun.COM DDI_STRUCTURE_LE_ACC,
24110393SSaurabh.Mishra@Sun.COM DDI_STRICTORDER_ACC
24210393SSaurabh.Mishra@Sun.COM };
24310393SSaurabh.Mishra@Sun.COM
24410393SSaurabh.Mishra@Sun.COM /*
24510393SSaurabh.Mishra@Sun.COM * Buffers should be native endianness.
24610393SSaurabh.Mishra@Sun.COM */
24710393SSaurabh.Mishra@Sun.COM static struct ddi_device_acc_attr atge_buf_attr = {
24810393SSaurabh.Mishra@Sun.COM DDI_DEVICE_ATTR_V0,
24910393SSaurabh.Mishra@Sun.COM DDI_NEVERSWAP_ACC, /* native endianness */
25010393SSaurabh.Mishra@Sun.COM DDI_STRICTORDER_ACC
25110393SSaurabh.Mishra@Sun.COM };
25210393SSaurabh.Mishra@Sun.COM
25310393SSaurabh.Mishra@Sun.COM /*
25411353SSaurabh.Mishra@Sun.COM * DMA device attributes. Buffer can be 64-bit.
25510393SSaurabh.Mishra@Sun.COM */
25610393SSaurabh.Mishra@Sun.COM static ddi_dma_attr_t atge_dma_attr_buf = {
25710393SSaurabh.Mishra@Sun.COM DMA_ATTR_V0, /* dma_attr_version */
25810393SSaurabh.Mishra@Sun.COM 0, /* dma_attr_addr_lo */
25910393SSaurabh.Mishra@Sun.COM 0x00ffffffffffull, /* dma_attr_addr_hi */
26010393SSaurabh.Mishra@Sun.COM 0x000000003fffull, /* dma_attr_count_max */
26110393SSaurabh.Mishra@Sun.COM 8, /* dma_attr_align */
26210393SSaurabh.Mishra@Sun.COM 0x00003ffc, /* dma_attr_burstsizes */
26310393SSaurabh.Mishra@Sun.COM 1, /* dma_attr_minxfer */
26410393SSaurabh.Mishra@Sun.COM 0x0000000027ffull, /* dma_attr_maxxfer */
26510393SSaurabh.Mishra@Sun.COM 0x0000ffffffffull, /* dma_attr_seg */
26610393SSaurabh.Mishra@Sun.COM 1, /* dma_attr_sgllen */
26710393SSaurabh.Mishra@Sun.COM 1, /* dma_attr_granular */
26810393SSaurabh.Mishra@Sun.COM 0 /* dma_attr_flags */
26910393SSaurabh.Mishra@Sun.COM };
27010393SSaurabh.Mishra@Sun.COM
27110393SSaurabh.Mishra@Sun.COM /*
27210393SSaurabh.Mishra@Sun.COM * Table of supported devices.
27310393SSaurabh.Mishra@Sun.COM */
27410393SSaurabh.Mishra@Sun.COM #define ATGE_VENDOR_ID 0x1969
27510393SSaurabh.Mishra@Sun.COM #define ATGE_L1E_STR "Atheros AR8121/8113/8114"
27610393SSaurabh.Mishra@Sun.COM
27710393SSaurabh.Mishra@Sun.COM static atge_cards_t atge_cards[] = {
27810393SSaurabh.Mishra@Sun.COM {ATGE_VENDOR_ID, ATGE_CHIP_L1E_DEV_ID, ATGE_L1E_STR, ATGE_CHIP_L1E},
27911353SSaurabh.Mishra@Sun.COM {ATGE_VENDOR_ID, ATGE_CHIP_L1_DEV_ID, "Attansic L1", ATGE_CHIP_L1},
28010393SSaurabh.Mishra@Sun.COM };
28110393SSaurabh.Mishra@Sun.COM
28210393SSaurabh.Mishra@Sun.COM /*
28310393SSaurabh.Mishra@Sun.COM * Global Debugging flag. Developer level debugging is done only in DEBUG mode.
28410393SSaurabh.Mishra@Sun.COM */
28510393SSaurabh.Mishra@Sun.COM int atge_debug = 1;
28610393SSaurabh.Mishra@Sun.COM
28710393SSaurabh.Mishra@Sun.COM /*
28810393SSaurabh.Mishra@Sun.COM * Debugging and error reporting.
28910393SSaurabh.Mishra@Sun.COM */
29010393SSaurabh.Mishra@Sun.COM void
atge_debug_func(char * fmt,...)29110393SSaurabh.Mishra@Sun.COM atge_debug_func(char *fmt, ...)
29210393SSaurabh.Mishra@Sun.COM {
29310393SSaurabh.Mishra@Sun.COM va_list ap;
29410393SSaurabh.Mishra@Sun.COM char buf[256];
29510393SSaurabh.Mishra@Sun.COM
29610393SSaurabh.Mishra@Sun.COM va_start(ap, fmt);
29710393SSaurabh.Mishra@Sun.COM (void) vsnprintf(buf, sizeof (buf), fmt, ap);
29810393SSaurabh.Mishra@Sun.COM va_end(ap);
29910393SSaurabh.Mishra@Sun.COM
30010393SSaurabh.Mishra@Sun.COM DTRACE_PROBE1(atge__debug, char *, buf);
30110393SSaurabh.Mishra@Sun.COM }
30210393SSaurabh.Mishra@Sun.COM
30310393SSaurabh.Mishra@Sun.COM void
atge_error(dev_info_t * dip,char * fmt,...)30410393SSaurabh.Mishra@Sun.COM atge_error(dev_info_t *dip, char *fmt, ...)
30510393SSaurabh.Mishra@Sun.COM {
30610393SSaurabh.Mishra@Sun.COM va_list ap;
30710393SSaurabh.Mishra@Sun.COM char buf[256];
30810393SSaurabh.Mishra@Sun.COM
30910393SSaurabh.Mishra@Sun.COM va_start(ap, fmt);
31010393SSaurabh.Mishra@Sun.COM (void) vsnprintf(buf, sizeof (buf), fmt, ap);
31110393SSaurabh.Mishra@Sun.COM va_end(ap);
31210393SSaurabh.Mishra@Sun.COM
31310393SSaurabh.Mishra@Sun.COM if (dip) {
31410393SSaurabh.Mishra@Sun.COM cmn_err(CE_WARN, "%s%d: %s",
31510393SSaurabh.Mishra@Sun.COM ddi_driver_name(dip), ddi_get_instance(dip), buf);
31610393SSaurabh.Mishra@Sun.COM } else {
31710393SSaurabh.Mishra@Sun.COM cmn_err(CE_WARN, "atge: %s", buf);
31810393SSaurabh.Mishra@Sun.COM }
31910393SSaurabh.Mishra@Sun.COM }
32010393SSaurabh.Mishra@Sun.COM
32110393SSaurabh.Mishra@Sun.COM void
atge_mac_config(atge_t * atgep)32210393SSaurabh.Mishra@Sun.COM atge_mac_config(atge_t *atgep)
32310393SSaurabh.Mishra@Sun.COM {
32410393SSaurabh.Mishra@Sun.COM uint32_t reg;
32510393SSaurabh.Mishra@Sun.COM int speed;
32610393SSaurabh.Mishra@Sun.COM link_duplex_t ld;
32710393SSaurabh.Mishra@Sun.COM
32810393SSaurabh.Mishra@Sun.COM reg = INL(atgep, ATGE_MAC_CFG);
32910393SSaurabh.Mishra@Sun.COM reg &= ~(ATGE_CFG_FULL_DUPLEX | ATGE_CFG_TX_FC | ATGE_CFG_RX_FC |
33010393SSaurabh.Mishra@Sun.COM ATGE_CFG_SPEED_MASK);
33110393SSaurabh.Mishra@Sun.COM
33210393SSaurabh.Mishra@Sun.COM speed = mii_get_speed(atgep->atge_mii);
33310393SSaurabh.Mishra@Sun.COM switch (speed) {
33410393SSaurabh.Mishra@Sun.COM case 10:
33510393SSaurabh.Mishra@Sun.COM case 100:
33610393SSaurabh.Mishra@Sun.COM reg |= ATGE_CFG_SPEED_10_100;
33710393SSaurabh.Mishra@Sun.COM break;
33810393SSaurabh.Mishra@Sun.COM case 1000:
33910393SSaurabh.Mishra@Sun.COM reg |= ATGE_CFG_SPEED_1000;
34010393SSaurabh.Mishra@Sun.COM break;
34110393SSaurabh.Mishra@Sun.COM }
34210393SSaurabh.Mishra@Sun.COM
34310393SSaurabh.Mishra@Sun.COM ld = mii_get_duplex(atgep->atge_mii);
34410393SSaurabh.Mishra@Sun.COM if (ld == LINK_DUPLEX_FULL)
34510393SSaurabh.Mishra@Sun.COM reg |= ATGE_CFG_FULL_DUPLEX;
34610393SSaurabh.Mishra@Sun.COM
34710393SSaurabh.Mishra@Sun.COM /* Re-enable TX/RX MACs */
34811353SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
34911353SSaurabh.Mishra@Sun.COM reg |= ATGE_CFG_TX_ENB | ATGE_CFG_RX_ENB | ATGE_CFG_RX_FC;
35011353SSaurabh.Mishra@Sun.COM } else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
35111353SSaurabh.Mishra@Sun.COM reg |= ATGE_CFG_TX_ENB | ATGE_CFG_RX_ENB;
35211353SSaurabh.Mishra@Sun.COM }
35311353SSaurabh.Mishra@Sun.COM
35410393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_MAC_CFG, reg);
35510393SSaurabh.Mishra@Sun.COM
35610393SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
35710393SSaurabh.Mishra@Sun.COM reg = ATGE_USECS(ATGE_IM_RX_TIMER_DEFAULT) << IM_TIMER_RX_SHIFT;
35810393SSaurabh.Mishra@Sun.COM reg |= ATGE_USECS(ATGE_IM_TX_TIMER_DEFAULT) <<
35910393SSaurabh.Mishra@Sun.COM IM_TIMER_TX_SHIFT;
36010393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_IM_TIMER, reg);
36110393SSaurabh.Mishra@Sun.COM }
36210393SSaurabh.Mishra@Sun.COM
36310393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s() mac_cfg is : %x",
36410393SSaurabh.Mishra@Sun.COM atgep->atge_name, __func__, INL(atgep, ATGE_MAC_CFG)));
36510393SSaurabh.Mishra@Sun.COM }
36610393SSaurabh.Mishra@Sun.COM
36710393SSaurabh.Mishra@Sun.COM static void
atge_mii_notify(void * arg,link_state_t link)36810393SSaurabh.Mishra@Sun.COM atge_mii_notify(void *arg, link_state_t link)
36910393SSaurabh.Mishra@Sun.COM {
37010393SSaurabh.Mishra@Sun.COM atge_t *atgep = arg;
37110393SSaurabh.Mishra@Sun.COM
37210393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s() LINK STATUS CHANGED from %x -> %x",
37310393SSaurabh.Mishra@Sun.COM atgep->atge_name, __func__, atgep->atge_link_state, link));
37410393SSaurabh.Mishra@Sun.COM
37510393SSaurabh.Mishra@Sun.COM mac_link_update(atgep->atge_mh, link);
37610393SSaurabh.Mishra@Sun.COM
37710393SSaurabh.Mishra@Sun.COM /*
37810393SSaurabh.Mishra@Sun.COM * Reconfigure MAC if link status is UP now.
37910393SSaurabh.Mishra@Sun.COM */
38010393SSaurabh.Mishra@Sun.COM mutex_enter(&atgep->atge_tx_lock);
38110393SSaurabh.Mishra@Sun.COM if (link == LINK_STATE_UP) {
38211353SSaurabh.Mishra@Sun.COM atgep->atge_link_state = LINK_STATE_UP;
38310393SSaurabh.Mishra@Sun.COM atge_mac_config(atgep);
38410393SSaurabh.Mishra@Sun.COM atgep->atge_tx_resched = 0;
38510393SSaurabh.Mishra@Sun.COM } else {
38610393SSaurabh.Mishra@Sun.COM atgep->atge_link_state = LINK_STATE_DOWN;
38711353SSaurabh.Mishra@Sun.COM atgep->atge_flags |= ATGE_MII_CHECK;
38810393SSaurabh.Mishra@Sun.COM }
38910393SSaurabh.Mishra@Sun.COM
39010393SSaurabh.Mishra@Sun.COM mutex_exit(&atgep->atge_tx_lock);
39110393SSaurabh.Mishra@Sun.COM
39210393SSaurabh.Mishra@Sun.COM if (link == LINK_STATE_UP)
39310393SSaurabh.Mishra@Sun.COM mac_tx_update(atgep->atge_mh);
39410393SSaurabh.Mishra@Sun.COM }
39510393SSaurabh.Mishra@Sun.COM
39611353SSaurabh.Mishra@Sun.COM void
atge_tx_reclaim(atge_t * atgep,int end)39711353SSaurabh.Mishra@Sun.COM atge_tx_reclaim(atge_t *atgep, int end)
39810393SSaurabh.Mishra@Sun.COM {
39911353SSaurabh.Mishra@Sun.COM atge_tx_desc_t *txd;
40011353SSaurabh.Mishra@Sun.COM atge_ring_t *r = atgep->atge_tx_ring;
40111353SSaurabh.Mishra@Sun.COM uchar_t *c;
40211353SSaurabh.Mishra@Sun.COM int start;
40311353SSaurabh.Mishra@Sun.COM
40411353SSaurabh.Mishra@Sun.COM ASSERT(MUTEX_HELD(&atgep->atge_tx_lock));
40511353SSaurabh.Mishra@Sun.COM ASSERT(r != NULL);
40611353SSaurabh.Mishra@Sun.COM
40711353SSaurabh.Mishra@Sun.COM start = r->r_consumer;
40811353SSaurabh.Mishra@Sun.COM
40911353SSaurabh.Mishra@Sun.COM if (start == end)
41011353SSaurabh.Mishra@Sun.COM return;
41111353SSaurabh.Mishra@Sun.COM
41211353SSaurabh.Mishra@Sun.COM while (start != end) {
41311353SSaurabh.Mishra@Sun.COM r->r_avail_desc++;
41411353SSaurabh.Mishra@Sun.COM if (r->r_avail_desc > ATGE_TX_RING_CNT) {
41511353SSaurabh.Mishra@Sun.COM
41611353SSaurabh.Mishra@Sun.COM atge_error(atgep->atge_dip,
41711353SSaurabh.Mishra@Sun.COM "Reclaim : TX descriptor error");
41811353SSaurabh.Mishra@Sun.COM
41911353SSaurabh.Mishra@Sun.COM if (r->r_avail_desc > (ATGE_TX_RING_CNT + 5)) {
42011353SSaurabh.Mishra@Sun.COM atge_device_stop(atgep);
42111353SSaurabh.Mishra@Sun.COM break;
42211353SSaurabh.Mishra@Sun.COM }
42310393SSaurabh.Mishra@Sun.COM }
42410393SSaurabh.Mishra@Sun.COM
42511353SSaurabh.Mishra@Sun.COM c = (uchar_t *)r->r_desc_ring->addr;
42611353SSaurabh.Mishra@Sun.COM c += (sizeof (atge_tx_desc_t) * start);
42711353SSaurabh.Mishra@Sun.COM txd = (atge_tx_desc_t *)c;
42811353SSaurabh.Mishra@Sun.COM
42910393SSaurabh.Mishra@Sun.COM /*
43011353SSaurabh.Mishra@Sun.COM * Clearing TX descriptor helps in debugging some strange
43111353SSaurabh.Mishra@Sun.COM * problems.
43210393SSaurabh.Mishra@Sun.COM */
43311353SSaurabh.Mishra@Sun.COM txd->addr = 0;
43411353SSaurabh.Mishra@Sun.COM txd->len = 0;
43511353SSaurabh.Mishra@Sun.COM txd->flags = 0;
43611353SSaurabh.Mishra@Sun.COM
43711353SSaurabh.Mishra@Sun.COM ATGE_INC_SLOT(start, ATGE_TX_RING_CNT);
43810393SSaurabh.Mishra@Sun.COM }
43910393SSaurabh.Mishra@Sun.COM
44011353SSaurabh.Mishra@Sun.COM atgep->atge_tx_ring->r_consumer = start;
44111353SSaurabh.Mishra@Sun.COM
44211353SSaurabh.Mishra@Sun.COM DMA_SYNC(r->r_desc_ring, 0, ATGE_TX_RING_SZ, DDI_DMA_SYNC_FORDEV);
44310393SSaurabh.Mishra@Sun.COM }
44410393SSaurabh.Mishra@Sun.COM
44510393SSaurabh.Mishra@Sun.COM /*
44610393SSaurabh.Mishra@Sun.COM * Adds interrupt handler depending upon the type of interrupt supported by
44710393SSaurabh.Mishra@Sun.COM * the chip.
44810393SSaurabh.Mishra@Sun.COM */
44910393SSaurabh.Mishra@Sun.COM static int
atge_add_intr_handler(atge_t * atgep,int intr_type)45010393SSaurabh.Mishra@Sun.COM atge_add_intr_handler(atge_t *atgep, int intr_type)
45110393SSaurabh.Mishra@Sun.COM {
45210393SSaurabh.Mishra@Sun.COM int err;
45310393SSaurabh.Mishra@Sun.COM int count = 0;
45410393SSaurabh.Mishra@Sun.COM int avail = 0;
45510393SSaurabh.Mishra@Sun.COM int i;
45610393SSaurabh.Mishra@Sun.COM int flag;
45710393SSaurabh.Mishra@Sun.COM
45810393SSaurabh.Mishra@Sun.COM if (intr_type != DDI_INTR_TYPE_FIXED) {
45910393SSaurabh.Mishra@Sun.COM err = ddi_intr_get_nintrs(atgep->atge_dip, intr_type, &count);
46010393SSaurabh.Mishra@Sun.COM if (err != DDI_SUCCESS) {
46110393SSaurabh.Mishra@Sun.COM atge_error(atgep->atge_dip,
46210393SSaurabh.Mishra@Sun.COM "ddi_intr_get_nintrs failed : %d", err);
46311353SSaurabh.Mishra@Sun.COM return (DDI_FAILURE);
46410393SSaurabh.Mishra@Sun.COM }
46510393SSaurabh.Mishra@Sun.COM
46610393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s() count : %d",
46710393SSaurabh.Mishra@Sun.COM atgep->atge_name, __func__, count));
46810393SSaurabh.Mishra@Sun.COM
46910393SSaurabh.Mishra@Sun.COM err = ddi_intr_get_navail(atgep->atge_dip, intr_type, &avail);
47010393SSaurabh.Mishra@Sun.COM if (err != DDI_SUCCESS) {
47110393SSaurabh.Mishra@Sun.COM atge_error(atgep->atge_dip,
47210393SSaurabh.Mishra@Sun.COM "ddi_intr_get_navail failed : %d", err);
47311353SSaurabh.Mishra@Sun.COM return (DDI_FAILURE);
47410393SSaurabh.Mishra@Sun.COM }
47510393SSaurabh.Mishra@Sun.COM
47610393SSaurabh.Mishra@Sun.COM if (avail < count) {
47710393SSaurabh.Mishra@Sun.COM atge_error(atgep->atge_dip, "count :%d,"
47810393SSaurabh.Mishra@Sun.COM " avail : %d", count, avail);
47910393SSaurabh.Mishra@Sun.COM }
48010393SSaurabh.Mishra@Sun.COM
48110393SSaurabh.Mishra@Sun.COM flag = DDI_INTR_ALLOC_STRICT;
48210393SSaurabh.Mishra@Sun.COM } else {
48310393SSaurabh.Mishra@Sun.COM /*
48410393SSaurabh.Mishra@Sun.COM * DDI_INTR_TYPE_FIXED case.
48510393SSaurabh.Mishra@Sun.COM */
48610393SSaurabh.Mishra@Sun.COM count = 1;
48710393SSaurabh.Mishra@Sun.COM avail = 1;
48810393SSaurabh.Mishra@Sun.COM flag = DDI_INTR_ALLOC_NORMAL;
48910393SSaurabh.Mishra@Sun.COM }
49010393SSaurabh.Mishra@Sun.COM
49110393SSaurabh.Mishra@Sun.COM atgep->atge_intr_size = avail * sizeof (ddi_intr_handle_t);
49210393SSaurabh.Mishra@Sun.COM atgep->atge_intr_handle = kmem_zalloc(atgep->atge_intr_size, KM_SLEEP);
49310393SSaurabh.Mishra@Sun.COM
49410393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s() avail:%d, count : %d, type : %d",
49510393SSaurabh.Mishra@Sun.COM atgep->atge_name, __func__, avail, count,
49610393SSaurabh.Mishra@Sun.COM intr_type));
49710393SSaurabh.Mishra@Sun.COM
49810393SSaurabh.Mishra@Sun.COM err = ddi_intr_alloc(atgep->atge_dip, atgep->atge_intr_handle,
49910393SSaurabh.Mishra@Sun.COM intr_type, 0, avail, &atgep->atge_intr_cnt, flag);
50010393SSaurabh.Mishra@Sun.COM
50110393SSaurabh.Mishra@Sun.COM if (err != DDI_SUCCESS) {
50210393SSaurabh.Mishra@Sun.COM atge_error(atgep->atge_dip, "ddi_intr_alloc failed : %d", err);
50310393SSaurabh.Mishra@Sun.COM kmem_free(atgep->atge_intr_handle, atgep->atge_intr_size);
50411353SSaurabh.Mishra@Sun.COM return (DDI_FAILURE);
50510393SSaurabh.Mishra@Sun.COM }
50610393SSaurabh.Mishra@Sun.COM
50710393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: atge_add_intr_handler() after alloc count"
50810393SSaurabh.Mishra@Sun.COM " :%d, avail : %d", atgep->atge_name, count, avail));
50910393SSaurabh.Mishra@Sun.COM
51010393SSaurabh.Mishra@Sun.COM err = ddi_intr_get_pri(atgep->atge_intr_handle[0],
51110393SSaurabh.Mishra@Sun.COM &atgep->atge_intr_pri);
51210393SSaurabh.Mishra@Sun.COM if (err != DDI_SUCCESS) {
51310393SSaurabh.Mishra@Sun.COM atge_error(atgep->atge_dip, "ddi_intr_get_pri failed:%d", err);
51410393SSaurabh.Mishra@Sun.COM for (i = 0; i < atgep->atge_intr_cnt; i++) {
51510393SSaurabh.Mishra@Sun.COM (void) ddi_intr_free(atgep->atge_intr_handle[i]);
51610393SSaurabh.Mishra@Sun.COM }
51710393SSaurabh.Mishra@Sun.COM kmem_free(atgep->atge_intr_handle, atgep->atge_intr_size);
51810393SSaurabh.Mishra@Sun.COM
51911353SSaurabh.Mishra@Sun.COM return (DDI_FAILURE);
52010393SSaurabh.Mishra@Sun.COM }
52110393SSaurabh.Mishra@Sun.COM
52210393SSaurabh.Mishra@Sun.COM /*
52310393SSaurabh.Mishra@Sun.COM * Add interrupt handler now.
52410393SSaurabh.Mishra@Sun.COM */
52510393SSaurabh.Mishra@Sun.COM for (i = 0; i < atgep->atge_intr_cnt; i++) {
52611353SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
52711353SSaurabh.Mishra@Sun.COM err = ddi_intr_add_handler(atgep->atge_intr_handle[i],
52811353SSaurabh.Mishra@Sun.COM atge_l1e_interrupt, atgep, (caddr_t)(uintptr_t)i);
52911353SSaurabh.Mishra@Sun.COM } else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
53011353SSaurabh.Mishra@Sun.COM err = ddi_intr_add_handler(atgep->atge_intr_handle[i],
53111353SSaurabh.Mishra@Sun.COM atge_l1_interrupt, atgep, (caddr_t)(uintptr_t)i);
53211353SSaurabh.Mishra@Sun.COM }
53310393SSaurabh.Mishra@Sun.COM
53410393SSaurabh.Mishra@Sun.COM if (err != DDI_SUCCESS) {
53510393SSaurabh.Mishra@Sun.COM atge_error(atgep->atge_dip,
53610393SSaurabh.Mishra@Sun.COM "ddi_intr_add_handler failed : %d", err);
53710393SSaurabh.Mishra@Sun.COM
53810393SSaurabh.Mishra@Sun.COM (void) ddi_intr_free(atgep->atge_intr_handle[i]);
53910393SSaurabh.Mishra@Sun.COM while (--i >= 0) {
54010393SSaurabh.Mishra@Sun.COM (void) ddi_intr_remove_handler(
54110393SSaurabh.Mishra@Sun.COM atgep->atge_intr_handle[i]);
54210393SSaurabh.Mishra@Sun.COM (void) ddi_intr_free(
54310393SSaurabh.Mishra@Sun.COM atgep->atge_intr_handle[i]);
54410393SSaurabh.Mishra@Sun.COM }
54510393SSaurabh.Mishra@Sun.COM
54610393SSaurabh.Mishra@Sun.COM kmem_free(atgep->atge_intr_handle,
54710393SSaurabh.Mishra@Sun.COM atgep->atge_intr_size);
54810393SSaurabh.Mishra@Sun.COM
54911353SSaurabh.Mishra@Sun.COM return (DDI_FAILURE);
55010393SSaurabh.Mishra@Sun.COM }
55110393SSaurabh.Mishra@Sun.COM }
55210393SSaurabh.Mishra@Sun.COM
55310393SSaurabh.Mishra@Sun.COM err = ddi_intr_get_cap(atgep->atge_intr_handle[0],
55410393SSaurabh.Mishra@Sun.COM &atgep->atge_intr_cap);
55510393SSaurabh.Mishra@Sun.COM
55610393SSaurabh.Mishra@Sun.COM if (err != DDI_SUCCESS) {
55710393SSaurabh.Mishra@Sun.COM atge_error(atgep->atge_dip,
55810393SSaurabh.Mishra@Sun.COM "ddi_intr_get_cap failed : %d", err);
55910393SSaurabh.Mishra@Sun.COM atge_remove_intr(atgep);
56011353SSaurabh.Mishra@Sun.COM return (DDI_FAILURE);
56110393SSaurabh.Mishra@Sun.COM }
56210393SSaurabh.Mishra@Sun.COM
56310393SSaurabh.Mishra@Sun.COM if (intr_type == DDI_INTR_TYPE_FIXED)
56410393SSaurabh.Mishra@Sun.COM atgep->atge_flags |= ATGE_FIXED_TYPE;
56510393SSaurabh.Mishra@Sun.COM else if (intr_type == DDI_INTR_TYPE_MSI)
56610393SSaurabh.Mishra@Sun.COM atgep->atge_flags |= ATGE_MSI_TYPE;
56710393SSaurabh.Mishra@Sun.COM else if (intr_type == DDI_INTR_TYPE_MSIX)
56810393SSaurabh.Mishra@Sun.COM atgep->atge_flags |= ATGE_MSIX_TYPE;
56910393SSaurabh.Mishra@Sun.COM
57011353SSaurabh.Mishra@Sun.COM return (DDI_SUCCESS);
57110393SSaurabh.Mishra@Sun.COM }
57210393SSaurabh.Mishra@Sun.COM
57310393SSaurabh.Mishra@Sun.COM void
atge_remove_intr(atge_t * atgep)57410393SSaurabh.Mishra@Sun.COM atge_remove_intr(atge_t *atgep)
57510393SSaurabh.Mishra@Sun.COM {
57610393SSaurabh.Mishra@Sun.COM int i;
57710393SSaurabh.Mishra@Sun.COM int cap = 0;
57810393SSaurabh.Mishra@Sun.COM
57910393SSaurabh.Mishra@Sun.COM if (atgep->atge_intr_handle == NULL)
58010393SSaurabh.Mishra@Sun.COM return;
58110393SSaurabh.Mishra@Sun.COM
58210393SSaurabh.Mishra@Sun.COM if (atgep->atge_intr_cap & DDI_INTR_FLAG_BLOCK) {
58310393SSaurabh.Mishra@Sun.COM (void) ddi_intr_block_disable(atgep->atge_intr_handle,
58410393SSaurabh.Mishra@Sun.COM atgep->atge_intr_cnt);
58510393SSaurabh.Mishra@Sun.COM
58610393SSaurabh.Mishra@Sun.COM cap = 1;
58710393SSaurabh.Mishra@Sun.COM }
58810393SSaurabh.Mishra@Sun.COM
58910393SSaurabh.Mishra@Sun.COM for (i = 0; i < atgep->atge_intr_cnt; i++) {
59010393SSaurabh.Mishra@Sun.COM if (cap == 0)
59110393SSaurabh.Mishra@Sun.COM (void) ddi_intr_disable(atgep->atge_intr_handle[i]);
59210393SSaurabh.Mishra@Sun.COM
59310393SSaurabh.Mishra@Sun.COM (void) ddi_intr_remove_handler(atgep->atge_intr_handle[i]);
59410393SSaurabh.Mishra@Sun.COM (void) ddi_intr_free(atgep->atge_intr_handle[i]);
59510393SSaurabh.Mishra@Sun.COM }
59610393SSaurabh.Mishra@Sun.COM
59710393SSaurabh.Mishra@Sun.COM kmem_free(atgep->atge_intr_handle, atgep->atge_intr_size);
59810393SSaurabh.Mishra@Sun.COM }
59910393SSaurabh.Mishra@Sun.COM
60010393SSaurabh.Mishra@Sun.COM int
atge_enable_intrs(atge_t * atgep)60110393SSaurabh.Mishra@Sun.COM atge_enable_intrs(atge_t *atgep)
60210393SSaurabh.Mishra@Sun.COM {
60310393SSaurabh.Mishra@Sun.COM int err;
60410393SSaurabh.Mishra@Sun.COM int i;
60510393SSaurabh.Mishra@Sun.COM
60610393SSaurabh.Mishra@Sun.COM if (atgep->atge_intr_cap & DDI_INTR_FLAG_BLOCK) {
60710393SSaurabh.Mishra@Sun.COM /*
60810393SSaurabh.Mishra@Sun.COM * Do block enable.
60910393SSaurabh.Mishra@Sun.COM */
61010393SSaurabh.Mishra@Sun.COM err = ddi_intr_block_enable(atgep->atge_intr_handle,
61110393SSaurabh.Mishra@Sun.COM atgep->atge_intr_cnt);
61210393SSaurabh.Mishra@Sun.COM
61310393SSaurabh.Mishra@Sun.COM if (err != DDI_SUCCESS) {
61410393SSaurabh.Mishra@Sun.COM atge_error(atgep->atge_dip,
61510393SSaurabh.Mishra@Sun.COM "Failed to block enable intrs %d", err);
61611353SSaurabh.Mishra@Sun.COM err = DDI_FAILURE;
61710393SSaurabh.Mishra@Sun.COM } else {
61811353SSaurabh.Mishra@Sun.COM err = DDI_SUCCESS;
61910393SSaurabh.Mishra@Sun.COM }
62010393SSaurabh.Mishra@Sun.COM } else {
62110393SSaurabh.Mishra@Sun.COM /*
62210393SSaurabh.Mishra@Sun.COM * Call ddi_intr_enable() for MSI non-block enable.
62310393SSaurabh.Mishra@Sun.COM */
62410393SSaurabh.Mishra@Sun.COM for (i = 0; i < atgep->atge_intr_cnt; i++) {
62510393SSaurabh.Mishra@Sun.COM err = ddi_intr_enable(atgep->atge_intr_handle[i]);
62610393SSaurabh.Mishra@Sun.COM if (err != DDI_SUCCESS) {
62710393SSaurabh.Mishra@Sun.COM atge_error(atgep->atge_dip,
62810393SSaurabh.Mishra@Sun.COM "Failed to enable intrs on %d with : %d",
62910393SSaurabh.Mishra@Sun.COM i, err);
63010393SSaurabh.Mishra@Sun.COM break;
63110393SSaurabh.Mishra@Sun.COM }
63210393SSaurabh.Mishra@Sun.COM }
63310393SSaurabh.Mishra@Sun.COM
63410393SSaurabh.Mishra@Sun.COM if (err == DDI_SUCCESS)
63511353SSaurabh.Mishra@Sun.COM err = DDI_SUCCESS;
63610393SSaurabh.Mishra@Sun.COM else
63711353SSaurabh.Mishra@Sun.COM err = DDI_FAILURE;
63810393SSaurabh.Mishra@Sun.COM }
63910393SSaurabh.Mishra@Sun.COM
64010393SSaurabh.Mishra@Sun.COM return (err);
64110393SSaurabh.Mishra@Sun.COM }
64210393SSaurabh.Mishra@Sun.COM
64310393SSaurabh.Mishra@Sun.COM /*
64410393SSaurabh.Mishra@Sun.COM * Adds interrupt handler depending on the supported interrupt type by the
64510393SSaurabh.Mishra@Sun.COM * chip.
64610393SSaurabh.Mishra@Sun.COM */
64710393SSaurabh.Mishra@Sun.COM static int
atge_add_intr(atge_t * atgep)64810393SSaurabh.Mishra@Sun.COM atge_add_intr(atge_t *atgep)
64910393SSaurabh.Mishra@Sun.COM {
65010393SSaurabh.Mishra@Sun.COM int err;
65110393SSaurabh.Mishra@Sun.COM
65210393SSaurabh.Mishra@Sun.COM /*
65310393SSaurabh.Mishra@Sun.COM * Get the supported interrupt types.
65410393SSaurabh.Mishra@Sun.COM */
65510393SSaurabh.Mishra@Sun.COM err = ddi_intr_get_supported_types(atgep->atge_dip,
65610393SSaurabh.Mishra@Sun.COM &atgep->atge_intr_types);
65710393SSaurabh.Mishra@Sun.COM if (err != DDI_SUCCESS) {
65810393SSaurabh.Mishra@Sun.COM atge_error(atgep->atge_dip,
65910393SSaurabh.Mishra@Sun.COM "ddi_intr_get_supported_types failed : %d", err);
66011353SSaurabh.Mishra@Sun.COM return (DDI_FAILURE);
66110393SSaurabh.Mishra@Sun.COM }
66210393SSaurabh.Mishra@Sun.COM
66310393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: ddi_intr_get_supported_types() returned : %d",
66410393SSaurabh.Mishra@Sun.COM atgep->atge_name, atgep->atge_intr_types));
66510393SSaurabh.Mishra@Sun.COM
66610393SSaurabh.Mishra@Sun.COM
66710393SSaurabh.Mishra@Sun.COM if (atgep->atge_intr_types & DDI_INTR_TYPE_MSIX) {
66810393SSaurabh.Mishra@Sun.COM err = atge_add_intr_handler(atgep, DDI_INTR_TYPE_MSIX);
66911353SSaurabh.Mishra@Sun.COM if (err == DDI_SUCCESS) {
67010393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: Using MSIx for interrupt",
67110393SSaurabh.Mishra@Sun.COM atgep->atge_name));
67210393SSaurabh.Mishra@Sun.COM return (err);
67310393SSaurabh.Mishra@Sun.COM }
67410393SSaurabh.Mishra@Sun.COM }
67510393SSaurabh.Mishra@Sun.COM
67610393SSaurabh.Mishra@Sun.COM if (atgep->atge_intr_types & DDI_INTR_TYPE_MSI) {
67710393SSaurabh.Mishra@Sun.COM err = atge_add_intr_handler(atgep, DDI_INTR_TYPE_MSI);
67811353SSaurabh.Mishra@Sun.COM if (err == DDI_SUCCESS) {
67910393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: Using MSI for interrupt",
68010393SSaurabh.Mishra@Sun.COM atgep->atge_name));
68110393SSaurabh.Mishra@Sun.COM return (err);
68210393SSaurabh.Mishra@Sun.COM }
68310393SSaurabh.Mishra@Sun.COM }
68410393SSaurabh.Mishra@Sun.COM
68511353SSaurabh.Mishra@Sun.COM err = DDI_FAILURE;
68610393SSaurabh.Mishra@Sun.COM if (atgep->atge_intr_types & DDI_INTR_TYPE_FIXED) {
68710393SSaurabh.Mishra@Sun.COM err = atge_add_intr_handler(atgep, DDI_INTR_TYPE_FIXED);
68811353SSaurabh.Mishra@Sun.COM if (err == DDI_SUCCESS) {
68910393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: Using FIXED type for interrupt",
69010393SSaurabh.Mishra@Sun.COM atgep->atge_name));
69110393SSaurabh.Mishra@Sun.COM return (err);
69210393SSaurabh.Mishra@Sun.COM }
69310393SSaurabh.Mishra@Sun.COM }
69410393SSaurabh.Mishra@Sun.COM
69510393SSaurabh.Mishra@Sun.COM return (err);
69610393SSaurabh.Mishra@Sun.COM }
69710393SSaurabh.Mishra@Sun.COM
69810393SSaurabh.Mishra@Sun.COM int
atge_identify_hardware(atge_t * atgep)69910393SSaurabh.Mishra@Sun.COM atge_identify_hardware(atge_t *atgep)
70010393SSaurabh.Mishra@Sun.COM {
70110393SSaurabh.Mishra@Sun.COM uint16_t vid, did;
70210393SSaurabh.Mishra@Sun.COM int i;
70310393SSaurabh.Mishra@Sun.COM
70410393SSaurabh.Mishra@Sun.COM vid = pci_config_get16(atgep->atge_conf_handle, PCI_CONF_VENID);
70510393SSaurabh.Mishra@Sun.COM did = pci_config_get16(atgep->atge_conf_handle, PCI_CONF_DEVID);
70610393SSaurabh.Mishra@Sun.COM
70710393SSaurabh.Mishra@Sun.COM atgep->atge_model = 0;
70810393SSaurabh.Mishra@Sun.COM for (i = 0; i < (sizeof (atge_cards) / sizeof (atge_cards_t)); i++) {
70910393SSaurabh.Mishra@Sun.COM if (atge_cards[i].vendor_id == vid &&
71010393SSaurabh.Mishra@Sun.COM atge_cards[i].device_id == did) {
71110393SSaurabh.Mishra@Sun.COM atgep->atge_model = atge_cards[i].model;
71210393SSaurabh.Mishra@Sun.COM atgep->atge_revid =
71310393SSaurabh.Mishra@Sun.COM pci_config_get8(atgep->atge_conf_handle,
71410393SSaurabh.Mishra@Sun.COM PCI_CONF_REVID);
71510393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s : PCI-ID pci%x,%x and model : %d",
71610393SSaurabh.Mishra@Sun.COM atgep->atge_name, __func__, vid, did,
71710393SSaurabh.Mishra@Sun.COM atgep->atge_model));
71810393SSaurabh.Mishra@Sun.COM
71911353SSaurabh.Mishra@Sun.COM return (DDI_SUCCESS);
72010393SSaurabh.Mishra@Sun.COM }
72110393SSaurabh.Mishra@Sun.COM }
72210393SSaurabh.Mishra@Sun.COM
72310393SSaurabh.Mishra@Sun.COM atge_error(atgep->atge_dip, "atge driver is attaching to unknown"
72410393SSaurabh.Mishra@Sun.COM " pci%d,%d vendor/device-id card", vid, did);
72510393SSaurabh.Mishra@Sun.COM
72610393SSaurabh.Mishra@Sun.COM /*
72711353SSaurabh.Mishra@Sun.COM * Assume it's L1 chip.
72810393SSaurabh.Mishra@Sun.COM */
72911353SSaurabh.Mishra@Sun.COM atgep->atge_model = ATGE_CHIP_L1;
73010393SSaurabh.Mishra@Sun.COM atgep->atge_revid = pci_config_get8(atgep->atge_conf_handle,
73110393SSaurabh.Mishra@Sun.COM PCI_CONF_REVID);
73210393SSaurabh.Mishra@Sun.COM
73310393SSaurabh.Mishra@Sun.COM /*
73410393SSaurabh.Mishra@Sun.COM * We will leave the decision to caller.
73510393SSaurabh.Mishra@Sun.COM */
73611353SSaurabh.Mishra@Sun.COM return (DDI_FAILURE);
73710393SSaurabh.Mishra@Sun.COM }
73810393SSaurabh.Mishra@Sun.COM
73910393SSaurabh.Mishra@Sun.COM int
atge_get_macaddr(atge_t * atgep)74010393SSaurabh.Mishra@Sun.COM atge_get_macaddr(atge_t *atgep)
74110393SSaurabh.Mishra@Sun.COM {
74210393SSaurabh.Mishra@Sun.COM uint32_t reg;
74310393SSaurabh.Mishra@Sun.COM
74410393SSaurabh.Mishra@Sun.COM reg = INL(atgep, ATGE_SPI_CTRL);
74510393SSaurabh.Mishra@Sun.COM if ((reg & SPI_VPD_ENB) != 0) {
74610393SSaurabh.Mishra@Sun.COM /*
74710393SSaurabh.Mishra@Sun.COM * Get VPD stored in TWSI EEPROM.
74810393SSaurabh.Mishra@Sun.COM */
74910393SSaurabh.Mishra@Sun.COM reg &= ~SPI_VPD_ENB;
75010393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_SPI_CTRL, reg);
75110393SSaurabh.Mishra@Sun.COM
75210393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s called Get VPD", atgep->atge_name, __func__));
75310393SSaurabh.Mishra@Sun.COM }
75410393SSaurabh.Mishra@Sun.COM
75510393SSaurabh.Mishra@Sun.COM atgep->atge_ether_addr[5] = INB(atgep, ATGE_PAR0 + 0);
75610393SSaurabh.Mishra@Sun.COM atgep->atge_ether_addr[4] = INB(atgep, ATGE_PAR0 + 1);
75710393SSaurabh.Mishra@Sun.COM atgep->atge_ether_addr[3] = INB(atgep, ATGE_PAR0 + 2);
75810393SSaurabh.Mishra@Sun.COM atgep->atge_ether_addr[2] = INB(atgep, ATGE_PAR0 + 3);
75910393SSaurabh.Mishra@Sun.COM atgep->atge_ether_addr[1] = INB(atgep, ATGE_PAR1 + 0);
76010393SSaurabh.Mishra@Sun.COM atgep->atge_ether_addr[0] = INB(atgep, ATGE_PAR1 + 1);
76110393SSaurabh.Mishra@Sun.COM
76210393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s() Station Address - %x:%x:%x:%x:%x:%x",
76310393SSaurabh.Mishra@Sun.COM atgep->atge_name, __func__,
76410393SSaurabh.Mishra@Sun.COM atgep->atge_ether_addr[0],
76510393SSaurabh.Mishra@Sun.COM atgep->atge_ether_addr[1],
76610393SSaurabh.Mishra@Sun.COM atgep->atge_ether_addr[2],
76710393SSaurabh.Mishra@Sun.COM atgep->atge_ether_addr[3],
76810393SSaurabh.Mishra@Sun.COM atgep->atge_ether_addr[4],
76910393SSaurabh.Mishra@Sun.COM atgep->atge_ether_addr[5]));
77010393SSaurabh.Mishra@Sun.COM
77110393SSaurabh.Mishra@Sun.COM bcopy(atgep->atge_ether_addr, atgep->atge_dev_addr, ETHERADDRL);
77210393SSaurabh.Mishra@Sun.COM
77311353SSaurabh.Mishra@Sun.COM return (DDI_SUCCESS);
77410393SSaurabh.Mishra@Sun.COM }
77510393SSaurabh.Mishra@Sun.COM
77610393SSaurabh.Mishra@Sun.COM /*
77710393SSaurabh.Mishra@Sun.COM * Reset functionality for L1 and L1E. It's same.
77810393SSaurabh.Mishra@Sun.COM */
77910393SSaurabh.Mishra@Sun.COM static void
atge_device_reset(atge_t * atgep)78010393SSaurabh.Mishra@Sun.COM atge_device_reset(atge_t *atgep)
78110393SSaurabh.Mishra@Sun.COM {
78210393SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E ||
78310393SSaurabh.Mishra@Sun.COM ATGE_MODEL(atgep) == ATGE_CHIP_L1)
78410393SSaurabh.Mishra@Sun.COM atge_device_reset_l1_l1e(atgep);
78510393SSaurabh.Mishra@Sun.COM }
78610393SSaurabh.Mishra@Sun.COM
78710393SSaurabh.Mishra@Sun.COM void
atge_device_reset_l1_l1e(atge_t * atgep)78810393SSaurabh.Mishra@Sun.COM atge_device_reset_l1_l1e(atge_t *atgep)
78910393SSaurabh.Mishra@Sun.COM {
79010393SSaurabh.Mishra@Sun.COM uint32_t reg;
79110393SSaurabh.Mishra@Sun.COM int t;
79210393SSaurabh.Mishra@Sun.COM
79310393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_MASTER_CFG, MASTER_RESET);
79410393SSaurabh.Mishra@Sun.COM reg = INL(atgep, ATGE_MASTER_CFG);
79510393SSaurabh.Mishra@Sun.COM for (t = ATGE_RESET_TIMEOUT; t > 0; t--) {
79610393SSaurabh.Mishra@Sun.COM drv_usecwait(10);
79710393SSaurabh.Mishra@Sun.COM reg = INL(atgep, ATGE_MASTER_CFG);
79810393SSaurabh.Mishra@Sun.COM if ((reg & MASTER_RESET) == 0)
79910393SSaurabh.Mishra@Sun.COM break;
80010393SSaurabh.Mishra@Sun.COM }
80110393SSaurabh.Mishra@Sun.COM
80210393SSaurabh.Mishra@Sun.COM if (t == 0) {
80310393SSaurabh.Mishra@Sun.COM atge_error(atgep->atge_dip, " master reset timeout reg : %x",
80410393SSaurabh.Mishra@Sun.COM reg);
80510393SSaurabh.Mishra@Sun.COM }
80610393SSaurabh.Mishra@Sun.COM
80710393SSaurabh.Mishra@Sun.COM for (t = ATGE_RESET_TIMEOUT; t > 0; t--) {
80810393SSaurabh.Mishra@Sun.COM if ((reg = INL(atgep, ATGE_IDLE_STATUS)) == 0)
80910393SSaurabh.Mishra@Sun.COM break;
81010393SSaurabh.Mishra@Sun.COM
81110393SSaurabh.Mishra@Sun.COM drv_usecwait(10);
81210393SSaurabh.Mishra@Sun.COM }
81310393SSaurabh.Mishra@Sun.COM
81410393SSaurabh.Mishra@Sun.COM if (t == 0) {
81510393SSaurabh.Mishra@Sun.COM atge_error(atgep->atge_dip, "device reset timeout reg : %x",
81610393SSaurabh.Mishra@Sun.COM reg);
81710393SSaurabh.Mishra@Sun.COM }
81810393SSaurabh.Mishra@Sun.COM
81910393SSaurabh.Mishra@Sun.COM /*
82010393SSaurabh.Mishra@Sun.COM * Initialize PCIe module. These values came from FreeBSD and
82110393SSaurabh.Mishra@Sun.COM * we don't know the meaning of it.
82210393SSaurabh.Mishra@Sun.COM */
82310393SSaurabh.Mishra@Sun.COM OUTL(atgep, 0x12FC, 0x6500);
82410393SSaurabh.Mishra@Sun.COM reg = INL(atgep, 0x1008) | 0x8000;
82510393SSaurabh.Mishra@Sun.COM OUTL(atgep, 0x1008, reg);
82610393SSaurabh.Mishra@Sun.COM
82710393SSaurabh.Mishra@Sun.COM /*
82810393SSaurabh.Mishra@Sun.COM * Get chip revision.
82910393SSaurabh.Mishra@Sun.COM */
83010393SSaurabh.Mishra@Sun.COM atgep->atge_chip_rev = INL(atgep, ATGE_MASTER_CFG) >>
83110393SSaurabh.Mishra@Sun.COM MASTER_CHIP_REV_SHIFT;
83210393SSaurabh.Mishra@Sun.COM
83310393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s reset successfully rev : %x", atgep->atge_name,
83410393SSaurabh.Mishra@Sun.COM __func__, atgep->atge_chip_rev));
83510393SSaurabh.Mishra@Sun.COM }
83610393SSaurabh.Mishra@Sun.COM
83710393SSaurabh.Mishra@Sun.COM /*
83810393SSaurabh.Mishra@Sun.COM * DMA allocation for L1 and L1E is bit different since L1E uses RX pages
83910393SSaurabh.Mishra@Sun.COM * instead of descriptor based RX model.
84010393SSaurabh.Mishra@Sun.COM */
84110393SSaurabh.Mishra@Sun.COM static int
atge_alloc_dma(atge_t * atgep)84210393SSaurabh.Mishra@Sun.COM atge_alloc_dma(atge_t *atgep)
84310393SSaurabh.Mishra@Sun.COM {
84411353SSaurabh.Mishra@Sun.COM int err = DDI_FAILURE;
84510393SSaurabh.Mishra@Sun.COM
84610393SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
84710393SSaurabh.Mishra@Sun.COM err = atge_l1e_alloc_dma(atgep);
84811353SSaurabh.Mishra@Sun.COM } else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
84911353SSaurabh.Mishra@Sun.COM err = atge_l1_alloc_dma(atgep);
85010393SSaurabh.Mishra@Sun.COM }
85110393SSaurabh.Mishra@Sun.COM
85210393SSaurabh.Mishra@Sun.COM return (err);
85310393SSaurabh.Mishra@Sun.COM }
85410393SSaurabh.Mishra@Sun.COM
85510393SSaurabh.Mishra@Sun.COM static void
atge_free_dma(atge_t * atgep)85610393SSaurabh.Mishra@Sun.COM atge_free_dma(atge_t *atgep)
85710393SSaurabh.Mishra@Sun.COM {
85810393SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
85910393SSaurabh.Mishra@Sun.COM atge_l1e_free_dma(atgep);
86010393SSaurabh.Mishra@Sun.COM }
86110393SSaurabh.Mishra@Sun.COM }
86210393SSaurabh.Mishra@Sun.COM
86310393SSaurabh.Mishra@Sun.COM /*
86410393SSaurabh.Mishra@Sun.COM * Attach entry point in the driver.
86510393SSaurabh.Mishra@Sun.COM */
86610393SSaurabh.Mishra@Sun.COM static int
atge_attach(dev_info_t * devinfo,ddi_attach_cmd_t cmd)86710393SSaurabh.Mishra@Sun.COM atge_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
86810393SSaurabh.Mishra@Sun.COM {
86910393SSaurabh.Mishra@Sun.COM atge_t *atgep;
87010393SSaurabh.Mishra@Sun.COM mac_register_t *macreg;
87110393SSaurabh.Mishra@Sun.COM int instance;
87210393SSaurabh.Mishra@Sun.COM uint16_t cap_ptr;
87310393SSaurabh.Mishra@Sun.COM uint16_t burst;
87410393SSaurabh.Mishra@Sun.COM int err;
87510393SSaurabh.Mishra@Sun.COM mii_ops_t *mii_ops;
87610393SSaurabh.Mishra@Sun.COM
87710393SSaurabh.Mishra@Sun.COM instance = ddi_get_instance(devinfo);
87810393SSaurabh.Mishra@Sun.COM
87910393SSaurabh.Mishra@Sun.COM switch (cmd) {
88010393SSaurabh.Mishra@Sun.COM default:
88110393SSaurabh.Mishra@Sun.COM return (DDI_FAILURE);
88210393SSaurabh.Mishra@Sun.COM
88310393SSaurabh.Mishra@Sun.COM case DDI_RESUME:
88410393SSaurabh.Mishra@Sun.COM return (atge_resume(devinfo));
88510393SSaurabh.Mishra@Sun.COM
88610393SSaurabh.Mishra@Sun.COM case DDI_ATTACH:
88710393SSaurabh.Mishra@Sun.COM ddi_set_driver_private(devinfo, NULL);
88810393SSaurabh.Mishra@Sun.COM break;
88910393SSaurabh.Mishra@Sun.COM }
89010393SSaurabh.Mishra@Sun.COM
89110393SSaurabh.Mishra@Sun.COM atgep = kmem_zalloc(sizeof (atge_t), KM_SLEEP);
89210393SSaurabh.Mishra@Sun.COM ddi_set_driver_private(devinfo, atgep);
89310393SSaurabh.Mishra@Sun.COM atgep->atge_dip = devinfo;
89410393SSaurabh.Mishra@Sun.COM
89510393SSaurabh.Mishra@Sun.COM /*
89610393SSaurabh.Mishra@Sun.COM * Setup name and instance number to be used for debugging and
89710393SSaurabh.Mishra@Sun.COM * error reporting.
89810393SSaurabh.Mishra@Sun.COM */
89910393SSaurabh.Mishra@Sun.COM (void) snprintf(atgep->atge_name, sizeof (atgep->atge_name), "%s%d",
90010393SSaurabh.Mishra@Sun.COM "atge", instance);
90110393SSaurabh.Mishra@Sun.COM
90210393SSaurabh.Mishra@Sun.COM
90310393SSaurabh.Mishra@Sun.COM /*
90410393SSaurabh.Mishra@Sun.COM * Map PCI config space.
90510393SSaurabh.Mishra@Sun.COM */
90610393SSaurabh.Mishra@Sun.COM err = pci_config_setup(devinfo, &atgep->atge_conf_handle);
90710393SSaurabh.Mishra@Sun.COM if (err != DDI_SUCCESS) {
90810393SSaurabh.Mishra@Sun.COM atge_error(devinfo, "pci_config_setup() failed");
90910393SSaurabh.Mishra@Sun.COM goto fail1;
91010393SSaurabh.Mishra@Sun.COM }
91110393SSaurabh.Mishra@Sun.COM
91210393SSaurabh.Mishra@Sun.COM (void) atge_identify_hardware(atgep);
91310393SSaurabh.Mishra@Sun.COM
91410393SSaurabh.Mishra@Sun.COM /*
91510393SSaurabh.Mishra@Sun.COM * Map Device registers.
91610393SSaurabh.Mishra@Sun.COM */
91710393SSaurabh.Mishra@Sun.COM err = ddi_regs_map_setup(devinfo, ATGE_PCI_REG_NUMBER,
91810393SSaurabh.Mishra@Sun.COM &atgep->atge_io_regs, 0, 0, &atge_dev_attr, &atgep->atge_io_handle);
91910393SSaurabh.Mishra@Sun.COM if (err != DDI_SUCCESS) {
92010393SSaurabh.Mishra@Sun.COM atge_error(devinfo, "ddi_regs_map_setup() failed");
92110393SSaurabh.Mishra@Sun.COM goto fail2;
92210393SSaurabh.Mishra@Sun.COM }
92310393SSaurabh.Mishra@Sun.COM
92410393SSaurabh.Mishra@Sun.COM /*
92510393SSaurabh.Mishra@Sun.COM * Add interrupt and its associated handler.
92610393SSaurabh.Mishra@Sun.COM */
92710393SSaurabh.Mishra@Sun.COM err = atge_add_intr(atgep);
92811353SSaurabh.Mishra@Sun.COM if (err != DDI_SUCCESS) {
92910393SSaurabh.Mishra@Sun.COM atge_error(devinfo, "Failed to add interrupt handler");
93010393SSaurabh.Mishra@Sun.COM goto fail3;
93110393SSaurabh.Mishra@Sun.COM }
93210393SSaurabh.Mishra@Sun.COM
93310393SSaurabh.Mishra@Sun.COM mutex_init(&atgep->atge_intr_lock, NULL, MUTEX_DRIVER,
93410393SSaurabh.Mishra@Sun.COM DDI_INTR_PRI(atgep->atge_intr_pri));
93510393SSaurabh.Mishra@Sun.COM
93610393SSaurabh.Mishra@Sun.COM mutex_init(&atgep->atge_tx_lock, NULL, MUTEX_DRIVER,
93710393SSaurabh.Mishra@Sun.COM DDI_INTR_PRI(atgep->atge_intr_pri));
93810393SSaurabh.Mishra@Sun.COM
93910393SSaurabh.Mishra@Sun.COM mutex_init(&atgep->atge_rx_lock, NULL, MUTEX_DRIVER,
94010393SSaurabh.Mishra@Sun.COM DDI_INTR_PRI(atgep->atge_intr_pri));
94110393SSaurabh.Mishra@Sun.COM
94210393SSaurabh.Mishra@Sun.COM mutex_init(&atgep->atge_mii_lock, NULL, MUTEX_DRIVER, NULL);
94310393SSaurabh.Mishra@Sun.COM
94411353SSaurabh.Mishra@Sun.COM /*
94511353SSaurabh.Mishra@Sun.COM * Used to lock down MBOX register on L1 chip since RX consumer,
94611353SSaurabh.Mishra@Sun.COM * TX producer and RX return ring consumer are shared.
94711353SSaurabh.Mishra@Sun.COM */
94811353SSaurabh.Mishra@Sun.COM mutex_init(&atgep->atge_mbox_lock, NULL, MUTEX_DRIVER,
94911353SSaurabh.Mishra@Sun.COM DDI_INTR_PRI(atgep->atge_intr_pri));
95011353SSaurabh.Mishra@Sun.COM
95110393SSaurabh.Mishra@Sun.COM atgep->atge_link_state = LINK_STATE_DOWN;
95210393SSaurabh.Mishra@Sun.COM atgep->atge_mtu = ETHERMTU;
95310393SSaurabh.Mishra@Sun.COM
95411353SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
95511353SSaurabh.Mishra@Sun.COM if (atgep->atge_revid > 0xF0) {
95611353SSaurabh.Mishra@Sun.COM /* L2E Rev. B. AR8114 */
95711353SSaurabh.Mishra@Sun.COM atgep->atge_flags |= ATGE_FLAG_FASTETHER;
95810393SSaurabh.Mishra@Sun.COM } else {
95911353SSaurabh.Mishra@Sun.COM if ((INL(atgep, L1E_PHY_STATUS) &
96011353SSaurabh.Mishra@Sun.COM PHY_STATUS_100M) != 0) {
96111353SSaurabh.Mishra@Sun.COM /* L1E AR8121 */
96211353SSaurabh.Mishra@Sun.COM atgep->atge_flags |= ATGE_FLAG_JUMBO;
96311353SSaurabh.Mishra@Sun.COM } else {
96411353SSaurabh.Mishra@Sun.COM /* L2E Rev. A. AR8113 */
96511353SSaurabh.Mishra@Sun.COM atgep->atge_flags |= ATGE_FLAG_FASTETHER;
96611353SSaurabh.Mishra@Sun.COM }
96710393SSaurabh.Mishra@Sun.COM }
96810393SSaurabh.Mishra@Sun.COM }
96910393SSaurabh.Mishra@Sun.COM
97010393SSaurabh.Mishra@Sun.COM /*
97110393SSaurabh.Mishra@Sun.COM * Get DMA parameters from PCIe device control register.
97210393SSaurabh.Mishra@Sun.COM */
97310393SSaurabh.Mishra@Sun.COM err = PCI_CAP_LOCATE(atgep->atge_conf_handle, PCI_CAP_ID_PCI_E,
97410393SSaurabh.Mishra@Sun.COM &cap_ptr);
97510393SSaurabh.Mishra@Sun.COM
97610393SSaurabh.Mishra@Sun.COM if (err == DDI_FAILURE) {
97710393SSaurabh.Mishra@Sun.COM atgep->atge_dma_rd_burst = DMA_CFG_RD_BURST_128;
97810393SSaurabh.Mishra@Sun.COM atgep->atge_dma_wr_burst = DMA_CFG_WR_BURST_128;
97910393SSaurabh.Mishra@Sun.COM } else {
98010393SSaurabh.Mishra@Sun.COM atgep->atge_flags |= ATGE_FLAG_PCIE;
98110393SSaurabh.Mishra@Sun.COM burst = pci_config_get16(atgep->atge_conf_handle,
98210393SSaurabh.Mishra@Sun.COM cap_ptr + 0x08);
98310393SSaurabh.Mishra@Sun.COM
98410393SSaurabh.Mishra@Sun.COM /*
98510393SSaurabh.Mishra@Sun.COM * Max read request size.
98610393SSaurabh.Mishra@Sun.COM */
98710393SSaurabh.Mishra@Sun.COM atgep->atge_dma_rd_burst = ((burst >> 12) & 0x07) <<
98810393SSaurabh.Mishra@Sun.COM DMA_CFG_RD_BURST_SHIFT;
98910393SSaurabh.Mishra@Sun.COM
99010393SSaurabh.Mishra@Sun.COM /*
99110393SSaurabh.Mishra@Sun.COM * Max Payload Size.
99210393SSaurabh.Mishra@Sun.COM */
99310393SSaurabh.Mishra@Sun.COM atgep->atge_dma_wr_burst = ((burst >> 5) & 0x07) <<
99410393SSaurabh.Mishra@Sun.COM DMA_CFG_WR_BURST_SHIFT;
99510393SSaurabh.Mishra@Sun.COM
99610393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s() MRR : %d, MPS : %d",
99710393SSaurabh.Mishra@Sun.COM atgep->atge_name, __func__,
99810393SSaurabh.Mishra@Sun.COM (128 << ((burst >> 12) & 0x07)),
99910393SSaurabh.Mishra@Sun.COM (128 << ((burst >> 5) & 0x07))));
100010393SSaurabh.Mishra@Sun.COM }
100110393SSaurabh.Mishra@Sun.COM
100210393SSaurabh.Mishra@Sun.COM /*
100310393SSaurabh.Mishra@Sun.COM * Allocate DMA resources.
100410393SSaurabh.Mishra@Sun.COM */
100510393SSaurabh.Mishra@Sun.COM err = atge_alloc_dma(atgep);
100611353SSaurabh.Mishra@Sun.COM if (err != DDI_SUCCESS) {
100710393SSaurabh.Mishra@Sun.COM atge_error(devinfo, "Failed to allocate DMA resources");
100810393SSaurabh.Mishra@Sun.COM goto fail4;
100910393SSaurabh.Mishra@Sun.COM }
101010393SSaurabh.Mishra@Sun.COM
101110393SSaurabh.Mishra@Sun.COM /*
101210393SSaurabh.Mishra@Sun.COM * Get station address.
101310393SSaurabh.Mishra@Sun.COM */
101410393SSaurabh.Mishra@Sun.COM (void) atge_get_macaddr(atgep);
101510393SSaurabh.Mishra@Sun.COM
101610393SSaurabh.Mishra@Sun.COM /*
101710393SSaurabh.Mishra@Sun.COM * Setup MII.
101810393SSaurabh.Mishra@Sun.COM */
101910393SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
102010393SSaurabh.Mishra@Sun.COM mii_ops = &atge_l1e_mii_ops;
102111353SSaurabh.Mishra@Sun.COM } else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
102211353SSaurabh.Mishra@Sun.COM mii_ops = &atge_l1_mii_ops;
102310393SSaurabh.Mishra@Sun.COM }
102410393SSaurabh.Mishra@Sun.COM
102510393SSaurabh.Mishra@Sun.COM if ((atgep->atge_mii = mii_alloc(atgep, devinfo,
102610393SSaurabh.Mishra@Sun.COM mii_ops)) == NULL) {
102710393SSaurabh.Mishra@Sun.COM atge_error(devinfo, "mii_alloc() failed");
102810393SSaurabh.Mishra@Sun.COM goto fail4;
102910393SSaurabh.Mishra@Sun.COM }
103010393SSaurabh.Mishra@Sun.COM
103110393SSaurabh.Mishra@Sun.COM /*
103210393SSaurabh.Mishra@Sun.COM * Register with MAC layer.
103310393SSaurabh.Mishra@Sun.COM */
103410393SSaurabh.Mishra@Sun.COM if ((macreg = mac_alloc(MAC_VERSION)) == NULL) {
103510393SSaurabh.Mishra@Sun.COM atge_error(devinfo, "mac_alloc() failed due to version");
103610393SSaurabh.Mishra@Sun.COM goto fail4;
103710393SSaurabh.Mishra@Sun.COM }
103810393SSaurabh.Mishra@Sun.COM
103910393SSaurabh.Mishra@Sun.COM macreg->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
104010393SSaurabh.Mishra@Sun.COM macreg->m_driver = atgep;
104110393SSaurabh.Mishra@Sun.COM macreg->m_dip = devinfo;
104210393SSaurabh.Mishra@Sun.COM macreg->m_instance = instance;
104310393SSaurabh.Mishra@Sun.COM macreg->m_src_addr = atgep->atge_ether_addr;
104410393SSaurabh.Mishra@Sun.COM macreg->m_callbacks = &atge_m_callbacks;
104510393SSaurabh.Mishra@Sun.COM macreg->m_min_sdu = 0;
104610393SSaurabh.Mishra@Sun.COM macreg->m_max_sdu = atgep->atge_mtu;
104710393SSaurabh.Mishra@Sun.COM macreg->m_margin = VLAN_TAGSZ;
104810393SSaurabh.Mishra@Sun.COM
104910393SSaurabh.Mishra@Sun.COM if ((err = mac_register(macreg, &atgep->atge_mh)) != 0) {
105010393SSaurabh.Mishra@Sun.COM atge_error(devinfo, "mac_register() failed with :%d", err);
105110393SSaurabh.Mishra@Sun.COM mac_free(macreg);
105210393SSaurabh.Mishra@Sun.COM goto fail4;
105310393SSaurabh.Mishra@Sun.COM }
105410393SSaurabh.Mishra@Sun.COM
105510393SSaurabh.Mishra@Sun.COM mac_free(macreg);
105610393SSaurabh.Mishra@Sun.COM
105710393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s() driver attached successfully",
105810393SSaurabh.Mishra@Sun.COM atgep->atge_name, __func__));
105910393SSaurabh.Mishra@Sun.COM
106010393SSaurabh.Mishra@Sun.COM atge_device_reset(atgep);
106110393SSaurabh.Mishra@Sun.COM
106210393SSaurabh.Mishra@Sun.COM atgep->atge_chip_state = ATGE_CHIP_INITIALIZED;
106310393SSaurabh.Mishra@Sun.COM
106410393SSaurabh.Mishra@Sun.COM /*
106510393SSaurabh.Mishra@Sun.COM * At last - enable interrupts.
106610393SSaurabh.Mishra@Sun.COM */
106710393SSaurabh.Mishra@Sun.COM err = atge_enable_intrs(atgep);
106811353SSaurabh.Mishra@Sun.COM if (err == DDI_FAILURE) {
106910393SSaurabh.Mishra@Sun.COM goto fail5;
107010393SSaurabh.Mishra@Sun.COM }
107110393SSaurabh.Mishra@Sun.COM
107210393SSaurabh.Mishra@Sun.COM /*
107310393SSaurabh.Mishra@Sun.COM * Reset the PHY before starting.
107410393SSaurabh.Mishra@Sun.COM */
107510393SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
107610393SSaurabh.Mishra@Sun.COM atge_l1e_mii_reset(atgep);
107711353SSaurabh.Mishra@Sun.COM } else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
107811353SSaurabh.Mishra@Sun.COM atge_l1_mii_reset(atgep);
107910393SSaurabh.Mishra@Sun.COM }
108010393SSaurabh.Mishra@Sun.COM
108110393SSaurabh.Mishra@Sun.COM /*
108210393SSaurabh.Mishra@Sun.COM * Let the PHY run.
108310393SSaurabh.Mishra@Sun.COM */
108410393SSaurabh.Mishra@Sun.COM mii_start(atgep->atge_mii);
108510393SSaurabh.Mishra@Sun.COM
108610393SSaurabh.Mishra@Sun.COM return (DDI_SUCCESS);
108710393SSaurabh.Mishra@Sun.COM
108810393SSaurabh.Mishra@Sun.COM fail5:
108910393SSaurabh.Mishra@Sun.COM (void) mac_unregister(atgep->atge_mh);
109010393SSaurabh.Mishra@Sun.COM atge_device_stop(atgep);
109110393SSaurabh.Mishra@Sun.COM mii_stop(atgep->atge_mii);
109210393SSaurabh.Mishra@Sun.COM mii_free(atgep->atge_mii);
109310393SSaurabh.Mishra@Sun.COM fail4:
109410393SSaurabh.Mishra@Sun.COM atge_free_dma(atgep);
109510393SSaurabh.Mishra@Sun.COM mutex_destroy(&atgep->atge_intr_lock);
109610393SSaurabh.Mishra@Sun.COM mutex_destroy(&atgep->atge_tx_lock);
109710393SSaurabh.Mishra@Sun.COM mutex_destroy(&atgep->atge_rx_lock);
109810393SSaurabh.Mishra@Sun.COM atge_remove_intr(atgep);
109910393SSaurabh.Mishra@Sun.COM fail3:
110010393SSaurabh.Mishra@Sun.COM ddi_regs_map_free(&atgep->atge_io_handle);
110110393SSaurabh.Mishra@Sun.COM fail2:
110210393SSaurabh.Mishra@Sun.COM pci_config_teardown(&atgep->atge_conf_handle);
110310393SSaurabh.Mishra@Sun.COM fail1:
110410393SSaurabh.Mishra@Sun.COM if (atgep)
110510393SSaurabh.Mishra@Sun.COM kmem_free(atgep, sizeof (atge_t));
110610393SSaurabh.Mishra@Sun.COM
110710393SSaurabh.Mishra@Sun.COM return (DDI_FAILURE);
110810393SSaurabh.Mishra@Sun.COM }
110910393SSaurabh.Mishra@Sun.COM
111010393SSaurabh.Mishra@Sun.COM static int
atge_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)111110393SSaurabh.Mishra@Sun.COM atge_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
111210393SSaurabh.Mishra@Sun.COM {
111310393SSaurabh.Mishra@Sun.COM atge_t *atgep;
111410393SSaurabh.Mishra@Sun.COM
111510393SSaurabh.Mishra@Sun.COM atgep = ddi_get_driver_private(dip);
111610393SSaurabh.Mishra@Sun.COM if (atgep == NULL) {
111710393SSaurabh.Mishra@Sun.COM atge_error(dip, "No soft state in detach");
111810393SSaurabh.Mishra@Sun.COM return (DDI_FAILURE);
111910393SSaurabh.Mishra@Sun.COM }
112010393SSaurabh.Mishra@Sun.COM
112110393SSaurabh.Mishra@Sun.COM switch (cmd) {
112210393SSaurabh.Mishra@Sun.COM case DDI_DETACH:
112310393SSaurabh.Mishra@Sun.COM
112410393SSaurabh.Mishra@Sun.COM /*
112510393SSaurabh.Mishra@Sun.COM * First unregister with MAC layer before stopping DMA
112610393SSaurabh.Mishra@Sun.COM */
1127*12398Sgdamore@opensolaris.org if (mac_disable(atgep->atge_mh) != DDI_SUCCESS)
112810393SSaurabh.Mishra@Sun.COM return (DDI_FAILURE);
112910393SSaurabh.Mishra@Sun.COM
1130*12398Sgdamore@opensolaris.org mii_stop(atgep->atge_mii);
113110393SSaurabh.Mishra@Sun.COM
113210393SSaurabh.Mishra@Sun.COM mutex_enter(&atgep->atge_intr_lock);
113310393SSaurabh.Mishra@Sun.COM mutex_enter(&atgep->atge_tx_lock);
113410393SSaurabh.Mishra@Sun.COM atge_device_stop(atgep);
113510393SSaurabh.Mishra@Sun.COM mutex_exit(&atgep->atge_tx_lock);
113610393SSaurabh.Mishra@Sun.COM mutex_exit(&atgep->atge_intr_lock);
113710393SSaurabh.Mishra@Sun.COM
113810393SSaurabh.Mishra@Sun.COM mii_free(atgep->atge_mii);
113910393SSaurabh.Mishra@Sun.COM atge_free_dma(atgep);
114010393SSaurabh.Mishra@Sun.COM
114110393SSaurabh.Mishra@Sun.COM ddi_regs_map_free(&atgep->atge_io_handle);
114210393SSaurabh.Mishra@Sun.COM atge_remove_intr(atgep);
114310393SSaurabh.Mishra@Sun.COM pci_config_teardown(&atgep->atge_conf_handle);
114410393SSaurabh.Mishra@Sun.COM
1145*12398Sgdamore@opensolaris.org (void) mac_unregister(atgep->atge_mh);
114610393SSaurabh.Mishra@Sun.COM mutex_destroy(&atgep->atge_intr_lock);
114710393SSaurabh.Mishra@Sun.COM mutex_destroy(&atgep->atge_tx_lock);
114810393SSaurabh.Mishra@Sun.COM mutex_destroy(&atgep->atge_rx_lock);
114910393SSaurabh.Mishra@Sun.COM kmem_free(atgep, sizeof (atge_t));
115010393SSaurabh.Mishra@Sun.COM ddi_set_driver_private(dip, NULL);
115110393SSaurabh.Mishra@Sun.COM
115210393SSaurabh.Mishra@Sun.COM return (DDI_SUCCESS);
115310393SSaurabh.Mishra@Sun.COM
115410393SSaurabh.Mishra@Sun.COM case DDI_SUSPEND:
115510393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s() is being suspended",
115610393SSaurabh.Mishra@Sun.COM atgep->atge_name, __func__));
115710393SSaurabh.Mishra@Sun.COM
115810393SSaurabh.Mishra@Sun.COM /*
115910393SSaurabh.Mishra@Sun.COM * Suspend monitoring MII.
116010393SSaurabh.Mishra@Sun.COM */
116110393SSaurabh.Mishra@Sun.COM mii_suspend(atgep->atge_mii);
116210393SSaurabh.Mishra@Sun.COM
116310393SSaurabh.Mishra@Sun.COM mutex_enter(&atgep->atge_intr_lock);
116410393SSaurabh.Mishra@Sun.COM mutex_enter(&atgep->atge_tx_lock);
116510393SSaurabh.Mishra@Sun.COM atgep->atge_chip_state |= ATGE_CHIP_SUSPENDED;
116610393SSaurabh.Mishra@Sun.COM atge_device_stop(atgep);
116710393SSaurabh.Mishra@Sun.COM mutex_exit(&atgep->atge_tx_lock);
116810393SSaurabh.Mishra@Sun.COM mutex_exit(&atgep->atge_intr_lock);
116910393SSaurabh.Mishra@Sun.COM
117010393SSaurabh.Mishra@Sun.COM return (DDI_SUCCESS);
117110393SSaurabh.Mishra@Sun.COM
117210393SSaurabh.Mishra@Sun.COM default:
117310393SSaurabh.Mishra@Sun.COM return (DDI_FAILURE);
117410393SSaurabh.Mishra@Sun.COM }
117510393SSaurabh.Mishra@Sun.COM }
117610393SSaurabh.Mishra@Sun.COM
117710393SSaurabh.Mishra@Sun.COM int
atge_alloc_buffers(atge_ring_t * r,size_t rcnt,size_t buflen,int f)117810393SSaurabh.Mishra@Sun.COM atge_alloc_buffers(atge_ring_t *r, size_t rcnt, size_t buflen, int f)
117910393SSaurabh.Mishra@Sun.COM {
118010393SSaurabh.Mishra@Sun.COM atge_dma_t *dma;
118110393SSaurabh.Mishra@Sun.COM atge_dma_t **tbl;
118211353SSaurabh.Mishra@Sun.COM int err = DDI_SUCCESS;
118310393SSaurabh.Mishra@Sun.COM int i;
118410393SSaurabh.Mishra@Sun.COM
118510393SSaurabh.Mishra@Sun.COM tbl = kmem_zalloc(rcnt * sizeof (atge_dma_t *), KM_SLEEP);
118610393SSaurabh.Mishra@Sun.COM r->r_buf_tbl = tbl;
118710393SSaurabh.Mishra@Sun.COM
118810393SSaurabh.Mishra@Sun.COM for (i = 0; i < rcnt; i++) {
118910393SSaurabh.Mishra@Sun.COM dma = atge_buf_alloc(r->r_atge, buflen, f);
119010393SSaurabh.Mishra@Sun.COM if (dma == NULL) {
119111353SSaurabh.Mishra@Sun.COM err = DDI_FAILURE;
119210393SSaurabh.Mishra@Sun.COM break;
119310393SSaurabh.Mishra@Sun.COM }
119410393SSaurabh.Mishra@Sun.COM
119510393SSaurabh.Mishra@Sun.COM tbl[i] = dma;
119610393SSaurabh.Mishra@Sun.COM }
119710393SSaurabh.Mishra@Sun.COM
119810393SSaurabh.Mishra@Sun.COM return (err);
119910393SSaurabh.Mishra@Sun.COM }
120010393SSaurabh.Mishra@Sun.COM
120110393SSaurabh.Mishra@Sun.COM void
atge_free_buffers(atge_ring_t * r,size_t rcnt)120210393SSaurabh.Mishra@Sun.COM atge_free_buffers(atge_ring_t *r, size_t rcnt)
120310393SSaurabh.Mishra@Sun.COM {
120410393SSaurabh.Mishra@Sun.COM atge_dma_t **tbl;
120510393SSaurabh.Mishra@Sun.COM int i;
120610393SSaurabh.Mishra@Sun.COM
120710393SSaurabh.Mishra@Sun.COM if (r == NULL || r->r_buf_tbl == NULL)
120810393SSaurabh.Mishra@Sun.COM return;
120910393SSaurabh.Mishra@Sun.COM
121010393SSaurabh.Mishra@Sun.COM tbl = r->r_buf_tbl;
121110393SSaurabh.Mishra@Sun.COM for (i = 0; i < rcnt; i++) {
121210393SSaurabh.Mishra@Sun.COM if (tbl[i] != NULL) {
121310393SSaurabh.Mishra@Sun.COM atge_buf_free(tbl[i]);
121410393SSaurabh.Mishra@Sun.COM }
121510393SSaurabh.Mishra@Sun.COM }
121610393SSaurabh.Mishra@Sun.COM
121710393SSaurabh.Mishra@Sun.COM kmem_free(tbl, rcnt * sizeof (atge_dma_t *));
121810393SSaurabh.Mishra@Sun.COM }
121910393SSaurabh.Mishra@Sun.COM
122010393SSaurabh.Mishra@Sun.COM atge_dma_t *
atge_alloc_a_dma_blk(atge_t * atgep,ddi_dma_attr_t * attr,int size,int d)122110393SSaurabh.Mishra@Sun.COM atge_alloc_a_dma_blk(atge_t *atgep, ddi_dma_attr_t *attr, int size, int d)
122210393SSaurabh.Mishra@Sun.COM {
122310393SSaurabh.Mishra@Sun.COM int err;
122410393SSaurabh.Mishra@Sun.COM atge_dma_t *dma;
122510393SSaurabh.Mishra@Sun.COM
122610393SSaurabh.Mishra@Sun.COM dma = kmem_zalloc(sizeof (atge_dma_t), KM_SLEEP);
122710393SSaurabh.Mishra@Sun.COM
122810393SSaurabh.Mishra@Sun.COM err = ddi_dma_alloc_handle(atgep->atge_dip, attr,
122910393SSaurabh.Mishra@Sun.COM DDI_DMA_SLEEP, NULL, &dma->hdl);
123010393SSaurabh.Mishra@Sun.COM
123110393SSaurabh.Mishra@Sun.COM if (err != DDI_SUCCESS) {
123210393SSaurabh.Mishra@Sun.COM atge_error(atgep->atge_dip, "%s() : failed"
123310393SSaurabh.Mishra@Sun.COM " in ddi_dma_alloc_handle() : %d", __func__, err);
123410393SSaurabh.Mishra@Sun.COM goto fail;
123510393SSaurabh.Mishra@Sun.COM }
123610393SSaurabh.Mishra@Sun.COM
123710393SSaurabh.Mishra@Sun.COM err = ddi_dma_mem_alloc(dma->hdl,
123810393SSaurabh.Mishra@Sun.COM size, &atge_buf_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
123910393SSaurabh.Mishra@Sun.COM &dma->addr, &dma->len, &dma->acchdl);
124010393SSaurabh.Mishra@Sun.COM
124110393SSaurabh.Mishra@Sun.COM if (err != DDI_SUCCESS) {
124210393SSaurabh.Mishra@Sun.COM atge_error(atgep->atge_dip, "%s() : failed"
124310393SSaurabh.Mishra@Sun.COM " in ddi_dma_mem_alloc() : %d", __func__, err);
124410393SSaurabh.Mishra@Sun.COM ddi_dma_free_handle(&dma->hdl);
124510393SSaurabh.Mishra@Sun.COM goto fail;
124610393SSaurabh.Mishra@Sun.COM }
124710393SSaurabh.Mishra@Sun.COM
124810393SSaurabh.Mishra@Sun.COM err = ddi_dma_addr_bind_handle(dma->hdl, NULL, dma->addr,
124910393SSaurabh.Mishra@Sun.COM dma->len, d | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP,
125010393SSaurabh.Mishra@Sun.COM NULL, &dma->cookie, &dma->count);
125110393SSaurabh.Mishra@Sun.COM
125210393SSaurabh.Mishra@Sun.COM if (err != DDI_SUCCESS) {
125310393SSaurabh.Mishra@Sun.COM atge_error(atgep->atge_dip, "%s() : failed"
125410393SSaurabh.Mishra@Sun.COM " in ddi_dma_addr_bind_handle() : %d", __func__, err);
125510393SSaurabh.Mishra@Sun.COM ddi_dma_mem_free(&dma->acchdl);
125610393SSaurabh.Mishra@Sun.COM ddi_dma_free_handle(&dma->hdl);
125710393SSaurabh.Mishra@Sun.COM goto fail;
125810393SSaurabh.Mishra@Sun.COM }
125910393SSaurabh.Mishra@Sun.COM
126010393SSaurabh.Mishra@Sun.COM return (dma);
126110393SSaurabh.Mishra@Sun.COM fail:
126210393SSaurabh.Mishra@Sun.COM kmem_free(dma, sizeof (atge_dma_t));
126310393SSaurabh.Mishra@Sun.COM return (NULL);
126410393SSaurabh.Mishra@Sun.COM }
126510393SSaurabh.Mishra@Sun.COM
126610393SSaurabh.Mishra@Sun.COM void
atge_free_a_dma_blk(atge_dma_t * dma)126710393SSaurabh.Mishra@Sun.COM atge_free_a_dma_blk(atge_dma_t *dma)
126810393SSaurabh.Mishra@Sun.COM {
126910393SSaurabh.Mishra@Sun.COM if (dma != NULL) {
127010393SSaurabh.Mishra@Sun.COM (void) ddi_dma_unbind_handle(dma->hdl);
127110393SSaurabh.Mishra@Sun.COM ddi_dma_mem_free(&dma->acchdl);
127210393SSaurabh.Mishra@Sun.COM ddi_dma_free_handle(&dma->hdl);
127310393SSaurabh.Mishra@Sun.COM kmem_free(dma, sizeof (atge_dma_t));
127410393SSaurabh.Mishra@Sun.COM }
127510393SSaurabh.Mishra@Sun.COM }
127610393SSaurabh.Mishra@Sun.COM
127710393SSaurabh.Mishra@Sun.COM atge_dma_t *
atge_buf_alloc(atge_t * atgep,size_t len,int f)127810393SSaurabh.Mishra@Sun.COM atge_buf_alloc(atge_t *atgep, size_t len, int f)
127910393SSaurabh.Mishra@Sun.COM {
128010393SSaurabh.Mishra@Sun.COM atge_dma_t *dma = NULL;
128110393SSaurabh.Mishra@Sun.COM int err;
128210393SSaurabh.Mishra@Sun.COM
128310393SSaurabh.Mishra@Sun.COM dma = kmem_zalloc(sizeof (atge_dma_t), KM_SLEEP);
128410393SSaurabh.Mishra@Sun.COM
128510393SSaurabh.Mishra@Sun.COM err = ddi_dma_alloc_handle(atgep->atge_dip, &atge_dma_attr_buf,
128610393SSaurabh.Mishra@Sun.COM DDI_DMA_SLEEP, NULL, &dma->hdl);
128710393SSaurabh.Mishra@Sun.COM
128810393SSaurabh.Mishra@Sun.COM if (err != DDI_SUCCESS) {
128910393SSaurabh.Mishra@Sun.COM atge_error(atgep->atge_dip, "%s() : failed"
129010393SSaurabh.Mishra@Sun.COM " in %s() : %d", __func__, err);
129110393SSaurabh.Mishra@Sun.COM goto fail;
129210393SSaurabh.Mishra@Sun.COM }
129310393SSaurabh.Mishra@Sun.COM
129410393SSaurabh.Mishra@Sun.COM err = ddi_dma_mem_alloc(dma->hdl, len, &atge_buf_attr,
129510393SSaurabh.Mishra@Sun.COM DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &dma->addr,
129610393SSaurabh.Mishra@Sun.COM &dma->len, &dma->acchdl);
129710393SSaurabh.Mishra@Sun.COM
129810393SSaurabh.Mishra@Sun.COM if (err != DDI_SUCCESS) {
129910393SSaurabh.Mishra@Sun.COM atge_error(atgep->atge_dip, "%s() : failed"
130010393SSaurabh.Mishra@Sun.COM " in %s() : %d", __func__, err);
130110393SSaurabh.Mishra@Sun.COM ddi_dma_free_handle(&dma->hdl);
130210393SSaurabh.Mishra@Sun.COM goto fail;
130310393SSaurabh.Mishra@Sun.COM }
130410393SSaurabh.Mishra@Sun.COM
130510393SSaurabh.Mishra@Sun.COM err = ddi_dma_addr_bind_handle(dma->hdl, NULL, dma->addr, dma->len,
130610393SSaurabh.Mishra@Sun.COM (f | DDI_DMA_CONSISTENT), DDI_DMA_SLEEP, NULL, &dma->cookie,
130710393SSaurabh.Mishra@Sun.COM &dma->count);
130810393SSaurabh.Mishra@Sun.COM
130910393SSaurabh.Mishra@Sun.COM if (err != DDI_SUCCESS) {
131010393SSaurabh.Mishra@Sun.COM atge_error(atgep->atge_dip, "%s() : failed"
131110393SSaurabh.Mishra@Sun.COM " in %s() : %d", __func__, err);
131210393SSaurabh.Mishra@Sun.COM ddi_dma_mem_free(&dma->acchdl);
131310393SSaurabh.Mishra@Sun.COM ddi_dma_free_handle(&dma->hdl);
131410393SSaurabh.Mishra@Sun.COM goto fail;
131510393SSaurabh.Mishra@Sun.COM }
131610393SSaurabh.Mishra@Sun.COM
131710393SSaurabh.Mishra@Sun.COM /*
131810393SSaurabh.Mishra@Sun.COM * Number of return'ed cookie should be one.
131910393SSaurabh.Mishra@Sun.COM */
132010393SSaurabh.Mishra@Sun.COM ASSERT(dma->count == 1);
132110393SSaurabh.Mishra@Sun.COM
132210393SSaurabh.Mishra@Sun.COM return (dma);
132310393SSaurabh.Mishra@Sun.COM fail:
132410393SSaurabh.Mishra@Sun.COM kmem_free(dma, sizeof (atge_dma_t));
132510393SSaurabh.Mishra@Sun.COM return (NULL);
132610393SSaurabh.Mishra@Sun.COM }
132710393SSaurabh.Mishra@Sun.COM
132810393SSaurabh.Mishra@Sun.COM void
atge_buf_free(atge_dma_t * dma)132910393SSaurabh.Mishra@Sun.COM atge_buf_free(atge_dma_t *dma)
133010393SSaurabh.Mishra@Sun.COM {
133110393SSaurabh.Mishra@Sun.COM ASSERT(dma != NULL);
133210393SSaurabh.Mishra@Sun.COM
133310393SSaurabh.Mishra@Sun.COM (void) ddi_dma_unbind_handle(dma->hdl);
133410393SSaurabh.Mishra@Sun.COM ddi_dma_mem_free(&dma->acchdl);
133510393SSaurabh.Mishra@Sun.COM ddi_dma_free_handle(&dma->hdl);
133610393SSaurabh.Mishra@Sun.COM kmem_free(dma, sizeof (atge_dma_t));
133710393SSaurabh.Mishra@Sun.COM }
133810393SSaurabh.Mishra@Sun.COM
133910393SSaurabh.Mishra@Sun.COM static int
atge_resume(dev_info_t * dip)134010393SSaurabh.Mishra@Sun.COM atge_resume(dev_info_t *dip)
134110393SSaurabh.Mishra@Sun.COM {
134210393SSaurabh.Mishra@Sun.COM atge_t *atgep;
134310393SSaurabh.Mishra@Sun.COM
134410393SSaurabh.Mishra@Sun.COM if ((atgep = ddi_get_driver_private(dip)) == NULL) {
134510393SSaurabh.Mishra@Sun.COM return (DDI_FAILURE);
134610393SSaurabh.Mishra@Sun.COM }
134710393SSaurabh.Mishra@Sun.COM
134810393SSaurabh.Mishra@Sun.COM mutex_enter(&atgep->atge_intr_lock);
134910393SSaurabh.Mishra@Sun.COM mutex_enter(&atgep->atge_tx_lock);
135010393SSaurabh.Mishra@Sun.COM
135110393SSaurabh.Mishra@Sun.COM atgep->atge_chip_state &= ~ATGE_CHIP_SUSPENDED;
135210393SSaurabh.Mishra@Sun.COM
135310393SSaurabh.Mishra@Sun.COM if (atgep->atge_chip_state & ATGE_CHIP_RUNNING) {
135410393SSaurabh.Mishra@Sun.COM atge_device_restart(atgep);
135510393SSaurabh.Mishra@Sun.COM } else {
135610393SSaurabh.Mishra@Sun.COM atge_device_reset(atgep);
135710393SSaurabh.Mishra@Sun.COM }
135810393SSaurabh.Mishra@Sun.COM
135910393SSaurabh.Mishra@Sun.COM mutex_exit(&atgep->atge_tx_lock);
136010393SSaurabh.Mishra@Sun.COM mutex_exit(&atgep->atge_intr_lock);
136110393SSaurabh.Mishra@Sun.COM
136210393SSaurabh.Mishra@Sun.COM /*
136310393SSaurabh.Mishra@Sun.COM * Reset the PHY before resuming MII.
136410393SSaurabh.Mishra@Sun.COM */
136510393SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
136610393SSaurabh.Mishra@Sun.COM atge_l1e_mii_reset(atgep);
136710393SSaurabh.Mishra@Sun.COM }
136810393SSaurabh.Mishra@Sun.COM
136910393SSaurabh.Mishra@Sun.COM mii_resume(atgep->atge_mii);
137010393SSaurabh.Mishra@Sun.COM
137110393SSaurabh.Mishra@Sun.COM /* kick-off downstream */
137210393SSaurabh.Mishra@Sun.COM mac_tx_update(atgep->atge_mh);
137310393SSaurabh.Mishra@Sun.COM
137410393SSaurabh.Mishra@Sun.COM return (DDI_SUCCESS);
137510393SSaurabh.Mishra@Sun.COM }
137610393SSaurabh.Mishra@Sun.COM
137710393SSaurabh.Mishra@Sun.COM static int
atge_quiesce(dev_info_t * dip)137810393SSaurabh.Mishra@Sun.COM atge_quiesce(dev_info_t *dip)
137910393SSaurabh.Mishra@Sun.COM {
138010393SSaurabh.Mishra@Sun.COM atge_t *atgep;
138110393SSaurabh.Mishra@Sun.COM
138210393SSaurabh.Mishra@Sun.COM if ((atgep = ddi_get_driver_private(dip)) == NULL) {
138310393SSaurabh.Mishra@Sun.COM return (DDI_FAILURE);
138410393SSaurabh.Mishra@Sun.COM }
138510393SSaurabh.Mishra@Sun.COM
138610393SSaurabh.Mishra@Sun.COM atge_device_stop(atgep);
138710393SSaurabh.Mishra@Sun.COM
138810393SSaurabh.Mishra@Sun.COM return (DDI_SUCCESS);
138910393SSaurabh.Mishra@Sun.COM }
139010393SSaurabh.Mishra@Sun.COM
139110393SSaurabh.Mishra@Sun.COM void
atge_add_multicst(atge_t * atgep,uint8_t * macaddr)139210393SSaurabh.Mishra@Sun.COM atge_add_multicst(atge_t *atgep, uint8_t *macaddr)
139310393SSaurabh.Mishra@Sun.COM {
139410393SSaurabh.Mishra@Sun.COM uint32_t crc;
139510393SSaurabh.Mishra@Sun.COM int bit;
139610393SSaurabh.Mishra@Sun.COM
139710393SSaurabh.Mishra@Sun.COM ASSERT(MUTEX_HELD(&atgep->atge_intr_lock));
139810393SSaurabh.Mishra@Sun.COM ASSERT(MUTEX_HELD(&atgep->atge_tx_lock));
139910393SSaurabh.Mishra@Sun.COM
140010393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s() %x:%x:%x:%x:%x:%x",
140110393SSaurabh.Mishra@Sun.COM atgep->atge_name, __func__, macaddr[0], macaddr[1], macaddr[2],
140210393SSaurabh.Mishra@Sun.COM macaddr[3], macaddr[4], macaddr[5]));
140310393SSaurabh.Mishra@Sun.COM
140410393SSaurabh.Mishra@Sun.COM crc = atge_ether_crc(macaddr, ETHERADDRL);
140510393SSaurabh.Mishra@Sun.COM bit = (crc >> 26);
140610393SSaurabh.Mishra@Sun.COM atgep->atge_mchash_ref_cnt[bit]++;
140710393SSaurabh.Mishra@Sun.COM atgep->atge_mchash |= (1ULL << (crc >> 26));
140810393SSaurabh.Mishra@Sun.COM
140910393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s() mchash :%llx, bit : %d,"
141010393SSaurabh.Mishra@Sun.COM " atge_mchash_ref_cnt[bit] :%d",
141110393SSaurabh.Mishra@Sun.COM atgep->atge_name, __func__, atgep->atge_mchash, bit,
141210393SSaurabh.Mishra@Sun.COM atgep->atge_mchash_ref_cnt[bit]));
141310393SSaurabh.Mishra@Sun.COM }
141410393SSaurabh.Mishra@Sun.COM
141510393SSaurabh.Mishra@Sun.COM void
atge_remove_multicst(atge_t * atgep,uint8_t * macaddr)141610393SSaurabh.Mishra@Sun.COM atge_remove_multicst(atge_t *atgep, uint8_t *macaddr)
141710393SSaurabh.Mishra@Sun.COM {
141810393SSaurabh.Mishra@Sun.COM uint32_t crc;
141910393SSaurabh.Mishra@Sun.COM int bit;
142010393SSaurabh.Mishra@Sun.COM
142110393SSaurabh.Mishra@Sun.COM ASSERT(MUTEX_HELD(&atgep->atge_intr_lock));
142210393SSaurabh.Mishra@Sun.COM ASSERT(MUTEX_HELD(&atgep->atge_tx_lock));
142310393SSaurabh.Mishra@Sun.COM
142410393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s() %x:%x:%x:%x:%x:%x",
142510393SSaurabh.Mishra@Sun.COM atgep->atge_name, __func__, macaddr[0], macaddr[1], macaddr[2],
142610393SSaurabh.Mishra@Sun.COM macaddr[3], macaddr[4], macaddr[5]));
142710393SSaurabh.Mishra@Sun.COM
142810393SSaurabh.Mishra@Sun.COM crc = atge_ether_crc(macaddr, ETHERADDRL);
142910393SSaurabh.Mishra@Sun.COM bit = (crc >> 26);
143010393SSaurabh.Mishra@Sun.COM atgep->atge_mchash_ref_cnt[bit]--;
143110393SSaurabh.Mishra@Sun.COM if (atgep->atge_mchash_ref_cnt[bit] == 0)
143210393SSaurabh.Mishra@Sun.COM atgep->atge_mchash &= ~(1ULL << (crc >> 26));
143310393SSaurabh.Mishra@Sun.COM
143410393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s() mchash :%llx, bit : %d,"
143510393SSaurabh.Mishra@Sun.COM " atge_mchash_ref_cnt[bit] :%d",
143610393SSaurabh.Mishra@Sun.COM atgep->atge_name, __func__, atgep->atge_mchash, bit,
143710393SSaurabh.Mishra@Sun.COM atgep->atge_mchash_ref_cnt[bit]));
143810393SSaurabh.Mishra@Sun.COM }
143910393SSaurabh.Mishra@Sun.COM
144010393SSaurabh.Mishra@Sun.COM int
atge_m_multicst(void * arg,boolean_t add,const uint8_t * macaddr)144110393SSaurabh.Mishra@Sun.COM atge_m_multicst(void *arg, boolean_t add, const uint8_t *macaddr)
144210393SSaurabh.Mishra@Sun.COM {
144310393SSaurabh.Mishra@Sun.COM atge_t *atgep = arg;
144410393SSaurabh.Mishra@Sun.COM
144510393SSaurabh.Mishra@Sun.COM mutex_enter(&atgep->atge_intr_lock);
144610393SSaurabh.Mishra@Sun.COM mutex_enter(&atgep->atge_tx_lock);
144710393SSaurabh.Mishra@Sun.COM
144810393SSaurabh.Mishra@Sun.COM if (add) {
144910393SSaurabh.Mishra@Sun.COM atge_add_multicst(atgep, (uint8_t *)macaddr);
145010393SSaurabh.Mishra@Sun.COM } else {
145110393SSaurabh.Mishra@Sun.COM atge_remove_multicst(atgep, (uint8_t *)macaddr);
145210393SSaurabh.Mishra@Sun.COM }
145310393SSaurabh.Mishra@Sun.COM
145410393SSaurabh.Mishra@Sun.COM atge_rxfilter(atgep);
145510393SSaurabh.Mishra@Sun.COM
145610393SSaurabh.Mishra@Sun.COM mutex_exit(&atgep->atge_tx_lock);
145710393SSaurabh.Mishra@Sun.COM mutex_exit(&atgep->atge_intr_lock);
145810393SSaurabh.Mishra@Sun.COM
145910393SSaurabh.Mishra@Sun.COM return (0);
146010393SSaurabh.Mishra@Sun.COM }
146110393SSaurabh.Mishra@Sun.COM
146210393SSaurabh.Mishra@Sun.COM int
atge_m_promisc(void * arg,boolean_t on)146310393SSaurabh.Mishra@Sun.COM atge_m_promisc(void *arg, boolean_t on)
146410393SSaurabh.Mishra@Sun.COM {
146510393SSaurabh.Mishra@Sun.COM atge_t *atgep = arg;
146610393SSaurabh.Mishra@Sun.COM
146710393SSaurabh.Mishra@Sun.COM mutex_enter(&atgep->atge_intr_lock);
146810393SSaurabh.Mishra@Sun.COM mutex_enter(&atgep->atge_tx_lock);
146910393SSaurabh.Mishra@Sun.COM
147010393SSaurabh.Mishra@Sun.COM if (on) {
147110393SSaurabh.Mishra@Sun.COM atgep->atge_filter_flags |= ATGE_PROMISC;
147210393SSaurabh.Mishra@Sun.COM } else {
147310393SSaurabh.Mishra@Sun.COM atgep->atge_filter_flags &= ~ATGE_PROMISC;
147410393SSaurabh.Mishra@Sun.COM }
147510393SSaurabh.Mishra@Sun.COM
147610393SSaurabh.Mishra@Sun.COM if (atgep->atge_chip_state & ATGE_CHIP_RUNNING) {
147710393SSaurabh.Mishra@Sun.COM atge_rxfilter(atgep);
147810393SSaurabh.Mishra@Sun.COM }
147910393SSaurabh.Mishra@Sun.COM
148010393SSaurabh.Mishra@Sun.COM mutex_exit(&atgep->atge_tx_lock);
148110393SSaurabh.Mishra@Sun.COM mutex_exit(&atgep->atge_intr_lock);
148210393SSaurabh.Mishra@Sun.COM
148310393SSaurabh.Mishra@Sun.COM return (0);
148410393SSaurabh.Mishra@Sun.COM }
148510393SSaurabh.Mishra@Sun.COM
148610393SSaurabh.Mishra@Sun.COM int
atge_m_unicst(void * arg,const uint8_t * macaddr)148710393SSaurabh.Mishra@Sun.COM atge_m_unicst(void *arg, const uint8_t *macaddr)
148810393SSaurabh.Mishra@Sun.COM {
148910393SSaurabh.Mishra@Sun.COM atge_t *atgep = arg;
149010393SSaurabh.Mishra@Sun.COM
149110393SSaurabh.Mishra@Sun.COM mutex_enter(&atgep->atge_intr_lock);
149210393SSaurabh.Mishra@Sun.COM mutex_enter(&atgep->atge_tx_lock);
149310393SSaurabh.Mishra@Sun.COM bcopy(macaddr, atgep->atge_ether_addr, ETHERADDRL);
149410393SSaurabh.Mishra@Sun.COM atge_program_ether(atgep);
149510393SSaurabh.Mishra@Sun.COM atge_rxfilter(atgep);
149610393SSaurabh.Mishra@Sun.COM mutex_exit(&atgep->atge_tx_lock);
149710393SSaurabh.Mishra@Sun.COM mutex_exit(&atgep->atge_intr_lock);
149810393SSaurabh.Mishra@Sun.COM
149910393SSaurabh.Mishra@Sun.COM return (0);
150010393SSaurabh.Mishra@Sun.COM }
150110393SSaurabh.Mishra@Sun.COM
150210393SSaurabh.Mishra@Sun.COM mblk_t *
atge_m_tx(void * arg,mblk_t * mp)150310393SSaurabh.Mishra@Sun.COM atge_m_tx(void *arg, mblk_t *mp)
150410393SSaurabh.Mishra@Sun.COM {
150510393SSaurabh.Mishra@Sun.COM atge_t *atgep = arg;
150610393SSaurabh.Mishra@Sun.COM mblk_t *nmp;
150710393SSaurabh.Mishra@Sun.COM
150810393SSaurabh.Mishra@Sun.COM mutex_enter(&atgep->atge_tx_lock);
150910393SSaurabh.Mishra@Sun.COM
151010393SSaurabh.Mishra@Sun.COM /*
151110393SSaurabh.Mishra@Sun.COM * This NIC does not like us to send pkt when link is down.
151210393SSaurabh.Mishra@Sun.COM */
151310393SSaurabh.Mishra@Sun.COM if (!(atgep->atge_link_state & LINK_STATE_UP)) {
151410393SSaurabh.Mishra@Sun.COM atgep->atge_tx_resched = 1;
151511353SSaurabh.Mishra@Sun.COM
151610393SSaurabh.Mishra@Sun.COM mutex_exit(&atgep->atge_tx_lock);
151710393SSaurabh.Mishra@Sun.COM return (mp);
151810393SSaurabh.Mishra@Sun.COM }
151910393SSaurabh.Mishra@Sun.COM
152010393SSaurabh.Mishra@Sun.COM /*
152110393SSaurabh.Mishra@Sun.COM * Don't send a pkt if chip isn't running or in suspended state.
152210393SSaurabh.Mishra@Sun.COM */
152310393SSaurabh.Mishra@Sun.COM if ((atgep->atge_chip_state & ATGE_CHIP_RUNNING) == 0 ||
152410393SSaurabh.Mishra@Sun.COM atgep->atge_chip_state & ATGE_CHIP_SUSPENDED) {
152510393SSaurabh.Mishra@Sun.COM atgep->atge_carrier_errors++;
152610393SSaurabh.Mishra@Sun.COM atgep->atge_tx_resched = 1;
152711353SSaurabh.Mishra@Sun.COM
152810393SSaurabh.Mishra@Sun.COM mutex_exit(&atgep->atge_tx_lock);
152910393SSaurabh.Mishra@Sun.COM return (mp);
153010393SSaurabh.Mishra@Sun.COM }
153110393SSaurabh.Mishra@Sun.COM
153210393SSaurabh.Mishra@Sun.COM while (mp != NULL) {
153310393SSaurabh.Mishra@Sun.COM nmp = mp->b_next;
153410393SSaurabh.Mishra@Sun.COM mp->b_next = NULL;
153510393SSaurabh.Mishra@Sun.COM
153611353SSaurabh.Mishra@Sun.COM if (atge_send_a_packet(atgep, mp) == DDI_FAILURE) {
153710393SSaurabh.Mishra@Sun.COM mp->b_next = nmp;
153810393SSaurabh.Mishra@Sun.COM break;
153910393SSaurabh.Mishra@Sun.COM }
154010393SSaurabh.Mishra@Sun.COM
154110393SSaurabh.Mishra@Sun.COM mp = nmp;
154210393SSaurabh.Mishra@Sun.COM }
154310393SSaurabh.Mishra@Sun.COM
154410393SSaurabh.Mishra@Sun.COM mutex_exit(&atgep->atge_tx_lock);
154510393SSaurabh.Mishra@Sun.COM return (mp);
154610393SSaurabh.Mishra@Sun.COM }
154710393SSaurabh.Mishra@Sun.COM
154810393SSaurabh.Mishra@Sun.COM int
atge_m_start(void * arg)154910393SSaurabh.Mishra@Sun.COM atge_m_start(void *arg)
155010393SSaurabh.Mishra@Sun.COM {
155110393SSaurabh.Mishra@Sun.COM atge_t *atgep = arg;
155210393SSaurabh.Mishra@Sun.COM int started = 0;
155310393SSaurabh.Mishra@Sun.COM
155410393SSaurabh.Mishra@Sun.COM ASSERT(atgep != NULL);
155510393SSaurabh.Mishra@Sun.COM
155610393SSaurabh.Mishra@Sun.COM
155710393SSaurabh.Mishra@Sun.COM mii_stop(atgep->atge_mii);
155810393SSaurabh.Mishra@Sun.COM
155910393SSaurabh.Mishra@Sun.COM mutex_enter(&atgep->atge_intr_lock);
156010393SSaurabh.Mishra@Sun.COM mutex_enter(&atgep->atge_tx_lock);
156110393SSaurabh.Mishra@Sun.COM
156210393SSaurabh.Mishra@Sun.COM if (!(atgep->atge_chip_state & ATGE_CHIP_SUSPENDED)) {
156310393SSaurabh.Mishra@Sun.COM atge_device_restart(atgep);
156410393SSaurabh.Mishra@Sun.COM started = 1;
156510393SSaurabh.Mishra@Sun.COM }
156610393SSaurabh.Mishra@Sun.COM
156710393SSaurabh.Mishra@Sun.COM mutex_exit(&atgep->atge_tx_lock);
156810393SSaurabh.Mishra@Sun.COM mutex_exit(&atgep->atge_intr_lock);
156910393SSaurabh.Mishra@Sun.COM
157010393SSaurabh.Mishra@Sun.COM mii_start(atgep->atge_mii);
157110393SSaurabh.Mishra@Sun.COM
157210393SSaurabh.Mishra@Sun.COM /* kick-off downstream */
157310393SSaurabh.Mishra@Sun.COM if (started)
157410393SSaurabh.Mishra@Sun.COM mac_tx_update(atgep->atge_mh);
157510393SSaurabh.Mishra@Sun.COM
157610393SSaurabh.Mishra@Sun.COM return (0);
157710393SSaurabh.Mishra@Sun.COM }
157810393SSaurabh.Mishra@Sun.COM
157910393SSaurabh.Mishra@Sun.COM void
atge_m_stop(void * arg)158010393SSaurabh.Mishra@Sun.COM atge_m_stop(void *arg)
158110393SSaurabh.Mishra@Sun.COM {
158210393SSaurabh.Mishra@Sun.COM atge_t *atgep = arg;
158310393SSaurabh.Mishra@Sun.COM
158410393SSaurabh.Mishra@Sun.COM mii_stop(atgep->atge_mii);
158510393SSaurabh.Mishra@Sun.COM
158610393SSaurabh.Mishra@Sun.COM /*
158710393SSaurabh.Mishra@Sun.COM * Cancel any pending I/O.
158810393SSaurabh.Mishra@Sun.COM */
158910393SSaurabh.Mishra@Sun.COM mutex_enter(&atgep->atge_intr_lock);
159010393SSaurabh.Mishra@Sun.COM atgep->atge_chip_state &= ~ATGE_CHIP_RUNNING;
159110393SSaurabh.Mishra@Sun.COM if (!(atgep->atge_chip_state & ATGE_CHIP_SUSPENDED))
159210393SSaurabh.Mishra@Sun.COM atge_device_stop(atgep);
159310393SSaurabh.Mishra@Sun.COM mutex_exit(&atgep->atge_intr_lock);
159410393SSaurabh.Mishra@Sun.COM }
159510393SSaurabh.Mishra@Sun.COM
159610393SSaurabh.Mishra@Sun.COM int
atge_m_stat(void * arg,uint_t stat,uint64_t * val)159710393SSaurabh.Mishra@Sun.COM atge_m_stat(void *arg, uint_t stat, uint64_t *val)
159810393SSaurabh.Mishra@Sun.COM {
159910393SSaurabh.Mishra@Sun.COM atge_t *atgep = arg;
160010393SSaurabh.Mishra@Sun.COM
160110393SSaurabh.Mishra@Sun.COM if (mii_m_getstat(atgep->atge_mii, stat, val) == 0) {
160210393SSaurabh.Mishra@Sun.COM return (0);
160310393SSaurabh.Mishra@Sun.COM }
160410393SSaurabh.Mishra@Sun.COM
160510393SSaurabh.Mishra@Sun.COM switch (stat) {
160610393SSaurabh.Mishra@Sun.COM case MAC_STAT_MULTIRCV:
160710393SSaurabh.Mishra@Sun.COM *val = atgep->atge_multircv;
160810393SSaurabh.Mishra@Sun.COM break;
160910393SSaurabh.Mishra@Sun.COM
161010393SSaurabh.Mishra@Sun.COM case MAC_STAT_BRDCSTRCV:
161110393SSaurabh.Mishra@Sun.COM *val = atgep->atge_brdcstrcv;
161210393SSaurabh.Mishra@Sun.COM break;
161310393SSaurabh.Mishra@Sun.COM
161410393SSaurabh.Mishra@Sun.COM case MAC_STAT_MULTIXMT:
161510393SSaurabh.Mishra@Sun.COM *val = atgep->atge_multixmt;
161610393SSaurabh.Mishra@Sun.COM break;
161710393SSaurabh.Mishra@Sun.COM
161810393SSaurabh.Mishra@Sun.COM case MAC_STAT_BRDCSTXMT:
161910393SSaurabh.Mishra@Sun.COM *val = atgep->atge_brdcstxmt;
162010393SSaurabh.Mishra@Sun.COM break;
162110393SSaurabh.Mishra@Sun.COM
162210393SSaurabh.Mishra@Sun.COM case MAC_STAT_IPACKETS:
162310393SSaurabh.Mishra@Sun.COM *val = atgep->atge_ipackets;
162410393SSaurabh.Mishra@Sun.COM break;
162510393SSaurabh.Mishra@Sun.COM
162610393SSaurabh.Mishra@Sun.COM case MAC_STAT_RBYTES:
162710393SSaurabh.Mishra@Sun.COM *val = atgep->atge_rbytes;
162810393SSaurabh.Mishra@Sun.COM break;
162910393SSaurabh.Mishra@Sun.COM
163010393SSaurabh.Mishra@Sun.COM case MAC_STAT_OPACKETS:
163110393SSaurabh.Mishra@Sun.COM *val = atgep->atge_opackets;
163210393SSaurabh.Mishra@Sun.COM break;
163310393SSaurabh.Mishra@Sun.COM
163410393SSaurabh.Mishra@Sun.COM case MAC_STAT_OBYTES:
163510393SSaurabh.Mishra@Sun.COM *val = atgep->atge_obytes;
163610393SSaurabh.Mishra@Sun.COM break;
163710393SSaurabh.Mishra@Sun.COM
163810393SSaurabh.Mishra@Sun.COM case MAC_STAT_NORCVBUF:
163910393SSaurabh.Mishra@Sun.COM *val = atgep->atge_norcvbuf;
164010393SSaurabh.Mishra@Sun.COM break;
164110393SSaurabh.Mishra@Sun.COM
164210393SSaurabh.Mishra@Sun.COM case MAC_STAT_NOXMTBUF:
164310393SSaurabh.Mishra@Sun.COM *val = 0;
164410393SSaurabh.Mishra@Sun.COM break;
164510393SSaurabh.Mishra@Sun.COM
164610393SSaurabh.Mishra@Sun.COM case MAC_STAT_COLLISIONS:
164710393SSaurabh.Mishra@Sun.COM *val = atgep->atge_collisions;
164810393SSaurabh.Mishra@Sun.COM break;
164910393SSaurabh.Mishra@Sun.COM
165010393SSaurabh.Mishra@Sun.COM case MAC_STAT_IERRORS:
165110393SSaurabh.Mishra@Sun.COM *val = atgep->atge_errrcv;
165210393SSaurabh.Mishra@Sun.COM break;
165310393SSaurabh.Mishra@Sun.COM
165410393SSaurabh.Mishra@Sun.COM case MAC_STAT_OERRORS:
165510393SSaurabh.Mishra@Sun.COM *val = atgep->atge_errxmt;
165610393SSaurabh.Mishra@Sun.COM break;
165710393SSaurabh.Mishra@Sun.COM
165810393SSaurabh.Mishra@Sun.COM case ETHER_STAT_ALIGN_ERRORS:
165910393SSaurabh.Mishra@Sun.COM *val = atgep->atge_align_errors;
166010393SSaurabh.Mishra@Sun.COM break;
166110393SSaurabh.Mishra@Sun.COM
166210393SSaurabh.Mishra@Sun.COM case ETHER_STAT_FCS_ERRORS:
166310393SSaurabh.Mishra@Sun.COM *val = atgep->atge_fcs_errors;
166410393SSaurabh.Mishra@Sun.COM break;
166510393SSaurabh.Mishra@Sun.COM
166610393SSaurabh.Mishra@Sun.COM case ETHER_STAT_SQE_ERRORS:
166710393SSaurabh.Mishra@Sun.COM *val = atgep->atge_sqe_errors;
166810393SSaurabh.Mishra@Sun.COM break;
166910393SSaurabh.Mishra@Sun.COM
167010393SSaurabh.Mishra@Sun.COM case ETHER_STAT_DEFER_XMTS:
167110393SSaurabh.Mishra@Sun.COM *val = atgep->atge_defer_xmts;
167210393SSaurabh.Mishra@Sun.COM break;
167310393SSaurabh.Mishra@Sun.COM
167410393SSaurabh.Mishra@Sun.COM case ETHER_STAT_FIRST_COLLISIONS:
167510393SSaurabh.Mishra@Sun.COM *val = atgep->atge_first_collisions;
167610393SSaurabh.Mishra@Sun.COM break;
167710393SSaurabh.Mishra@Sun.COM
167810393SSaurabh.Mishra@Sun.COM case ETHER_STAT_MULTI_COLLISIONS:
167910393SSaurabh.Mishra@Sun.COM *val = atgep->atge_multi_collisions;
168010393SSaurabh.Mishra@Sun.COM break;
168110393SSaurabh.Mishra@Sun.COM
168210393SSaurabh.Mishra@Sun.COM case ETHER_STAT_TX_LATE_COLLISIONS:
168310393SSaurabh.Mishra@Sun.COM *val = atgep->atge_tx_late_collisions;
168410393SSaurabh.Mishra@Sun.COM break;
168510393SSaurabh.Mishra@Sun.COM
168610393SSaurabh.Mishra@Sun.COM case ETHER_STAT_EX_COLLISIONS:
168710393SSaurabh.Mishra@Sun.COM *val = atgep->atge_ex_collisions;
168810393SSaurabh.Mishra@Sun.COM break;
168910393SSaurabh.Mishra@Sun.COM
169010393SSaurabh.Mishra@Sun.COM case ETHER_STAT_MACXMT_ERRORS:
169110393SSaurabh.Mishra@Sun.COM *val = atgep->atge_macxmt_errors;
169210393SSaurabh.Mishra@Sun.COM break;
169310393SSaurabh.Mishra@Sun.COM
169410393SSaurabh.Mishra@Sun.COM case ETHER_STAT_CARRIER_ERRORS:
169510393SSaurabh.Mishra@Sun.COM *val = atgep->atge_carrier_errors;
169610393SSaurabh.Mishra@Sun.COM break;
169710393SSaurabh.Mishra@Sun.COM
169810393SSaurabh.Mishra@Sun.COM case ETHER_STAT_TOOLONG_ERRORS:
169910393SSaurabh.Mishra@Sun.COM *val = atgep->atge_toolong_errors;
170010393SSaurabh.Mishra@Sun.COM break;
170110393SSaurabh.Mishra@Sun.COM
170210393SSaurabh.Mishra@Sun.COM case ETHER_STAT_MACRCV_ERRORS:
170310393SSaurabh.Mishra@Sun.COM *val = atgep->atge_macrcv_errors;
170410393SSaurabh.Mishra@Sun.COM break;
170510393SSaurabh.Mishra@Sun.COM
170610393SSaurabh.Mishra@Sun.COM case MAC_STAT_OVERFLOWS:
170710393SSaurabh.Mishra@Sun.COM *val = atgep->atge_overflow;
170810393SSaurabh.Mishra@Sun.COM break;
170910393SSaurabh.Mishra@Sun.COM
171010393SSaurabh.Mishra@Sun.COM case MAC_STAT_UNDERFLOWS:
171110393SSaurabh.Mishra@Sun.COM *val = atgep->atge_underflow;
171210393SSaurabh.Mishra@Sun.COM break;
171310393SSaurabh.Mishra@Sun.COM
171410393SSaurabh.Mishra@Sun.COM case ETHER_STAT_TOOSHORT_ERRORS:
171510393SSaurabh.Mishra@Sun.COM *val = atgep->atge_runt;
171610393SSaurabh.Mishra@Sun.COM break;
171710393SSaurabh.Mishra@Sun.COM
171810393SSaurabh.Mishra@Sun.COM case ETHER_STAT_JABBER_ERRORS:
171910393SSaurabh.Mishra@Sun.COM *val = atgep->atge_jabber;
172010393SSaurabh.Mishra@Sun.COM break;
172110393SSaurabh.Mishra@Sun.COM
172210393SSaurabh.Mishra@Sun.COM default:
172310393SSaurabh.Mishra@Sun.COM return (ENOTSUP);
172410393SSaurabh.Mishra@Sun.COM }
172510393SSaurabh.Mishra@Sun.COM
172610393SSaurabh.Mishra@Sun.COM return (0);
172710393SSaurabh.Mishra@Sun.COM }
172810393SSaurabh.Mishra@Sun.COM
172910393SSaurabh.Mishra@Sun.COM int
atge_m_getprop(void * arg,const char * name,mac_prop_id_t num,uint_t sz,void * val)173011878SVenu.Iyer@Sun.COM atge_m_getprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz,
173111878SVenu.Iyer@Sun.COM void *val)
173210393SSaurabh.Mishra@Sun.COM {
173310393SSaurabh.Mishra@Sun.COM atge_t *atgep = arg;
173410393SSaurabh.Mishra@Sun.COM
173511878SVenu.Iyer@Sun.COM return (mii_m_getprop(atgep->atge_mii, name, num, sz, val));
173610393SSaurabh.Mishra@Sun.COM }
173710393SSaurabh.Mishra@Sun.COM
173810393SSaurabh.Mishra@Sun.COM int
atge_m_setprop(void * arg,const char * name,mac_prop_id_t num,uint_t sz,const void * val)173910393SSaurabh.Mishra@Sun.COM atge_m_setprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz,
174010393SSaurabh.Mishra@Sun.COM const void *val)
174110393SSaurabh.Mishra@Sun.COM {
174210393SSaurabh.Mishra@Sun.COM atge_t *atgep = arg;
174311353SSaurabh.Mishra@Sun.COM int r;
174411353SSaurabh.Mishra@Sun.COM
174511353SSaurabh.Mishra@Sun.COM r = mii_m_setprop(atgep->atge_mii, name, num, sz, val);
174611353SSaurabh.Mishra@Sun.COM
174711353SSaurabh.Mishra@Sun.COM if (r == 0) {
174811353SSaurabh.Mishra@Sun.COM mutex_enter(&atgep->atge_intr_lock);
174911353SSaurabh.Mishra@Sun.COM mutex_enter(&atgep->atge_tx_lock);
175011353SSaurabh.Mishra@Sun.COM
175111353SSaurabh.Mishra@Sun.COM if (atgep->atge_chip_state & ATGE_CHIP_RUNNING) {
175211353SSaurabh.Mishra@Sun.COM atge_device_restart(atgep);
175311353SSaurabh.Mishra@Sun.COM }
175411353SSaurabh.Mishra@Sun.COM
175511353SSaurabh.Mishra@Sun.COM mutex_exit(&atgep->atge_tx_lock);
175611353SSaurabh.Mishra@Sun.COM mutex_exit(&atgep->atge_intr_lock);
175711353SSaurabh.Mishra@Sun.COM }
175811353SSaurabh.Mishra@Sun.COM
175911353SSaurabh.Mishra@Sun.COM return (r);
176010393SSaurabh.Mishra@Sun.COM }
176110393SSaurabh.Mishra@Sun.COM
176211878SVenu.Iyer@Sun.COM static void
atge_m_propinfo(void * arg,const char * name,mac_prop_id_t num,mac_prop_info_handle_t prh)176311878SVenu.Iyer@Sun.COM atge_m_propinfo(void *arg, const char *name, mac_prop_id_t num,
176411878SVenu.Iyer@Sun.COM mac_prop_info_handle_t prh)
176511878SVenu.Iyer@Sun.COM {
176611878SVenu.Iyer@Sun.COM atge_t *atgep = arg;
176711878SVenu.Iyer@Sun.COM
176811878SVenu.Iyer@Sun.COM mii_m_propinfo(atgep->atge_mii, name, num, prh);
176911878SVenu.Iyer@Sun.COM }
177010393SSaurabh.Mishra@Sun.COM
177110393SSaurabh.Mishra@Sun.COM void
atge_program_ether(atge_t * atgep)177210393SSaurabh.Mishra@Sun.COM atge_program_ether(atge_t *atgep)
177310393SSaurabh.Mishra@Sun.COM {
177410393SSaurabh.Mishra@Sun.COM ether_addr_t e;
177510393SSaurabh.Mishra@Sun.COM
177610393SSaurabh.Mishra@Sun.COM /*
177710393SSaurabh.Mishra@Sun.COM * Reprogram the Station address.
177810393SSaurabh.Mishra@Sun.COM */
177910393SSaurabh.Mishra@Sun.COM bcopy(atgep->atge_ether_addr, e, ETHERADDRL);
178010393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_PAR0,
178110393SSaurabh.Mishra@Sun.COM ((e[2] << 24) | (e[3] << 16) | (e[4] << 8) | e[5]));
178210393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_PAR1, (e[0] << 8) | e[1]);
178310393SSaurabh.Mishra@Sun.COM }
178410393SSaurabh.Mishra@Sun.COM
178510393SSaurabh.Mishra@Sun.COM /*
178610393SSaurabh.Mishra@Sun.COM * Device specific operations.
178710393SSaurabh.Mishra@Sun.COM */
178810393SSaurabh.Mishra@Sun.COM void
atge_device_start(atge_t * atgep)178910393SSaurabh.Mishra@Sun.COM atge_device_start(atge_t *atgep)
179010393SSaurabh.Mishra@Sun.COM {
179111353SSaurabh.Mishra@Sun.COM uint32_t rxf_hi, rxf_lo, rrd_hi, rrd_lo;
179210393SSaurabh.Mishra@Sun.COM uint32_t reg;
179310393SSaurabh.Mishra@Sun.COM uint32_t fsize;
179410393SSaurabh.Mishra@Sun.COM
179510393SSaurabh.Mishra@Sun.COM /*
179610393SSaurabh.Mishra@Sun.COM * Reprogram the Station address.
179710393SSaurabh.Mishra@Sun.COM */
179810393SSaurabh.Mishra@Sun.COM atge_program_ether(atgep);
179910393SSaurabh.Mishra@Sun.COM
180010393SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
180110393SSaurabh.Mishra@Sun.COM atge_l1e_program_dma(atgep);
180211353SSaurabh.Mishra@Sun.COM } else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
180311353SSaurabh.Mishra@Sun.COM atge_l1_program_dma(atgep);
180410393SSaurabh.Mishra@Sun.COM }
180510393SSaurabh.Mishra@Sun.COM
180610393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s() dma, counters programmed ", atgep->atge_name,
180710393SSaurabh.Mishra@Sun.COM __func__));
180810393SSaurabh.Mishra@Sun.COM
180910393SSaurabh.Mishra@Sun.COM OUTW(atgep, ATGE_INTR_CLR_TIMER, 1*1000/2);
181010393SSaurabh.Mishra@Sun.COM
181110393SSaurabh.Mishra@Sun.COM /*
181211353SSaurabh.Mishra@Sun.COM * Set Maximum frame size but don't let MTU be less than ETHER_MTU.
181310393SSaurabh.Mishra@Sun.COM */
181410393SSaurabh.Mishra@Sun.COM if (atgep->atge_mtu < ETHERMTU)
181510393SSaurabh.Mishra@Sun.COM atgep->atge_max_frame_size = ETHERMTU;
181610393SSaurabh.Mishra@Sun.COM else
181710393SSaurabh.Mishra@Sun.COM atgep->atge_max_frame_size = atgep->atge_mtu;
181810393SSaurabh.Mishra@Sun.COM
181910393SSaurabh.Mishra@Sun.COM atgep->atge_max_frame_size += sizeof (struct ether_header) +
182010393SSaurabh.Mishra@Sun.COM VLAN_TAGSZ + ETHERFCSL;
182110393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_FRAME_SIZE, atgep->atge_max_frame_size);
182210393SSaurabh.Mishra@Sun.COM
182310393SSaurabh.Mishra@Sun.COM
182410393SSaurabh.Mishra@Sun.COM /*
182510393SSaurabh.Mishra@Sun.COM * Configure IPG/IFG parameters.
182610393SSaurabh.Mishra@Sun.COM */
182710393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_IPG_IFG_CFG,
182810393SSaurabh.Mishra@Sun.COM ((IPG_IFG_IPG2_DEFAULT << IPG_IFG_IPG2_SHIFT) & IPG_IFG_IPG2_MASK) |
182910393SSaurabh.Mishra@Sun.COM ((IPG_IFG_IPG1_DEFAULT << IPG_IFG_IPG1_SHIFT) & IPG_IFG_IPG1_MASK) |
183010393SSaurabh.Mishra@Sun.COM ((IPG_IFG_MIFG_DEFAULT << IPG_IFG_MIFG_SHIFT) & IPG_IFG_MIFG_MASK) |
183110393SSaurabh.Mishra@Sun.COM ((IPG_IFG_IPGT_DEFAULT << IPG_IFG_IPGT_SHIFT) & IPG_IFG_IPGT_MASK));
183210393SSaurabh.Mishra@Sun.COM
183310393SSaurabh.Mishra@Sun.COM /*
183410393SSaurabh.Mishra@Sun.COM * Set parameters for half-duplex media.
183510393SSaurabh.Mishra@Sun.COM */
183610393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_HDPX_CFG,
183710393SSaurabh.Mishra@Sun.COM ((HDPX_CFG_LCOL_DEFAULT << HDPX_CFG_LCOL_SHIFT) &
183810393SSaurabh.Mishra@Sun.COM HDPX_CFG_LCOL_MASK) |
183910393SSaurabh.Mishra@Sun.COM ((HDPX_CFG_RETRY_DEFAULT << HDPX_CFG_RETRY_SHIFT) &
184010393SSaurabh.Mishra@Sun.COM HDPX_CFG_RETRY_MASK) | HDPX_CFG_EXC_DEF_EN |
184110393SSaurabh.Mishra@Sun.COM ((HDPX_CFG_ABEBT_DEFAULT << HDPX_CFG_ABEBT_SHIFT) &
184210393SSaurabh.Mishra@Sun.COM HDPX_CFG_ABEBT_MASK) |
184310393SSaurabh.Mishra@Sun.COM ((HDPX_CFG_JAMIPG_DEFAULT << HDPX_CFG_JAMIPG_SHIFT) &
184410393SSaurabh.Mishra@Sun.COM HDPX_CFG_JAMIPG_MASK));
184510393SSaurabh.Mishra@Sun.COM
184610393SSaurabh.Mishra@Sun.COM /*
184710393SSaurabh.Mishra@Sun.COM * Configure jumbo frame.
184810393SSaurabh.Mishra@Sun.COM */
184910393SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
185010393SSaurabh.Mishra@Sun.COM fsize = ROUNDUP(atgep->atge_max_frame_size, sizeof (uint64_t));
185110393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_RXQ_JUMBO_CFG,
185210393SSaurabh.Mishra@Sun.COM (((fsize / sizeof (uint64_t)) <<
185310393SSaurabh.Mishra@Sun.COM RXQ_JUMBO_CFG_SZ_THRESH_SHIFT) &
185410393SSaurabh.Mishra@Sun.COM RXQ_JUMBO_CFG_SZ_THRESH_MASK) |
185510393SSaurabh.Mishra@Sun.COM ((RXQ_JUMBO_CFG_LKAH_DEFAULT <<
185610393SSaurabh.Mishra@Sun.COM RXQ_JUMBO_CFG_LKAH_SHIFT) & RXQ_JUMBO_CFG_LKAH_MASK) |
185710393SSaurabh.Mishra@Sun.COM ((ATGE_USECS(8) << RXQ_JUMBO_CFG_RRD_TIMER_SHIFT) &
185810393SSaurabh.Mishra@Sun.COM RXQ_JUMBO_CFG_RRD_TIMER_MASK));
185910393SSaurabh.Mishra@Sun.COM } else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E &&
186010393SSaurabh.Mishra@Sun.COM atgep->atge_flags & ATGE_FLAG_JUMBO) {
186110393SSaurabh.Mishra@Sun.COM
186210393SSaurabh.Mishra@Sun.COM if (atgep->atge_mtu < ETHERMTU)
186310393SSaurabh.Mishra@Sun.COM reg = atgep->atge_max_frame_size;
186410393SSaurabh.Mishra@Sun.COM else if (atgep->atge_mtu < 6 * 1024)
186510393SSaurabh.Mishra@Sun.COM reg = (atgep->atge_max_frame_size * 2) / 3;
186610393SSaurabh.Mishra@Sun.COM else
186710393SSaurabh.Mishra@Sun.COM reg = atgep->atge_max_frame_size / 2;
186810393SSaurabh.Mishra@Sun.COM
186910393SSaurabh.Mishra@Sun.COM OUTL(atgep, L1E_TX_JUMBO_THRESH,
187010393SSaurabh.Mishra@Sun.COM ROUNDUP(reg, TX_JUMBO_THRESH_UNIT) >>
187110393SSaurabh.Mishra@Sun.COM TX_JUMBO_THRESH_UNIT_SHIFT);
187210393SSaurabh.Mishra@Sun.COM }
187310393SSaurabh.Mishra@Sun.COM
187410393SSaurabh.Mishra@Sun.COM /*
187510393SSaurabh.Mishra@Sun.COM * Configure flow-control parameters.
187610393SSaurabh.Mishra@Sun.COM */
187710393SSaurabh.Mishra@Sun.COM if ((atgep->atge_flags & ATGE_FLAG_PCIE) != 0) {
187810393SSaurabh.Mishra@Sun.COM /*
187910393SSaurabh.Mishra@Sun.COM * Some hardware version require this magic.
188010393SSaurabh.Mishra@Sun.COM */
188110393SSaurabh.Mishra@Sun.COM OUTL(atgep, 0x12FC, 0x6500);
188210393SSaurabh.Mishra@Sun.COM reg = INL(atgep, 0x1008);
188310393SSaurabh.Mishra@Sun.COM OUTL(atgep, 0x1008, reg | 0x8000);
188410393SSaurabh.Mishra@Sun.COM }
188510393SSaurabh.Mishra@Sun.COM
188610393SSaurabh.Mishra@Sun.COM /*
188710393SSaurabh.Mishra@Sun.COM * These are all magic parameters which came from FreeBSD.
188810393SSaurabh.Mishra@Sun.COM */
188911353SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
189011353SSaurabh.Mishra@Sun.COM switch (atgep->atge_chip_rev) {
189111353SSaurabh.Mishra@Sun.COM case 0x8001:
189211353SSaurabh.Mishra@Sun.COM case 0x9001:
189311353SSaurabh.Mishra@Sun.COM case 0x9002:
189411353SSaurabh.Mishra@Sun.COM case 0x9003:
189511353SSaurabh.Mishra@Sun.COM rxf_hi = L1_RX_RING_CNT / 16;
189611353SSaurabh.Mishra@Sun.COM rxf_lo = (L1_RX_RING_CNT * 7) / 8;
189711353SSaurabh.Mishra@Sun.COM rrd_hi = (L1_RR_RING_CNT * 7) / 8;
189811353SSaurabh.Mishra@Sun.COM rrd_lo = L1_RR_RING_CNT / 16;
189911353SSaurabh.Mishra@Sun.COM break;
190011353SSaurabh.Mishra@Sun.COM default:
190111353SSaurabh.Mishra@Sun.COM reg = INL(atgep, L1_SRAM_RX_FIFO_LEN);
190211353SSaurabh.Mishra@Sun.COM rxf_lo = reg / 16;
190311353SSaurabh.Mishra@Sun.COM if (rxf_lo > 192)
190411353SSaurabh.Mishra@Sun.COM rxf_lo = 192;
190511353SSaurabh.Mishra@Sun.COM rxf_hi = (reg * 7) / 8;
190611353SSaurabh.Mishra@Sun.COM if (rxf_hi < rxf_lo)
190711353SSaurabh.Mishra@Sun.COM rxf_hi = rxf_lo + 16;
190811353SSaurabh.Mishra@Sun.COM reg = INL(atgep, L1_SRAM_RRD_LEN);
190911353SSaurabh.Mishra@Sun.COM rrd_lo = reg / 8;
191011353SSaurabh.Mishra@Sun.COM rrd_hi = (reg * 7) / 8;
191111353SSaurabh.Mishra@Sun.COM if (rrd_lo > 2)
191211353SSaurabh.Mishra@Sun.COM rrd_lo = 2;
191311353SSaurabh.Mishra@Sun.COM if (rrd_hi < rrd_lo)
191411353SSaurabh.Mishra@Sun.COM rrd_hi = rrd_lo + 3;
191511353SSaurabh.Mishra@Sun.COM break;
191611353SSaurabh.Mishra@Sun.COM }
191711353SSaurabh.Mishra@Sun.COM
191811353SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_RXQ_FIFO_PAUSE_THRESH,
191911353SSaurabh.Mishra@Sun.COM ((rxf_lo << RXQ_FIFO_PAUSE_THRESH_LO_SHIFT) &
192011353SSaurabh.Mishra@Sun.COM RXQ_FIFO_PAUSE_THRESH_LO_MASK) |
192111353SSaurabh.Mishra@Sun.COM ((rxf_hi << RXQ_FIFO_PAUSE_THRESH_HI_SHIFT) &
192211353SSaurabh.Mishra@Sun.COM RXQ_FIFO_PAUSE_THRESH_HI_MASK));
192311353SSaurabh.Mishra@Sun.COM
192411353SSaurabh.Mishra@Sun.COM OUTL(atgep, L1_RXQ_RRD_PAUSE_THRESH,
192511353SSaurabh.Mishra@Sun.COM ((rrd_lo << RXQ_RRD_PAUSE_THRESH_LO_SHIFT) &
192611353SSaurabh.Mishra@Sun.COM RXQ_RRD_PAUSE_THRESH_LO_MASK) |
192711353SSaurabh.Mishra@Sun.COM ((rrd_hi << RXQ_RRD_PAUSE_THRESH_HI_SHIFT) &
192811353SSaurabh.Mishra@Sun.COM RXQ_RRD_PAUSE_THRESH_HI_MASK));
192911353SSaurabh.Mishra@Sun.COM } else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
193010393SSaurabh.Mishra@Sun.COM reg = INL(atgep, L1E_SRAM_RX_FIFO_LEN);
193110393SSaurabh.Mishra@Sun.COM rxf_hi = (reg * 4) / 5;
193210393SSaurabh.Mishra@Sun.COM rxf_lo = reg/ 5;
193310393SSaurabh.Mishra@Sun.COM
193410393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_RXQ_FIFO_PAUSE_THRESH,
193510393SSaurabh.Mishra@Sun.COM ((rxf_lo << RXQ_FIFO_PAUSE_THRESH_LO_SHIFT) &
193610393SSaurabh.Mishra@Sun.COM RXQ_FIFO_PAUSE_THRESH_LO_MASK) |
193710393SSaurabh.Mishra@Sun.COM ((rxf_hi << RXQ_FIFO_PAUSE_THRESH_HI_SHIFT) &
193810393SSaurabh.Mishra@Sun.COM RXQ_FIFO_PAUSE_THRESH_HI_MASK));
193910393SSaurabh.Mishra@Sun.COM }
194010393SSaurabh.Mishra@Sun.COM
194110393SSaurabh.Mishra@Sun.COM /* Configure RxQ. */
194210393SSaurabh.Mishra@Sun.COM reg = 0;
194311353SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
194411353SSaurabh.Mishra@Sun.COM reg =
194511353SSaurabh.Mishra@Sun.COM ((RXQ_CFG_RD_BURST_DEFAULT << RXQ_CFG_RD_BURST_SHIFT) &
194611353SSaurabh.Mishra@Sun.COM RXQ_CFG_RD_BURST_MASK) |
194711353SSaurabh.Mishra@Sun.COM ((RXQ_CFG_RRD_BURST_THRESH_DEFAULT <<
194811353SSaurabh.Mishra@Sun.COM RXQ_CFG_RRD_BURST_THRESH_SHIFT) &
194911353SSaurabh.Mishra@Sun.COM RXQ_CFG_RRD_BURST_THRESH_MASK) |
195011353SSaurabh.Mishra@Sun.COM ((RXQ_CFG_RD_PREF_MIN_IPG_DEFAULT <<
195111353SSaurabh.Mishra@Sun.COM RXQ_CFG_RD_PREF_MIN_IPG_SHIFT) &
195211353SSaurabh.Mishra@Sun.COM RXQ_CFG_RD_PREF_MIN_IPG_MASK) |
195311353SSaurabh.Mishra@Sun.COM RXQ_CFG_CUT_THROUGH_ENB | RXQ_CFG_ENB;
195411353SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_RXQ_CFG, reg);
195511353SSaurabh.Mishra@Sun.COM } else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
195610393SSaurabh.Mishra@Sun.COM reg = RXQ_CFG_ALIGN_32 | RXQ_CFG_CUT_THROUGH_ENB |
195710393SSaurabh.Mishra@Sun.COM RXQ_CFG_IPV6_CSUM_VERIFY | RXQ_CFG_ENB;
195810393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_RXQ_CFG, reg);
195910393SSaurabh.Mishra@Sun.COM }
196010393SSaurabh.Mishra@Sun.COM
196110393SSaurabh.Mishra@Sun.COM /*
196210393SSaurabh.Mishra@Sun.COM * Configure TxQ.
196310393SSaurabh.Mishra@Sun.COM */
196411353SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
196511353SSaurabh.Mishra@Sun.COM reg =
196611353SSaurabh.Mishra@Sun.COM (((TXQ_CFG_TPD_BURST_DEFAULT << TXQ_CFG_TPD_BURST_SHIFT) &
196711353SSaurabh.Mishra@Sun.COM TXQ_CFG_TPD_BURST_MASK) |
196811353SSaurabh.Mishra@Sun.COM ((TXQ_CFG_TX_FIFO_BURST_DEFAULT <<
196911353SSaurabh.Mishra@Sun.COM TXQ_CFG_TX_FIFO_BURST_SHIFT) &
197011353SSaurabh.Mishra@Sun.COM TXQ_CFG_TX_FIFO_BURST_MASK) |
197111353SSaurabh.Mishra@Sun.COM ((TXQ_CFG_TPD_FETCH_DEFAULT <<
197211353SSaurabh.Mishra@Sun.COM TXQ_CFG_TPD_FETCH_THRESH_SHIFT) &
197311353SSaurabh.Mishra@Sun.COM TXQ_CFG_TPD_FETCH_THRESH_MASK) |
197411353SSaurabh.Mishra@Sun.COM TXQ_CFG_ENB);
197511353SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_TXQ_CFG, reg);
197611353SSaurabh.Mishra@Sun.COM } else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
197710393SSaurabh.Mishra@Sun.COM reg = (128 <<
197810393SSaurabh.Mishra@Sun.COM (atgep->atge_dma_rd_burst >> DMA_CFG_RD_BURST_SHIFT)) <<
197910393SSaurabh.Mishra@Sun.COM TXQ_CFG_TX_FIFO_BURST_SHIFT;
198010393SSaurabh.Mishra@Sun.COM
198110393SSaurabh.Mishra@Sun.COM reg |= (TXQ_CFG_TPD_BURST_DEFAULT << TXQ_CFG_TPD_BURST_SHIFT) &
198210393SSaurabh.Mishra@Sun.COM TXQ_CFG_TPD_BURST_MASK;
198310393SSaurabh.Mishra@Sun.COM
198410393SSaurabh.Mishra@Sun.COM reg |= TXQ_CFG_ENHANCED_MODE | TXQ_CFG_ENB;
198510393SSaurabh.Mishra@Sun.COM
198610393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_TXQ_CFG, reg);
198710393SSaurabh.Mishra@Sun.COM }
198810393SSaurabh.Mishra@Sun.COM
198911353SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
199011353SSaurabh.Mishra@Sun.COM OUTL(atgep, L1_TX_JUMBO_TPD_TH_IPG,
199111353SSaurabh.Mishra@Sun.COM (((fsize / sizeof (uint64_t) << TX_JUMBO_TPD_TH_SHIFT)) &
199211353SSaurabh.Mishra@Sun.COM TX_JUMBO_TPD_TH_MASK) |
199311353SSaurabh.Mishra@Sun.COM ((TX_JUMBO_TPD_IPG_DEFAULT << TX_JUMBO_TPD_IPG_SHIFT) &
199411353SSaurabh.Mishra@Sun.COM TX_JUMBO_TPD_IPG_MASK));
199511353SSaurabh.Mishra@Sun.COM }
199611353SSaurabh.Mishra@Sun.COM
199710393SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
199810393SSaurabh.Mishra@Sun.COM /* Disable RSS. */
199910393SSaurabh.Mishra@Sun.COM OUTL(atgep, L1E_RSS_IDT_TABLE0, 0);
200010393SSaurabh.Mishra@Sun.COM OUTL(atgep, L1E_RSS_CPU, 0);
200110393SSaurabh.Mishra@Sun.COM }
200210393SSaurabh.Mishra@Sun.COM
200310393SSaurabh.Mishra@Sun.COM /*
200410393SSaurabh.Mishra@Sun.COM * Configure DMA parameters.
200510393SSaurabh.Mishra@Sun.COM */
200611353SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
200711353SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_DMA_CFG,
200811353SSaurabh.Mishra@Sun.COM DMA_CFG_ENH_ORDER | DMA_CFG_RCB_64 |
200911353SSaurabh.Mishra@Sun.COM atgep->atge_dma_rd_burst | DMA_CFG_RD_ENB |
201011353SSaurabh.Mishra@Sun.COM atgep->atge_dma_wr_burst | DMA_CFG_WR_ENB);
201111353SSaurabh.Mishra@Sun.COM
201211353SSaurabh.Mishra@Sun.COM /* Configure CMB DMA write threshold. */
201311353SSaurabh.Mishra@Sun.COM OUTL(atgep, L1_CMB_WR_THRESH,
201411353SSaurabh.Mishra@Sun.COM ((CMB_WR_THRESH_RRD_DEFAULT << CMB_WR_THRESH_RRD_SHIFT) &
201511353SSaurabh.Mishra@Sun.COM CMB_WR_THRESH_RRD_MASK) |
201611353SSaurabh.Mishra@Sun.COM ((CMB_WR_THRESH_TPD_DEFAULT << CMB_WR_THRESH_TPD_SHIFT) &
201711353SSaurabh.Mishra@Sun.COM CMB_WR_THRESH_TPD_MASK));
201811353SSaurabh.Mishra@Sun.COM } else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
201910393SSaurabh.Mishra@Sun.COM /*
202010393SSaurabh.Mishra@Sun.COM * Don't use Tx CMB. It is known to cause RRS update failure
202110393SSaurabh.Mishra@Sun.COM * under certain circumstances. Typical phenomenon of the
202210393SSaurabh.Mishra@Sun.COM * issue would be unexpected sequence number encountered in
202310393SSaurabh.Mishra@Sun.COM * Rx handler. Hence we don't set DMA_CFG_TXCMB_ENB.
202410393SSaurabh.Mishra@Sun.COM */
202510393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_DMA_CFG,
202610393SSaurabh.Mishra@Sun.COM DMA_CFG_OUT_ORDER | DMA_CFG_RD_REQ_PRI | DMA_CFG_RCB_64 |
202710393SSaurabh.Mishra@Sun.COM atgep->atge_dma_rd_burst | atgep->atge_dma_wr_burst |
202810393SSaurabh.Mishra@Sun.COM DMA_CFG_RXCMB_ENB |
202910393SSaurabh.Mishra@Sun.COM ((DMA_CFG_RD_DELAY_CNT_DEFAULT <<
203010393SSaurabh.Mishra@Sun.COM DMA_CFG_RD_DELAY_CNT_SHIFT) & DMA_CFG_RD_DELAY_CNT_MASK) |
203110393SSaurabh.Mishra@Sun.COM ((DMA_CFG_WR_DELAY_CNT_DEFAULT <<
203210393SSaurabh.Mishra@Sun.COM DMA_CFG_WR_DELAY_CNT_SHIFT) & DMA_CFG_WR_DELAY_CNT_MASK));
203310393SSaurabh.Mishra@Sun.COM }
203410393SSaurabh.Mishra@Sun.COM
203510393SSaurabh.Mishra@Sun.COM /*
203611353SSaurabh.Mishra@Sun.COM * Enable CMB/SMB timer.
203710393SSaurabh.Mishra@Sun.COM */
203811353SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
203911353SSaurabh.Mishra@Sun.COM /* Set CMB/SMB timer and enable them. */
204011353SSaurabh.Mishra@Sun.COM OUTL(atgep, L1_CMB_WR_TIMER,
204111353SSaurabh.Mishra@Sun.COM ((ATGE_USECS(2) << CMB_WR_TIMER_TX_SHIFT) &
204211353SSaurabh.Mishra@Sun.COM CMB_WR_TIMER_TX_MASK) |
204311353SSaurabh.Mishra@Sun.COM ((ATGE_USECS(2) << CMB_WR_TIMER_RX_SHIFT) &
204411353SSaurabh.Mishra@Sun.COM CMB_WR_TIMER_RX_MASK));
204511353SSaurabh.Mishra@Sun.COM
204611353SSaurabh.Mishra@Sun.COM /* Request SMB updates for every seconds. */
204711353SSaurabh.Mishra@Sun.COM OUTL(atgep, L1_SMB_TIMER, ATGE_USECS(1000 * 1000));
204811353SSaurabh.Mishra@Sun.COM OUTL(atgep, L1_CSMB_CTRL,
204911353SSaurabh.Mishra@Sun.COM CSMB_CTRL_SMB_ENB | CSMB_CTRL_CMB_ENB);
205011353SSaurabh.Mishra@Sun.COM } else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
205110393SSaurabh.Mishra@Sun.COM OUTL(atgep, L1E_SMB_STAT_TIMER, 100000);
205210393SSaurabh.Mishra@Sun.COM atge_l1e_clear_stats(atgep);
205310393SSaurabh.Mishra@Sun.COM }
205410393SSaurabh.Mishra@Sun.COM
205511353SSaurabh.Mishra@Sun.COM
205610393SSaurabh.Mishra@Sun.COM /*
205710393SSaurabh.Mishra@Sun.COM * Disable all WOL bits as WOL can interfere normal Rx
205810393SSaurabh.Mishra@Sun.COM * operation.
205910393SSaurabh.Mishra@Sun.COM */
206010393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_WOL_CFG, 0);
206110393SSaurabh.Mishra@Sun.COM
206210393SSaurabh.Mishra@Sun.COM /*
206310393SSaurabh.Mishra@Sun.COM * Configure Tx/Rx MACs.
206410393SSaurabh.Mishra@Sun.COM * - Auto-padding for short frames.
206510393SSaurabh.Mishra@Sun.COM * - Enable CRC generation.
206610393SSaurabh.Mishra@Sun.COM *
206710393SSaurabh.Mishra@Sun.COM * Start with full-duplex/1000Mbps media. Actual reconfiguration
206810393SSaurabh.Mishra@Sun.COM * of MAC is followed after link establishment.
206910393SSaurabh.Mishra@Sun.COM */
207010393SSaurabh.Mishra@Sun.COM reg = (ATGE_CFG_TX_CRC_ENB | ATGE_CFG_TX_AUTO_PAD |
207110393SSaurabh.Mishra@Sun.COM ATGE_CFG_FULL_DUPLEX |
207210393SSaurabh.Mishra@Sun.COM ((ATGE_CFG_PREAMBLE_DEFAULT << ATGE_CFG_PREAMBLE_SHIFT) &
207310393SSaurabh.Mishra@Sun.COM ATGE_CFG_PREAMBLE_MASK));
207410393SSaurabh.Mishra@Sun.COM
207510393SSaurabh.Mishra@Sun.COM if ((atgep->atge_flags & ATGE_FLAG_FASTETHER) != 0) {
207610393SSaurabh.Mishra@Sun.COM reg |= ATGE_CFG_SPEED_10_100;
207710393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s() Fast Ethernet", atgep->atge_name, __func__));
207810393SSaurabh.Mishra@Sun.COM } else {
207910393SSaurabh.Mishra@Sun.COM reg |= ATGE_CFG_SPEED_1000;
208010393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s() 1G speed", atgep->atge_name, __func__));
208110393SSaurabh.Mishra@Sun.COM }
208210393SSaurabh.Mishra@Sun.COM
208310393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_MAC_CFG, reg);
208410393SSaurabh.Mishra@Sun.COM
208510393SSaurabh.Mishra@Sun.COM atgep->atge_chip_state |= ATGE_CHIP_RUNNING;
208610393SSaurabh.Mishra@Sun.COM
208710393SSaurabh.Mishra@Sun.COM /*
208810393SSaurabh.Mishra@Sun.COM * Set up the receive filter.
208910393SSaurabh.Mishra@Sun.COM */
209010393SSaurabh.Mishra@Sun.COM atge_rxfilter(atgep);
209110393SSaurabh.Mishra@Sun.COM
209211353SSaurabh.Mishra@Sun.COM /*
209311353SSaurabh.Mishra@Sun.COM * Acknowledge all pending interrupts and clear it.
209411353SSaurabh.Mishra@Sun.COM */
209511353SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
209611353SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_INTR_STATUS, 0);
209711353SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_INTR_MASK, atgep->atge_intrs);
209811353SSaurabh.Mishra@Sun.COM } else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
209910393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_INTR_MASK, L1E_INTRS);
210010393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_INTR_STATUS, 0xFFFFFFFF);
210110393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_INTR_STATUS, 0);
210210393SSaurabh.Mishra@Sun.COM }
210310393SSaurabh.Mishra@Sun.COM
210411353SSaurabh.Mishra@Sun.COM atge_mac_config(atgep);
210511353SSaurabh.Mishra@Sun.COM
210610393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s() device started", atgep->atge_name, __func__));
210710393SSaurabh.Mishra@Sun.COM }
210810393SSaurabh.Mishra@Sun.COM
210910393SSaurabh.Mishra@Sun.COM /*
211010393SSaurabh.Mishra@Sun.COM * Generic functions.
211110393SSaurabh.Mishra@Sun.COM */
211210393SSaurabh.Mishra@Sun.COM
211310393SSaurabh.Mishra@Sun.COM #define CRC32_POLY_BE 0x04c11db7
211410393SSaurabh.Mishra@Sun.COM uint32_t
atge_ether_crc(const uint8_t * addr,int len)211510393SSaurabh.Mishra@Sun.COM atge_ether_crc(const uint8_t *addr, int len)
211610393SSaurabh.Mishra@Sun.COM {
211710393SSaurabh.Mishra@Sun.COM int idx;
211810393SSaurabh.Mishra@Sun.COM int bit;
211910393SSaurabh.Mishra@Sun.COM uint_t data;
212010393SSaurabh.Mishra@Sun.COM uint32_t crc;
212110393SSaurabh.Mishra@Sun.COM
212210393SSaurabh.Mishra@Sun.COM crc = 0xffffffff;
212310393SSaurabh.Mishra@Sun.COM for (idx = 0; idx < len; idx++) {
212410393SSaurabh.Mishra@Sun.COM for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) {
212510393SSaurabh.Mishra@Sun.COM crc = (crc << 1)
212610393SSaurabh.Mishra@Sun.COM ^ ((((crc >> 31) ^ data) & 1) ? CRC32_POLY_BE : 0);
212710393SSaurabh.Mishra@Sun.COM }
212810393SSaurabh.Mishra@Sun.COM }
212910393SSaurabh.Mishra@Sun.COM
213010393SSaurabh.Mishra@Sun.COM return (crc);
213110393SSaurabh.Mishra@Sun.COM }
213210393SSaurabh.Mishra@Sun.COM
213310393SSaurabh.Mishra@Sun.COM
213410393SSaurabh.Mishra@Sun.COM /*
213510393SSaurabh.Mishra@Sun.COM * Programs RX filter. We use a link-list to keep track of all multicast
213610393SSaurabh.Mishra@Sun.COM * addressess.
213710393SSaurabh.Mishra@Sun.COM */
213810393SSaurabh.Mishra@Sun.COM void
atge_rxfilter(atge_t * atgep)213910393SSaurabh.Mishra@Sun.COM atge_rxfilter(atge_t *atgep)
214010393SSaurabh.Mishra@Sun.COM {
214110393SSaurabh.Mishra@Sun.COM uint32_t rxcfg;
214210393SSaurabh.Mishra@Sun.COM uint64_t mchash;
214310393SSaurabh.Mishra@Sun.COM
214410393SSaurabh.Mishra@Sun.COM rxcfg = INL(atgep, ATGE_MAC_CFG);
214510393SSaurabh.Mishra@Sun.COM rxcfg &= ~(ATGE_CFG_ALLMULTI | ATGE_CFG_PROMISC);
214610393SSaurabh.Mishra@Sun.COM
214710393SSaurabh.Mishra@Sun.COM /*
214810393SSaurabh.Mishra@Sun.COM * Accept broadcast frames.
214910393SSaurabh.Mishra@Sun.COM */
215010393SSaurabh.Mishra@Sun.COM rxcfg |= ATGE_CFG_BCAST;
215110393SSaurabh.Mishra@Sun.COM
215210393SSaurabh.Mishra@Sun.COM /*
215310393SSaurabh.Mishra@Sun.COM * We don't use Hardware VLAN tagging.
215410393SSaurabh.Mishra@Sun.COM */
215510393SSaurabh.Mishra@Sun.COM rxcfg &= ~ATGE_CFG_VLAN_TAG_STRIP;
215610393SSaurabh.Mishra@Sun.COM
215710393SSaurabh.Mishra@Sun.COM if (atgep->atge_filter_flags & (ATGE_PROMISC | ATGE_ALL_MULTICST)) {
215810393SSaurabh.Mishra@Sun.COM mchash = ~0ULL;
215910393SSaurabh.Mishra@Sun.COM
216010393SSaurabh.Mishra@Sun.COM if (atgep->atge_filter_flags & ATGE_PROMISC)
216110393SSaurabh.Mishra@Sun.COM rxcfg |= ATGE_CFG_PROMISC;
216210393SSaurabh.Mishra@Sun.COM
216310393SSaurabh.Mishra@Sun.COM if (atgep->atge_filter_flags & ATGE_ALL_MULTICST)
216410393SSaurabh.Mishra@Sun.COM rxcfg |= ATGE_CFG_ALLMULTI;
216510393SSaurabh.Mishra@Sun.COM } else {
216610393SSaurabh.Mishra@Sun.COM mchash = atgep->atge_mchash;
216710393SSaurabh.Mishra@Sun.COM }
216810393SSaurabh.Mishra@Sun.COM
216910393SSaurabh.Mishra@Sun.COM atge_program_ether(atgep);
217010393SSaurabh.Mishra@Sun.COM
217110393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_MAR0, (uint32_t)mchash);
217210393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_MAR1, (uint32_t)(mchash >> 32));
217310393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_MAC_CFG, rxcfg);
217410393SSaurabh.Mishra@Sun.COM
217510393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s() mac_cfg is : %x, mchash : %llx",
217610393SSaurabh.Mishra@Sun.COM atgep->atge_name, __func__, rxcfg, mchash));
217710393SSaurabh.Mishra@Sun.COM }
217810393SSaurabh.Mishra@Sun.COM
217910393SSaurabh.Mishra@Sun.COM void
atge_device_stop(atge_t * atgep)218010393SSaurabh.Mishra@Sun.COM atge_device_stop(atge_t *atgep)
218110393SSaurabh.Mishra@Sun.COM {
218210393SSaurabh.Mishra@Sun.COM uint32_t reg;
218310393SSaurabh.Mishra@Sun.COM int t;
218410393SSaurabh.Mishra@Sun.COM
218510393SSaurabh.Mishra@Sun.COM /*
218610393SSaurabh.Mishra@Sun.COM * If the chip is being suspended, then don't touch the state. Caller
218710393SSaurabh.Mishra@Sun.COM * will take care of setting the correct state.
218810393SSaurabh.Mishra@Sun.COM */
218910393SSaurabh.Mishra@Sun.COM if (!(atgep->atge_chip_state & ATGE_CHIP_SUSPENDED)) {
219010393SSaurabh.Mishra@Sun.COM atgep->atge_chip_state |= ATGE_CHIP_STOPPED;
219110393SSaurabh.Mishra@Sun.COM atgep->atge_chip_state &= ~ATGE_CHIP_RUNNING;
219210393SSaurabh.Mishra@Sun.COM }
219310393SSaurabh.Mishra@Sun.COM
219410393SSaurabh.Mishra@Sun.COM /*
219510393SSaurabh.Mishra@Sun.COM * Collect stats for L1E. L1 chip's stats are collected by interrupt.
219610393SSaurabh.Mishra@Sun.COM */
219710393SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
219810393SSaurabh.Mishra@Sun.COM atge_l1e_gather_stats(atgep);
219910393SSaurabh.Mishra@Sun.COM }
220010393SSaurabh.Mishra@Sun.COM
220110393SSaurabh.Mishra@Sun.COM /*
220210393SSaurabh.Mishra@Sun.COM * Disable interrupts.
220310393SSaurabh.Mishra@Sun.COM */
220410393SSaurabh.Mishra@Sun.COM atge_disable_intrs(atgep);
220510393SSaurabh.Mishra@Sun.COM
220611353SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1)
220711353SSaurabh.Mishra@Sun.COM OUTL(atgep, L1_CSMB_CTRL, 0);
220811353SSaurabh.Mishra@Sun.COM
220911353SSaurabh.Mishra@Sun.COM /* Stop DMA Engine */
221011353SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
221111353SSaurabh.Mishra@Sun.COM atge_l1_stop_tx_mac(atgep);
221211353SSaurabh.Mishra@Sun.COM atge_l1_stop_rx_mac(atgep);
221311353SSaurabh.Mishra@Sun.COM
221411353SSaurabh.Mishra@Sun.COM reg = INL(atgep, ATGE_DMA_CFG);
221511353SSaurabh.Mishra@Sun.COM reg &= ~(DMA_CFG_RD_ENB | DMA_CFG_WR_ENB);
221611353SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_DMA_CFG, reg);
221711353SSaurabh.Mishra@Sun.COM
221811353SSaurabh.Mishra@Sun.COM }
221911353SSaurabh.Mishra@Sun.COM
222010393SSaurabh.Mishra@Sun.COM /*
222110393SSaurabh.Mishra@Sun.COM * Disable queue processing.
222210393SSaurabh.Mishra@Sun.COM */
222310393SSaurabh.Mishra@Sun.COM /* Stop TxQ */
222410393SSaurabh.Mishra@Sun.COM reg = INL(atgep, ATGE_TXQ_CFG);
222510393SSaurabh.Mishra@Sun.COM reg = reg & ~TXQ_CFG_ENB;
222610393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_TXQ_CFG, reg);
222710393SSaurabh.Mishra@Sun.COM
222810393SSaurabh.Mishra@Sun.COM /* Stop RxQ */
222910393SSaurabh.Mishra@Sun.COM reg = INL(atgep, ATGE_RXQ_CFG);
223010393SSaurabh.Mishra@Sun.COM reg = reg & ~RXQ_CFG_ENB;
223110393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_RXQ_CFG, reg);
223210393SSaurabh.Mishra@Sun.COM
223310393SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
223410393SSaurabh.Mishra@Sun.COM reg = INL(atgep, ATGE_DMA_CFG);
223510393SSaurabh.Mishra@Sun.COM reg = reg & ~(DMA_CFG_TXCMB_ENB | DMA_CFG_RXCMB_ENB);
223610393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_DMA_CFG, reg);
223710393SSaurabh.Mishra@Sun.COM drv_usecwait(1000);
223810393SSaurabh.Mishra@Sun.COM atge_l1e_stop_mac(atgep);
223910393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_INTR_STATUS, 0xFFFFFFFF);
224010393SSaurabh.Mishra@Sun.COM }
224110393SSaurabh.Mishra@Sun.COM
224210393SSaurabh.Mishra@Sun.COM for (t = ATGE_RESET_TIMEOUT; t > 0; t--) {
224310393SSaurabh.Mishra@Sun.COM if ((reg = INL(atgep, ATGE_IDLE_STATUS)) == 0)
224410393SSaurabh.Mishra@Sun.COM break;
224510393SSaurabh.Mishra@Sun.COM drv_usecwait(10);
224610393SSaurabh.Mishra@Sun.COM }
224710393SSaurabh.Mishra@Sun.COM
224810393SSaurabh.Mishra@Sun.COM if (t == 0) {
224910393SSaurabh.Mishra@Sun.COM atge_error(atgep->atge_dip, "%s() stopping TX/RX MAC timeout",
225010393SSaurabh.Mishra@Sun.COM __func__);
225110393SSaurabh.Mishra@Sun.COM }
225210393SSaurabh.Mishra@Sun.COM }
225310393SSaurabh.Mishra@Sun.COM
225410393SSaurabh.Mishra@Sun.COM void
atge_disable_intrs(atge_t * atgep)225510393SSaurabh.Mishra@Sun.COM atge_disable_intrs(atge_t *atgep)
225610393SSaurabh.Mishra@Sun.COM {
225710393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_INTR_MASK, 0);
225810393SSaurabh.Mishra@Sun.COM OUTL(atgep, ATGE_INTR_STATUS, 0xFFFFFFFF);
225910393SSaurabh.Mishra@Sun.COM }
226010393SSaurabh.Mishra@Sun.COM
226110393SSaurabh.Mishra@Sun.COM void
atge_device_init(atge_t * atgep)226210393SSaurabh.Mishra@Sun.COM atge_device_init(atge_t *atgep)
226310393SSaurabh.Mishra@Sun.COM {
226410393SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
226510393SSaurabh.Mishra@Sun.COM atgep->atge_intrs = L1E_INTRS;
226610393SSaurabh.Mishra@Sun.COM atgep->atge_int_mod = ATGE_IM_TIMER_DEFAULT;
226710393SSaurabh.Mishra@Sun.COM
226810393SSaurabh.Mishra@Sun.COM atge_l1e_init_tx_ring(atgep);
226910393SSaurabh.Mishra@Sun.COM atge_l1e_init_rx_pages(atgep);
227011353SSaurabh.Mishra@Sun.COM } else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
227111353SSaurabh.Mishra@Sun.COM atgep->atge_intrs = L1_INTRS | INTR_GPHY | INTR_PHY_LINK_DOWN |
227211353SSaurabh.Mishra@Sun.COM INTR_LINK_CHG;
227311353SSaurabh.Mishra@Sun.COM atgep->atge_int_mod = ATGE_IM_TIMER_DEFAULT;
227411353SSaurabh.Mishra@Sun.COM
227511353SSaurabh.Mishra@Sun.COM atge_l1_init_tx_ring(atgep);
227611353SSaurabh.Mishra@Sun.COM atge_l1_init_rx_ring(atgep);
227711353SSaurabh.Mishra@Sun.COM atge_l1_init_rr_ring(atgep);
227811353SSaurabh.Mishra@Sun.COM atge_l1_init_cmb(atgep);
227911353SSaurabh.Mishra@Sun.COM atge_l1_init_smb(atgep);
228010393SSaurabh.Mishra@Sun.COM }
228110393SSaurabh.Mishra@Sun.COM }
228210393SSaurabh.Mishra@Sun.COM
228310393SSaurabh.Mishra@Sun.COM void
atge_device_restart(atge_t * atgep)228410393SSaurabh.Mishra@Sun.COM atge_device_restart(atge_t *atgep)
228510393SSaurabh.Mishra@Sun.COM {
228610393SSaurabh.Mishra@Sun.COM ASSERT(MUTEX_HELD(&atgep->atge_intr_lock));
228710393SSaurabh.Mishra@Sun.COM ASSERT(MUTEX_HELD(&atgep->atge_tx_lock));
228810393SSaurabh.Mishra@Sun.COM
228910393SSaurabh.Mishra@Sun.COM /*
229010393SSaurabh.Mishra@Sun.COM * Cancel any pending I/O.
229110393SSaurabh.Mishra@Sun.COM */
229210393SSaurabh.Mishra@Sun.COM atge_device_stop(atgep);
229310393SSaurabh.Mishra@Sun.COM
229410393SSaurabh.Mishra@Sun.COM /*
229510393SSaurabh.Mishra@Sun.COM * Reset the chip to a known state.
229610393SSaurabh.Mishra@Sun.COM */
229710393SSaurabh.Mishra@Sun.COM atge_device_reset(atgep);
229810393SSaurabh.Mishra@Sun.COM
229910393SSaurabh.Mishra@Sun.COM /*
230010393SSaurabh.Mishra@Sun.COM * Initialize the ring and other descriptor like CMB/SMB/Rx return.
230110393SSaurabh.Mishra@Sun.COM */
230210393SSaurabh.Mishra@Sun.COM atge_device_init(atgep);
230310393SSaurabh.Mishra@Sun.COM
230410393SSaurabh.Mishra@Sun.COM /*
230510393SSaurabh.Mishra@Sun.COM * Start the chip.
230610393SSaurabh.Mishra@Sun.COM */
230710393SSaurabh.Mishra@Sun.COM atge_device_start(atgep);
230810393SSaurabh.Mishra@Sun.COM
230910393SSaurabh.Mishra@Sun.COM }
231010393SSaurabh.Mishra@Sun.COM
231110393SSaurabh.Mishra@Sun.COM static int
atge_send_a_packet(atge_t * atgep,mblk_t * mp)231210393SSaurabh.Mishra@Sun.COM atge_send_a_packet(atge_t *atgep, mblk_t *mp)
231310393SSaurabh.Mishra@Sun.COM {
231411353SSaurabh.Mishra@Sun.COM atge_tx_desc_t *txd;
231511353SSaurabh.Mishra@Sun.COM uchar_t *c;
231611353SSaurabh.Mishra@Sun.COM uint32_t cflags = 0;
231710393SSaurabh.Mishra@Sun.COM atge_ring_t *r;
231810393SSaurabh.Mishra@Sun.COM size_t pktlen;
231910393SSaurabh.Mishra@Sun.COM uchar_t *buf;
232010393SSaurabh.Mishra@Sun.COM int start;
232110393SSaurabh.Mishra@Sun.COM
232210393SSaurabh.Mishra@Sun.COM ASSERT(MUTEX_HELD(&atgep->atge_tx_lock));
232310393SSaurabh.Mishra@Sun.COM ASSERT(mp != NULL);
232410393SSaurabh.Mishra@Sun.COM
232510393SSaurabh.Mishra@Sun.COM pktlen = msgsize(mp);
232610393SSaurabh.Mishra@Sun.COM if (pktlen > atgep->atge_tx_buf_len) {
232710393SSaurabh.Mishra@Sun.COM atgep->atge_macxmt_errors++;
232810393SSaurabh.Mishra@Sun.COM
232910393SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s() pktlen (%d) > rx_buf_len (%d)",
233010393SSaurabh.Mishra@Sun.COM atgep->atge_name, __func__,
233110393SSaurabh.Mishra@Sun.COM pktlen, atgep->atge_rx_buf_len));
233210393SSaurabh.Mishra@Sun.COM
233310393SSaurabh.Mishra@Sun.COM freemsg(mp);
233411353SSaurabh.Mishra@Sun.COM return (DDI_SUCCESS);
233510393SSaurabh.Mishra@Sun.COM }
233610393SSaurabh.Mishra@Sun.COM
233710393SSaurabh.Mishra@Sun.COM r = atgep->atge_tx_ring;
233810393SSaurabh.Mishra@Sun.COM
233910393SSaurabh.Mishra@Sun.COM if (r->r_avail_desc <= 1) {
234010393SSaurabh.Mishra@Sun.COM atgep->atge_noxmtbuf++;
234110393SSaurabh.Mishra@Sun.COM atgep->atge_tx_resched = 1;
234211353SSaurabh.Mishra@Sun.COM
234311353SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s() No transmit buf",
234411353SSaurabh.Mishra@Sun.COM atgep->atge_name, __func__));
234511353SSaurabh.Mishra@Sun.COM
234611353SSaurabh.Mishra@Sun.COM return (DDI_FAILURE);
234710393SSaurabh.Mishra@Sun.COM }
234810393SSaurabh.Mishra@Sun.COM
234910393SSaurabh.Mishra@Sun.COM start = r->r_producer;
235010393SSaurabh.Mishra@Sun.COM
235110393SSaurabh.Mishra@Sun.COM /*
235210393SSaurabh.Mishra@Sun.COM * Get the DMA buffer to hold a packet.
235310393SSaurabh.Mishra@Sun.COM */
235410393SSaurabh.Mishra@Sun.COM buf = (uchar_t *)r->r_buf_tbl[start]->addr;
235510393SSaurabh.Mishra@Sun.COM
235610393SSaurabh.Mishra@Sun.COM /*
235710393SSaurabh.Mishra@Sun.COM * Copy the msg and free mp
235810393SSaurabh.Mishra@Sun.COM */
235910393SSaurabh.Mishra@Sun.COM mcopymsg(mp, buf);
236010393SSaurabh.Mishra@Sun.COM
236110393SSaurabh.Mishra@Sun.COM r->r_avail_desc--;
236210393SSaurabh.Mishra@Sun.COM
236311353SSaurabh.Mishra@Sun.COM c = (uchar_t *)r->r_desc_ring->addr;
236411353SSaurabh.Mishra@Sun.COM c += (sizeof (atge_tx_desc_t) * start);
236511353SSaurabh.Mishra@Sun.COM txd = (atge_tx_desc_t *)c;
236611353SSaurabh.Mishra@Sun.COM
236711353SSaurabh.Mishra@Sun.COM ATGE_PUT64(r->r_desc_ring, &txd->addr,
236811353SSaurabh.Mishra@Sun.COM r->r_buf_tbl[start]->cookie.dmac_laddress);
236911353SSaurabh.Mishra@Sun.COM
237011353SSaurabh.Mishra@Sun.COM ATGE_PUT32(r->r_desc_ring, &txd->len, ATGE_TX_BYTES(pktlen));
237111353SSaurabh.Mishra@Sun.COM
237211353SSaurabh.Mishra@Sun.COM cflags |= ATGE_TD_EOP;
237311353SSaurabh.Mishra@Sun.COM ATGE_PUT32(r->r_desc_ring, &txd->flags, cflags);
237411353SSaurabh.Mishra@Sun.COM
237511353SSaurabh.Mishra@Sun.COM /*
237611353SSaurabh.Mishra@Sun.COM * Sync buffer first.
237711353SSaurabh.Mishra@Sun.COM */
237811353SSaurabh.Mishra@Sun.COM DMA_SYNC(r->r_buf_tbl[start], 0, pktlen, DDI_DMA_SYNC_FORDEV);
237911353SSaurabh.Mishra@Sun.COM
238011353SSaurabh.Mishra@Sun.COM /*
238111353SSaurabh.Mishra@Sun.COM * Increment TX producer count by one.
238211353SSaurabh.Mishra@Sun.COM */
238311353SSaurabh.Mishra@Sun.COM ATGE_INC_SLOT(r->r_producer, ATGE_TX_RING_CNT);
238411353SSaurabh.Mishra@Sun.COM
238511353SSaurabh.Mishra@Sun.COM /*
238611353SSaurabh.Mishra@Sun.COM * Sync descriptor table.
238711353SSaurabh.Mishra@Sun.COM */
238811353SSaurabh.Mishra@Sun.COM DMA_SYNC(r->r_desc_ring, 0, ATGE_TX_RING_SZ, DDI_DMA_SYNC_FORDEV);
238911353SSaurabh.Mishra@Sun.COM
239010393SSaurabh.Mishra@Sun.COM /*
239110393SSaurabh.Mishra@Sun.COM * Program TX descriptor to send a packet.
239210393SSaurabh.Mishra@Sun.COM */
239310393SSaurabh.Mishra@Sun.COM if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
239411353SSaurabh.Mishra@Sun.COM atge_l1e_send_packet(r);
239511353SSaurabh.Mishra@Sun.COM } else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
239611353SSaurabh.Mishra@Sun.COM atge_l1_send_packet(r);
239710393SSaurabh.Mishra@Sun.COM }
239810393SSaurabh.Mishra@Sun.COM
239911353SSaurabh.Mishra@Sun.COM r->r_atge->atge_opackets++;
240011353SSaurabh.Mishra@Sun.COM r->r_atge->atge_obytes += pktlen;
240111353SSaurabh.Mishra@Sun.COM
240211353SSaurabh.Mishra@Sun.COM ATGE_DB(("%s: %s() pktlen : %d, avail_desc : %d, producer :%d, "
240311353SSaurabh.Mishra@Sun.COM "consumer : %d", atgep->atge_name, __func__, pktlen,
240411353SSaurabh.Mishra@Sun.COM r->r_avail_desc, r->r_producer, r->r_consumer));
240511353SSaurabh.Mishra@Sun.COM
240611353SSaurabh.Mishra@Sun.COM return (DDI_SUCCESS);
240710393SSaurabh.Mishra@Sun.COM }
240810393SSaurabh.Mishra@Sun.COM
240910393SSaurabh.Mishra@Sun.COM /*
241010393SSaurabh.Mishra@Sun.COM * Stream Information.
241110393SSaurabh.Mishra@Sun.COM */
241210393SSaurabh.Mishra@Sun.COM DDI_DEFINE_STREAM_OPS(atge_devops, nulldev, nulldev, atge_attach, atge_detach,
241310393SSaurabh.Mishra@Sun.COM nodev, NULL, D_MP, NULL, atge_quiesce);
241410393SSaurabh.Mishra@Sun.COM
241510393SSaurabh.Mishra@Sun.COM /*
241610393SSaurabh.Mishra@Sun.COM * Module linkage information.
241710393SSaurabh.Mishra@Sun.COM */
241810393SSaurabh.Mishra@Sun.COM static struct modldrv atge_modldrv = {
241910393SSaurabh.Mishra@Sun.COM &mod_driverops, /* Type of Module */
242010393SSaurabh.Mishra@Sun.COM "Atheros/Attansic Gb Ethernet", /* Description */
242110393SSaurabh.Mishra@Sun.COM &atge_devops /* drv_dev_ops */
242210393SSaurabh.Mishra@Sun.COM };
242310393SSaurabh.Mishra@Sun.COM
242410393SSaurabh.Mishra@Sun.COM static struct modlinkage atge_modlinkage = {
242510393SSaurabh.Mishra@Sun.COM MODREV_1, /* ml_rev */
242610393SSaurabh.Mishra@Sun.COM (void *)&atge_modldrv,
242710393SSaurabh.Mishra@Sun.COM NULL
242810393SSaurabh.Mishra@Sun.COM };
242910393SSaurabh.Mishra@Sun.COM
243010393SSaurabh.Mishra@Sun.COM /*
243110393SSaurabh.Mishra@Sun.COM * DDI Entry points.
243210393SSaurabh.Mishra@Sun.COM */
243310393SSaurabh.Mishra@Sun.COM int
_init(void)243410393SSaurabh.Mishra@Sun.COM _init(void)
243510393SSaurabh.Mishra@Sun.COM {
243610393SSaurabh.Mishra@Sun.COM int r;
243710393SSaurabh.Mishra@Sun.COM mac_init_ops(&atge_devops, "atge");
243810393SSaurabh.Mishra@Sun.COM if ((r = mod_install(&atge_modlinkage)) != DDI_SUCCESS) {
243910393SSaurabh.Mishra@Sun.COM mac_fini_ops(&atge_devops);
244010393SSaurabh.Mishra@Sun.COM }
244110393SSaurabh.Mishra@Sun.COM
244210393SSaurabh.Mishra@Sun.COM return (r);
244310393SSaurabh.Mishra@Sun.COM }
244410393SSaurabh.Mishra@Sun.COM
244510393SSaurabh.Mishra@Sun.COM int
_fini(void)244610393SSaurabh.Mishra@Sun.COM _fini(void)
244710393SSaurabh.Mishra@Sun.COM {
244810393SSaurabh.Mishra@Sun.COM int r;
244910393SSaurabh.Mishra@Sun.COM
245010393SSaurabh.Mishra@Sun.COM if ((r = mod_remove(&atge_modlinkage)) == DDI_SUCCESS) {
245110393SSaurabh.Mishra@Sun.COM mac_fini_ops(&atge_devops);
245210393SSaurabh.Mishra@Sun.COM }
245310393SSaurabh.Mishra@Sun.COM
245410393SSaurabh.Mishra@Sun.COM return (r);
245510393SSaurabh.Mishra@Sun.COM }
245610393SSaurabh.Mishra@Sun.COM
245710393SSaurabh.Mishra@Sun.COM int
_info(struct modinfo * modinfop)245810393SSaurabh.Mishra@Sun.COM _info(struct modinfo *modinfop)
245910393SSaurabh.Mishra@Sun.COM {
246010393SSaurabh.Mishra@Sun.COM return (mod_info(&atge_modlinkage, modinfop));
246110393SSaurabh.Mishra@Sun.COM }
2462