162387023Sdduvall /*
262387023Sdduvall * CDDL HEADER START
362387023Sdduvall *
462387023Sdduvall * The contents of this file are subject to the terms of the
562387023Sdduvall * Common Development and Distribution License (the "License").
662387023Sdduvall * You may not use this file except in compliance with the License.
762387023Sdduvall *
862387023Sdduvall * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
962387023Sdduvall * or http://www.opensolaris.org/os/licensing.
1062387023Sdduvall * See the License for the specific language governing permissions
1162387023Sdduvall * and limitations under the License.
1262387023Sdduvall *
1362387023Sdduvall * When distributing Covered Code, include this CDDL HEADER in each
1462387023Sdduvall * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1562387023Sdduvall * If applicable, add the following below this CDDL HEADER, with the
1662387023Sdduvall * fields enclosed by brackets "[]" replaced with your own identifying
1762387023Sdduvall * information: Portions Copyright [yyyy] [name of copyright owner]
1862387023Sdduvall *
1962387023Sdduvall * CDDL HEADER END
2062387023Sdduvall */
2162387023Sdduvall
2262387023Sdduvall /*
23087a28d1SDavid Gwynne * Copyright (c) 2010-2013, by Broadcom, Inc.
24087a28d1SDavid Gwynne * All Rights Reserved.
25087a28d1SDavid Gwynne */
26087a28d1SDavid Gwynne
27087a28d1SDavid Gwynne /*
28087a28d1SDavid Gwynne * Copyright (c) 2002, 2010, Oracle and/or its affiliates.
29087a28d1SDavid Gwynne * All rights reserved.
30*4289b4d5SHans Rosenfeld * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
3162387023Sdduvall */
3262387023Sdduvall
33f724721bSzh199473 #include "bge_impl.h"
3462387023Sdduvall #include <sys/sdt.h>
35da14cebeSEric Cheng #include <sys/mac_provider.h>
363fd94f8cSam223141 #include <sys/mac.h>
37da14cebeSEric Cheng #include <sys/mac_flow.h>
3862387023Sdduvall
39087a28d1SDavid Gwynne
40087a28d1SDavid Gwynne #ifndef STRINGIFY
41087a28d1SDavid Gwynne #define XSTRINGIFY(x) #x
42087a28d1SDavid Gwynne #define STRINGIFY(x) XSTRINGIFY(x)
43087a28d1SDavid Gwynne #endif
44087a28d1SDavid Gwynne
4562387023Sdduvall /*
4662387023Sdduvall * This is the string displayed by modinfo, etc.
4727c3238fSyong tan - Sun Microsystems - Beijing China */
4827c3238fSyong tan - Sun Microsystems - Beijing China static char bge_ident[] = "Broadcom Gb Ethernet";
4962387023Sdduvall
5062387023Sdduvall /*
5162387023Sdduvall * Property names
5262387023Sdduvall */
5362387023Sdduvall static char debug_propname[] = "bge-debug-flags";
5462387023Sdduvall static char clsize_propname[] = "cache-line-size";
5562387023Sdduvall static char latency_propname[] = "latency-timer";
5662387023Sdduvall static char localmac_boolname[] = "local-mac-address?";
5762387023Sdduvall static char localmac_propname[] = "local-mac-address";
5862387023Sdduvall static char macaddr_propname[] = "mac-address";
5962387023Sdduvall static char subdev_propname[] = "subsystem-id";
6062387023Sdduvall static char subven_propname[] = "subsystem-vendor-id";
6162387023Sdduvall static char rxrings_propname[] = "bge-rx-rings";
6262387023Sdduvall static char txrings_propname[] = "bge-tx-rings";
63087a28d1SDavid Gwynne static char eee_propname[] = "bge-eee";
6400d0963fSdilpreet static char fm_cap[] = "fm-capable";
651b5c96f3Sly149593 static char default_mtu[] = "default_mtu";
6662387023Sdduvall
6762387023Sdduvall static int bge_add_intrs(bge_t *, int);
6862387023Sdduvall static void bge_rem_intrs(bge_t *);
69da14cebeSEric Cheng static int bge_unicst_set(void *, const uint8_t *, int);
70087a28d1SDavid Gwynne static int bge_addmac(void *, const uint8_t *);
71087a28d1SDavid Gwynne static int bge_remmac(void *, const uint8_t *);
7262387023Sdduvall
7362387023Sdduvall /*
7462387023Sdduvall * Describes the chip's DMA engine
7562387023Sdduvall */
7662387023Sdduvall static ddi_dma_attr_t dma_attr = {
77087a28d1SDavid Gwynne DMA_ATTR_V0, /* dma_attr_version */
7862387023Sdduvall 0x0000000000000000ull, /* dma_attr_addr_lo */
7962387023Sdduvall 0xFFFFFFFFFFFFFFFFull, /* dma_attr_addr_hi */
8062387023Sdduvall 0x00000000FFFFFFFFull, /* dma_attr_count_max */
8162387023Sdduvall 0x0000000000000001ull, /* dma_attr_align */
8262387023Sdduvall 0x00000FFF, /* dma_attr_burstsizes */
8362387023Sdduvall 0x00000001, /* dma_attr_minxfer */
8462387023Sdduvall 0x000000000000FFFFull, /* dma_attr_maxxfer */
85087a28d1SDavid Gwynne 0x00000000FFFFFFFFull, /* dma_attr_seg */
8662387023Sdduvall 1, /* dma_attr_sgllen */
8762387023Sdduvall 0x00000001, /* dma_attr_granular */
8800d0963fSdilpreet DDI_DMA_FLAGERR /* dma_attr_flags */
8962387023Sdduvall };
9062387023Sdduvall
9162387023Sdduvall /*
9262387023Sdduvall * PIO access attributes for registers
9362387023Sdduvall */
9462387023Sdduvall static ddi_device_acc_attr_t bge_reg_accattr = {
95837c1ac4SStephen Hanson DDI_DEVICE_ATTR_V1,
9662387023Sdduvall DDI_NEVERSWAP_ACC,
9700d0963fSdilpreet DDI_STRICTORDER_ACC,
9800d0963fSdilpreet DDI_FLAGERR_ACC
9962387023Sdduvall };
10062387023Sdduvall
10162387023Sdduvall /*
10262387023Sdduvall * DMA access attributes for descriptors: NOT to be byte swapped.
10362387023Sdduvall */
10462387023Sdduvall static ddi_device_acc_attr_t bge_desc_accattr = {
10562387023Sdduvall DDI_DEVICE_ATTR_V0,
10662387023Sdduvall DDI_NEVERSWAP_ACC,
107837c1ac4SStephen Hanson DDI_STRICTORDER_ACC
10862387023Sdduvall };
10962387023Sdduvall
11062387023Sdduvall /*
11162387023Sdduvall * DMA access attributes for data: NOT to be byte swapped.
11262387023Sdduvall */
11362387023Sdduvall static ddi_device_acc_attr_t bge_data_accattr = {
11462387023Sdduvall DDI_DEVICE_ATTR_V0,
11562387023Sdduvall DDI_NEVERSWAP_ACC,
11662387023Sdduvall DDI_STRICTORDER_ACC
11762387023Sdduvall };
11862387023Sdduvall
119ba2e4443Sseb static int bge_m_start(void *);
120ba2e4443Sseb static void bge_m_stop(void *);
121ba2e4443Sseb static int bge_m_promisc(void *, boolean_t);
122087a28d1SDavid Gwynne static int bge_m_unicst(void * pArg, const uint8_t *);
123ba2e4443Sseb static int bge_m_multicst(void *, boolean_t, const uint8_t *);
124087a28d1SDavid Gwynne static void bge_m_resources(void * arg);
125ba2e4443Sseb static void bge_m_ioctl(void *, queue_t *, mblk_t *);
126ba2e4443Sseb static boolean_t bge_m_getcapab(void *, mac_capab_t, void *);
127ed8845d8Skrgopi static int bge_unicst_set(void *, const uint8_t *,
128da14cebeSEric Cheng int);
129e7801d59Ssowmini static int bge_m_setprop(void *, const char *, mac_prop_id_t,
130e7801d59Ssowmini uint_t, const void *);
131e7801d59Ssowmini static int bge_m_getprop(void *, const char *, mac_prop_id_t,
1320dc2366fSVenugopal Iyer uint_t, void *);
1330dc2366fSVenugopal Iyer static void bge_m_propinfo(void *, const char *, mac_prop_id_t,
1340dc2366fSVenugopal Iyer mac_prop_info_handle_t);
135e7801d59Ssowmini static int bge_set_priv_prop(bge_t *, const char *, uint_t,
136e7801d59Ssowmini const void *);
137e7801d59Ssowmini static int bge_get_priv_prop(bge_t *, const char *, uint_t,
1380dc2366fSVenugopal Iyer void *);
1390dc2366fSVenugopal Iyer static void bge_priv_propinfo(const char *,
1400dc2366fSVenugopal Iyer mac_prop_info_handle_t);
141ba2e4443Sseb
142ba2e4443Sseb static mac_callbacks_t bge_m_callbacks = {
143087a28d1SDavid Gwynne MC_IOCTL
144087a28d1SDavid Gwynne #ifdef MC_RESOURCES
145087a28d1SDavid Gwynne | MC_RESOURCES
146087a28d1SDavid Gwynne #endif
147087a28d1SDavid Gwynne #ifdef MC_SETPROP
148087a28d1SDavid Gwynne | MC_SETPROP
149087a28d1SDavid Gwynne #endif
150087a28d1SDavid Gwynne #ifdef MC_GETPROP
151087a28d1SDavid Gwynne | MC_GETPROP
152087a28d1SDavid Gwynne #endif
153087a28d1SDavid Gwynne #ifdef MC_PROPINFO
154087a28d1SDavid Gwynne | MC_PROPINFO
155087a28d1SDavid Gwynne #endif
156087a28d1SDavid Gwynne | MC_GETCAPAB,
157ba2e4443Sseb bge_m_stat,
158ba2e4443Sseb bge_m_start,
159ba2e4443Sseb bge_m_stop,
160ba2e4443Sseb bge_m_promisc,
161ba2e4443Sseb bge_m_multicst,
162087a28d1SDavid Gwynne bge_m_unicst,
163ba2e4443Sseb bge_m_tx,
164087a28d1SDavid Gwynne #ifdef MC_RESOURCES
165087a28d1SDavid Gwynne bge_m_resources,
166087a28d1SDavid Gwynne #else
1670dc2366fSVenugopal Iyer NULL,
168087a28d1SDavid Gwynne #endif
169ba2e4443Sseb bge_m_ioctl,
170e7801d59Ssowmini bge_m_getcapab,
171087a28d1SDavid Gwynne #ifdef MC_OPEN
172e7801d59Ssowmini NULL,
173e7801d59Ssowmini NULL,
174087a28d1SDavid Gwynne #endif
175087a28d1SDavid Gwynne #ifdef MC_SETPROP
176e7801d59Ssowmini bge_m_setprop,
177087a28d1SDavid Gwynne #endif
178087a28d1SDavid Gwynne #ifdef MC_GETPROP
1790dc2366fSVenugopal Iyer bge_m_getprop,
180087a28d1SDavid Gwynne #endif
181087a28d1SDavid Gwynne #ifdef MC_PROPINFO
1820dc2366fSVenugopal Iyer bge_m_propinfo
183087a28d1SDavid Gwynne #endif
184ba2e4443Sseb };
185ba2e4443Sseb
1860dc2366fSVenugopal Iyer char *bge_priv_prop[] = {
1870dc2366fSVenugopal Iyer "_adv_asym_pause_cap",
1880dc2366fSVenugopal Iyer "_adv_pause_cap",
1890dc2366fSVenugopal Iyer "_drain_max",
1900dc2366fSVenugopal Iyer "_msi_cnt",
1910dc2366fSVenugopal Iyer "_rx_intr_coalesce_blank_time",
1920dc2366fSVenugopal Iyer "_tx_intr_coalesce_blank_time",
1930dc2366fSVenugopal Iyer "_rx_intr_coalesce_pkt_cnt",
1940dc2366fSVenugopal Iyer "_tx_intr_coalesce_pkt_cnt",
1950dc2366fSVenugopal Iyer NULL
1964045d941Ssowmini };
1974045d941Ssowmini
198da14cebeSEric Cheng uint8_t zero_addr[6] = {0, 0, 0, 0, 0, 0};
19962387023Sdduvall /*
20062387023Sdduvall * ========== Transmit and receive ring reinitialisation ==========
20162387023Sdduvall */
20262387023Sdduvall
20362387023Sdduvall /*
20462387023Sdduvall * These <reinit> routines each reset the specified ring to an initial
20562387023Sdduvall * state, assuming that the corresponding <init> routine has already
20662387023Sdduvall * been called exactly once.
20762387023Sdduvall */
20862387023Sdduvall
20962387023Sdduvall static void
bge_reinit_send_ring(send_ring_t * srp)21062387023Sdduvall bge_reinit_send_ring(send_ring_t *srp)
21162387023Sdduvall {
212931dca7dSgs150176 bge_queue_t *txbuf_queue;
213931dca7dSgs150176 bge_queue_item_t *txbuf_head;
214931dca7dSgs150176 sw_txbuf_t *txbuf;
215931dca7dSgs150176 sw_sbd_t *ssbdp;
216931dca7dSgs150176 uint32_t slot;
217931dca7dSgs150176
21862387023Sdduvall /*
21962387023Sdduvall * Reinitialise control variables ...
22062387023Sdduvall */
221931dca7dSgs150176 srp->tx_flow = 0;
22262387023Sdduvall srp->tx_next = 0;
223931dca7dSgs150176 srp->txfill_next = 0;
22462387023Sdduvall srp->tx_free = srp->desc.nslots;
22562387023Sdduvall ASSERT(mutex_owned(srp->tc_lock));
22662387023Sdduvall srp->tc_next = 0;
227931dca7dSgs150176 srp->txpkt_next = 0;
228931dca7dSgs150176 srp->tx_block = 0;
229931dca7dSgs150176 srp->tx_nobd = 0;
230931dca7dSgs150176 srp->tx_nobuf = 0;
231931dca7dSgs150176
232931dca7dSgs150176 /*
233931dca7dSgs150176 * Initialize the tx buffer push queue
234931dca7dSgs150176 */
235931dca7dSgs150176 mutex_enter(srp->freetxbuf_lock);
236931dca7dSgs150176 mutex_enter(srp->txbuf_lock);
237931dca7dSgs150176 txbuf_queue = &srp->freetxbuf_queue;
238931dca7dSgs150176 txbuf_queue->head = NULL;
239931dca7dSgs150176 txbuf_queue->count = 0;
240931dca7dSgs150176 txbuf_queue->lock = srp->freetxbuf_lock;
241931dca7dSgs150176 srp->txbuf_push_queue = txbuf_queue;
242931dca7dSgs150176
243931dca7dSgs150176 /*
244931dca7dSgs150176 * Initialize the tx buffer pop queue
245931dca7dSgs150176 */
246931dca7dSgs150176 txbuf_queue = &srp->txbuf_queue;
247931dca7dSgs150176 txbuf_queue->head = NULL;
248931dca7dSgs150176 txbuf_queue->count = 0;
249931dca7dSgs150176 txbuf_queue->lock = srp->txbuf_lock;
250931dca7dSgs150176 srp->txbuf_pop_queue = txbuf_queue;
251931dca7dSgs150176 txbuf_head = srp->txbuf_head;
252931dca7dSgs150176 txbuf = srp->txbuf;
253931dca7dSgs150176 for (slot = 0; slot < srp->tx_buffers; ++slot) {
254931dca7dSgs150176 txbuf_head->item = txbuf;
255931dca7dSgs150176 txbuf_head->next = txbuf_queue->head;
256931dca7dSgs150176 txbuf_queue->head = txbuf_head;
257931dca7dSgs150176 txbuf_queue->count++;
258931dca7dSgs150176 txbuf++;
259931dca7dSgs150176 txbuf_head++;
260931dca7dSgs150176 }
261931dca7dSgs150176 mutex_exit(srp->txbuf_lock);
262931dca7dSgs150176 mutex_exit(srp->freetxbuf_lock);
26362387023Sdduvall
26462387023Sdduvall /*
26562387023Sdduvall * Zero and sync all the h/w Send Buffer Descriptors
26662387023Sdduvall */
26762387023Sdduvall DMA_ZERO(srp->desc);
26862387023Sdduvall DMA_SYNC(srp->desc, DDI_DMA_SYNC_FORDEV);
269931dca7dSgs150176 bzero(srp->pktp, BGE_SEND_BUF_MAX * sizeof (*srp->pktp));
270931dca7dSgs150176 ssbdp = srp->sw_sbds;
271931dca7dSgs150176 for (slot = 0; slot < srp->desc.nslots; ++ssbdp, ++slot)
272931dca7dSgs150176 ssbdp->pbuf = NULL;
27362387023Sdduvall }
27462387023Sdduvall
27562387023Sdduvall static void
bge_reinit_recv_ring(recv_ring_t * rrp)27662387023Sdduvall bge_reinit_recv_ring(recv_ring_t *rrp)
27762387023Sdduvall {
27862387023Sdduvall /*
27962387023Sdduvall * Reinitialise control variables ...
28062387023Sdduvall */
28162387023Sdduvall rrp->rx_next = 0;
28262387023Sdduvall }
28362387023Sdduvall
28462387023Sdduvall static void
bge_reinit_buff_ring(buff_ring_t * brp,uint32_t ring)285931dca7dSgs150176 bge_reinit_buff_ring(buff_ring_t *brp, uint32_t ring)
28662387023Sdduvall {
28762387023Sdduvall bge_rbd_t *hw_rbd_p;
28862387023Sdduvall sw_rbd_t *srbdp;
28962387023Sdduvall uint32_t bufsize;
29062387023Sdduvall uint32_t nslots;
29162387023Sdduvall uint32_t slot;
29262387023Sdduvall
29362387023Sdduvall static uint16_t ring_type_flag[BGE_BUFF_RINGS_MAX] = {
29462387023Sdduvall RBD_FLAG_STD_RING,
29562387023Sdduvall RBD_FLAG_JUMBO_RING,
29662387023Sdduvall RBD_FLAG_MINI_RING
29762387023Sdduvall };
29862387023Sdduvall
29962387023Sdduvall /*
30062387023Sdduvall * Zero, initialise and sync all the h/w Receive Buffer Descriptors
30162387023Sdduvall * Note: all the remaining fields (<type>, <flags>, <ip_cksum>,
30262387023Sdduvall * <tcp_udp_cksum>, <error_flag>, <vlan_tag>, and <reserved>)
30362387023Sdduvall * should be zeroed, and so don't need to be set up specifically
30462387023Sdduvall * once the whole area has been cleared.
30562387023Sdduvall */
30662387023Sdduvall DMA_ZERO(brp->desc);
30762387023Sdduvall
30862387023Sdduvall hw_rbd_p = DMA_VPTR(brp->desc);
30962387023Sdduvall nslots = brp->desc.nslots;
31062387023Sdduvall ASSERT(brp->buf[0].nslots == nslots/BGE_SPLIT);
31162387023Sdduvall bufsize = brp->buf[0].size;
31262387023Sdduvall srbdp = brp->sw_rbds;
31362387023Sdduvall for (slot = 0; slot < nslots; ++hw_rbd_p, ++srbdp, ++slot) {
31462387023Sdduvall hw_rbd_p->host_buf_addr = srbdp->pbuf.cookie.dmac_laddress;
3154a06b59fSyt223700 hw_rbd_p->index = (uint16_t)slot;
3164a06b59fSyt223700 hw_rbd_p->len = (uint16_t)bufsize;
31762387023Sdduvall hw_rbd_p->opaque = srbdp->pbuf.token;
31862387023Sdduvall hw_rbd_p->flags |= ring_type_flag[ring];
31962387023Sdduvall }
32062387023Sdduvall
32162387023Sdduvall DMA_SYNC(brp->desc, DDI_DMA_SYNC_FORDEV);
32262387023Sdduvall
32362387023Sdduvall /*
32462387023Sdduvall * Finally, reinitialise the ring control variables ...
32562387023Sdduvall */
32662387023Sdduvall brp->rf_next = (nslots != 0) ? (nslots-1) : 0;
32762387023Sdduvall }
32862387023Sdduvall
32962387023Sdduvall /*
33062387023Sdduvall * Reinitialize all rings
33162387023Sdduvall */
33262387023Sdduvall static void
bge_reinit_rings(bge_t * bgep)33362387023Sdduvall bge_reinit_rings(bge_t *bgep)
33462387023Sdduvall {
335931dca7dSgs150176 uint32_t ring;
33662387023Sdduvall
33762387023Sdduvall ASSERT(mutex_owned(bgep->genlock));
33862387023Sdduvall
33962387023Sdduvall /*
34062387023Sdduvall * Send Rings ...
34162387023Sdduvall */
34262387023Sdduvall for (ring = 0; ring < bgep->chipid.tx_rings; ++ring)
34362387023Sdduvall bge_reinit_send_ring(&bgep->send[ring]);
34462387023Sdduvall
34562387023Sdduvall /*
34662387023Sdduvall * Receive Return Rings ...
34762387023Sdduvall */
34862387023Sdduvall for (ring = 0; ring < bgep->chipid.rx_rings; ++ring)
34962387023Sdduvall bge_reinit_recv_ring(&bgep->recv[ring]);
35062387023Sdduvall
35162387023Sdduvall /*
35262387023Sdduvall * Receive Producer Rings ...
35362387023Sdduvall */
35462387023Sdduvall for (ring = 0; ring < BGE_BUFF_RINGS_USED; ++ring)
35562387023Sdduvall bge_reinit_buff_ring(&bgep->buff[ring], ring);
35662387023Sdduvall }
35762387023Sdduvall
35862387023Sdduvall /*
35962387023Sdduvall * ========== Internal state management entry points ==========
36062387023Sdduvall */
36162387023Sdduvall
36262387023Sdduvall #undef BGE_DBG
36362387023Sdduvall #define BGE_DBG BGE_DBG_NEMO /* debug flag for this code */
36462387023Sdduvall
36562387023Sdduvall /*
36662387023Sdduvall * These routines provide all the functionality required by the
36762387023Sdduvall * corresponding GLD entry points, but don't update the GLD state
36862387023Sdduvall * so they can be called internally without disturbing our record
36962387023Sdduvall * of what GLD thinks we should be doing ...
37062387023Sdduvall */
37162387023Sdduvall
37262387023Sdduvall /*
37362387023Sdduvall * bge_reset() -- reset h/w & rings to initial state
37462387023Sdduvall */
37500d0963fSdilpreet static int
37667f02347Srandyf #ifdef BGE_IPMI_ASF
bge_reset(bge_t * bgep,uint_t asf_mode)37767f02347Srandyf bge_reset(bge_t *bgep, uint_t asf_mode)
37867f02347Srandyf #else
37962387023Sdduvall bge_reset(bge_t *bgep)
38067f02347Srandyf #endif
38162387023Sdduvall {
382931dca7dSgs150176 uint32_t ring;
38300d0963fSdilpreet int retval;
38462387023Sdduvall
38562387023Sdduvall BGE_TRACE(("bge_reset($%p)", (void *)bgep));
38662387023Sdduvall
38762387023Sdduvall ASSERT(mutex_owned(bgep->genlock));
38862387023Sdduvall
38962387023Sdduvall /*
39062387023Sdduvall * Grab all the other mutexes in the world (this should
39162387023Sdduvall * ensure no other threads are manipulating driver state)
39262387023Sdduvall */
39362387023Sdduvall for (ring = 0; ring < BGE_RECV_RINGS_MAX; ++ring)
39462387023Sdduvall mutex_enter(bgep->recv[ring].rx_lock);
39562387023Sdduvall for (ring = 0; ring < BGE_BUFF_RINGS_MAX; ++ring)
39662387023Sdduvall mutex_enter(bgep->buff[ring].rf_lock);
39762387023Sdduvall rw_enter(bgep->errlock, RW_WRITER);
39862387023Sdduvall for (ring = 0; ring < BGE_SEND_RINGS_MAX; ++ring)
399931dca7dSgs150176 mutex_enter(bgep->send[ring].tx_lock);
400931dca7dSgs150176 for (ring = 0; ring < BGE_SEND_RINGS_MAX; ++ring)
40162387023Sdduvall mutex_enter(bgep->send[ring].tc_lock);
40262387023Sdduvall
40367f02347Srandyf #ifdef BGE_IPMI_ASF
40400d0963fSdilpreet retval = bge_chip_reset(bgep, B_TRUE, asf_mode);
40567f02347Srandyf #else
40600d0963fSdilpreet retval = bge_chip_reset(bgep, B_TRUE);
40767f02347Srandyf #endif
40862387023Sdduvall bge_reinit_rings(bgep);
40962387023Sdduvall
41062387023Sdduvall /*
41162387023Sdduvall * Free the world ...
41262387023Sdduvall */
41362387023Sdduvall for (ring = BGE_SEND_RINGS_MAX; ring-- > 0; )
41462387023Sdduvall mutex_exit(bgep->send[ring].tc_lock);
415931dca7dSgs150176 for (ring = 0; ring < BGE_SEND_RINGS_MAX; ++ring)
416931dca7dSgs150176 mutex_exit(bgep->send[ring].tx_lock);
41762387023Sdduvall rw_exit(bgep->errlock);
41862387023Sdduvall for (ring = BGE_BUFF_RINGS_MAX; ring-- > 0; )
41962387023Sdduvall mutex_exit(bgep->buff[ring].rf_lock);
42062387023Sdduvall for (ring = BGE_RECV_RINGS_MAX; ring-- > 0; )
42162387023Sdduvall mutex_exit(bgep->recv[ring].rx_lock);
42262387023Sdduvall
42362387023Sdduvall BGE_DEBUG(("bge_reset($%p) done", (void *)bgep));
42400d0963fSdilpreet return (retval);
42562387023Sdduvall }
42662387023Sdduvall
42762387023Sdduvall /*
42862387023Sdduvall * bge_stop() -- stop processing, don't reset h/w or rings
42962387023Sdduvall */
43062387023Sdduvall static void
bge_stop(bge_t * bgep)43162387023Sdduvall bge_stop(bge_t *bgep)
43262387023Sdduvall {
43362387023Sdduvall BGE_TRACE(("bge_stop($%p)", (void *)bgep));
43462387023Sdduvall
43562387023Sdduvall ASSERT(mutex_owned(bgep->genlock));
43662387023Sdduvall
43767f02347Srandyf #ifdef BGE_IPMI_ASF
43867f02347Srandyf if (bgep->asf_enabled) {
43967f02347Srandyf bgep->asf_pseudostop = B_TRUE;
44067f02347Srandyf } else {
44167f02347Srandyf #endif
44262387023Sdduvall bge_chip_stop(bgep, B_FALSE);
44367f02347Srandyf #ifdef BGE_IPMI_ASF
44467f02347Srandyf }
44567f02347Srandyf #endif
44662387023Sdduvall
44762387023Sdduvall BGE_DEBUG(("bge_stop($%p) done", (void *)bgep));
44862387023Sdduvall }
44962387023Sdduvall
45062387023Sdduvall /*
45162387023Sdduvall * bge_start() -- start transmitting/receiving
45262387023Sdduvall */
45300d0963fSdilpreet static int
bge_start(bge_t * bgep,boolean_t reset_phys)45462387023Sdduvall bge_start(bge_t *bgep, boolean_t reset_phys)
45562387023Sdduvall {
45600d0963fSdilpreet int retval;
45700d0963fSdilpreet
45862387023Sdduvall BGE_TRACE(("bge_start($%p, %d)", (void *)bgep, reset_phys));
45962387023Sdduvall
46062387023Sdduvall ASSERT(mutex_owned(bgep->genlock));
46162387023Sdduvall
46262387023Sdduvall /*
46362387023Sdduvall * Start chip processing, including enabling interrupts
46462387023Sdduvall */
46500d0963fSdilpreet retval = bge_chip_start(bgep, reset_phys);
46662387023Sdduvall
46762387023Sdduvall BGE_DEBUG(("bge_start($%p, %d) done", (void *)bgep, reset_phys));
46800d0963fSdilpreet return (retval);
46962387023Sdduvall }
47062387023Sdduvall
47162387023Sdduvall /*
47262387023Sdduvall * bge_restart - restart transmitting/receiving after error or suspend
47362387023Sdduvall */
47400d0963fSdilpreet int
bge_restart(bge_t * bgep,boolean_t reset_phys)47562387023Sdduvall bge_restart(bge_t *bgep, boolean_t reset_phys)
47662387023Sdduvall {
47700d0963fSdilpreet int retval = DDI_SUCCESS;
47862387023Sdduvall ASSERT(mutex_owned(bgep->genlock));
47962387023Sdduvall
48067f02347Srandyf #ifdef BGE_IPMI_ASF
48167f02347Srandyf if (bgep->asf_enabled) {
48200d0963fSdilpreet if (bge_reset(bgep, ASF_MODE_POST_INIT) != DDI_SUCCESS)
48300d0963fSdilpreet retval = DDI_FAILURE;
48467f02347Srandyf } else
48500d0963fSdilpreet if (bge_reset(bgep, ASF_MODE_NONE) != DDI_SUCCESS)
48600d0963fSdilpreet retval = DDI_FAILURE;
48767f02347Srandyf #else
48800d0963fSdilpreet if (bge_reset(bgep) != DDI_SUCCESS)
48900d0963fSdilpreet retval = DDI_FAILURE;
49067f02347Srandyf #endif
491c77e0fa5Szh199473 if (bgep->bge_mac_state == BGE_MAC_STARTED) {
49200d0963fSdilpreet if (bge_start(bgep, reset_phys) != DDI_SUCCESS)
49300d0963fSdilpreet retval = DDI_FAILURE;
49462387023Sdduvall bgep->watchdog = 0;
495931dca7dSgs150176 ddi_trigger_softintr(bgep->drain_id);
49662387023Sdduvall }
49762387023Sdduvall
49862387023Sdduvall BGE_DEBUG(("bge_restart($%p, %d) done", (void *)bgep, reset_phys));
49900d0963fSdilpreet return (retval);
50062387023Sdduvall }
50162387023Sdduvall
50262387023Sdduvall
50362387023Sdduvall /*
50462387023Sdduvall * ========== Nemo-required management entry points ==========
50562387023Sdduvall */
50662387023Sdduvall
50762387023Sdduvall #undef BGE_DBG
50862387023Sdduvall #define BGE_DBG BGE_DBG_NEMO /* debug flag for this code */
50962387023Sdduvall
51062387023Sdduvall /*
51162387023Sdduvall * bge_m_stop() -- stop transmitting/receiving
51262387023Sdduvall */
51362387023Sdduvall static void
bge_m_stop(void * arg)51462387023Sdduvall bge_m_stop(void *arg)
51562387023Sdduvall {
51662387023Sdduvall bge_t *bgep = arg; /* private device info */
517931dca7dSgs150176 send_ring_t *srp;
518931dca7dSgs150176 uint32_t ring;
51962387023Sdduvall
52062387023Sdduvall BGE_TRACE(("bge_m_stop($%p)", arg));
52162387023Sdduvall
52262387023Sdduvall /*
52362387023Sdduvall * Just stop processing, then record new GLD state
52462387023Sdduvall */
52562387023Sdduvall mutex_enter(bgep->genlock);
52600d0963fSdilpreet if (!(bgep->progress & PROGRESS_INTR)) {
52700d0963fSdilpreet /* can happen during autorecovery */
52827c3238fSyong tan - Sun Microsystems - Beijing China bgep->bge_chip_state = BGE_CHIP_STOPPED;
52927c3238fSyong tan - Sun Microsystems - Beijing China } else
53062387023Sdduvall bge_stop(bgep);
531dca582a1Sgh162552
532dca582a1Sgh162552 bgep->link_state = LINK_STATE_UNKNOWN;
533dca582a1Sgh162552 mac_link_update(bgep->mh, bgep->link_state);
534dca582a1Sgh162552
535931dca7dSgs150176 /*
536931dca7dSgs150176 * Free the possible tx buffers allocated in tx process.
537931dca7dSgs150176 */
538931dca7dSgs150176 #ifdef BGE_IPMI_ASF
539931dca7dSgs150176 if (!bgep->asf_pseudostop)
540931dca7dSgs150176 #endif
541931dca7dSgs150176 {
542931dca7dSgs150176 rw_enter(bgep->errlock, RW_WRITER);
543931dca7dSgs150176 for (ring = 0; ring < bgep->chipid.tx_rings; ++ring) {
544931dca7dSgs150176 srp = &bgep->send[ring];
545931dca7dSgs150176 mutex_enter(srp->tx_lock);
546931dca7dSgs150176 if (srp->tx_array > 1)
547931dca7dSgs150176 bge_free_txbuf_arrays(srp);
548931dca7dSgs150176 mutex_exit(srp->tx_lock);
549931dca7dSgs150176 }
550931dca7dSgs150176 rw_exit(bgep->errlock);
551931dca7dSgs150176 }
55262387023Sdduvall bgep->bge_mac_state = BGE_MAC_STOPPED;
55362387023Sdduvall BGE_DEBUG(("bge_m_stop($%p) done", arg));
55400d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK)
55500d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_UNAFFECTED);
55662387023Sdduvall mutex_exit(bgep->genlock);
55762387023Sdduvall }
55862387023Sdduvall
55962387023Sdduvall /*
56062387023Sdduvall * bge_m_start() -- start transmitting/receiving
56162387023Sdduvall */
56262387023Sdduvall static int
bge_m_start(void * arg)56362387023Sdduvall bge_m_start(void *arg)
56462387023Sdduvall {
56562387023Sdduvall bge_t *bgep = arg; /* private device info */
56662387023Sdduvall
56762387023Sdduvall BGE_TRACE(("bge_m_start($%p)", arg));
56862387023Sdduvall
56962387023Sdduvall /*
57062387023Sdduvall * Start processing and record new GLD state
57162387023Sdduvall */
57262387023Sdduvall mutex_enter(bgep->genlock);
57300d0963fSdilpreet if (!(bgep->progress & PROGRESS_INTR)) {
57400d0963fSdilpreet /* can happen during autorecovery */
57500d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED);
57600d0963fSdilpreet mutex_exit(bgep->genlock);
57700d0963fSdilpreet return (EIO);
57800d0963fSdilpreet }
57967f02347Srandyf #ifdef BGE_IPMI_ASF
58067f02347Srandyf if (bgep->asf_enabled) {
58167f02347Srandyf if ((bgep->asf_status == ASF_STAT_RUN) &&
58267f02347Srandyf (bgep->asf_pseudostop)) {
58367f02347Srandyf bgep->bge_mac_state = BGE_MAC_STARTED;
584087a28d1SDavid Gwynne /* forcing a mac link update here */
585087a28d1SDavid Gwynne bge_phys_check(bgep);
586087a28d1SDavid Gwynne bgep->link_state = (bgep->param_link_up) ? LINK_STATE_UP :
587087a28d1SDavid Gwynne LINK_STATE_DOWN;
588087a28d1SDavid Gwynne mac_link_update(bgep->mh, bgep->link_state);
58967f02347Srandyf mutex_exit(bgep->genlock);
59067f02347Srandyf return (0);
59167f02347Srandyf }
59267f02347Srandyf }
59300d0963fSdilpreet if (bge_reset(bgep, ASF_MODE_INIT) != DDI_SUCCESS) {
59467f02347Srandyf #else
59500d0963fSdilpreet if (bge_reset(bgep) != DDI_SUCCESS) {
59667f02347Srandyf #endif
59700d0963fSdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle);
59800d0963fSdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle);
59900d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED);
60000d0963fSdilpreet mutex_exit(bgep->genlock);
60100d0963fSdilpreet return (EIO);
60200d0963fSdilpreet }
60300d0963fSdilpreet if (bge_start(bgep, B_TRUE) != DDI_SUCCESS) {
60400d0963fSdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle);
60500d0963fSdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle);
60600d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED);
60700d0963fSdilpreet mutex_exit(bgep->genlock);
60800d0963fSdilpreet return (EIO);
60900d0963fSdilpreet }
6106adbf114Syong tan - Sun Microsystems - Beijing China bgep->watchdog = 0;
61162387023Sdduvall bgep->bge_mac_state = BGE_MAC_STARTED;
61262387023Sdduvall BGE_DEBUG(("bge_m_start($%p) done", arg));
61367f02347Srandyf
61400d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) {
61500d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED);
61600d0963fSdilpreet mutex_exit(bgep->genlock);
61700d0963fSdilpreet return (EIO);
61800d0963fSdilpreet }
61900d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) {
62000d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED);
62100d0963fSdilpreet mutex_exit(bgep->genlock);
62200d0963fSdilpreet return (EIO);
62300d0963fSdilpreet }
62467f02347Srandyf #ifdef BGE_IPMI_ASF
62567f02347Srandyf if (bgep->asf_enabled) {
62667f02347Srandyf if (bgep->asf_status != ASF_STAT_RUN) {
62767f02347Srandyf /* start ASF heart beat */
62867f02347Srandyf bgep->asf_timeout_id = timeout(bge_asf_heartbeat,
62967f02347Srandyf (void *)bgep,
63067f02347Srandyf drv_usectohz(BGE_ASF_HEARTBEAT_INTERVAL));
63167f02347Srandyf bgep->asf_status = ASF_STAT_RUN;
63267f02347Srandyf }
63367f02347Srandyf }
63467f02347Srandyf #endif
63562387023Sdduvall mutex_exit(bgep->genlock);
63662387023Sdduvall
63762387023Sdduvall return (0);
63862387023Sdduvall }
63962387023Sdduvall
64062387023Sdduvall /*
641ed8845d8Skrgopi * bge_unicst_set() -- set the physical network address
642ed8845d8Skrgopi */
643ed8845d8Skrgopi static int
644da14cebeSEric Cheng bge_unicst_set(void *arg, const uint8_t *macaddr, int slot)
645ed8845d8Skrgopi {
64662387023Sdduvall bge_t *bgep = arg; /* private device info */
64762387023Sdduvall
648087a28d1SDavid Gwynne BGE_TRACE(("bge_unicst_set($%p, %s)", arg,
64962387023Sdduvall ether_sprintf((void *)macaddr)));
65062387023Sdduvall /*
65162387023Sdduvall * Remember the new current address in the driver state
65262387023Sdduvall * Sync the chip's idea of the address too ...
65362387023Sdduvall */
65462387023Sdduvall mutex_enter(bgep->genlock);
65500d0963fSdilpreet if (!(bgep->progress & PROGRESS_INTR)) {
65600d0963fSdilpreet /* can happen during autorecovery */
65700d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED);
65800d0963fSdilpreet mutex_exit(bgep->genlock);
65900d0963fSdilpreet return (EIO);
66000d0963fSdilpreet }
661ed8845d8Skrgopi ethaddr_copy(macaddr, bgep->curr_addr[slot].addr);
66267f02347Srandyf #ifdef BGE_IPMI_ASF
66300d0963fSdilpreet if (bge_chip_sync(bgep, B_FALSE) == DDI_FAILURE) {
66400d0963fSdilpreet #else
66500d0963fSdilpreet if (bge_chip_sync(bgep) == DDI_FAILURE) {
66600d0963fSdilpreet #endif
66700d0963fSdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle);
66800d0963fSdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle);
66900d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED);
67000d0963fSdilpreet mutex_exit(bgep->genlock);
67100d0963fSdilpreet return (EIO);
67200d0963fSdilpreet }
67300d0963fSdilpreet #ifdef BGE_IPMI_ASF
67467f02347Srandyf if (bgep->asf_enabled) {
67567f02347Srandyf /*
67667f02347Srandyf * The above bge_chip_sync() function wrote the ethernet MAC
67767f02347Srandyf * addresses registers which destroyed the IPMI/ASF sideband.
67867f02347Srandyf * Here, we have to reset chip to make IPMI/ASF sideband work.
67967f02347Srandyf */
68067f02347Srandyf if (bgep->asf_status == ASF_STAT_RUN) {
68167f02347Srandyf /*
68267f02347Srandyf * We must stop ASF heart beat before bge_chip_stop(),
68367f02347Srandyf * otherwise some computers (ex. IBM HS20 blade server)
68467f02347Srandyf * may crash.
68567f02347Srandyf */
68667f02347Srandyf bge_asf_update_status(bgep);
68767f02347Srandyf bge_asf_stop_timer(bgep);
68867f02347Srandyf bgep->asf_status = ASF_STAT_STOP;
68967f02347Srandyf
69067f02347Srandyf bge_asf_pre_reset_operations(bgep, BGE_INIT_RESET);
69167f02347Srandyf }
69200d0963fSdilpreet bge_chip_stop(bgep, B_FALSE);
69367f02347Srandyf
69400d0963fSdilpreet if (bge_restart(bgep, B_FALSE) == DDI_FAILURE) {
69500d0963fSdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle);
69600d0963fSdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle);
69700d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo,
69800d0963fSdilpreet DDI_SERVICE_DEGRADED);
69900d0963fSdilpreet mutex_exit(bgep->genlock);
70000d0963fSdilpreet return (EIO);
70100d0963fSdilpreet }
70200d0963fSdilpreet
70367f02347Srandyf /*
70467f02347Srandyf * Start our ASF heartbeat counter as soon as possible.
70567f02347Srandyf */
70667f02347Srandyf if (bgep->asf_status != ASF_STAT_RUN) {
70767f02347Srandyf /* start ASF heart beat */
70867f02347Srandyf bgep->asf_timeout_id = timeout(bge_asf_heartbeat,
70967f02347Srandyf (void *)bgep,
71067f02347Srandyf drv_usectohz(BGE_ASF_HEARTBEAT_INTERVAL));
71167f02347Srandyf bgep->asf_status = ASF_STAT_RUN;
71267f02347Srandyf }
71367f02347Srandyf }
71467f02347Srandyf #endif
715087a28d1SDavid Gwynne BGE_DEBUG(("bge_unicst_set($%p) done", arg));
71600d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) {
71700d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED);
71800d0963fSdilpreet mutex_exit(bgep->genlock);
71900d0963fSdilpreet return (EIO);
72000d0963fSdilpreet }
72100d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) {
72200d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED);
72300d0963fSdilpreet mutex_exit(bgep->genlock);
72400d0963fSdilpreet return (EIO);
72500d0963fSdilpreet }
72662387023Sdduvall mutex_exit(bgep->genlock);
72762387023Sdduvall
72862387023Sdduvall return (0);
72962387023Sdduvall }
73062387023Sdduvall
731e7801d59Ssowmini extern void bge_wake_factotum(bge_t *);
732e7801d59Ssowmini
733e7801d59Ssowmini static boolean_t
734e7801d59Ssowmini bge_param_locked(mac_prop_id_t pr_num)
735e7801d59Ssowmini {
736e7801d59Ssowmini /*
737e7801d59Ssowmini * All adv_* parameters are locked (read-only) while
738e7801d59Ssowmini * the device is in any sort of loopback mode ...
739e7801d59Ssowmini */
740e7801d59Ssowmini switch (pr_num) {
7413fd94f8cSam223141 case MAC_PROP_ADV_1000FDX_CAP:
7423fd94f8cSam223141 case MAC_PROP_EN_1000FDX_CAP:
7433fd94f8cSam223141 case MAC_PROP_ADV_1000HDX_CAP:
7443fd94f8cSam223141 case MAC_PROP_EN_1000HDX_CAP:
7453fd94f8cSam223141 case MAC_PROP_ADV_100FDX_CAP:
7463fd94f8cSam223141 case MAC_PROP_EN_100FDX_CAP:
7473fd94f8cSam223141 case MAC_PROP_ADV_100HDX_CAP:
7483fd94f8cSam223141 case MAC_PROP_EN_100HDX_CAP:
7493fd94f8cSam223141 case MAC_PROP_ADV_10FDX_CAP:
7503fd94f8cSam223141 case MAC_PROP_EN_10FDX_CAP:
7513fd94f8cSam223141 case MAC_PROP_ADV_10HDX_CAP:
7523fd94f8cSam223141 case MAC_PROP_EN_10HDX_CAP:
7533fd94f8cSam223141 case MAC_PROP_AUTONEG:
7543fd94f8cSam223141 case MAC_PROP_FLOWCTRL:
755e7801d59Ssowmini return (B_TRUE);
756e7801d59Ssowmini }
757e7801d59Ssowmini return (B_FALSE);
758e7801d59Ssowmini }
759e7801d59Ssowmini /*
760e7801d59Ssowmini * callback functions for set/get of properties
761e7801d59Ssowmini */
762e7801d59Ssowmini static int
763e7801d59Ssowmini bge_m_setprop(void *barg, const char *pr_name, mac_prop_id_t pr_num,
764e7801d59Ssowmini uint_t pr_valsize, const void *pr_val)
765e7801d59Ssowmini {
766e7801d59Ssowmini bge_t *bgep = barg;
767e7801d59Ssowmini int err = 0;
7684045d941Ssowmini uint32_t cur_mtu, new_mtu;
769e7801d59Ssowmini link_flowctrl_t fl;
770e7801d59Ssowmini
771e7801d59Ssowmini mutex_enter(bgep->genlock);
772e7801d59Ssowmini if (bgep->param_loop_mode != BGE_LOOP_NONE &&
773e7801d59Ssowmini bge_param_locked(pr_num)) {
774e7801d59Ssowmini /*
775e7801d59Ssowmini * All adv_* parameters are locked (read-only)
776e7801d59Ssowmini * while the device is in any sort of loopback mode.
777e7801d59Ssowmini */
778e7801d59Ssowmini mutex_exit(bgep->genlock);
779e7801d59Ssowmini return (EBUSY);
780e7801d59Ssowmini }
7814045d941Ssowmini if ((bgep->chipid.flags & CHIP_FLAG_SERDES) &&
7823fd94f8cSam223141 ((pr_num == MAC_PROP_EN_100FDX_CAP) ||
783afdda45fSVasumathi Sundaram - Sun Microsystems (pr_num == MAC_PROP_EN_100HDX_CAP) ||
7843fd94f8cSam223141 (pr_num == MAC_PROP_EN_10FDX_CAP) ||
7853fd94f8cSam223141 (pr_num == MAC_PROP_EN_10HDX_CAP))) {
7864045d941Ssowmini /*
7874045d941Ssowmini * these properties are read/write on copper,
7884045d941Ssowmini * read-only and 0 on serdes
7894045d941Ssowmini */
7904045d941Ssowmini mutex_exit(bgep->genlock);
7914045d941Ssowmini return (ENOTSUP);
7924045d941Ssowmini }
79327c3238fSyong tan - Sun Microsystems - Beijing China if (DEVICE_5906_SERIES_CHIPSETS(bgep) &&
79427c3238fSyong tan - Sun Microsystems - Beijing China ((pr_num == MAC_PROP_EN_1000FDX_CAP) ||
7955a506a18Syong tan - Sun Microsystems - Beijing China (pr_num == MAC_PROP_EN_1000HDX_CAP))) {
7965a506a18Syong tan - Sun Microsystems - Beijing China mutex_exit(bgep->genlock);
7975a506a18Syong tan - Sun Microsystems - Beijing China return (ENOTSUP);
7985a506a18Syong tan - Sun Microsystems - Beijing China }
7994045d941Ssowmini
800e7801d59Ssowmini switch (pr_num) {
8013fd94f8cSam223141 case MAC_PROP_EN_1000FDX_CAP:
802e7801d59Ssowmini bgep->param_en_1000fdx = *(uint8_t *)pr_val;
803e7801d59Ssowmini bgep->param_adv_1000fdx = *(uint8_t *)pr_val;
804e7801d59Ssowmini goto reprogram;
8053fd94f8cSam223141 case MAC_PROP_EN_1000HDX_CAP:
806e7801d59Ssowmini bgep->param_en_1000hdx = *(uint8_t *)pr_val;
807e7801d59Ssowmini bgep->param_adv_1000hdx = *(uint8_t *)pr_val;
808e7801d59Ssowmini goto reprogram;
8093fd94f8cSam223141 case MAC_PROP_EN_100FDX_CAP:
810e7801d59Ssowmini bgep->param_en_100fdx = *(uint8_t *)pr_val;
811e7801d59Ssowmini bgep->param_adv_100fdx = *(uint8_t *)pr_val;
812e7801d59Ssowmini goto reprogram;
8133fd94f8cSam223141 case MAC_PROP_EN_100HDX_CAP:
814e7801d59Ssowmini bgep->param_en_100hdx = *(uint8_t *)pr_val;
815e7801d59Ssowmini bgep->param_adv_100hdx = *(uint8_t *)pr_val;
816e7801d59Ssowmini goto reprogram;
8173fd94f8cSam223141 case MAC_PROP_EN_10FDX_CAP:
818e7801d59Ssowmini bgep->param_en_10fdx = *(uint8_t *)pr_val;
819e7801d59Ssowmini bgep->param_adv_10fdx = *(uint8_t *)pr_val;
820e7801d59Ssowmini goto reprogram;
8213fd94f8cSam223141 case MAC_PROP_EN_10HDX_CAP:
822e7801d59Ssowmini bgep->param_en_10hdx = *(uint8_t *)pr_val;
823e7801d59Ssowmini bgep->param_adv_10hdx = *(uint8_t *)pr_val;
824e7801d59Ssowmini reprogram:
825e7801d59Ssowmini if (err == 0 && bge_reprogram(bgep) == IOC_INVAL)
826e7801d59Ssowmini err = EINVAL;
827e7801d59Ssowmini break;
8283fd94f8cSam223141 case MAC_PROP_ADV_1000FDX_CAP:
8293fd94f8cSam223141 case MAC_PROP_ADV_1000HDX_CAP:
8303fd94f8cSam223141 case MAC_PROP_ADV_100FDX_CAP:
8313fd94f8cSam223141 case MAC_PROP_ADV_100HDX_CAP:
8323fd94f8cSam223141 case MAC_PROP_ADV_10FDX_CAP:
8333fd94f8cSam223141 case MAC_PROP_ADV_10HDX_CAP:
8343fd94f8cSam223141 case MAC_PROP_STATUS:
8353fd94f8cSam223141 case MAC_PROP_SPEED:
8363fd94f8cSam223141 case MAC_PROP_DUPLEX:
8374045d941Ssowmini err = ENOTSUP; /* read-only prop. Can't set this */
838e7801d59Ssowmini break;
8393fd94f8cSam223141 case MAC_PROP_AUTONEG:
840e7801d59Ssowmini bgep->param_adv_autoneg = *(uint8_t *)pr_val;
841e7801d59Ssowmini if (bge_reprogram(bgep) == IOC_INVAL)
842e7801d59Ssowmini err = EINVAL;
843e7801d59Ssowmini break;
8443fd94f8cSam223141 case MAC_PROP_MTU:
845e7801d59Ssowmini cur_mtu = bgep->chipid.default_mtu;
846e7801d59Ssowmini bcopy(pr_val, &new_mtu, sizeof (new_mtu));
8474045d941Ssowmini
848e7801d59Ssowmini if (new_mtu == cur_mtu) {
849e7801d59Ssowmini err = 0;
850e7801d59Ssowmini break;
851e7801d59Ssowmini }
852e7801d59Ssowmini if (new_mtu < BGE_DEFAULT_MTU ||
853e7801d59Ssowmini new_mtu > BGE_MAXIMUM_MTU) {
854e7801d59Ssowmini err = EINVAL;
855e7801d59Ssowmini break;
856e7801d59Ssowmini }
857e7801d59Ssowmini if ((new_mtu > BGE_DEFAULT_MTU) &&
858e7801d59Ssowmini (bgep->chipid.flags & CHIP_FLAG_NO_JUMBO)) {
859e7801d59Ssowmini err = EINVAL;
860e7801d59Ssowmini break;
861e7801d59Ssowmini }
862e7801d59Ssowmini if (bgep->bge_mac_state == BGE_MAC_STARTED) {
863e7801d59Ssowmini err = EBUSY;
864e7801d59Ssowmini break;
865e7801d59Ssowmini }
866e7801d59Ssowmini bgep->chipid.default_mtu = new_mtu;
867e7801d59Ssowmini if (bge_chip_id_init(bgep)) {
868e7801d59Ssowmini err = EINVAL;
869e7801d59Ssowmini break;
870e7801d59Ssowmini }
871e7801d59Ssowmini bgep->bge_dma_error = B_TRUE;
872e7801d59Ssowmini bgep->manual_reset = B_TRUE;
873e7801d59Ssowmini bge_chip_stop(bgep, B_TRUE);
874e7801d59Ssowmini bge_wake_factotum(bgep);
875e7801d59Ssowmini err = 0;
876e7801d59Ssowmini break;
8773fd94f8cSam223141 case MAC_PROP_FLOWCTRL:
878e7801d59Ssowmini bcopy(pr_val, &fl, sizeof (fl));
879e7801d59Ssowmini switch (fl) {
880e7801d59Ssowmini default:
8814045d941Ssowmini err = ENOTSUP;
882e7801d59Ssowmini break;
883e7801d59Ssowmini case LINK_FLOWCTRL_NONE:
884e7801d59Ssowmini bgep->param_adv_pause = 0;
885e7801d59Ssowmini bgep->param_adv_asym_pause = 0;
886e7801d59Ssowmini
887e7801d59Ssowmini bgep->param_link_rx_pause = B_FALSE;
888e7801d59Ssowmini bgep->param_link_tx_pause = B_FALSE;
889e7801d59Ssowmini break;
890e7801d59Ssowmini case LINK_FLOWCTRL_RX:
891e7801d59Ssowmini bgep->param_adv_pause = 1;
892e7801d59Ssowmini bgep->param_adv_asym_pause = 1;
893e7801d59Ssowmini
894e7801d59Ssowmini bgep->param_link_rx_pause = B_TRUE;
895e7801d59Ssowmini bgep->param_link_tx_pause = B_FALSE;
896e7801d59Ssowmini break;
897e7801d59Ssowmini case LINK_FLOWCTRL_TX:
898e7801d59Ssowmini bgep->param_adv_pause = 0;
899e7801d59Ssowmini bgep->param_adv_asym_pause = 1;
900e7801d59Ssowmini
901e7801d59Ssowmini bgep->param_link_rx_pause = B_FALSE;
902e7801d59Ssowmini bgep->param_link_tx_pause = B_TRUE;
903e7801d59Ssowmini break;
904e7801d59Ssowmini case LINK_FLOWCTRL_BI:
905e7801d59Ssowmini bgep->param_adv_pause = 1;
90627c3238fSyong tan - Sun Microsystems - Beijing China bgep->param_adv_asym_pause = 0;
907e7801d59Ssowmini
908e7801d59Ssowmini bgep->param_link_rx_pause = B_TRUE;
909e7801d59Ssowmini bgep->param_link_tx_pause = B_TRUE;
910e7801d59Ssowmini break;
911e7801d59Ssowmini }
912e7801d59Ssowmini
913e7801d59Ssowmini if (err == 0) {
914e7801d59Ssowmini if (bge_reprogram(bgep) == IOC_INVAL)
915e7801d59Ssowmini err = EINVAL;
916e7801d59Ssowmini }
917e7801d59Ssowmini
918e7801d59Ssowmini break;
9193fd94f8cSam223141 case MAC_PROP_PRIVATE:
920e7801d59Ssowmini err = bge_set_priv_prop(bgep, pr_name, pr_valsize,
921e7801d59Ssowmini pr_val);
922e7801d59Ssowmini break;
9234045d941Ssowmini default:
9244045d941Ssowmini err = ENOTSUP;
9254045d941Ssowmini break;
926e7801d59Ssowmini }
927e7801d59Ssowmini mutex_exit(bgep->genlock);
928e7801d59Ssowmini return (err);
929e7801d59Ssowmini }
9304045d941Ssowmini
931afdda45fSVasumathi Sundaram - Sun Microsystems /* ARGSUSED */
932e7801d59Ssowmini static int
933e7801d59Ssowmini bge_m_getprop(void *barg, const char *pr_name, mac_prop_id_t pr_num,
9340dc2366fSVenugopal Iyer uint_t pr_valsize, void *pr_val)
935e7801d59Ssowmini {
936e7801d59Ssowmini bge_t *bgep = barg;
937e7801d59Ssowmini int err = 0;
938afdda45fSVasumathi Sundaram - Sun Microsystems
939e7801d59Ssowmini switch (pr_num) {
9403fd94f8cSam223141 case MAC_PROP_DUPLEX:
9410dc2366fSVenugopal Iyer ASSERT(pr_valsize >= sizeof (link_duplex_t));
9424045d941Ssowmini bcopy(&bgep->param_link_duplex, pr_val,
9434045d941Ssowmini sizeof (link_duplex_t));
944e7801d59Ssowmini break;
9450dc2366fSVenugopal Iyer case MAC_PROP_SPEED: {
9460dc2366fSVenugopal Iyer uint64_t speed = bgep->param_link_speed * 1000000ull;
9470dc2366fSVenugopal Iyer
9480dc2366fSVenugopal Iyer ASSERT(pr_valsize >= sizeof (speed));
9494045d941Ssowmini bcopy(&speed, pr_val, sizeof (speed));
950e7801d59Ssowmini break;
9510dc2366fSVenugopal Iyer }
9523fd94f8cSam223141 case MAC_PROP_STATUS:
9530dc2366fSVenugopal Iyer ASSERT(pr_valsize >= sizeof (link_state_t));
9544045d941Ssowmini bcopy(&bgep->link_state, pr_val,
9554045d941Ssowmini sizeof (link_state_t));
956e7801d59Ssowmini break;
9573fd94f8cSam223141 case MAC_PROP_AUTONEG:
958e7801d59Ssowmini *(uint8_t *)pr_val = bgep->param_adv_autoneg;
959e7801d59Ssowmini break;
9600dc2366fSVenugopal Iyer case MAC_PROP_FLOWCTRL: {
9610dc2366fSVenugopal Iyer link_flowctrl_t fl;
9620dc2366fSVenugopal Iyer
9630dc2366fSVenugopal Iyer ASSERT(pr_valsize >= sizeof (fl));
9644045d941Ssowmini
965e7801d59Ssowmini if (bgep->param_link_rx_pause &&
966e7801d59Ssowmini !bgep->param_link_tx_pause)
967e7801d59Ssowmini fl = LINK_FLOWCTRL_RX;
968e7801d59Ssowmini
969e7801d59Ssowmini if (!bgep->param_link_rx_pause &&
970e7801d59Ssowmini !bgep->param_link_tx_pause)
971e7801d59Ssowmini fl = LINK_FLOWCTRL_NONE;
972e7801d59Ssowmini
973e7801d59Ssowmini if (!bgep->param_link_rx_pause &&
974e7801d59Ssowmini bgep->param_link_tx_pause)
975e7801d59Ssowmini fl = LINK_FLOWCTRL_TX;
976e7801d59Ssowmini
977e7801d59Ssowmini if (bgep->param_link_rx_pause &&
978e7801d59Ssowmini bgep->param_link_tx_pause)
979e7801d59Ssowmini fl = LINK_FLOWCTRL_BI;
980e7801d59Ssowmini bcopy(&fl, pr_val, sizeof (fl));
981e7801d59Ssowmini break;
9825a506a18Syong tan - Sun Microsystems - Beijing China }
9830dc2366fSVenugopal Iyer case MAC_PROP_ADV_1000FDX_CAP:
984e7801d59Ssowmini *(uint8_t *)pr_val = bgep->param_adv_1000fdx;
985e7801d59Ssowmini break;
9863fd94f8cSam223141 case MAC_PROP_EN_1000FDX_CAP:
987e7801d59Ssowmini *(uint8_t *)pr_val = bgep->param_en_1000fdx;
988e7801d59Ssowmini break;
9893fd94f8cSam223141 case MAC_PROP_ADV_1000HDX_CAP:
990e7801d59Ssowmini *(uint8_t *)pr_val = bgep->param_adv_1000hdx;
991e7801d59Ssowmini break;
9923fd94f8cSam223141 case MAC_PROP_EN_1000HDX_CAP:
993e7801d59Ssowmini *(uint8_t *)pr_val = bgep->param_en_1000hdx;
994e7801d59Ssowmini break;
9953fd94f8cSam223141 case MAC_PROP_ADV_100FDX_CAP:
996e7801d59Ssowmini *(uint8_t *)pr_val = bgep->param_adv_100fdx;
997e7801d59Ssowmini break;
9983fd94f8cSam223141 case MAC_PROP_EN_100FDX_CAP:
999e7801d59Ssowmini *(uint8_t *)pr_val = bgep->param_en_100fdx;
1000e7801d59Ssowmini break;
10013fd94f8cSam223141 case MAC_PROP_ADV_100HDX_CAP:
1002e7801d59Ssowmini *(uint8_t *)pr_val = bgep->param_adv_100hdx;
1003e7801d59Ssowmini break;
10043fd94f8cSam223141 case MAC_PROP_EN_100HDX_CAP:
1005e7801d59Ssowmini *(uint8_t *)pr_val = bgep->param_en_100hdx;
1006e7801d59Ssowmini break;
10073fd94f8cSam223141 case MAC_PROP_ADV_10FDX_CAP:
1008e7801d59Ssowmini *(uint8_t *)pr_val = bgep->param_adv_10fdx;
1009e7801d59Ssowmini break;
10103fd94f8cSam223141 case MAC_PROP_EN_10FDX_CAP:
1011e7801d59Ssowmini *(uint8_t *)pr_val = bgep->param_en_10fdx;
1012e7801d59Ssowmini break;
10133fd94f8cSam223141 case MAC_PROP_ADV_10HDX_CAP:
1014e7801d59Ssowmini *(uint8_t *)pr_val = bgep->param_adv_10hdx;
1015e7801d59Ssowmini break;
10163fd94f8cSam223141 case MAC_PROP_EN_10HDX_CAP:
1017e7801d59Ssowmini *(uint8_t *)pr_val = bgep->param_en_10hdx;
1018e7801d59Ssowmini break;
10193fd94f8cSam223141 case MAC_PROP_ADV_100T4_CAP:
10203fd94f8cSam223141 case MAC_PROP_EN_100T4_CAP:
10214045d941Ssowmini *(uint8_t *)pr_val = 0;
10224045d941Ssowmini break;
10233fd94f8cSam223141 case MAC_PROP_PRIVATE:
10240dc2366fSVenugopal Iyer err = bge_get_priv_prop(bgep, pr_name,
10254045d941Ssowmini pr_valsize, pr_val);
1026e7801d59Ssowmini return (err);
10274045d941Ssowmini default:
10284045d941Ssowmini return (ENOTSUP);
1029e7801d59Ssowmini }
1030e7801d59Ssowmini return (0);
1031e7801d59Ssowmini }
1032e7801d59Ssowmini
10330dc2366fSVenugopal Iyer static void
10340dc2366fSVenugopal Iyer bge_m_propinfo(void *barg, const char *pr_name, mac_prop_id_t pr_num,
10350dc2366fSVenugopal Iyer mac_prop_info_handle_t prh)
10360dc2366fSVenugopal Iyer {
10370dc2366fSVenugopal Iyer bge_t *bgep = barg;
10380dc2366fSVenugopal Iyer int flags = bgep->chipid.flags;
10390dc2366fSVenugopal Iyer
10400dc2366fSVenugopal Iyer /*
10410dc2366fSVenugopal Iyer * By default permissions are read/write unless specified
10420dc2366fSVenugopal Iyer * otherwise by the driver.
10430dc2366fSVenugopal Iyer */
10440dc2366fSVenugopal Iyer
10450dc2366fSVenugopal Iyer switch (pr_num) {
10460dc2366fSVenugopal Iyer case MAC_PROP_DUPLEX:
10470dc2366fSVenugopal Iyer case MAC_PROP_SPEED:
10480dc2366fSVenugopal Iyer case MAC_PROP_STATUS:
10490dc2366fSVenugopal Iyer case MAC_PROP_ADV_1000FDX_CAP:
10500dc2366fSVenugopal Iyer case MAC_PROP_ADV_1000HDX_CAP:
10510dc2366fSVenugopal Iyer case MAC_PROP_ADV_100FDX_CAP:
10520dc2366fSVenugopal Iyer case MAC_PROP_ADV_100HDX_CAP:
10530dc2366fSVenugopal Iyer case MAC_PROP_ADV_10FDX_CAP:
10540dc2366fSVenugopal Iyer case MAC_PROP_ADV_10HDX_CAP:
10550dc2366fSVenugopal Iyer case MAC_PROP_ADV_100T4_CAP:
10560dc2366fSVenugopal Iyer case MAC_PROP_EN_100T4_CAP:
10570dc2366fSVenugopal Iyer mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
10580dc2366fSVenugopal Iyer break;
10590dc2366fSVenugopal Iyer
10600dc2366fSVenugopal Iyer case MAC_PROP_EN_1000FDX_CAP:
10610dc2366fSVenugopal Iyer case MAC_PROP_EN_1000HDX_CAP:
10620dc2366fSVenugopal Iyer if (DEVICE_5906_SERIES_CHIPSETS(bgep))
10630dc2366fSVenugopal Iyer mac_prop_info_set_default_uint8(prh, 0);
10640dc2366fSVenugopal Iyer else
10650dc2366fSVenugopal Iyer mac_prop_info_set_default_uint8(prh, 1);
10660dc2366fSVenugopal Iyer break;
10670dc2366fSVenugopal Iyer
10680dc2366fSVenugopal Iyer case MAC_PROP_EN_100FDX_CAP:
10690dc2366fSVenugopal Iyer case MAC_PROP_EN_100HDX_CAP:
10700dc2366fSVenugopal Iyer case MAC_PROP_EN_10FDX_CAP:
10710dc2366fSVenugopal Iyer case MAC_PROP_EN_10HDX_CAP:
10720dc2366fSVenugopal Iyer mac_prop_info_set_default_uint8(prh,
10730dc2366fSVenugopal Iyer (flags & CHIP_FLAG_SERDES) ? 0 : 1);
10740dc2366fSVenugopal Iyer break;
10750dc2366fSVenugopal Iyer
10760dc2366fSVenugopal Iyer case MAC_PROP_AUTONEG:
10770dc2366fSVenugopal Iyer mac_prop_info_set_default_uint8(prh, 1);
10780dc2366fSVenugopal Iyer break;
10790dc2366fSVenugopal Iyer
10800dc2366fSVenugopal Iyer case MAC_PROP_FLOWCTRL:
10810dc2366fSVenugopal Iyer mac_prop_info_set_default_link_flowctrl(prh,
10820dc2366fSVenugopal Iyer LINK_FLOWCTRL_BI);
10830dc2366fSVenugopal Iyer break;
10840dc2366fSVenugopal Iyer
10850dc2366fSVenugopal Iyer case MAC_PROP_MTU:
10860dc2366fSVenugopal Iyer mac_prop_info_set_range_uint32(prh, BGE_DEFAULT_MTU,
10870dc2366fSVenugopal Iyer (flags & CHIP_FLAG_NO_JUMBO) ?
10880dc2366fSVenugopal Iyer BGE_DEFAULT_MTU : BGE_MAXIMUM_MTU);
10890dc2366fSVenugopal Iyer break;
10900dc2366fSVenugopal Iyer
10910dc2366fSVenugopal Iyer case MAC_PROP_PRIVATE:
10920dc2366fSVenugopal Iyer bge_priv_propinfo(pr_name, prh);
10930dc2366fSVenugopal Iyer break;
10940dc2366fSVenugopal Iyer }
10950dc2366fSVenugopal Iyer
10960dc2366fSVenugopal Iyer mutex_enter(bgep->genlock);
10970dc2366fSVenugopal Iyer if ((bgep->param_loop_mode != BGE_LOOP_NONE &&
10980dc2366fSVenugopal Iyer bge_param_locked(pr_num)) ||
10990dc2366fSVenugopal Iyer ((bgep->chipid.flags & CHIP_FLAG_SERDES) &&
11000dc2366fSVenugopal Iyer ((pr_num == MAC_PROP_EN_100FDX_CAP) ||
11010dc2366fSVenugopal Iyer (pr_num == MAC_PROP_EN_100HDX_CAP) ||
11020dc2366fSVenugopal Iyer (pr_num == MAC_PROP_EN_10FDX_CAP) ||
11030dc2366fSVenugopal Iyer (pr_num == MAC_PROP_EN_10HDX_CAP))) ||
11040dc2366fSVenugopal Iyer (DEVICE_5906_SERIES_CHIPSETS(bgep) &&
11050dc2366fSVenugopal Iyer ((pr_num == MAC_PROP_EN_1000FDX_CAP) ||
11060dc2366fSVenugopal Iyer (pr_num == MAC_PROP_EN_1000HDX_CAP))))
11070dc2366fSVenugopal Iyer mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
11080dc2366fSVenugopal Iyer mutex_exit(bgep->genlock);
11090dc2366fSVenugopal Iyer }
11100dc2366fSVenugopal Iyer
1111e7801d59Ssowmini /* ARGSUSED */
1112e7801d59Ssowmini static int
1113e7801d59Ssowmini bge_set_priv_prop(bge_t *bgep, const char *pr_name, uint_t pr_valsize,
1114e7801d59Ssowmini const void *pr_val)
1115e7801d59Ssowmini {
1116e7801d59Ssowmini int err = 0;
1117e7801d59Ssowmini long result;
1118e7801d59Ssowmini
11194045d941Ssowmini if (strcmp(pr_name, "_adv_pause_cap") == 0) {
11204045d941Ssowmini (void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
11214045d941Ssowmini if (result > 1 || result < 0) {
11224045d941Ssowmini err = EINVAL;
11234045d941Ssowmini } else {
11244a06b59fSyt223700 bgep->param_adv_pause = (uint32_t)result;
11254045d941Ssowmini if (bge_reprogram(bgep) == IOC_INVAL)
11264045d941Ssowmini err = EINVAL;
11274045d941Ssowmini }
11284045d941Ssowmini return (err);
11294045d941Ssowmini }
11304045d941Ssowmini if (strcmp(pr_name, "_adv_asym_pause_cap") == 0) {
11314045d941Ssowmini (void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
11324045d941Ssowmini if (result > 1 || result < 0) {
11334045d941Ssowmini err = EINVAL;
11344045d941Ssowmini } else {
11354a06b59fSyt223700 bgep->param_adv_asym_pause = (uint32_t)result;
11364045d941Ssowmini if (bge_reprogram(bgep) == IOC_INVAL)
11374045d941Ssowmini err = EINVAL;
11384045d941Ssowmini }
11394045d941Ssowmini return (err);
11404045d941Ssowmini }
1141e7801d59Ssowmini if (strcmp(pr_name, "_drain_max") == 0) {
1142e7801d59Ssowmini
1143e7801d59Ssowmini /*
1144e7801d59Ssowmini * on the Tx side, we need to update the h/w register for
1145e7801d59Ssowmini * real packet transmission per packet. The drain_max parameter
1146e7801d59Ssowmini * is used to reduce the register access. This parameter
1147e7801d59Ssowmini * controls the max number of packets that we will hold before
1148e7801d59Ssowmini * updating the bge h/w to trigger h/w transmit. The bge
1149e7801d59Ssowmini * chipset usually has a max of 512 Tx descriptors, thus
1150e7801d59Ssowmini * the upper bound on drain_max is 512.
1151e7801d59Ssowmini */
1152e7801d59Ssowmini if (pr_val == NULL) {
1153e7801d59Ssowmini err = EINVAL;
1154e7801d59Ssowmini return (err);
1155e7801d59Ssowmini }
1156e7801d59Ssowmini (void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
1157e7801d59Ssowmini if (result > 512 || result < 1)
1158e7801d59Ssowmini err = EINVAL;
1159e7801d59Ssowmini else {
1160e7801d59Ssowmini bgep->param_drain_max = (uint32_t)result;
1161e7801d59Ssowmini if (bge_reprogram(bgep) == IOC_INVAL)
1162e7801d59Ssowmini err = EINVAL;
1163e7801d59Ssowmini }
1164e7801d59Ssowmini return (err);
1165e7801d59Ssowmini }
1166e7801d59Ssowmini if (strcmp(pr_name, "_msi_cnt") == 0) {
1167e7801d59Ssowmini
1168e7801d59Ssowmini if (pr_val == NULL) {
1169e7801d59Ssowmini err = EINVAL;
1170e7801d59Ssowmini return (err);
1171e7801d59Ssowmini }
1172e7801d59Ssowmini (void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
1173e7801d59Ssowmini if (result > 7 || result < 0)
1174e7801d59Ssowmini err = EINVAL;
1175e7801d59Ssowmini else {
1176e7801d59Ssowmini bgep->param_msi_cnt = (uint32_t)result;
1177e7801d59Ssowmini if (bge_reprogram(bgep) == IOC_INVAL)
1178e7801d59Ssowmini err = EINVAL;
1179e7801d59Ssowmini }
1180e7801d59Ssowmini return (err);
1181e7801d59Ssowmini }
11824d6eaea5Syong tan - Sun Microsystems - Beijing China if (strcmp(pr_name, "_rx_intr_coalesce_blank_time") == 0) {
11834045d941Ssowmini if (ddi_strtol(pr_val, (char **)NULL, 0, &result) != 0)
1184e7801d59Ssowmini return (EINVAL);
11854d6eaea5Syong tan - Sun Microsystems - Beijing China if (result < 0)
11864d6eaea5Syong tan - Sun Microsystems - Beijing China err = EINVAL;
11874d6eaea5Syong tan - Sun Microsystems - Beijing China else {
11884a06b59fSyt223700 bgep->chipid.rx_ticks_norm = (uint32_t)result;
11894d6eaea5Syong tan - Sun Microsystems - Beijing China bge_chip_coalesce_update(bgep);
11904d6eaea5Syong tan - Sun Microsystems - Beijing China }
11914d6eaea5Syong tan - Sun Microsystems - Beijing China return (err);
1192e7801d59Ssowmini }
1193e7801d59Ssowmini
11944d6eaea5Syong tan - Sun Microsystems - Beijing China if (strcmp(pr_name, "_rx_intr_coalesce_pkt_cnt") == 0) {
1195e7801d59Ssowmini if (ddi_strtol(pr_val, (char **)NULL, 0, &result) != 0)
1196e7801d59Ssowmini return (EINVAL);
1197e7801d59Ssowmini
11984d6eaea5Syong tan - Sun Microsystems - Beijing China if (result < 0)
11994d6eaea5Syong tan - Sun Microsystems - Beijing China err = EINVAL;
12004d6eaea5Syong tan - Sun Microsystems - Beijing China else {
12014a06b59fSyt223700 bgep->chipid.rx_count_norm = (uint32_t)result;
12024d6eaea5Syong tan - Sun Microsystems - Beijing China bge_chip_coalesce_update(bgep);
12034d6eaea5Syong tan - Sun Microsystems - Beijing China }
12044d6eaea5Syong tan - Sun Microsystems - Beijing China return (err);
12054d6eaea5Syong tan - Sun Microsystems - Beijing China }
12064d6eaea5Syong tan - Sun Microsystems - Beijing China if (strcmp(pr_name, "_tx_intr_coalesce_blank_time") == 0) {
12074d6eaea5Syong tan - Sun Microsystems - Beijing China if (ddi_strtol(pr_val, (char **)NULL, 0, &result) != 0)
12084d6eaea5Syong tan - Sun Microsystems - Beijing China return (EINVAL);
12094d6eaea5Syong tan - Sun Microsystems - Beijing China if (result < 0)
12104d6eaea5Syong tan - Sun Microsystems - Beijing China err = EINVAL;
12114d6eaea5Syong tan - Sun Microsystems - Beijing China else {
12124d6eaea5Syong tan - Sun Microsystems - Beijing China bgep->chipid.tx_ticks_norm = (uint32_t)result;
12134d6eaea5Syong tan - Sun Microsystems - Beijing China bge_chip_coalesce_update(bgep);
12144d6eaea5Syong tan - Sun Microsystems - Beijing China }
12154d6eaea5Syong tan - Sun Microsystems - Beijing China return (err);
12164d6eaea5Syong tan - Sun Microsystems - Beijing China }
12174d6eaea5Syong tan - Sun Microsystems - Beijing China
12184d6eaea5Syong tan - Sun Microsystems - Beijing China if (strcmp(pr_name, "_tx_intr_coalesce_pkt_cnt") == 0) {
12194d6eaea5Syong tan - Sun Microsystems - Beijing China if (ddi_strtol(pr_val, (char **)NULL, 0, &result) != 0)
12204d6eaea5Syong tan - Sun Microsystems - Beijing China return (EINVAL);
12214d6eaea5Syong tan - Sun Microsystems - Beijing China
12224d6eaea5Syong tan - Sun Microsystems - Beijing China if (result < 0)
12234d6eaea5Syong tan - Sun Microsystems - Beijing China err = EINVAL;
12244d6eaea5Syong tan - Sun Microsystems - Beijing China else {
12254d6eaea5Syong tan - Sun Microsystems - Beijing China bgep->chipid.tx_count_norm = (uint32_t)result;
12264d6eaea5Syong tan - Sun Microsystems - Beijing China bge_chip_coalesce_update(bgep);
12274d6eaea5Syong tan - Sun Microsystems - Beijing China }
12284d6eaea5Syong tan - Sun Microsystems - Beijing China return (err);
1229e7801d59Ssowmini }
12304045d941Ssowmini return (ENOTSUP);
1231e7801d59Ssowmini }
1232e7801d59Ssowmini
1233e7801d59Ssowmini static int
12340dc2366fSVenugopal Iyer bge_get_priv_prop(bge_t *bge, const char *pr_name, uint_t pr_valsize,
12350dc2366fSVenugopal Iyer void *pr_val)
1236e7801d59Ssowmini {
12374045d941Ssowmini int value;
1238e7801d59Ssowmini
12390dc2366fSVenugopal Iyer if (strcmp(pr_name, "_adv_pause_cap") == 0)
12400dc2366fSVenugopal Iyer value = bge->param_adv_pause;
12410dc2366fSVenugopal Iyer else if (strcmp(pr_name, "_adv_asym_pause_cap") == 0)
12420dc2366fSVenugopal Iyer value = bge->param_adv_asym_pause;
12430dc2366fSVenugopal Iyer else if (strcmp(pr_name, "_drain_max") == 0)
12440dc2366fSVenugopal Iyer value = bge->param_drain_max;
12450dc2366fSVenugopal Iyer else if (strcmp(pr_name, "_msi_cnt") == 0)
12460dc2366fSVenugopal Iyer value = bge->param_msi_cnt;
12470dc2366fSVenugopal Iyer else if (strcmp(pr_name, "_rx_intr_coalesce_blank_time") == 0)
12480dc2366fSVenugopal Iyer value = bge->chipid.rx_ticks_norm;
12490dc2366fSVenugopal Iyer else if (strcmp(pr_name, "_tx_intr_coalesce_blank_time") == 0)
12500dc2366fSVenugopal Iyer value = bge->chipid.tx_ticks_norm;
12510dc2366fSVenugopal Iyer else if (strcmp(pr_name, "_rx_intr_coalesce_pkt_cnt") == 0)
12520dc2366fSVenugopal Iyer value = bge->chipid.rx_count_norm;
12530dc2366fSVenugopal Iyer else if (strcmp(pr_name, "_tx_intr_coalesce_pkt_cnt") == 0)
12540dc2366fSVenugopal Iyer value = bge->chipid.tx_count_norm;
12550dc2366fSVenugopal Iyer else
12560dc2366fSVenugopal Iyer return (ENOTSUP);
1257e7801d59Ssowmini
12584045d941Ssowmini (void) snprintf(pr_val, pr_valsize, "%d", value);
12590dc2366fSVenugopal Iyer return (0);
12606b9e797cSsowmini }
12610dc2366fSVenugopal Iyer
12620dc2366fSVenugopal Iyer static void
12630dc2366fSVenugopal Iyer bge_priv_propinfo(const char *pr_name, mac_prop_info_handle_t mph)
12640dc2366fSVenugopal Iyer {
12650dc2366fSVenugopal Iyer char valstr[64];
12660dc2366fSVenugopal Iyer int value;
12670dc2366fSVenugopal Iyer
12680dc2366fSVenugopal Iyer if (strcmp(pr_name, "_adv_pause_cap") == 0)
12690dc2366fSVenugopal Iyer value = 1;
12700dc2366fSVenugopal Iyer else if (strcmp(pr_name, "_adv_asym_pause_cap") == 0)
12710dc2366fSVenugopal Iyer value = 1;
12720dc2366fSVenugopal Iyer else if (strcmp(pr_name, "_drain_max") == 0)
12730dc2366fSVenugopal Iyer value = 64;
12740dc2366fSVenugopal Iyer else if (strcmp(pr_name, "_msi_cnt") == 0)
12750dc2366fSVenugopal Iyer value = 0;
12760dc2366fSVenugopal Iyer else if (strcmp(pr_name, "_rx_intr_coalesce_blank_time") == 0)
12770dc2366fSVenugopal Iyer value = bge_rx_ticks_norm;
12780dc2366fSVenugopal Iyer else if (strcmp(pr_name, "_tx_intr_coalesce_blank_time") == 0)
12790dc2366fSVenugopal Iyer value = bge_tx_ticks_norm;
12800dc2366fSVenugopal Iyer else if (strcmp(pr_name, "_rx_intr_coalesce_pkt_cnt") == 0)
12810dc2366fSVenugopal Iyer value = bge_rx_count_norm;
12820dc2366fSVenugopal Iyer else if (strcmp(pr_name, "_tx_intr_coalesce_pkt_cnt") == 0)
12830dc2366fSVenugopal Iyer value = bge_tx_count_norm;
12840dc2366fSVenugopal Iyer else
12850dc2366fSVenugopal Iyer return;
12860dc2366fSVenugopal Iyer
12870dc2366fSVenugopal Iyer (void) snprintf(valstr, sizeof (valstr), "%d", value);
12880dc2366fSVenugopal Iyer mac_prop_info_set_default_str(mph, valstr);
1289e7801d59Ssowmini }
1290e7801d59Ssowmini
1291087a28d1SDavid Gwynne
1292087a28d1SDavid Gwynne static int
1293087a28d1SDavid Gwynne bge_m_unicst(void * arg, const uint8_t * mac_addr)
1294087a28d1SDavid Gwynne {
1295087a28d1SDavid Gwynne bge_t *bgep = arg;
1296087a28d1SDavid Gwynne int i;
1297087a28d1SDavid Gwynne
1298087a28d1SDavid Gwynne /* XXX sets the mac address for all ring slots... OK? */
1299087a28d1SDavid Gwynne for (i = 0; i < MIN(bgep->chipid.rx_rings, MAC_ADDRESS_REGS_MAX); i++)
1300087a28d1SDavid Gwynne bge_addmac(&bgep->recv[i], mac_addr);
1301087a28d1SDavid Gwynne
1302087a28d1SDavid Gwynne return (0);
1303087a28d1SDavid Gwynne }
1304087a28d1SDavid Gwynne
1305087a28d1SDavid Gwynne
1306ed8845d8Skrgopi /*
130762387023Sdduvall * Compute the index of the required bit in the multicast hash map.
130862387023Sdduvall * This must mirror the way the hardware actually does it!
130962387023Sdduvall * See Broadcom document 570X-PG102-R page 125.
131062387023Sdduvall */
131162387023Sdduvall static uint32_t
131262387023Sdduvall bge_hash_index(const uint8_t *mca)
131362387023Sdduvall {
131462387023Sdduvall uint32_t hash;
131562387023Sdduvall
131662387023Sdduvall CRC32(hash, mca, ETHERADDRL, -1U, crc32_table);
131762387023Sdduvall
131862387023Sdduvall return (hash);
131962387023Sdduvall }
132062387023Sdduvall
132162387023Sdduvall /*
132262387023Sdduvall * bge_m_multicst_add() -- enable/disable a multicast address
132362387023Sdduvall */
132462387023Sdduvall static int
132562387023Sdduvall bge_m_multicst(void *arg, boolean_t add, const uint8_t *mca)
132662387023Sdduvall {
132762387023Sdduvall bge_t *bgep = arg; /* private device info */
132862387023Sdduvall uint32_t hash;
132962387023Sdduvall uint32_t index;
133062387023Sdduvall uint32_t word;
133162387023Sdduvall uint32_t bit;
133262387023Sdduvall uint8_t *refp;
133362387023Sdduvall
133462387023Sdduvall BGE_TRACE(("bge_m_multicst($%p, %s, %s)", arg,
133562387023Sdduvall (add) ? "add" : "remove", ether_sprintf((void *)mca)));
133662387023Sdduvall
133762387023Sdduvall /*
133862387023Sdduvall * Precalculate all required masks, pointers etc ...
133962387023Sdduvall */
134062387023Sdduvall hash = bge_hash_index(mca);
134162387023Sdduvall index = hash % BGE_HASH_TABLE_SIZE;
134262387023Sdduvall word = index/32u;
134362387023Sdduvall bit = 1 << (index % 32u);
134462387023Sdduvall refp = &bgep->mcast_refs[index];
134562387023Sdduvall
134662387023Sdduvall BGE_DEBUG(("bge_m_multicst: hash 0x%x index %d (%d:0x%x) = %d",
134762387023Sdduvall hash, index, word, bit, *refp));
134862387023Sdduvall
134962387023Sdduvall /*
135062387023Sdduvall * We must set the appropriate bit in the hash map (and the
135162387023Sdduvall * corresponding h/w register) when the refcount goes from 0
135262387023Sdduvall * to >0, and clear it when the last ref goes away (refcount
135362387023Sdduvall * goes from >0 back to 0). If we change the hash map, we
135462387023Sdduvall * must also update the chip's hardware map registers.
135562387023Sdduvall */
135662387023Sdduvall mutex_enter(bgep->genlock);
135700d0963fSdilpreet if (!(bgep->progress & PROGRESS_INTR)) {
135800d0963fSdilpreet /* can happen during autorecovery */
135900d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED);
136000d0963fSdilpreet mutex_exit(bgep->genlock);
136100d0963fSdilpreet return (EIO);
136200d0963fSdilpreet }
136362387023Sdduvall if (add) {
136462387023Sdduvall if ((*refp)++ == 0) {
136562387023Sdduvall bgep->mcast_hash[word] |= bit;
136667f02347Srandyf #ifdef BGE_IPMI_ASF
136700d0963fSdilpreet if (bge_chip_sync(bgep, B_TRUE) == DDI_FAILURE) {
136867f02347Srandyf #else
136900d0963fSdilpreet if (bge_chip_sync(bgep) == DDI_FAILURE) {
137067f02347Srandyf #endif
137100d0963fSdilpreet (void) bge_check_acc_handle(bgep,
137200d0963fSdilpreet bgep->cfg_handle);
137300d0963fSdilpreet (void) bge_check_acc_handle(bgep,
137400d0963fSdilpreet bgep->io_handle);
137500d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo,
137600d0963fSdilpreet DDI_SERVICE_DEGRADED);
137700d0963fSdilpreet mutex_exit(bgep->genlock);
137800d0963fSdilpreet return (EIO);
137900d0963fSdilpreet }
138062387023Sdduvall }
138162387023Sdduvall } else {
138262387023Sdduvall if (--(*refp) == 0) {
138362387023Sdduvall bgep->mcast_hash[word] &= ~bit;
138467f02347Srandyf #ifdef BGE_IPMI_ASF
138500d0963fSdilpreet if (bge_chip_sync(bgep, B_TRUE) == DDI_FAILURE) {
138667f02347Srandyf #else
138700d0963fSdilpreet if (bge_chip_sync(bgep) == DDI_FAILURE) {
138867f02347Srandyf #endif
138900d0963fSdilpreet (void) bge_check_acc_handle(bgep,
139000d0963fSdilpreet bgep->cfg_handle);
139100d0963fSdilpreet (void) bge_check_acc_handle(bgep,
139200d0963fSdilpreet bgep->io_handle);
139300d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo,
139400d0963fSdilpreet DDI_SERVICE_DEGRADED);
139500d0963fSdilpreet mutex_exit(bgep->genlock);
139600d0963fSdilpreet return (EIO);
139700d0963fSdilpreet }
139862387023Sdduvall }
139962387023Sdduvall }
140062387023Sdduvall BGE_DEBUG(("bge_m_multicst($%p) done", arg));
140100d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) {
140200d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED);
140300d0963fSdilpreet mutex_exit(bgep->genlock);
140400d0963fSdilpreet return (EIO);
140500d0963fSdilpreet }
140600d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) {
140700d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED);
140800d0963fSdilpreet mutex_exit(bgep->genlock);
140900d0963fSdilpreet return (EIO);
141000d0963fSdilpreet }
141162387023Sdduvall mutex_exit(bgep->genlock);
141262387023Sdduvall
141362387023Sdduvall return (0);
141462387023Sdduvall }
141562387023Sdduvall
141662387023Sdduvall /*
141762387023Sdduvall * bge_m_promisc() -- set or reset promiscuous mode on the board
141862387023Sdduvall *
141962387023Sdduvall * Program the hardware to enable/disable promiscuous and/or
142062387023Sdduvall * receive-all-multicast modes.
142162387023Sdduvall */
142262387023Sdduvall static int
142362387023Sdduvall bge_m_promisc(void *arg, boolean_t on)
142462387023Sdduvall {
142562387023Sdduvall bge_t *bgep = arg;
142662387023Sdduvall
142762387023Sdduvall BGE_TRACE(("bge_m_promisc_set($%p, %d)", arg, on));
142862387023Sdduvall
142962387023Sdduvall /*
143062387023Sdduvall * Store MAC layer specified mode and pass to chip layer to update h/w
143162387023Sdduvall */
143262387023Sdduvall mutex_enter(bgep->genlock);
143300d0963fSdilpreet if (!(bgep->progress & PROGRESS_INTR)) {
143400d0963fSdilpreet /* can happen during autorecovery */
143500d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED);
143600d0963fSdilpreet mutex_exit(bgep->genlock);
143700d0963fSdilpreet return (EIO);
143800d0963fSdilpreet }
143962387023Sdduvall bgep->promisc = on;
144067f02347Srandyf #ifdef BGE_IPMI_ASF
144100d0963fSdilpreet if (bge_chip_sync(bgep, B_TRUE) == DDI_FAILURE) {
144267f02347Srandyf #else
144300d0963fSdilpreet if (bge_chip_sync(bgep) == DDI_FAILURE) {
144467f02347Srandyf #endif
144500d0963fSdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle);
144600d0963fSdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle);
144700d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED);
144800d0963fSdilpreet mutex_exit(bgep->genlock);
144900d0963fSdilpreet return (EIO);
145000d0963fSdilpreet }
145162387023Sdduvall BGE_DEBUG(("bge_m_promisc_set($%p) done", arg));
145200d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) {
145300d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED);
145400d0963fSdilpreet mutex_exit(bgep->genlock);
145500d0963fSdilpreet return (EIO);
145600d0963fSdilpreet }
145700d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) {
145800d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED);
145900d0963fSdilpreet mutex_exit(bgep->genlock);
146000d0963fSdilpreet return (EIO);
146100d0963fSdilpreet }
146262387023Sdduvall mutex_exit(bgep->genlock);
146362387023Sdduvall return (0);
146462387023Sdduvall }
146562387023Sdduvall
1466087a28d1SDavid Gwynne #ifdef MC_RESOURCES
1467087a28d1SDavid Gwynne
1468087a28d1SDavid Gwynne static void
1469087a28d1SDavid Gwynne bge_blank(void * arg, time_t tick_cnt, uint_t pkt_cnt)
1470087a28d1SDavid Gwynne {
1471087a28d1SDavid Gwynne (void)arg;
1472087a28d1SDavid Gwynne (void)tick_cnt;
1473087a28d1SDavid Gwynne (void)pkt_cnt;
1474087a28d1SDavid Gwynne }
1475087a28d1SDavid Gwynne
1476087a28d1SDavid Gwynne static void
1477087a28d1SDavid Gwynne bge_m_resources(void * arg)
1478087a28d1SDavid Gwynne {
1479087a28d1SDavid Gwynne bge_t *bgep = arg;
1480087a28d1SDavid Gwynne mac_rx_fifo_t mrf;
1481087a28d1SDavid Gwynne int i;
1482087a28d1SDavid Gwynne
1483087a28d1SDavid Gwynne mrf.mrf_type = MAC_RX_FIFO;
1484087a28d1SDavid Gwynne mrf.mrf_blank = bge_blank;
1485087a28d1SDavid Gwynne mrf.mrf_arg = (void *)bgep;
1486087a28d1SDavid Gwynne mrf.mrf_normal_blank_time = 25;
1487087a28d1SDavid Gwynne mrf.mrf_normal_pkt_count = 8;
1488087a28d1SDavid Gwynne
1489087a28d1SDavid Gwynne for (i = 0; i < BGE_RECV_RINGS_MAX; i++) {
1490087a28d1SDavid Gwynne bgep->macRxResourceHandles[i] =
1491087a28d1SDavid Gwynne mac_resource_add(bgep->mh, (mac_resource_t *)&mrf);
1492087a28d1SDavid Gwynne }
1493087a28d1SDavid Gwynne }
1494087a28d1SDavid Gwynne
1495087a28d1SDavid Gwynne #endif /* MC_RESOURCES */
1496087a28d1SDavid Gwynne
1497da14cebeSEric Cheng /*
1498da14cebeSEric Cheng * Find the slot for the specified unicast address
1499da14cebeSEric Cheng */
1500da14cebeSEric Cheng int
1501da14cebeSEric Cheng bge_unicst_find(bge_t *bgep, const uint8_t *mac_addr)
1502da14cebeSEric Cheng {
1503da14cebeSEric Cheng int slot;
1504da14cebeSEric Cheng
1505da14cebeSEric Cheng ASSERT(mutex_owned(bgep->genlock));
1506da14cebeSEric Cheng
1507da14cebeSEric Cheng for (slot = 0; slot < bgep->unicst_addr_total; slot++) {
1508da14cebeSEric Cheng if (bcmp(bgep->curr_addr[slot].addr, mac_addr, ETHERADDRL) == 0)
1509da14cebeSEric Cheng return (slot);
1510da14cebeSEric Cheng }
1511da14cebeSEric Cheng
1512da14cebeSEric Cheng return (-1);
1513da14cebeSEric Cheng }
1514da14cebeSEric Cheng
1515da14cebeSEric Cheng /*
1516da14cebeSEric Cheng * Programs the classifier to start steering packets matching 'mac_addr' to the
1517da14cebeSEric Cheng * specified ring 'arg'.
1518da14cebeSEric Cheng */
1519da14cebeSEric Cheng static int
1520da14cebeSEric Cheng bge_addmac(void *arg, const uint8_t * mac_addr)
1521da14cebeSEric Cheng {
1522da14cebeSEric Cheng recv_ring_t *rrp = (recv_ring_t *)arg;
1523da14cebeSEric Cheng bge_t *bgep = rrp->bgep;
1524da14cebeSEric Cheng bge_recv_rule_t *rulep = bgep->recv_rules;
1525da14cebeSEric Cheng bge_rule_info_t *rinfop = NULL;
1526da14cebeSEric Cheng uint8_t ring = (uint8_t)(rrp - bgep->recv) + 1;
1527da14cebeSEric Cheng int i;
1528da14cebeSEric Cheng uint16_t tmp16;
1529da14cebeSEric Cheng uint32_t tmp32;
1530da14cebeSEric Cheng int slot;
1531da14cebeSEric Cheng int err;
1532da14cebeSEric Cheng
1533da14cebeSEric Cheng mutex_enter(bgep->genlock);
1534da14cebeSEric Cheng if (bgep->unicst_addr_avail == 0) {
1535da14cebeSEric Cheng mutex_exit(bgep->genlock);
1536da14cebeSEric Cheng return (ENOSPC);
1537da14cebeSEric Cheng }
1538da14cebeSEric Cheng
1539da14cebeSEric Cheng /*
1540da14cebeSEric Cheng * First add the unicast address to a available slot.
1541da14cebeSEric Cheng */
1542da14cebeSEric Cheng slot = bge_unicst_find(bgep, mac_addr);
1543da14cebeSEric Cheng ASSERT(slot == -1);
1544da14cebeSEric Cheng
1545da14cebeSEric Cheng for (slot = 0; slot < bgep->unicst_addr_total; slot++) {
1546da14cebeSEric Cheng if (!bgep->curr_addr[slot].set) {
1547da14cebeSEric Cheng bgep->curr_addr[slot].set = B_TRUE;
1548da14cebeSEric Cheng break;
1549da14cebeSEric Cheng }
1550da14cebeSEric Cheng }
1551da14cebeSEric Cheng
1552da14cebeSEric Cheng ASSERT(slot < bgep->unicst_addr_total);
1553da14cebeSEric Cheng bgep->unicst_addr_avail--;
1554da14cebeSEric Cheng mutex_exit(bgep->genlock);
1555da14cebeSEric Cheng
1556da14cebeSEric Cheng if ((err = bge_unicst_set(bgep, mac_addr, slot)) != 0)
1557da14cebeSEric Cheng goto fail;
1558da14cebeSEric Cheng
1559da14cebeSEric Cheng /* A rule is already here. Deny this. */
1560da14cebeSEric Cheng if (rrp->mac_addr_rule != NULL) {
1561da14cebeSEric Cheng err = ether_cmp(mac_addr, rrp->mac_addr_val) ? EEXIST : EBUSY;
1562da14cebeSEric Cheng goto fail;
1563da14cebeSEric Cheng }
1564da14cebeSEric Cheng
1565da14cebeSEric Cheng /*
1566da14cebeSEric Cheng * Allocate a bge_rule_info_t to keep track of which rule slots
1567da14cebeSEric Cheng * are being used.
1568da14cebeSEric Cheng */
1569da14cebeSEric Cheng rinfop = kmem_zalloc(sizeof (bge_rule_info_t), KM_NOSLEEP);
1570da14cebeSEric Cheng if (rinfop == NULL) {
1571da14cebeSEric Cheng err = ENOMEM;
1572da14cebeSEric Cheng goto fail;
1573da14cebeSEric Cheng }
1574da14cebeSEric Cheng
1575da14cebeSEric Cheng /*
1576da14cebeSEric Cheng * Look for the starting slot to place the rules.
1577da14cebeSEric Cheng * The two slots we reserve must be contiguous.
1578da14cebeSEric Cheng */
1579da14cebeSEric Cheng for (i = 0; i + 1 < RECV_RULES_NUM_MAX; i++)
1580da14cebeSEric Cheng if ((rulep[i].control & RECV_RULE_CTL_ENABLE) == 0 &&
1581da14cebeSEric Cheng (rulep[i+1].control & RECV_RULE_CTL_ENABLE) == 0)
1582da14cebeSEric Cheng break;
1583da14cebeSEric Cheng
1584da14cebeSEric Cheng ASSERT(i + 1 < RECV_RULES_NUM_MAX);
1585da14cebeSEric Cheng
1586da14cebeSEric Cheng bcopy(mac_addr, &tmp32, sizeof (tmp32));
1587da14cebeSEric Cheng rulep[i].mask_value = ntohl(tmp32);
1588da14cebeSEric Cheng rulep[i].control = RULE_DEST_MAC_1(ring) | RECV_RULE_CTL_AND;
1589da14cebeSEric Cheng bge_reg_put32(bgep, RECV_RULE_MASK_REG(i), rulep[i].mask_value);
1590da14cebeSEric Cheng bge_reg_put32(bgep, RECV_RULE_CONTROL_REG(i), rulep[i].control);
1591da14cebeSEric Cheng
1592da14cebeSEric Cheng bcopy(mac_addr + 4, &tmp16, sizeof (tmp16));
1593da14cebeSEric Cheng rulep[i+1].mask_value = 0xffff0000 | ntohs(tmp16);
1594da14cebeSEric Cheng rulep[i+1].control = RULE_DEST_MAC_2(ring);
1595da14cebeSEric Cheng bge_reg_put32(bgep, RECV_RULE_MASK_REG(i+1), rulep[i+1].mask_value);
1596da14cebeSEric Cheng bge_reg_put32(bgep, RECV_RULE_CONTROL_REG(i+1), rulep[i+1].control);
1597da14cebeSEric Cheng rinfop->start = i;
1598da14cebeSEric Cheng rinfop->count = 2;
1599da14cebeSEric Cheng
1600da14cebeSEric Cheng rrp->mac_addr_rule = rinfop;
1601da14cebeSEric Cheng bcopy(mac_addr, rrp->mac_addr_val, ETHERADDRL);
1602da14cebeSEric Cheng
1603da14cebeSEric Cheng return (0);
1604da14cebeSEric Cheng
1605da14cebeSEric Cheng fail:
1606da14cebeSEric Cheng /* Clear the address just set */
1607da14cebeSEric Cheng (void) bge_unicst_set(bgep, zero_addr, slot);
1608da14cebeSEric Cheng mutex_enter(bgep->genlock);
1609da14cebeSEric Cheng bgep->curr_addr[slot].set = B_FALSE;
1610da14cebeSEric Cheng bgep->unicst_addr_avail++;
1611da14cebeSEric Cheng mutex_exit(bgep->genlock);
1612da14cebeSEric Cheng
1613da14cebeSEric Cheng return (err);
1614da14cebeSEric Cheng }
1615da14cebeSEric Cheng
1616da14cebeSEric Cheng /*
1617da14cebeSEric Cheng * Stop classifying packets matching the MAC address to the specified ring.
1618da14cebeSEric Cheng */
1619da14cebeSEric Cheng static int
1620da14cebeSEric Cheng bge_remmac(void *arg, const uint8_t *mac_addr)
1621da14cebeSEric Cheng {
1622da14cebeSEric Cheng recv_ring_t *rrp = (recv_ring_t *)arg;
1623da14cebeSEric Cheng bge_t *bgep = rrp->bgep;
1624da14cebeSEric Cheng bge_recv_rule_t *rulep = bgep->recv_rules;
1625da14cebeSEric Cheng bge_rule_info_t *rinfop = rrp->mac_addr_rule;
1626da14cebeSEric Cheng int start;
1627da14cebeSEric Cheng int slot;
1628da14cebeSEric Cheng int err;
1629da14cebeSEric Cheng
1630da14cebeSEric Cheng /*
1631da14cebeSEric Cheng * Remove the MAC address from its slot.
1632da14cebeSEric Cheng */
1633da14cebeSEric Cheng mutex_enter(bgep->genlock);
1634da14cebeSEric Cheng slot = bge_unicst_find(bgep, mac_addr);
1635da14cebeSEric Cheng if (slot == -1) {
1636da14cebeSEric Cheng mutex_exit(bgep->genlock);
1637da14cebeSEric Cheng return (EINVAL);
1638da14cebeSEric Cheng }
1639da14cebeSEric Cheng
1640da14cebeSEric Cheng ASSERT(bgep->curr_addr[slot].set);
1641da14cebeSEric Cheng mutex_exit(bgep->genlock);
1642da14cebeSEric Cheng
1643da14cebeSEric Cheng if ((err = bge_unicst_set(bgep, zero_addr, slot)) != 0)
1644da14cebeSEric Cheng return (err);
1645da14cebeSEric Cheng
1646da14cebeSEric Cheng if (rinfop == NULL || ether_cmp(mac_addr, rrp->mac_addr_val) != 0)
1647da14cebeSEric Cheng return (EINVAL);
1648da14cebeSEric Cheng
1649da14cebeSEric Cheng start = rinfop->start;
1650da14cebeSEric Cheng rulep[start].mask_value = 0;
1651da14cebeSEric Cheng rulep[start].control = 0;
1652da14cebeSEric Cheng bge_reg_put32(bgep, RECV_RULE_MASK_REG(start), rulep[start].mask_value);
1653da14cebeSEric Cheng bge_reg_put32(bgep, RECV_RULE_CONTROL_REG(start), rulep[start].control);
1654da14cebeSEric Cheng start++;
1655da14cebeSEric Cheng rulep[start].mask_value = 0;
1656da14cebeSEric Cheng rulep[start].control = 0;
1657da14cebeSEric Cheng bge_reg_put32(bgep, RECV_RULE_MASK_REG(start), rulep[start].mask_value);
1658da14cebeSEric Cheng bge_reg_put32(bgep, RECV_RULE_CONTROL_REG(start), rulep[start].control);
1659da14cebeSEric Cheng
1660da14cebeSEric Cheng kmem_free(rinfop, sizeof (bge_rule_info_t));
1661da14cebeSEric Cheng rrp->mac_addr_rule = NULL;
1662da14cebeSEric Cheng bzero(rrp->mac_addr_val, ETHERADDRL);
1663da14cebeSEric Cheng
1664da14cebeSEric Cheng mutex_enter(bgep->genlock);
1665da14cebeSEric Cheng bgep->curr_addr[slot].set = B_FALSE;
1666da14cebeSEric Cheng bgep->unicst_addr_avail++;
1667da14cebeSEric Cheng mutex_exit(bgep->genlock);
1668da14cebeSEric Cheng
1669da14cebeSEric Cheng return (0);
1670da14cebeSEric Cheng }
1671da14cebeSEric Cheng
1672087a28d1SDavid Gwynne
1673da14cebeSEric Cheng static int
1674087a28d1SDavid Gwynne bge_flag_intr_enable(mac_ring_driver_t ih)
1675da14cebeSEric Cheng {
1676da14cebeSEric Cheng recv_ring_t *rrp = (recv_ring_t *)ih;
1677da14cebeSEric Cheng bge_t *bgep = rrp->bgep;
1678da14cebeSEric Cheng
1679da14cebeSEric Cheng mutex_enter(bgep->genlock);
1680da14cebeSEric Cheng rrp->poll_flag = 0;
1681da14cebeSEric Cheng mutex_exit(bgep->genlock);
1682da14cebeSEric Cheng
1683da14cebeSEric Cheng return (0);
1684da14cebeSEric Cheng }
1685da14cebeSEric Cheng
1686da14cebeSEric Cheng static int
1687087a28d1SDavid Gwynne bge_flag_intr_disable(mac_ring_driver_t ih)
1688da14cebeSEric Cheng {
1689da14cebeSEric Cheng recv_ring_t *rrp = (recv_ring_t *)ih;
1690da14cebeSEric Cheng bge_t *bgep = rrp->bgep;
1691da14cebeSEric Cheng
1692da14cebeSEric Cheng mutex_enter(bgep->genlock);
1693da14cebeSEric Cheng rrp->poll_flag = 1;
1694da14cebeSEric Cheng mutex_exit(bgep->genlock);
1695da14cebeSEric Cheng
1696da14cebeSEric Cheng return (0);
1697da14cebeSEric Cheng }
1698da14cebeSEric Cheng
1699da14cebeSEric Cheng static int
1700da14cebeSEric Cheng bge_ring_start(mac_ring_driver_t rh, uint64_t mr_gen_num)
1701da14cebeSEric Cheng {
1702da14cebeSEric Cheng recv_ring_t *rx_ring;
1703da14cebeSEric Cheng
1704da14cebeSEric Cheng rx_ring = (recv_ring_t *)rh;
1705da14cebeSEric Cheng mutex_enter(rx_ring->rx_lock);
1706da14cebeSEric Cheng rx_ring->ring_gen_num = mr_gen_num;
1707da14cebeSEric Cheng mutex_exit(rx_ring->rx_lock);
1708da14cebeSEric Cheng return (0);
1709da14cebeSEric Cheng }
1710da14cebeSEric Cheng
1711da14cebeSEric Cheng
1712da14cebeSEric Cheng /*
1713da14cebeSEric Cheng * Callback funtion for MAC layer to register all rings
1714da14cebeSEric Cheng * for given ring_group, noted by rg_index.
1715da14cebeSEric Cheng */
1716da14cebeSEric Cheng void
1717da14cebeSEric Cheng bge_fill_ring(void *arg, mac_ring_type_t rtype, const int rg_index,
1718da14cebeSEric Cheng const int index, mac_ring_info_t *infop, mac_ring_handle_t rh)
1719da14cebeSEric Cheng {
1720da14cebeSEric Cheng bge_t *bgep = arg;
1721da14cebeSEric Cheng mac_intr_t *mintr;
1722da14cebeSEric Cheng
1723da14cebeSEric Cheng switch (rtype) {
1724da14cebeSEric Cheng case MAC_RING_TYPE_RX: {
1725da14cebeSEric Cheng recv_ring_t *rx_ring;
1726da14cebeSEric Cheng ASSERT(rg_index >= 0 && rg_index < MIN(bgep->chipid.rx_rings,
1727da14cebeSEric Cheng MAC_ADDRESS_REGS_MAX) && index == 0);
1728da14cebeSEric Cheng
1729da14cebeSEric Cheng rx_ring = &bgep->recv[rg_index];
1730da14cebeSEric Cheng rx_ring->ring_handle = rh;
1731da14cebeSEric Cheng
1732da14cebeSEric Cheng infop->mri_driver = (mac_ring_driver_t)rx_ring;
1733da14cebeSEric Cheng infop->mri_start = bge_ring_start;
1734da14cebeSEric Cheng infop->mri_stop = NULL;
1735da14cebeSEric Cheng infop->mri_poll = bge_poll_ring;
17360dc2366fSVenugopal Iyer infop->mri_stat = bge_rx_ring_stat;
1737da14cebeSEric Cheng
1738da14cebeSEric Cheng mintr = &infop->mri_intr;
1739087a28d1SDavid Gwynne mintr->mi_enable = (mac_intr_enable_t)bge_flag_intr_enable;
1740087a28d1SDavid Gwynne mintr->mi_disable = (mac_intr_disable_t)bge_flag_intr_disable;
1741da14cebeSEric Cheng
1742da14cebeSEric Cheng break;
1743da14cebeSEric Cheng }
1744da14cebeSEric Cheng case MAC_RING_TYPE_TX:
1745da14cebeSEric Cheng default:
1746da14cebeSEric Cheng ASSERT(0);
1747da14cebeSEric Cheng break;
1748da14cebeSEric Cheng }
1749da14cebeSEric Cheng }
1750da14cebeSEric Cheng
1751da14cebeSEric Cheng /*
1752da14cebeSEric Cheng * Fill infop passed as argument
1753da14cebeSEric Cheng * fill in respective ring_group info
1754da14cebeSEric Cheng * Each group has a single ring in it. We keep it simple
1755da14cebeSEric Cheng * and use the same internal handle for rings and groups.
1756da14cebeSEric Cheng */
1757da14cebeSEric Cheng void
1758da14cebeSEric Cheng bge_fill_group(void *arg, mac_ring_type_t rtype, const int rg_index,
1759da14cebeSEric Cheng mac_group_info_t * infop, mac_group_handle_t gh)
1760da14cebeSEric Cheng {
1761da14cebeSEric Cheng bge_t *bgep = arg;
1762da14cebeSEric Cheng
1763da14cebeSEric Cheng switch (rtype) {
1764da14cebeSEric Cheng case MAC_RING_TYPE_RX: {
1765da14cebeSEric Cheng recv_ring_t *rx_ring;
1766da14cebeSEric Cheng
1767da14cebeSEric Cheng ASSERT(rg_index >= 0 && rg_index < MIN(bgep->chipid.rx_rings,
1768da14cebeSEric Cheng MAC_ADDRESS_REGS_MAX));
1769da14cebeSEric Cheng rx_ring = &bgep->recv[rg_index];
1770da14cebeSEric Cheng rx_ring->ring_group_handle = gh;
1771da14cebeSEric Cheng
1772da14cebeSEric Cheng infop->mgi_driver = (mac_group_driver_t)rx_ring;
1773da14cebeSEric Cheng infop->mgi_start = NULL;
1774da14cebeSEric Cheng infop->mgi_stop = NULL;
1775da14cebeSEric Cheng infop->mgi_addmac = bge_addmac;
1776da14cebeSEric Cheng infop->mgi_remmac = bge_remmac;
1777da14cebeSEric Cheng infop->mgi_count = 1;
1778da14cebeSEric Cheng break;
1779da14cebeSEric Cheng }
1780da14cebeSEric Cheng case MAC_RING_TYPE_TX:
1781da14cebeSEric Cheng default:
1782da14cebeSEric Cheng ASSERT(0);
1783da14cebeSEric Cheng break;
1784da14cebeSEric Cheng }
1785da14cebeSEric Cheng }
1786da14cebeSEric Cheng
1787087a28d1SDavid Gwynne
1788ba2e4443Sseb /*ARGSUSED*/
1789ba2e4443Sseb static boolean_t
1790ba2e4443Sseb bge_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
1791ba2e4443Sseb {
1792ed8845d8Skrgopi bge_t *bgep = arg;
1793087a28d1SDavid Gwynne mac_capab_rings_t *cap_rings;
1794ed8845d8Skrgopi
1795ba2e4443Sseb switch (cap) {
1796ba2e4443Sseb case MAC_CAPAB_HCKSUM: {
1797ba2e4443Sseb uint32_t *txflags = cap_data;
1798ba2e4443Sseb
1799ba2e4443Sseb *txflags = HCKSUM_INET_FULL_V4 | HCKSUM_IPHDRCKSUM;
1800ba2e4443Sseb break;
1801ba2e4443Sseb }
1802087a28d1SDavid Gwynne
1803087a28d1SDavid Gwynne case MAC_CAPAB_RINGS:
1804087a28d1SDavid Gwynne cap_rings = (mac_capab_rings_t *)cap_data;
1805ed8845d8Skrgopi
1806da14cebeSEric Cheng /* Temporarily disable multiple tx rings. */
1807da14cebeSEric Cheng if (cap_rings->mr_type != MAC_RING_TYPE_RX)
1808da14cebeSEric Cheng return (B_FALSE);
1809ed8845d8Skrgopi
1810da14cebeSEric Cheng cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
1811087a28d1SDavid Gwynne cap_rings->mr_rnum =
1812087a28d1SDavid Gwynne cap_rings->mr_gnum =
1813da14cebeSEric Cheng MIN(bgep->chipid.rx_rings, MAC_ADDRESS_REGS_MAX);
1814da14cebeSEric Cheng cap_rings->mr_rget = bge_fill_ring;
1815da14cebeSEric Cheng cap_rings->mr_gget = bge_fill_group;
1816ed8845d8Skrgopi break;
1817087a28d1SDavid Gwynne
1818ba2e4443Sseb default:
1819ba2e4443Sseb return (B_FALSE);
1820ba2e4443Sseb }
1821ba2e4443Sseb return (B_TRUE);
1822ba2e4443Sseb }
1823ba2e4443Sseb
1824087a28d1SDavid Gwynne #ifdef NOT_SUPPORTED_XXX
1825087a28d1SDavid Gwynne
182662387023Sdduvall /*
182762387023Sdduvall * Loopback ioctl code
182862387023Sdduvall */
182962387023Sdduvall
183062387023Sdduvall static lb_property_t loopmodes[] = {
183162387023Sdduvall { normal, "normal", BGE_LOOP_NONE },
183262387023Sdduvall { external, "1000Mbps", BGE_LOOP_EXTERNAL_1000 },
183362387023Sdduvall { external, "100Mbps", BGE_LOOP_EXTERNAL_100 },
183462387023Sdduvall { external, "10Mbps", BGE_LOOP_EXTERNAL_10 },
183562387023Sdduvall { internal, "PHY", BGE_LOOP_INTERNAL_PHY },
183662387023Sdduvall { internal, "MAC", BGE_LOOP_INTERNAL_MAC }
183762387023Sdduvall };
183862387023Sdduvall
183962387023Sdduvall static enum ioc_reply
184062387023Sdduvall bge_set_loop_mode(bge_t *bgep, uint32_t mode)
184162387023Sdduvall {
184262387023Sdduvall /*
184362387023Sdduvall * If the mode isn't being changed, there's nothing to do ...
184462387023Sdduvall */
184562387023Sdduvall if (mode == bgep->param_loop_mode)
184662387023Sdduvall return (IOC_ACK);
184762387023Sdduvall
184862387023Sdduvall /*
184962387023Sdduvall * Validate the requested mode and prepare a suitable message
185062387023Sdduvall * to explain the link down/up cycle that the change will
185162387023Sdduvall * probably induce ...
185262387023Sdduvall */
185362387023Sdduvall switch (mode) {
185462387023Sdduvall default:
185562387023Sdduvall return (IOC_INVAL);
185662387023Sdduvall
185762387023Sdduvall case BGE_LOOP_NONE:
185862387023Sdduvall case BGE_LOOP_EXTERNAL_1000:
185962387023Sdduvall case BGE_LOOP_EXTERNAL_100:
186062387023Sdduvall case BGE_LOOP_EXTERNAL_10:
186162387023Sdduvall case BGE_LOOP_INTERNAL_PHY:
186262387023Sdduvall case BGE_LOOP_INTERNAL_MAC:
186362387023Sdduvall break;
186462387023Sdduvall }
186562387023Sdduvall
186662387023Sdduvall /*
186762387023Sdduvall * All OK; tell the caller to reprogram
186862387023Sdduvall * the PHY and/or MAC for the new mode ...
186962387023Sdduvall */
187062387023Sdduvall bgep->param_loop_mode = mode;
187162387023Sdduvall return (IOC_RESTART_ACK);
187262387023Sdduvall }
187362387023Sdduvall
187462387023Sdduvall static enum ioc_reply
187562387023Sdduvall bge_loop_ioctl(bge_t *bgep, queue_t *wq, mblk_t *mp, struct iocblk *iocp)
187662387023Sdduvall {
187762387023Sdduvall lb_info_sz_t *lbsp;
187862387023Sdduvall lb_property_t *lbpp;
187962387023Sdduvall uint32_t *lbmp;
188062387023Sdduvall int cmd;
188162387023Sdduvall
188262387023Sdduvall _NOTE(ARGUNUSED(wq))
188362387023Sdduvall
188462387023Sdduvall /*
188562387023Sdduvall * Validate format of ioctl
188662387023Sdduvall */
188762387023Sdduvall if (mp->b_cont == NULL)
188862387023Sdduvall return (IOC_INVAL);
188962387023Sdduvall
189062387023Sdduvall cmd = iocp->ioc_cmd;
189162387023Sdduvall switch (cmd) {
189262387023Sdduvall default:
189362387023Sdduvall /* NOTREACHED */
189462387023Sdduvall bge_error(bgep, "bge_loop_ioctl: invalid cmd 0x%x", cmd);
189562387023Sdduvall return (IOC_INVAL);
189662387023Sdduvall
189762387023Sdduvall case LB_GET_INFO_SIZE:
189862387023Sdduvall if (iocp->ioc_count != sizeof (lb_info_sz_t))
189962387023Sdduvall return (IOC_INVAL);
19004a06b59fSyt223700 lbsp = (void *)mp->b_cont->b_rptr;
190162387023Sdduvall *lbsp = sizeof (loopmodes);
190262387023Sdduvall return (IOC_REPLY);
190362387023Sdduvall
190462387023Sdduvall case LB_GET_INFO:
190562387023Sdduvall if (iocp->ioc_count != sizeof (loopmodes))
190662387023Sdduvall return (IOC_INVAL);
19074a06b59fSyt223700 lbpp = (void *)mp->b_cont->b_rptr;
190862387023Sdduvall bcopy(loopmodes, lbpp, sizeof (loopmodes));
190962387023Sdduvall return (IOC_REPLY);
191062387023Sdduvall
191162387023Sdduvall case LB_GET_MODE:
191262387023Sdduvall if (iocp->ioc_count != sizeof (uint32_t))
191362387023Sdduvall return (IOC_INVAL);
19144a06b59fSyt223700 lbmp = (void *)mp->b_cont->b_rptr;
191562387023Sdduvall *lbmp = bgep->param_loop_mode;
191662387023Sdduvall return (IOC_REPLY);
191762387023Sdduvall
191862387023Sdduvall case LB_SET_MODE:
191962387023Sdduvall if (iocp->ioc_count != sizeof (uint32_t))
192062387023Sdduvall return (IOC_INVAL);
19214a06b59fSyt223700 lbmp = (void *)mp->b_cont->b_rptr;
192262387023Sdduvall return (bge_set_loop_mode(bgep, *lbmp));
192362387023Sdduvall }
192462387023Sdduvall }
192562387023Sdduvall
1926087a28d1SDavid Gwynne #endif /* NOT_SUPPORTED_XXX */
1927087a28d1SDavid Gwynne
192862387023Sdduvall /*
192962387023Sdduvall * Specific bge IOCTLs, the gld module handles the generic ones.
193062387023Sdduvall */
193162387023Sdduvall static void
193262387023Sdduvall bge_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
193362387023Sdduvall {
193462387023Sdduvall bge_t *bgep = arg;
193562387023Sdduvall struct iocblk *iocp;
193662387023Sdduvall enum ioc_reply status;
193762387023Sdduvall boolean_t need_privilege;
193862387023Sdduvall int err;
193962387023Sdduvall int cmd;
194062387023Sdduvall
194162387023Sdduvall /*
194262387023Sdduvall * Validate the command before bothering with the mutex ...
194362387023Sdduvall */
19444a06b59fSyt223700 iocp = (void *)mp->b_rptr;
194562387023Sdduvall iocp->ioc_error = 0;
194662387023Sdduvall need_privilege = B_TRUE;
194762387023Sdduvall cmd = iocp->ioc_cmd;
194862387023Sdduvall switch (cmd) {
194962387023Sdduvall default:
195062387023Sdduvall miocnak(wq, mp, 0, EINVAL);
195162387023Sdduvall return;
195262387023Sdduvall
195362387023Sdduvall case BGE_MII_READ:
195462387023Sdduvall case BGE_MII_WRITE:
195562387023Sdduvall case BGE_SEE_READ:
195662387023Sdduvall case BGE_SEE_WRITE:
1957f724721bSzh199473 case BGE_FLASH_READ:
1958f724721bSzh199473 case BGE_FLASH_WRITE:
195962387023Sdduvall case BGE_DIAG:
196062387023Sdduvall case BGE_PEEK:
196162387023Sdduvall case BGE_POKE:
196262387023Sdduvall case BGE_PHY_RESET:
196362387023Sdduvall case BGE_SOFT_RESET:
196462387023Sdduvall case BGE_HARD_RESET:
196562387023Sdduvall break;
196662387023Sdduvall
1967087a28d1SDavid Gwynne #ifdef NOT_SUPPORTED_XXX
196862387023Sdduvall case LB_GET_INFO_SIZE:
196962387023Sdduvall case LB_GET_INFO:
197062387023Sdduvall case LB_GET_MODE:
197162387023Sdduvall need_privilege = B_FALSE;
197262387023Sdduvall /* FALLTHRU */
197362387023Sdduvall case LB_SET_MODE:
197462387023Sdduvall break;
1975087a28d1SDavid Gwynne #endif
197662387023Sdduvall
197762387023Sdduvall }
197862387023Sdduvall
197962387023Sdduvall if (need_privilege) {
198062387023Sdduvall /*
198162387023Sdduvall * Check for specific net_config privilege on Solaris 10+.
198262387023Sdduvall */
198362387023Sdduvall err = secpolicy_net_config(iocp->ioc_cr, B_FALSE);
198462387023Sdduvall if (err != 0) {
198562387023Sdduvall miocnak(wq, mp, 0, err);
198662387023Sdduvall return;
198762387023Sdduvall }
198862387023Sdduvall }
198962387023Sdduvall
199062387023Sdduvall mutex_enter(bgep->genlock);
199100d0963fSdilpreet if (!(bgep->progress & PROGRESS_INTR)) {
199200d0963fSdilpreet /* can happen during autorecovery */
199300d0963fSdilpreet mutex_exit(bgep->genlock);
199400d0963fSdilpreet miocnak(wq, mp, 0, EIO);
199500d0963fSdilpreet return;
199600d0963fSdilpreet }
199762387023Sdduvall
199862387023Sdduvall switch (cmd) {
199962387023Sdduvall default:
200062387023Sdduvall _NOTE(NOTREACHED)
200162387023Sdduvall status = IOC_INVAL;
200262387023Sdduvall break;
200362387023Sdduvall
200462387023Sdduvall case BGE_MII_READ:
200562387023Sdduvall case BGE_MII_WRITE:
200662387023Sdduvall case BGE_SEE_READ:
200762387023Sdduvall case BGE_SEE_WRITE:
2008f724721bSzh199473 case BGE_FLASH_READ:
2009f724721bSzh199473 case BGE_FLASH_WRITE:
201062387023Sdduvall case BGE_DIAG:
201162387023Sdduvall case BGE_PEEK:
201262387023Sdduvall case BGE_POKE:
201362387023Sdduvall case BGE_PHY_RESET:
201462387023Sdduvall case BGE_SOFT_RESET:
201562387023Sdduvall case BGE_HARD_RESET:
201662387023Sdduvall status = bge_chip_ioctl(bgep, wq, mp, iocp);
201762387023Sdduvall break;
201862387023Sdduvall
2019087a28d1SDavid Gwynne #ifdef NOT_SUPPORTED_XXX
202062387023Sdduvall case LB_GET_INFO_SIZE:
202162387023Sdduvall case LB_GET_INFO:
202262387023Sdduvall case LB_GET_MODE:
202362387023Sdduvall case LB_SET_MODE:
202462387023Sdduvall status = bge_loop_ioctl(bgep, wq, mp, iocp);
202562387023Sdduvall break;
2026087a28d1SDavid Gwynne #endif
202762387023Sdduvall
202862387023Sdduvall }
202962387023Sdduvall
203062387023Sdduvall /*
203162387023Sdduvall * Do we need to reprogram the PHY and/or the MAC?
203262387023Sdduvall * Do it now, while we still have the mutex.
203362387023Sdduvall *
203462387023Sdduvall * Note: update the PHY first, 'cos it controls the
203562387023Sdduvall * speed/duplex parameters that the MAC code uses.
203662387023Sdduvall */
203762387023Sdduvall switch (status) {
203862387023Sdduvall case IOC_RESTART_REPLY:
203962387023Sdduvall case IOC_RESTART_ACK:
2040e7801d59Ssowmini if (bge_reprogram(bgep) == IOC_INVAL)
204100d0963fSdilpreet status = IOC_INVAL;
204262387023Sdduvall break;
204362387023Sdduvall }
204462387023Sdduvall
204500d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) {
204600d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED);
204700d0963fSdilpreet status = IOC_INVAL;
204800d0963fSdilpreet }
204900d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) {
205000d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED);
205100d0963fSdilpreet status = IOC_INVAL;
205200d0963fSdilpreet }
205362387023Sdduvall mutex_exit(bgep->genlock);
205462387023Sdduvall
205562387023Sdduvall /*
205662387023Sdduvall * Finally, decide how to reply
205762387023Sdduvall */
205862387023Sdduvall switch (status) {
205962387023Sdduvall default:
206062387023Sdduvall case IOC_INVAL:
206162387023Sdduvall /*
206262387023Sdduvall * Error, reply with a NAK and EINVAL or the specified error
206362387023Sdduvall */
206462387023Sdduvall miocnak(wq, mp, 0, iocp->ioc_error == 0 ?
206562387023Sdduvall EINVAL : iocp->ioc_error);
206662387023Sdduvall break;
206762387023Sdduvall
206862387023Sdduvall case IOC_DONE:
206962387023Sdduvall /*
207062387023Sdduvall * OK, reply already sent
207162387023Sdduvall */
207262387023Sdduvall break;
207362387023Sdduvall
207462387023Sdduvall case IOC_RESTART_ACK:
207562387023Sdduvall case IOC_ACK:
207662387023Sdduvall /*
207762387023Sdduvall * OK, reply with an ACK
207862387023Sdduvall */
207962387023Sdduvall miocack(wq, mp, 0, 0);
208062387023Sdduvall break;
208162387023Sdduvall
208262387023Sdduvall case IOC_RESTART_REPLY:
208362387023Sdduvall case IOC_REPLY:
208462387023Sdduvall /*
208562387023Sdduvall * OK, send prepared reply as ACK or NAK
208662387023Sdduvall */
208762387023Sdduvall mp->b_datap->db_type = iocp->ioc_error == 0 ?
208862387023Sdduvall M_IOCACK : M_IOCNAK;
208962387023Sdduvall qreply(wq, mp);
209062387023Sdduvall break;
209162387023Sdduvall }
209262387023Sdduvall }
209362387023Sdduvall
209462387023Sdduvall /*
209562387023Sdduvall * ========== Per-instance setup/teardown code ==========
209662387023Sdduvall */
209762387023Sdduvall
209862387023Sdduvall #undef BGE_DBG
2099087a28d1SDavid Gwynne #define BGE_DBG BGE_DBG_MEM /* debug flag for this code */
2100931dca7dSgs150176 /*
2101931dca7dSgs150176 * Allocate an area of memory and a DMA handle for accessing it
2102931dca7dSgs150176 */
2103931dca7dSgs150176 static int
2104931dca7dSgs150176 bge_alloc_dma_mem(bge_t *bgep, size_t memsize, ddi_device_acc_attr_t *attr_p,
2105931dca7dSgs150176 uint_t dma_flags, dma_area_t *dma_p)
2106931dca7dSgs150176 {
2107931dca7dSgs150176 caddr_t va;
2108931dca7dSgs150176 int err;
210962387023Sdduvall
2110931dca7dSgs150176 BGE_TRACE(("bge_alloc_dma_mem($%p, %ld, $%p, 0x%x, $%p)",
2111931dca7dSgs150176 (void *)bgep, memsize, attr_p, dma_flags, dma_p));
2112931dca7dSgs150176
2113931dca7dSgs150176 /*
2114931dca7dSgs150176 * Allocate handle
2115931dca7dSgs150176 */
2116931dca7dSgs150176 err = ddi_dma_alloc_handle(bgep->devinfo, &dma_attr,
2117931dca7dSgs150176 DDI_DMA_DONTWAIT, NULL, &dma_p->dma_hdl);
2118931dca7dSgs150176 if (err != DDI_SUCCESS)
2119931dca7dSgs150176 return (DDI_FAILURE);
2120931dca7dSgs150176
2121931dca7dSgs150176 /*
2122931dca7dSgs150176 * Allocate memory
2123931dca7dSgs150176 */
2124931dca7dSgs150176 err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, attr_p,
2125931dca7dSgs150176 dma_flags, DDI_DMA_DONTWAIT, NULL, &va, &dma_p->alength,
2126931dca7dSgs150176 &dma_p->acc_hdl);
2127931dca7dSgs150176 if (err != DDI_SUCCESS)
2128931dca7dSgs150176 return (DDI_FAILURE);
2129931dca7dSgs150176
2130931dca7dSgs150176 /*
2131931dca7dSgs150176 * Bind the two together
2132931dca7dSgs150176 */
2133931dca7dSgs150176 dma_p->mem_va = va;
2134931dca7dSgs150176 err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL,
2135931dca7dSgs150176 va, dma_p->alength, dma_flags, DDI_DMA_DONTWAIT, NULL,
2136931dca7dSgs150176 &dma_p->cookie, &dma_p->ncookies);
2137931dca7dSgs150176
2138931dca7dSgs150176 BGE_DEBUG(("bge_alloc_dma_mem(): bind %d bytes; err %d, %d cookies",
2139931dca7dSgs150176 dma_p->alength, err, dma_p->ncookies));
2140931dca7dSgs150176
2141931dca7dSgs150176 if (err != DDI_DMA_MAPPED || dma_p->ncookies != 1)
2142931dca7dSgs150176 return (DDI_FAILURE);
2143931dca7dSgs150176
2144931dca7dSgs150176 dma_p->nslots = ~0U;
2145931dca7dSgs150176 dma_p->size = ~0U;
2146931dca7dSgs150176 dma_p->token = ~0U;
2147931dca7dSgs150176 dma_p->offset = 0;
2148931dca7dSgs150176 return (DDI_SUCCESS);
2149931dca7dSgs150176 }
2150931dca7dSgs150176
2151931dca7dSgs150176 /*
2152931dca7dSgs150176 * Free one allocated area of DMAable memory
2153931dca7dSgs150176 */
2154931dca7dSgs150176 static void
2155931dca7dSgs150176 bge_free_dma_mem(dma_area_t *dma_p)
2156931dca7dSgs150176 {
2157931dca7dSgs150176 if (dma_p->dma_hdl != NULL) {
2158931dca7dSgs150176 if (dma_p->ncookies) {
2159931dca7dSgs150176 (void) ddi_dma_unbind_handle(dma_p->dma_hdl);
2160931dca7dSgs150176 dma_p->ncookies = 0;
2161931dca7dSgs150176 }
2162931dca7dSgs150176 ddi_dma_free_handle(&dma_p->dma_hdl);
2163931dca7dSgs150176 dma_p->dma_hdl = NULL;
2164931dca7dSgs150176 }
2165931dca7dSgs150176
2166931dca7dSgs150176 if (dma_p->acc_hdl != NULL) {
2167931dca7dSgs150176 ddi_dma_mem_free(&dma_p->acc_hdl);
2168931dca7dSgs150176 dma_p->acc_hdl = NULL;
2169931dca7dSgs150176 }
2170931dca7dSgs150176 }
217162387023Sdduvall /*
217262387023Sdduvall * Utility routine to carve a slice off a chunk of allocated memory,
217362387023Sdduvall * updating the chunk descriptor accordingly. The size of the slice
217462387023Sdduvall * is given by the product of the <qty> and <size> parameters.
217562387023Sdduvall */
217662387023Sdduvall static void
217762387023Sdduvall bge_slice_chunk(dma_area_t *slice, dma_area_t *chunk,
217862387023Sdduvall uint32_t qty, uint32_t size)
217962387023Sdduvall {
218062387023Sdduvall static uint32_t sequence = 0xbcd5704a;
218162387023Sdduvall size_t totsize;
218262387023Sdduvall
218362387023Sdduvall totsize = qty*size;
218462387023Sdduvall ASSERT(totsize <= chunk->alength);
218562387023Sdduvall
218662387023Sdduvall *slice = *chunk;
218762387023Sdduvall slice->nslots = qty;
218862387023Sdduvall slice->size = size;
218962387023Sdduvall slice->alength = totsize;
219062387023Sdduvall slice->token = ++sequence;
219162387023Sdduvall
219262387023Sdduvall chunk->mem_va = (caddr_t)chunk->mem_va + totsize;
219362387023Sdduvall chunk->alength -= totsize;
219462387023Sdduvall chunk->offset += totsize;
219562387023Sdduvall chunk->cookie.dmac_laddress += totsize;
219662387023Sdduvall chunk->cookie.dmac_size -= totsize;
219762387023Sdduvall }
219862387023Sdduvall
219962387023Sdduvall /*
220062387023Sdduvall * Initialise the specified Receive Producer (Buffer) Ring, using
220162387023Sdduvall * the information in the <dma_area> descriptors that it contains
220262387023Sdduvall * to set up all the other fields. This routine should be called
220362387023Sdduvall * only once for each ring.
220462387023Sdduvall */
220562387023Sdduvall static void
220662387023Sdduvall bge_init_buff_ring(bge_t *bgep, uint64_t ring)
220762387023Sdduvall {
220862387023Sdduvall buff_ring_t *brp;
220962387023Sdduvall bge_status_t *bsp;
221062387023Sdduvall sw_rbd_t *srbdp;
221162387023Sdduvall dma_area_t pbuf;
221262387023Sdduvall uint32_t bufsize;
221362387023Sdduvall uint32_t nslots;
221462387023Sdduvall uint32_t slot;
221562387023Sdduvall uint32_t split;
221662387023Sdduvall
221762387023Sdduvall static bge_regno_t nic_ring_addrs[BGE_BUFF_RINGS_MAX] = {
221862387023Sdduvall NIC_MEM_SHADOW_BUFF_STD,
221962387023Sdduvall NIC_MEM_SHADOW_BUFF_JUMBO,
222062387023Sdduvall NIC_MEM_SHADOW_BUFF_MINI
222162387023Sdduvall };
222262387023Sdduvall static bge_regno_t mailbox_regs[BGE_BUFF_RINGS_MAX] = {
222362387023Sdduvall RECV_STD_PROD_INDEX_REG,
222462387023Sdduvall RECV_JUMBO_PROD_INDEX_REG,
222562387023Sdduvall RECV_MINI_PROD_INDEX_REG
222662387023Sdduvall };
222762387023Sdduvall static bge_regno_t buff_cons_xref[BGE_BUFF_RINGS_MAX] = {
222862387023Sdduvall STATUS_STD_BUFF_CONS_INDEX,
222962387023Sdduvall STATUS_JUMBO_BUFF_CONS_INDEX,
223062387023Sdduvall STATUS_MINI_BUFF_CONS_INDEX
223162387023Sdduvall };
223262387023Sdduvall
223362387023Sdduvall BGE_TRACE(("bge_init_buff_ring($%p, %d)",
223462387023Sdduvall (void *)bgep, ring));
223562387023Sdduvall
223662387023Sdduvall brp = &bgep->buff[ring];
223762387023Sdduvall nslots = brp->desc.nslots;
223862387023Sdduvall ASSERT(brp->buf[0].nslots == nslots/BGE_SPLIT);
223962387023Sdduvall bufsize = brp->buf[0].size;
224062387023Sdduvall
224162387023Sdduvall /*
224262387023Sdduvall * Set up the copy of the h/w RCB
224362387023Sdduvall *
224462387023Sdduvall * Note: unlike Send & Receive Return Rings, (where the max_len
224562387023Sdduvall * field holds the number of slots), in a Receive Buffer Ring
224662387023Sdduvall * this field indicates the size of each buffer in the ring.
224762387023Sdduvall */
224862387023Sdduvall brp->hw_rcb.host_ring_addr = brp->desc.cookie.dmac_laddress;
22494a06b59fSyt223700 brp->hw_rcb.max_len = (uint16_t)bufsize;
225062387023Sdduvall brp->hw_rcb.flags = nslots > 0 ? 0 : RCB_FLAG_RING_DISABLED;
225162387023Sdduvall brp->hw_rcb.nic_ring_addr = nic_ring_addrs[ring];
225262387023Sdduvall
225362387023Sdduvall /*
225462387023Sdduvall * Other one-off initialisation of per-ring data
225562387023Sdduvall */
225662387023Sdduvall brp->bgep = bgep;
225762387023Sdduvall bsp = DMA_VPTR(bgep->status_block);
225862387023Sdduvall brp->cons_index_p = &bsp->buff_cons_index[buff_cons_xref[ring]];
225962387023Sdduvall brp->chip_mbx_reg = mailbox_regs[ring];
226062387023Sdduvall mutex_init(brp->rf_lock, NULL, MUTEX_DRIVER,
226162387023Sdduvall DDI_INTR_PRI(bgep->intr_pri));
226262387023Sdduvall
226362387023Sdduvall /*
226462387023Sdduvall * Allocate the array of s/w Receive Buffer Descriptors
226562387023Sdduvall */
226662387023Sdduvall srbdp = kmem_zalloc(nslots*sizeof (*srbdp), KM_SLEEP);
226762387023Sdduvall brp->sw_rbds = srbdp;
226862387023Sdduvall
226962387023Sdduvall /*
227062387023Sdduvall * Now initialise each array element once and for all
227162387023Sdduvall */
227262387023Sdduvall for (split = 0; split < BGE_SPLIT; ++split) {
227362387023Sdduvall pbuf = brp->buf[split];
227462387023Sdduvall for (slot = 0; slot < nslots/BGE_SPLIT; ++srbdp, ++slot)
227562387023Sdduvall bge_slice_chunk(&srbdp->pbuf, &pbuf, 1, bufsize);
227662387023Sdduvall ASSERT(pbuf.alength == 0);
227762387023Sdduvall }
227862387023Sdduvall }
227962387023Sdduvall
228062387023Sdduvall /*
228162387023Sdduvall * Clean up initialisation done above before the memory is freed
228262387023Sdduvall */
228362387023Sdduvall static void
228462387023Sdduvall bge_fini_buff_ring(bge_t *bgep, uint64_t ring)
228562387023Sdduvall {
228662387023Sdduvall buff_ring_t *brp;
228762387023Sdduvall sw_rbd_t *srbdp;
228862387023Sdduvall
228962387023Sdduvall BGE_TRACE(("bge_fini_buff_ring($%p, %d)",
229062387023Sdduvall (void *)bgep, ring));
229162387023Sdduvall
229262387023Sdduvall brp = &bgep->buff[ring];
229362387023Sdduvall srbdp = brp->sw_rbds;
229462387023Sdduvall kmem_free(srbdp, brp->desc.nslots*sizeof (*srbdp));
229562387023Sdduvall
229662387023Sdduvall mutex_destroy(brp->rf_lock);
229762387023Sdduvall }
229862387023Sdduvall
229962387023Sdduvall /*
230062387023Sdduvall * Initialise the specified Receive (Return) Ring, using the
230162387023Sdduvall * information in the <dma_area> descriptors that it contains
230262387023Sdduvall * to set up all the other fields. This routine should be called
230362387023Sdduvall * only once for each ring.
230462387023Sdduvall */
230562387023Sdduvall static void
230662387023Sdduvall bge_init_recv_ring(bge_t *bgep, uint64_t ring)
230762387023Sdduvall {
230862387023Sdduvall recv_ring_t *rrp;
230962387023Sdduvall bge_status_t *bsp;
231062387023Sdduvall uint32_t nslots;
231162387023Sdduvall
231262387023Sdduvall BGE_TRACE(("bge_init_recv_ring($%p, %d)",
231362387023Sdduvall (void *)bgep, ring));
231462387023Sdduvall
231562387023Sdduvall /*
231662387023Sdduvall * The chip architecture requires that receive return rings have
231762387023Sdduvall * 512 or 1024 or 2048 elements per ring. See 570X-PG108-R page 103.
231862387023Sdduvall */
231962387023Sdduvall rrp = &bgep->recv[ring];
232062387023Sdduvall nslots = rrp->desc.nslots;
232162387023Sdduvall ASSERT(nslots == 0 || nslots == 512 ||
232262387023Sdduvall nslots == 1024 || nslots == 2048);
232362387023Sdduvall
232462387023Sdduvall /*
232562387023Sdduvall * Set up the copy of the h/w RCB
232662387023Sdduvall */
232762387023Sdduvall rrp->hw_rcb.host_ring_addr = rrp->desc.cookie.dmac_laddress;
23284a06b59fSyt223700 rrp->hw_rcb.max_len = (uint16_t)nslots;
232962387023Sdduvall rrp->hw_rcb.flags = nslots > 0 ? 0 : RCB_FLAG_RING_DISABLED;
233062387023Sdduvall rrp->hw_rcb.nic_ring_addr = 0;
233162387023Sdduvall
233262387023Sdduvall /*
233362387023Sdduvall * Other one-off initialisation of per-ring data
233462387023Sdduvall */
233562387023Sdduvall rrp->bgep = bgep;
233662387023Sdduvall bsp = DMA_VPTR(bgep->status_block);
233762387023Sdduvall rrp->prod_index_p = RECV_INDEX_P(bsp, ring);
233862387023Sdduvall rrp->chip_mbx_reg = RECV_RING_CONS_INDEX_REG(ring);
233962387023Sdduvall mutex_init(rrp->rx_lock, NULL, MUTEX_DRIVER,
234062387023Sdduvall DDI_INTR_PRI(bgep->intr_pri));
234162387023Sdduvall }
234262387023Sdduvall
234362387023Sdduvall
234462387023Sdduvall /*
234562387023Sdduvall * Clean up initialisation done above before the memory is freed
234662387023Sdduvall */
234762387023Sdduvall static void
234862387023Sdduvall bge_fini_recv_ring(bge_t *bgep, uint64_t ring)
234962387023Sdduvall {
235062387023Sdduvall recv_ring_t *rrp;
235162387023Sdduvall
235262387023Sdduvall BGE_TRACE(("bge_fini_recv_ring($%p, %d)",
235362387023Sdduvall (void *)bgep, ring));
235462387023Sdduvall
235562387023Sdduvall rrp = &bgep->recv[ring];
235662387023Sdduvall if (rrp->rx_softint)
235762387023Sdduvall ddi_remove_softintr(rrp->rx_softint);
235862387023Sdduvall mutex_destroy(rrp->rx_lock);
235962387023Sdduvall }
236062387023Sdduvall
236162387023Sdduvall /*
236262387023Sdduvall * Initialise the specified Send Ring, using the information in the
236362387023Sdduvall * <dma_area> descriptors that it contains to set up all the other
236462387023Sdduvall * fields. This routine should be called only once for each ring.
236562387023Sdduvall */
236662387023Sdduvall static void
236762387023Sdduvall bge_init_send_ring(bge_t *bgep, uint64_t ring)
236862387023Sdduvall {
236962387023Sdduvall send_ring_t *srp;
237062387023Sdduvall bge_status_t *bsp;
237162387023Sdduvall sw_sbd_t *ssbdp;
237262387023Sdduvall dma_area_t desc;
237362387023Sdduvall dma_area_t pbuf;
237462387023Sdduvall uint32_t nslots;
237562387023Sdduvall uint32_t slot;
237662387023Sdduvall uint32_t split;
2377931dca7dSgs150176 sw_txbuf_t *txbuf;
237862387023Sdduvall
237962387023Sdduvall BGE_TRACE(("bge_init_send_ring($%p, %d)",
238062387023Sdduvall (void *)bgep, ring));
238162387023Sdduvall
238262387023Sdduvall /*
238362387023Sdduvall * The chip architecture requires that host-based send rings
238462387023Sdduvall * have 512 elements per ring. See 570X-PG102-R page 56.
238562387023Sdduvall */
238662387023Sdduvall srp = &bgep->send[ring];
238762387023Sdduvall nslots = srp->desc.nslots;
238862387023Sdduvall ASSERT(nslots == 0 || nslots == 512);
238962387023Sdduvall
239062387023Sdduvall /*
239162387023Sdduvall * Set up the copy of the h/w RCB
239262387023Sdduvall */
239362387023Sdduvall srp->hw_rcb.host_ring_addr = srp->desc.cookie.dmac_laddress;
23944a06b59fSyt223700 srp->hw_rcb.max_len = (uint16_t)nslots;
239562387023Sdduvall srp->hw_rcb.flags = nslots > 0 ? 0 : RCB_FLAG_RING_DISABLED;
239662387023Sdduvall srp->hw_rcb.nic_ring_addr = NIC_MEM_SHADOW_SEND_RING(ring, nslots);
239762387023Sdduvall
239862387023Sdduvall /*
239962387023Sdduvall * Other one-off initialisation of per-ring data
240062387023Sdduvall */
240162387023Sdduvall srp->bgep = bgep;
240262387023Sdduvall bsp = DMA_VPTR(bgep->status_block);
240362387023Sdduvall srp->cons_index_p = SEND_INDEX_P(bsp, ring);
240462387023Sdduvall srp->chip_mbx_reg = SEND_RING_HOST_INDEX_REG(ring);
240562387023Sdduvall mutex_init(srp->tx_lock, NULL, MUTEX_DRIVER,
240662387023Sdduvall DDI_INTR_PRI(bgep->intr_pri));
2407931dca7dSgs150176 mutex_init(srp->txbuf_lock, NULL, MUTEX_DRIVER,
2408931dca7dSgs150176 DDI_INTR_PRI(bgep->intr_pri));
2409931dca7dSgs150176 mutex_init(srp->freetxbuf_lock, NULL, MUTEX_DRIVER,
2410931dca7dSgs150176 DDI_INTR_PRI(bgep->intr_pri));
241162387023Sdduvall mutex_init(srp->tc_lock, NULL, MUTEX_DRIVER,
241262387023Sdduvall DDI_INTR_PRI(bgep->intr_pri));
2413931dca7dSgs150176 if (nslots == 0)
2414931dca7dSgs150176 return;
241562387023Sdduvall
241662387023Sdduvall /*
241762387023Sdduvall * Allocate the array of s/w Send Buffer Descriptors
241862387023Sdduvall */
241962387023Sdduvall ssbdp = kmem_zalloc(nslots*sizeof (*ssbdp), KM_SLEEP);
2420931dca7dSgs150176 txbuf = kmem_zalloc(BGE_SEND_BUF_MAX*sizeof (*txbuf), KM_SLEEP);
2421931dca7dSgs150176 srp->txbuf_head =
2422931dca7dSgs150176 kmem_zalloc(BGE_SEND_BUF_MAX*sizeof (bge_queue_item_t), KM_SLEEP);
2423931dca7dSgs150176 srp->pktp = kmem_zalloc(BGE_SEND_BUF_MAX*sizeof (send_pkt_t), KM_SLEEP);
242462387023Sdduvall srp->sw_sbds = ssbdp;
2425931dca7dSgs150176 srp->txbuf = txbuf;
2426931dca7dSgs150176 srp->tx_buffers = BGE_SEND_BUF_NUM;
2427931dca7dSgs150176 srp->tx_buffers_low = srp->tx_buffers / 4;
2428931dca7dSgs150176 if (bgep->chipid.snd_buff_size > BGE_SEND_BUFF_SIZE_DEFAULT)
2429931dca7dSgs150176 srp->tx_array_max = BGE_SEND_BUF_ARRAY_JUMBO;
2430931dca7dSgs150176 else
2431931dca7dSgs150176 srp->tx_array_max = BGE_SEND_BUF_ARRAY;
2432931dca7dSgs150176 srp->tx_array = 1;
243362387023Sdduvall
243462387023Sdduvall /*
2435931dca7dSgs150176 * Chunk tx desc area
243662387023Sdduvall */
243762387023Sdduvall desc = srp->desc;
2438931dca7dSgs150176 for (slot = 0; slot < nslots; ++ssbdp, ++slot) {
243962387023Sdduvall bge_slice_chunk(&ssbdp->desc, &desc, 1,
244062387023Sdduvall sizeof (bge_sbd_t));
2441931dca7dSgs150176 }
2442931dca7dSgs150176 ASSERT(desc.alength == 0);
2443931dca7dSgs150176
2444931dca7dSgs150176 /*
2445931dca7dSgs150176 * Chunk tx buffer area
2446931dca7dSgs150176 */
2447931dca7dSgs150176 for (split = 0; split < BGE_SPLIT; ++split) {
2448931dca7dSgs150176 pbuf = srp->buf[0][split];
2449931dca7dSgs150176 for (slot = 0; slot < BGE_SEND_BUF_NUM/BGE_SPLIT; ++slot) {
2450931dca7dSgs150176 bge_slice_chunk(&txbuf->buf, &pbuf, 1,
245162387023Sdduvall bgep->chipid.snd_buff_size);
2452931dca7dSgs150176 txbuf++;
245362387023Sdduvall }
245462387023Sdduvall ASSERT(pbuf.alength == 0);
245562387023Sdduvall }
245662387023Sdduvall }
245762387023Sdduvall
245862387023Sdduvall /*
245962387023Sdduvall * Clean up initialisation done above before the memory is freed
246062387023Sdduvall */
246162387023Sdduvall static void
246262387023Sdduvall bge_fini_send_ring(bge_t *bgep, uint64_t ring)
246362387023Sdduvall {
246462387023Sdduvall send_ring_t *srp;
2465931dca7dSgs150176 uint32_t array;
2466931dca7dSgs150176 uint32_t split;
2467931dca7dSgs150176 uint32_t nslots;
246862387023Sdduvall
246962387023Sdduvall BGE_TRACE(("bge_fini_send_ring($%p, %d)",
247062387023Sdduvall (void *)bgep, ring));
247162387023Sdduvall
247262387023Sdduvall srp = &bgep->send[ring];
247362387023Sdduvall mutex_destroy(srp->tc_lock);
2474931dca7dSgs150176 mutex_destroy(srp->freetxbuf_lock);
2475931dca7dSgs150176 mutex_destroy(srp->txbuf_lock);
2476931dca7dSgs150176 mutex_destroy(srp->tx_lock);
2477931dca7dSgs150176 nslots = srp->desc.nslots;
2478931dca7dSgs150176 if (nslots == 0)
2479931dca7dSgs150176 return;
2480931dca7dSgs150176
2481931dca7dSgs150176 for (array = 1; array < srp->tx_array; ++array)
2482931dca7dSgs150176 for (split = 0; split < BGE_SPLIT; ++split)
2483931dca7dSgs150176 bge_free_dma_mem(&srp->buf[array][split]);
2484931dca7dSgs150176 kmem_free(srp->sw_sbds, nslots*sizeof (*srp->sw_sbds));
2485931dca7dSgs150176 kmem_free(srp->txbuf_head, BGE_SEND_BUF_MAX*sizeof (*srp->txbuf_head));
2486931dca7dSgs150176 kmem_free(srp->txbuf, BGE_SEND_BUF_MAX*sizeof (*srp->txbuf));
2487931dca7dSgs150176 kmem_free(srp->pktp, BGE_SEND_BUF_MAX*sizeof (*srp->pktp));
2488931dca7dSgs150176 srp->sw_sbds = NULL;
2489931dca7dSgs150176 srp->txbuf_head = NULL;
2490931dca7dSgs150176 srp->txbuf = NULL;
2491931dca7dSgs150176 srp->pktp = NULL;
249262387023Sdduvall }
249362387023Sdduvall
249462387023Sdduvall /*
249562387023Sdduvall * Initialise all transmit, receive, and buffer rings.
249662387023Sdduvall */
249700d0963fSdilpreet void
249862387023Sdduvall bge_init_rings(bge_t *bgep)
249962387023Sdduvall {
2500931dca7dSgs150176 uint32_t ring;
250162387023Sdduvall
250262387023Sdduvall BGE_TRACE(("bge_init_rings($%p)", (void *)bgep));
250362387023Sdduvall
250462387023Sdduvall /*
250562387023Sdduvall * Perform one-off initialisation of each ring ...
250662387023Sdduvall */
250762387023Sdduvall for (ring = 0; ring < BGE_SEND_RINGS_MAX; ++ring)
250862387023Sdduvall bge_init_send_ring(bgep, ring);
250962387023Sdduvall for (ring = 0; ring < BGE_RECV_RINGS_MAX; ++ring)
251062387023Sdduvall bge_init_recv_ring(bgep, ring);
251162387023Sdduvall for (ring = 0; ring < BGE_BUFF_RINGS_MAX; ++ring)
251262387023Sdduvall bge_init_buff_ring(bgep, ring);
251362387023Sdduvall }
251462387023Sdduvall
251562387023Sdduvall /*
251662387023Sdduvall * Undo the work of bge_init_rings() above before the memory is freed
251762387023Sdduvall */
251800d0963fSdilpreet void
251962387023Sdduvall bge_fini_rings(bge_t *bgep)
252062387023Sdduvall {
2521931dca7dSgs150176 uint32_t ring;
252262387023Sdduvall
252362387023Sdduvall BGE_TRACE(("bge_fini_rings($%p)", (void *)bgep));
252462387023Sdduvall
252562387023Sdduvall for (ring = 0; ring < BGE_BUFF_RINGS_MAX; ++ring)
252662387023Sdduvall bge_fini_buff_ring(bgep, ring);
252762387023Sdduvall for (ring = 0; ring < BGE_RECV_RINGS_MAX; ++ring)
252862387023Sdduvall bge_fini_recv_ring(bgep, ring);
252962387023Sdduvall for (ring = 0; ring < BGE_SEND_RINGS_MAX; ++ring)
253062387023Sdduvall bge_fini_send_ring(bgep, ring);
253162387023Sdduvall }
253262387023Sdduvall
253362387023Sdduvall /*
2534931dca7dSgs150176 * Called from the bge_m_stop() to free the tx buffers which are
2535931dca7dSgs150176 * allocated from the tx process.
253662387023Sdduvall */
2537931dca7dSgs150176 void
2538931dca7dSgs150176 bge_free_txbuf_arrays(send_ring_t *srp)
253962387023Sdduvall {
2540931dca7dSgs150176 uint32_t array;
2541931dca7dSgs150176 uint32_t split;
254262387023Sdduvall
2543931dca7dSgs150176 ASSERT(mutex_owned(srp->tx_lock));
254462387023Sdduvall
254562387023Sdduvall /*
2546931dca7dSgs150176 * Free the extra tx buffer DMA area
254762387023Sdduvall */
2548931dca7dSgs150176 for (array = 1; array < srp->tx_array; ++array)
2549931dca7dSgs150176 for (split = 0; split < BGE_SPLIT; ++split)
2550931dca7dSgs150176 bge_free_dma_mem(&srp->buf[array][split]);
255162387023Sdduvall
255262387023Sdduvall /*
2553931dca7dSgs150176 * Restore initial tx buffer numbers
255462387023Sdduvall */
2555931dca7dSgs150176 srp->tx_array = 1;
2556931dca7dSgs150176 srp->tx_buffers = BGE_SEND_BUF_NUM;
2557931dca7dSgs150176 srp->tx_buffers_low = srp->tx_buffers / 4;
2558931dca7dSgs150176 srp->tx_flow = 0;
2559931dca7dSgs150176 bzero(srp->pktp, BGE_SEND_BUF_MAX * sizeof (*srp->pktp));
256062387023Sdduvall }
256162387023Sdduvall
256262387023Sdduvall /*
2563931dca7dSgs150176 * Called from tx process to allocate more tx buffers
256462387023Sdduvall */
2565931dca7dSgs150176 bge_queue_item_t *
2566931dca7dSgs150176 bge_alloc_txbuf_array(bge_t *bgep, send_ring_t *srp)
256762387023Sdduvall {
2568931dca7dSgs150176 bge_queue_t *txbuf_queue;
2569931dca7dSgs150176 bge_queue_item_t *txbuf_item_last;
2570931dca7dSgs150176 bge_queue_item_t *txbuf_item;
2571931dca7dSgs150176 bge_queue_item_t *txbuf_item_rtn;
2572931dca7dSgs150176 sw_txbuf_t *txbuf;
2573931dca7dSgs150176 dma_area_t area;
2574931dca7dSgs150176 size_t txbuffsize;
2575931dca7dSgs150176 uint32_t slot;
2576931dca7dSgs150176 uint32_t array;
2577931dca7dSgs150176 uint32_t split;
2578931dca7dSgs150176 uint32_t err;
2579931dca7dSgs150176
2580931dca7dSgs150176 ASSERT(mutex_owned(srp->tx_lock));
2581931dca7dSgs150176
2582931dca7dSgs150176 array = srp->tx_array;
2583931dca7dSgs150176 if (array >= srp->tx_array_max)
2584931dca7dSgs150176 return (NULL);
2585931dca7dSgs150176
2586931dca7dSgs150176 /*
2587931dca7dSgs150176 * Allocate memory & handles for TX buffers
2588931dca7dSgs150176 */
2589931dca7dSgs150176 txbuffsize = BGE_SEND_BUF_NUM*bgep->chipid.snd_buff_size;
2590931dca7dSgs150176 ASSERT((txbuffsize % BGE_SPLIT) == 0);
2591931dca7dSgs150176 for (split = 0; split < BGE_SPLIT; ++split) {
2592931dca7dSgs150176 err = bge_alloc_dma_mem(bgep, txbuffsize/BGE_SPLIT,
2593931dca7dSgs150176 &bge_data_accattr, DDI_DMA_WRITE | BGE_DMA_MODE,
2594931dca7dSgs150176 &srp->buf[array][split]);
2595931dca7dSgs150176 if (err != DDI_SUCCESS) {
2596931dca7dSgs150176 /* Free the last already allocated OK chunks */
2597931dca7dSgs150176 for (slot = 0; slot <= split; ++slot)
2598931dca7dSgs150176 bge_free_dma_mem(&srp->buf[array][slot]);
2599931dca7dSgs150176 srp->tx_alloc_fail++;
2600931dca7dSgs150176 return (NULL);
260162387023Sdduvall }
260262387023Sdduvall }
260362387023Sdduvall
2604931dca7dSgs150176 /*
2605931dca7dSgs150176 * Chunk tx buffer area
2606931dca7dSgs150176 */
2607931dca7dSgs150176 txbuf = srp->txbuf + array*BGE_SEND_BUF_NUM;
2608931dca7dSgs150176 for (split = 0; split < BGE_SPLIT; ++split) {
2609931dca7dSgs150176 area = srp->buf[array][split];
2610931dca7dSgs150176 for (slot = 0; slot < BGE_SEND_BUF_NUM/BGE_SPLIT; ++slot) {
2611931dca7dSgs150176 bge_slice_chunk(&txbuf->buf, &area, 1,
2612931dca7dSgs150176 bgep->chipid.snd_buff_size);
2613931dca7dSgs150176 txbuf++;
261462387023Sdduvall }
261562387023Sdduvall }
261662387023Sdduvall
261762387023Sdduvall /*
2618931dca7dSgs150176 * Add above buffers to the tx buffer pop queue
2619931dca7dSgs150176 */
2620931dca7dSgs150176 txbuf_item = srp->txbuf_head + array*BGE_SEND_BUF_NUM;
2621931dca7dSgs150176 txbuf = srp->txbuf + array*BGE_SEND_BUF_NUM;
2622931dca7dSgs150176 txbuf_item_last = NULL;
2623931dca7dSgs150176 for (slot = 0; slot < BGE_SEND_BUF_NUM; ++slot) {
2624931dca7dSgs150176 txbuf_item->item = txbuf;
2625931dca7dSgs150176 txbuf_item->next = txbuf_item_last;
2626931dca7dSgs150176 txbuf_item_last = txbuf_item;
2627931dca7dSgs150176 txbuf++;
2628931dca7dSgs150176 txbuf_item++;
2629931dca7dSgs150176 }
2630931dca7dSgs150176 txbuf_item = srp->txbuf_head + array*BGE_SEND_BUF_NUM;
2631931dca7dSgs150176 txbuf_item_rtn = txbuf_item;
2632931dca7dSgs150176 txbuf_item++;
2633931dca7dSgs150176 txbuf_queue = srp->txbuf_pop_queue;
2634931dca7dSgs150176 mutex_enter(txbuf_queue->lock);
2635931dca7dSgs150176 txbuf_item->next = txbuf_queue->head;
2636931dca7dSgs150176 txbuf_queue->head = txbuf_item_last;
2637931dca7dSgs150176 txbuf_queue->count += BGE_SEND_BUF_NUM - 1;
2638931dca7dSgs150176 mutex_exit(txbuf_queue->lock);
2639931dca7dSgs150176
2640931dca7dSgs150176 srp->tx_array++;
2641931dca7dSgs150176 srp->tx_buffers += BGE_SEND_BUF_NUM;
2642931dca7dSgs150176 srp->tx_buffers_low = srp->tx_buffers / 4;
2643931dca7dSgs150176
2644931dca7dSgs150176 return (txbuf_item_rtn);
2645931dca7dSgs150176 }
2646931dca7dSgs150176
2647931dca7dSgs150176 /*
264862387023Sdduvall * This function allocates all the transmit and receive buffers
2649931dca7dSgs150176 * and descriptors, in four chunks.
265062387023Sdduvall */
265100d0963fSdilpreet int
265262387023Sdduvall bge_alloc_bufs(bge_t *bgep)
265362387023Sdduvall {
265462387023Sdduvall dma_area_t area;
265562387023Sdduvall size_t rxbuffsize;
265662387023Sdduvall size_t txbuffsize;
265762387023Sdduvall size_t rxbuffdescsize;
265862387023Sdduvall size_t rxdescsize;
265962387023Sdduvall size_t txdescsize;
2660931dca7dSgs150176 uint32_t ring;
2661931dca7dSgs150176 uint32_t rx_rings = bgep->chipid.rx_rings;
2662931dca7dSgs150176 uint32_t tx_rings = bgep->chipid.tx_rings;
266362387023Sdduvall int split;
266462387023Sdduvall int err;
266562387023Sdduvall
266662387023Sdduvall BGE_TRACE(("bge_alloc_bufs($%p)",
266762387023Sdduvall (void *)bgep));
266862387023Sdduvall
26691b5c96f3Sly149593 rxbuffsize = BGE_STD_SLOTS_USED*bgep->chipid.std_buf_size;
267062387023Sdduvall rxbuffsize += bgep->chipid.jumbo_slots*bgep->chipid.recv_jumbo_size;
267162387023Sdduvall rxbuffsize += BGE_MINI_SLOTS_USED*BGE_MINI_BUFF_SIZE;
267262387023Sdduvall
2673931dca7dSgs150176 txbuffsize = BGE_SEND_BUF_NUM*bgep->chipid.snd_buff_size;
267462387023Sdduvall txbuffsize *= tx_rings;
267562387023Sdduvall
267662387023Sdduvall rxdescsize = rx_rings*bgep->chipid.recv_slots;
267762387023Sdduvall rxdescsize *= sizeof (bge_rbd_t);
267862387023Sdduvall
267962387023Sdduvall rxbuffdescsize = BGE_STD_SLOTS_USED;
268062387023Sdduvall rxbuffdescsize += bgep->chipid.jumbo_slots;
268162387023Sdduvall rxbuffdescsize += BGE_MINI_SLOTS_USED;
268262387023Sdduvall rxbuffdescsize *= sizeof (bge_rbd_t);
268362387023Sdduvall
268462387023Sdduvall txdescsize = tx_rings*BGE_SEND_SLOTS_USED;
268562387023Sdduvall txdescsize *= sizeof (bge_sbd_t);
268662387023Sdduvall txdescsize += sizeof (bge_statistics_t);
268762387023Sdduvall txdescsize += sizeof (bge_status_t);
268862387023Sdduvall txdescsize += BGE_STATUS_PADDING;
268962387023Sdduvall
269062387023Sdduvall /*
26915952d588Szh199473 * Enable PCI relaxed ordering only for RX/TX data buffers
26925952d588Szh199473 */
2693087a28d1SDavid Gwynne if (!(DEVICE_5717_SERIES_CHIPSETS(bgep) ||
2694087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep))) {
26955952d588Szh199473 if (bge_relaxed_ordering)
26965952d588Szh199473 dma_attr.dma_attr_flags |= DDI_DMA_RELAXED_ORDERING;
2697087a28d1SDavid Gwynne }
26985952d588Szh199473
26995952d588Szh199473 /*
270062387023Sdduvall * Allocate memory & handles for RX buffers
270162387023Sdduvall */
270262387023Sdduvall ASSERT((rxbuffsize % BGE_SPLIT) == 0);
270362387023Sdduvall for (split = 0; split < BGE_SPLIT; ++split) {
270462387023Sdduvall err = bge_alloc_dma_mem(bgep, rxbuffsize/BGE_SPLIT,
270562387023Sdduvall &bge_data_accattr, DDI_DMA_READ | BGE_DMA_MODE,
270662387023Sdduvall &bgep->rx_buff[split]);
270762387023Sdduvall if (err != DDI_SUCCESS)
270862387023Sdduvall return (DDI_FAILURE);
270962387023Sdduvall }
2710087a28d1SDavid Gwynne BGE_DEBUG(("DMA ALLOC: allocated %d chunks for Rx Buffers (rxbuffsize = %d)",
2711087a28d1SDavid Gwynne rxbuffsize/BGE_SPLIT,
2712087a28d1SDavid Gwynne rxbuffsize));
271362387023Sdduvall
271462387023Sdduvall /*
271562387023Sdduvall * Allocate memory & handles for TX buffers
271662387023Sdduvall */
271762387023Sdduvall ASSERT((txbuffsize % BGE_SPLIT) == 0);
271862387023Sdduvall for (split = 0; split < BGE_SPLIT; ++split) {
271962387023Sdduvall err = bge_alloc_dma_mem(bgep, txbuffsize/BGE_SPLIT,
272062387023Sdduvall &bge_data_accattr, DDI_DMA_WRITE | BGE_DMA_MODE,
272162387023Sdduvall &bgep->tx_buff[split]);
272262387023Sdduvall if (err != DDI_SUCCESS)
272362387023Sdduvall return (DDI_FAILURE);
272462387023Sdduvall }
2725087a28d1SDavid Gwynne BGE_DEBUG(("DMA ALLOC: allocated %d chunks for Tx Buffers (txbuffsize = %d)",
2726087a28d1SDavid Gwynne txbuffsize/BGE_SPLIT,
2727087a28d1SDavid Gwynne txbuffsize));
272862387023Sdduvall
2729087a28d1SDavid Gwynne if (!(DEVICE_5717_SERIES_CHIPSETS(bgep) ||
2730087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep))) {
2731087a28d1SDavid Gwynne /* no relaxed ordering for descriptors rings? */
27325952d588Szh199473 dma_attr.dma_attr_flags &= ~DDI_DMA_RELAXED_ORDERING;
2733087a28d1SDavid Gwynne }
27345952d588Szh199473
273562387023Sdduvall /*
273662387023Sdduvall * Allocate memory & handles for receive return rings
273762387023Sdduvall */
273862387023Sdduvall ASSERT((rxdescsize % rx_rings) == 0);
273962387023Sdduvall for (split = 0; split < rx_rings; ++split) {
274062387023Sdduvall err = bge_alloc_dma_mem(bgep, rxdescsize/rx_rings,
274162387023Sdduvall &bge_desc_accattr, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
274262387023Sdduvall &bgep->rx_desc[split]);
274362387023Sdduvall if (err != DDI_SUCCESS)
274462387023Sdduvall return (DDI_FAILURE);
274562387023Sdduvall }
2746087a28d1SDavid Gwynne BGE_DEBUG(("DMA ALLOC: allocated %d chunks for Rx Descs cons (rx_rings = %d, rxdescsize = %d)",
2747087a28d1SDavid Gwynne rxdescsize/rx_rings,
2748087a28d1SDavid Gwynne rx_rings,
2749087a28d1SDavid Gwynne rxdescsize));
275062387023Sdduvall
275162387023Sdduvall /*
2752087a28d1SDavid Gwynne * Allocate memory & handles for buffer (producer) descriptor rings.
2753087a28d1SDavid Gwynne * Note that split=rx_rings.
275462387023Sdduvall */
275562387023Sdduvall err = bge_alloc_dma_mem(bgep, rxbuffdescsize, &bge_desc_accattr,
275662387023Sdduvall DDI_DMA_RDWR | DDI_DMA_CONSISTENT, &bgep->rx_desc[split]);
275762387023Sdduvall if (err != DDI_SUCCESS)
275862387023Sdduvall return (DDI_FAILURE);
2759087a28d1SDavid Gwynne BGE_DEBUG(("DMA ALLOC: allocated 1 chunks for Rx Descs prod (rxbuffdescsize = %d)",
2760087a28d1SDavid Gwynne rxdescsize));
276162387023Sdduvall
276262387023Sdduvall /*
276362387023Sdduvall * Allocate memory & handles for TX descriptor rings,
276462387023Sdduvall * status block, and statistics area
276562387023Sdduvall */
276662387023Sdduvall err = bge_alloc_dma_mem(bgep, txdescsize, &bge_desc_accattr,
276762387023Sdduvall DDI_DMA_RDWR | DDI_DMA_CONSISTENT, &bgep->tx_desc);
276862387023Sdduvall if (err != DDI_SUCCESS)
276962387023Sdduvall return (DDI_FAILURE);
2770087a28d1SDavid Gwynne BGE_DEBUG(("DMA ALLOC: allocated 1 chunks for Tx Descs / Status Block / Stats (txdescdize = %d)",
2771087a28d1SDavid Gwynne txdescsize));
277262387023Sdduvall
277362387023Sdduvall /*
277462387023Sdduvall * Now carve up each of the allocated areas ...
277562387023Sdduvall */
2776087a28d1SDavid Gwynne
2777087a28d1SDavid Gwynne /* rx buffers */
277862387023Sdduvall for (split = 0; split < BGE_SPLIT; ++split) {
277962387023Sdduvall area = bgep->rx_buff[split];
2780087a28d1SDavid Gwynne
2781087a28d1SDavid Gwynne BGE_DEBUG(("RXB CHNK %d INIT: va=%p alen=%d off=%d pa=%llx psz=%d",
2782087a28d1SDavid Gwynne split,
2783087a28d1SDavid Gwynne area.mem_va,
2784087a28d1SDavid Gwynne area.alength,
2785087a28d1SDavid Gwynne area.offset,
2786087a28d1SDavid Gwynne area.cookie.dmac_laddress,
2787087a28d1SDavid Gwynne area.cookie.dmac_size));
2788087a28d1SDavid Gwynne
278962387023Sdduvall bge_slice_chunk(&bgep->buff[BGE_STD_BUFF_RING].buf[split],
279062387023Sdduvall &area, BGE_STD_SLOTS_USED/BGE_SPLIT,
27911b5c96f3Sly149593 bgep->chipid.std_buf_size);
2792087a28d1SDavid Gwynne
2793087a28d1SDavid Gwynne BGE_DEBUG(("RXB SLCE %d STND: va=%p alen=%d off=%d pa=%llx psz=%d (nslots=%d slotlen=%d)",
2794087a28d1SDavid Gwynne split,
2795087a28d1SDavid Gwynne bgep->buff[BGE_STD_BUFF_RING].buf[split].mem_va,
2796087a28d1SDavid Gwynne bgep->buff[BGE_STD_BUFF_RING].buf[split].alength,
2797087a28d1SDavid Gwynne bgep->buff[BGE_STD_BUFF_RING].buf[split].offset,
2798087a28d1SDavid Gwynne bgep->buff[BGE_STD_BUFF_RING].buf[split].cookie.dmac_laddress,
2799087a28d1SDavid Gwynne bgep->buff[BGE_STD_BUFF_RING].buf[split].cookie.dmac_size,
2800087a28d1SDavid Gwynne BGE_STD_SLOTS_USED/BGE_SPLIT,
2801087a28d1SDavid Gwynne bgep->chipid.std_buf_size));
2802087a28d1SDavid Gwynne
280362387023Sdduvall bge_slice_chunk(&bgep->buff[BGE_JUMBO_BUFF_RING].buf[split],
280462387023Sdduvall &area, bgep->chipid.jumbo_slots/BGE_SPLIT,
280562387023Sdduvall bgep->chipid.recv_jumbo_size);
2806087a28d1SDavid Gwynne
2807087a28d1SDavid Gwynne if ((bgep->chipid.jumbo_slots / BGE_SPLIT) > 0)
2808087a28d1SDavid Gwynne {
2809087a28d1SDavid Gwynne BGE_DEBUG(("RXB SLCE %d JUMB: va=%p alen=%d off=%d pa=%llx psz=%d (nslots=%d slotlen=%d)",
2810087a28d1SDavid Gwynne split,
2811087a28d1SDavid Gwynne bgep->buff[BGE_JUMBO_BUFF_RING].buf[split].mem_va,
2812087a28d1SDavid Gwynne bgep->buff[BGE_JUMBO_BUFF_RING].buf[split].alength,
2813087a28d1SDavid Gwynne bgep->buff[BGE_JUMBO_BUFF_RING].buf[split].offset,
2814087a28d1SDavid Gwynne bgep->buff[BGE_JUMBO_BUFF_RING].buf[split].cookie.dmac_laddress,
2815087a28d1SDavid Gwynne bgep->buff[BGE_JUMBO_BUFF_RING].buf[split].cookie.dmac_size,
2816087a28d1SDavid Gwynne bgep->chipid.jumbo_slots/BGE_SPLIT,
2817087a28d1SDavid Gwynne bgep->chipid.recv_jumbo_size));
2818087a28d1SDavid Gwynne }
2819087a28d1SDavid Gwynne
282062387023Sdduvall bge_slice_chunk(&bgep->buff[BGE_MINI_BUFF_RING].buf[split],
282162387023Sdduvall &area, BGE_MINI_SLOTS_USED/BGE_SPLIT,
282262387023Sdduvall BGE_MINI_BUFF_SIZE);
2823087a28d1SDavid Gwynne
2824087a28d1SDavid Gwynne if ((BGE_MINI_SLOTS_USED / BGE_SPLIT) > 0)
2825087a28d1SDavid Gwynne {
2826087a28d1SDavid Gwynne BGE_DEBUG(("RXB SLCE %d MINI: va=%p alen=%d off=%d pa=%llx psz=%d (nslots=%d slotlen=%d)",
2827087a28d1SDavid Gwynne split,
2828087a28d1SDavid Gwynne bgep->buff[BGE_MINI_BUFF_RING].buf[split].mem_va,
2829087a28d1SDavid Gwynne bgep->buff[BGE_MINI_BUFF_RING].buf[split].alength,
2830087a28d1SDavid Gwynne bgep->buff[BGE_MINI_BUFF_RING].buf[split].offset,
2831087a28d1SDavid Gwynne bgep->buff[BGE_MINI_BUFF_RING].buf[split].cookie.dmac_laddress,
2832087a28d1SDavid Gwynne bgep->buff[BGE_MINI_BUFF_RING].buf[split].cookie.dmac_size,
2833087a28d1SDavid Gwynne BGE_MINI_SLOTS_USED/BGE_SPLIT,
2834087a28d1SDavid Gwynne BGE_MINI_BUFF_SIZE));
283562387023Sdduvall }
283662387023Sdduvall
2837087a28d1SDavid Gwynne BGE_DEBUG(("RXB CHNK %d DONE: va=%p alen=%d off=%d pa=%llx psz=%d",
2838087a28d1SDavid Gwynne split,
2839087a28d1SDavid Gwynne area.mem_va,
2840087a28d1SDavid Gwynne area.alength,
2841087a28d1SDavid Gwynne area.offset,
2842087a28d1SDavid Gwynne area.cookie.dmac_laddress,
2843087a28d1SDavid Gwynne area.cookie.dmac_size));
2844087a28d1SDavid Gwynne }
2845087a28d1SDavid Gwynne
2846087a28d1SDavid Gwynne /* tx buffers */
284762387023Sdduvall for (split = 0; split < BGE_SPLIT; ++split) {
284862387023Sdduvall area = bgep->tx_buff[split];
2849087a28d1SDavid Gwynne
2850087a28d1SDavid Gwynne BGE_DEBUG(("TXB CHNK %d INIT: va=%p alen=%d off=%d pa=%llx psz=%d",
2851087a28d1SDavid Gwynne split,
2852087a28d1SDavid Gwynne area.mem_va,
2853087a28d1SDavid Gwynne area.alength,
2854087a28d1SDavid Gwynne area.offset,
2855087a28d1SDavid Gwynne area.cookie.dmac_laddress,
2856087a28d1SDavid Gwynne area.cookie.dmac_size));
2857087a28d1SDavid Gwynne
2858087a28d1SDavid Gwynne for (ring = 0; ring < tx_rings; ++ring) {
2859931dca7dSgs150176 bge_slice_chunk(&bgep->send[ring].buf[0][split],
2860931dca7dSgs150176 &area, BGE_SEND_BUF_NUM/BGE_SPLIT,
286162387023Sdduvall bgep->chipid.snd_buff_size);
2862087a28d1SDavid Gwynne
2863087a28d1SDavid Gwynne BGE_DEBUG(("TXB SLCE %d RING %d: va=%p alen=%d off=%d pa=%llx psz=%d (nslots=%d slotlen=%d)",
2864087a28d1SDavid Gwynne split, ring,
2865087a28d1SDavid Gwynne bgep->send[ring].buf[0][split].mem_va,
2866087a28d1SDavid Gwynne bgep->send[ring].buf[0][split].alength,
2867087a28d1SDavid Gwynne bgep->send[ring].buf[0][split].offset,
2868087a28d1SDavid Gwynne bgep->send[ring].buf[0][split].cookie.dmac_laddress,
2869087a28d1SDavid Gwynne bgep->send[ring].buf[0][split].cookie.dmac_size,
2870087a28d1SDavid Gwynne BGE_SEND_BUF_NUM/BGE_SPLIT,
2871087a28d1SDavid Gwynne bgep->chipid.snd_buff_size));
2872087a28d1SDavid Gwynne }
2873087a28d1SDavid Gwynne
2874087a28d1SDavid Gwynne for (; ring < BGE_SEND_RINGS_MAX; ++ring) {
2875931dca7dSgs150176 bge_slice_chunk(&bgep->send[ring].buf[0][split],
2876931dca7dSgs150176 &area, 0, bgep->chipid.snd_buff_size);
287762387023Sdduvall }
287862387023Sdduvall
2879087a28d1SDavid Gwynne BGE_DEBUG(("TXB CHNK %d DONE: va=%p alen=%d off=%d pa=%llx psz=%d",
2880087a28d1SDavid Gwynne split,
2881087a28d1SDavid Gwynne area.mem_va,
2882087a28d1SDavid Gwynne area.alength,
2883087a28d1SDavid Gwynne area.offset,
2884087a28d1SDavid Gwynne area.cookie.dmac_laddress,
2885087a28d1SDavid Gwynne area.cookie.dmac_size));
2886087a28d1SDavid Gwynne }
2887087a28d1SDavid Gwynne
2888087a28d1SDavid Gwynne for (ring = 0; ring < rx_rings; ++ring) {
288962387023Sdduvall bge_slice_chunk(&bgep->recv[ring].desc, &bgep->rx_desc[ring],
289062387023Sdduvall bgep->chipid.recv_slots, sizeof (bge_rbd_t));
289162387023Sdduvall
2892087a28d1SDavid Gwynne BGE_DEBUG(("RXD CONS RING %d: va=%p alen=%d off=%d pa=%llx psz=%d (nslots=%d slotlen=%d)",
2893087a28d1SDavid Gwynne ring,
2894087a28d1SDavid Gwynne bgep->recv[ring].desc.mem_va,
2895087a28d1SDavid Gwynne bgep->recv[ring].desc.alength,
2896087a28d1SDavid Gwynne bgep->recv[ring].desc.offset,
2897087a28d1SDavid Gwynne bgep->recv[ring].desc.cookie.dmac_laddress,
2898087a28d1SDavid Gwynne bgep->recv[ring].desc.cookie.dmac_size,
2899087a28d1SDavid Gwynne bgep->chipid.recv_slots,
2900087a28d1SDavid Gwynne sizeof(bge_rbd_t)));
2901087a28d1SDavid Gwynne }
2902087a28d1SDavid Gwynne
2903087a28d1SDavid Gwynne /* dma alloc for rxbuffdescsize is located at bgep->rx_desc[#rings] */
2904087a28d1SDavid Gwynne area = bgep->rx_desc[rx_rings]; /* note rx_rings = one beyond rings */
2905087a28d1SDavid Gwynne
2906087a28d1SDavid Gwynne for (; ring < BGE_RECV_RINGS_MAX; ++ring) /* skip unused rings */
290762387023Sdduvall bge_slice_chunk(&bgep->recv[ring].desc, &area,
290862387023Sdduvall 0, sizeof (bge_rbd_t));
2909087a28d1SDavid Gwynne
2910087a28d1SDavid Gwynne BGE_DEBUG(("RXD PROD INIT: va=%p alen=%d off=%d pa=%llx psz=%d",
2911087a28d1SDavid Gwynne area.mem_va,
2912087a28d1SDavid Gwynne area.alength,
2913087a28d1SDavid Gwynne area.offset,
2914087a28d1SDavid Gwynne area.cookie.dmac_laddress,
2915087a28d1SDavid Gwynne area.cookie.dmac_size));
2916087a28d1SDavid Gwynne
291762387023Sdduvall bge_slice_chunk(&bgep->buff[BGE_STD_BUFF_RING].desc, &area,
291862387023Sdduvall BGE_STD_SLOTS_USED, sizeof (bge_rbd_t));
2919087a28d1SDavid Gwynne BGE_DEBUG(("RXD PROD STND: va=%p alen=%d off=%d pa=%llx psz=%d (nslots=%d slotlen=%d)",
2920087a28d1SDavid Gwynne bgep->buff[BGE_STD_BUFF_RING].desc.mem_va,
2921087a28d1SDavid Gwynne bgep->buff[BGE_STD_BUFF_RING].desc.alength,
2922087a28d1SDavid Gwynne bgep->buff[BGE_STD_BUFF_RING].desc.offset,
2923087a28d1SDavid Gwynne bgep->buff[BGE_STD_BUFF_RING].desc.cookie.dmac_laddress,
2924087a28d1SDavid Gwynne bgep->buff[BGE_STD_BUFF_RING].desc.cookie.dmac_size,
2925087a28d1SDavid Gwynne BGE_STD_SLOTS_USED,
2926087a28d1SDavid Gwynne sizeof(bge_rbd_t)));
2927087a28d1SDavid Gwynne
292862387023Sdduvall bge_slice_chunk(&bgep->buff[BGE_JUMBO_BUFF_RING].desc, &area,
292962387023Sdduvall bgep->chipid.jumbo_slots, sizeof (bge_rbd_t));
2930087a28d1SDavid Gwynne BGE_DEBUG(("RXD PROD JUMB: va=%p alen=%d off=%d pa=%llx psz=%d (nslots=%d slotlen=%d)",
2931087a28d1SDavid Gwynne bgep->buff[BGE_JUMBO_BUFF_RING].desc.mem_va,
2932087a28d1SDavid Gwynne bgep->buff[BGE_JUMBO_BUFF_RING].desc.alength,
2933087a28d1SDavid Gwynne bgep->buff[BGE_JUMBO_BUFF_RING].desc.offset,
2934087a28d1SDavid Gwynne bgep->buff[BGE_JUMBO_BUFF_RING].desc.cookie.dmac_laddress,
2935087a28d1SDavid Gwynne bgep->buff[BGE_JUMBO_BUFF_RING].desc.cookie.dmac_size,
2936087a28d1SDavid Gwynne bgep->chipid.jumbo_slots,
2937087a28d1SDavid Gwynne sizeof(bge_rbd_t)));
2938087a28d1SDavid Gwynne
293962387023Sdduvall bge_slice_chunk(&bgep->buff[BGE_MINI_BUFF_RING].desc, &area,
294062387023Sdduvall BGE_MINI_SLOTS_USED, sizeof (bge_rbd_t));
2941087a28d1SDavid Gwynne BGE_DEBUG(("RXD PROD MINI: va=%p alen=%d off=%d pa=%llx psz=%d (nslots=%d slotlen=%d)",
2942087a28d1SDavid Gwynne bgep->buff[BGE_MINI_BUFF_RING].desc.mem_va,
2943087a28d1SDavid Gwynne bgep->buff[BGE_MINI_BUFF_RING].desc.alength,
2944087a28d1SDavid Gwynne bgep->buff[BGE_MINI_BUFF_RING].desc.offset,
2945087a28d1SDavid Gwynne bgep->buff[BGE_MINI_BUFF_RING].desc.cookie.dmac_laddress,
2946087a28d1SDavid Gwynne bgep->buff[BGE_MINI_BUFF_RING].desc.cookie.dmac_size,
2947087a28d1SDavid Gwynne BGE_MINI_SLOTS_USED,
2948087a28d1SDavid Gwynne sizeof(bge_rbd_t)));
2949087a28d1SDavid Gwynne
2950087a28d1SDavid Gwynne BGE_DEBUG(("RXD PROD DONE: va=%p alen=%d off=%d pa=%llx psz=%d",
2951087a28d1SDavid Gwynne area.mem_va,
2952087a28d1SDavid Gwynne area.alength,
2953087a28d1SDavid Gwynne area.offset,
2954087a28d1SDavid Gwynne area.cookie.dmac_laddress,
2955087a28d1SDavid Gwynne area.cookie.dmac_size));
2956087a28d1SDavid Gwynne
295762387023Sdduvall ASSERT(area.alength == 0);
295862387023Sdduvall
295962387023Sdduvall area = bgep->tx_desc;
2960087a28d1SDavid Gwynne
2961087a28d1SDavid Gwynne BGE_DEBUG(("TXD INIT: va=%p alen=%d off=%d pa=%llx psz=%d",
2962087a28d1SDavid Gwynne area.mem_va,
2963087a28d1SDavid Gwynne area.alength,
2964087a28d1SDavid Gwynne area.offset,
2965087a28d1SDavid Gwynne area.cookie.dmac_laddress,
2966087a28d1SDavid Gwynne area.cookie.dmac_size));
2967087a28d1SDavid Gwynne
2968087a28d1SDavid Gwynne for (ring = 0; ring < tx_rings; ++ring) {
296962387023Sdduvall bge_slice_chunk(&bgep->send[ring].desc, &area,
297062387023Sdduvall BGE_SEND_SLOTS_USED, sizeof (bge_sbd_t));
2971087a28d1SDavid Gwynne
2972087a28d1SDavid Gwynne BGE_DEBUG(("TXD RING %d: va=%p alen=%d off=%d pa=%llx psz=%d (nslots=%d slotlen=%d)",
2973087a28d1SDavid Gwynne ring,
2974087a28d1SDavid Gwynne bgep->send[ring].desc.mem_va,
2975087a28d1SDavid Gwynne bgep->send[ring].desc.alength,
2976087a28d1SDavid Gwynne bgep->send[ring].desc.offset,
2977087a28d1SDavid Gwynne bgep->send[ring].desc.cookie.dmac_laddress,
2978087a28d1SDavid Gwynne bgep->send[ring].desc.cookie.dmac_size,
2979087a28d1SDavid Gwynne BGE_SEND_SLOTS_USED,
2980087a28d1SDavid Gwynne sizeof(bge_sbd_t)));
2981087a28d1SDavid Gwynne }
2982087a28d1SDavid Gwynne
2983087a28d1SDavid Gwynne for (; ring < BGE_SEND_RINGS_MAX; ++ring) /* skip unused rings */
298462387023Sdduvall bge_slice_chunk(&bgep->send[ring].desc, &area,
298562387023Sdduvall 0, sizeof (bge_sbd_t));
2986087a28d1SDavid Gwynne
298762387023Sdduvall bge_slice_chunk(&bgep->statistics, &area, 1, sizeof (bge_statistics_t));
2988087a28d1SDavid Gwynne BGE_DEBUG(("TXD STATISTICS: va=%p alen=%d off=%d pa=%llx psz=%d (nslots=%d slotlen=%d)",
2989087a28d1SDavid Gwynne bgep->statistics.mem_va,
2990087a28d1SDavid Gwynne bgep->statistics.alength,
2991087a28d1SDavid Gwynne bgep->statistics.offset,
2992087a28d1SDavid Gwynne bgep->statistics.cookie.dmac_laddress,
2993087a28d1SDavid Gwynne bgep->statistics.cookie.dmac_size,
2994087a28d1SDavid Gwynne 1,
2995087a28d1SDavid Gwynne sizeof(bge_statistics_t)));
2996087a28d1SDavid Gwynne
299762387023Sdduvall bge_slice_chunk(&bgep->status_block, &area, 1, sizeof (bge_status_t));
2998087a28d1SDavid Gwynne BGE_DEBUG(("TXD STATUS BLOCK: va=%p alen=%d off=%d pa=%llx psz=%d (nslots=%d slotlen=%d)",
2999087a28d1SDavid Gwynne bgep->status_block.mem_va,
3000087a28d1SDavid Gwynne bgep->status_block.alength,
3001087a28d1SDavid Gwynne bgep->status_block.offset,
3002087a28d1SDavid Gwynne bgep->status_block.cookie.dmac_laddress,
3003087a28d1SDavid Gwynne bgep->status_block.cookie.dmac_size,
3004087a28d1SDavid Gwynne 1,
3005087a28d1SDavid Gwynne sizeof(bge_status_t)));
3006087a28d1SDavid Gwynne
3007087a28d1SDavid Gwynne BGE_DEBUG(("TXD DONE: va=%p alen=%d off=%d pa=%llx psz=%d",
3008087a28d1SDavid Gwynne area.mem_va,
3009087a28d1SDavid Gwynne area.alength,
3010087a28d1SDavid Gwynne area.offset,
3011087a28d1SDavid Gwynne area.cookie.dmac_laddress,
3012087a28d1SDavid Gwynne area.cookie.dmac_size));
3013087a28d1SDavid Gwynne
301462387023Sdduvall ASSERT(area.alength == BGE_STATUS_PADDING);
3015087a28d1SDavid Gwynne
301662387023Sdduvall DMA_ZERO(bgep->status_block);
301762387023Sdduvall
301862387023Sdduvall return (DDI_SUCCESS);
301962387023Sdduvall }
302062387023Sdduvall
3021087a28d1SDavid Gwynne #undef BGE_DBG
3022087a28d1SDavid Gwynne #define BGE_DBG BGE_DBG_INIT /* debug flag for this code */
3023087a28d1SDavid Gwynne
302462387023Sdduvall /*
302562387023Sdduvall * This routine frees the transmit and receive buffers and descriptors.
302662387023Sdduvall * Make sure the chip is stopped before calling it!
302762387023Sdduvall */
302800d0963fSdilpreet void
302962387023Sdduvall bge_free_bufs(bge_t *bgep)
303062387023Sdduvall {
303162387023Sdduvall int split;
303262387023Sdduvall
303362387023Sdduvall BGE_TRACE(("bge_free_bufs($%p)",
303462387023Sdduvall (void *)bgep));
303562387023Sdduvall
303662387023Sdduvall bge_free_dma_mem(&bgep->tx_desc);
303762387023Sdduvall for (split = 0; split < BGE_RECV_RINGS_SPLIT; ++split)
303862387023Sdduvall bge_free_dma_mem(&bgep->rx_desc[split]);
303962387023Sdduvall for (split = 0; split < BGE_SPLIT; ++split)
304062387023Sdduvall bge_free_dma_mem(&bgep->tx_buff[split]);
304162387023Sdduvall for (split = 0; split < BGE_SPLIT; ++split)
304262387023Sdduvall bge_free_dma_mem(&bgep->rx_buff[split]);
304362387023Sdduvall }
304462387023Sdduvall
304562387023Sdduvall /*
304662387023Sdduvall * Determine (initial) MAC address ("BIA") to use for this interface
304762387023Sdduvall */
304862387023Sdduvall
304962387023Sdduvall static void
305062387023Sdduvall bge_find_mac_address(bge_t *bgep, chip_id_t *cidp)
305162387023Sdduvall {
305262387023Sdduvall struct ether_addr sysaddr;
305362387023Sdduvall char propbuf[8]; /* "true" or "false", plus NUL */
305462387023Sdduvall uchar_t *bytes;
305562387023Sdduvall int *ints;
305662387023Sdduvall uint_t nelts;
305762387023Sdduvall int err;
305862387023Sdduvall
305962387023Sdduvall BGE_TRACE(("bge_find_mac_address($%p)",
306062387023Sdduvall (void *)bgep));
306162387023Sdduvall
306262387023Sdduvall BGE_DEBUG(("bge_find_mac_address: hw_mac_addr %012llx, => %s (%sset)",
306362387023Sdduvall cidp->hw_mac_addr,
306462387023Sdduvall ether_sprintf((void *)cidp->vendor_addr.addr),
306562387023Sdduvall cidp->vendor_addr.set ? "" : "not "));
306662387023Sdduvall
306762387023Sdduvall /*
306862387023Sdduvall * The "vendor's factory-set address" may already have
306962387023Sdduvall * been extracted from the chip, but if the property
307062387023Sdduvall * "local-mac-address" is set we use that instead. It
307162387023Sdduvall * will normally be set by OBP, but it could also be
307262387023Sdduvall * specified in a .conf file(!)
307362387023Sdduvall *
307462387023Sdduvall * There doesn't seem to be a way to define byte-array
307562387023Sdduvall * properties in a .conf, so we check whether it looks
307662387023Sdduvall * like an array of 6 ints instead.
307762387023Sdduvall *
307862387023Sdduvall * Then, we check whether it looks like an array of 6
307962387023Sdduvall * bytes (which it should, if OBP set it). If we can't
308062387023Sdduvall * make sense of it either way, we'll ignore it.
308162387023Sdduvall */
308262387023Sdduvall err = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, bgep->devinfo,
308362387023Sdduvall DDI_PROP_DONTPASS, localmac_propname, &ints, &nelts);
308462387023Sdduvall if (err == DDI_PROP_SUCCESS) {
308562387023Sdduvall if (nelts == ETHERADDRL) {
308662387023Sdduvall while (nelts--)
308762387023Sdduvall cidp->vendor_addr.addr[nelts] = ints[nelts];
3088ed8845d8Skrgopi cidp->vendor_addr.set = B_TRUE;
308962387023Sdduvall }
309062387023Sdduvall ddi_prop_free(ints);
309162387023Sdduvall }
309262387023Sdduvall
309362387023Sdduvall err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, bgep->devinfo,
309462387023Sdduvall DDI_PROP_DONTPASS, localmac_propname, &bytes, &nelts);
309562387023Sdduvall if (err == DDI_PROP_SUCCESS) {
309662387023Sdduvall if (nelts == ETHERADDRL) {
309762387023Sdduvall while (nelts--)
309862387023Sdduvall cidp->vendor_addr.addr[nelts] = bytes[nelts];
3099ed8845d8Skrgopi cidp->vendor_addr.set = B_TRUE;
310062387023Sdduvall }
310162387023Sdduvall ddi_prop_free(bytes);
310262387023Sdduvall }
310362387023Sdduvall
310462387023Sdduvall BGE_DEBUG(("bge_find_mac_address: +local %s (%sset)",
310562387023Sdduvall ether_sprintf((void *)cidp->vendor_addr.addr),
310662387023Sdduvall cidp->vendor_addr.set ? "" : "not "));
310762387023Sdduvall
310862387023Sdduvall /*
310962387023Sdduvall * Look up the OBP property "local-mac-address?". Note that even
311062387023Sdduvall * though its value is a string (which should be "true" or "false"),
311162387023Sdduvall * it can't be decoded by ddi_prop_lookup_string(9F). So, we zero
311262387023Sdduvall * the buffer first and then fetch the property as an untyped array;
311362387023Sdduvall * this may or may not include a final NUL, but since there will
311462387023Sdduvall * always be one left at the end of the buffer we can now treat it
311562387023Sdduvall * as a string anyway.
311662387023Sdduvall */
311762387023Sdduvall nelts = sizeof (propbuf);
311862387023Sdduvall bzero(propbuf, nelts--);
311962387023Sdduvall err = ddi_getlongprop_buf(DDI_DEV_T_ANY, bgep->devinfo,
312062387023Sdduvall DDI_PROP_CANSLEEP, localmac_boolname, propbuf, (int *)&nelts);
312162387023Sdduvall
312262387023Sdduvall /*
312362387023Sdduvall * Now, if the address still isn't set from the hardware (SEEPROM)
312462387023Sdduvall * or the OBP or .conf property, OR if the user has foolishly set
312562387023Sdduvall * 'local-mac-address? = false', use "the system address" instead
312662387023Sdduvall * (but only if it's non-null i.e. has been set from the IDPROM).
312762387023Sdduvall */
3128ed8845d8Skrgopi if (cidp->vendor_addr.set == B_FALSE || strcmp(propbuf, "false") == 0)
312962387023Sdduvall if (localetheraddr(NULL, &sysaddr) != 0) {
313062387023Sdduvall ethaddr_copy(&sysaddr, cidp->vendor_addr.addr);
3131ed8845d8Skrgopi cidp->vendor_addr.set = B_TRUE;
313262387023Sdduvall }
313362387023Sdduvall
313462387023Sdduvall BGE_DEBUG(("bge_find_mac_address: +system %s (%sset)",
313562387023Sdduvall ether_sprintf((void *)cidp->vendor_addr.addr),
313662387023Sdduvall cidp->vendor_addr.set ? "" : "not "));
313762387023Sdduvall
313862387023Sdduvall /*
313962387023Sdduvall * Finally(!), if there's a valid "mac-address" property (created
314062387023Sdduvall * if we netbooted from this interface), we must use this instead
314162387023Sdduvall * of any of the above to ensure that the NFS/install server doesn't
314262387023Sdduvall * get confused by the address changing as Solaris takes over!
314362387023Sdduvall */
314462387023Sdduvall err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, bgep->devinfo,
314562387023Sdduvall DDI_PROP_DONTPASS, macaddr_propname, &bytes, &nelts);
314662387023Sdduvall if (err == DDI_PROP_SUCCESS) {
314762387023Sdduvall if (nelts == ETHERADDRL) {
314862387023Sdduvall while (nelts--)
314962387023Sdduvall cidp->vendor_addr.addr[nelts] = bytes[nelts];
3150ed8845d8Skrgopi cidp->vendor_addr.set = B_TRUE;
315162387023Sdduvall }
315262387023Sdduvall ddi_prop_free(bytes);
315362387023Sdduvall }
315462387023Sdduvall
315562387023Sdduvall BGE_DEBUG(("bge_find_mac_address: =final %s (%sset)",
315662387023Sdduvall ether_sprintf((void *)cidp->vendor_addr.addr),
315762387023Sdduvall cidp->vendor_addr.set ? "" : "not "));
315862387023Sdduvall }
315962387023Sdduvall
316000d0963fSdilpreet /*ARGSUSED*/
316100d0963fSdilpreet int
316200d0963fSdilpreet bge_check_acc_handle(bge_t *bgep, ddi_acc_handle_t handle)
316300d0963fSdilpreet {
316400d0963fSdilpreet ddi_fm_error_t de;
316500d0963fSdilpreet
316600d0963fSdilpreet ddi_fm_acc_err_get(handle, &de, DDI_FME_VERSION);
316700d0963fSdilpreet ddi_fm_acc_err_clear(handle, DDI_FME_VERSION);
316800d0963fSdilpreet return (de.fme_status);
316900d0963fSdilpreet }
317000d0963fSdilpreet
317100d0963fSdilpreet /*ARGSUSED*/
317200d0963fSdilpreet int
317300d0963fSdilpreet bge_check_dma_handle(bge_t *bgep, ddi_dma_handle_t handle)
317400d0963fSdilpreet {
317500d0963fSdilpreet ddi_fm_error_t de;
317600d0963fSdilpreet
317700d0963fSdilpreet ASSERT(bgep->progress & PROGRESS_BUFS);
317800d0963fSdilpreet ddi_fm_dma_err_get(handle, &de, DDI_FME_VERSION);
317900d0963fSdilpreet return (de.fme_status);
318000d0963fSdilpreet }
318100d0963fSdilpreet
318200d0963fSdilpreet /*
318300d0963fSdilpreet * The IO fault service error handling callback function
318400d0963fSdilpreet */
318500d0963fSdilpreet /*ARGSUSED*/
318600d0963fSdilpreet static int
318700d0963fSdilpreet bge_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data)
318800d0963fSdilpreet {
318900d0963fSdilpreet /*
319000d0963fSdilpreet * as the driver can always deal with an error in any dma or
319100d0963fSdilpreet * access handle, we can just return the fme_status value.
319200d0963fSdilpreet */
319300d0963fSdilpreet pci_ereport_post(dip, err, NULL);
319400d0963fSdilpreet return (err->fme_status);
319500d0963fSdilpreet }
319600d0963fSdilpreet
319700d0963fSdilpreet static void
319800d0963fSdilpreet bge_fm_init(bge_t *bgep)
319900d0963fSdilpreet {
320000d0963fSdilpreet ddi_iblock_cookie_t iblk;
320100d0963fSdilpreet
320200d0963fSdilpreet /* Only register with IO Fault Services if we have some capability */
320300d0963fSdilpreet if (bgep->fm_capabilities) {
320400d0963fSdilpreet bge_reg_accattr.devacc_attr_access = DDI_FLAGERR_ACC;
320500d0963fSdilpreet dma_attr.dma_attr_flags = DDI_DMA_FLAGERR;
320600d0963fSdilpreet
320700d0963fSdilpreet /* Register capabilities with IO Fault Services */
320800d0963fSdilpreet ddi_fm_init(bgep->devinfo, &bgep->fm_capabilities, &iblk);
320900d0963fSdilpreet
321000d0963fSdilpreet /*
321100d0963fSdilpreet * Initialize pci ereport capabilities if ereport capable
321200d0963fSdilpreet */
321300d0963fSdilpreet if (DDI_FM_EREPORT_CAP(bgep->fm_capabilities) ||
321400d0963fSdilpreet DDI_FM_ERRCB_CAP(bgep->fm_capabilities))
321500d0963fSdilpreet pci_ereport_setup(bgep->devinfo);
321600d0963fSdilpreet
321700d0963fSdilpreet /*
321800d0963fSdilpreet * Register error callback if error callback capable
321900d0963fSdilpreet */
322000d0963fSdilpreet if (DDI_FM_ERRCB_CAP(bgep->fm_capabilities))
322100d0963fSdilpreet ddi_fm_handler_register(bgep->devinfo,
322200d0963fSdilpreet bge_fm_error_cb, (void*) bgep);
322300d0963fSdilpreet } else {
322400d0963fSdilpreet /*
322500d0963fSdilpreet * These fields have to be cleared of FMA if there are no
322600d0963fSdilpreet * FMA capabilities at runtime.
322700d0963fSdilpreet */
322800d0963fSdilpreet bge_reg_accattr.devacc_attr_access = DDI_DEFAULT_ACC;
322900d0963fSdilpreet dma_attr.dma_attr_flags = 0;
323000d0963fSdilpreet }
323100d0963fSdilpreet }
323200d0963fSdilpreet
323300d0963fSdilpreet static void
323400d0963fSdilpreet bge_fm_fini(bge_t *bgep)
323500d0963fSdilpreet {
323600d0963fSdilpreet /* Only unregister FMA capabilities if we registered some */
323700d0963fSdilpreet if (bgep->fm_capabilities) {
323800d0963fSdilpreet
323900d0963fSdilpreet /*
324000d0963fSdilpreet * Release any resources allocated by pci_ereport_setup()
324100d0963fSdilpreet */
324200d0963fSdilpreet if (DDI_FM_EREPORT_CAP(bgep->fm_capabilities) ||
324300d0963fSdilpreet DDI_FM_ERRCB_CAP(bgep->fm_capabilities))
324400d0963fSdilpreet pci_ereport_teardown(bgep->devinfo);
324500d0963fSdilpreet
324600d0963fSdilpreet /*
324700d0963fSdilpreet * Un-register error callback if error callback capable
324800d0963fSdilpreet */
324900d0963fSdilpreet if (DDI_FM_ERRCB_CAP(bgep->fm_capabilities))
325000d0963fSdilpreet ddi_fm_handler_unregister(bgep->devinfo);
325100d0963fSdilpreet
325200d0963fSdilpreet /* Unregister from IO Fault Services */
325300d0963fSdilpreet ddi_fm_fini(bgep->devinfo);
325400d0963fSdilpreet }
325500d0963fSdilpreet }
325600d0963fSdilpreet
325762387023Sdduvall static void
325867f02347Srandyf #ifdef BGE_IPMI_ASF
325967f02347Srandyf bge_unattach(bge_t *bgep, uint_t asf_mode)
326067f02347Srandyf #else
326162387023Sdduvall bge_unattach(bge_t *bgep)
326267f02347Srandyf #endif
326362387023Sdduvall {
326462387023Sdduvall BGE_TRACE(("bge_unattach($%p)",
326562387023Sdduvall (void *)bgep));
326662387023Sdduvall
326762387023Sdduvall /*
326862387023Sdduvall * Flag that no more activity may be initiated
326962387023Sdduvall */
327062387023Sdduvall bgep->progress &= ~PROGRESS_READY;
327162387023Sdduvall
327262387023Sdduvall /*
327362387023Sdduvall * Quiesce the PHY and MAC (leave it reset but still powered).
327462387023Sdduvall * Clean up and free all BGE data structures
327562387023Sdduvall */
3276dd4eeefdSeota if (bgep->periodic_id != NULL) {
3277dd4eeefdSeota ddi_periodic_delete(bgep->periodic_id);
3278dd4eeefdSeota bgep->periodic_id = NULL;
327962387023Sdduvall }
3280087a28d1SDavid Gwynne
328162387023Sdduvall if (bgep->progress & PROGRESS_KSTATS)
328262387023Sdduvall bge_fini_kstats(bgep);
328362387023Sdduvall if (bgep->progress & PROGRESS_PHY)
328462387023Sdduvall bge_phys_reset(bgep);
328562387023Sdduvall if (bgep->progress & PROGRESS_HWINT) {
328662387023Sdduvall mutex_enter(bgep->genlock);
328767f02347Srandyf #ifdef BGE_IPMI_ASF
328800d0963fSdilpreet if (bge_chip_reset(bgep, B_FALSE, asf_mode) != DDI_SUCCESS)
328900d0963fSdilpreet #else
329000d0963fSdilpreet if (bge_chip_reset(bgep, B_FALSE) != DDI_SUCCESS)
329100d0963fSdilpreet #endif
329200d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo,
329300d0963fSdilpreet DDI_SERVICE_UNAFFECTED);
329400d0963fSdilpreet #ifdef BGE_IPMI_ASF
329567f02347Srandyf if (bgep->asf_enabled) {
329667f02347Srandyf /*
329767f02347Srandyf * This register has been overlaid. We restore its
329867f02347Srandyf * initial value here.
329967f02347Srandyf */
330067f02347Srandyf bge_nic_put32(bgep, BGE_NIC_DATA_SIG_ADDR,
330167f02347Srandyf BGE_NIC_DATA_SIG);
330267f02347Srandyf }
330367f02347Srandyf #endif
330400d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK)
330500d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo,
330600d0963fSdilpreet DDI_SERVICE_UNAFFECTED);
330700d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK)
330800d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo,
330900d0963fSdilpreet DDI_SERVICE_UNAFFECTED);
331062387023Sdduvall mutex_exit(bgep->genlock);
331162387023Sdduvall }
331262387023Sdduvall if (bgep->progress & PROGRESS_INTR) {
331300d0963fSdilpreet bge_intr_disable(bgep);
331462387023Sdduvall bge_fini_rings(bgep);
331562387023Sdduvall }
331600d0963fSdilpreet if (bgep->progress & PROGRESS_HWINT) {
331700d0963fSdilpreet bge_rem_intrs(bgep);
331800d0963fSdilpreet rw_destroy(bgep->errlock);
331900d0963fSdilpreet mutex_destroy(bgep->softintrlock);
332000d0963fSdilpreet mutex_destroy(bgep->genlock);
332100d0963fSdilpreet }
332262387023Sdduvall if (bgep->progress & PROGRESS_FACTOTUM)
332362387023Sdduvall ddi_remove_softintr(bgep->factotum_id);
332462387023Sdduvall if (bgep->progress & PROGRESS_RESCHED)
3325931dca7dSgs150176 ddi_remove_softintr(bgep->drain_id);
332600d0963fSdilpreet if (bgep->progress & PROGRESS_BUFS)
332762387023Sdduvall bge_free_bufs(bgep);
3328087a28d1SDavid Gwynne if (bgep->progress & PROGRESS_REGS) {
332962387023Sdduvall ddi_regs_map_free(&bgep->io_handle);
3330087a28d1SDavid Gwynne if (bgep->ape_enabled)
3331087a28d1SDavid Gwynne ddi_regs_map_free(&bgep->ape_handle);
3332087a28d1SDavid Gwynne }
333362387023Sdduvall if (bgep->progress & PROGRESS_CFG)
333462387023Sdduvall pci_config_teardown(&bgep->cfg_handle);
333562387023Sdduvall
333600d0963fSdilpreet bge_fm_fini(bgep);
333700d0963fSdilpreet
333862387023Sdduvall ddi_remove_minor_node(bgep->devinfo, NULL);
3339931dca7dSgs150176 kmem_free(bgep->pstats, sizeof (bge_statistics_reg_t));
334062387023Sdduvall kmem_free(bgep, sizeof (*bgep));
334162387023Sdduvall }
334262387023Sdduvall
334362387023Sdduvall static int
334462387023Sdduvall bge_resume(dev_info_t *devinfo)
334562387023Sdduvall {
334662387023Sdduvall bge_t *bgep; /* Our private data */
334762387023Sdduvall chip_id_t *cidp;
334862387023Sdduvall chip_id_t chipid;
334962387023Sdduvall
335062387023Sdduvall bgep = ddi_get_driver_private(devinfo);
335162387023Sdduvall if (bgep == NULL)
335262387023Sdduvall return (DDI_FAILURE);
335362387023Sdduvall
335462387023Sdduvall /*
335562387023Sdduvall * Refuse to resume if the data structures aren't consistent
335662387023Sdduvall */
335762387023Sdduvall if (bgep->devinfo != devinfo)
335862387023Sdduvall return (DDI_FAILURE);
335962387023Sdduvall
336067f02347Srandyf #ifdef BGE_IPMI_ASF
336167f02347Srandyf /*
336267f02347Srandyf * Power management hasn't been supported in BGE now. If you
336367f02347Srandyf * want to implement it, please add the ASF/IPMI related
336467f02347Srandyf * code here.
336567f02347Srandyf */
336667f02347Srandyf
336767f02347Srandyf #endif
336867f02347Srandyf
336962387023Sdduvall /*
337062387023Sdduvall * Read chip ID & set up config space command register(s)
337162387023Sdduvall * Refuse to resume if the chip has changed its identity!
337262387023Sdduvall */
337362387023Sdduvall cidp = &bgep->chipid;
337400d0963fSdilpreet mutex_enter(bgep->genlock);
337562387023Sdduvall bge_chip_cfg_init(bgep, &chipid, B_FALSE);
337600d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) {
337700d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST);
337800d0963fSdilpreet mutex_exit(bgep->genlock);
337900d0963fSdilpreet return (DDI_FAILURE);
338000d0963fSdilpreet }
338100d0963fSdilpreet mutex_exit(bgep->genlock);
338262387023Sdduvall if (chipid.vendor != cidp->vendor)
338362387023Sdduvall return (DDI_FAILURE);
338462387023Sdduvall if (chipid.device != cidp->device)
338562387023Sdduvall return (DDI_FAILURE);
338662387023Sdduvall if (chipid.revision != cidp->revision)
338762387023Sdduvall return (DDI_FAILURE);
338862387023Sdduvall if (chipid.asic_rev != cidp->asic_rev)
338962387023Sdduvall return (DDI_FAILURE);
339062387023Sdduvall
339162387023Sdduvall /*
339262387023Sdduvall * All OK, reinitialise h/w & kick off GLD scheduling
339362387023Sdduvall */
339462387023Sdduvall mutex_enter(bgep->genlock);
339500d0963fSdilpreet if (bge_restart(bgep, B_TRUE) != DDI_SUCCESS) {
339600d0963fSdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle);
339700d0963fSdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle);
339800d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST);
339900d0963fSdilpreet mutex_exit(bgep->genlock);
340000d0963fSdilpreet return (DDI_FAILURE);
340100d0963fSdilpreet }
340200d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) {
340300d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST);
340400d0963fSdilpreet mutex_exit(bgep->genlock);
340500d0963fSdilpreet return (DDI_FAILURE);
340600d0963fSdilpreet }
340700d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) {
340800d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST);
340900d0963fSdilpreet mutex_exit(bgep->genlock);
341000d0963fSdilpreet return (DDI_FAILURE);
341100d0963fSdilpreet }
341262387023Sdduvall mutex_exit(bgep->genlock);
341362387023Sdduvall return (DDI_SUCCESS);
341462387023Sdduvall }
341562387023Sdduvall
3416087a28d1SDavid Gwynne static int
3417087a28d1SDavid Gwynne bge_fw_img_is_valid(bge_t *bgep, uint32_t offset)
3418087a28d1SDavid Gwynne {
3419087a28d1SDavid Gwynne uint32_t val;
3420087a28d1SDavid Gwynne
3421087a28d1SDavid Gwynne if (bge_nvmem_read32(bgep, offset, &val) ||
3422087a28d1SDavid Gwynne (val & 0xfc000000) != 0x0c000000 ||
3423087a28d1SDavid Gwynne bge_nvmem_read32(bgep, offset + 4, &val) ||
3424087a28d1SDavid Gwynne val != 0)
3425087a28d1SDavid Gwynne return (0);
3426087a28d1SDavid Gwynne
3427087a28d1SDavid Gwynne return (1);
3428087a28d1SDavid Gwynne }
3429087a28d1SDavid Gwynne
3430087a28d1SDavid Gwynne static void
3431087a28d1SDavid Gwynne bge_read_mgmtfw_ver(bge_t *bgep)
3432087a28d1SDavid Gwynne {
3433087a28d1SDavid Gwynne uint32_t val;
3434087a28d1SDavid Gwynne uint32_t offset;
3435087a28d1SDavid Gwynne uint32_t start;
3436087a28d1SDavid Gwynne int i, vlen;
3437087a28d1SDavid Gwynne
3438087a28d1SDavid Gwynne for (offset = NVM_DIR_START;
3439087a28d1SDavid Gwynne offset < NVM_DIR_END;
3440087a28d1SDavid Gwynne offset += NVM_DIRENT_SIZE) {
3441087a28d1SDavid Gwynne if (bge_nvmem_read32(bgep, offset, &val))
3442087a28d1SDavid Gwynne return;
3443087a28d1SDavid Gwynne
3444087a28d1SDavid Gwynne if ((val >> NVM_DIRTYPE_SHIFT) == NVM_DIRTYPE_ASFINI)
3445087a28d1SDavid Gwynne break;
3446087a28d1SDavid Gwynne }
3447087a28d1SDavid Gwynne
3448087a28d1SDavid Gwynne if (offset == NVM_DIR_END)
3449087a28d1SDavid Gwynne return;
3450087a28d1SDavid Gwynne
3451087a28d1SDavid Gwynne if (bge_nvmem_read32(bgep, offset - 4, &start))
3452087a28d1SDavid Gwynne return;
3453087a28d1SDavid Gwynne
3454087a28d1SDavid Gwynne if (bge_nvmem_read32(bgep, offset + 4, &offset) ||
3455087a28d1SDavid Gwynne !bge_fw_img_is_valid(bgep, offset) ||
3456087a28d1SDavid Gwynne bge_nvmem_read32(bgep, offset + 8, &val))
3457087a28d1SDavid Gwynne return;
3458087a28d1SDavid Gwynne
3459087a28d1SDavid Gwynne offset += val - start;
3460087a28d1SDavid Gwynne
3461087a28d1SDavid Gwynne vlen = strlen(bgep->fw_version);
3462087a28d1SDavid Gwynne
3463087a28d1SDavid Gwynne bgep->fw_version[vlen++] = ',';
3464087a28d1SDavid Gwynne bgep->fw_version[vlen++] = ' ';
3465087a28d1SDavid Gwynne
3466087a28d1SDavid Gwynne for (i = 0; i < 4; i++) {
3467087a28d1SDavid Gwynne uint32_t v;
3468087a28d1SDavid Gwynne
3469087a28d1SDavid Gwynne if (bge_nvmem_read32(bgep, offset, &v))
3470087a28d1SDavid Gwynne return;
3471087a28d1SDavid Gwynne
3472087a28d1SDavid Gwynne v = BE_32(v);
3473087a28d1SDavid Gwynne
3474087a28d1SDavid Gwynne offset += sizeof(v);
3475087a28d1SDavid Gwynne
3476087a28d1SDavid Gwynne if (vlen > BGE_FW_VER_SIZE - sizeof(v)) {
3477087a28d1SDavid Gwynne memcpy(&bgep->fw_version[vlen], &v, BGE_FW_VER_SIZE - vlen);
3478087a28d1SDavid Gwynne break;
3479087a28d1SDavid Gwynne }
3480087a28d1SDavid Gwynne
3481087a28d1SDavid Gwynne memcpy(&bgep->fw_version[vlen], &v, sizeof(v));
3482087a28d1SDavid Gwynne vlen += sizeof(v);
3483087a28d1SDavid Gwynne }
3484087a28d1SDavid Gwynne }
3485087a28d1SDavid Gwynne
3486087a28d1SDavid Gwynne static void
3487087a28d1SDavid Gwynne bge_read_dash_ver(bge_t *bgep)
3488087a28d1SDavid Gwynne {
3489087a28d1SDavid Gwynne int vlen;
3490087a28d1SDavid Gwynne uint32_t apedata;
3491087a28d1SDavid Gwynne char *fwtype;
3492087a28d1SDavid Gwynne
3493087a28d1SDavid Gwynne if (!bgep->ape_enabled || !bgep->asf_enabled)
3494087a28d1SDavid Gwynne return;
3495087a28d1SDavid Gwynne
3496087a28d1SDavid Gwynne apedata = bge_ape_get32(bgep, BGE_APE_SEG_SIG);
3497087a28d1SDavid Gwynne if (apedata != APE_SEG_SIG_MAGIC)
3498087a28d1SDavid Gwynne return;
3499087a28d1SDavid Gwynne
3500087a28d1SDavid Gwynne apedata = bge_ape_get32(bgep, BGE_APE_FW_STATUS);
3501087a28d1SDavid Gwynne if (!(apedata & APE_FW_STATUS_READY))
3502087a28d1SDavid Gwynne return;
3503087a28d1SDavid Gwynne
3504087a28d1SDavid Gwynne apedata = bge_ape_get32(bgep, BGE_APE_FW_VERSION);
3505087a28d1SDavid Gwynne
3506087a28d1SDavid Gwynne if (bge_ape_get32(bgep, BGE_APE_FW_FEATURES) &
3507087a28d1SDavid Gwynne BGE_APE_FW_FEATURE_NCSI) {
3508087a28d1SDavid Gwynne bgep->ape_has_ncsi = B_TRUE;
3509087a28d1SDavid Gwynne fwtype = "NCSI";
3510087a28d1SDavid Gwynne } else if ((bgep->chipid.device == DEVICE_ID_5725) ||
3511087a28d1SDavid Gwynne (bgep->chipid.device == DEVICE_ID_5727)) {
3512087a28d1SDavid Gwynne fwtype = "SMASH";
3513087a28d1SDavid Gwynne } else {
3514087a28d1SDavid Gwynne fwtype = "DASH";
3515087a28d1SDavid Gwynne }
3516087a28d1SDavid Gwynne
3517087a28d1SDavid Gwynne vlen = strlen(bgep->fw_version);
3518087a28d1SDavid Gwynne
3519087a28d1SDavid Gwynne snprintf(&bgep->fw_version[vlen], BGE_FW_VER_SIZE - vlen,
3520087a28d1SDavid Gwynne " %s v%d.%d.%d.%d", fwtype,
3521087a28d1SDavid Gwynne (apedata & APE_FW_VERSION_MAJMSK) >> APE_FW_VERSION_MAJSFT,
3522087a28d1SDavid Gwynne (apedata & APE_FW_VERSION_MINMSK) >> APE_FW_VERSION_MINSFT,
3523087a28d1SDavid Gwynne (apedata & APE_FW_VERSION_REVMSK) >> APE_FW_VERSION_REVSFT,
3524087a28d1SDavid Gwynne (apedata & APE_FW_VERSION_BLDMSK));
3525087a28d1SDavid Gwynne }
3526087a28d1SDavid Gwynne
3527087a28d1SDavid Gwynne static void
3528087a28d1SDavid Gwynne bge_read_bc_ver(bge_t *bgep)
3529087a28d1SDavid Gwynne {
3530087a28d1SDavid Gwynne uint32_t val;
3531087a28d1SDavid Gwynne uint32_t offset;
3532087a28d1SDavid Gwynne uint32_t start;
3533087a28d1SDavid Gwynne uint32_t ver_offset;
3534087a28d1SDavid Gwynne int i, dst_off;
3535087a28d1SDavid Gwynne uint32_t major;
3536087a28d1SDavid Gwynne uint32_t minor;
3537087a28d1SDavid Gwynne boolean_t newver = B_FALSE;
3538087a28d1SDavid Gwynne
3539087a28d1SDavid Gwynne if (bge_nvmem_read32(bgep, 0xc, &offset) ||
3540087a28d1SDavid Gwynne bge_nvmem_read32(bgep, 0x4, &start))
3541087a28d1SDavid Gwynne return;
3542087a28d1SDavid Gwynne
3543087a28d1SDavid Gwynne if (bge_nvmem_read32(bgep, offset, &val))
3544087a28d1SDavid Gwynne return;
3545087a28d1SDavid Gwynne
3546087a28d1SDavid Gwynne if ((val & 0xfc000000) == 0x0c000000) {
3547087a28d1SDavid Gwynne if (bge_nvmem_read32(bgep, offset + 4, &val))
3548087a28d1SDavid Gwynne return;
3549087a28d1SDavid Gwynne
3550087a28d1SDavid Gwynne if (val == 0)
3551087a28d1SDavid Gwynne newver = B_TRUE;
3552087a28d1SDavid Gwynne }
3553087a28d1SDavid Gwynne
3554087a28d1SDavid Gwynne dst_off = strlen(bgep->fw_version);
3555087a28d1SDavid Gwynne
3556087a28d1SDavid Gwynne if (newver) {
3557087a28d1SDavid Gwynne if (((BGE_FW_VER_SIZE - dst_off) < 16) ||
3558087a28d1SDavid Gwynne bge_nvmem_read32(bgep, offset + 8, &ver_offset))
3559087a28d1SDavid Gwynne return;
3560087a28d1SDavid Gwynne
3561087a28d1SDavid Gwynne offset = offset + ver_offset - start;
3562087a28d1SDavid Gwynne for (i = 0; i < 16; i += 4) {
3563087a28d1SDavid Gwynne if (bge_nvmem_read32(bgep, offset + i, &val))
3564087a28d1SDavid Gwynne return;
3565087a28d1SDavid Gwynne val = BE_32(val);
3566087a28d1SDavid Gwynne memcpy(bgep->fw_version + dst_off + i, &val,
3567087a28d1SDavid Gwynne sizeof(val));
3568087a28d1SDavid Gwynne }
3569087a28d1SDavid Gwynne } else {
3570087a28d1SDavid Gwynne if (bge_nvmem_read32(bgep, NVM_PTREV_BCVER, &ver_offset))
3571087a28d1SDavid Gwynne return;
3572087a28d1SDavid Gwynne
3573087a28d1SDavid Gwynne major = (ver_offset & NVM_BCVER_MAJMSK) >> NVM_BCVER_MAJSFT;
3574087a28d1SDavid Gwynne minor = ver_offset & NVM_BCVER_MINMSK;
3575087a28d1SDavid Gwynne snprintf(&bgep->fw_version[dst_off], BGE_FW_VER_SIZE - dst_off,
3576087a28d1SDavid Gwynne "v%d.%02d", major, minor);
3577087a28d1SDavid Gwynne }
3578087a28d1SDavid Gwynne }
3579087a28d1SDavid Gwynne
3580087a28d1SDavid Gwynne static void
3581087a28d1SDavid Gwynne bge_read_fw_ver(bge_t *bgep)
3582087a28d1SDavid Gwynne {
3583087a28d1SDavid Gwynne uint32_t val;
3584087a28d1SDavid Gwynne uint32_t magic;
3585087a28d1SDavid Gwynne
3586087a28d1SDavid Gwynne *bgep->fw_version = 0;
3587087a28d1SDavid Gwynne
3588087a28d1SDavid Gwynne if ((bgep->chipid.nvtype == BGE_NVTYPE_NONE) ||
3589087a28d1SDavid Gwynne (bgep->chipid.nvtype == BGE_NVTYPE_UNKNOWN)) {
3590087a28d1SDavid Gwynne snprintf(bgep->fw_version, sizeof(bgep->fw_version), "sb");
3591087a28d1SDavid Gwynne return;
3592087a28d1SDavid Gwynne }
3593087a28d1SDavid Gwynne
3594087a28d1SDavid Gwynne mutex_enter(bgep->genlock);
3595087a28d1SDavid Gwynne
3596087a28d1SDavid Gwynne bge_nvmem_read32(bgep, 0, &magic);
3597087a28d1SDavid Gwynne
3598087a28d1SDavid Gwynne if (magic == EEPROM_MAGIC) {
3599087a28d1SDavid Gwynne bge_read_bc_ver(bgep);
3600087a28d1SDavid Gwynne } else {
3601087a28d1SDavid Gwynne /* ignore other configs for now */
3602087a28d1SDavid Gwynne mutex_exit(bgep->genlock);
3603087a28d1SDavid Gwynne return;
3604087a28d1SDavid Gwynne }
3605087a28d1SDavid Gwynne
3606087a28d1SDavid Gwynne if (bgep->ape_enabled) {
3607087a28d1SDavid Gwynne if (bgep->asf_enabled) {
3608087a28d1SDavid Gwynne bge_read_dash_ver(bgep);
3609087a28d1SDavid Gwynne }
3610087a28d1SDavid Gwynne } else if (bgep->asf_enabled) {
3611087a28d1SDavid Gwynne bge_read_mgmtfw_ver(bgep);
3612087a28d1SDavid Gwynne }
3613087a28d1SDavid Gwynne
3614087a28d1SDavid Gwynne mutex_exit(bgep->genlock);
3615087a28d1SDavid Gwynne
3616087a28d1SDavid Gwynne bgep->fw_version[BGE_FW_VER_SIZE - 1] = 0; /* safety */
3617087a28d1SDavid Gwynne }
3618087a28d1SDavid Gwynne
361962387023Sdduvall /*
362062387023Sdduvall * attach(9E) -- Attach a device to the system
362162387023Sdduvall *
362262387023Sdduvall * Called once for each board successfully probed.
362362387023Sdduvall */
362462387023Sdduvall static int
362562387023Sdduvall bge_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
362662387023Sdduvall {
362762387023Sdduvall bge_t *bgep; /* Our private data */
3628ba2e4443Sseb mac_register_t *macp;
362962387023Sdduvall chip_id_t *cidp;
363062387023Sdduvall caddr_t regs;
363162387023Sdduvall int instance;
363262387023Sdduvall int err;
363362387023Sdduvall int intr_types;
3634087a28d1SDavid Gwynne int *props = NULL;
3635087a28d1SDavid Gwynne uint_t numProps;
3636087a28d1SDavid Gwynne uint32_t regval;
3637087a28d1SDavid Gwynne uint32_t pci_state_reg;
363867f02347Srandyf #ifdef BGE_IPMI_ASF
363967f02347Srandyf uint32_t mhcrValue;
3640a4de4ba2Sml149210 #ifdef __sparc
3641a4de4ba2Sml149210 uint16_t value16;
3642a4de4ba2Sml149210 #endif
3643a4de4ba2Sml149210 #ifdef BGE_NETCONSOLE
3644a4de4ba2Sml149210 int retval;
3645a4de4ba2Sml149210 #endif
364667f02347Srandyf #endif
364762387023Sdduvall
364862387023Sdduvall instance = ddi_get_instance(devinfo);
364962387023Sdduvall
365062387023Sdduvall BGE_GTRACE(("bge_attach($%p, %d) instance %d",
365162387023Sdduvall (void *)devinfo, cmd, instance));
365262387023Sdduvall BGE_BRKPT(NULL, "bge_attach");
365362387023Sdduvall
365462387023Sdduvall switch (cmd) {
365562387023Sdduvall default:
365662387023Sdduvall return (DDI_FAILURE);
365762387023Sdduvall
365862387023Sdduvall case DDI_RESUME:
365962387023Sdduvall return (bge_resume(devinfo));
366062387023Sdduvall
366162387023Sdduvall case DDI_ATTACH:
366262387023Sdduvall break;
366362387023Sdduvall }
366462387023Sdduvall
366562387023Sdduvall bgep = kmem_zalloc(sizeof (*bgep), KM_SLEEP);
3666931dca7dSgs150176 bgep->pstats = kmem_zalloc(sizeof (bge_statistics_reg_t), KM_SLEEP);
366762387023Sdduvall ddi_set_driver_private(devinfo, bgep);
366862387023Sdduvall bgep->bge_guard = BGE_GUARD;
366962387023Sdduvall bgep->devinfo = devinfo;
3670e7801d59Ssowmini bgep->param_drain_max = 64;
3671e7801d59Ssowmini bgep->param_msi_cnt = 0;
3672e7801d59Ssowmini bgep->param_loop_mode = 0;
367362387023Sdduvall
367462387023Sdduvall /*
367562387023Sdduvall * Initialize more fields in BGE private data
367662387023Sdduvall */
367762387023Sdduvall bgep->debug = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
367862387023Sdduvall DDI_PROP_DONTPASS, debug_propname, bge_debug);
367962387023Sdduvall (void) snprintf(bgep->ifname, sizeof (bgep->ifname), "%s%d",
368062387023Sdduvall BGE_DRIVER_NAME, instance);
368162387023Sdduvall
368262387023Sdduvall /*
368300d0963fSdilpreet * Initialize for fma support
368400d0963fSdilpreet */
368500d0963fSdilpreet bgep->fm_capabilities = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
368600d0963fSdilpreet DDI_PROP_DONTPASS, fm_cap,
368700d0963fSdilpreet DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE |
368800d0963fSdilpreet DDI_FM_DMACHK_CAPABLE | DDI_FM_ERRCB_CAPABLE);
368900d0963fSdilpreet BGE_DEBUG(("bgep->fm_capabilities = %d", bgep->fm_capabilities));
369000d0963fSdilpreet bge_fm_init(bgep);
369100d0963fSdilpreet
369200d0963fSdilpreet /*
369362387023Sdduvall * Look up the IOMMU's page size for DVMA mappings (must be
369462387023Sdduvall * a power of 2) and convert to a mask. This can be used to
369562387023Sdduvall * determine whether a message buffer crosses a page boundary.
369662387023Sdduvall * Note: in 2s complement binary notation, if X is a power of
369762387023Sdduvall * 2, then -X has the representation "11...1100...00".
369862387023Sdduvall */
369962387023Sdduvall bgep->pagemask = dvma_pagesize(devinfo);
370062387023Sdduvall ASSERT(ddi_ffs(bgep->pagemask) == ddi_fls(bgep->pagemask));
370162387023Sdduvall bgep->pagemask = -bgep->pagemask;
370262387023Sdduvall
370362387023Sdduvall /*
370462387023Sdduvall * Map config space registers
370562387023Sdduvall * Read chip ID & set up config space command register(s)
370662387023Sdduvall *
370762387023Sdduvall * Note: this leaves the chip accessible by Memory Space
370862387023Sdduvall * accesses, but with interrupts and Bus Mastering off.
370962387023Sdduvall * This should ensure that nothing untoward will happen
371062387023Sdduvall * if it has been left active by the (net-)bootloader.
371162387023Sdduvall * We'll re-enable Bus Mastering once we've reset the chip,
371262387023Sdduvall * and allow interrupts only when everything else is set up.
371362387023Sdduvall */
371462387023Sdduvall err = pci_config_setup(devinfo, &bgep->cfg_handle);
3715*4289b4d5SHans Rosenfeld
3716*4289b4d5SHans Rosenfeld bgep->ape_enabled = B_FALSE;
3717*4289b4d5SHans Rosenfeld bgep->ape_regs = NULL;
3718*4289b4d5SHans Rosenfeld
3719*4289b4d5SHans Rosenfeld if (DEVICE_5717_SERIES_CHIPSETS(bgep) ||
3720*4289b4d5SHans Rosenfeld DEVICE_5725_SERIES_CHIPSETS(bgep)) {
3721*4289b4d5SHans Rosenfeld err = ddi_regs_map_setup(devinfo, BGE_PCI_APEREGS_RNUMBER,
3722*4289b4d5SHans Rosenfeld ®s, 0, 0, &bge_reg_accattr, &bgep->ape_handle);
3723*4289b4d5SHans Rosenfeld if (err != DDI_SUCCESS) {
3724*4289b4d5SHans Rosenfeld ddi_regs_map_free(&bgep->io_handle);
3725*4289b4d5SHans Rosenfeld bge_problem(bgep, "ddi_regs_map_setup() failed");
3726*4289b4d5SHans Rosenfeld goto attach_fail;
3727*4289b4d5SHans Rosenfeld }
3728*4289b4d5SHans Rosenfeld bgep->ape_regs = regs;
3729*4289b4d5SHans Rosenfeld bgep->ape_enabled = B_TRUE;
3730*4289b4d5SHans Rosenfeld
3731*4289b4d5SHans Rosenfeld /*
3732*4289b4d5SHans Rosenfeld * Allow reads and writes to the
3733*4289b4d5SHans Rosenfeld * APE register and memory space.
3734*4289b4d5SHans Rosenfeld */
3735*4289b4d5SHans Rosenfeld
3736*4289b4d5SHans Rosenfeld pci_state_reg = pci_config_get32(bgep->cfg_handle,
3737*4289b4d5SHans Rosenfeld PCI_CONF_BGE_PCISTATE);
3738*4289b4d5SHans Rosenfeld pci_state_reg |= PCISTATE_ALLOW_APE_CTLSPC_WR |
3739*4289b4d5SHans Rosenfeld PCISTATE_ALLOW_APE_SHMEM_WR | PCISTATE_ALLOW_APE_PSPACE_WR;
3740*4289b4d5SHans Rosenfeld pci_config_put32(bgep->cfg_handle,
3741*4289b4d5SHans Rosenfeld PCI_CONF_BGE_PCISTATE, pci_state_reg);
3742*4289b4d5SHans Rosenfeld bge_ape_lock_init(bgep);
3743*4289b4d5SHans Rosenfeld }
3744*4289b4d5SHans Rosenfeld
374567f02347Srandyf #ifdef BGE_IPMI_ASF
3746a4de4ba2Sml149210 #ifdef __sparc
3747dc3f9a75Syong tan - Sun Microsystems - Beijing China /*
3748dc3f9a75Syong tan - Sun Microsystems - Beijing China * We need to determine the type of chipset for accessing some configure
3749dc3f9a75Syong tan - Sun Microsystems - Beijing China * registers. (This information will be used by bge_ind_put32,
3750dc3f9a75Syong tan - Sun Microsystems - Beijing China * bge_ind_get32 and bge_nic_read32)
3751dc3f9a75Syong tan - Sun Microsystems - Beijing China */
3752dc3f9a75Syong tan - Sun Microsystems - Beijing China bgep->chipid.device = pci_config_get16(bgep->cfg_handle,
3753dc3f9a75Syong tan - Sun Microsystems - Beijing China PCI_CONF_DEVID);
3754a4de4ba2Sml149210 value16 = pci_config_get16(bgep->cfg_handle, PCI_CONF_COMM);
3755a4de4ba2Sml149210 value16 = value16 | (PCI_COMM_MAE | PCI_COMM_ME);
3756a4de4ba2Sml149210 pci_config_put16(bgep->cfg_handle, PCI_CONF_COMM, value16);
3757a4de4ba2Sml149210 mhcrValue = MHCR_ENABLE_INDIRECT_ACCESS |
3758a4de4ba2Sml149210 MHCR_ENABLE_TAGGED_STATUS_MODE |
3759a4de4ba2Sml149210 MHCR_MASK_INTERRUPT_MODE |
3760a4de4ba2Sml149210 MHCR_MASK_PCI_INT_OUTPUT |
3761a4de4ba2Sml149210 MHCR_CLEAR_INTERRUPT_INTA |
3762a4de4ba2Sml149210 MHCR_ENABLE_ENDIAN_WORD_SWAP |
3763a4de4ba2Sml149210 MHCR_ENABLE_ENDIAN_BYTE_SWAP;
3764dc3f9a75Syong tan - Sun Microsystems - Beijing China /*
3765dc3f9a75Syong tan - Sun Microsystems - Beijing China * For some chipsets (e.g., BCM5718), if MHCR_ENABLE_ENDIAN_BYTE_SWAP
3766dc3f9a75Syong tan - Sun Microsystems - Beijing China * has been set in PCI_CONF_COMM already, we need to write the
3767dc3f9a75Syong tan - Sun Microsystems - Beijing China * byte-swapped value to it. So we just write zero first for simplicity.
3768dc3f9a75Syong tan - Sun Microsystems - Beijing China */
3769087a28d1SDavid Gwynne if (DEVICE_5717_SERIES_CHIPSETS(bgep) ||
3770087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep))
3771dc3f9a75Syong tan - Sun Microsystems - Beijing China pci_config_put32(bgep->cfg_handle, PCI_CONF_BGE_MHCR, 0);
3772087a28d1SDavid Gwynne #else
3773087a28d1SDavid Gwynne mhcrValue = MHCR_ENABLE_INDIRECT_ACCESS |
3774087a28d1SDavid Gwynne MHCR_ENABLE_TAGGED_STATUS_MODE |
3775087a28d1SDavid Gwynne MHCR_MASK_INTERRUPT_MODE |
3776087a28d1SDavid Gwynne MHCR_MASK_PCI_INT_OUTPUT |
3777087a28d1SDavid Gwynne MHCR_CLEAR_INTERRUPT_INTA;
3778087a28d1SDavid Gwynne #endif
3779a4de4ba2Sml149210 pci_config_put32(bgep->cfg_handle, PCI_CONF_BGE_MHCR, mhcrValue);
3780a4de4ba2Sml149210 bge_ind_put32(bgep, MEMORY_ARBITER_MODE_REG,
3781a4de4ba2Sml149210 bge_ind_get32(bgep, MEMORY_ARBITER_MODE_REG) |
3782a4de4ba2Sml149210 MEMORY_ARBITER_ENABLE);
378367f02347Srandyf if (mhcrValue & MHCR_ENABLE_ENDIAN_WORD_SWAP) {
378467f02347Srandyf bgep->asf_wordswapped = B_TRUE;
378567f02347Srandyf } else {
378667f02347Srandyf bgep->asf_wordswapped = B_FALSE;
378767f02347Srandyf }
378867f02347Srandyf bge_asf_get_config(bgep);
378967f02347Srandyf #endif
379062387023Sdduvall if (err != DDI_SUCCESS) {
379162387023Sdduvall bge_problem(bgep, "pci_config_setup() failed");
379262387023Sdduvall goto attach_fail;
379362387023Sdduvall }
379462387023Sdduvall bgep->progress |= PROGRESS_CFG;
379562387023Sdduvall cidp = &bgep->chipid;
379662387023Sdduvall bzero(cidp, sizeof(*cidp));
379762387023Sdduvall bge_chip_cfg_init(bgep, cidp, B_FALSE);
379800d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) {
379900d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST);
380000d0963fSdilpreet goto attach_fail;
380100d0963fSdilpreet }
380262387023Sdduvall
380367f02347Srandyf #ifdef BGE_IPMI_ASF
380467f02347Srandyf if (DEVICE_5721_SERIES_CHIPSETS(bgep) ||
380567f02347Srandyf DEVICE_5714_SERIES_CHIPSETS(bgep)) {
380667f02347Srandyf bgep->asf_newhandshake = B_TRUE;
380767f02347Srandyf } else {
380867f02347Srandyf bgep->asf_newhandshake = B_FALSE;
380967f02347Srandyf }
381067f02347Srandyf #endif
381167f02347Srandyf
381262387023Sdduvall /*
381362387023Sdduvall * Update those parts of the chip ID derived from volatile
381462387023Sdduvall * registers with the values seen by OBP (in case the chip
381562387023Sdduvall * has been reset externally and therefore lost them).
381662387023Sdduvall */
381762387023Sdduvall cidp->subven = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
381862387023Sdduvall DDI_PROP_DONTPASS, subven_propname, cidp->subven);
381962387023Sdduvall cidp->subdev = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
382062387023Sdduvall DDI_PROP_DONTPASS, subdev_propname, cidp->subdev);
382162387023Sdduvall cidp->clsize = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
382262387023Sdduvall DDI_PROP_DONTPASS, clsize_propname, cidp->clsize);
382362387023Sdduvall cidp->latency = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
382462387023Sdduvall DDI_PROP_DONTPASS, latency_propname, cidp->latency);
382562387023Sdduvall cidp->rx_rings = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
382662387023Sdduvall DDI_PROP_DONTPASS, rxrings_propname, cidp->rx_rings);
382762387023Sdduvall cidp->tx_rings = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
382862387023Sdduvall DDI_PROP_DONTPASS, txrings_propname, cidp->tx_rings);
3829087a28d1SDavid Gwynne cidp->eee = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
3830087a28d1SDavid Gwynne DDI_PROP_DONTPASS, eee_propname, cidp->eee);
383162387023Sdduvall
38326e6ed1baSyong tan - Sun Microsystems - Beijing China cidp->default_mtu = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo,
38336e6ed1baSyong tan - Sun Microsystems - Beijing China DDI_PROP_DONTPASS, default_mtu, BGE_DEFAULT_MTU);
38346e6ed1baSyong tan - Sun Microsystems - Beijing China if ((cidp->default_mtu < BGE_DEFAULT_MTU) ||
38356e6ed1baSyong tan - Sun Microsystems - Beijing China (cidp->default_mtu > BGE_MAXIMUM_MTU)) {
38366e6ed1baSyong tan - Sun Microsystems - Beijing China cidp->default_mtu = BGE_DEFAULT_MTU;
38376e6ed1baSyong tan - Sun Microsystems - Beijing China }
38386e6ed1baSyong tan - Sun Microsystems - Beijing China
383962387023Sdduvall /*
384062387023Sdduvall * Map operating registers
384162387023Sdduvall */
384262387023Sdduvall err = ddi_regs_map_setup(devinfo, BGE_PCI_OPREGS_RNUMBER,
384362387023Sdduvall ®s, 0, 0, &bge_reg_accattr, &bgep->io_handle);
384462387023Sdduvall if (err != DDI_SUCCESS) {
384562387023Sdduvall bge_problem(bgep, "ddi_regs_map_setup() failed");
384662387023Sdduvall goto attach_fail;
384762387023Sdduvall }
384862387023Sdduvall bgep->io_regs = regs;
3849087a28d1SDavid Gwynne
385062387023Sdduvall bgep->progress |= PROGRESS_REGS;
385162387023Sdduvall
385262387023Sdduvall /*
385362387023Sdduvall * Characterise the device, so we know its requirements.
385462387023Sdduvall * Then allocate the appropriate TX and RX descriptors & buffers.
385562387023Sdduvall */
385600d0963fSdilpreet if (bge_chip_id_init(bgep) == EIO) {
385700d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST);
385800d0963fSdilpreet goto attach_fail;
385900d0963fSdilpreet }
38604045d941Ssowmini
3861087a28d1SDavid Gwynne err = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, bgep->devinfo,
3862087a28d1SDavid Gwynne 0, "reg", &props, &numProps);
3863087a28d1SDavid Gwynne if ((err == DDI_PROP_SUCCESS) && (numProps > 0)) {
3864087a28d1SDavid Gwynne bgep->pci_bus = PCI_REG_BUS_G(props[0]);
3865087a28d1SDavid Gwynne bgep->pci_dev = PCI_REG_DEV_G(props[0]);
3866087a28d1SDavid Gwynne bgep->pci_func = PCI_REG_FUNC_G(props[0]);
3867087a28d1SDavid Gwynne ddi_prop_free(props);
3868087a28d1SDavid Gwynne }
3869087a28d1SDavid Gwynne
3870087a28d1SDavid Gwynne if (DEVICE_5717_SERIES_CHIPSETS(bgep) ||
3871087a28d1SDavid Gwynne DEVICE_5725_SERIES_CHIPSETS(bgep)) {
3872087a28d1SDavid Gwynne regval = bge_reg_get32(bgep, CPMU_STATUS_REG);
3873087a28d1SDavid Gwynne if ((bgep->chipid.device == DEVICE_ID_5719) ||
3874087a28d1SDavid Gwynne (bgep->chipid.device == DEVICE_ID_5720)) {
3875087a28d1SDavid Gwynne bgep->pci_func =
3876087a28d1SDavid Gwynne ((regval & CPMU_STATUS_FUNC_NUM_5719) >>
3877087a28d1SDavid Gwynne CPMU_STATUS_FUNC_NUM_5719_SHIFT);
3878087a28d1SDavid Gwynne } else {
3879087a28d1SDavid Gwynne bgep->pci_func = ((regval & CPMU_STATUS_FUNC_NUM) >>
3880087a28d1SDavid Gwynne CPMU_STATUS_FUNC_NUM_SHIFT);
3881087a28d1SDavid Gwynne }
3882087a28d1SDavid Gwynne }
3883087a28d1SDavid Gwynne
388462387023Sdduvall err = bge_alloc_bufs(bgep);
388562387023Sdduvall if (err != DDI_SUCCESS) {
388662387023Sdduvall bge_problem(bgep, "DMA buffer allocation failed");
388762387023Sdduvall goto attach_fail;
388862387023Sdduvall }
388900d0963fSdilpreet bgep->progress |= PROGRESS_BUFS;
389062387023Sdduvall
389162387023Sdduvall /*
389262387023Sdduvall * Add the softint handlers:
389362387023Sdduvall *
389462387023Sdduvall * Both of these handlers are used to avoid restrictions on the
389562387023Sdduvall * context and/or mutexes required for some operations. In
389662387023Sdduvall * particular, the hardware interrupt handler and its subfunctions
389762387023Sdduvall * can detect a number of conditions that we don't want to handle
389862387023Sdduvall * in that context or with that set of mutexes held. So, these
389962387023Sdduvall * softints are triggered instead:
390062387023Sdduvall *
3901256e438eSzh199473 * the <resched> softint is triggered if we have previously
390262387023Sdduvall * had to refuse to send a packet because of resource shortage
390362387023Sdduvall * (we've run out of transmit buffers), but the send completion
390462387023Sdduvall * interrupt handler has now detected that more buffers have
390562387023Sdduvall * become available.
390662387023Sdduvall *
390762387023Sdduvall * the <factotum> is triggered if the h/w interrupt handler
390862387023Sdduvall * sees the <link state changed> or <error> bits in the status
390962387023Sdduvall * block. It's also triggered periodically to poll the link
391062387023Sdduvall * state, just in case we aren't getting link status change
391162387023Sdduvall * interrupts ...
391262387023Sdduvall */
3913931dca7dSgs150176 err = ddi_add_softintr(devinfo, DDI_SOFTINT_LOW, &bgep->drain_id,
3914931dca7dSgs150176 NULL, NULL, bge_send_drain, (caddr_t)bgep);
391562387023Sdduvall if (err != DDI_SUCCESS) {
391662387023Sdduvall bge_problem(bgep, "ddi_add_softintr() failed");
391762387023Sdduvall goto attach_fail;
391862387023Sdduvall }
391962387023Sdduvall bgep->progress |= PROGRESS_RESCHED;
392062387023Sdduvall err = ddi_add_softintr(devinfo, DDI_SOFTINT_LOW, &bgep->factotum_id,
392162387023Sdduvall NULL, NULL, bge_chip_factotum, (caddr_t)bgep);
392262387023Sdduvall if (err != DDI_SUCCESS) {
392362387023Sdduvall bge_problem(bgep, "ddi_add_softintr() failed");
392462387023Sdduvall goto attach_fail;
392562387023Sdduvall }
392662387023Sdduvall bgep->progress |= PROGRESS_FACTOTUM;
392762387023Sdduvall
392862387023Sdduvall /* Get supported interrupt types */
392962387023Sdduvall if (ddi_intr_get_supported_types(devinfo, &intr_types) != DDI_SUCCESS) {
393062387023Sdduvall bge_error(bgep, "ddi_intr_get_supported_types failed\n");
393162387023Sdduvall
393262387023Sdduvall goto attach_fail;
393362387023Sdduvall }
393462387023Sdduvall
3935f724721bSzh199473 BGE_DEBUG(("%s: ddi_intr_get_supported_types() returned: %x",
3936f724721bSzh199473 bgep->ifname, intr_types));
393762387023Sdduvall
393862387023Sdduvall if ((intr_types & DDI_INTR_TYPE_MSI) && bgep->chipid.msi_enabled) {
393962387023Sdduvall if (bge_add_intrs(bgep, DDI_INTR_TYPE_MSI) != DDI_SUCCESS) {
394062387023Sdduvall bge_error(bgep, "MSI registration failed, "
394162387023Sdduvall "trying FIXED interrupt type\n");
394262387023Sdduvall } else {
3943f724721bSzh199473 BGE_DEBUG(("%s: Using MSI interrupt type",
3944f724721bSzh199473 bgep->ifname));
394562387023Sdduvall bgep->intr_type = DDI_INTR_TYPE_MSI;
394600d0963fSdilpreet bgep->progress |= PROGRESS_HWINT;
394762387023Sdduvall }
394862387023Sdduvall }
394962387023Sdduvall
395000d0963fSdilpreet if (!(bgep->progress & PROGRESS_HWINT) &&
395162387023Sdduvall (intr_types & DDI_INTR_TYPE_FIXED)) {
395262387023Sdduvall if (bge_add_intrs(bgep, DDI_INTR_TYPE_FIXED) != DDI_SUCCESS) {
395362387023Sdduvall bge_error(bgep, "FIXED interrupt "
395462387023Sdduvall "registration failed\n");
395562387023Sdduvall goto attach_fail;
395662387023Sdduvall }
395762387023Sdduvall
3958f724721bSzh199473 BGE_DEBUG(("%s: Using FIXED interrupt type", bgep->ifname));
395962387023Sdduvall
396062387023Sdduvall bgep->intr_type = DDI_INTR_TYPE_FIXED;
396100d0963fSdilpreet bgep->progress |= PROGRESS_HWINT;
396262387023Sdduvall }
396362387023Sdduvall
396400d0963fSdilpreet if (!(bgep->progress & PROGRESS_HWINT)) {
396562387023Sdduvall bge_error(bgep, "No interrupts registered\n");
396662387023Sdduvall goto attach_fail;
396762387023Sdduvall }
396862387023Sdduvall
396962387023Sdduvall /*
397062387023Sdduvall * Note that interrupts are not enabled yet as
397100d0963fSdilpreet * mutex locks are not initialized. Initialize mutex locks.
397200d0963fSdilpreet */
397300d0963fSdilpreet mutex_init(bgep->genlock, NULL, MUTEX_DRIVER,
397400d0963fSdilpreet DDI_INTR_PRI(bgep->intr_pri));
397500d0963fSdilpreet mutex_init(bgep->softintrlock, NULL, MUTEX_DRIVER,
397600d0963fSdilpreet DDI_INTR_PRI(bgep->intr_pri));
397700d0963fSdilpreet rw_init(bgep->errlock, NULL, RW_DRIVER,
397800d0963fSdilpreet DDI_INTR_PRI(bgep->intr_pri));
397900d0963fSdilpreet
398000d0963fSdilpreet /*
398100d0963fSdilpreet * Initialize rings.
398262387023Sdduvall */
398362387023Sdduvall bge_init_rings(bgep);
398462387023Sdduvall
398562387023Sdduvall /*
398662387023Sdduvall * Now that mutex locks are initialized, enable interrupts.
398762387023Sdduvall */
398800d0963fSdilpreet bge_intr_enable(bgep);
398900d0963fSdilpreet bgep->progress |= PROGRESS_INTR;
399062387023Sdduvall
399162387023Sdduvall /*
399262387023Sdduvall * Initialise link state variables
399362387023Sdduvall * Stop, reset & reinitialise the chip.
399462387023Sdduvall * Initialise the (internal) PHY.
399562387023Sdduvall */
399662387023Sdduvall bgep->link_state = LINK_STATE_UNKNOWN;
399762387023Sdduvall
399862387023Sdduvall mutex_enter(bgep->genlock);
399962387023Sdduvall
400062387023Sdduvall /*
400162387023Sdduvall * Reset chip & rings to initial state; also reset address
400262387023Sdduvall * filtering, promiscuity, loopback mode.
400362387023Sdduvall */
400467f02347Srandyf #ifdef BGE_IPMI_ASF
4005a4de4ba2Sml149210 #ifdef BGE_NETCONSOLE
4006a4de4ba2Sml149210 if (bge_reset(bgep, ASF_MODE_INIT) != DDI_SUCCESS) {
4007a4de4ba2Sml149210 #else
400800d0963fSdilpreet if (bge_reset(bgep, ASF_MODE_SHUTDOWN) != DDI_SUCCESS) {
4009a4de4ba2Sml149210 #endif
401067f02347Srandyf #else
401100d0963fSdilpreet if (bge_reset(bgep) != DDI_SUCCESS) {
401267f02347Srandyf #endif
401300d0963fSdilpreet (void) bge_check_acc_handle(bgep, bgep->cfg_handle);
401400d0963fSdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle);
401500d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST);
401600d0963fSdilpreet mutex_exit(bgep->genlock);
401700d0963fSdilpreet goto attach_fail;
401800d0963fSdilpreet }
401962387023Sdduvall
4020f724721bSzh199473 #ifdef BGE_IPMI_ASF
4021f724721bSzh199473 if (bgep->asf_enabled) {
4022f724721bSzh199473 bgep->asf_status = ASF_STAT_RUN_INIT;
4023f724721bSzh199473 }
4024f724721bSzh199473 #endif
4025f724721bSzh199473
402662387023Sdduvall bzero(bgep->mcast_hash, sizeof (bgep->mcast_hash));
402762387023Sdduvall bzero(bgep->mcast_refs, sizeof (bgep->mcast_refs));
402862387023Sdduvall bgep->promisc = B_FALSE;
402962387023Sdduvall bgep->param_loop_mode = BGE_LOOP_NONE;
403000d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK) {
403100d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST);
403200d0963fSdilpreet mutex_exit(bgep->genlock);
403300d0963fSdilpreet goto attach_fail;
403400d0963fSdilpreet }
403500d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) {
403600d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST);
403700d0963fSdilpreet mutex_exit(bgep->genlock);
403800d0963fSdilpreet goto attach_fail;
403900d0963fSdilpreet }
404062387023Sdduvall
404162387023Sdduvall mutex_exit(bgep->genlock);
404262387023Sdduvall
404300d0963fSdilpreet if (bge_phys_init(bgep) == EIO) {
404400d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST);
404500d0963fSdilpreet goto attach_fail;
404600d0963fSdilpreet }
404762387023Sdduvall bgep->progress |= PROGRESS_PHY;
404862387023Sdduvall
404962387023Sdduvall /*
40504045d941Ssowmini * initialize NDD-tweakable parameters
405162387023Sdduvall */
405262387023Sdduvall if (bge_nd_init(bgep)) {
405362387023Sdduvall bge_problem(bgep, "bge_nd_init() failed");
405462387023Sdduvall goto attach_fail;
405562387023Sdduvall }
405662387023Sdduvall bgep->progress |= PROGRESS_NDD;
405762387023Sdduvall
405862387023Sdduvall /*
405962387023Sdduvall * Create & initialise named kstats
406062387023Sdduvall */
406162387023Sdduvall bge_init_kstats(bgep, instance);
406262387023Sdduvall bgep->progress |= PROGRESS_KSTATS;
406362387023Sdduvall
406462387023Sdduvall /*
406562387023Sdduvall * Determine whether to override the chip's own MAC address
406662387023Sdduvall */
406762387023Sdduvall bge_find_mac_address(bgep, cidp);
4068087a28d1SDavid Gwynne {
4069087a28d1SDavid Gwynne int slot;
4070087a28d1SDavid Gwynne for (slot = 0; slot < MAC_ADDRESS_REGS_MAX; slot++) {
4071087a28d1SDavid Gwynne ethaddr_copy(cidp->vendor_addr.addr,
4072087a28d1SDavid Gwynne bgep->curr_addr[slot].addr);
4073087a28d1SDavid Gwynne bgep->curr_addr[slot].set = 1;
4074087a28d1SDavid Gwynne }
4075087a28d1SDavid Gwynne }
4076087a28d1SDavid Gwynne
4077087a28d1SDavid Gwynne bge_read_fw_ver(bgep);
4078ed8845d8Skrgopi
40798398201fSkrgopi bgep->unicst_addr_total = MAC_ADDRESS_REGS_MAX;
4080da14cebeSEric Cheng bgep->unicst_addr_avail = MAC_ADDRESS_REGS_MAX;
408162387023Sdduvall
4082ba2e4443Sseb if ((macp = mac_alloc(MAC_VERSION)) == NULL)
4083ba2e4443Sseb goto attach_fail;
4084ba2e4443Sseb macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
4085ba2e4443Sseb macp->m_driver = bgep;
408662387023Sdduvall macp->m_dip = devinfo;
4087da14cebeSEric Cheng macp->m_src_addr = cidp->vendor_addr.addr;
4088ba2e4443Sseb macp->m_callbacks = &bge_m_callbacks;
4089ba2e4443Sseb macp->m_min_sdu = 0;
4090ba2e4443Sseb macp->m_max_sdu = cidp->ethmax_size - sizeof (struct ether_header);
4091d62bc4baSyz147064 macp->m_margin = VLAN_TAGSZ;
40924045d941Ssowmini macp->m_priv_props = bge_priv_prop;
4093087a28d1SDavid Gwynne
4094087a28d1SDavid Gwynne #if defined(ILLUMOS)
4095087a28d1SDavid Gwynne bge_m_unicst(bgep, cidp->vendor_addr.addr);
4096087a28d1SDavid Gwynne #endif
40974045d941Ssowmini
409862387023Sdduvall /*
409962387023Sdduvall * Finally, we're ready to register ourselves with the MAC layer
410062387023Sdduvall * interface; if this succeeds, we're all ready to start()
410162387023Sdduvall */
4102ba2e4443Sseb err = mac_register(macp, &bgep->mh);
4103ba2e4443Sseb mac_free(macp);
4104ba2e4443Sseb if (err != 0)
410562387023Sdduvall goto attach_fail;
410662387023Sdduvall
410746ffce64Syong tan - Sun Microsystems - Beijing China mac_link_update(bgep->mh, LINK_STATE_UNKNOWN);
410846ffce64Syong tan - Sun Microsystems - Beijing China
4109dd4eeefdSeota /*
4110dd4eeefdSeota * Register a periodical handler.
4111dd4eeefdSeota * bge_chip_cyclic() is invoked in kernel context.
4112dd4eeefdSeota */
4113dd4eeefdSeota bgep->periodic_id = ddi_periodic_add(bge_chip_cyclic, bgep,
4114dd4eeefdSeota BGE_CYCLIC_PERIOD, DDI_IPL_0);
411562387023Sdduvall
411662387023Sdduvall bgep->progress |= PROGRESS_READY;
411762387023Sdduvall ASSERT(bgep->bge_guard == BGE_GUARD);
4118a4de4ba2Sml149210 #ifdef BGE_IPMI_ASF
4119a4de4ba2Sml149210 #ifdef BGE_NETCONSOLE
4120a4de4ba2Sml149210 if (bgep->asf_enabled) {
4121a4de4ba2Sml149210 mutex_enter(bgep->genlock);
4122a4de4ba2Sml149210 retval = bge_chip_start(bgep, B_TRUE);
4123a4de4ba2Sml149210 mutex_exit(bgep->genlock);
4124a4de4ba2Sml149210 if (retval != DDI_SUCCESS)
4125a4de4ba2Sml149210 goto attach_fail;
4126a4de4ba2Sml149210 }
4127a4de4ba2Sml149210 #endif
4128a4de4ba2Sml149210 #endif
412919397407SSherry Moore
413019397407SSherry Moore ddi_report_dev(devinfo);
413127c3238fSyong tan - Sun Microsystems - Beijing China
413262387023Sdduvall return (DDI_SUCCESS);
413362387023Sdduvall
413462387023Sdduvall attach_fail:
413567f02347Srandyf #ifdef BGE_IPMI_ASF
4136f724721bSzh199473 bge_unattach(bgep, ASF_MODE_SHUTDOWN);
413767f02347Srandyf #else
413862387023Sdduvall bge_unattach(bgep);
413967f02347Srandyf #endif
414062387023Sdduvall return (DDI_FAILURE);
414162387023Sdduvall }
414262387023Sdduvall
414362387023Sdduvall /*
414462387023Sdduvall * bge_suspend() -- suspend transmit/receive for powerdown
414562387023Sdduvall */
414662387023Sdduvall static int
414762387023Sdduvall bge_suspend(bge_t *bgep)
414862387023Sdduvall {
414962387023Sdduvall /*
415062387023Sdduvall * Stop processing and idle (powerdown) the PHY ...
415162387023Sdduvall */
415262387023Sdduvall mutex_enter(bgep->genlock);
415367f02347Srandyf #ifdef BGE_IPMI_ASF
415467f02347Srandyf /*
415567f02347Srandyf * Power management hasn't been supported in BGE now. If you
415667f02347Srandyf * want to implement it, please add the ASF/IPMI related
415767f02347Srandyf * code here.
415867f02347Srandyf */
415967f02347Srandyf #endif
416062387023Sdduvall bge_stop(bgep);
416100d0963fSdilpreet if (bge_phys_idle(bgep) != DDI_SUCCESS) {
416200d0963fSdilpreet (void) bge_check_acc_handle(bgep, bgep->io_handle);
416300d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED);
416400d0963fSdilpreet mutex_exit(bgep->genlock);
416500d0963fSdilpreet return (DDI_FAILURE);
416600d0963fSdilpreet }
416700d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK) {
416800d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED);
416900d0963fSdilpreet mutex_exit(bgep->genlock);
417000d0963fSdilpreet return (DDI_FAILURE);
417100d0963fSdilpreet }
417262387023Sdduvall mutex_exit(bgep->genlock);
417362387023Sdduvall
417462387023Sdduvall return (DDI_SUCCESS);
417562387023Sdduvall }
417662387023Sdduvall
417762387023Sdduvall /*
417819397407SSherry Moore * quiesce(9E) entry point.
417919397407SSherry Moore *
418019397407SSherry Moore * This function is called when the system is single-threaded at high
418119397407SSherry Moore * PIL with preemption disabled. Therefore, this function must not be
418219397407SSherry Moore * blocked.
418319397407SSherry Moore *
418419397407SSherry Moore * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
418519397407SSherry Moore * DDI_FAILURE indicates an error condition and should almost never happen.
418619397407SSherry Moore */
418719397407SSherry Moore #ifdef __sparc
418819397407SSherry Moore #define bge_quiesce ddi_quiesce_not_supported
418919397407SSherry Moore #else
419019397407SSherry Moore static int
419119397407SSherry Moore bge_quiesce(dev_info_t *devinfo)
419219397407SSherry Moore {
419319397407SSherry Moore bge_t *bgep = ddi_get_driver_private(devinfo);
419419397407SSherry Moore
419519397407SSherry Moore if (bgep == NULL)
419619397407SSherry Moore return (DDI_FAILURE);
419719397407SSherry Moore
419819397407SSherry Moore if (bgep->intr_type == DDI_INTR_TYPE_FIXED) {
419919397407SSherry Moore bge_reg_set32(bgep, PCI_CONF_BGE_MHCR,
420019397407SSherry Moore MHCR_MASK_PCI_INT_OUTPUT);
420119397407SSherry Moore } else {
420219397407SSherry Moore bge_reg_clr32(bgep, MSI_MODE_REG, MSI_MSI_ENABLE);
420319397407SSherry Moore }
420419397407SSherry Moore
420519397407SSherry Moore /* Stop the chip */
420619397407SSherry Moore bge_chip_stop_nonblocking(bgep);
420719397407SSherry Moore
420819397407SSherry Moore return (DDI_SUCCESS);
420919397407SSherry Moore }
421019397407SSherry Moore #endif
421119397407SSherry Moore
421219397407SSherry Moore /*
421362387023Sdduvall * detach(9E) -- Detach a device from the system
421462387023Sdduvall */
421562387023Sdduvall static int
421662387023Sdduvall bge_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
421762387023Sdduvall {
421862387023Sdduvall bge_t *bgep;
421967f02347Srandyf #ifdef BGE_IPMI_ASF
422067f02347Srandyf uint_t asf_mode;
422167f02347Srandyf asf_mode = ASF_MODE_NONE;
422267f02347Srandyf #endif
422362387023Sdduvall
422462387023Sdduvall BGE_GTRACE(("bge_detach($%p, %d)", (void *)devinfo, cmd));
422562387023Sdduvall
422662387023Sdduvall bgep = ddi_get_driver_private(devinfo);
422762387023Sdduvall
422862387023Sdduvall switch (cmd) {
422962387023Sdduvall default:
423062387023Sdduvall return (DDI_FAILURE);
423162387023Sdduvall
423262387023Sdduvall case DDI_SUSPEND:
423362387023Sdduvall return (bge_suspend(bgep));
423462387023Sdduvall
423562387023Sdduvall case DDI_DETACH:
423662387023Sdduvall break;
423762387023Sdduvall }
423862387023Sdduvall
423967f02347Srandyf #ifdef BGE_IPMI_ASF
424067f02347Srandyf mutex_enter(bgep->genlock);
4241f724721bSzh199473 if (bgep->asf_enabled && ((bgep->asf_status == ASF_STAT_RUN) ||
4242f724721bSzh199473 (bgep->asf_status == ASF_STAT_RUN_INIT))) {
424367f02347Srandyf
424467f02347Srandyf bge_asf_update_status(bgep);
4245f724721bSzh199473 if (bgep->asf_status == ASF_STAT_RUN) {
424667f02347Srandyf bge_asf_stop_timer(bgep);
4247f724721bSzh199473 }
424867f02347Srandyf bgep->asf_status = ASF_STAT_STOP;
424967f02347Srandyf
425067f02347Srandyf bge_asf_pre_reset_operations(bgep, BGE_SHUTDOWN_RESET);
425167f02347Srandyf
425267f02347Srandyf if (bgep->asf_pseudostop) {
425367f02347Srandyf bge_chip_stop(bgep, B_FALSE);
425467f02347Srandyf bgep->bge_mac_state = BGE_MAC_STOPPED;
425567f02347Srandyf bgep->asf_pseudostop = B_FALSE;
425667f02347Srandyf }
425767f02347Srandyf
425867f02347Srandyf asf_mode = ASF_MODE_POST_SHUTDOWN;
425900d0963fSdilpreet
426000d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->cfg_handle) != DDI_FM_OK)
426100d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo,
426200d0963fSdilpreet DDI_SERVICE_UNAFFECTED);
426300d0963fSdilpreet if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK)
426400d0963fSdilpreet ddi_fm_service_impact(bgep->devinfo,
426500d0963fSdilpreet DDI_SERVICE_UNAFFECTED);
426667f02347Srandyf }
426767f02347Srandyf mutex_exit(bgep->genlock);
426867f02347Srandyf #endif
426967f02347Srandyf
427062387023Sdduvall /*
427162387023Sdduvall * Unregister from the GLD subsystem. This can fail, in
427262387023Sdduvall * particular if there are DLPI style-2 streams still open -
427362387023Sdduvall * in which case we just return failure without shutting
427462387023Sdduvall * down chip operations.
427562387023Sdduvall */
4276ba2e4443Sseb if (mac_unregister(bgep->mh) != 0)
427762387023Sdduvall return (DDI_FAILURE);
427862387023Sdduvall
427962387023Sdduvall /*
428062387023Sdduvall * All activity stopped, so we can clean up & exit
428162387023Sdduvall */
428267f02347Srandyf #ifdef BGE_IPMI_ASF
428367f02347Srandyf bge_unattach(bgep, asf_mode);
428467f02347Srandyf #else
428562387023Sdduvall bge_unattach(bgep);
428667f02347Srandyf #endif
428762387023Sdduvall return (DDI_SUCCESS);
428862387023Sdduvall }
428962387023Sdduvall
429062387023Sdduvall
429162387023Sdduvall /*
429262387023Sdduvall * ========== Module Loading Data & Entry Points ==========
429362387023Sdduvall */
429462387023Sdduvall
429562387023Sdduvall #undef BGE_DBG
429662387023Sdduvall #define BGE_DBG BGE_DBG_INIT /* debug flag for this code */
429762387023Sdduvall
429819397407SSherry Moore DDI_DEFINE_STREAM_OPS(bge_dev_ops,
429919397407SSherry Moore nulldev, /* identify */
430019397407SSherry Moore nulldev, /* probe */
430119397407SSherry Moore bge_attach, /* attach */
430219397407SSherry Moore bge_detach, /* detach */
430319397407SSherry Moore nodev, /* reset */
430419397407SSherry Moore NULL, /* cb_ops */
430519397407SSherry Moore D_MP, /* bus_ops */
430619397407SSherry Moore NULL, /* power */
430719397407SSherry Moore bge_quiesce /* quiesce */
430819397407SSherry Moore );
430962387023Sdduvall
431062387023Sdduvall static struct modldrv bge_modldrv = {
431162387023Sdduvall &mod_driverops, /* Type of module. This one is a driver */
431262387023Sdduvall bge_ident, /* short description */
431362387023Sdduvall &bge_dev_ops /* driver specific ops */
431462387023Sdduvall };
431562387023Sdduvall
431662387023Sdduvall static struct modlinkage modlinkage = {
431762387023Sdduvall MODREV_1, (void *)&bge_modldrv, NULL
431862387023Sdduvall };
431962387023Sdduvall
432062387023Sdduvall
432162387023Sdduvall int
432262387023Sdduvall _info(struct modinfo *modinfop)
432362387023Sdduvall {
432462387023Sdduvall return (mod_info(&modlinkage, modinfop));
432562387023Sdduvall }
432662387023Sdduvall
432762387023Sdduvall int
432862387023Sdduvall _init(void)
432962387023Sdduvall {
433062387023Sdduvall int status;
433162387023Sdduvall
433262387023Sdduvall mac_init_ops(&bge_dev_ops, "bge");
433362387023Sdduvall status = mod_install(&modlinkage);
433462387023Sdduvall if (status == DDI_SUCCESS)
433562387023Sdduvall mutex_init(bge_log_mutex, NULL, MUTEX_DRIVER, NULL);
433662387023Sdduvall else
433762387023Sdduvall mac_fini_ops(&bge_dev_ops);
433862387023Sdduvall return (status);
433962387023Sdduvall }
434062387023Sdduvall
434162387023Sdduvall int
434262387023Sdduvall _fini(void)
434362387023Sdduvall {
434462387023Sdduvall int status;
434562387023Sdduvall
434662387023Sdduvall status = mod_remove(&modlinkage);
434762387023Sdduvall if (status == DDI_SUCCESS) {
434862387023Sdduvall mac_fini_ops(&bge_dev_ops);
434962387023Sdduvall mutex_destroy(bge_log_mutex);
435062387023Sdduvall }
435162387023Sdduvall return (status);
435262387023Sdduvall }
435362387023Sdduvall
435462387023Sdduvall
435562387023Sdduvall /*
435662387023Sdduvall * bge_add_intrs:
435762387023Sdduvall *
435862387023Sdduvall * Register FIXED or MSI interrupts.
435962387023Sdduvall */
436062387023Sdduvall static int
436162387023Sdduvall bge_add_intrs(bge_t *bgep, int intr_type)
436262387023Sdduvall {
436362387023Sdduvall dev_info_t *dip = bgep->devinfo;
436462387023Sdduvall int avail, actual, intr_size, count = 0;
436562387023Sdduvall int i, flag, ret;
436662387023Sdduvall
4367f724721bSzh199473 BGE_DEBUG(("bge_add_intrs($%p, 0x%x)", (void *)bgep, intr_type));
436862387023Sdduvall
436962387023Sdduvall /* Get number of interrupts */
437062387023Sdduvall ret = ddi_intr_get_nintrs(dip, intr_type, &count);
437162387023Sdduvall if ((ret != DDI_SUCCESS) || (count == 0)) {
437262387023Sdduvall bge_error(bgep, "ddi_intr_get_nintrs() failure, ret: %d, "
437362387023Sdduvall "count: %d", ret, count);
437462387023Sdduvall
437562387023Sdduvall return (DDI_FAILURE);
437662387023Sdduvall }
437762387023Sdduvall
437862387023Sdduvall /* Get number of available interrupts */
437962387023Sdduvall ret = ddi_intr_get_navail(dip, intr_type, &avail);
438062387023Sdduvall if ((ret != DDI_SUCCESS) || (avail == 0)) {
438162387023Sdduvall bge_error(bgep, "ddi_intr_get_navail() failure, "
438262387023Sdduvall "ret: %d, avail: %d\n", ret, avail);
438362387023Sdduvall
438462387023Sdduvall return (DDI_FAILURE);
438562387023Sdduvall }
438662387023Sdduvall
438762387023Sdduvall if (avail < count) {
4388f724721bSzh199473 BGE_DEBUG(("%s: nintrs() returned %d, navail returned %d",
4389f724721bSzh199473 bgep->ifname, count, avail));
439062387023Sdduvall }
439162387023Sdduvall
439262387023Sdduvall /*
439362387023Sdduvall * BGE hardware generates only single MSI even though it claims
439462387023Sdduvall * to support multiple MSIs. So, hard code MSI count value to 1.
439562387023Sdduvall */
439662387023Sdduvall if (intr_type == DDI_INTR_TYPE_MSI) {
439762387023Sdduvall count = 1;
439862387023Sdduvall flag = DDI_INTR_ALLOC_STRICT;
439962387023Sdduvall } else {
440062387023Sdduvall flag = DDI_INTR_ALLOC_NORMAL;
440162387023Sdduvall }
440262387023Sdduvall
440362387023Sdduvall /* Allocate an array of interrupt handles */
440462387023Sdduvall intr_size = count * sizeof (ddi_intr_handle_t);
440562387023Sdduvall bgep->htable = kmem_alloc(intr_size, KM_SLEEP);
440662387023Sdduvall
440762387023Sdduvall /* Call ddi_intr_alloc() */
440862387023Sdduvall ret = ddi_intr_alloc(dip, bgep->htable, intr_type, 0,
440962387023Sdduvall count, &actual, flag);
441062387023Sdduvall
441162387023Sdduvall if ((ret != DDI_SUCCESS) || (actual == 0)) {
441262387023Sdduvall bge_error(bgep, "ddi_intr_alloc() failed %d\n", ret);
441362387023Sdduvall
441462387023Sdduvall kmem_free(bgep->htable, intr_size);
441562387023Sdduvall return (DDI_FAILURE);
441662387023Sdduvall }
441762387023Sdduvall
441862387023Sdduvall if (actual < count) {
4419f724721bSzh199473 BGE_DEBUG(("%s: Requested: %d, Received: %d",
4420f724721bSzh199473 bgep->ifname, count, actual));
442162387023Sdduvall }
442262387023Sdduvall
442362387023Sdduvall bgep->intr_cnt = actual;
442462387023Sdduvall
442562387023Sdduvall /*
442662387023Sdduvall * Get priority for first msi, assume remaining are all the same
442762387023Sdduvall */
442862387023Sdduvall if ((ret = ddi_intr_get_pri(bgep->htable[0], &bgep->intr_pri)) !=
442962387023Sdduvall DDI_SUCCESS) {
443062387023Sdduvall bge_error(bgep, "ddi_intr_get_pri() failed %d\n", ret);
443162387023Sdduvall
443262387023Sdduvall /* Free already allocated intr */
443362387023Sdduvall for (i = 0; i < actual; i++) {
443462387023Sdduvall (void) ddi_intr_free(bgep->htable[i]);
443562387023Sdduvall }
443662387023Sdduvall
443762387023Sdduvall kmem_free(bgep->htable, intr_size);
443862387023Sdduvall return (DDI_FAILURE);
443962387023Sdduvall }
444062387023Sdduvall
444162387023Sdduvall /* Call ddi_intr_add_handler() */
444262387023Sdduvall for (i = 0; i < actual; i++) {
444362387023Sdduvall if ((ret = ddi_intr_add_handler(bgep->htable[i], bge_intr,
444462387023Sdduvall (caddr_t)bgep, (caddr_t)(uintptr_t)i)) != DDI_SUCCESS) {
444562387023Sdduvall bge_error(bgep, "ddi_intr_add_handler() "
444662387023Sdduvall "failed %d\n", ret);
444762387023Sdduvall
444862387023Sdduvall /* Free already allocated intr */
444962387023Sdduvall for (i = 0; i < actual; i++) {
445062387023Sdduvall (void) ddi_intr_free(bgep->htable[i]);
445162387023Sdduvall }
445262387023Sdduvall
445362387023Sdduvall kmem_free(bgep->htable, intr_size);
445462387023Sdduvall return (DDI_FAILURE);
445562387023Sdduvall }
445662387023Sdduvall }
445762387023Sdduvall
445862387023Sdduvall if ((ret = ddi_intr_get_cap(bgep->htable[0], &bgep->intr_cap))
445962387023Sdduvall != DDI_SUCCESS) {
446062387023Sdduvall bge_error(bgep, "ddi_intr_get_cap() failed %d\n", ret);
446162387023Sdduvall
446262387023Sdduvall for (i = 0; i < actual; i++) {
446362387023Sdduvall (void) ddi_intr_remove_handler(bgep->htable[i]);
446462387023Sdduvall (void) ddi_intr_free(bgep->htable[i]);
446562387023Sdduvall }
446662387023Sdduvall
446762387023Sdduvall kmem_free(bgep->htable, intr_size);
446862387023Sdduvall return (DDI_FAILURE);
446962387023Sdduvall }
447062387023Sdduvall
447162387023Sdduvall return (DDI_SUCCESS);
447262387023Sdduvall }
447362387023Sdduvall
447462387023Sdduvall /*
447562387023Sdduvall * bge_rem_intrs:
447662387023Sdduvall *
447762387023Sdduvall * Unregister FIXED or MSI interrupts
447862387023Sdduvall */
447962387023Sdduvall static void
448062387023Sdduvall bge_rem_intrs(bge_t *bgep)
448162387023Sdduvall {
448262387023Sdduvall int i;
448362387023Sdduvall
4484f724721bSzh199473 BGE_DEBUG(("bge_rem_intrs($%p)", (void *)bgep));
448562387023Sdduvall
448600d0963fSdilpreet /* Call ddi_intr_remove_handler() */
448700d0963fSdilpreet for (i = 0; i < bgep->intr_cnt; i++) {
448800d0963fSdilpreet (void) ddi_intr_remove_handler(bgep->htable[i]);
448900d0963fSdilpreet (void) ddi_intr_free(bgep->htable[i]);
449000d0963fSdilpreet }
449100d0963fSdilpreet
449200d0963fSdilpreet kmem_free(bgep->htable, bgep->intr_cnt * sizeof (ddi_intr_handle_t));
449300d0963fSdilpreet }
449400d0963fSdilpreet
449500d0963fSdilpreet
449600d0963fSdilpreet void
449700d0963fSdilpreet bge_intr_enable(bge_t *bgep)
449800d0963fSdilpreet {
449900d0963fSdilpreet int i;
450000d0963fSdilpreet
450100d0963fSdilpreet if (bgep->intr_cap & DDI_INTR_FLAG_BLOCK) {
450200d0963fSdilpreet /* Call ddi_intr_block_enable() for MSI interrupts */
450300d0963fSdilpreet (void) ddi_intr_block_enable(bgep->htable, bgep->intr_cnt);
450400d0963fSdilpreet } else {
450500d0963fSdilpreet /* Call ddi_intr_enable for MSI or FIXED interrupts */
450600d0963fSdilpreet for (i = 0; i < bgep->intr_cnt; i++) {
450700d0963fSdilpreet (void) ddi_intr_enable(bgep->htable[i]);
450800d0963fSdilpreet }
450900d0963fSdilpreet }
451000d0963fSdilpreet }
451100d0963fSdilpreet
451200d0963fSdilpreet
451300d0963fSdilpreet void
451400d0963fSdilpreet bge_intr_disable(bge_t *bgep)
451500d0963fSdilpreet {
451600d0963fSdilpreet int i;
451700d0963fSdilpreet
451862387023Sdduvall if (bgep->intr_cap & DDI_INTR_FLAG_BLOCK) {
451962387023Sdduvall /* Call ddi_intr_block_disable() */
452062387023Sdduvall (void) ddi_intr_block_disable(bgep->htable, bgep->intr_cnt);
452162387023Sdduvall } else {
452262387023Sdduvall for (i = 0; i < bgep->intr_cnt; i++) {
452362387023Sdduvall (void) ddi_intr_disable(bgep->htable[i]);
452462387023Sdduvall }
452562387023Sdduvall }
452662387023Sdduvall }
4527e7801d59Ssowmini
4528e7801d59Ssowmini int
4529e7801d59Ssowmini bge_reprogram(bge_t *bgep)
4530e7801d59Ssowmini {
4531e7801d59Ssowmini int status = 0;
4532e7801d59Ssowmini
4533e7801d59Ssowmini ASSERT(mutex_owned(bgep->genlock));
4534e7801d59Ssowmini
4535e7801d59Ssowmini if (bge_phys_update(bgep) != DDI_SUCCESS) {
4536e7801d59Ssowmini ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED);
4537e7801d59Ssowmini status = IOC_INVAL;
4538e7801d59Ssowmini }
4539e7801d59Ssowmini #ifdef BGE_IPMI_ASF
4540e7801d59Ssowmini if (bge_chip_sync(bgep, B_TRUE) == DDI_FAILURE) {
4541e7801d59Ssowmini #else
4542e7801d59Ssowmini if (bge_chip_sync(bgep) == DDI_FAILURE) {
4543e7801d59Ssowmini #endif
4544e7801d59Ssowmini ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED);
4545e7801d59Ssowmini status = IOC_INVAL;
4546e7801d59Ssowmini }
4547e7801d59Ssowmini if (bgep->intr_type == DDI_INTR_TYPE_MSI)
4548e7801d59Ssowmini bge_chip_msi_trig(bgep);
4549e7801d59Ssowmini return (status);
4550e7801d59Ssowmini }
4551