1bdb9230aSGarrett D'Amore /*
2bdb9230aSGarrett D'Amore * CDDL HEADER START
3bdb9230aSGarrett D'Amore *
4bdb9230aSGarrett D'Amore * The contents of this file are subject to the terms of the
5bdb9230aSGarrett D'Amore * Common Development and Distribution License (the "License").
6bdb9230aSGarrett D'Amore * You may not use this file except in compliance with the License.
7bdb9230aSGarrett D'Amore *
8bdb9230aSGarrett D'Amore * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9bdb9230aSGarrett D'Amore * or http://www.opensolaris.org/os/licensing.
10bdb9230aSGarrett D'Amore * See the License for the specific language governing permissions
11bdb9230aSGarrett D'Amore * and limitations under the License.
12bdb9230aSGarrett D'Amore *
13bdb9230aSGarrett D'Amore * When distributing Covered Code, include this CDDL HEADER in each
14bdb9230aSGarrett D'Amore * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15bdb9230aSGarrett D'Amore * If applicable, add the following below this CDDL HEADER, with the
16bdb9230aSGarrett D'Amore * fields enclosed by brackets "[]" replaced with your own identifying
17bdb9230aSGarrett D'Amore * information: Portions Copyright [yyyy] [name of copyright owner]
18bdb9230aSGarrett D'Amore *
19bdb9230aSGarrett D'Amore * CDDL HEADER END
20bdb9230aSGarrett D'Amore */
21bdb9230aSGarrett D'Amore
22bdb9230aSGarrett D'Amore /*
23*0dc2366fSVenugopal Iyer * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24bdb9230aSGarrett D'Amore * Use is subject to license terms.
25bdb9230aSGarrett D'Amore */
26bdb9230aSGarrett D'Amore
27bdb9230aSGarrett D'Amore
28bdb9230aSGarrett D'Amore /*
29bdb9230aSGarrett D'Amore * dnet -- DEC 21x4x
30bdb9230aSGarrett D'Amore *
31bdb9230aSGarrett D'Amore * Currently supports:
32bdb9230aSGarrett D'Amore * 21040, 21041, 21140, 21142, 21143
33bdb9230aSGarrett D'Amore * SROM versions 1, 3, 3.03, 4
34bdb9230aSGarrett D'Amore * TP, AUI, BNC, 100BASETX, 100BASET4
35bdb9230aSGarrett D'Amore *
36bdb9230aSGarrett D'Amore * XXX NEEDSWORK
37bdb9230aSGarrett D'Amore * All media SHOULD work, FX is untested
38bdb9230aSGarrett D'Amore *
3998e8d175SSteven Stallion * Depends on the Generic LAN Driver utility functions in /kernel/misc/mac
40bdb9230aSGarrett D'Amore */
41bdb9230aSGarrett D'Amore
42bdb9230aSGarrett D'Amore #define BUG_4010796 /* See 4007871, 4010796 */
43bdb9230aSGarrett D'Amore
44bdb9230aSGarrett D'Amore #include <sys/types.h>
45bdb9230aSGarrett D'Amore #include <sys/errno.h>
46bdb9230aSGarrett D'Amore #include <sys/param.h>
47bdb9230aSGarrett D'Amore #include <sys/stropts.h>
48bdb9230aSGarrett D'Amore #include <sys/stream.h>
49bdb9230aSGarrett D'Amore #include <sys/kmem.h>
50bdb9230aSGarrett D'Amore #include <sys/conf.h>
51bdb9230aSGarrett D'Amore #include <sys/devops.h>
52bdb9230aSGarrett D'Amore #include <sys/ksynch.h>
53bdb9230aSGarrett D'Amore #include <sys/stat.h>
54bdb9230aSGarrett D'Amore #include <sys/modctl.h>
55bdb9230aSGarrett D'Amore #include <sys/debug.h>
56bdb9230aSGarrett D'Amore #include <sys/dlpi.h>
57bdb9230aSGarrett D'Amore #include <sys/ethernet.h>
5898e8d175SSteven Stallion #include <sys/vlan.h>
5998e8d175SSteven Stallion #include <sys/mac.h>
6098e8d175SSteven Stallion #include <sys/mac_ether.h>
6198e8d175SSteven Stallion #include <sys/mac_provider.h>
62bdb9230aSGarrett D'Amore #include <sys/pci.h>
63bdb9230aSGarrett D'Amore #include <sys/ddi.h>
64bdb9230aSGarrett D'Amore #include <sys/sunddi.h>
6598e8d175SSteven Stallion #include <sys/strsun.h>
66bdb9230aSGarrett D'Amore
67bdb9230aSGarrett D'Amore #include "dnet_mii.h"
68bdb9230aSGarrett D'Amore #include "dnet.h"
69bdb9230aSGarrett D'Amore
70bdb9230aSGarrett D'Amore /*
71bdb9230aSGarrett D'Amore * Declarations and Module Linkage
72bdb9230aSGarrett D'Amore */
73bdb9230aSGarrett D'Amore
74bdb9230aSGarrett D'Amore #define IDENT "DNET 21x4x"
75bdb9230aSGarrett D'Amore
76bdb9230aSGarrett D'Amore /*
77bdb9230aSGarrett D'Amore * #define DNET_NOISY
78bdb9230aSGarrett D'Amore * #define SROMDEBUG
79bdb9230aSGarrett D'Amore * #define SROMDUMPSTRUCTURES
80bdb9230aSGarrett D'Amore */
81bdb9230aSGarrett D'Amore
82bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
83bdb9230aSGarrett D'Amore #ifdef DNET_NOISY
84bdb9230aSGarrett D'Amore int dnetdebug = -1;
85bdb9230aSGarrett D'Amore #else
86bdb9230aSGarrett D'Amore int dnetdebug = 0;
87bdb9230aSGarrett D'Amore #endif
88bdb9230aSGarrett D'Amore #endif
89bdb9230aSGarrett D'Amore
90bdb9230aSGarrett D'Amore /* used for message allocated using desballoc() */
91bdb9230aSGarrett D'Amore struct free_ptr {
92bdb9230aSGarrett D'Amore struct free_rtn free_rtn;
93bdb9230aSGarrett D'Amore caddr_t buf;
94bdb9230aSGarrett D'Amore };
95bdb9230aSGarrett D'Amore
96bdb9230aSGarrett D'Amore struct rbuf_list {
97bdb9230aSGarrett D'Amore struct rbuf_list *rbuf_next; /* next in the list */
98bdb9230aSGarrett D'Amore caddr_t rbuf_vaddr; /* virual addr of the buf */
99bdb9230aSGarrett D'Amore uint32_t rbuf_paddr; /* physical addr of the buf */
100bdb9230aSGarrett D'Amore uint32_t rbuf_endpaddr; /* physical addr at the end */
101bdb9230aSGarrett D'Amore ddi_dma_handle_t rbuf_dmahdl; /* dma handle */
102bdb9230aSGarrett D'Amore ddi_acc_handle_t rbuf_acchdl; /* handle for DDI functions */
103bdb9230aSGarrett D'Amore };
104bdb9230aSGarrett D'Amore
105bdb9230aSGarrett D'Amore /* Required system entry points */
10698e8d175SSteven Stallion static int dnet_probe(dev_info_t *);
10798e8d175SSteven Stallion static int dnet_attach(dev_info_t *, ddi_attach_cmd_t);
10898e8d175SSteven Stallion static int dnet_detach(dev_info_t *, ddi_detach_cmd_t);
10998e8d175SSteven Stallion static int dnet_quiesce(dev_info_t *);
110bdb9230aSGarrett D'Amore
11198e8d175SSteven Stallion /* Required driver entry points for GLDv3 */
11298e8d175SSteven Stallion static int dnet_m_start(void *);
11398e8d175SSteven Stallion static void dnet_m_stop(void *);
11498e8d175SSteven Stallion static int dnet_m_getstat(void *, uint_t, uint64_t *);
11598e8d175SSteven Stallion static int dnet_m_setpromisc(void *, boolean_t);
11698e8d175SSteven Stallion static int dnet_m_multicst(void *, boolean_t, const uint8_t *);
11798e8d175SSteven Stallion static int dnet_m_unicst(void *, const uint8_t *);
11898e8d175SSteven Stallion static mblk_t *dnet_m_tx(void *, mblk_t *);
11998e8d175SSteven Stallion
12098e8d175SSteven Stallion static uint_t dnet_intr(caddr_t);
121bdb9230aSGarrett D'Amore
122bdb9230aSGarrett D'Amore /* Internal functions used by the above entry points */
123bdb9230aSGarrett D'Amore static void write_gpr(struct dnetinstance *dnetp, uint32_t val);
12498e8d175SSteven Stallion static void dnet_reset_board(struct dnetinstance *);
12598e8d175SSteven Stallion static void dnet_init_board(struct dnetinstance *);
12698e8d175SSteven Stallion static void dnet_chip_init(struct dnetinstance *);
12798e8d175SSteven Stallion static uint32_t hashindex(const uint8_t *);
12898e8d175SSteven Stallion static int dnet_start(struct dnetinstance *);
12998e8d175SSteven Stallion static int dnet_set_addr(struct dnetinstance *);
130bdb9230aSGarrett D'Amore
13198e8d175SSteven Stallion static boolean_t dnet_send(struct dnetinstance *, mblk_t *);
13298e8d175SSteven Stallion
13398e8d175SSteven Stallion static void dnet_getp(struct dnetinstance *);
13498e8d175SSteven Stallion static void update_rx_stats(struct dnetinstance *, int);
13598e8d175SSteven Stallion static void update_tx_stats(struct dnetinstance *, int);
136bdb9230aSGarrett D'Amore
137bdb9230aSGarrett D'Amore /* Media Selection Setup Routines */
13898e8d175SSteven Stallion static void set_gpr(struct dnetinstance *);
13998e8d175SSteven Stallion static void set_opr(struct dnetinstance *);
14098e8d175SSteven Stallion static void set_sia(struct dnetinstance *);
141bdb9230aSGarrett D'Amore
142bdb9230aSGarrett D'Amore /* Buffer Management Routines */
14398e8d175SSteven Stallion static int dnet_alloc_bufs(struct dnetinstance *);
14498e8d175SSteven Stallion static void dnet_free_bufs(struct dnetinstance *);
14598e8d175SSteven Stallion static void dnet_init_txrx_bufs(struct dnetinstance *);
14698e8d175SSteven Stallion static int alloc_descriptor(struct dnetinstance *);
14798e8d175SSteven Stallion static void dnet_reclaim_Tx_desc(struct dnetinstance *);
148bdb9230aSGarrett D'Amore static int dnet_rbuf_init(dev_info_t *, int);
149bdb9230aSGarrett D'Amore static int dnet_rbuf_destroy();
150bdb9230aSGarrett D'Amore static struct rbuf_list *dnet_rbuf_alloc(dev_info_t *, int);
151bdb9230aSGarrett D'Amore static void dnet_rbuf_free(caddr_t);
152bdb9230aSGarrett D'Amore static void dnet_freemsg_buf(struct free_ptr *);
153bdb9230aSGarrett D'Amore
15498e8d175SSteven Stallion static void setup_block(struct dnetinstance *);
155bdb9230aSGarrett D'Amore
156bdb9230aSGarrett D'Amore /* SROM read functions */
157bdb9230aSGarrett D'Amore static int dnet_read_srom(dev_info_t *, int, ddi_acc_handle_t, caddr_t,
158bdb9230aSGarrett D'Amore uchar_t *, int);
159bdb9230aSGarrett D'Amore static void dnet_read21040addr(dev_info_t *, ddi_acc_handle_t, caddr_t,
160bdb9230aSGarrett D'Amore uchar_t *, int *);
161bdb9230aSGarrett D'Amore static void dnet_read21140srom(ddi_acc_handle_t, caddr_t, uchar_t *, int);
162bdb9230aSGarrett D'Amore static int get_alternative_srom_image(dev_info_t *, uchar_t *, int);
163bdb9230aSGarrett D'Amore static void dnet_print_srom(SROM_FORMAT *sr);
164bdb9230aSGarrett D'Amore static void dnet_dump_leaf(LEAF_FORMAT *leaf);
165bdb9230aSGarrett D'Amore static void dnet_dump_block(media_block_t *block);
166bdb9230aSGarrett D'Amore #ifdef BUG_4010796
167bdb9230aSGarrett D'Amore static void set_alternative_srom_image(dev_info_t *, uchar_t *, int);
16898e8d175SSteven Stallion static int dnet_hack(dev_info_t *);
169bdb9230aSGarrett D'Amore #endif
170bdb9230aSGarrett D'Amore
17198e8d175SSteven Stallion static int dnet_hack_interrupts(struct dnetinstance *, int);
172bdb9230aSGarrett D'Amore static int dnet_detach_hacked_interrupt(dev_info_t *devinfo);
17398e8d175SSteven Stallion static void enable_interrupts(struct dnetinstance *);
174bdb9230aSGarrett D'Amore
175bdb9230aSGarrett D'Amore /* SROM parsing functions */
176bdb9230aSGarrett D'Amore static void dnet_parse_srom(struct dnetinstance *dnetp, SROM_FORMAT *sr,
177bdb9230aSGarrett D'Amore uchar_t *vi);
178bdb9230aSGarrett D'Amore static void parse_controller_leaf(struct dnetinstance *dnetp, LEAF_FORMAT *leaf,
179bdb9230aSGarrett D'Amore uchar_t *vi);
180bdb9230aSGarrett D'Amore static uchar_t *parse_media_block(struct dnetinstance *dnetp,
181bdb9230aSGarrett D'Amore media_block_t *block, uchar_t *vi);
182bdb9230aSGarrett D'Amore static int check_srom_valid(uchar_t *);
183bdb9230aSGarrett D'Amore static void dnet_dumpbin(char *msg, uchar_t *, int size, int len);
184bdb9230aSGarrett D'Amore static void setup_legacy_blocks();
185bdb9230aSGarrett D'Amore /* Active Media Determination Routines */
18698e8d175SSteven Stallion static void find_active_media(struct dnetinstance *);
18798e8d175SSteven Stallion static int send_test_packet(struct dnetinstance *);
18898e8d175SSteven Stallion static int dnet_link_sense(struct dnetinstance *);
189bdb9230aSGarrett D'Amore
190bdb9230aSGarrett D'Amore /* PHY MII Routines */
191bdb9230aSGarrett D'Amore static ushort_t dnet_mii_read(dev_info_t *dip, int phy_addr, int reg_num);
192bdb9230aSGarrett D'Amore static void dnet_mii_write(dev_info_t *dip, int phy_addr, int reg_num,
193bdb9230aSGarrett D'Amore int reg_dat);
194bdb9230aSGarrett D'Amore static void write_mii(struct dnetinstance *, uint32_t, int);
195bdb9230aSGarrett D'Amore static void mii_tristate(struct dnetinstance *);
19698e8d175SSteven Stallion static void do_phy(struct dnetinstance *);
197bdb9230aSGarrett D'Amore static void dnet_mii_link_cb(dev_info_t *, int, enum mii_phy_state);
198bdb9230aSGarrett D'Amore static void set_leaf(SROM_FORMAT *sr, LEAF_FORMAT *leaf);
199bdb9230aSGarrett D'Amore
200bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
201bdb9230aSGarrett D'Amore uint32_t dnet_usecelapsed(struct dnetinstance *dnetp);
202bdb9230aSGarrett D'Amore void dnet_timestamp(struct dnetinstance *, char *);
203bdb9230aSGarrett D'Amore void dnet_usectimeout(struct dnetinstance *, uint32_t, int, timercb_t);
204bdb9230aSGarrett D'Amore #endif
205bdb9230aSGarrett D'Amore static char *media_str[] = {
206bdb9230aSGarrett D'Amore "10BaseT",
207bdb9230aSGarrett D'Amore "10Base2",
208bdb9230aSGarrett D'Amore "10Base5",
209bdb9230aSGarrett D'Amore "100BaseTX",
210bdb9230aSGarrett D'Amore "10BaseT FD",
211bdb9230aSGarrett D'Amore "100BaseTX FD",
212bdb9230aSGarrett D'Amore "100BaseT4",
213bdb9230aSGarrett D'Amore "100BaseFX",
214bdb9230aSGarrett D'Amore "100BaseFX FD",
215bdb9230aSGarrett D'Amore "MII"
216bdb9230aSGarrett D'Amore };
217bdb9230aSGarrett D'Amore
218bdb9230aSGarrett D'Amore /* default SROM info for cards with no SROMs */
219bdb9230aSGarrett D'Amore static LEAF_FORMAT leaf_default_100;
220bdb9230aSGarrett D'Amore static LEAF_FORMAT leaf_asante;
221bdb9230aSGarrett D'Amore static LEAF_FORMAT leaf_phylegacy;
222bdb9230aSGarrett D'Amore static LEAF_FORMAT leaf_cogent_100;
223bdb9230aSGarrett D'Amore static LEAF_FORMAT leaf_21041;
224bdb9230aSGarrett D'Amore static LEAF_FORMAT leaf_21040;
225bdb9230aSGarrett D'Amore
22698e8d175SSteven Stallion /* rx buffer size (rounded up to 4) */
22798e8d175SSteven Stallion int rx_buf_size = (ETHERMAX + ETHERFCSL + VLAN_TAGSZ + 3) & ~3;
228bdb9230aSGarrett D'Amore
229bdb9230aSGarrett D'Amore int max_rx_desc_21040 = MAX_RX_DESC_21040;
230bdb9230aSGarrett D'Amore int max_rx_desc_21140 = MAX_RX_DESC_21140;
231bdb9230aSGarrett D'Amore int max_tx_desc = MAX_TX_DESC;
232bdb9230aSGarrett D'Amore int dnet_xmit_threshold = MAX_TX_DESC >> 2; /* XXX need tuning? */
233bdb9230aSGarrett D'Amore
234bdb9230aSGarrett D'Amore static kmutex_t dnet_rbuf_lock; /* mutex to protect rbuf_list data */
235bdb9230aSGarrett D'Amore
236bdb9230aSGarrett D'Amore /* used for buffers allocated by ddi_dma_mem_alloc() */
237bdb9230aSGarrett D'Amore static ddi_dma_attr_t dma_attr = {
238bdb9230aSGarrett D'Amore DMA_ATTR_V0, /* dma_attr version */
239bdb9230aSGarrett D'Amore 0, /* dma_attr_addr_lo */
240bdb9230aSGarrett D'Amore (uint64_t)0xFFFFFFFF, /* dma_attr_addr_hi */
241bdb9230aSGarrett D'Amore 0x7FFFFFFF, /* dma_attr_count_max */
242bdb9230aSGarrett D'Amore 4, /* dma_attr_align */
243bdb9230aSGarrett D'Amore 0x3F, /* dma_attr_burstsizes */
244bdb9230aSGarrett D'Amore 1, /* dma_attr_minxfer */
245bdb9230aSGarrett D'Amore (uint64_t)0xFFFFFFFF, /* dma_attr_maxxfer */
246bdb9230aSGarrett D'Amore (uint64_t)0xFFFFFFFF, /* dma_attr_seg */
247bdb9230aSGarrett D'Amore 1, /* dma_attr_sgllen */
248bdb9230aSGarrett D'Amore 1, /* dma_attr_granular */
249bdb9230aSGarrett D'Amore 0, /* dma_attr_flags */
250bdb9230aSGarrett D'Amore };
251bdb9230aSGarrett D'Amore
252bdb9230aSGarrett D'Amore /* used for buffers allocated for rbuf, allow 2 cookies */
253bdb9230aSGarrett D'Amore static ddi_dma_attr_t dma_attr_rb = {
254bdb9230aSGarrett D'Amore DMA_ATTR_V0, /* dma_attr version */
255bdb9230aSGarrett D'Amore 0, /* dma_attr_addr_lo */
256bdb9230aSGarrett D'Amore (uint64_t)0xFFFFFFFF, /* dma_attr_addr_hi */
257bdb9230aSGarrett D'Amore 0x7FFFFFFF, /* dma_attr_count_max */
258bdb9230aSGarrett D'Amore 4, /* dma_attr_align */
259bdb9230aSGarrett D'Amore 0x3F, /* dma_attr_burstsizes */
260bdb9230aSGarrett D'Amore 1, /* dma_attr_minxfer */
261bdb9230aSGarrett D'Amore (uint64_t)0xFFFFFFFF, /* dma_attr_maxxfer */
262bdb9230aSGarrett D'Amore (uint64_t)0xFFFFFFFF, /* dma_attr_seg */
263bdb9230aSGarrett D'Amore 2, /* dma_attr_sgllen */
264bdb9230aSGarrett D'Amore 1, /* dma_attr_granular */
265bdb9230aSGarrett D'Amore 0, /* dma_attr_flags */
266bdb9230aSGarrett D'Amore };
267bdb9230aSGarrett D'Amore /* used for buffers which are NOT from ddi_dma_mem_alloc() - xmit side */
268bdb9230aSGarrett D'Amore static ddi_dma_attr_t dma_attr_tx = {
269bdb9230aSGarrett D'Amore DMA_ATTR_V0, /* dma_attr version */
270bdb9230aSGarrett D'Amore 0, /* dma_attr_addr_lo */
271bdb9230aSGarrett D'Amore (uint64_t)0xFFFFFFFF, /* dma_attr_addr_hi */
272bdb9230aSGarrett D'Amore 0x7FFFFFFF, /* dma_attr_count_max */
273bdb9230aSGarrett D'Amore 1, /* dma_attr_align */
274bdb9230aSGarrett D'Amore 0x3F, /* dma_attr_burstsizes */
275bdb9230aSGarrett D'Amore 1, /* dma_attr_minxfer */
276bdb9230aSGarrett D'Amore (uint64_t)0xFFFFFFFF, /* dma_attr_maxxfer */
277bdb9230aSGarrett D'Amore (uint64_t)0xFFFFFFFF, /* dma_attr_seg */
278bdb9230aSGarrett D'Amore 0x7FFF, /* dma_attr_sgllen */
279bdb9230aSGarrett D'Amore 1, /* dma_attr_granular */
280bdb9230aSGarrett D'Amore 0, /* dma_attr_flags */
281bdb9230aSGarrett D'Amore };
282bdb9230aSGarrett D'Amore
283bdb9230aSGarrett D'Amore static ddi_device_acc_attr_t accattr = {
284bdb9230aSGarrett D'Amore DDI_DEVICE_ATTR_V0,
285bdb9230aSGarrett D'Amore DDI_NEVERSWAP_ACC,
286bdb9230aSGarrett D'Amore DDI_STRICTORDER_ACC,
287bdb9230aSGarrett D'Amore };
288bdb9230aSGarrett D'Amore
289bdb9230aSGarrett D'Amore uchar_t dnet_broadcastaddr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
290bdb9230aSGarrett D'Amore
291bdb9230aSGarrett D'Amore /* Standard Module linkage initialization for a Streams driver */
292bdb9230aSGarrett D'Amore extern struct mod_ops mod_driverops;
293bdb9230aSGarrett D'Amore
29498e8d175SSteven Stallion DDI_DEFINE_STREAM_OPS(dnet_devops, nulldev, dnet_probe, dnet_attach,
29598e8d175SSteven Stallion dnet_detach, nodev, NULL, D_MP, NULL, dnet_quiesce);
296bdb9230aSGarrett D'Amore
29798e8d175SSteven Stallion static struct modldrv dnet_modldrv = {
298bdb9230aSGarrett D'Amore &mod_driverops, /* Type of module. This one is a driver */
299bdb9230aSGarrett D'Amore IDENT, /* short description */
30098e8d175SSteven Stallion &dnet_devops /* driver specific ops */
301bdb9230aSGarrett D'Amore };
302bdb9230aSGarrett D'Amore
30398e8d175SSteven Stallion static struct modlinkage dnet_modlinkage = {
30498e8d175SSteven Stallion MODREV_1, /* ml_rev */
30598e8d175SSteven Stallion { &dnet_modldrv, NULL } /* ml_linkage */
306bdb9230aSGarrett D'Amore };
307bdb9230aSGarrett D'Amore
30898e8d175SSteven Stallion static mac_callbacks_t dnet_m_callbacks = {
30998e8d175SSteven Stallion 0, /* mc_callbacks */
31098e8d175SSteven Stallion dnet_m_getstat, /* mc_getstat */
31198e8d175SSteven Stallion dnet_m_start, /* mc_start */
31298e8d175SSteven Stallion dnet_m_stop, /* mc_stop */
31398e8d175SSteven Stallion dnet_m_setpromisc, /* mc_setpromisc */
31498e8d175SSteven Stallion dnet_m_multicst, /* mc_multicst */
31598e8d175SSteven Stallion dnet_m_unicst, /* mc_unicst */
31698e8d175SSteven Stallion dnet_m_tx, /* mc_tx */
317*0dc2366fSVenugopal Iyer NULL,
31898e8d175SSteven Stallion NULL, /* mc_ioctl */
31998e8d175SSteven Stallion NULL, /* mc_getcapab */
32098e8d175SSteven Stallion NULL, /* mc_open */
32198e8d175SSteven Stallion NULL /* mc_close */
32298e8d175SSteven Stallion };
323bdb9230aSGarrett D'Amore
324bdb9230aSGarrett D'Amore /*
325bdb9230aSGarrett D'Amore * Passed to the hacked interrupt for multiport Cogent and ZNYX cards with
326bdb9230aSGarrett D'Amore * dodgy interrupt routing
327bdb9230aSGarrett D'Amore */
328bdb9230aSGarrett D'Amore #define MAX_INST 8 /* Maximum instances on a multiport adapter. */
329bdb9230aSGarrett D'Amore struct hackintr_inf
330bdb9230aSGarrett D'Amore {
33198e8d175SSteven Stallion struct dnetinstance *dnetps[MAX_INST]; /* dnetps for each port */
332bdb9230aSGarrett D'Amore dev_info_t *devinfo; /* Devinfo of the primary device */
333bdb9230aSGarrett D'Amore kmutex_t lock;
334bdb9230aSGarrett D'Amore /* Ensures the interrupt doesn't get called while detaching */
335bdb9230aSGarrett D'Amore };
336bdb9230aSGarrett D'Amore static char hackintr_propname[] = "InterruptData";
337bdb9230aSGarrett D'Amore static char macoffset_propname[] = "MAC_offset";
338bdb9230aSGarrett D'Amore static char speed_propname[] = "speed";
339bdb9230aSGarrett D'Amore static char ofloprob_propname[] = "dmaworkaround";
340bdb9230aSGarrett D'Amore static char duplex_propname[] = "full-duplex"; /* Must agree with MII */
341bdb9230aSGarrett D'Amore static char printsrom_propname[] = "print-srom";
342bdb9230aSGarrett D'Amore
343bdb9230aSGarrett D'Amore static uint_t dnet_hack_intr(struct hackintr_inf *);
344bdb9230aSGarrett D'Amore
345bdb9230aSGarrett D'Amore int
_init(void)346bdb9230aSGarrett D'Amore _init(void)
347bdb9230aSGarrett D'Amore {
348bdb9230aSGarrett D'Amore int i;
349bdb9230aSGarrett D'Amore
350bdb9230aSGarrett D'Amore /* Configure fake sroms for legacy cards */
351bdb9230aSGarrett D'Amore mutex_init(&dnet_rbuf_lock, NULL, MUTEX_DRIVER, NULL);
352bdb9230aSGarrett D'Amore setup_legacy_blocks();
35398e8d175SSteven Stallion
35498e8d175SSteven Stallion mac_init_ops(&dnet_devops, "dnet");
35598e8d175SSteven Stallion
35698e8d175SSteven Stallion if ((i = mod_install(&dnet_modlinkage)) != 0) {
35798e8d175SSteven Stallion mac_fini_ops(&dnet_devops);
358bdb9230aSGarrett D'Amore mutex_destroy(&dnet_rbuf_lock);
359bdb9230aSGarrett D'Amore }
360bdb9230aSGarrett D'Amore return (i);
361bdb9230aSGarrett D'Amore }
362bdb9230aSGarrett D'Amore
363bdb9230aSGarrett D'Amore int
_fini(void)364bdb9230aSGarrett D'Amore _fini(void)
365bdb9230aSGarrett D'Amore {
366bdb9230aSGarrett D'Amore int i;
36798e8d175SSteven Stallion
36898e8d175SSteven Stallion if ((i = mod_remove(&dnet_modlinkage)) == 0) {
36998e8d175SSteven Stallion mac_fini_ops(&dnet_devops);
37098e8d175SSteven Stallion
371bdb9230aSGarrett D'Amore /* loop until all the receive buffers are freed */
372bdb9230aSGarrett D'Amore while (dnet_rbuf_destroy() != 0) {
373bdb9230aSGarrett D'Amore delay(drv_usectohz(100000));
374bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
375bdb9230aSGarrett D'Amore if (dnetdebug & DNETDDI)
376bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "dnet _fini delay");
377bdb9230aSGarrett D'Amore #endif
378bdb9230aSGarrett D'Amore }
379bdb9230aSGarrett D'Amore mutex_destroy(&dnet_rbuf_lock);
380bdb9230aSGarrett D'Amore }
381bdb9230aSGarrett D'Amore return (i);
382bdb9230aSGarrett D'Amore }
383bdb9230aSGarrett D'Amore
384bdb9230aSGarrett D'Amore int
_info(struct modinfo * modinfop)385bdb9230aSGarrett D'Amore _info(struct modinfo *modinfop)
386bdb9230aSGarrett D'Amore {
38798e8d175SSteven Stallion return (mod_info(&dnet_modlinkage, modinfop));
388bdb9230aSGarrett D'Amore }
389bdb9230aSGarrett D'Amore
390bdb9230aSGarrett D'Amore /*
391bdb9230aSGarrett D'Amore * probe(9E) -- Determine if a device is present
392bdb9230aSGarrett D'Amore */
393bdb9230aSGarrett D'Amore static int
dnet_probe(dev_info_t * devinfo)39498e8d175SSteven Stallion dnet_probe(dev_info_t *devinfo)
395bdb9230aSGarrett D'Amore {
396bdb9230aSGarrett D'Amore ddi_acc_handle_t handle;
397bdb9230aSGarrett D'Amore uint16_t vendorid;
398bdb9230aSGarrett D'Amore uint16_t deviceid;
399bdb9230aSGarrett D'Amore
400bdb9230aSGarrett D'Amore if (pci_config_setup(devinfo, &handle) != DDI_SUCCESS)
401bdb9230aSGarrett D'Amore return (DDI_PROBE_FAILURE);
402bdb9230aSGarrett D'Amore
403bdb9230aSGarrett D'Amore vendorid = pci_config_get16(handle, PCI_CONF_VENID);
404bdb9230aSGarrett D'Amore
405bdb9230aSGarrett D'Amore if (vendorid != DEC_VENDOR_ID) {
406bdb9230aSGarrett D'Amore pci_config_teardown(&handle);
407bdb9230aSGarrett D'Amore return (DDI_PROBE_FAILURE);
408bdb9230aSGarrett D'Amore }
409bdb9230aSGarrett D'Amore
410bdb9230aSGarrett D'Amore deviceid = pci_config_get16(handle, PCI_CONF_DEVID);
411bdb9230aSGarrett D'Amore switch (deviceid) {
412bdb9230aSGarrett D'Amore case DEVICE_ID_21040:
413bdb9230aSGarrett D'Amore case DEVICE_ID_21041:
414bdb9230aSGarrett D'Amore case DEVICE_ID_21140:
415bdb9230aSGarrett D'Amore case DEVICE_ID_21143: /* And 142 */
416bdb9230aSGarrett D'Amore break;
417bdb9230aSGarrett D'Amore default:
418bdb9230aSGarrett D'Amore pci_config_teardown(&handle);
419bdb9230aSGarrett D'Amore return (DDI_PROBE_FAILURE);
420bdb9230aSGarrett D'Amore }
421bdb9230aSGarrett D'Amore
422bdb9230aSGarrett D'Amore pci_config_teardown(&handle);
423bdb9230aSGarrett D'Amore #ifndef BUG_4010796
424bdb9230aSGarrett D'Amore return (DDI_PROBE_SUCCESS);
425bdb9230aSGarrett D'Amore #else
42698e8d175SSteven Stallion return (dnet_hack(devinfo));
427bdb9230aSGarrett D'Amore #endif
428bdb9230aSGarrett D'Amore }
429bdb9230aSGarrett D'Amore
430bdb9230aSGarrett D'Amore #ifdef BUG_4010796
431bdb9230aSGarrett D'Amore /*
432bdb9230aSGarrett D'Amore * If we have a device, but we cannot presently access its SROM data,
433bdb9230aSGarrett D'Amore * then we return DDI_PROBE_PARTIAL and hope that sometime later we
434bdb9230aSGarrett D'Amore * will be able to get at the SROM data. This can only happen if we
435bdb9230aSGarrett D'Amore * are a secondary port with no SROM, and the bootstrap failed to set
436bdb9230aSGarrett D'Amore * our DNET_SROM property, and our primary sibling has not yet probed.
437bdb9230aSGarrett D'Amore */
438bdb9230aSGarrett D'Amore static int
dnet_hack(dev_info_t * devinfo)43998e8d175SSteven Stallion dnet_hack(dev_info_t *devinfo)
440bdb9230aSGarrett D'Amore {
441bdb9230aSGarrett D'Amore uchar_t vendor_info[SROM_SIZE];
442bdb9230aSGarrett D'Amore uint32_t csr;
443bdb9230aSGarrett D'Amore uint16_t deviceid;
444bdb9230aSGarrett D'Amore ddi_acc_handle_t handle;
445bdb9230aSGarrett D'Amore uint32_t retval;
446bdb9230aSGarrett D'Amore int secondary;
447bdb9230aSGarrett D'Amore ddi_acc_handle_t io_handle;
448bdb9230aSGarrett D'Amore caddr_t io_reg;
449bdb9230aSGarrett D'Amore
450bdb9230aSGarrett D'Amore #define DNET_PCI_RNUMBER 1
451bdb9230aSGarrett D'Amore
452bdb9230aSGarrett D'Amore if (pci_config_setup(devinfo, &handle) != DDI_SUCCESS)
453bdb9230aSGarrett D'Amore return (DDI_PROBE_FAILURE);
454bdb9230aSGarrett D'Amore
455bdb9230aSGarrett D'Amore deviceid = pci_config_get16(handle, PCI_CONF_DEVID);
456bdb9230aSGarrett D'Amore
457bdb9230aSGarrett D'Amore /*
458bdb9230aSGarrett D'Amore * Turn on Master Enable and IO Enable bits.
459bdb9230aSGarrett D'Amore */
460bdb9230aSGarrett D'Amore csr = pci_config_get32(handle, PCI_CONF_COMM);
461bdb9230aSGarrett D'Amore pci_config_put32(handle, PCI_CONF_COMM, (csr |PCI_COMM_ME|PCI_COMM_IO));
462bdb9230aSGarrett D'Amore
463bdb9230aSGarrett D'Amore pci_config_teardown(&handle);
464bdb9230aSGarrett D'Amore
465bdb9230aSGarrett D'Amore /* Now map I/O register */
466bdb9230aSGarrett D'Amore if (ddi_regs_map_setup(devinfo, DNET_PCI_RNUMBER,
467bdb9230aSGarrett D'Amore &io_reg, 0, 0, &accattr, &io_handle) != DDI_SUCCESS) {
468bdb9230aSGarrett D'Amore return (DDI_PROBE_FAILURE);
469bdb9230aSGarrett D'Amore }
470bdb9230aSGarrett D'Amore
471bdb9230aSGarrett D'Amore /*
472bdb9230aSGarrett D'Amore * Reset the chip
473bdb9230aSGarrett D'Amore */
474bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, BUS_MODE_REG), SW_RESET);
475bdb9230aSGarrett D'Amore drv_usecwait(3);
476bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, BUS_MODE_REG), 0);
477bdb9230aSGarrett D'Amore drv_usecwait(8);
478bdb9230aSGarrett D'Amore
479bdb9230aSGarrett D'Amore secondary = dnet_read_srom(devinfo, deviceid, io_handle,
480bdb9230aSGarrett D'Amore io_reg, vendor_info, sizeof (vendor_info));
481bdb9230aSGarrett D'Amore
482bdb9230aSGarrett D'Amore switch (secondary) {
483bdb9230aSGarrett D'Amore case -1:
484bdb9230aSGarrett D'Amore /* We can't access our SROM data! */
485bdb9230aSGarrett D'Amore retval = DDI_PROBE_PARTIAL;
486bdb9230aSGarrett D'Amore break;
487bdb9230aSGarrett D'Amore case 0:
488bdb9230aSGarrett D'Amore retval = DDI_PROBE_SUCCESS;
489bdb9230aSGarrett D'Amore break;
490bdb9230aSGarrett D'Amore default:
491bdb9230aSGarrett D'Amore retval = DDI_PROBE_SUCCESS;
492bdb9230aSGarrett D'Amore }
493bdb9230aSGarrett D'Amore
494bdb9230aSGarrett D'Amore ddi_regs_map_free(&io_handle);
495bdb9230aSGarrett D'Amore return (retval);
496bdb9230aSGarrett D'Amore }
497bdb9230aSGarrett D'Amore #endif /* BUG_4010796 */
498bdb9230aSGarrett D'Amore
499bdb9230aSGarrett D'Amore /*
500bdb9230aSGarrett D'Amore * attach(9E) -- Attach a device to the system
501bdb9230aSGarrett D'Amore *
502bdb9230aSGarrett D'Amore * Called once for each board successfully probed.
503bdb9230aSGarrett D'Amore */
504bdb9230aSGarrett D'Amore static int
dnet_attach(dev_info_t * devinfo,ddi_attach_cmd_t cmd)50598e8d175SSteven Stallion dnet_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
506bdb9230aSGarrett D'Amore {
507bdb9230aSGarrett D'Amore uint16_t revid;
508bdb9230aSGarrett D'Amore struct dnetinstance *dnetp; /* Our private device info */
50998e8d175SSteven Stallion mac_register_t *macp;
510bdb9230aSGarrett D'Amore uchar_t vendor_info[SROM_SIZE];
511bdb9230aSGarrett D'Amore uint32_t csr;
512bdb9230aSGarrett D'Amore uint16_t deviceid;
513bdb9230aSGarrett D'Amore ddi_acc_handle_t handle;
514bdb9230aSGarrett D'Amore int secondary;
515bdb9230aSGarrett D'Amore
516bdb9230aSGarrett D'Amore #define DNET_PCI_RNUMBER 1
517bdb9230aSGarrett D'Amore
518bdb9230aSGarrett D'Amore switch (cmd) {
519bdb9230aSGarrett D'Amore case DDI_ATTACH:
520bdb9230aSGarrett D'Amore break;
521bdb9230aSGarrett D'Amore
522bdb9230aSGarrett D'Amore case DDI_RESUME:
52398e8d175SSteven Stallion /* Get the driver private (dnetinstance) structure */
52498e8d175SSteven Stallion dnetp = ddi_get_driver_private(devinfo);
525bdb9230aSGarrett D'Amore
526bdb9230aSGarrett D'Amore mutex_enter(&dnetp->intrlock);
527bdb9230aSGarrett D'Amore mutex_enter(&dnetp->txlock);
52898e8d175SSteven Stallion dnet_reset_board(dnetp);
52998e8d175SSteven Stallion dnet_init_board(dnetp);
530bdb9230aSGarrett D'Amore dnetp->suspended = B_FALSE;
531bdb9230aSGarrett D'Amore
532bdb9230aSGarrett D'Amore if (dnetp->running) {
53398e8d175SSteven Stallion dnetp->need_tx_update = B_FALSE;
534bdb9230aSGarrett D'Amore mutex_exit(&dnetp->txlock);
53598e8d175SSteven Stallion (void) dnet_start(dnetp);
536bdb9230aSGarrett D'Amore mutex_exit(&dnetp->intrlock);
53798e8d175SSteven Stallion mac_tx_update(dnetp->mac_handle);
538bdb9230aSGarrett D'Amore } else {
539bdb9230aSGarrett D'Amore mutex_exit(&dnetp->txlock);
540bdb9230aSGarrett D'Amore mutex_exit(&dnetp->intrlock);
541bdb9230aSGarrett D'Amore }
542bdb9230aSGarrett D'Amore return (DDI_SUCCESS);
543bdb9230aSGarrett D'Amore default:
544bdb9230aSGarrett D'Amore return (DDI_FAILURE);
545bdb9230aSGarrett D'Amore }
54698e8d175SSteven Stallion
547bdb9230aSGarrett D'Amore if (pci_config_setup(devinfo, &handle) != DDI_SUCCESS)
548bdb9230aSGarrett D'Amore return (DDI_FAILURE);
549bdb9230aSGarrett D'Amore
550bdb9230aSGarrett D'Amore deviceid = pci_config_get16(handle, PCI_CONF_DEVID);
551bdb9230aSGarrett D'Amore switch (deviceid) {
552bdb9230aSGarrett D'Amore case DEVICE_ID_21040:
553bdb9230aSGarrett D'Amore case DEVICE_ID_21041:
554bdb9230aSGarrett D'Amore case DEVICE_ID_21140:
555bdb9230aSGarrett D'Amore case DEVICE_ID_21143: /* And 142 */
556bdb9230aSGarrett D'Amore break;
557bdb9230aSGarrett D'Amore default:
558bdb9230aSGarrett D'Amore pci_config_teardown(&handle);
559bdb9230aSGarrett D'Amore return (DDI_FAILURE);
560bdb9230aSGarrett D'Amore }
561bdb9230aSGarrett D'Amore
562bdb9230aSGarrett D'Amore /*
563bdb9230aSGarrett D'Amore * Turn on Master Enable and IO Enable bits.
564bdb9230aSGarrett D'Amore */
565bdb9230aSGarrett D'Amore csr = pci_config_get32(handle, PCI_CONF_COMM);
566bdb9230aSGarrett D'Amore pci_config_put32(handle, PCI_CONF_COMM, (csr |PCI_COMM_ME|PCI_COMM_IO));
567bdb9230aSGarrett D'Amore
568bdb9230aSGarrett D'Amore /* Make sure the device is not asleep */
569bdb9230aSGarrett D'Amore csr = pci_config_get32(handle, PCI_DNET_CONF_CFDD);
570bdb9230aSGarrett D'Amore pci_config_put32(handle, PCI_DNET_CONF_CFDD,
571bdb9230aSGarrett D'Amore csr & ~(CFDD_SLEEP|CFDD_SNOOZE));
572bdb9230aSGarrett D'Amore
573bdb9230aSGarrett D'Amore revid = pci_config_get8(handle, PCI_CONF_REVID);
574bdb9230aSGarrett D'Amore pci_config_teardown(&handle);
575bdb9230aSGarrett D'Amore
57698e8d175SSteven Stallion dnetp = kmem_zalloc(sizeof (struct dnetinstance), KM_SLEEP);
57798e8d175SSteven Stallion ddi_set_driver_private(devinfo, dnetp);
578bdb9230aSGarrett D'Amore
579bdb9230aSGarrett D'Amore /* Now map I/O register */
580bdb9230aSGarrett D'Amore if (ddi_regs_map_setup(devinfo, DNET_PCI_RNUMBER, &dnetp->io_reg,
581bdb9230aSGarrett D'Amore 0, 0, &accattr, &dnetp->io_handle) != DDI_SUCCESS) {
582bdb9230aSGarrett D'Amore kmem_free(dnetp, sizeof (struct dnetinstance));
583bdb9230aSGarrett D'Amore return (DDI_FAILURE);
584bdb9230aSGarrett D'Amore }
585bdb9230aSGarrett D'Amore
586bdb9230aSGarrett D'Amore dnetp->devinfo = devinfo;
587bdb9230aSGarrett D'Amore dnetp->board_type = deviceid;
588bdb9230aSGarrett D'Amore
589bdb9230aSGarrett D'Amore /*
590bdb9230aSGarrett D'Amore * Get the iblock cookie with which to initialize the mutexes.
591bdb9230aSGarrett D'Amore */
59298e8d175SSteven Stallion if (ddi_get_iblock_cookie(devinfo, 0, &dnetp->icookie)
593bdb9230aSGarrett D'Amore != DDI_SUCCESS)
594bdb9230aSGarrett D'Amore goto fail;
595bdb9230aSGarrett D'Amore
596bdb9230aSGarrett D'Amore /*
597bdb9230aSGarrett D'Amore * Initialize mutex's for this device.
598bdb9230aSGarrett D'Amore * Do this before registering the interrupt handler to avoid
599bdb9230aSGarrett D'Amore * condition where interrupt handler can try using uninitialized
600bdb9230aSGarrett D'Amore * mutex.
601bdb9230aSGarrett D'Amore * Lock ordering rules: always lock intrlock first before
602bdb9230aSGarrett D'Amore * txlock if both are required.
603bdb9230aSGarrett D'Amore */
60498e8d175SSteven Stallion mutex_init(&dnetp->txlock, NULL, MUTEX_DRIVER, dnetp->icookie);
60598e8d175SSteven Stallion mutex_init(&dnetp->intrlock, NULL, MUTEX_DRIVER, dnetp->icookie);
606bdb9230aSGarrett D'Amore
607bdb9230aSGarrett D'Amore /*
608bdb9230aSGarrett D'Amore * Get the BNC/TP indicator from the conf file for 21040
609bdb9230aSGarrett D'Amore */
610bdb9230aSGarrett D'Amore dnetp->bnc_indicator =
611bdb9230aSGarrett D'Amore ddi_getprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
612bdb9230aSGarrett D'Amore "bncaui", -1);
613bdb9230aSGarrett D'Amore
614bdb9230aSGarrett D'Amore /*
615bdb9230aSGarrett D'Amore * For 21140 check the data rate set in the conf file. Default is
616bdb9230aSGarrett D'Amore * 100Mb/s. Disallow connections at settings that would conflict
617bdb9230aSGarrett D'Amore * with what's in the conf file
618bdb9230aSGarrett D'Amore */
619bdb9230aSGarrett D'Amore dnetp->speed =
620bdb9230aSGarrett D'Amore ddi_getprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
621bdb9230aSGarrett D'Amore speed_propname, 0);
622bdb9230aSGarrett D'Amore dnetp->full_duplex =
623bdb9230aSGarrett D'Amore ddi_getprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
624bdb9230aSGarrett D'Amore duplex_propname, -1);
625bdb9230aSGarrett D'Amore
626bdb9230aSGarrett D'Amore if (dnetp->speed == 100) {
627bdb9230aSGarrett D'Amore dnetp->disallowed_media |= (1UL<<MEDIA_TP) | (1UL<<MEDIA_TP_FD);
628bdb9230aSGarrett D'Amore } else if (dnetp->speed == 10) {
629bdb9230aSGarrett D'Amore dnetp->disallowed_media |=
630bdb9230aSGarrett D'Amore (1UL<<MEDIA_SYM_SCR) | (1UL<<MEDIA_SYM_SCR_FD);
631bdb9230aSGarrett D'Amore }
632bdb9230aSGarrett D'Amore
633bdb9230aSGarrett D'Amore if (dnetp->full_duplex == 1) {
634bdb9230aSGarrett D'Amore dnetp->disallowed_media |=
635bdb9230aSGarrett D'Amore (1UL<<MEDIA_TP) | (1UL<<MEDIA_SYM_SCR);
636bdb9230aSGarrett D'Amore } else if (dnetp->full_duplex == 0) {
637bdb9230aSGarrett D'Amore dnetp->disallowed_media |=
638bdb9230aSGarrett D'Amore (1UL<<MEDIA_TP_FD) | (1UL<<MEDIA_SYM_SCR_FD);
639bdb9230aSGarrett D'Amore }
640bdb9230aSGarrett D'Amore
641bdb9230aSGarrett D'Amore if (dnetp->bnc_indicator == 0) /* Disable BNC and AUI media */
642bdb9230aSGarrett D'Amore dnetp->disallowed_media |= (1UL<<MEDIA_BNC) | (1UL<<MEDIA_AUI);
643bdb9230aSGarrett D'Amore else if (dnetp->bnc_indicator == 1) /* Force BNC only */
644bdb9230aSGarrett D'Amore dnetp->disallowed_media = (uint32_t)~(1U<<MEDIA_BNC);
645bdb9230aSGarrett D'Amore else if (dnetp->bnc_indicator == 2) /* Force AUI only */
646bdb9230aSGarrett D'Amore dnetp->disallowed_media = (uint32_t)~(1U<<MEDIA_AUI);
647bdb9230aSGarrett D'Amore
64898e8d175SSteven Stallion dnet_reset_board(dnetp);
649bdb9230aSGarrett D'Amore
650bdb9230aSGarrett D'Amore secondary = dnet_read_srom(devinfo, dnetp->board_type, dnetp->io_handle,
651bdb9230aSGarrett D'Amore dnetp->io_reg, vendor_info, sizeof (vendor_info));
652bdb9230aSGarrett D'Amore
653bdb9230aSGarrett D'Amore if (secondary == -1) /* ASSERT (vendor_info not big enough) */
654bdb9230aSGarrett D'Amore goto fail1;
655bdb9230aSGarrett D'Amore
656bdb9230aSGarrett D'Amore dnet_parse_srom(dnetp, &dnetp->sr, vendor_info);
657bdb9230aSGarrett D'Amore
658bdb9230aSGarrett D'Amore if (ddi_getprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
659bdb9230aSGarrett D'Amore printsrom_propname, 0))
660bdb9230aSGarrett D'Amore dnet_print_srom(&dnetp->sr);
661bdb9230aSGarrett D'Amore
662bdb9230aSGarrett D'Amore dnetp->sr.netaddr[ETHERADDRL-1] += secondary; /* unique ether addr */
663bdb9230aSGarrett D'Amore
664bdb9230aSGarrett D'Amore BCOPY((caddr_t)dnetp->sr.netaddr,
665bdb9230aSGarrett D'Amore (caddr_t)dnetp->vendor_addr, ETHERADDRL);
666bdb9230aSGarrett D'Amore
667bdb9230aSGarrett D'Amore BCOPY((caddr_t)dnetp->sr.netaddr,
668bdb9230aSGarrett D'Amore (caddr_t)dnetp->curr_macaddr, ETHERADDRL);
669bdb9230aSGarrett D'Amore
670bdb9230aSGarrett D'Amore /*
671bdb9230aSGarrett D'Amore * determine whether to implement workaround from DEC
672bdb9230aSGarrett D'Amore * for DMA overrun errata.
673bdb9230aSGarrett D'Amore */
674bdb9230aSGarrett D'Amore dnetp->overrun_workaround =
675bdb9230aSGarrett D'Amore ((dnetp->board_type == DEVICE_ID_21140 && revid >= 0x20) ||
676bdb9230aSGarrett D'Amore (dnetp->board_type == DEVICE_ID_21143 && revid <= 0x30)) ? 1 : 0;
677bdb9230aSGarrett D'Amore
678bdb9230aSGarrett D'Amore dnetp->overrun_workaround =
679bdb9230aSGarrett D'Amore ddi_getprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
680bdb9230aSGarrett D'Amore ofloprob_propname, dnetp->overrun_workaround);
681bdb9230aSGarrett D'Amore
682bdb9230aSGarrett D'Amore /*
683bdb9230aSGarrett D'Amore * Add the interrupt handler if dnet_hack_interrupts() returns 0.
684bdb9230aSGarrett D'Amore * Otherwise dnet_hack_interrupts() itself adds the handler.
685bdb9230aSGarrett D'Amore */
68698e8d175SSteven Stallion if (!dnet_hack_interrupts(dnetp, secondary)) {
687bdb9230aSGarrett D'Amore (void) ddi_add_intr(devinfo, 0, NULL,
68898e8d175SSteven Stallion NULL, dnet_intr, (caddr_t)dnetp);
689bdb9230aSGarrett D'Amore }
690bdb9230aSGarrett D'Amore
691bdb9230aSGarrett D'Amore dnetp->max_tx_desc = max_tx_desc;
692bdb9230aSGarrett D'Amore dnetp->max_rx_desc = max_rx_desc_21040;
693bdb9230aSGarrett D'Amore if (dnetp->board_type != DEVICE_ID_21040 &&
694bdb9230aSGarrett D'Amore dnetp->board_type != DEVICE_ID_21041 &&
695bdb9230aSGarrett D'Amore dnetp->speed != 10)
696bdb9230aSGarrett D'Amore dnetp->max_rx_desc = max_rx_desc_21140;
697bdb9230aSGarrett D'Amore
698bdb9230aSGarrett D'Amore /* Allocate the TX and RX descriptors/buffers. */
69998e8d175SSteven Stallion if (dnet_alloc_bufs(dnetp) == FAILURE) {
700bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "DNET: Not enough DMA memory for buffers.");
701bdb9230aSGarrett D'Amore goto fail2;
702bdb9230aSGarrett D'Amore }
703bdb9230aSGarrett D'Amore
704bdb9230aSGarrett D'Amore /*
70598e8d175SSteven Stallion * Register ourselves with the GLDv3 interface
706bdb9230aSGarrett D'Amore */
70798e8d175SSteven Stallion if ((macp = mac_alloc(MAC_VERSION)) == NULL)
70898e8d175SSteven Stallion goto fail2;
709bdb9230aSGarrett D'Amore
71098e8d175SSteven Stallion macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
71198e8d175SSteven Stallion macp->m_driver = dnetp;
71298e8d175SSteven Stallion macp->m_dip = devinfo;
71398e8d175SSteven Stallion macp->m_src_addr = dnetp->curr_macaddr;
71498e8d175SSteven Stallion macp->m_callbacks = &dnet_m_callbacks;
71598e8d175SSteven Stallion macp->m_min_sdu = 0;
71698e8d175SSteven Stallion macp->m_max_sdu = ETHERMTU;
71798e8d175SSteven Stallion macp->m_margin = VLAN_TAGSZ;
71898e8d175SSteven Stallion
71998e8d175SSteven Stallion if (mac_register(macp, &dnetp->mac_handle) == 0) {
72098e8d175SSteven Stallion mac_free(macp);
72198e8d175SSteven Stallion
722bdb9230aSGarrett D'Amore mutex_enter(&dnetp->intrlock);
72398e8d175SSteven Stallion
724bdb9230aSGarrett D'Amore dnetp->phyaddr = -1;
725bdb9230aSGarrett D'Amore if (dnetp->board_type == DEVICE_ID_21140 ||
726bdb9230aSGarrett D'Amore dnetp->board_type == DEVICE_ID_21143)
72798e8d175SSteven Stallion do_phy(dnetp); /* Initialize the PHY, if any */
72898e8d175SSteven Stallion find_active_media(dnetp);
729bdb9230aSGarrett D'Amore
730bdb9230aSGarrett D'Amore /* if the chosen media is non-MII, stop the port monitor */
731bdb9230aSGarrett D'Amore if (dnetp->selected_media_block->media_code != MEDIA_MII &&
732bdb9230aSGarrett D'Amore dnetp->mii != NULL) {
733bdb9230aSGarrett D'Amore mii_destroy(dnetp->mii);
734bdb9230aSGarrett D'Amore dnetp->mii = NULL;
735bdb9230aSGarrett D'Amore dnetp->phyaddr = -1;
736bdb9230aSGarrett D'Amore }
737bdb9230aSGarrett D'Amore
738bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
739bdb9230aSGarrett D'Amore if (dnetdebug & DNETSENSE)
740bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "dnet: link configured : %s",
741bdb9230aSGarrett D'Amore media_str[dnetp->selected_media_block->media_code]);
742bdb9230aSGarrett D'Amore #endif
743bdb9230aSGarrett D'Amore bzero(dnetp->setup_buf_vaddr, SETUPBUF_SIZE);
74498e8d175SSteven Stallion
74598e8d175SSteven Stallion dnet_reset_board(dnetp);
74698e8d175SSteven Stallion dnet_init_board(dnetp);
74798e8d175SSteven Stallion
748bdb9230aSGarrett D'Amore mutex_exit(&dnetp->intrlock);
74998e8d175SSteven Stallion
75098e8d175SSteven Stallion (void) dnet_m_unicst(dnetp, dnetp->curr_macaddr);
75198e8d175SSteven Stallion (void) dnet_m_multicst(dnetp, B_TRUE, dnet_broadcastaddr);
75298e8d175SSteven Stallion
753bdb9230aSGarrett D'Amore return (DDI_SUCCESS);
754bdb9230aSGarrett D'Amore }
75598e8d175SSteven Stallion
75698e8d175SSteven Stallion mac_free(macp);
757bdb9230aSGarrett D'Amore fail2:
758bdb9230aSGarrett D'Amore /* XXX function return value ignored */
759bdb9230aSGarrett D'Amore /*
760bdb9230aSGarrett D'Amore * dnet_detach_hacked_interrupt() will remove
761bdb9230aSGarrett D'Amore * interrupt for the non-hacked case also.
762bdb9230aSGarrett D'Amore */
763bdb9230aSGarrett D'Amore (void) dnet_detach_hacked_interrupt(devinfo);
76498e8d175SSteven Stallion dnet_free_bufs(dnetp);
765bdb9230aSGarrett D'Amore fail1:
766bdb9230aSGarrett D'Amore mutex_destroy(&dnetp->txlock);
767bdb9230aSGarrett D'Amore mutex_destroy(&dnetp->intrlock);
768bdb9230aSGarrett D'Amore fail:
769bdb9230aSGarrett D'Amore ddi_regs_map_free(&dnetp->io_handle);
770bdb9230aSGarrett D'Amore kmem_free(dnetp, sizeof (struct dnetinstance));
771bdb9230aSGarrett D'Amore return (DDI_FAILURE);
772bdb9230aSGarrett D'Amore }
773bdb9230aSGarrett D'Amore
774bdb9230aSGarrett D'Amore /*
775bdb9230aSGarrett D'Amore * detach(9E) -- Detach a device from the system
776bdb9230aSGarrett D'Amore */
777bdb9230aSGarrett D'Amore static int
dnet_detach(dev_info_t * devinfo,ddi_detach_cmd_t cmd)77898e8d175SSteven Stallion dnet_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
779bdb9230aSGarrett D'Amore {
780bdb9230aSGarrett D'Amore int32_t rc;
781bdb9230aSGarrett D'Amore struct dnetinstance *dnetp; /* Our private device info */
782bdb9230aSGarrett D'Amore int32_t proplen;
783bdb9230aSGarrett D'Amore
78498e8d175SSteven Stallion /* Get the driver private (dnetinstance) structure */
78598e8d175SSteven Stallion dnetp = ddi_get_driver_private(devinfo);
786bdb9230aSGarrett D'Amore
787bdb9230aSGarrett D'Amore switch (cmd) {
788bdb9230aSGarrett D'Amore case DDI_DETACH:
789bdb9230aSGarrett D'Amore break;
790bdb9230aSGarrett D'Amore
791bdb9230aSGarrett D'Amore case DDI_SUSPEND:
792bdb9230aSGarrett D'Amore /*
793bdb9230aSGarrett D'Amore * NB: dnetp->suspended can only be modified (marked true)
794bdb9230aSGarrett D'Amore * if both intrlock and txlock are held. This keeps both
795bdb9230aSGarrett D'Amore * tx and rx code paths excluded.
796bdb9230aSGarrett D'Amore */
797bdb9230aSGarrett D'Amore mutex_enter(&dnetp->intrlock);
798bdb9230aSGarrett D'Amore mutex_enter(&dnetp->txlock);
799bdb9230aSGarrett D'Amore dnetp->suspended = B_TRUE;
80098e8d175SSteven Stallion dnet_reset_board(dnetp);
801bdb9230aSGarrett D'Amore mutex_exit(&dnetp->txlock);
802bdb9230aSGarrett D'Amore mutex_exit(&dnetp->intrlock);
803bdb9230aSGarrett D'Amore return (DDI_SUCCESS);
804bdb9230aSGarrett D'Amore
805bdb9230aSGarrett D'Amore default:
806bdb9230aSGarrett D'Amore return (DDI_FAILURE);
807bdb9230aSGarrett D'Amore }
808bdb9230aSGarrett D'Amore
809bdb9230aSGarrett D'Amore /*
81098e8d175SSteven Stallion * Unregister ourselves from the GLDv3 interface
811bdb9230aSGarrett D'Amore */
81298e8d175SSteven Stallion if (mac_unregister(dnetp->mac_handle) != 0)
813bdb9230aSGarrett D'Amore return (DDI_FAILURE);
814bdb9230aSGarrett D'Amore
815bdb9230aSGarrett D'Amore /* stop the board if it is running */
81698e8d175SSteven Stallion dnet_reset_board(dnetp);
817bdb9230aSGarrett D'Amore
818bdb9230aSGarrett D'Amore if ((rc = dnet_detach_hacked_interrupt(devinfo)) != DDI_SUCCESS)
819bdb9230aSGarrett D'Amore return (rc);
820bdb9230aSGarrett D'Amore
821bdb9230aSGarrett D'Amore if (dnetp->mii != NULL)
822bdb9230aSGarrett D'Amore mii_destroy(dnetp->mii);
823bdb9230aSGarrett D'Amore
824bdb9230aSGarrett D'Amore /* Free leaf information */
825bdb9230aSGarrett D'Amore set_leaf(&dnetp->sr, NULL);
826bdb9230aSGarrett D'Amore
827bdb9230aSGarrett D'Amore ddi_regs_map_free(&dnetp->io_handle);
82898e8d175SSteven Stallion dnet_free_bufs(dnetp);
829bdb9230aSGarrett D'Amore mutex_destroy(&dnetp->txlock);
830bdb9230aSGarrett D'Amore mutex_destroy(&dnetp->intrlock);
831bdb9230aSGarrett D'Amore kmem_free(dnetp, sizeof (struct dnetinstance));
832bdb9230aSGarrett D'Amore
833bdb9230aSGarrett D'Amore #ifdef BUG_4010796
834bdb9230aSGarrett D'Amore if (ddi_getproplen(DDI_DEV_T_ANY, devinfo, 0,
835bdb9230aSGarrett D'Amore "DNET_HACK", &proplen) != DDI_PROP_SUCCESS)
836bdb9230aSGarrett D'Amore return (DDI_SUCCESS);
837bdb9230aSGarrett D'Amore
838bdb9230aSGarrett D'Amore /*
839bdb9230aSGarrett D'Amore * We must remove the properties we added, because if we leave
840bdb9230aSGarrett D'Amore * them in the devinfo nodes and the driver is unloaded, when
841bdb9230aSGarrett D'Amore * the driver is reloaded the info will still be there, causing
842bdb9230aSGarrett D'Amore * nodes which had returned PROBE_PARTIAL the first time to
843bdb9230aSGarrett D'Amore * instead return PROBE_SUCCESS, in turn causing the nodes to be
844bdb9230aSGarrett D'Amore * attached in a different order, causing their PPA numbers to
845bdb9230aSGarrett D'Amore * be different the second time around, which is undesirable.
846bdb9230aSGarrett D'Amore */
847bdb9230aSGarrett D'Amore (void) ddi_prop_remove(DDI_DEV_T_NONE, devinfo, "DNET_HACK");
848bdb9230aSGarrett D'Amore (void) ddi_prop_remove(DDI_DEV_T_NONE, ddi_get_parent(devinfo),
849bdb9230aSGarrett D'Amore "DNET_SROM");
850bdb9230aSGarrett D'Amore (void) ddi_prop_remove(DDI_DEV_T_NONE, ddi_get_parent(devinfo),
851bdb9230aSGarrett D'Amore "DNET_DEVNUM");
852bdb9230aSGarrett D'Amore #endif
853bdb9230aSGarrett D'Amore
854bdb9230aSGarrett D'Amore return (DDI_SUCCESS);
855bdb9230aSGarrett D'Amore }
856bdb9230aSGarrett D'Amore
85798e8d175SSteven Stallion int
dnet_quiesce(dev_info_t * dip)85898e8d175SSteven Stallion dnet_quiesce(dev_info_t *dip)
859bdb9230aSGarrett D'Amore {
86098e8d175SSteven Stallion struct dnetinstance *dnetp = ddi_get_driver_private(dip);
861bdb9230aSGarrett D'Amore
862bdb9230aSGarrett D'Amore /*
86398e8d175SSteven Stallion * Reset chip (disables interrupts).
864bdb9230aSGarrett D'Amore */
86598e8d175SSteven Stallion ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, INT_MASK_REG), 0);
86698e8d175SSteven Stallion ddi_put32(dnetp->io_handle,
86798e8d175SSteven Stallion REG32(dnetp->io_reg, BUS_MODE_REG), SW_RESET);
868bdb9230aSGarrett D'Amore
86998e8d175SSteven Stallion return (DDI_SUCCESS);
870bdb9230aSGarrett D'Amore }
871bdb9230aSGarrett D'Amore
872bdb9230aSGarrett D'Amore static void
dnet_reset_board(struct dnetinstance * dnetp)87398e8d175SSteven Stallion dnet_reset_board(struct dnetinstance *dnetp)
874bdb9230aSGarrett D'Amore {
875bdb9230aSGarrett D'Amore uint32_t val;
876bdb9230aSGarrett D'Amore
877bdb9230aSGarrett D'Amore /*
878bdb9230aSGarrett D'Amore * before initializing the dnet should be in STOP state
879bdb9230aSGarrett D'Amore */
880bdb9230aSGarrett D'Amore val = ddi_get32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG));
881bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG),
882bdb9230aSGarrett D'Amore val & ~(START_TRANSMIT | START_RECEIVE));
883bdb9230aSGarrett D'Amore
884bdb9230aSGarrett D'Amore /*
885bdb9230aSGarrett D'Amore * Reset the chip
886bdb9230aSGarrett D'Amore */
887bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, INT_MASK_REG), 0);
888bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle,
889bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, BUS_MODE_REG), SW_RESET);
890bdb9230aSGarrett D'Amore drv_usecwait(5);
891bdb9230aSGarrett D'Amore }
892bdb9230aSGarrett D'Amore
893bdb9230aSGarrett D'Amore /*
894bdb9230aSGarrett D'Amore * dnet_init_board() -- initialize the specified network board short of
895bdb9230aSGarrett D'Amore * actually starting the board. Call after dnet_reset_board().
896bdb9230aSGarrett D'Amore * called with intrlock held.
897bdb9230aSGarrett D'Amore */
898bdb9230aSGarrett D'Amore static void
dnet_init_board(struct dnetinstance * dnetp)89998e8d175SSteven Stallion dnet_init_board(struct dnetinstance *dnetp)
900bdb9230aSGarrett D'Amore {
90198e8d175SSteven Stallion set_opr(dnetp);
90298e8d175SSteven Stallion set_gpr(dnetp);
90398e8d175SSteven Stallion set_sia(dnetp);
90498e8d175SSteven Stallion dnet_chip_init(dnetp);
905bdb9230aSGarrett D'Amore }
906bdb9230aSGarrett D'Amore
907bdb9230aSGarrett D'Amore /* dnet_chip_init() - called with intrlock held */
908bdb9230aSGarrett D'Amore static void
dnet_chip_init(struct dnetinstance * dnetp)90998e8d175SSteven Stallion dnet_chip_init(struct dnetinstance *dnetp)
910bdb9230aSGarrett D'Amore {
911bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, BUS_MODE_REG),
912bdb9230aSGarrett D'Amore CACHE_ALIGN | BURST_SIZE); /* CSR0 */
913bdb9230aSGarrett D'Amore
914bdb9230aSGarrett D'Amore /*
915bdb9230aSGarrett D'Amore * Initialize the TX and RX descriptors/buffers
916bdb9230aSGarrett D'Amore */
91798e8d175SSteven Stallion dnet_init_txrx_bufs(dnetp);
918bdb9230aSGarrett D'Amore
919bdb9230aSGarrett D'Amore /*
920bdb9230aSGarrett D'Amore * Set the base address of the Rx descriptor list in CSR3
921bdb9230aSGarrett D'Amore */
922bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, RX_BASE_ADDR_REG),
923bdb9230aSGarrett D'Amore dnetp->rx_desc_paddr);
924bdb9230aSGarrett D'Amore
925bdb9230aSGarrett D'Amore /*
926bdb9230aSGarrett D'Amore * Set the base address of the Tx descrptor list in CSR4
927bdb9230aSGarrett D'Amore */
928bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, TX_BASE_ADDR_REG),
929bdb9230aSGarrett D'Amore dnetp->tx_desc_paddr);
930bdb9230aSGarrett D'Amore
931bdb9230aSGarrett D'Amore dnetp->tx_current_desc = dnetp->rx_current_desc = 0;
932bdb9230aSGarrett D'Amore dnetp->transmitted_desc = 0;
933bdb9230aSGarrett D'Amore dnetp->free_desc = dnetp->max_tx_desc;
93498e8d175SSteven Stallion enable_interrupts(dnetp);
935bdb9230aSGarrett D'Amore }
936bdb9230aSGarrett D'Amore
937bdb9230aSGarrett D'Amore /*
938bdb9230aSGarrett D'Amore * dnet_start() -- start the board receiving and allow transmits.
939bdb9230aSGarrett D'Amore * Called with intrlock held.
940bdb9230aSGarrett D'Amore */
941bdb9230aSGarrett D'Amore static int
dnet_start(struct dnetinstance * dnetp)94298e8d175SSteven Stallion dnet_start(struct dnetinstance *dnetp)
943bdb9230aSGarrett D'Amore {
944bdb9230aSGarrett D'Amore uint32_t val;
945bdb9230aSGarrett D'Amore
946bdb9230aSGarrett D'Amore ASSERT(MUTEX_HELD(&dnetp->intrlock));
947bdb9230aSGarrett D'Amore /*
948bdb9230aSGarrett D'Amore * start the board and enable receiving
949bdb9230aSGarrett D'Amore */
950bdb9230aSGarrett D'Amore val = ddi_get32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG));
951bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG),
952bdb9230aSGarrett D'Amore val | START_TRANSMIT);
95398e8d175SSteven Stallion (void) dnet_set_addr(dnetp);
954bdb9230aSGarrett D'Amore val = ddi_get32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG));
955bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG),
956bdb9230aSGarrett D'Amore val | START_RECEIVE);
95798e8d175SSteven Stallion enable_interrupts(dnetp);
958bdb9230aSGarrett D'Amore return (0);
959bdb9230aSGarrett D'Amore }
960bdb9230aSGarrett D'Amore
961bdb9230aSGarrett D'Amore static int
dnet_m_start(void * arg)96298e8d175SSteven Stallion dnet_m_start(void *arg)
963bdb9230aSGarrett D'Amore {
96498e8d175SSteven Stallion struct dnetinstance *dnetp = arg;
965bdb9230aSGarrett D'Amore
966bdb9230aSGarrett D'Amore mutex_enter(&dnetp->intrlock);
967bdb9230aSGarrett D'Amore dnetp->running = B_TRUE;
968bdb9230aSGarrett D'Amore /*
969bdb9230aSGarrett D'Amore * start the board and enable receiving
970bdb9230aSGarrett D'Amore */
971bdb9230aSGarrett D'Amore if (!dnetp->suspended)
97298e8d175SSteven Stallion (void) dnet_start(dnetp);
973bdb9230aSGarrett D'Amore mutex_exit(&dnetp->intrlock);
974bdb9230aSGarrett D'Amore return (0);
975bdb9230aSGarrett D'Amore }
976bdb9230aSGarrett D'Amore
97798e8d175SSteven Stallion static void
dnet_m_stop(void * arg)97898e8d175SSteven Stallion dnet_m_stop(void *arg)
979bdb9230aSGarrett D'Amore {
98098e8d175SSteven Stallion struct dnetinstance *dnetp = arg;
981bdb9230aSGarrett D'Amore uint32_t val;
982bdb9230aSGarrett D'Amore
983bdb9230aSGarrett D'Amore /*
984bdb9230aSGarrett D'Amore * stop the board and disable transmit/receive
985bdb9230aSGarrett D'Amore */
986bdb9230aSGarrett D'Amore mutex_enter(&dnetp->intrlock);
987bdb9230aSGarrett D'Amore if (!dnetp->suspended) {
988bdb9230aSGarrett D'Amore val = ddi_get32(dnetp->io_handle,
989bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, OPN_MODE_REG));
990bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG),
991bdb9230aSGarrett D'Amore val & ~(START_TRANSMIT | START_RECEIVE));
992bdb9230aSGarrett D'Amore }
99332607e28SSteven Stallion mac_link_update(dnetp->mac_handle, LINK_STATE_UNKNOWN);
994bdb9230aSGarrett D'Amore dnetp->running = B_FALSE;
995bdb9230aSGarrett D'Amore mutex_exit(&dnetp->intrlock);
996bdb9230aSGarrett D'Amore }
997bdb9230aSGarrett D'Amore
998bdb9230aSGarrett D'Amore /*
999bdb9230aSGarrett D'Amore * dnet_set_addr() -- set the physical network address on the board
1000bdb9230aSGarrett D'Amore * Called with intrlock held.
1001bdb9230aSGarrett D'Amore */
1002bdb9230aSGarrett D'Amore static int
dnet_set_addr(struct dnetinstance * dnetp)100398e8d175SSteven Stallion dnet_set_addr(struct dnetinstance *dnetp)
1004bdb9230aSGarrett D'Amore {
1005bdb9230aSGarrett D'Amore struct tx_desc_type *desc;
1006bdb9230aSGarrett D'Amore int current_desc;
1007bdb9230aSGarrett D'Amore uint32_t val;
1008bdb9230aSGarrett D'Amore
1009bdb9230aSGarrett D'Amore ASSERT(MUTEX_HELD(&dnetp->intrlock));
1010bdb9230aSGarrett D'Amore
1011bdb9230aSGarrett D'Amore val = ddi_get32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG));
1012bdb9230aSGarrett D'Amore if (!(val & START_TRANSMIT))
1013bdb9230aSGarrett D'Amore return (0);
1014bdb9230aSGarrett D'Amore
1015bdb9230aSGarrett D'Amore current_desc = dnetp->tx_current_desc;
1016bdb9230aSGarrett D'Amore desc = &dnetp->tx_desc[current_desc];
1017bdb9230aSGarrett D'Amore
1018bdb9230aSGarrett D'Amore mutex_enter(&dnetp->txlock);
1019bdb9230aSGarrett D'Amore dnetp->need_saddr = 0;
1020bdb9230aSGarrett D'Amore mutex_exit(&dnetp->txlock);
1021bdb9230aSGarrett D'Amore
102298e8d175SSteven Stallion if ((alloc_descriptor(dnetp)) == FAILURE) {
1023bdb9230aSGarrett D'Amore mutex_enter(&dnetp->txlock);
1024bdb9230aSGarrett D'Amore dnetp->need_saddr = 1;
1025bdb9230aSGarrett D'Amore mutex_exit(&dnetp->txlock);
1026bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
1027bdb9230aSGarrett D'Amore if (dnetdebug & DNETTRACE)
1028bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "DNET saddr:alloc descriptor failure");
1029bdb9230aSGarrett D'Amore #endif
1030bdb9230aSGarrett D'Amore return (0);
1031bdb9230aSGarrett D'Amore }
1032bdb9230aSGarrett D'Amore
1033bdb9230aSGarrett D'Amore desc->buffer1 = dnetp->setup_buf_paddr;
1034bdb9230aSGarrett D'Amore desc->buffer2 = 0;
1035bdb9230aSGarrett D'Amore desc->desc1.buffer_size1 = SETUPBUF_SIZE;
1036bdb9230aSGarrett D'Amore desc->desc1.buffer_size2 = 0;
1037bdb9230aSGarrett D'Amore desc->desc1.setup_packet = 1;
1038bdb9230aSGarrett D'Amore desc->desc1.first_desc = 0;
1039bdb9230aSGarrett D'Amore desc->desc1.last_desc = 0;
1040bdb9230aSGarrett D'Amore desc->desc1.filter_type0 = 1;
1041bdb9230aSGarrett D'Amore desc->desc1.filter_type1 = 1;
1042bdb9230aSGarrett D'Amore desc->desc1.int_on_comp = 1;
1043bdb9230aSGarrett D'Amore
1044bdb9230aSGarrett D'Amore desc->desc0.own = 1;
1045bdb9230aSGarrett D'Amore ddi_put8(dnetp->io_handle, REG8(dnetp->io_reg, TX_POLL_REG),
1046bdb9230aSGarrett D'Amore TX_POLL_DEMAND);
1047bdb9230aSGarrett D'Amore return (0);
1048bdb9230aSGarrett D'Amore }
1049bdb9230aSGarrett D'Amore
1050bdb9230aSGarrett D'Amore static int
dnet_m_unicst(void * arg,const uint8_t * macaddr)105198e8d175SSteven Stallion dnet_m_unicst(void *arg, const uint8_t *macaddr)
1052bdb9230aSGarrett D'Amore {
105398e8d175SSteven Stallion struct dnetinstance *dnetp = arg;
1054bdb9230aSGarrett D'Amore uint32_t index;
1055bdb9230aSGarrett D'Amore uint32_t *hashp;
1056bdb9230aSGarrett D'Amore
1057bdb9230aSGarrett D'Amore mutex_enter(&dnetp->intrlock);
1058bdb9230aSGarrett D'Amore
1059bdb9230aSGarrett D'Amore bcopy(macaddr, dnetp->curr_macaddr, ETHERADDRL);
1060bdb9230aSGarrett D'Amore
1061bdb9230aSGarrett D'Amore /*
1062bdb9230aSGarrett D'Amore * As we are using Imperfect filtering, the broadcast address has to
1063bdb9230aSGarrett D'Amore * be set explicitly in the 512 bit hash table. Hence the index into
1064bdb9230aSGarrett D'Amore * the hash table is calculated and the bit set to enable reception
1065bdb9230aSGarrett D'Amore * of broadcast packets.
1066bdb9230aSGarrett D'Amore *
1067bdb9230aSGarrett D'Amore * We also use HASH_ONLY mode, without using the perfect filter for
1068bdb9230aSGarrett D'Amore * our station address, because there appears to be a bug in the
1069bdb9230aSGarrett D'Amore * 21140 where it fails to receive the specified perfect filter
1070bdb9230aSGarrett D'Amore * address.
1071bdb9230aSGarrett D'Amore *
1072bdb9230aSGarrett D'Amore * Since dlsdmult comes through here, it doesn't matter that the count
1073bdb9230aSGarrett D'Amore * is wrong for the two bits that correspond to the cases below. The
1074bdb9230aSGarrett D'Amore * worst that could happen is that we'd leave on a bit for an old
1075bdb9230aSGarrett D'Amore * macaddr, in the case where the macaddr gets changed, which is rare.
1076bdb9230aSGarrett D'Amore * Since filtering is imperfect, it is OK if that happens.
1077bdb9230aSGarrett D'Amore */
1078bdb9230aSGarrett D'Amore hashp = (uint32_t *)dnetp->setup_buf_vaddr;
107998e8d175SSteven Stallion index = hashindex((uint8_t *)dnet_broadcastaddr);
1080bdb9230aSGarrett D'Amore hashp[ index / 16 ] |= 1 << (index % 16);
1081bdb9230aSGarrett D'Amore
108298e8d175SSteven Stallion index = hashindex((uint8_t *)dnetp->curr_macaddr);
1083bdb9230aSGarrett D'Amore hashp[ index / 16 ] |= 1 << (index % 16);
1084bdb9230aSGarrett D'Amore
1085bdb9230aSGarrett D'Amore if (!dnetp->suspended)
108698e8d175SSteven Stallion (void) dnet_set_addr(dnetp);
1087bdb9230aSGarrett D'Amore mutex_exit(&dnetp->intrlock);
1088bdb9230aSGarrett D'Amore return (0);
1089bdb9230aSGarrett D'Amore }
1090bdb9230aSGarrett D'Amore
1091bdb9230aSGarrett D'Amore static int
dnet_m_multicst(void * arg,boolean_t add,const uint8_t * macaddr)109298e8d175SSteven Stallion dnet_m_multicst(void *arg, boolean_t add, const uint8_t *macaddr)
1093bdb9230aSGarrett D'Amore {
109498e8d175SSteven Stallion struct dnetinstance *dnetp = arg;
1095bdb9230aSGarrett D'Amore uint32_t index;
1096bdb9230aSGarrett D'Amore uint32_t *hashp;
1097bdb9230aSGarrett D'Amore uint32_t retval;
1098bdb9230aSGarrett D'Amore
1099bdb9230aSGarrett D'Amore mutex_enter(&dnetp->intrlock);
110098e8d175SSteven Stallion index = hashindex(macaddr);
1101bdb9230aSGarrett D'Amore hashp = (uint32_t *)dnetp->setup_buf_vaddr;
110298e8d175SSteven Stallion if (add) {
1103bdb9230aSGarrett D'Amore if (dnetp->multicast_cnt[index]++) {
1104bdb9230aSGarrett D'Amore mutex_exit(&dnetp->intrlock);
1105bdb9230aSGarrett D'Amore return (0);
1106bdb9230aSGarrett D'Amore }
1107bdb9230aSGarrett D'Amore hashp[ index / 16 ] |= 1 << (index % 16);
1108bdb9230aSGarrett D'Amore } else {
1109bdb9230aSGarrett D'Amore if (--dnetp->multicast_cnt[index]) {
1110bdb9230aSGarrett D'Amore mutex_exit(&dnetp->intrlock);
1111bdb9230aSGarrett D'Amore return (0);
1112bdb9230aSGarrett D'Amore }
1113bdb9230aSGarrett D'Amore hashp[ index / 16 ] &= ~ (1 << (index % 16));
1114bdb9230aSGarrett D'Amore }
1115bdb9230aSGarrett D'Amore if (!dnetp->suspended)
111698e8d175SSteven Stallion retval = dnet_set_addr(dnetp);
1117bdb9230aSGarrett D'Amore else
1118bdb9230aSGarrett D'Amore retval = 0;
1119bdb9230aSGarrett D'Amore mutex_exit(&dnetp->intrlock);
1120bdb9230aSGarrett D'Amore return (retval);
1121bdb9230aSGarrett D'Amore }
1122bdb9230aSGarrett D'Amore
1123bdb9230aSGarrett D'Amore /*
1124bdb9230aSGarrett D'Amore * A hashing function used for setting the
1125bdb9230aSGarrett D'Amore * node address or a multicast address
1126bdb9230aSGarrett D'Amore */
1127bdb9230aSGarrett D'Amore static uint32_t
hashindex(const uint8_t * address)112898e8d175SSteven Stallion hashindex(const uint8_t *address)
1129bdb9230aSGarrett D'Amore {
1130bdb9230aSGarrett D'Amore uint32_t crc = (uint32_t)HASH_CRC;
1131bdb9230aSGarrett D'Amore uint32_t const POLY = HASH_POLY;
1132bdb9230aSGarrett D'Amore uint32_t msb;
1133bdb9230aSGarrett D'Amore int32_t byteslength;
1134bdb9230aSGarrett D'Amore uint8_t currentbyte;
1135bdb9230aSGarrett D'Amore uint32_t index;
1136bdb9230aSGarrett D'Amore int32_t bit;
1137bdb9230aSGarrett D'Amore int32_t shift;
1138bdb9230aSGarrett D'Amore
1139bdb9230aSGarrett D'Amore for (byteslength = 0; byteslength < ETHERADDRL; byteslength++) {
1140bdb9230aSGarrett D'Amore currentbyte = address[byteslength];
1141bdb9230aSGarrett D'Amore for (bit = 0; bit < 8; bit++) {
1142bdb9230aSGarrett D'Amore msb = crc >> 31;
1143bdb9230aSGarrett D'Amore crc <<= 1;
1144bdb9230aSGarrett D'Amore if (msb ^ (currentbyte & 1)) {
1145bdb9230aSGarrett D'Amore crc ^= POLY;
1146bdb9230aSGarrett D'Amore crc |= 0x00000001;
1147bdb9230aSGarrett D'Amore }
1148bdb9230aSGarrett D'Amore currentbyte >>= 1;
1149bdb9230aSGarrett D'Amore }
1150bdb9230aSGarrett D'Amore }
1151bdb9230aSGarrett D'Amore
1152bdb9230aSGarrett D'Amore for (index = 0, bit = 23, shift = 8; shift >= 0; bit++, shift--) {
1153bdb9230aSGarrett D'Amore index |= (((crc >> bit) & 1) << shift);
1154bdb9230aSGarrett D'Amore }
1155bdb9230aSGarrett D'Amore return (index);
1156bdb9230aSGarrett D'Amore }
1157bdb9230aSGarrett D'Amore
1158bdb9230aSGarrett D'Amore static int
dnet_m_setpromisc(void * arg,boolean_t on)115998e8d175SSteven Stallion dnet_m_setpromisc(void *arg, boolean_t on)
1160bdb9230aSGarrett D'Amore {
116198e8d175SSteven Stallion struct dnetinstance *dnetp = arg;
1162bdb9230aSGarrett D'Amore uint32_t val;
1163bdb9230aSGarrett D'Amore
1164bdb9230aSGarrett D'Amore mutex_enter(&dnetp->intrlock);
1165bdb9230aSGarrett D'Amore if (dnetp->promisc == on) {
1166bdb9230aSGarrett D'Amore mutex_exit(&dnetp->intrlock);
116798e8d175SSteven Stallion return (0);
1168bdb9230aSGarrett D'Amore }
1169bdb9230aSGarrett D'Amore dnetp->promisc = on;
1170bdb9230aSGarrett D'Amore
1171bdb9230aSGarrett D'Amore if (!dnetp->suspended) {
1172bdb9230aSGarrett D'Amore val = ddi_get32(dnetp->io_handle,
1173bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, OPN_MODE_REG));
117498e8d175SSteven Stallion if (on)
1175bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle,
1176bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, OPN_MODE_REG),
1177bdb9230aSGarrett D'Amore val | PROM_MODE);
1178bdb9230aSGarrett D'Amore else
1179bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle,
1180bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, OPN_MODE_REG),
1181bdb9230aSGarrett D'Amore val & (~PROM_MODE));
1182bdb9230aSGarrett D'Amore }
1183bdb9230aSGarrett D'Amore mutex_exit(&dnetp->intrlock);
118498e8d175SSteven Stallion return (0);
1185bdb9230aSGarrett D'Amore }
1186bdb9230aSGarrett D'Amore
1187bdb9230aSGarrett D'Amore static int
dnet_m_getstat(void * arg,uint_t stat,uint64_t * val)118898e8d175SSteven Stallion dnet_m_getstat(void *arg, uint_t stat, uint64_t *val)
1189bdb9230aSGarrett D'Amore {
119098e8d175SSteven Stallion struct dnetinstance *dnetp = arg;
1191bdb9230aSGarrett D'Amore
119298e8d175SSteven Stallion switch (stat) {
119398e8d175SSteven Stallion case MAC_STAT_IFSPEED:
119432607e28SSteven Stallion if (!dnetp->running) {
119532607e28SSteven Stallion *val = 0;
119632607e28SSteven Stallion } else {
119798e8d175SSteven Stallion *val = (dnetp->mii_up ?
119898e8d175SSteven Stallion dnetp->mii_speed : dnetp->speed) * 1000000;
119932607e28SSteven Stallion }
120098e8d175SSteven Stallion break;
120198e8d175SSteven Stallion
120298e8d175SSteven Stallion case MAC_STAT_NORCVBUF:
120398e8d175SSteven Stallion *val = dnetp->stat_norcvbuf;
120498e8d175SSteven Stallion break;
120598e8d175SSteven Stallion
120698e8d175SSteven Stallion case MAC_STAT_IERRORS:
120798e8d175SSteven Stallion *val = dnetp->stat_errrcv;
120898e8d175SSteven Stallion break;
120998e8d175SSteven Stallion
121098e8d175SSteven Stallion case MAC_STAT_OERRORS:
121198e8d175SSteven Stallion *val = dnetp->stat_errxmt;
121298e8d175SSteven Stallion break;
121398e8d175SSteven Stallion
121498e8d175SSteven Stallion case MAC_STAT_COLLISIONS:
121598e8d175SSteven Stallion *val = dnetp->stat_collisions;
121698e8d175SSteven Stallion break;
121798e8d175SSteven Stallion
121898e8d175SSteven Stallion case ETHER_STAT_DEFER_XMTS:
121998e8d175SSteven Stallion *val = dnetp->stat_defer;
122098e8d175SSteven Stallion break;
122198e8d175SSteven Stallion
122298e8d175SSteven Stallion case ETHER_STAT_CARRIER_ERRORS:
122398e8d175SSteven Stallion *val = dnetp->stat_nocarrier;
122498e8d175SSteven Stallion break;
122598e8d175SSteven Stallion
122698e8d175SSteven Stallion case ETHER_STAT_TOOSHORT_ERRORS:
122798e8d175SSteven Stallion *val = dnetp->stat_short;
122898e8d175SSteven Stallion break;
122998e8d175SSteven Stallion
123098e8d175SSteven Stallion case ETHER_STAT_LINK_DUPLEX:
123198e8d175SSteven Stallion if (!dnetp->running) {
123298e8d175SSteven Stallion *val = LINK_DUPLEX_UNKNOWN;
123398e8d175SSteven Stallion
123432607e28SSteven Stallion } else if (dnetp->mii_up) {
123598e8d175SSteven Stallion *val = dnetp->mii_duplex ?
123698e8d175SSteven Stallion LINK_DUPLEX_FULL : LINK_DUPLEX_HALF;
1237bdb9230aSGarrett D'Amore } else {
123898e8d175SSteven Stallion *val = dnetp->full_duplex ?
123998e8d175SSteven Stallion LINK_DUPLEX_FULL : LINK_DUPLEX_HALF;
124098e8d175SSteven Stallion }
124198e8d175SSteven Stallion break;
124298e8d175SSteven Stallion
124398e8d175SSteven Stallion case ETHER_STAT_TX_LATE_COLLISIONS:
124498e8d175SSteven Stallion *val = dnetp->stat_xmtlatecoll;
124598e8d175SSteven Stallion break;
124698e8d175SSteven Stallion
124798e8d175SSteven Stallion case ETHER_STAT_EX_COLLISIONS:
124898e8d175SSteven Stallion *val = dnetp->stat_excoll;
124998e8d175SSteven Stallion break;
125098e8d175SSteven Stallion
125198e8d175SSteven Stallion case MAC_STAT_OVERFLOWS:
125298e8d175SSteven Stallion *val = dnetp->stat_overflow;
125398e8d175SSteven Stallion break;
125498e8d175SSteven Stallion
125598e8d175SSteven Stallion case MAC_STAT_UNDERFLOWS:
125698e8d175SSteven Stallion *val = dnetp->stat_underflow;
125798e8d175SSteven Stallion break;
125898e8d175SSteven Stallion
125998e8d175SSteven Stallion default:
126098e8d175SSteven Stallion return (ENOTSUP);
1261bdb9230aSGarrett D'Amore }
1262bdb9230aSGarrett D'Amore
126398e8d175SSteven Stallion return (0);
1264bdb9230aSGarrett D'Amore }
1265bdb9230aSGarrett D'Amore
1266bdb9230aSGarrett D'Amore #define NextTXIndex(index) (((index)+1) % dnetp->max_tx_desc)
1267bdb9230aSGarrett D'Amore #define PrevTXIndex(index) (((index)-1) < 0 ? dnetp->max_tx_desc - 1: (index)-1)
1268bdb9230aSGarrett D'Amore
126998e8d175SSteven Stallion static mblk_t *
dnet_m_tx(void * arg,mblk_t * mp)127098e8d175SSteven Stallion dnet_m_tx(void *arg, mblk_t *mp)
1271bdb9230aSGarrett D'Amore {
127298e8d175SSteven Stallion struct dnetinstance *dnetp = arg;
127398e8d175SSteven Stallion
127498e8d175SSteven Stallion mutex_enter(&dnetp->txlock);
127598e8d175SSteven Stallion
127698e8d175SSteven Stallion /* if suspended, drop the packet on the floor, we missed it */
127798e8d175SSteven Stallion if (dnetp->suspended) {
127898e8d175SSteven Stallion mutex_exit(&dnetp->txlock);
127998e8d175SSteven Stallion freemsg(mp);
128098e8d175SSteven Stallion return (NULL);
128198e8d175SSteven Stallion }
128298e8d175SSteven Stallion
128398e8d175SSteven Stallion if (dnetp->need_saddr) {
128498e8d175SSteven Stallion /* XXX function return value ignored */
128598e8d175SSteven Stallion mutex_exit(&dnetp->txlock);
128698e8d175SSteven Stallion mutex_enter(&dnetp->intrlock);
128798e8d175SSteven Stallion (void) dnet_set_addr(dnetp);
128898e8d175SSteven Stallion mutex_exit(&dnetp->intrlock);
128998e8d175SSteven Stallion mutex_enter(&dnetp->txlock);
129098e8d175SSteven Stallion }
129198e8d175SSteven Stallion
129298e8d175SSteven Stallion while (mp != NULL) {
129398e8d175SSteven Stallion if (!dnet_send(dnetp, mp)) {
129498e8d175SSteven Stallion mutex_exit(&dnetp->txlock);
129598e8d175SSteven Stallion return (mp);
129698e8d175SSteven Stallion }
129798e8d175SSteven Stallion mp = mp->b_next;
129898e8d175SSteven Stallion }
129998e8d175SSteven Stallion
130098e8d175SSteven Stallion mutex_exit(&dnetp->txlock);
130198e8d175SSteven Stallion
130298e8d175SSteven Stallion /*
130398e8d175SSteven Stallion * Enable xmit interrupt in case we are running out of xmit descriptors
130498e8d175SSteven Stallion * or there are more packets on the queue waiting to be transmitted.
130598e8d175SSteven Stallion */
130698e8d175SSteven Stallion mutex_enter(&dnetp->intrlock);
130798e8d175SSteven Stallion
130898e8d175SSteven Stallion enable_interrupts(dnetp);
130998e8d175SSteven Stallion
131098e8d175SSteven Stallion /*
131198e8d175SSteven Stallion * Kick the transmitter
131298e8d175SSteven Stallion */
131398e8d175SSteven Stallion ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, TX_POLL_REG),
131498e8d175SSteven Stallion TX_POLL_DEMAND);
131598e8d175SSteven Stallion
131698e8d175SSteven Stallion mutex_exit(&dnetp->intrlock);
131798e8d175SSteven Stallion
131898e8d175SSteven Stallion return (NULL);
131998e8d175SSteven Stallion }
132098e8d175SSteven Stallion
132198e8d175SSteven Stallion static boolean_t
dnet_send(struct dnetinstance * dnetp,mblk_t * mp)132298e8d175SSteven Stallion dnet_send(struct dnetinstance *dnetp, mblk_t *mp)
132398e8d175SSteven Stallion {
1324bdb9230aSGarrett D'Amore struct tx_desc_type *ring = dnetp->tx_desc;
1325bdb9230aSGarrett D'Amore int mblen, totlen;
1326bdb9230aSGarrett D'Amore int index, end_index, start_index;
1327bdb9230aSGarrett D'Amore int avail;
1328bdb9230aSGarrett D'Amore int error;
1329bdb9230aSGarrett D'Amore int bufn;
1330bdb9230aSGarrett D'Amore int retval;
1331bdb9230aSGarrett D'Amore mblk_t *bp;
1332bdb9230aSGarrett D'Amore
133398e8d175SSteven Stallion ASSERT(MUTEX_HELD(&dnetp->txlock));
1334bdb9230aSGarrett D'Amore
1335bdb9230aSGarrett D'Amore /* reclaim any xmit descriptors completed */
133698e8d175SSteven Stallion dnet_reclaim_Tx_desc(dnetp);
1337bdb9230aSGarrett D'Amore
1338bdb9230aSGarrett D'Amore /*
1339bdb9230aSGarrett D'Amore * Use the data buffers from the message and construct the
1340bdb9230aSGarrett D'Amore * scatter/gather list by calling ddi_dma_addr_bind_handle().
1341bdb9230aSGarrett D'Amore */
134298e8d175SSteven Stallion error = 0;
1343bdb9230aSGarrett D'Amore totlen = 0;
1344bdb9230aSGarrett D'Amore bp = mp;
1345bdb9230aSGarrett D'Amore bufn = 0;
1346bdb9230aSGarrett D'Amore index = start_index = dnetp->tx_current_desc;
1347bdb9230aSGarrett D'Amore avail = dnetp->free_desc;
1348bdb9230aSGarrett D'Amore while (bp != NULL) {
1349bdb9230aSGarrett D'Amore uint_t ncookies;
1350bdb9230aSGarrett D'Amore ddi_dma_cookie_t dma_cookie;
1351bdb9230aSGarrett D'Amore
135298e8d175SSteven Stallion mblen = MBLKL(bp);
1353bdb9230aSGarrett D'Amore
1354bdb9230aSGarrett D'Amore if (!mblen) { /* skip zero-length message blocks */
1355bdb9230aSGarrett D'Amore bp = bp->b_cont;
1356bdb9230aSGarrett D'Amore continue;
1357bdb9230aSGarrett D'Amore }
1358bdb9230aSGarrett D'Amore
1359bdb9230aSGarrett D'Amore retval = ddi_dma_addr_bind_handle(dnetp->dma_handle_tx, NULL,
1360bdb9230aSGarrett D'Amore (caddr_t)bp->b_rptr, mblen,
1361bdb9230aSGarrett D'Amore DDI_DMA_WRITE | DDI_DMA_STREAMING, DDI_DMA_SLEEP, 0,
1362bdb9230aSGarrett D'Amore &dma_cookie, &ncookies);
1363bdb9230aSGarrett D'Amore
1364bdb9230aSGarrett D'Amore switch (retval) {
1365bdb9230aSGarrett D'Amore case DDI_DMA_MAPPED:
1366bdb9230aSGarrett D'Amore break; /* everything's fine */
1367bdb9230aSGarrett D'Amore
1368bdb9230aSGarrett D'Amore case DDI_DMA_NORESOURCES:
1369bdb9230aSGarrett D'Amore error = 1; /* allow retry by gld */
1370bdb9230aSGarrett D'Amore break;
1371bdb9230aSGarrett D'Amore
1372bdb9230aSGarrett D'Amore case DDI_DMA_NOMAPPING:
1373bdb9230aSGarrett D'Amore case DDI_DMA_INUSE:
1374bdb9230aSGarrett D'Amore case DDI_DMA_TOOBIG:
1375bdb9230aSGarrett D'Amore default:
1376bdb9230aSGarrett D'Amore error = 2; /* error, no retry */
1377bdb9230aSGarrett D'Amore break;
1378bdb9230aSGarrett D'Amore }
1379bdb9230aSGarrett D'Amore
1380bdb9230aSGarrett D'Amore /*
1381bdb9230aSGarrett D'Amore * we can use two cookies per descriptor (i.e buffer1 and
1382bdb9230aSGarrett D'Amore * buffer2) so we need at least (ncookies+1)/2 descriptors.
1383bdb9230aSGarrett D'Amore */
1384bdb9230aSGarrett D'Amore if (((ncookies + 1) >> 1) > dnetp->free_desc) {
1385bdb9230aSGarrett D'Amore (void) ddi_dma_unbind_handle(dnetp->dma_handle_tx);
1386bdb9230aSGarrett D'Amore error = 1;
1387bdb9230aSGarrett D'Amore break;
1388bdb9230aSGarrett D'Amore }
1389bdb9230aSGarrett D'Amore
1390bdb9230aSGarrett D'Amore /* setup the descriptors for this data buffer */
1391bdb9230aSGarrett D'Amore while (ncookies) {
1392bdb9230aSGarrett D'Amore end_index = index;
1393bdb9230aSGarrett D'Amore if (bufn % 2) {
1394bdb9230aSGarrett D'Amore ring[index].buffer2 =
1395bdb9230aSGarrett D'Amore (uint32_t)dma_cookie.dmac_address;
1396bdb9230aSGarrett D'Amore ring[index].desc1.buffer_size2 =
1397bdb9230aSGarrett D'Amore dma_cookie.dmac_size;
1398bdb9230aSGarrett D'Amore index = NextTXIndex(index); /* goto next desc */
1399bdb9230aSGarrett D'Amore } else {
1400bdb9230aSGarrett D'Amore /* initialize the descriptor */
1401bdb9230aSGarrett D'Amore ASSERT(ring[index].desc0.own == 0);
1402bdb9230aSGarrett D'Amore *(uint32_t *)&ring[index].desc0 = 0;
1403bdb9230aSGarrett D'Amore *(uint32_t *)&ring[index].desc1 &=
1404bdb9230aSGarrett D'Amore DNET_END_OF_RING;
1405bdb9230aSGarrett D'Amore ring[index].buffer1 =
1406bdb9230aSGarrett D'Amore (uint32_t)dma_cookie.dmac_address;
1407bdb9230aSGarrett D'Amore ring[index].desc1.buffer_size1 =
1408bdb9230aSGarrett D'Amore dma_cookie.dmac_size;
1409bdb9230aSGarrett D'Amore ring[index].buffer2 = (uint32_t)(0);
1410bdb9230aSGarrett D'Amore dnetp->free_desc--;
1411bdb9230aSGarrett D'Amore ASSERT(dnetp->free_desc >= 0);
1412bdb9230aSGarrett D'Amore }
1413bdb9230aSGarrett D'Amore totlen += dma_cookie.dmac_size;
1414bdb9230aSGarrett D'Amore bufn++;
1415bdb9230aSGarrett D'Amore if (--ncookies)
1416bdb9230aSGarrett D'Amore ddi_dma_nextcookie(dnetp->dma_handle_tx,
1417bdb9230aSGarrett D'Amore &dma_cookie);
1418bdb9230aSGarrett D'Amore }
1419bdb9230aSGarrett D'Amore (void) ddi_dma_unbind_handle(dnetp->dma_handle_tx);
1420bdb9230aSGarrett D'Amore bp = bp->b_cont;
1421bdb9230aSGarrett D'Amore }
1422bdb9230aSGarrett D'Amore
1423bdb9230aSGarrett D'Amore if (error == 1) {
1424bdb9230aSGarrett D'Amore dnetp->stat_defer++;
1425bdb9230aSGarrett D'Amore dnetp->free_desc = avail;
142698e8d175SSteven Stallion dnetp->need_tx_update = B_TRUE;
142798e8d175SSteven Stallion return (B_FALSE);
1428bdb9230aSGarrett D'Amore } else if (error) {
1429bdb9230aSGarrett D'Amore dnetp->free_desc = avail;
1430bdb9230aSGarrett D'Amore freemsg(mp);
143198e8d175SSteven Stallion return (B_TRUE); /* Drop packet, don't retry */
1432bdb9230aSGarrett D'Amore }
1433bdb9230aSGarrett D'Amore
143498e8d175SSteven Stallion if (totlen > ETHERMAX + VLAN_TAGSZ) {
1435bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "DNET: tried to send large %d packet", totlen);
1436bdb9230aSGarrett D'Amore dnetp->free_desc = avail;
1437bdb9230aSGarrett D'Amore freemsg(mp);
143898e8d175SSteven Stallion return (B_TRUE); /* Don't repeat this attempt */
1439bdb9230aSGarrett D'Amore }
1440bdb9230aSGarrett D'Amore
1441bdb9230aSGarrett D'Amore /*
1442bdb9230aSGarrett D'Amore * Remeber the message buffer pointer to do freemsg() at xmit
1443bdb9230aSGarrett D'Amore * interrupt time.
1444bdb9230aSGarrett D'Amore */
1445bdb9230aSGarrett D'Amore dnetp->tx_msgbufp[end_index] = mp;
1446bdb9230aSGarrett D'Amore
1447bdb9230aSGarrett D'Amore /*
1448bdb9230aSGarrett D'Amore * Now set the first/last buffer and own bits
1449bdb9230aSGarrett D'Amore * Since the 21040 looks for these bits set in the
1450bdb9230aSGarrett D'Amore * first buffer, work backwards in multiple buffers.
1451bdb9230aSGarrett D'Amore */
1452bdb9230aSGarrett D'Amore ring[end_index].desc1.last_desc = 1;
1453bdb9230aSGarrett D'Amore ring[end_index].desc1.int_on_comp = 1;
1454bdb9230aSGarrett D'Amore for (index = end_index; index != start_index;
1455bdb9230aSGarrett D'Amore index = PrevTXIndex(index))
1456bdb9230aSGarrett D'Amore ring[index].desc0.own = 1;
1457bdb9230aSGarrett D'Amore ring[start_index].desc1.first_desc = 1;
1458bdb9230aSGarrett D'Amore ring[start_index].desc0.own = 1;
1459bdb9230aSGarrett D'Amore
1460bdb9230aSGarrett D'Amore dnetp->tx_current_desc = NextTXIndex(end_index);
1461bdb9230aSGarrett D'Amore
1462bdb9230aSGarrett D'Amore /*
1463bdb9230aSGarrett D'Amore * Safety check: make sure end-of-ring is set in last desc.
1464bdb9230aSGarrett D'Amore */
1465bdb9230aSGarrett D'Amore ASSERT(ring[dnetp->max_tx_desc-1].desc1.end_of_ring != 0);
1466bdb9230aSGarrett D'Amore
146798e8d175SSteven Stallion return (B_TRUE);
1468bdb9230aSGarrett D'Amore }
1469bdb9230aSGarrett D'Amore
1470bdb9230aSGarrett D'Amore /*
147198e8d175SSteven Stallion * dnet_intr() -- interrupt from board to inform us that a receive or
1472bdb9230aSGarrett D'Amore * transmit has completed.
1473bdb9230aSGarrett D'Amore */
1474bdb9230aSGarrett D'Amore static uint_t
dnet_intr(caddr_t arg)147598e8d175SSteven Stallion dnet_intr(caddr_t arg)
1476bdb9230aSGarrett D'Amore {
147798e8d175SSteven Stallion struct dnetinstance *dnetp = (struct dnetinstance *)arg;
1478bdb9230aSGarrett D'Amore uint32_t int_status;
1479bdb9230aSGarrett D'Amore
1480bdb9230aSGarrett D'Amore mutex_enter(&dnetp->intrlock);
148198e8d175SSteven Stallion
1482bdb9230aSGarrett D'Amore if (dnetp->suspended) {
1483bdb9230aSGarrett D'Amore mutex_exit(&dnetp->intrlock);
1484bdb9230aSGarrett D'Amore return (DDI_INTR_UNCLAIMED);
1485bdb9230aSGarrett D'Amore }
1486bdb9230aSGarrett D'Amore
1487bdb9230aSGarrett D'Amore int_status = ddi_get32(dnetp->io_handle, REG32(dnetp->io_reg,
1488bdb9230aSGarrett D'Amore STATUS_REG));
1489bdb9230aSGarrett D'Amore
1490bdb9230aSGarrett D'Amore /*
1491bdb9230aSGarrett D'Amore * If interrupt was not from this board
1492bdb9230aSGarrett D'Amore */
1493bdb9230aSGarrett D'Amore if (!(int_status & (NORMAL_INTR_SUMM | ABNORMAL_INTR_SUMM))) {
1494bdb9230aSGarrett D'Amore mutex_exit(&dnetp->intrlock);
1495bdb9230aSGarrett D'Amore return (DDI_INTR_UNCLAIMED);
1496bdb9230aSGarrett D'Amore }
1497bdb9230aSGarrett D'Amore
1498bdb9230aSGarrett D'Amore dnetp->stat_intr++;
1499bdb9230aSGarrett D'Amore
1500bdb9230aSGarrett D'Amore if (int_status & GPTIMER_INTR) {
1501bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle,
1502bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, STATUS_REG), GPTIMER_INTR);
1503bdb9230aSGarrett D'Amore if (dnetp->timer.cb)
1504bdb9230aSGarrett D'Amore dnetp->timer.cb(dnetp);
1505bdb9230aSGarrett D'Amore else
1506bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "dnet: unhandled timer interrupt");
1507bdb9230aSGarrett D'Amore }
1508bdb9230aSGarrett D'Amore
1509bdb9230aSGarrett D'Amore if (int_status & TX_INTR) {
1510bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle,
1511bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, STATUS_REG), TX_INTR);
1512bdb9230aSGarrett D'Amore mutex_enter(&dnetp->txlock);
151398e8d175SSteven Stallion if (dnetp->need_tx_update) {
1514bdb9230aSGarrett D'Amore mutex_exit(&dnetp->txlock);
1515bdb9230aSGarrett D'Amore mutex_exit(&dnetp->intrlock);
151698e8d175SSteven Stallion mac_tx_update(dnetp->mac_handle);
1517bdb9230aSGarrett D'Amore mutex_enter(&dnetp->intrlock);
1518bdb9230aSGarrett D'Amore mutex_enter(&dnetp->txlock);
151998e8d175SSteven Stallion dnetp->need_tx_update = B_FALSE;
1520bdb9230aSGarrett D'Amore }
1521bdb9230aSGarrett D'Amore /* reclaim any xmit descriptors that are completed */
152298e8d175SSteven Stallion dnet_reclaim_Tx_desc(dnetp);
1523bdb9230aSGarrett D'Amore mutex_exit(&dnetp->txlock);
1524bdb9230aSGarrett D'Amore }
1525bdb9230aSGarrett D'Amore
1526bdb9230aSGarrett D'Amore /*
1527bdb9230aSGarrett D'Amore * Check if receive interrupt bit is set
1528bdb9230aSGarrett D'Amore */
1529bdb9230aSGarrett D'Amore if (int_status & (RX_INTR | RX_UNAVAIL_INTR)) {
1530bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle,
1531bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, STATUS_REG),
1532bdb9230aSGarrett D'Amore int_status & (RX_INTR | RX_UNAVAIL_INTR));
153398e8d175SSteven Stallion dnet_getp(dnetp);
1534bdb9230aSGarrett D'Amore }
1535bdb9230aSGarrett D'Amore
1536bdb9230aSGarrett D'Amore if (int_status & ABNORMAL_INTR_SUMM) {
1537bdb9230aSGarrett D'Amore /*
1538bdb9230aSGarrett D'Amore * Check for system error
1539bdb9230aSGarrett D'Amore */
1540bdb9230aSGarrett D'Amore if (int_status & SYS_ERR) {
1541bdb9230aSGarrett D'Amore if ((int_status & SYS_ERR_BITS) == MASTER_ABORT)
1542bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "DNET: Bus Master Abort");
1543bdb9230aSGarrett D'Amore if ((int_status & SYS_ERR_BITS) == TARGET_ABORT)
1544bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "DNET: Bus Target Abort");
1545bdb9230aSGarrett D'Amore if ((int_status & SYS_ERR_BITS) == PARITY_ERROR)
1546bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "DNET: Parity error");
1547bdb9230aSGarrett D'Amore }
1548bdb9230aSGarrett D'Amore
1549bdb9230aSGarrett D'Amore /*
1550bdb9230aSGarrett D'Amore * If the jabber has timed out then reset the chip
1551bdb9230aSGarrett D'Amore */
1552bdb9230aSGarrett D'Amore if (int_status & TX_JABBER_TIMEOUT)
1553bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "DNET: Jabber timeout.");
1554bdb9230aSGarrett D'Amore
1555bdb9230aSGarrett D'Amore /*
1556bdb9230aSGarrett D'Amore * If an underflow has occurred, reset the chip
1557bdb9230aSGarrett D'Amore */
1558bdb9230aSGarrett D'Amore if (int_status & TX_UNDERFLOW)
1559bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "DNET: Tx Underflow.");
1560bdb9230aSGarrett D'Amore
1561bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
1562bdb9230aSGarrett D'Amore if (dnetdebug & DNETINT)
1563bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "Trying to reset...");
1564bdb9230aSGarrett D'Amore #endif
156598e8d175SSteven Stallion dnet_reset_board(dnetp);
156698e8d175SSteven Stallion dnet_init_board(dnetp);
1567bdb9230aSGarrett D'Amore /* XXX function return value ignored */
156898e8d175SSteven Stallion (void) dnet_start(dnetp);
1569bdb9230aSGarrett D'Amore }
1570bdb9230aSGarrett D'Amore
1571bdb9230aSGarrett D'Amore /*
157298e8d175SSteven Stallion * Enable the interrupts. Enable xmit interrupt in case we are
1573bdb9230aSGarrett D'Amore * running out of free descriptors or if there are packets
1574bdb9230aSGarrett D'Amore * in the queue waiting to be transmitted.
1575bdb9230aSGarrett D'Amore */
157698e8d175SSteven Stallion enable_interrupts(dnetp);
1577bdb9230aSGarrett D'Amore mutex_exit(&dnetp->intrlock);
1578bdb9230aSGarrett D'Amore return (DDI_INTR_CLAIMED); /* Indicate it was our interrupt */
1579bdb9230aSGarrett D'Amore }
1580bdb9230aSGarrett D'Amore
1581bdb9230aSGarrett D'Amore static void
dnet_getp(struct dnetinstance * dnetp)158298e8d175SSteven Stallion dnet_getp(struct dnetinstance *dnetp)
1583bdb9230aSGarrett D'Amore {
1584bdb9230aSGarrett D'Amore int packet_length, index;
1585bdb9230aSGarrett D'Amore mblk_t *mp;
1586bdb9230aSGarrett D'Amore caddr_t virtual_address;
1587bdb9230aSGarrett D'Amore struct rx_desc_type *desc = dnetp->rx_desc;
1588bdb9230aSGarrett D'Amore int marker = dnetp->rx_current_desc;
1589bdb9230aSGarrett D'Amore int misses;
1590bdb9230aSGarrett D'Amore
1591bdb9230aSGarrett D'Amore if (!dnetp->overrun_workaround) {
1592bdb9230aSGarrett D'Amore /*
1593bdb9230aSGarrett D'Amore * If the workaround is not in place, we must still update
1594bdb9230aSGarrett D'Amore * the missed frame statistic from the on-chip counter.
1595bdb9230aSGarrett D'Amore */
1596bdb9230aSGarrett D'Amore misses = ddi_get32(dnetp->io_handle,
1597bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, MISSED_FRAME_REG));
1598bdb9230aSGarrett D'Amore dnetp->stat_missed += (misses & MISSED_FRAME_MASK);
1599bdb9230aSGarrett D'Amore }
1600bdb9230aSGarrett D'Amore
1601bdb9230aSGarrett D'Amore /* While host owns the current descriptor */
1602bdb9230aSGarrett D'Amore while (!(desc[dnetp->rx_current_desc].desc0.own)) {
1603bdb9230aSGarrett D'Amore struct free_ptr *frp;
1604bdb9230aSGarrett D'Amore caddr_t newbuf;
1605bdb9230aSGarrett D'Amore struct rbuf_list *rp;
1606bdb9230aSGarrett D'Amore
1607bdb9230aSGarrett D'Amore index = dnetp->rx_current_desc;
1608bdb9230aSGarrett D'Amore ASSERT(desc[index].desc0.first_desc != 0);
1609bdb9230aSGarrett D'Amore
1610bdb9230aSGarrett D'Amore /*
1611bdb9230aSGarrett D'Amore * DMA overrun errata from DEC: avoid possible bus hangs
1612bdb9230aSGarrett D'Amore * and data corruption
1613bdb9230aSGarrett D'Amore */
1614bdb9230aSGarrett D'Amore if (dnetp->overrun_workaround &&
1615bdb9230aSGarrett D'Amore marker == dnetp->rx_current_desc) {
1616bdb9230aSGarrett D'Amore int opn;
1617bdb9230aSGarrett D'Amore do {
1618bdb9230aSGarrett D'Amore marker = (marker+1) % dnetp->max_rx_desc;
1619bdb9230aSGarrett D'Amore } while (!(dnetp->rx_desc[marker].desc0.own) &&
1620bdb9230aSGarrett D'Amore marker != index);
1621bdb9230aSGarrett D'Amore
1622bdb9230aSGarrett D'Amore misses = ddi_get32(dnetp->io_handle,
1623bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, MISSED_FRAME_REG));
1624bdb9230aSGarrett D'Amore dnetp->stat_missed +=
1625bdb9230aSGarrett D'Amore (misses & MISSED_FRAME_MASK);
1626bdb9230aSGarrett D'Amore if (misses & OVERFLOW_COUNTER_MASK) {
1627bdb9230aSGarrett D'Amore /*
1628bdb9230aSGarrett D'Amore * Overflow(s) have occurred : stop receiver,
1629bdb9230aSGarrett D'Amore * and wait until in stopped state
1630bdb9230aSGarrett D'Amore */
1631bdb9230aSGarrett D'Amore opn = ddi_get32(dnetp->io_handle,
1632bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, OPN_MODE_REG));
1633bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle,
1634bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, OPN_MODE_REG),
1635bdb9230aSGarrett D'Amore opn & ~(START_RECEIVE));
1636bdb9230aSGarrett D'Amore
1637bdb9230aSGarrett D'Amore do {
1638bdb9230aSGarrett D'Amore drv_usecwait(10);
1639bdb9230aSGarrett D'Amore } while ((ddi_get32(dnetp->io_handle,
1640bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, STATUS_REG)) &
1641bdb9230aSGarrett D'Amore RECEIVE_PROCESS_STATE) != 0);
1642bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
1643bdb9230aSGarrett D'Amore if (dnetdebug & DNETRECV)
1644bdb9230aSGarrett D'Amore cmn_err(CE_CONT, "^*");
1645bdb9230aSGarrett D'Amore #endif
1646bdb9230aSGarrett D'Amore /* Discard probably corrupt frames */
1647bdb9230aSGarrett D'Amore while (!(dnetp->rx_desc[index].desc0.own)) {
1648bdb9230aSGarrett D'Amore dnetp->rx_desc[index].desc0.own = 1;
1649bdb9230aSGarrett D'Amore index = (index+1) % dnetp->max_rx_desc;
1650bdb9230aSGarrett D'Amore dnetp->stat_missed++;
1651bdb9230aSGarrett D'Amore }
1652bdb9230aSGarrett D'Amore
1653bdb9230aSGarrett D'Amore /* restart the receiver */
1654bdb9230aSGarrett D'Amore opn = ddi_get32(dnetp->io_handle,
1655bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, OPN_MODE_REG));
1656bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle,
1657bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, OPN_MODE_REG),
1658bdb9230aSGarrett D'Amore opn | START_RECEIVE);
1659bdb9230aSGarrett D'Amore marker = dnetp->rx_current_desc = index;
1660bdb9230aSGarrett D'Amore continue;
1661bdb9230aSGarrett D'Amore }
1662bdb9230aSGarrett D'Amore /*
1663bdb9230aSGarrett D'Amore * At this point, we know that all packets before
1664bdb9230aSGarrett D'Amore * "marker" were received before a dma overrun occurred
1665bdb9230aSGarrett D'Amore */
1666bdb9230aSGarrett D'Amore }
1667bdb9230aSGarrett D'Amore
1668bdb9230aSGarrett D'Amore /*
1669bdb9230aSGarrett D'Amore * If we get an oversized packet it could span multiple
1670bdb9230aSGarrett D'Amore * descriptors. If this happens an error bit should be set.
1671bdb9230aSGarrett D'Amore */
1672bdb9230aSGarrett D'Amore while (desc[index].desc0.last_desc == 0) {
1673bdb9230aSGarrett D'Amore index = (index + 1) % dnetp->max_rx_desc;
1674bdb9230aSGarrett D'Amore if (desc[index].desc0.own)
1675bdb9230aSGarrett D'Amore return; /* not done receiving large packet */
1676bdb9230aSGarrett D'Amore }
1677bdb9230aSGarrett D'Amore while (dnetp->rx_current_desc != index) {
1678bdb9230aSGarrett D'Amore desc[dnetp->rx_current_desc].desc0.own = 1;
1679bdb9230aSGarrett D'Amore dnetp->rx_current_desc =
1680bdb9230aSGarrett D'Amore (dnetp->rx_current_desc + 1) % dnetp->max_rx_desc;
1681bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
1682bdb9230aSGarrett D'Amore if (dnetdebug & DNETRECV)
1683bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "dnet: received large packet");
1684bdb9230aSGarrett D'Amore #endif
1685bdb9230aSGarrett D'Amore }
1686bdb9230aSGarrett D'Amore
1687bdb9230aSGarrett D'Amore packet_length = desc[index].desc0.frame_len;
1688bdb9230aSGarrett D'Amore
1689bdb9230aSGarrett D'Amore /*
1690bdb9230aSGarrett D'Amore * Remove CRC from received data. This is an artefact of the
1691bdb9230aSGarrett D'Amore * 21x4x chip and should not be passed higher up the network
1692bdb9230aSGarrett D'Amore * stack.
1693bdb9230aSGarrett D'Amore */
1694bdb9230aSGarrett D'Amore packet_length -= ETHERFCSL;
1695bdb9230aSGarrett D'Amore
1696bdb9230aSGarrett D'Amore /* get the virtual address of the packet received */
1697bdb9230aSGarrett D'Amore virtual_address =
1698bdb9230aSGarrett D'Amore dnetp->rx_buf_vaddr[index];
1699bdb9230aSGarrett D'Amore
1700bdb9230aSGarrett D'Amore /*
1701bdb9230aSGarrett D'Amore * If no packet errors then do:
1702bdb9230aSGarrett D'Amore * 1. Allocate a new receive buffer so that we can
1703bdb9230aSGarrett D'Amore * use the current buffer as streams buffer to
1704bdb9230aSGarrett D'Amore * avoid bcopy.
1705bdb9230aSGarrett D'Amore * 2. If we got a new receive buffer then allocate
1706bdb9230aSGarrett D'Amore * an mblk using desballoc().
1707bdb9230aSGarrett D'Amore * 3. Otherwise use the mblk from allocb() and do
1708bdb9230aSGarrett D'Amore * the bcopy.
1709bdb9230aSGarrett D'Amore */
1710bdb9230aSGarrett D'Amore frp = NULL;
1711bdb9230aSGarrett D'Amore rp = NULL;
1712bdb9230aSGarrett D'Amore newbuf = NULL;
1713bdb9230aSGarrett D'Amore mp = NULL;
171498e8d175SSteven Stallion if (!desc[index].desc0.err_summary ||
171598e8d175SSteven Stallion (desc[index].desc0.frame2long &&
171698e8d175SSteven Stallion packet_length < rx_buf_size)) {
1717bdb9230aSGarrett D'Amore ASSERT(packet_length < rx_buf_size);
1718bdb9230aSGarrett D'Amore /*
1719bdb9230aSGarrett D'Amore * Allocate another receive buffer for this descriptor.
1720bdb9230aSGarrett D'Amore * If we fail to allocate then we do the normal bcopy.
1721bdb9230aSGarrett D'Amore */
1722bdb9230aSGarrett D'Amore rp = dnet_rbuf_alloc(dnetp->devinfo, 0);
1723bdb9230aSGarrett D'Amore if (rp != NULL) {
1724bdb9230aSGarrett D'Amore newbuf = rp->rbuf_vaddr;
1725bdb9230aSGarrett D'Amore frp = kmem_zalloc(sizeof (*frp), KM_NOSLEEP);
1726bdb9230aSGarrett D'Amore if (frp != NULL) {
1727bdb9230aSGarrett D'Amore frp->free_rtn.free_func =
1728bdb9230aSGarrett D'Amore dnet_freemsg_buf;
1729bdb9230aSGarrett D'Amore frp->free_rtn.free_arg = (char *)frp;
1730bdb9230aSGarrett D'Amore frp->buf = virtual_address;
1731bdb9230aSGarrett D'Amore mp = desballoc(
1732bdb9230aSGarrett D'Amore (uchar_t *)virtual_address,
1733bdb9230aSGarrett D'Amore packet_length, 0, &frp->free_rtn);
1734bdb9230aSGarrett D'Amore if (mp == NULL) {
1735bdb9230aSGarrett D'Amore kmem_free(frp, sizeof (*frp));
1736bdb9230aSGarrett D'Amore dnet_rbuf_free((caddr_t)newbuf);
1737bdb9230aSGarrett D'Amore frp = NULL;
1738bdb9230aSGarrett D'Amore newbuf = NULL;
1739bdb9230aSGarrett D'Amore }
1740bdb9230aSGarrett D'Amore }
1741bdb9230aSGarrett D'Amore }
1742bdb9230aSGarrett D'Amore if (mp == NULL) {
1743bdb9230aSGarrett D'Amore if (newbuf != NULL)
1744bdb9230aSGarrett D'Amore dnet_rbuf_free((caddr_t)newbuf);
1745bdb9230aSGarrett D'Amore mp = allocb(packet_length, 0);
1746bdb9230aSGarrett D'Amore }
1747bdb9230aSGarrett D'Amore }
1748bdb9230aSGarrett D'Amore
174998e8d175SSteven Stallion if ((desc[index].desc0.err_summary &&
175098e8d175SSteven Stallion packet_length >= rx_buf_size) || mp == NULL) {
1751bdb9230aSGarrett D'Amore
1752bdb9230aSGarrett D'Amore /* Update gld statistics */
1753bdb9230aSGarrett D'Amore if (desc[index].desc0.err_summary)
175498e8d175SSteven Stallion update_rx_stats(dnetp, index);
1755bdb9230aSGarrett D'Amore else
1756bdb9230aSGarrett D'Amore dnetp->stat_norcvbuf++;
1757bdb9230aSGarrett D'Amore
1758bdb9230aSGarrett D'Amore /*
1759bdb9230aSGarrett D'Amore * Reset ownership of the descriptor.
1760bdb9230aSGarrett D'Amore */
1761bdb9230aSGarrett D'Amore desc[index].desc0.own = 1;
1762bdb9230aSGarrett D'Amore dnetp->rx_current_desc =
1763bdb9230aSGarrett D'Amore (dnetp->rx_current_desc+1) % dnetp->max_rx_desc;
1764bdb9230aSGarrett D'Amore
1765bdb9230aSGarrett D'Amore /* Demand receive polling by the chip */
1766bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle,
1767bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, RX_POLL_REG), RX_POLL_DEMAND);
1768bdb9230aSGarrett D'Amore
1769bdb9230aSGarrett D'Amore continue;
1770bdb9230aSGarrett D'Amore }
1771bdb9230aSGarrett D'Amore
1772bdb9230aSGarrett D'Amore if (newbuf != NULL) {
1773bdb9230aSGarrett D'Amore uint32_t end_paddr;
1774bdb9230aSGarrett D'Amore /* attach the new buffer to the rx descriptor */
1775bdb9230aSGarrett D'Amore dnetp->rx_buf_vaddr[index] = newbuf;
1776bdb9230aSGarrett D'Amore dnetp->rx_buf_paddr[index] = rp->rbuf_paddr;
1777bdb9230aSGarrett D'Amore desc[index].buffer1 = rp->rbuf_paddr;
1778bdb9230aSGarrett D'Amore desc[index].desc1.buffer_size1 = rx_buf_size;
1779bdb9230aSGarrett D'Amore desc[index].desc1.buffer_size2 = 0;
1780bdb9230aSGarrett D'Amore end_paddr = rp->rbuf_endpaddr;
1781bdb9230aSGarrett D'Amore if ((desc[index].buffer1 & ~dnetp->pgmask) !=
1782bdb9230aSGarrett D'Amore (end_paddr & ~dnetp->pgmask)) {
1783bdb9230aSGarrett D'Amore /* discontiguous */
1784bdb9230aSGarrett D'Amore desc[index].buffer2 = end_paddr&~dnetp->pgmask;
1785bdb9230aSGarrett D'Amore desc[index].desc1.buffer_size2 =
1786bdb9230aSGarrett D'Amore (end_paddr & dnetp->pgmask) + 1;
1787bdb9230aSGarrett D'Amore desc[index].desc1.buffer_size1 =
1788bdb9230aSGarrett D'Amore rx_buf_size-desc[index].desc1.buffer_size2;
1789bdb9230aSGarrett D'Amore }
1790bdb9230aSGarrett D'Amore } else {
1791bdb9230aSGarrett D'Amore /* couldn't allocate another buffer; copy the data */
1792bdb9230aSGarrett D'Amore BCOPY((caddr_t)virtual_address, (caddr_t)mp->b_wptr,
1793bdb9230aSGarrett D'Amore packet_length);
1794bdb9230aSGarrett D'Amore }
1795bdb9230aSGarrett D'Amore
1796bdb9230aSGarrett D'Amore mp->b_wptr += packet_length;
1797bdb9230aSGarrett D'Amore
1798bdb9230aSGarrett D'Amore desc[dnetp->rx_current_desc].desc0.own = 1;
1799bdb9230aSGarrett D'Amore
1800bdb9230aSGarrett D'Amore /*
1801bdb9230aSGarrett D'Amore * Increment receive desc index. This is for the scan of
1802bdb9230aSGarrett D'Amore * next packet
1803bdb9230aSGarrett D'Amore */
1804bdb9230aSGarrett D'Amore dnetp->rx_current_desc =
1805bdb9230aSGarrett D'Amore (dnetp->rx_current_desc+1) % dnetp->max_rx_desc;
1806bdb9230aSGarrett D'Amore
1807bdb9230aSGarrett D'Amore /* Demand polling by chip */
1808bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle,
1809bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, RX_POLL_REG), RX_POLL_DEMAND);
1810bdb9230aSGarrett D'Amore
1811bdb9230aSGarrett D'Amore /* send the packet upstream */
1812bdb9230aSGarrett D'Amore mutex_exit(&dnetp->intrlock);
181398e8d175SSteven Stallion mac_rx(dnetp->mac_handle, NULL, mp);
1814bdb9230aSGarrett D'Amore mutex_enter(&dnetp->intrlock);
1815bdb9230aSGarrett D'Amore }
1816bdb9230aSGarrett D'Amore }
1817bdb9230aSGarrett D'Amore /*
1818bdb9230aSGarrett D'Amore * Function to update receive statistics
1819bdb9230aSGarrett D'Amore */
1820bdb9230aSGarrett D'Amore static void
update_rx_stats(struct dnetinstance * dnetp,int index)182198e8d175SSteven Stallion update_rx_stats(struct dnetinstance *dnetp, int index)
1822bdb9230aSGarrett D'Amore {
1823bdb9230aSGarrett D'Amore struct rx_desc_type *descp = &(dnetp->rx_desc[index]);
1824bdb9230aSGarrett D'Amore
1825bdb9230aSGarrett D'Amore /*
1826bdb9230aSGarrett D'Amore * Update gld statistics
1827bdb9230aSGarrett D'Amore */
1828bdb9230aSGarrett D'Amore dnetp->stat_errrcv++;
1829bdb9230aSGarrett D'Amore
1830bdb9230aSGarrett D'Amore if (descp->desc0.overflow) {
1831bdb9230aSGarrett D'Amore /* FIFO Overrun */
1832bdb9230aSGarrett D'Amore dnetp->stat_overflow++;
1833bdb9230aSGarrett D'Amore }
1834bdb9230aSGarrett D'Amore
1835bdb9230aSGarrett D'Amore if (descp->desc0.collision) {
1836bdb9230aSGarrett D'Amore /*EMPTY*/
1837bdb9230aSGarrett D'Amore /* Late Colllision on receive */
1838bdb9230aSGarrett D'Amore /* no appropriate counter */
1839bdb9230aSGarrett D'Amore }
1840bdb9230aSGarrett D'Amore
1841bdb9230aSGarrett D'Amore if (descp->desc0.crc) {
1842bdb9230aSGarrett D'Amore /* CRC Error */
1843bdb9230aSGarrett D'Amore dnetp->stat_crc++;
1844bdb9230aSGarrett D'Amore }
1845bdb9230aSGarrett D'Amore
1846bdb9230aSGarrett D'Amore if (descp->desc0.runt_frame) {
1847bdb9230aSGarrett D'Amore /* Runt Error */
1848bdb9230aSGarrett D'Amore dnetp->stat_short++;
1849bdb9230aSGarrett D'Amore }
1850bdb9230aSGarrett D'Amore
1851bdb9230aSGarrett D'Amore if (descp->desc0.desc_err) {
1852bdb9230aSGarrett D'Amore /*EMPTY*/
1853bdb9230aSGarrett D'Amore /* Not enough receive descriptors */
185498e8d175SSteven Stallion /* This condition is accounted in dnet_intr() */
1855bdb9230aSGarrett D'Amore }
1856bdb9230aSGarrett D'Amore
1857bdb9230aSGarrett D'Amore if (descp->desc0.frame2long) {
1858bdb9230aSGarrett D'Amore dnetp->stat_frame++;
1859bdb9230aSGarrett D'Amore }
1860bdb9230aSGarrett D'Amore }
1861bdb9230aSGarrett D'Amore
1862bdb9230aSGarrett D'Amore /*
1863bdb9230aSGarrett D'Amore * Function to update transmit statistics
1864bdb9230aSGarrett D'Amore */
1865bdb9230aSGarrett D'Amore static void
update_tx_stats(struct dnetinstance * dnetp,int index)186698e8d175SSteven Stallion update_tx_stats(struct dnetinstance *dnetp, int index)
1867bdb9230aSGarrett D'Amore {
1868bdb9230aSGarrett D'Amore struct tx_desc_type *descp = &(dnetp->tx_desc[index]);
1869bdb9230aSGarrett D'Amore int fd;
1870bdb9230aSGarrett D'Amore media_block_t *block = dnetp->selected_media_block;
1871bdb9230aSGarrett D'Amore
1872bdb9230aSGarrett D'Amore
1873bdb9230aSGarrett D'Amore /* Update gld statistics */
1874bdb9230aSGarrett D'Amore dnetp->stat_errxmt++;
1875bdb9230aSGarrett D'Amore
1876bdb9230aSGarrett D'Amore /* If we're in full-duplex don't count collisions or carrier loss. */
1877bdb9230aSGarrett D'Amore if (dnetp->mii_up) {
1878bdb9230aSGarrett D'Amore fd = dnetp->mii_duplex;
1879bdb9230aSGarrett D'Amore } else {
1880bdb9230aSGarrett D'Amore /* Rely on media code */
1881bdb9230aSGarrett D'Amore fd = block->media_code == MEDIA_TP_FD ||
1882bdb9230aSGarrett D'Amore block->media_code == MEDIA_SYM_SCR_FD;
1883bdb9230aSGarrett D'Amore }
1884bdb9230aSGarrett D'Amore
1885bdb9230aSGarrett D'Amore if (descp->desc0.collision_count && !fd) {
1886bdb9230aSGarrett D'Amore dnetp->stat_collisions += descp->desc0.collision_count;
1887bdb9230aSGarrett D'Amore }
1888bdb9230aSGarrett D'Amore
1889bdb9230aSGarrett D'Amore if (descp->desc0.late_collision && !fd) {
1890bdb9230aSGarrett D'Amore dnetp->stat_xmtlatecoll++;
1891bdb9230aSGarrett D'Amore }
1892bdb9230aSGarrett D'Amore
1893bdb9230aSGarrett D'Amore if (descp->desc0.excess_collision && !fd) {
1894bdb9230aSGarrett D'Amore dnetp->stat_excoll++;
1895bdb9230aSGarrett D'Amore }
1896bdb9230aSGarrett D'Amore
1897bdb9230aSGarrett D'Amore if (descp->desc0.underflow) {
1898bdb9230aSGarrett D'Amore dnetp->stat_underflow++;
1899bdb9230aSGarrett D'Amore }
1900bdb9230aSGarrett D'Amore
1901bdb9230aSGarrett D'Amore #if 0
1902bdb9230aSGarrett D'Amore if (descp->desc0.tx_jabber_to) {
1903bdb9230aSGarrett D'Amore /* no appropriate counter */
1904bdb9230aSGarrett D'Amore }
1905bdb9230aSGarrett D'Amore #endif
1906bdb9230aSGarrett D'Amore
1907bdb9230aSGarrett D'Amore if (descp->desc0.carrier_loss && !fd) {
1908bdb9230aSGarrett D'Amore dnetp->stat_nocarrier++;
1909bdb9230aSGarrett D'Amore }
1910bdb9230aSGarrett D'Amore
1911bdb9230aSGarrett D'Amore if (descp->desc0.no_carrier && !fd) {
1912bdb9230aSGarrett D'Amore dnetp->stat_nocarrier++;
1913bdb9230aSGarrett D'Amore }
1914bdb9230aSGarrett D'Amore }
1915bdb9230aSGarrett D'Amore
1916bdb9230aSGarrett D'Amore /*
1917bdb9230aSGarrett D'Amore * ========== Media Selection Setup Routines ==========
1918bdb9230aSGarrett D'Amore */
1919bdb9230aSGarrett D'Amore
1920bdb9230aSGarrett D'Amore
1921bdb9230aSGarrett D'Amore static void
write_gpr(struct dnetinstance * dnetp,uint32_t val)1922bdb9230aSGarrett D'Amore write_gpr(struct dnetinstance *dnetp, uint32_t val)
1923bdb9230aSGarrett D'Amore {
1924bdb9230aSGarrett D'Amore #ifdef DEBUG
1925bdb9230aSGarrett D'Amore if (dnetdebug & DNETREGCFG)
1926bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "GPR: %x", val);
1927bdb9230aSGarrett D'Amore #endif
1928bdb9230aSGarrett D'Amore switch (dnetp->board_type) {
1929bdb9230aSGarrett D'Amore case DEVICE_ID_21143:
1930bdb9230aSGarrett D'Amore /* Set the correct bit for a control write */
1931bdb9230aSGarrett D'Amore if (val & GPR_CONTROL_WRITE)
1932bdb9230aSGarrett D'Amore val |= CWE_21143, val &= ~GPR_CONTROL_WRITE;
1933bdb9230aSGarrett D'Amore /* Write to upper half of CSR15 */
1934bdb9230aSGarrett D'Amore dnetp->gprsia = (dnetp->gprsia & 0xffff) | (val << 16);
1935bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle,
1936bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, SIA_GENERAL_REG), dnetp->gprsia);
1937bdb9230aSGarrett D'Amore break;
1938bdb9230aSGarrett D'Amore default:
1939bdb9230aSGarrett D'Amore /* Set the correct bit for a control write */
1940bdb9230aSGarrett D'Amore if (val & GPR_CONTROL_WRITE)
1941bdb9230aSGarrett D'Amore val |= CWE_21140, val &= ~GPR_CONTROL_WRITE;
1942bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, GP_REG), val);
1943bdb9230aSGarrett D'Amore break;
1944bdb9230aSGarrett D'Amore }
1945bdb9230aSGarrett D'Amore }
1946bdb9230aSGarrett D'Amore
1947bdb9230aSGarrett D'Amore static uint32_t
read_gpr(struct dnetinstance * dnetp)1948bdb9230aSGarrett D'Amore read_gpr(struct dnetinstance *dnetp)
1949bdb9230aSGarrett D'Amore {
1950bdb9230aSGarrett D'Amore switch (dnetp->board_type) {
1951bdb9230aSGarrett D'Amore case DEVICE_ID_21143:
1952bdb9230aSGarrett D'Amore /* Read upper half of CSR15 */
1953bdb9230aSGarrett D'Amore return (ddi_get32(dnetp->io_handle,
1954bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, SIA_GENERAL_REG)) >> 16);
1955bdb9230aSGarrett D'Amore default:
1956bdb9230aSGarrett D'Amore return (ddi_get32(dnetp->io_handle,
1957bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, GP_REG)));
1958bdb9230aSGarrett D'Amore }
1959bdb9230aSGarrett D'Amore }
1960bdb9230aSGarrett D'Amore
1961bdb9230aSGarrett D'Amore static void
set_gpr(struct dnetinstance * dnetp)196298e8d175SSteven Stallion set_gpr(struct dnetinstance *dnetp)
1963bdb9230aSGarrett D'Amore {
1964bdb9230aSGarrett D'Amore uint32_t *sequence;
1965bdb9230aSGarrett D'Amore int len;
1966bdb9230aSGarrett D'Amore LEAF_FORMAT *leaf = &dnetp->sr.leaf[dnetp->leaf];
1967bdb9230aSGarrett D'Amore media_block_t *block = dnetp->selected_media_block;
1968bdb9230aSGarrett D'Amore int i;
1969bdb9230aSGarrett D'Amore
1970bdb9230aSGarrett D'Amore if (ddi_getlongprop(DDI_DEV_T_ANY, dnetp->devinfo,
1971bdb9230aSGarrett D'Amore DDI_PROP_DONTPASS, "gpr-sequence", (caddr_t)&sequence,
1972bdb9230aSGarrett D'Amore &len) == DDI_PROP_SUCCESS) {
1973bdb9230aSGarrett D'Amore for (i = 0; i < len / sizeof (uint32_t); i++)
1974bdb9230aSGarrett D'Amore write_gpr(dnetp, sequence[i]);
1975bdb9230aSGarrett D'Amore kmem_free(sequence, len);
1976bdb9230aSGarrett D'Amore } else {
1977bdb9230aSGarrett D'Amore /*
1978bdb9230aSGarrett D'Amore * Write the reset sequence if this is the first time this
1979bdb9230aSGarrett D'Amore * block has been selected.
1980bdb9230aSGarrett D'Amore */
1981bdb9230aSGarrett D'Amore if (block->rstseqlen) {
1982bdb9230aSGarrett D'Amore for (i = 0; i < block->rstseqlen; i++)
1983bdb9230aSGarrett D'Amore write_gpr(dnetp, block->rstseq[i]);
1984bdb9230aSGarrett D'Amore /*
1985bdb9230aSGarrett D'Amore * XXX Legacy blocks do not have reset sequences, so the
1986bdb9230aSGarrett D'Amore * static blocks will never be modified by this
1987bdb9230aSGarrett D'Amore */
1988bdb9230aSGarrett D'Amore block->rstseqlen = 0;
1989bdb9230aSGarrett D'Amore }
1990bdb9230aSGarrett D'Amore if (leaf->gpr)
1991bdb9230aSGarrett D'Amore write_gpr(dnetp, leaf->gpr | GPR_CONTROL_WRITE);
1992bdb9230aSGarrett D'Amore
1993bdb9230aSGarrett D'Amore /* write GPR sequence each time */
1994bdb9230aSGarrett D'Amore for (i = 0; i < block->gprseqlen; i++)
1995bdb9230aSGarrett D'Amore write_gpr(dnetp, block->gprseq[i]);
1996bdb9230aSGarrett D'Amore }
1997bdb9230aSGarrett D'Amore
1998bdb9230aSGarrett D'Amore /* This has possibly caused a PHY to reset. Let MII know */
1999bdb9230aSGarrett D'Amore if (dnetp->phyaddr != -1)
2000bdb9230aSGarrett D'Amore /* XXX function return value ignored */
2001bdb9230aSGarrett D'Amore (void) mii_sync(dnetp->mii, dnetp->phyaddr);
2002bdb9230aSGarrett D'Amore drv_usecwait(5);
2003bdb9230aSGarrett D'Amore }
2004bdb9230aSGarrett D'Amore
2005bdb9230aSGarrett D'Amore /* set_opr() - must be called with intrlock held */
2006bdb9230aSGarrett D'Amore
2007bdb9230aSGarrett D'Amore static void
set_opr(struct dnetinstance * dnetp)200898e8d175SSteven Stallion set_opr(struct dnetinstance *dnetp)
2009bdb9230aSGarrett D'Amore {
2010bdb9230aSGarrett D'Amore uint32_t fd, mb1, sf;
2011bdb9230aSGarrett D'Amore
2012bdb9230aSGarrett D'Amore int opnmode_len;
2013bdb9230aSGarrett D'Amore uint32_t val;
2014bdb9230aSGarrett D'Amore media_block_t *block = dnetp->selected_media_block;
2015bdb9230aSGarrett D'Amore
2016bdb9230aSGarrett D'Amore ASSERT(block);
2017bdb9230aSGarrett D'Amore
2018bdb9230aSGarrett D'Amore /* Check for custom "opnmode_reg" property */
2019bdb9230aSGarrett D'Amore opnmode_len = sizeof (val);
2020bdb9230aSGarrett D'Amore if (ddi_prop_op(DDI_DEV_T_ANY, dnetp->devinfo,
2021bdb9230aSGarrett D'Amore PROP_LEN_AND_VAL_BUF, DDI_PROP_DONTPASS, "opnmode_reg",
2022bdb9230aSGarrett D'Amore (caddr_t)&val, &opnmode_len) != DDI_PROP_SUCCESS)
2023bdb9230aSGarrett D'Amore opnmode_len = 0;
2024bdb9230aSGarrett D'Amore
2025bdb9230aSGarrett D'Amore /* Some bits exist only on 21140 and greater */
2026bdb9230aSGarrett D'Amore if (dnetp->board_type != DEVICE_ID_21040 &&
2027bdb9230aSGarrett D'Amore dnetp->board_type != DEVICE_ID_21041) {
2028bdb9230aSGarrett D'Amore mb1 = OPN_REG_MB1;
2029bdb9230aSGarrett D'Amore sf = STORE_AND_FORWARD;
2030bdb9230aSGarrett D'Amore } else {
2031bdb9230aSGarrett D'Amore mb1 = sf = 0;
2032bdb9230aSGarrett D'Amore mb1 = OPN_REG_MB1; /* Needed for 21040? */
2033bdb9230aSGarrett D'Amore }
2034bdb9230aSGarrett D'Amore
2035bdb9230aSGarrett D'Amore if (opnmode_len) {
2036bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle,
2037bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, OPN_MODE_REG), val);
203898e8d175SSteven Stallion dnet_reset_board(dnetp);
2039bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle,
2040bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, OPN_MODE_REG), val);
2041bdb9230aSGarrett D'Amore return;
2042bdb9230aSGarrett D'Amore }
2043bdb9230aSGarrett D'Amore
2044bdb9230aSGarrett D'Amore /*
2045bdb9230aSGarrett D'Amore * Set each bit in CSR6 that we want
2046bdb9230aSGarrett D'Amore */
2047bdb9230aSGarrett D'Amore
2048bdb9230aSGarrett D'Amore /* Always want these bits set */
2049bdb9230aSGarrett D'Amore val = HASH_FILTERING | HASH_ONLY | TX_THRESHOLD_160 | mb1 | sf;
2050bdb9230aSGarrett D'Amore
2051bdb9230aSGarrett D'Amore /* Promiscuous mode */
2052bdb9230aSGarrett D'Amore val |= dnetp->promisc ? PROM_MODE : 0;
2053bdb9230aSGarrett D'Amore
2054bdb9230aSGarrett D'Amore /* Scrambler for SYM style media */
2055bdb9230aSGarrett D'Amore val |= ((block->command & CMD_SCR) && !dnetp->disable_scrambler) ?
2056bdb9230aSGarrett D'Amore SCRAMBLER_MODE : 0;
2057bdb9230aSGarrett D'Amore
2058bdb9230aSGarrett D'Amore /* Full duplex */
2059bdb9230aSGarrett D'Amore if (dnetp->mii_up) {
2060bdb9230aSGarrett D'Amore fd = dnetp->mii_duplex;
2061bdb9230aSGarrett D'Amore } else {
2062bdb9230aSGarrett D'Amore /* Rely on media code */
2063bdb9230aSGarrett D'Amore fd = block->media_code == MEDIA_TP_FD ||
2064bdb9230aSGarrett D'Amore block->media_code == MEDIA_SYM_SCR_FD;
2065bdb9230aSGarrett D'Amore }
2066bdb9230aSGarrett D'Amore
2067bdb9230aSGarrett D'Amore /* Port select (and therefore, heartbeat disable) */
2068bdb9230aSGarrett D'Amore val |= block->command & CMD_PS ? (PORT_SELECT | HEARTBEAT_DISABLE) : 0;
2069bdb9230aSGarrett D'Amore
2070bdb9230aSGarrett D'Amore /* PCS function */
2071bdb9230aSGarrett D'Amore val |= (block->command) & CMD_PCS ? PCS_FUNCTION : 0;
2072bdb9230aSGarrett D'Amore val |= fd ? FULL_DUPLEX : 0;
2073bdb9230aSGarrett D'Amore
2074bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
2075bdb9230aSGarrett D'Amore if (dnetdebug & DNETREGCFG)
2076bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "OPN: %x", val);
2077bdb9230aSGarrett D'Amore #endif
2078bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG), val);
207998e8d175SSteven Stallion dnet_reset_board(dnetp);
2080bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG), val);
2081bdb9230aSGarrett D'Amore }
2082bdb9230aSGarrett D'Amore
2083bdb9230aSGarrett D'Amore static void
set_sia(struct dnetinstance * dnetp)208498e8d175SSteven Stallion set_sia(struct dnetinstance *dnetp)
2085bdb9230aSGarrett D'Amore {
2086bdb9230aSGarrett D'Amore media_block_t *block = dnetp->selected_media_block;
2087bdb9230aSGarrett D'Amore
2088bdb9230aSGarrett D'Amore ASSERT(MUTEX_HELD(&dnetp->intrlock));
2089bdb9230aSGarrett D'Amore if (block->type == 2) {
2090bdb9230aSGarrett D'Amore int sia_delay;
2091bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
2092bdb9230aSGarrett D'Amore if (dnetdebug & DNETREGCFG)
2093bdb9230aSGarrett D'Amore cmn_err(CE_NOTE,
2094bdb9230aSGarrett D'Amore "SIA: CSR13: %x, CSR14: %x, CSR15: %x",
2095bdb9230aSGarrett D'Amore block->un.sia.csr13,
2096bdb9230aSGarrett D'Amore block->un.sia.csr14,
2097bdb9230aSGarrett D'Amore block->un.sia.csr15);
2098bdb9230aSGarrett D'Amore #endif
2099bdb9230aSGarrett D'Amore sia_delay = ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo,
2100bdb9230aSGarrett D'Amore DDI_PROP_DONTPASS, "sia-delay", 10000);
2101bdb9230aSGarrett D'Amore
2102bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle,
2103bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, SIA_CONNECT_REG), 0);
2104bdb9230aSGarrett D'Amore
2105bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, SIA_TXRX_REG),
2106bdb9230aSGarrett D'Amore block->un.sia.csr14);
2107bdb9230aSGarrett D'Amore
2108bdb9230aSGarrett D'Amore /*
2109bdb9230aSGarrett D'Amore * For '143, we need to write through a copy of the register
2110bdb9230aSGarrett D'Amore * to keep the GP half intact
2111bdb9230aSGarrett D'Amore */
2112bdb9230aSGarrett D'Amore dnetp->gprsia = (dnetp->gprsia&0xffff0000)|block->un.sia.csr15;
2113bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle,
2114bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, SIA_GENERAL_REG),
2115bdb9230aSGarrett D'Amore dnetp->gprsia);
2116bdb9230aSGarrett D'Amore
2117bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle,
2118bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, SIA_CONNECT_REG),
2119bdb9230aSGarrett D'Amore block->un.sia.csr13);
2120bdb9230aSGarrett D'Amore
2121bdb9230aSGarrett D'Amore drv_usecwait(sia_delay);
2122bdb9230aSGarrett D'Amore
2123bdb9230aSGarrett D'Amore } else if (dnetp->board_type != DEVICE_ID_21140) {
2124bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle,
2125bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, SIA_CONNECT_REG), 0);
2126bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle,
2127bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, SIA_TXRX_REG), 0);
2128bdb9230aSGarrett D'Amore }
2129bdb9230aSGarrett D'Amore }
2130bdb9230aSGarrett D'Amore
2131bdb9230aSGarrett D'Amore /*
2132bdb9230aSGarrett D'Amore * This function (re)allocates the receive and transmit buffers and
2133bdb9230aSGarrett D'Amore * descriptors. It can be called more than once per instance, though
2134bdb9230aSGarrett D'Amore * currently it is only called from attach. It should only be called
2135bdb9230aSGarrett D'Amore * while the device is reset.
2136bdb9230aSGarrett D'Amore */
2137bdb9230aSGarrett D'Amore static int
dnet_alloc_bufs(struct dnetinstance * dnetp)213898e8d175SSteven Stallion dnet_alloc_bufs(struct dnetinstance *dnetp)
2139bdb9230aSGarrett D'Amore {
2140bdb9230aSGarrett D'Amore int i;
2141bdb9230aSGarrett D'Amore size_t len;
2142bdb9230aSGarrett D'Amore int page_size;
2143bdb9230aSGarrett D'Amore int realloc = 0;
2144bdb9230aSGarrett D'Amore int nrecv_desc_old = 0;
2145bdb9230aSGarrett D'Amore ddi_dma_cookie_t cookie;
2146bdb9230aSGarrett D'Amore uint_t ncookies;
2147bdb9230aSGarrett D'Amore
2148bdb9230aSGarrett D'Amore /*
2149bdb9230aSGarrett D'Amore * check if we are trying to reallocate with different xmit/recv
2150bdb9230aSGarrett D'Amore * descriptor ring sizes.
2151bdb9230aSGarrett D'Amore */
2152bdb9230aSGarrett D'Amore if ((dnetp->tx_desc != NULL) &&
2153bdb9230aSGarrett D'Amore (dnetp->nxmit_desc != dnetp->max_tx_desc))
2154bdb9230aSGarrett D'Amore realloc = 1;
2155bdb9230aSGarrett D'Amore
2156bdb9230aSGarrett D'Amore if ((dnetp->rx_desc != NULL) &&
2157bdb9230aSGarrett D'Amore (dnetp->nrecv_desc != dnetp->max_rx_desc))
2158bdb9230aSGarrett D'Amore realloc = 1;
2159bdb9230aSGarrett D'Amore
2160bdb9230aSGarrett D'Amore /* free up the old buffers if we are reallocating them */
2161bdb9230aSGarrett D'Amore if (realloc) {
2162bdb9230aSGarrett D'Amore nrecv_desc_old = dnetp->nrecv_desc;
216398e8d175SSteven Stallion dnet_free_bufs(dnetp); /* free the old buffers */
2164bdb9230aSGarrett D'Amore }
2165bdb9230aSGarrett D'Amore
2166bdb9230aSGarrett D'Amore if (dnetp->dma_handle == NULL)
2167bdb9230aSGarrett D'Amore if (ddi_dma_alloc_handle(dnetp->devinfo, &dma_attr,
2168bdb9230aSGarrett D'Amore DDI_DMA_SLEEP, 0, &dnetp->dma_handle) != DDI_SUCCESS)
2169bdb9230aSGarrett D'Amore return (FAILURE);
2170bdb9230aSGarrett D'Amore
2171bdb9230aSGarrett D'Amore if (dnetp->dma_handle_tx == NULL)
2172bdb9230aSGarrett D'Amore if (ddi_dma_alloc_handle(dnetp->devinfo, &dma_attr_tx,
2173bdb9230aSGarrett D'Amore DDI_DMA_SLEEP, 0, &dnetp->dma_handle_tx) != DDI_SUCCESS)
2174bdb9230aSGarrett D'Amore return (FAILURE);
2175bdb9230aSGarrett D'Amore
2176bdb9230aSGarrett D'Amore if (dnetp->dma_handle_txdesc == NULL)
2177bdb9230aSGarrett D'Amore if (ddi_dma_alloc_handle(dnetp->devinfo, &dma_attr,
2178bdb9230aSGarrett D'Amore DDI_DMA_SLEEP, 0, &dnetp->dma_handle_txdesc) != DDI_SUCCESS)
2179bdb9230aSGarrett D'Amore return (FAILURE);
2180bdb9230aSGarrett D'Amore
2181bdb9230aSGarrett D'Amore if (dnetp->dma_handle_setbuf == NULL)
2182bdb9230aSGarrett D'Amore if (ddi_dma_alloc_handle(dnetp->devinfo, &dma_attr,
2183bdb9230aSGarrett D'Amore DDI_DMA_SLEEP, 0, &dnetp->dma_handle_setbuf) != DDI_SUCCESS)
2184bdb9230aSGarrett D'Amore return (FAILURE);
2185bdb9230aSGarrett D'Amore
2186bdb9230aSGarrett D'Amore page_size = ddi_ptob(dnetp->devinfo, 1);
2187bdb9230aSGarrett D'Amore
2188bdb9230aSGarrett D'Amore dnetp->pgmask = page_size - 1;
2189bdb9230aSGarrett D'Amore
2190bdb9230aSGarrett D'Amore /* allocate setup buffer if necessary */
2191bdb9230aSGarrett D'Amore if (dnetp->setup_buf_vaddr == NULL) {
2192bdb9230aSGarrett D'Amore if (ddi_dma_mem_alloc(dnetp->dma_handle_setbuf,
2193bdb9230aSGarrett D'Amore SETUPBUF_SIZE, &accattr, DDI_DMA_STREAMING,
2194bdb9230aSGarrett D'Amore DDI_DMA_DONTWAIT, 0, (caddr_t *)&dnetp->setup_buf_vaddr,
2195bdb9230aSGarrett D'Amore &len, &dnetp->setup_buf_acchdl) != DDI_SUCCESS)
2196bdb9230aSGarrett D'Amore return (FAILURE);
2197bdb9230aSGarrett D'Amore
2198bdb9230aSGarrett D'Amore if (ddi_dma_addr_bind_handle(dnetp->dma_handle_setbuf,
2199bdb9230aSGarrett D'Amore NULL, dnetp->setup_buf_vaddr, SETUPBUF_SIZE,
2200bdb9230aSGarrett D'Amore DDI_DMA_RDWR | DDI_DMA_STREAMING, DDI_DMA_SLEEP,
2201bdb9230aSGarrett D'Amore NULL, &cookie, &ncookies) != DDI_DMA_MAPPED)
2202bdb9230aSGarrett D'Amore return (FAILURE);
2203bdb9230aSGarrett D'Amore
2204bdb9230aSGarrett D'Amore dnetp->setup_buf_paddr = cookie.dmac_address;
2205bdb9230aSGarrett D'Amore bzero(dnetp->setup_buf_vaddr, len);
2206bdb9230aSGarrett D'Amore }
2207bdb9230aSGarrett D'Amore
2208bdb9230aSGarrett D'Amore /* allocate xmit descriptor array of size dnetp->max_tx_desc */
2209bdb9230aSGarrett D'Amore if (dnetp->tx_desc == NULL) {
2210bdb9230aSGarrett D'Amore if (ddi_dma_mem_alloc(dnetp->dma_handle_txdesc,
2211bdb9230aSGarrett D'Amore sizeof (struct tx_desc_type) * dnetp->max_tx_desc,
2212bdb9230aSGarrett D'Amore &accattr, DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 0,
2213bdb9230aSGarrett D'Amore (caddr_t *)&dnetp->tx_desc, &len,
2214bdb9230aSGarrett D'Amore &dnetp->tx_desc_acchdl) != DDI_SUCCESS)
2215bdb9230aSGarrett D'Amore return (FAILURE);
2216bdb9230aSGarrett D'Amore
2217bdb9230aSGarrett D'Amore if (ddi_dma_addr_bind_handle(dnetp->dma_handle_txdesc,
2218bdb9230aSGarrett D'Amore NULL, (caddr_t)dnetp->tx_desc,
2219bdb9230aSGarrett D'Amore sizeof (struct tx_desc_type) * dnetp->max_tx_desc,
2220bdb9230aSGarrett D'Amore DDI_DMA_RDWR | DDI_DMA_STREAMING, DDI_DMA_SLEEP,
2221bdb9230aSGarrett D'Amore NULL, &cookie, &ncookies) != DDI_DMA_MAPPED)
2222bdb9230aSGarrett D'Amore return (FAILURE);
2223bdb9230aSGarrett D'Amore dnetp->tx_desc_paddr = cookie.dmac_address;
2224bdb9230aSGarrett D'Amore bzero(dnetp->tx_desc, len);
2225bdb9230aSGarrett D'Amore dnetp->nxmit_desc = dnetp->max_tx_desc;
2226bdb9230aSGarrett D'Amore
2227bdb9230aSGarrett D'Amore dnetp->tx_msgbufp =
2228bdb9230aSGarrett D'Amore kmem_zalloc(dnetp->max_tx_desc * sizeof (mblk_t **),
2229bdb9230aSGarrett D'Amore KM_SLEEP);
2230bdb9230aSGarrett D'Amore }
2231bdb9230aSGarrett D'Amore
2232bdb9230aSGarrett D'Amore /* allocate receive descriptor array of size dnetp->max_rx_desc */
2233bdb9230aSGarrett D'Amore if (dnetp->rx_desc == NULL) {
2234bdb9230aSGarrett D'Amore int ndesc;
2235bdb9230aSGarrett D'Amore
2236bdb9230aSGarrett D'Amore if (ddi_dma_mem_alloc(dnetp->dma_handle,
2237bdb9230aSGarrett D'Amore sizeof (struct rx_desc_type) * dnetp->max_rx_desc,
2238bdb9230aSGarrett D'Amore &accattr, DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 0,
2239bdb9230aSGarrett D'Amore (caddr_t *)&dnetp->rx_desc, &len,
2240bdb9230aSGarrett D'Amore &dnetp->rx_desc_acchdl) != DDI_SUCCESS)
2241bdb9230aSGarrett D'Amore return (FAILURE);
2242bdb9230aSGarrett D'Amore
2243bdb9230aSGarrett D'Amore if (ddi_dma_addr_bind_handle(dnetp->dma_handle,
2244bdb9230aSGarrett D'Amore NULL, (caddr_t)dnetp->rx_desc,
2245bdb9230aSGarrett D'Amore sizeof (struct rx_desc_type) * dnetp->max_rx_desc,
2246bdb9230aSGarrett D'Amore DDI_DMA_RDWR | DDI_DMA_STREAMING, DDI_DMA_SLEEP,
2247bdb9230aSGarrett D'Amore NULL, &cookie, &ncookies) != DDI_DMA_MAPPED)
2248bdb9230aSGarrett D'Amore return (FAILURE);
2249bdb9230aSGarrett D'Amore
2250bdb9230aSGarrett D'Amore dnetp->rx_desc_paddr = cookie.dmac_address;
2251bdb9230aSGarrett D'Amore bzero(dnetp->rx_desc, len);
2252bdb9230aSGarrett D'Amore dnetp->nrecv_desc = dnetp->max_rx_desc;
2253bdb9230aSGarrett D'Amore
2254bdb9230aSGarrett D'Amore dnetp->rx_buf_vaddr =
2255bdb9230aSGarrett D'Amore kmem_zalloc(dnetp->max_rx_desc * sizeof (caddr_t),
2256bdb9230aSGarrett D'Amore KM_SLEEP);
2257bdb9230aSGarrett D'Amore dnetp->rx_buf_paddr =
2258bdb9230aSGarrett D'Amore kmem_zalloc(dnetp->max_rx_desc * sizeof (uint32_t),
2259bdb9230aSGarrett D'Amore KM_SLEEP);
2260bdb9230aSGarrett D'Amore /*
2261bdb9230aSGarrett D'Amore * Allocate or add to the pool of receive buffers. The pool
2262bdb9230aSGarrett D'Amore * is shared among all instances of dnet.
2263bdb9230aSGarrett D'Amore *
2264bdb9230aSGarrett D'Amore * XXX NEEDSWORK
2265bdb9230aSGarrett D'Amore *
2266bdb9230aSGarrett D'Amore * We arbitrarily allocate twice as many receive buffers as
2267bdb9230aSGarrett D'Amore * receive descriptors because we use the buffers for streams
2268bdb9230aSGarrett D'Amore * messages to pass the packets up the stream. We should
2269bdb9230aSGarrett D'Amore * instead have initialized constants reflecting
2270bdb9230aSGarrett D'Amore * MAX_RX_BUF_2104x and MAX_RX_BUF_2114x, and we should also
2271bdb9230aSGarrett D'Amore * probably have a total maximum for the free pool, so that we
2272bdb9230aSGarrett D'Amore * don't get out of hand when someone puts in an 8-port board.
2273bdb9230aSGarrett D'Amore * The maximum for the entire pool should be the total number
2274bdb9230aSGarrett D'Amore * of descriptors for all attached instances together, plus the
2275bdb9230aSGarrett D'Amore * total maximum for the free pool. This maximum would only be
2276bdb9230aSGarrett D'Amore * reached after some number of instances allocate buffers:
2277bdb9230aSGarrett D'Amore * each instance would add (max_rx_buf-max_rx_desc) to the free
2278bdb9230aSGarrett D'Amore * pool.
2279bdb9230aSGarrett D'Amore */
2280bdb9230aSGarrett D'Amore ndesc = dnetp->max_rx_desc - nrecv_desc_old;
2281bdb9230aSGarrett D'Amore if ((ndesc > 0) &&
2282bdb9230aSGarrett D'Amore (dnet_rbuf_init(dnetp->devinfo, ndesc * 2) != 0))
2283bdb9230aSGarrett D'Amore return (FAILURE);
2284bdb9230aSGarrett D'Amore
2285bdb9230aSGarrett D'Amore for (i = 0; i < dnetp->max_rx_desc; i++) {
2286bdb9230aSGarrett D'Amore struct rbuf_list *rp;
2287bdb9230aSGarrett D'Amore
2288bdb9230aSGarrett D'Amore rp = dnet_rbuf_alloc(dnetp->devinfo, 1);
2289bdb9230aSGarrett D'Amore if (rp == NULL)
2290bdb9230aSGarrett D'Amore return (FAILURE);
2291bdb9230aSGarrett D'Amore dnetp->rx_buf_vaddr[i] = rp->rbuf_vaddr;
2292bdb9230aSGarrett D'Amore dnetp->rx_buf_paddr[i] = rp->rbuf_paddr;
2293bdb9230aSGarrett D'Amore }
2294bdb9230aSGarrett D'Amore }
2295bdb9230aSGarrett D'Amore
2296bdb9230aSGarrett D'Amore return (SUCCESS);
2297bdb9230aSGarrett D'Amore }
2298bdb9230aSGarrett D'Amore /*
2299bdb9230aSGarrett D'Amore * free descriptors/buffers allocated for this device instance. This routine
2300bdb9230aSGarrett D'Amore * should only be called while the device is reset.
2301bdb9230aSGarrett D'Amore */
2302bdb9230aSGarrett D'Amore static void
dnet_free_bufs(struct dnetinstance * dnetp)230398e8d175SSteven Stallion dnet_free_bufs(struct dnetinstance *dnetp)
2304bdb9230aSGarrett D'Amore {
2305bdb9230aSGarrett D'Amore int i;
2306bdb9230aSGarrett D'Amore /* free up any xmit descriptors/buffers */
2307bdb9230aSGarrett D'Amore if (dnetp->tx_desc != NULL) {
2308bdb9230aSGarrett D'Amore ddi_dma_mem_free(&dnetp->tx_desc_acchdl);
2309bdb9230aSGarrett D'Amore dnetp->tx_desc = NULL;
2310bdb9230aSGarrett D'Amore /* we use streams buffers for DMA in xmit process */
2311bdb9230aSGarrett D'Amore if (dnetp->tx_msgbufp != NULL) {
2312bdb9230aSGarrett D'Amore /* free up any streams message buffers unclaimed */
2313bdb9230aSGarrett D'Amore for (i = 0; i < dnetp->nxmit_desc; i++) {
2314bdb9230aSGarrett D'Amore if (dnetp->tx_msgbufp[i] != NULL) {
2315bdb9230aSGarrett D'Amore freemsg(dnetp->tx_msgbufp[i]);
2316bdb9230aSGarrett D'Amore }
2317bdb9230aSGarrett D'Amore }
2318bdb9230aSGarrett D'Amore kmem_free(dnetp->tx_msgbufp,
2319bdb9230aSGarrett D'Amore dnetp->nxmit_desc * sizeof (mblk_t **));
2320bdb9230aSGarrett D'Amore dnetp->tx_msgbufp = NULL;
2321bdb9230aSGarrett D'Amore }
2322bdb9230aSGarrett D'Amore dnetp->nxmit_desc = 0;
2323bdb9230aSGarrett D'Amore }
2324bdb9230aSGarrett D'Amore
2325bdb9230aSGarrett D'Amore /* free up any receive descriptors/buffers */
2326bdb9230aSGarrett D'Amore if (dnetp->rx_desc != NULL) {
2327bdb9230aSGarrett D'Amore ddi_dma_mem_free(&dnetp->rx_desc_acchdl);
2328bdb9230aSGarrett D'Amore dnetp->rx_desc = NULL;
2329bdb9230aSGarrett D'Amore if (dnetp->rx_buf_vaddr != NULL) {
2330bdb9230aSGarrett D'Amore /* free up the attached rbufs if any */
2331bdb9230aSGarrett D'Amore for (i = 0; i < dnetp->nrecv_desc; i++) {
2332bdb9230aSGarrett D'Amore if (dnetp->rx_buf_vaddr[i])
2333bdb9230aSGarrett D'Amore dnet_rbuf_free(
2334bdb9230aSGarrett D'Amore (caddr_t)dnetp->rx_buf_vaddr[i]);
2335bdb9230aSGarrett D'Amore }
2336bdb9230aSGarrett D'Amore kmem_free(dnetp->rx_buf_vaddr,
2337bdb9230aSGarrett D'Amore dnetp->nrecv_desc * sizeof (caddr_t));
2338bdb9230aSGarrett D'Amore kmem_free(dnetp->rx_buf_paddr,
2339bdb9230aSGarrett D'Amore dnetp->nrecv_desc * sizeof (uint32_t));
2340bdb9230aSGarrett D'Amore dnetp->rx_buf_vaddr = NULL;
2341bdb9230aSGarrett D'Amore dnetp->rx_buf_paddr = NULL;
2342bdb9230aSGarrett D'Amore }
2343bdb9230aSGarrett D'Amore dnetp->nrecv_desc = 0;
2344bdb9230aSGarrett D'Amore }
2345bdb9230aSGarrett D'Amore
2346bdb9230aSGarrett D'Amore if (dnetp->setup_buf_vaddr != NULL) {
2347bdb9230aSGarrett D'Amore ddi_dma_mem_free(&dnetp->setup_buf_acchdl);
2348bdb9230aSGarrett D'Amore dnetp->setup_buf_vaddr = NULL;
2349bdb9230aSGarrett D'Amore }
2350bdb9230aSGarrett D'Amore
2351bdb9230aSGarrett D'Amore if (dnetp->dma_handle != NULL) {
2352bdb9230aSGarrett D'Amore (void) ddi_dma_unbind_handle(dnetp->dma_handle);
2353bdb9230aSGarrett D'Amore ddi_dma_free_handle(&dnetp->dma_handle);
2354bdb9230aSGarrett D'Amore dnetp->dma_handle = NULL;
2355bdb9230aSGarrett D'Amore }
2356bdb9230aSGarrett D'Amore
2357bdb9230aSGarrett D'Amore if (dnetp->dma_handle_tx != NULL) {
2358bdb9230aSGarrett D'Amore (void) ddi_dma_unbind_handle(dnetp->dma_handle_tx);
2359bdb9230aSGarrett D'Amore ddi_dma_free_handle(&dnetp->dma_handle_tx);
2360bdb9230aSGarrett D'Amore dnetp->dma_handle_tx = NULL;
2361bdb9230aSGarrett D'Amore }
2362bdb9230aSGarrett D'Amore
2363bdb9230aSGarrett D'Amore if (dnetp->dma_handle_txdesc != NULL) {
2364bdb9230aSGarrett D'Amore (void) ddi_dma_unbind_handle(dnetp->dma_handle_txdesc);
2365bdb9230aSGarrett D'Amore ddi_dma_free_handle(&dnetp->dma_handle_txdesc);
2366bdb9230aSGarrett D'Amore dnetp->dma_handle_txdesc = NULL;
2367bdb9230aSGarrett D'Amore }
2368bdb9230aSGarrett D'Amore
2369bdb9230aSGarrett D'Amore if (dnetp->dma_handle_setbuf != NULL) {
2370bdb9230aSGarrett D'Amore (void) ddi_dma_unbind_handle(dnetp->dma_handle_setbuf);
2371bdb9230aSGarrett D'Amore ddi_dma_free_handle(&dnetp->dma_handle_setbuf);
2372bdb9230aSGarrett D'Amore dnetp->dma_handle_setbuf = NULL;
2373bdb9230aSGarrett D'Amore }
2374bdb9230aSGarrett D'Amore
2375bdb9230aSGarrett D'Amore }
2376bdb9230aSGarrett D'Amore
2377bdb9230aSGarrett D'Amore /*
2378bdb9230aSGarrett D'Amore * Initialize transmit and receive descriptors.
2379bdb9230aSGarrett D'Amore */
2380bdb9230aSGarrett D'Amore static void
dnet_init_txrx_bufs(struct dnetinstance * dnetp)238198e8d175SSteven Stallion dnet_init_txrx_bufs(struct dnetinstance *dnetp)
2382bdb9230aSGarrett D'Amore {
2383bdb9230aSGarrett D'Amore int i;
2384bdb9230aSGarrett D'Amore
2385bdb9230aSGarrett D'Amore /*
2386bdb9230aSGarrett D'Amore * Initilize all the Tx descriptors
2387bdb9230aSGarrett D'Amore */
2388bdb9230aSGarrett D'Amore for (i = 0; i < dnetp->nxmit_desc; i++) {
2389bdb9230aSGarrett D'Amore /*
2390bdb9230aSGarrett D'Amore * We may be resetting the device due to errors,
2391bdb9230aSGarrett D'Amore * so free up any streams message buffer unclaimed.
2392bdb9230aSGarrett D'Amore */
2393bdb9230aSGarrett D'Amore if (dnetp->tx_msgbufp[i] != NULL) {
2394bdb9230aSGarrett D'Amore freemsg(dnetp->tx_msgbufp[i]);
2395bdb9230aSGarrett D'Amore dnetp->tx_msgbufp[i] = NULL;
2396bdb9230aSGarrett D'Amore }
2397bdb9230aSGarrett D'Amore *(uint32_t *)&dnetp->tx_desc[i].desc0 = 0;
2398bdb9230aSGarrett D'Amore *(uint32_t *)&dnetp->tx_desc[i].desc1 = 0;
2399bdb9230aSGarrett D'Amore dnetp->tx_desc[i].buffer1 = 0;
2400bdb9230aSGarrett D'Amore dnetp->tx_desc[i].buffer2 = 0;
2401bdb9230aSGarrett D'Amore }
2402bdb9230aSGarrett D'Amore dnetp->tx_desc[i - 1].desc1.end_of_ring = 1;
2403bdb9230aSGarrett D'Amore
2404bdb9230aSGarrett D'Amore /*
2405bdb9230aSGarrett D'Amore * Initialize the Rx descriptors
2406bdb9230aSGarrett D'Amore */
2407bdb9230aSGarrett D'Amore for (i = 0; i < dnetp->nrecv_desc; i++) {
2408bdb9230aSGarrett D'Amore uint32_t end_paddr;
2409bdb9230aSGarrett D'Amore *(uint32_t *)&dnetp->rx_desc[i].desc0 = 0;
2410bdb9230aSGarrett D'Amore *(uint32_t *)&dnetp->rx_desc[i].desc1 = 0;
2411bdb9230aSGarrett D'Amore dnetp->rx_desc[i].desc0.own = 1;
2412bdb9230aSGarrett D'Amore dnetp->rx_desc[i].desc1.buffer_size1 = rx_buf_size;
2413bdb9230aSGarrett D'Amore dnetp->rx_desc[i].buffer1 = dnetp->rx_buf_paddr[i];
2414bdb9230aSGarrett D'Amore dnetp->rx_desc[i].buffer2 = 0;
2415bdb9230aSGarrett D'Amore end_paddr = dnetp->rx_buf_paddr[i]+rx_buf_size-1;
2416bdb9230aSGarrett D'Amore
2417bdb9230aSGarrett D'Amore if ((dnetp->rx_desc[i].buffer1 & ~dnetp->pgmask) !=
2418bdb9230aSGarrett D'Amore (end_paddr & ~dnetp->pgmask)) {
2419bdb9230aSGarrett D'Amore /* discontiguous */
2420bdb9230aSGarrett D'Amore dnetp->rx_desc[i].buffer2 = end_paddr&~dnetp->pgmask;
2421bdb9230aSGarrett D'Amore dnetp->rx_desc[i].desc1.buffer_size2 =
2422bdb9230aSGarrett D'Amore (end_paddr & dnetp->pgmask) + 1;
2423bdb9230aSGarrett D'Amore dnetp->rx_desc[i].desc1.buffer_size1 =
2424bdb9230aSGarrett D'Amore rx_buf_size-dnetp->rx_desc[i].desc1.buffer_size2;
2425bdb9230aSGarrett D'Amore }
2426bdb9230aSGarrett D'Amore }
2427bdb9230aSGarrett D'Amore dnetp->rx_desc[i - 1].desc1.end_of_ring = 1;
2428bdb9230aSGarrett D'Amore }
2429bdb9230aSGarrett D'Amore
2430bdb9230aSGarrett D'Amore static int
alloc_descriptor(struct dnetinstance * dnetp)243198e8d175SSteven Stallion alloc_descriptor(struct dnetinstance *dnetp)
2432bdb9230aSGarrett D'Amore {
2433bdb9230aSGarrett D'Amore int index;
2434bdb9230aSGarrett D'Amore struct tx_desc_type *ring = dnetp->tx_desc;
2435bdb9230aSGarrett D'Amore
2436bdb9230aSGarrett D'Amore ASSERT(MUTEX_HELD(&dnetp->intrlock));
2437bdb9230aSGarrett D'Amore alloctop:
2438bdb9230aSGarrett D'Amore mutex_enter(&dnetp->txlock);
2439bdb9230aSGarrett D'Amore index = dnetp->tx_current_desc;
2440bdb9230aSGarrett D'Amore
244198e8d175SSteven Stallion dnet_reclaim_Tx_desc(dnetp);
2442bdb9230aSGarrett D'Amore
2443bdb9230aSGarrett D'Amore /* we do have free descriptors, right? */
2444bdb9230aSGarrett D'Amore if (dnetp->free_desc <= 0) {
2445bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
2446bdb9230aSGarrett D'Amore if (dnetdebug & DNETRECV)
2447bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "dnet: Ring buffer is full");
2448bdb9230aSGarrett D'Amore #endif
2449bdb9230aSGarrett D'Amore mutex_exit(&dnetp->txlock);
2450bdb9230aSGarrett D'Amore return (FAILURE);
2451bdb9230aSGarrett D'Amore }
2452bdb9230aSGarrett D'Amore
2453bdb9230aSGarrett D'Amore /* sanity, make sure the next descriptor is free for use (should be) */
2454bdb9230aSGarrett D'Amore if (ring[index].desc0.own) {
2455bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
2456bdb9230aSGarrett D'Amore if (dnetdebug & DNETRECV)
2457bdb9230aSGarrett D'Amore cmn_err(CE_WARN,
2458bdb9230aSGarrett D'Amore "dnet: next descriptor is not free for use");
2459bdb9230aSGarrett D'Amore #endif
2460bdb9230aSGarrett D'Amore mutex_exit(&dnetp->txlock);
2461bdb9230aSGarrett D'Amore return (FAILURE);
2462bdb9230aSGarrett D'Amore }
2463bdb9230aSGarrett D'Amore if (dnetp->need_saddr) {
2464bdb9230aSGarrett D'Amore mutex_exit(&dnetp->txlock);
2465bdb9230aSGarrett D'Amore /* XXX function return value ignored */
2466bdb9230aSGarrett D'Amore if (!dnetp->suspended)
246798e8d175SSteven Stallion (void) dnet_set_addr(dnetp);
2468bdb9230aSGarrett D'Amore goto alloctop;
2469bdb9230aSGarrett D'Amore }
2470bdb9230aSGarrett D'Amore
2471bdb9230aSGarrett D'Amore *(uint32_t *)&ring[index].desc0 = 0; /* init descs */
2472bdb9230aSGarrett D'Amore *(uint32_t *)&ring[index].desc1 &= DNET_END_OF_RING;
2473bdb9230aSGarrett D'Amore
2474bdb9230aSGarrett D'Amore /* hardware will own this descriptor when poll activated */
2475bdb9230aSGarrett D'Amore dnetp->free_desc--;
2476bdb9230aSGarrett D'Amore
2477bdb9230aSGarrett D'Amore /* point to next free descriptor to be used */
2478bdb9230aSGarrett D'Amore dnetp->tx_current_desc = NextTXIndex(index);
2479bdb9230aSGarrett D'Amore
2480bdb9230aSGarrett D'Amore #ifdef DNET_NOISY
2481bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "sfree 0x%x, transmitted 0x%x, tx_current 0x%x",
2482bdb9230aSGarrett D'Amore dnetp->free_desc, dnetp->transmitted_desc, dnetp->tx_current_desc);
2483bdb9230aSGarrett D'Amore #endif
2484bdb9230aSGarrett D'Amore mutex_exit(&dnetp->txlock);
2485bdb9230aSGarrett D'Amore return (SUCCESS);
2486bdb9230aSGarrett D'Amore }
2487bdb9230aSGarrett D'Amore
2488bdb9230aSGarrett D'Amore /*
2489bdb9230aSGarrett D'Amore * dnet_reclaim_Tx_desc() - called with txlock held.
2490bdb9230aSGarrett D'Amore */
2491bdb9230aSGarrett D'Amore static void
dnet_reclaim_Tx_desc(struct dnetinstance * dnetp)249298e8d175SSteven Stallion dnet_reclaim_Tx_desc(struct dnetinstance *dnetp)
2493bdb9230aSGarrett D'Amore {
2494bdb9230aSGarrett D'Amore struct tx_desc_type *desc = dnetp->tx_desc;
2495bdb9230aSGarrett D'Amore int index;
2496bdb9230aSGarrett D'Amore
2497bdb9230aSGarrett D'Amore ASSERT(MUTEX_HELD(&dnetp->txlock));
2498bdb9230aSGarrett D'Amore
2499bdb9230aSGarrett D'Amore index = dnetp->transmitted_desc;
2500bdb9230aSGarrett D'Amore while (((dnetp->free_desc == 0) || (index != dnetp->tx_current_desc)) &&
2501bdb9230aSGarrett D'Amore !(desc[index].desc0.own)) {
2502bdb9230aSGarrett D'Amore /*
2503bdb9230aSGarrett D'Amore * Check for Tx Error that gets set
2504bdb9230aSGarrett D'Amore * in the last desc.
2505bdb9230aSGarrett D'Amore */
2506bdb9230aSGarrett D'Amore if (desc[index].desc1.setup_packet == 0 &&
2507bdb9230aSGarrett D'Amore desc[index].desc1.last_desc &&
2508bdb9230aSGarrett D'Amore desc[index].desc0.err_summary)
250998e8d175SSteven Stallion update_tx_stats(dnetp, index);
2510bdb9230aSGarrett D'Amore
2511bdb9230aSGarrett D'Amore /*
2512bdb9230aSGarrett D'Amore * If we have used the streams message buffer for this
2513bdb9230aSGarrett D'Amore * descriptor then free up the message now.
2514bdb9230aSGarrett D'Amore */
2515bdb9230aSGarrett D'Amore if (dnetp->tx_msgbufp[index] != NULL) {
2516bdb9230aSGarrett D'Amore freemsg(dnetp->tx_msgbufp[index]);
2517bdb9230aSGarrett D'Amore dnetp->tx_msgbufp[index] = NULL;
2518bdb9230aSGarrett D'Amore }
2519bdb9230aSGarrett D'Amore dnetp->free_desc++;
2520bdb9230aSGarrett D'Amore index = (index+1) % dnetp->max_tx_desc;
2521bdb9230aSGarrett D'Amore }
2522bdb9230aSGarrett D'Amore
2523bdb9230aSGarrett D'Amore dnetp->transmitted_desc = index;
2524bdb9230aSGarrett D'Amore }
2525bdb9230aSGarrett D'Amore
2526bdb9230aSGarrett D'Amore /*
2527bdb9230aSGarrett D'Amore * Receive buffer allocation/freeing routines.
2528bdb9230aSGarrett D'Amore *
2529bdb9230aSGarrett D'Amore * There is a common pool of receive buffers shared by all dnet instances.
2530bdb9230aSGarrett D'Amore *
2531bdb9230aSGarrett D'Amore * XXX NEEDSWORK
2532bdb9230aSGarrett D'Amore *
2533bdb9230aSGarrett D'Amore * We arbitrarily allocate twice as many receive buffers as
2534bdb9230aSGarrett D'Amore * receive descriptors because we use the buffers for streams
2535bdb9230aSGarrett D'Amore * messages to pass the packets up the stream. We should
2536bdb9230aSGarrett D'Amore * instead have initialized constants reflecting
2537bdb9230aSGarrett D'Amore * MAX_RX_BUF_2104x and MAX_RX_BUF_2114x, and we should also
2538bdb9230aSGarrett D'Amore * probably have a total maximum for the free pool, so that we
2539bdb9230aSGarrett D'Amore * don't get out of hand when someone puts in an 8-port board.
2540bdb9230aSGarrett D'Amore * The maximum for the entire pool should be the total number
2541bdb9230aSGarrett D'Amore * of descriptors for all attached instances together, plus the
2542bdb9230aSGarrett D'Amore * total maximum for the free pool. This maximum would only be
2543bdb9230aSGarrett D'Amore * reached after some number of instances allocate buffers:
2544bdb9230aSGarrett D'Amore * each instance would add (max_rx_buf-max_rx_desc) to the free
2545bdb9230aSGarrett D'Amore * pool.
2546bdb9230aSGarrett D'Amore */
2547bdb9230aSGarrett D'Amore
2548bdb9230aSGarrett D'Amore static struct rbuf_list *rbuf_usedlist_head;
2549bdb9230aSGarrett D'Amore static struct rbuf_list *rbuf_freelist_head;
2550bdb9230aSGarrett D'Amore static struct rbuf_list *rbuf_usedlist_end; /* last buffer allocated */
2551bdb9230aSGarrett D'Amore
2552bdb9230aSGarrett D'Amore static int rbuf_freebufs; /* no. of free buffers in the pool */
2553bdb9230aSGarrett D'Amore static int rbuf_pool_size; /* total no. of buffers in the pool */
2554bdb9230aSGarrett D'Amore
2555bdb9230aSGarrett D'Amore /* initialize/add 'nbufs' buffers to the rbuf pool */
2556bdb9230aSGarrett D'Amore /* ARGSUSED */
2557bdb9230aSGarrett D'Amore static int
dnet_rbuf_init(dev_info_t * dip,int nbufs)2558bdb9230aSGarrett D'Amore dnet_rbuf_init(dev_info_t *dip, int nbufs)
2559bdb9230aSGarrett D'Amore {
2560bdb9230aSGarrett D'Amore int i;
2561bdb9230aSGarrett D'Amore struct rbuf_list *rp;
2562bdb9230aSGarrett D'Amore ddi_dma_cookie_t cookie;
2563bdb9230aSGarrett D'Amore uint_t ncookies;
2564bdb9230aSGarrett D'Amore size_t len;
2565bdb9230aSGarrett D'Amore
2566bdb9230aSGarrett D'Amore mutex_enter(&dnet_rbuf_lock);
2567bdb9230aSGarrett D'Amore
2568bdb9230aSGarrett D'Amore /* allocate buffers and add them to the pool */
2569bdb9230aSGarrett D'Amore for (i = 0; i < nbufs; i++) {
2570bdb9230aSGarrett D'Amore /* allocate rbuf_list element */
2571bdb9230aSGarrett D'Amore rp = kmem_zalloc(sizeof (struct rbuf_list), KM_SLEEP);
2572bdb9230aSGarrett D'Amore if (ddi_dma_alloc_handle(dip, &dma_attr_rb, DDI_DMA_SLEEP,
2573bdb9230aSGarrett D'Amore 0, &rp->rbuf_dmahdl) != DDI_SUCCESS)
2574bdb9230aSGarrett D'Amore goto fail_kfree;
2575bdb9230aSGarrett D'Amore
2576bdb9230aSGarrett D'Amore /* allocate dma memory for the buffer */
2577bdb9230aSGarrett D'Amore if (ddi_dma_mem_alloc(rp->rbuf_dmahdl, rx_buf_size, &accattr,
2578bdb9230aSGarrett D'Amore DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 0,
2579bdb9230aSGarrett D'Amore &rp->rbuf_vaddr, &len,
2580bdb9230aSGarrett D'Amore &rp->rbuf_acchdl) != DDI_SUCCESS)
2581bdb9230aSGarrett D'Amore goto fail_freehdl;
2582bdb9230aSGarrett D'Amore
2583bdb9230aSGarrett D'Amore if (ddi_dma_addr_bind_handle(rp->rbuf_dmahdl, NULL,
2584bdb9230aSGarrett D'Amore rp->rbuf_vaddr, len, DDI_DMA_RDWR | DDI_DMA_STREAMING,
2585bdb9230aSGarrett D'Amore DDI_DMA_SLEEP, NULL, &cookie,
2586bdb9230aSGarrett D'Amore &ncookies) != DDI_DMA_MAPPED)
2587bdb9230aSGarrett D'Amore goto fail_free;
2588bdb9230aSGarrett D'Amore
2589bdb9230aSGarrett D'Amore if (ncookies > 2)
2590bdb9230aSGarrett D'Amore goto fail_unbind;
2591bdb9230aSGarrett D'Amore if (ncookies == 1) {
2592bdb9230aSGarrett D'Amore rp->rbuf_endpaddr =
2593bdb9230aSGarrett D'Amore cookie.dmac_address + rx_buf_size - 1;
2594bdb9230aSGarrett D'Amore } else {
2595bdb9230aSGarrett D'Amore ddi_dma_nextcookie(rp->rbuf_dmahdl, &cookie);
2596bdb9230aSGarrett D'Amore rp->rbuf_endpaddr =
2597bdb9230aSGarrett D'Amore cookie.dmac_address + cookie.dmac_size - 1;
2598bdb9230aSGarrett D'Amore }
2599bdb9230aSGarrett D'Amore rp->rbuf_paddr = cookie.dmac_address;
2600bdb9230aSGarrett D'Amore
2601bdb9230aSGarrett D'Amore rp->rbuf_next = rbuf_freelist_head;
2602bdb9230aSGarrett D'Amore rbuf_freelist_head = rp;
2603bdb9230aSGarrett D'Amore rbuf_pool_size++;
2604bdb9230aSGarrett D'Amore rbuf_freebufs++;
2605bdb9230aSGarrett D'Amore }
2606bdb9230aSGarrett D'Amore
2607bdb9230aSGarrett D'Amore mutex_exit(&dnet_rbuf_lock);
2608bdb9230aSGarrett D'Amore return (0);
2609bdb9230aSGarrett D'Amore fail_unbind:
2610bdb9230aSGarrett D'Amore (void) ddi_dma_unbind_handle(rp->rbuf_dmahdl);
2611bdb9230aSGarrett D'Amore fail_free:
2612bdb9230aSGarrett D'Amore ddi_dma_mem_free(&rp->rbuf_acchdl);
2613bdb9230aSGarrett D'Amore fail_freehdl:
2614bdb9230aSGarrett D'Amore ddi_dma_free_handle(&rp->rbuf_dmahdl);
2615bdb9230aSGarrett D'Amore fail_kfree:
2616bdb9230aSGarrett D'Amore kmem_free(rp, sizeof (struct rbuf_list));
2617bdb9230aSGarrett D'Amore
2618bdb9230aSGarrett D'Amore mutex_exit(&dnet_rbuf_lock);
2619bdb9230aSGarrett D'Amore return (-1);
2620bdb9230aSGarrett D'Amore }
2621bdb9230aSGarrett D'Amore
2622bdb9230aSGarrett D'Amore /*
2623bdb9230aSGarrett D'Amore * Try to free up all the rbufs in the pool. Returns 0 if it frees up all
2624bdb9230aSGarrett D'Amore * buffers. The buffers in the used list are considered busy so these
2625bdb9230aSGarrett D'Amore * buffers are not freed.
2626bdb9230aSGarrett D'Amore */
2627bdb9230aSGarrett D'Amore static int
dnet_rbuf_destroy()2628bdb9230aSGarrett D'Amore dnet_rbuf_destroy()
2629bdb9230aSGarrett D'Amore {
2630bdb9230aSGarrett D'Amore struct rbuf_list *rp, *next;
2631bdb9230aSGarrett D'Amore
2632bdb9230aSGarrett D'Amore mutex_enter(&dnet_rbuf_lock);
2633bdb9230aSGarrett D'Amore
2634bdb9230aSGarrett D'Amore for (rp = rbuf_freelist_head; rp; rp = next) {
2635bdb9230aSGarrett D'Amore next = rp->rbuf_next;
2636bdb9230aSGarrett D'Amore ddi_dma_mem_free(&rp->rbuf_acchdl);
2637bdb9230aSGarrett D'Amore (void) ddi_dma_unbind_handle(rp->rbuf_dmahdl);
2638bdb9230aSGarrett D'Amore kmem_free(rp, sizeof (struct rbuf_list));
2639bdb9230aSGarrett D'Amore rbuf_pool_size--;
2640bdb9230aSGarrett D'Amore rbuf_freebufs--;
2641bdb9230aSGarrett D'Amore }
2642bdb9230aSGarrett D'Amore rbuf_freelist_head = NULL;
2643bdb9230aSGarrett D'Amore
2644bdb9230aSGarrett D'Amore if (rbuf_pool_size) { /* pool is still not empty */
2645bdb9230aSGarrett D'Amore mutex_exit(&dnet_rbuf_lock);
2646bdb9230aSGarrett D'Amore return (-1);
2647bdb9230aSGarrett D'Amore }
2648bdb9230aSGarrett D'Amore mutex_exit(&dnet_rbuf_lock);
2649bdb9230aSGarrett D'Amore return (0);
2650bdb9230aSGarrett D'Amore }
2651bdb9230aSGarrett D'Amore static struct rbuf_list *
dnet_rbuf_alloc(dev_info_t * dip,int cansleep)2652bdb9230aSGarrett D'Amore dnet_rbuf_alloc(dev_info_t *dip, int cansleep)
2653bdb9230aSGarrett D'Amore {
2654bdb9230aSGarrett D'Amore struct rbuf_list *rp;
2655bdb9230aSGarrett D'Amore size_t len;
2656bdb9230aSGarrett D'Amore ddi_dma_cookie_t cookie;
2657bdb9230aSGarrett D'Amore uint_t ncookies;
2658bdb9230aSGarrett D'Amore
2659bdb9230aSGarrett D'Amore mutex_enter(&dnet_rbuf_lock);
2660bdb9230aSGarrett D'Amore
2661bdb9230aSGarrett D'Amore if (rbuf_freelist_head == NULL) {
2662bdb9230aSGarrett D'Amore
2663bdb9230aSGarrett D'Amore if (!cansleep) {
2664bdb9230aSGarrett D'Amore mutex_exit(&dnet_rbuf_lock);
2665bdb9230aSGarrett D'Amore return (NULL);
2666bdb9230aSGarrett D'Amore }
2667bdb9230aSGarrett D'Amore
2668bdb9230aSGarrett D'Amore /* allocate rbuf_list element */
2669bdb9230aSGarrett D'Amore rp = kmem_zalloc(sizeof (struct rbuf_list), KM_SLEEP);
2670bdb9230aSGarrett D'Amore if (ddi_dma_alloc_handle(dip, &dma_attr_rb, DDI_DMA_SLEEP,
2671bdb9230aSGarrett D'Amore 0, &rp->rbuf_dmahdl) != DDI_SUCCESS)
2672bdb9230aSGarrett D'Amore goto fail_kfree;
2673bdb9230aSGarrett D'Amore
2674bdb9230aSGarrett D'Amore /* allocate dma memory for the buffer */
2675bdb9230aSGarrett D'Amore if (ddi_dma_mem_alloc(rp->rbuf_dmahdl, rx_buf_size, &accattr,
2676bdb9230aSGarrett D'Amore DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 0,
2677bdb9230aSGarrett D'Amore &rp->rbuf_vaddr, &len,
2678bdb9230aSGarrett D'Amore &rp->rbuf_acchdl) != DDI_SUCCESS)
2679bdb9230aSGarrett D'Amore goto fail_freehdl;
2680bdb9230aSGarrett D'Amore
2681bdb9230aSGarrett D'Amore if (ddi_dma_addr_bind_handle(rp->rbuf_dmahdl, NULL,
2682bdb9230aSGarrett D'Amore rp->rbuf_vaddr, len, DDI_DMA_RDWR | DDI_DMA_STREAMING,
2683bdb9230aSGarrett D'Amore DDI_DMA_SLEEP, NULL, &cookie,
2684bdb9230aSGarrett D'Amore &ncookies) != DDI_DMA_MAPPED)
2685bdb9230aSGarrett D'Amore goto fail_free;
2686bdb9230aSGarrett D'Amore
2687bdb9230aSGarrett D'Amore if (ncookies > 2)
2688bdb9230aSGarrett D'Amore goto fail_unbind;
2689bdb9230aSGarrett D'Amore if (ncookies == 1) {
2690bdb9230aSGarrett D'Amore rp->rbuf_endpaddr =
2691bdb9230aSGarrett D'Amore cookie.dmac_address + rx_buf_size - 1;
2692bdb9230aSGarrett D'Amore } else {
2693bdb9230aSGarrett D'Amore ddi_dma_nextcookie(rp->rbuf_dmahdl, &cookie);
2694bdb9230aSGarrett D'Amore rp->rbuf_endpaddr =
2695bdb9230aSGarrett D'Amore cookie.dmac_address + cookie.dmac_size - 1;
2696bdb9230aSGarrett D'Amore }
2697bdb9230aSGarrett D'Amore rp->rbuf_paddr = cookie.dmac_address;
2698bdb9230aSGarrett D'Amore
2699bdb9230aSGarrett D'Amore rbuf_freelist_head = rp;
2700bdb9230aSGarrett D'Amore rbuf_pool_size++;
2701bdb9230aSGarrett D'Amore rbuf_freebufs++;
2702bdb9230aSGarrett D'Amore }
2703bdb9230aSGarrett D'Amore
2704bdb9230aSGarrett D'Amore /* take the buffer from the head of the free list */
2705bdb9230aSGarrett D'Amore rp = rbuf_freelist_head;
2706bdb9230aSGarrett D'Amore rbuf_freelist_head = rbuf_freelist_head->rbuf_next;
2707bdb9230aSGarrett D'Amore
2708bdb9230aSGarrett D'Amore /* update the used list; put the entry at the end */
2709bdb9230aSGarrett D'Amore if (rbuf_usedlist_head == NULL)
2710bdb9230aSGarrett D'Amore rbuf_usedlist_head = rp;
2711bdb9230aSGarrett D'Amore else
2712bdb9230aSGarrett D'Amore rbuf_usedlist_end->rbuf_next = rp;
2713bdb9230aSGarrett D'Amore rp->rbuf_next = NULL;
2714bdb9230aSGarrett D'Amore rbuf_usedlist_end = rp;
2715bdb9230aSGarrett D'Amore rbuf_freebufs--;
2716bdb9230aSGarrett D'Amore
2717bdb9230aSGarrett D'Amore mutex_exit(&dnet_rbuf_lock);
2718bdb9230aSGarrett D'Amore
2719bdb9230aSGarrett D'Amore return (rp);
2720bdb9230aSGarrett D'Amore fail_unbind:
2721bdb9230aSGarrett D'Amore (void) ddi_dma_unbind_handle(rp->rbuf_dmahdl);
2722bdb9230aSGarrett D'Amore fail_free:
2723bdb9230aSGarrett D'Amore ddi_dma_mem_free(&rp->rbuf_acchdl);
2724bdb9230aSGarrett D'Amore fail_freehdl:
2725bdb9230aSGarrett D'Amore ddi_dma_free_handle(&rp->rbuf_dmahdl);
2726bdb9230aSGarrett D'Amore fail_kfree:
2727bdb9230aSGarrett D'Amore kmem_free(rp, sizeof (struct rbuf_list));
2728bdb9230aSGarrett D'Amore mutex_exit(&dnet_rbuf_lock);
2729bdb9230aSGarrett D'Amore return (NULL);
2730bdb9230aSGarrett D'Amore }
2731bdb9230aSGarrett D'Amore
2732bdb9230aSGarrett D'Amore static void
dnet_rbuf_free(caddr_t vaddr)2733bdb9230aSGarrett D'Amore dnet_rbuf_free(caddr_t vaddr)
2734bdb9230aSGarrett D'Amore {
2735bdb9230aSGarrett D'Amore struct rbuf_list *rp, *prev;
2736bdb9230aSGarrett D'Amore
2737bdb9230aSGarrett D'Amore ASSERT(vaddr != NULL);
2738bdb9230aSGarrett D'Amore ASSERT(rbuf_usedlist_head != NULL);
2739bdb9230aSGarrett D'Amore
2740bdb9230aSGarrett D'Amore mutex_enter(&dnet_rbuf_lock);
2741bdb9230aSGarrett D'Amore
2742bdb9230aSGarrett D'Amore /* find the entry in the used list */
2743bdb9230aSGarrett D'Amore for (prev = rp = rbuf_usedlist_head; rp; rp = rp->rbuf_next) {
2744bdb9230aSGarrett D'Amore if (rp->rbuf_vaddr == vaddr)
2745bdb9230aSGarrett D'Amore break;
2746bdb9230aSGarrett D'Amore prev = rp;
2747bdb9230aSGarrett D'Amore }
2748bdb9230aSGarrett D'Amore
2749bdb9230aSGarrett D'Amore if (rp == NULL) {
2750bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "DNET: rbuf_free: bad addr 0x%p",
2751bdb9230aSGarrett D'Amore (void *)vaddr);
2752bdb9230aSGarrett D'Amore mutex_exit(&dnet_rbuf_lock);
2753bdb9230aSGarrett D'Amore return;
2754bdb9230aSGarrett D'Amore }
2755bdb9230aSGarrett D'Amore
2756bdb9230aSGarrett D'Amore /* update the used list and put the buffer back in the free list */
2757bdb9230aSGarrett D'Amore if (rbuf_usedlist_head != rp) {
2758bdb9230aSGarrett D'Amore prev->rbuf_next = rp->rbuf_next;
2759bdb9230aSGarrett D'Amore if (rbuf_usedlist_end == rp)
2760bdb9230aSGarrett D'Amore rbuf_usedlist_end = prev;
2761bdb9230aSGarrett D'Amore } else {
2762bdb9230aSGarrett D'Amore rbuf_usedlist_head = rp->rbuf_next;
2763bdb9230aSGarrett D'Amore if (rbuf_usedlist_end == rp)
2764bdb9230aSGarrett D'Amore rbuf_usedlist_end = NULL;
2765bdb9230aSGarrett D'Amore }
2766bdb9230aSGarrett D'Amore rp->rbuf_next = rbuf_freelist_head;
2767bdb9230aSGarrett D'Amore rbuf_freelist_head = rp;
2768bdb9230aSGarrett D'Amore rbuf_freebufs++;
2769bdb9230aSGarrett D'Amore
2770bdb9230aSGarrett D'Amore mutex_exit(&dnet_rbuf_lock);
2771bdb9230aSGarrett D'Amore }
2772bdb9230aSGarrett D'Amore
2773bdb9230aSGarrett D'Amore /*
2774bdb9230aSGarrett D'Amore * Free the receive buffer used in a stream's message block allocated
2775bdb9230aSGarrett D'Amore * thru desballoc().
2776bdb9230aSGarrett D'Amore */
2777bdb9230aSGarrett D'Amore static void
dnet_freemsg_buf(struct free_ptr * frp)2778bdb9230aSGarrett D'Amore dnet_freemsg_buf(struct free_ptr *frp)
2779bdb9230aSGarrett D'Amore {
2780bdb9230aSGarrett D'Amore dnet_rbuf_free((caddr_t)frp->buf); /* buffer goes back to the pool */
2781bdb9230aSGarrett D'Amore kmem_free(frp, sizeof (*frp)); /* free up the free_rtn structure */
2782bdb9230aSGarrett D'Amore }
2783bdb9230aSGarrett D'Amore
2784bdb9230aSGarrett D'Amore /*
2785bdb9230aSGarrett D'Amore * ========== SROM Read Routines ==========
2786bdb9230aSGarrett D'Amore */
2787bdb9230aSGarrett D'Amore
2788bdb9230aSGarrett D'Amore /*
2789bdb9230aSGarrett D'Amore * The following code gets the SROM information, either by reading it
2790bdb9230aSGarrett D'Amore * from the device or, failing that, by reading a property.
2791bdb9230aSGarrett D'Amore */
2792bdb9230aSGarrett D'Amore static int
dnet_read_srom(dev_info_t * devinfo,int board_type,ddi_acc_handle_t io_handle,caddr_t io_reg,uchar_t * vi,int maxlen)2793bdb9230aSGarrett D'Amore dnet_read_srom(dev_info_t *devinfo, int board_type, ddi_acc_handle_t io_handle,
2794bdb9230aSGarrett D'Amore caddr_t io_reg, uchar_t *vi, int maxlen)
2795bdb9230aSGarrett D'Amore {
2796bdb9230aSGarrett D'Amore int all_ones, zerocheck, i;
2797bdb9230aSGarrett D'Amore
2798bdb9230aSGarrett D'Amore /*
2799bdb9230aSGarrett D'Amore * Load SROM into vendor_info
2800bdb9230aSGarrett D'Amore */
2801bdb9230aSGarrett D'Amore if (board_type == DEVICE_ID_21040)
2802bdb9230aSGarrett D'Amore dnet_read21040addr(devinfo, io_handle, io_reg, vi, &maxlen);
2803bdb9230aSGarrett D'Amore else
2804bdb9230aSGarrett D'Amore /* 21041/21140 serial rom */
2805bdb9230aSGarrett D'Amore dnet_read21140srom(io_handle, io_reg, vi, maxlen);
2806bdb9230aSGarrett D'Amore /*
2807bdb9230aSGarrett D'Amore * If the dumpsrom property is present in the conf file, print
2808bdb9230aSGarrett D'Amore * the contents of the SROM to the console
2809bdb9230aSGarrett D'Amore */
2810bdb9230aSGarrett D'Amore if (ddi_getprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
2811bdb9230aSGarrett D'Amore "dumpsrom", 0))
2812bdb9230aSGarrett D'Amore dnet_dumpbin("SROM", vi, 1, maxlen);
2813bdb9230aSGarrett D'Amore
2814bdb9230aSGarrett D'Amore for (zerocheck = i = 0, all_ones = 0xff; i < maxlen; i++) {
2815bdb9230aSGarrett D'Amore zerocheck |= vi[i];
2816bdb9230aSGarrett D'Amore all_ones &= vi[i];
2817bdb9230aSGarrett D'Amore }
2818bdb9230aSGarrett D'Amore if (zerocheck == 0 || all_ones == 0xff) {
2819bdb9230aSGarrett D'Amore return (get_alternative_srom_image(devinfo, vi, maxlen));
2820bdb9230aSGarrett D'Amore } else {
2821bdb9230aSGarrett D'Amore #ifdef BUG_4010796
2822bdb9230aSGarrett D'Amore set_alternative_srom_image(devinfo, vi, maxlen);
2823bdb9230aSGarrett D'Amore #endif
2824bdb9230aSGarrett D'Amore return (0); /* Primary */
2825bdb9230aSGarrett D'Amore }
2826bdb9230aSGarrett D'Amore }
2827bdb9230aSGarrett D'Amore
2828bdb9230aSGarrett D'Amore /*
2829bdb9230aSGarrett D'Amore * The function reads the ethernet address of the 21040 adapter
2830bdb9230aSGarrett D'Amore */
2831bdb9230aSGarrett D'Amore static void
dnet_read21040addr(dev_info_t * dip,ddi_acc_handle_t io_handle,caddr_t io_reg,uchar_t * addr,int * len)2832bdb9230aSGarrett D'Amore dnet_read21040addr(dev_info_t *dip, ddi_acc_handle_t io_handle, caddr_t io_reg,
2833bdb9230aSGarrett D'Amore uchar_t *addr, int *len)
2834bdb9230aSGarrett D'Amore {
2835bdb9230aSGarrett D'Amore uint32_t val;
2836bdb9230aSGarrett D'Amore int i;
2837bdb9230aSGarrett D'Amore
2838bdb9230aSGarrett D'Amore /* No point reading more than the ethernet address */
2839bdb9230aSGarrett D'Amore *len = ddi_getprop(DDI_DEV_T_ANY, dip,
2840bdb9230aSGarrett D'Amore DDI_PROP_DONTPASS, macoffset_propname, 0) + ETHERADDRL;
2841bdb9230aSGarrett D'Amore
2842bdb9230aSGarrett D'Amore /* Reset ROM pointer */
2843bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG), 0);
2844bdb9230aSGarrett D'Amore for (i = 0; i < *len; i++) {
2845bdb9230aSGarrett D'Amore do {
2846bdb9230aSGarrett D'Amore val = ddi_get32(io_handle,
2847bdb9230aSGarrett D'Amore REG32(io_reg, ETHER_ROM_REG));
2848bdb9230aSGarrett D'Amore } while (val & 0x80000000);
2849bdb9230aSGarrett D'Amore addr[i] = val & 0xFF;
2850bdb9230aSGarrett D'Amore }
2851bdb9230aSGarrett D'Amore }
2852bdb9230aSGarrett D'Amore
2853bdb9230aSGarrett D'Amore #define drv_nsecwait(x) drv_usecwait(((x)+999)/1000) /* XXX */
2854bdb9230aSGarrett D'Amore
2855bdb9230aSGarrett D'Amore /*
2856bdb9230aSGarrett D'Amore * The function reads the SROM of the 21140 adapter
2857bdb9230aSGarrett D'Amore */
2858bdb9230aSGarrett D'Amore static void
dnet_read21140srom(ddi_acc_handle_t io_handle,caddr_t io_reg,uchar_t * addr,int maxlen)2859bdb9230aSGarrett D'Amore dnet_read21140srom(ddi_acc_handle_t io_handle, caddr_t io_reg, uchar_t *addr,
2860bdb9230aSGarrett D'Amore int maxlen)
2861bdb9230aSGarrett D'Amore {
2862bdb9230aSGarrett D'Amore uint32_t i, j;
2863bdb9230aSGarrett D'Amore uint32_t dout;
2864bdb9230aSGarrett D'Amore uint16_t word;
2865bdb9230aSGarrett D'Amore uint8_t rom_addr;
2866bdb9230aSGarrett D'Amore uint8_t bit;
2867bdb9230aSGarrett D'Amore
2868bdb9230aSGarrett D'Amore
2869bdb9230aSGarrett D'Amore rom_addr = 0;
2870bdb9230aSGarrett D'Amore for (i = 0; i < maxlen; i += 2) {
2871bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2872bdb9230aSGarrett D'Amore READ_OP | SEL_ROM);
2873bdb9230aSGarrett D'Amore drv_nsecwait(30);
2874bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2875bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP);
2876bdb9230aSGarrett D'Amore drv_nsecwait(50);
2877bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2878bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP | SEL_CLK);
2879bdb9230aSGarrett D'Amore drv_nsecwait(250);
2880bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2881bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP);
2882bdb9230aSGarrett D'Amore drv_nsecwait(100);
2883bdb9230aSGarrett D'Amore
2884bdb9230aSGarrett D'Amore /* command */
2885bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2886bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP | DATA_IN);
2887bdb9230aSGarrett D'Amore drv_nsecwait(150);
2888bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2889bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP | DATA_IN | SEL_CLK);
2890bdb9230aSGarrett D'Amore drv_nsecwait(250);
2891bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2892bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP | DATA_IN);
2893bdb9230aSGarrett D'Amore drv_nsecwait(250);
2894bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2895bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP | DATA_IN | SEL_CLK);
2896bdb9230aSGarrett D'Amore drv_nsecwait(250);
2897bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2898bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP | DATA_IN);
2899bdb9230aSGarrett D'Amore drv_nsecwait(100);
2900bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2901bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP);
2902bdb9230aSGarrett D'Amore drv_nsecwait(150);
2903bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2904bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP | SEL_CLK);
2905bdb9230aSGarrett D'Amore drv_nsecwait(250);
2906bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2907bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP);
2908bdb9230aSGarrett D'Amore drv_nsecwait(100);
2909bdb9230aSGarrett D'Amore
2910bdb9230aSGarrett D'Amore /* Address */
2911bdb9230aSGarrett D'Amore for (j = HIGH_ADDRESS_BIT; j >= 1; j >>= 1) {
2912bdb9230aSGarrett D'Amore bit = (rom_addr & j) ? DATA_IN : 0;
2913bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2914bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP | bit);
2915bdb9230aSGarrett D'Amore drv_nsecwait(150);
2916bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2917bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP | bit | SEL_CLK);
2918bdb9230aSGarrett D'Amore drv_nsecwait(250);
2919bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2920bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP | bit);
2921bdb9230aSGarrett D'Amore drv_nsecwait(100);
2922bdb9230aSGarrett D'Amore }
2923bdb9230aSGarrett D'Amore drv_nsecwait(150);
2924bdb9230aSGarrett D'Amore
2925bdb9230aSGarrett D'Amore /* Data */
2926bdb9230aSGarrett D'Amore word = 0;
2927bdb9230aSGarrett D'Amore for (j = 0x8000; j >= 1; j >>= 1) {
2928bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2929bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP | SEL_CLK);
2930bdb9230aSGarrett D'Amore drv_nsecwait(100);
2931bdb9230aSGarrett D'Amore dout = ddi_get32(io_handle,
2932bdb9230aSGarrett D'Amore REG32(io_reg, ETHER_ROM_REG));
2933bdb9230aSGarrett D'Amore drv_nsecwait(150);
2934bdb9230aSGarrett D'Amore if (dout & DATA_OUT)
2935bdb9230aSGarrett D'Amore word |= j;
2936bdb9230aSGarrett D'Amore ddi_put32(io_handle,
2937bdb9230aSGarrett D'Amore REG32(io_reg, ETHER_ROM_REG),
2938bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP);
2939bdb9230aSGarrett D'Amore drv_nsecwait(250);
2940bdb9230aSGarrett D'Amore }
2941bdb9230aSGarrett D'Amore addr[i] = (word & 0x0000FF);
2942bdb9230aSGarrett D'Amore addr[i + 1] = (word >> 8);
2943bdb9230aSGarrett D'Amore rom_addr++;
2944bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2945bdb9230aSGarrett D'Amore READ_OP | SEL_ROM);
2946bdb9230aSGarrett D'Amore drv_nsecwait(100);
2947bdb9230aSGarrett D'Amore }
2948bdb9230aSGarrett D'Amore }
2949bdb9230aSGarrett D'Amore
2950bdb9230aSGarrett D'Amore
2951bdb9230aSGarrett D'Amore /*
2952bdb9230aSGarrett D'Amore * XXX NEEDSWORK
2953bdb9230aSGarrett D'Amore *
2954bdb9230aSGarrett D'Amore * Some lame multiport cards have only one SROM, which can be accessed
2955bdb9230aSGarrett D'Amore * only from the "first" 21x4x chip, whichever that one is. If we can't
2956bdb9230aSGarrett D'Amore * get at our SROM, we look for its contents in a property instead, which
2957bdb9230aSGarrett D'Amore * we rely on the bootstrap to have properly set.
2958bdb9230aSGarrett D'Amore * #ifdef BUG_4010796
2959bdb9230aSGarrett D'Amore * We also have a hack to try to set it ourselves, when the "first" port
2960bdb9230aSGarrett D'Amore * attaches, if it has not already been properly set. However, this method
2961bdb9230aSGarrett D'Amore * is not reliable, since it makes the unwarrented assumption that the
2962bdb9230aSGarrett D'Amore * "first" port will attach first.
2963bdb9230aSGarrett D'Amore * #endif
2964bdb9230aSGarrett D'Amore */
2965bdb9230aSGarrett D'Amore
2966bdb9230aSGarrett D'Amore static int
get_alternative_srom_image(dev_info_t * devinfo,uchar_t * vi,int len)2967bdb9230aSGarrett D'Amore get_alternative_srom_image(dev_info_t *devinfo, uchar_t *vi, int len)
2968bdb9230aSGarrett D'Amore {
2969bdb9230aSGarrett D'Amore int l = len;
2970bdb9230aSGarrett D'Amore
2971bdb9230aSGarrett D'Amore if (ddi_getlongprop_buf(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
2972bdb9230aSGarrett D'Amore "DNET_SROM", (caddr_t)vi, &len) != DDI_PROP_SUCCESS &&
2973bdb9230aSGarrett D'Amore (len = l) && ddi_getlongprop_buf(DDI_DEV_T_ANY,
2974bdb9230aSGarrett D'Amore ddi_get_parent(devinfo), DDI_PROP_DONTPASS, "DNET_SROM",
2975bdb9230aSGarrett D'Amore (caddr_t)vi, &len) != DDI_PROP_SUCCESS)
2976bdb9230aSGarrett D'Amore return (-1); /* Can't find it! */
2977bdb9230aSGarrett D'Amore
2978bdb9230aSGarrett D'Amore /*
2979bdb9230aSGarrett D'Amore * The return value from this routine specifies which port number
2980bdb9230aSGarrett D'Amore * we are. The primary port is denoted port 0. On a QUAD card we
2981bdb9230aSGarrett D'Amore * should return 1, 2, and 3 from this routine. The return value
2982bdb9230aSGarrett D'Amore * is used to modify the ethernet address from the SROM data.
2983bdb9230aSGarrett D'Amore */
2984bdb9230aSGarrett D'Amore
2985bdb9230aSGarrett D'Amore #ifdef BUG_4010796
2986bdb9230aSGarrett D'Amore {
2987bdb9230aSGarrett D'Amore /*
2988bdb9230aSGarrett D'Amore * For the present, we remember the device number of our primary
2989bdb9230aSGarrett D'Amore * sibling and hope we and our other siblings are consecutively
2990bdb9230aSGarrett D'Amore * numbered up from there. In the future perhaps the bootstrap
2991bdb9230aSGarrett D'Amore * will pass us the necessary information telling us which physical
2992bdb9230aSGarrett D'Amore * port we really are.
2993bdb9230aSGarrett D'Amore */
2994bdb9230aSGarrett D'Amore pci_regspec_t *assignp;
2995bdb9230aSGarrett D'Amore int assign_len;
2996bdb9230aSGarrett D'Amore int devnum;
2997bdb9230aSGarrett D'Amore int primary_devnum;
2998bdb9230aSGarrett D'Amore
2999bdb9230aSGarrett D'Amore primary_devnum = ddi_getprop(DDI_DEV_T_ANY, devinfo, 0,
3000bdb9230aSGarrett D'Amore "DNET_DEVNUM", -1);
3001bdb9230aSGarrett D'Amore if (primary_devnum == -1)
3002bdb9230aSGarrett D'Amore return (1); /* XXX NEEDSWORK -- We have no better idea */
3003bdb9230aSGarrett D'Amore
3004bdb9230aSGarrett D'Amore if ((ddi_getlongprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
3005bdb9230aSGarrett D'Amore "assigned-addresses", (caddr_t)&assignp,
3006bdb9230aSGarrett D'Amore &assign_len)) != DDI_PROP_SUCCESS)
3007bdb9230aSGarrett D'Amore return (1); /* XXX NEEDSWORK -- We have no better idea */
3008bdb9230aSGarrett D'Amore
3009bdb9230aSGarrett D'Amore devnum = PCI_REG_DEV_G(assignp->pci_phys_hi);
3010bdb9230aSGarrett D'Amore kmem_free(assignp, assign_len);
3011bdb9230aSGarrett D'Amore return (devnum - primary_devnum);
3012bdb9230aSGarrett D'Amore }
3013bdb9230aSGarrett D'Amore #else
3014bdb9230aSGarrett D'Amore return (1); /* XXX NEEDSWORK -- We have no better idea */
3015bdb9230aSGarrett D'Amore #endif
3016bdb9230aSGarrett D'Amore }
3017bdb9230aSGarrett D'Amore
3018bdb9230aSGarrett D'Amore
3019bdb9230aSGarrett D'Amore #ifdef BUG_4010796
3020bdb9230aSGarrett D'Amore static void
set_alternative_srom_image(dev_info_t * devinfo,uchar_t * vi,int len)3021bdb9230aSGarrett D'Amore set_alternative_srom_image(dev_info_t *devinfo, uchar_t *vi, int len)
3022bdb9230aSGarrett D'Amore {
3023bdb9230aSGarrett D'Amore int proplen;
3024bdb9230aSGarrett D'Amore pci_regspec_t *assignp;
3025bdb9230aSGarrett D'Amore int assign_len;
3026bdb9230aSGarrett D'Amore int devnum;
3027bdb9230aSGarrett D'Amore
3028bdb9230aSGarrett D'Amore if (ddi_getproplen(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
3029bdb9230aSGarrett D'Amore "DNET_SROM", &proplen) == DDI_PROP_SUCCESS ||
3030bdb9230aSGarrett D'Amore ddi_getproplen(DDI_DEV_T_ANY, ddi_get_parent(devinfo),
3031bdb9230aSGarrett D'Amore DDI_PROP_DONTPASS, "DNET_SROM", &proplen) == DDI_PROP_SUCCESS)
3032bdb9230aSGarrett D'Amore return; /* Already done! */
3033bdb9230aSGarrett D'Amore
3034bdb9230aSGarrett D'Amore /* function return value ignored */
3035bdb9230aSGarrett D'Amore (void) ddi_prop_update_byte_array(DDI_DEV_T_NONE,
3036bdb9230aSGarrett D'Amore ddi_get_parent(devinfo), "DNET_SROM", (uchar_t *)vi, len);
3037bdb9230aSGarrett D'Amore (void) ddi_prop_update_string(DDI_DEV_T_NONE, devinfo,
3038bdb9230aSGarrett D'Amore "DNET_HACK", "hack");
3039bdb9230aSGarrett D'Amore
3040bdb9230aSGarrett D'Amore if ((ddi_getlongprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
3041bdb9230aSGarrett D'Amore "assigned-addresses", (caddr_t)&assignp,
3042bdb9230aSGarrett D'Amore &assign_len)) == DDI_PROP_SUCCESS) {
3043bdb9230aSGarrett D'Amore devnum = PCI_REG_DEV_G(assignp->pci_phys_hi);
3044bdb9230aSGarrett D'Amore kmem_free(assignp, assign_len);
3045bdb9230aSGarrett D'Amore /* function return value ignored */
3046bdb9230aSGarrett D'Amore (void) ddi_prop_update_int(DDI_DEV_T_NONE,
3047bdb9230aSGarrett D'Amore ddi_get_parent(devinfo), "DNET_DEVNUM", devnum);
3048bdb9230aSGarrett D'Amore }
3049bdb9230aSGarrett D'Amore }
3050bdb9230aSGarrett D'Amore #endif
3051bdb9230aSGarrett D'Amore
3052bdb9230aSGarrett D'Amore /*
3053bdb9230aSGarrett D'Amore * ========== SROM Parsing Routines ==========
3054bdb9230aSGarrett D'Amore */
3055bdb9230aSGarrett D'Amore
3056bdb9230aSGarrett D'Amore static int
check_srom_valid(uchar_t * vi)3057bdb9230aSGarrett D'Amore check_srom_valid(uchar_t *vi)
3058bdb9230aSGarrett D'Amore {
3059bdb9230aSGarrett D'Amore int word, bit;
3060bdb9230aSGarrett D'Amore uint8_t crc;
3061bdb9230aSGarrett D'Amore uint16_t *wvi; /* word16 pointer to vendor info */
3062bdb9230aSGarrett D'Amore uint16_t bitval;
3063bdb9230aSGarrett D'Amore
3064bdb9230aSGarrett D'Amore /* verify that the number of controllers on the card is within range */
3065bdb9230aSGarrett D'Amore if (vi[SROM_ADAPTER_CNT] < 1 || vi[SROM_ADAPTER_CNT] > MAX_ADAPTERS)
3066bdb9230aSGarrett D'Amore return (0);
3067bdb9230aSGarrett D'Amore
3068bdb9230aSGarrett D'Amore /*
3069bdb9230aSGarrett D'Amore * version 1 and 3 of this card did not check the id block CRC value
3070bdb9230aSGarrett D'Amore * and this can't be changed without retesting every supported card
3071bdb9230aSGarrett D'Amore *
3072bdb9230aSGarrett D'Amore * however version 4 of the SROM can have this test applied
3073bdb9230aSGarrett D'Amore * without fear of breaking something that used to work.
3074bdb9230aSGarrett D'Amore * the CRC algorithm is taken from the Intel document
3075bdb9230aSGarrett D'Amore * "21x4 Serial ROM Format"
3076bdb9230aSGarrett D'Amore * version 4.09
3077bdb9230aSGarrett D'Amore * 3-Mar-1999
3078bdb9230aSGarrett D'Amore */
3079bdb9230aSGarrett D'Amore
3080bdb9230aSGarrett D'Amore switch (vi[SROM_VERSION]) {
3081bdb9230aSGarrett D'Amore case 1:
3082bdb9230aSGarrett D'Amore /* fallthru */
3083bdb9230aSGarrett D'Amore case 3:
3084bdb9230aSGarrett D'Amore return (vi[SROM_MBZ] == 0 && /* must be zero */
3085bdb9230aSGarrett D'Amore vi[SROM_MBZ2] == 0 && /* must be zero */
3086bdb9230aSGarrett D'Amore vi[SROM_MBZ3] == 0); /* must be zero */
3087bdb9230aSGarrett D'Amore
3088bdb9230aSGarrett D'Amore case 4:
3089bdb9230aSGarrett D'Amore wvi = (uint16_t *)vi;
3090bdb9230aSGarrett D'Amore crc = 0xff;
3091bdb9230aSGarrett D'Amore for (word = 0; word < 9; word++)
3092bdb9230aSGarrett D'Amore for (bit = 15; bit >= 0; bit--) {
3093bdb9230aSGarrett D'Amore if (word == 8 && bit == 7)
3094bdb9230aSGarrett D'Amore return (crc == vi[16]);
3095bdb9230aSGarrett D'Amore bitval =
3096bdb9230aSGarrett D'Amore ((wvi[word] >> bit) & 1) ^ ((crc >> 7) & 1);
3097bdb9230aSGarrett D'Amore crc <<= 1;
3098bdb9230aSGarrett D'Amore if (bitval == 1) {
3099bdb9230aSGarrett D'Amore crc ^= 7;
3100bdb9230aSGarrett D'Amore }
3101bdb9230aSGarrett D'Amore }
3102bdb9230aSGarrett D'Amore
3103bdb9230aSGarrett D'Amore default:
3104bdb9230aSGarrett D'Amore return (0);
3105bdb9230aSGarrett D'Amore }
3106bdb9230aSGarrett D'Amore }
3107bdb9230aSGarrett D'Amore
3108bdb9230aSGarrett D'Amore /*
3109bdb9230aSGarrett D'Amore * ========== Active Media Determination Routines ==========
3110bdb9230aSGarrett D'Amore */
3111bdb9230aSGarrett D'Amore
3112bdb9230aSGarrett D'Amore /* This routine is also called for V3 Compact and extended type 0 SROMs */
3113bdb9230aSGarrett D'Amore static int
is_fdmedia(int media)3114bdb9230aSGarrett D'Amore is_fdmedia(int media)
3115bdb9230aSGarrett D'Amore {
3116bdb9230aSGarrett D'Amore if (media == MEDIA_TP_FD || media == MEDIA_SYM_SCR_FD)
3117bdb9230aSGarrett D'Amore return (1);
3118bdb9230aSGarrett D'Amore else
3119bdb9230aSGarrett D'Amore return (0);
3120bdb9230aSGarrett D'Amore }
3121bdb9230aSGarrett D'Amore
3122bdb9230aSGarrett D'Amore /*
3123bdb9230aSGarrett D'Amore * "Linkset" is used to merge media that use the same link test check. So,
3124bdb9230aSGarrett D'Amore * if the TP link is added to the linkset, so is the TP Full duplex link.
3125bdb9230aSGarrett D'Amore * Used to avoid checking the same link status twice.
3126bdb9230aSGarrett D'Amore */
3127bdb9230aSGarrett D'Amore static void
linkset_add(uint32_t * set,int media)3128bdb9230aSGarrett D'Amore linkset_add(uint32_t *set, int media)
3129bdb9230aSGarrett D'Amore {
3130bdb9230aSGarrett D'Amore if (media == MEDIA_TP_FD || media == MEDIA_TP)
3131bdb9230aSGarrett D'Amore *set |= (1UL<<MEDIA_TP_FD) | (1UL<<MEDIA_TP);
3132bdb9230aSGarrett D'Amore else if (media == MEDIA_SYM_SCR_FD || media == MEDIA_SYM_SCR)
3133bdb9230aSGarrett D'Amore *set |= (1UL<<MEDIA_SYM_SCR_FD) | (1UL<<MEDIA_SYM_SCR);
3134bdb9230aSGarrett D'Amore else *set |= 1UL<<media;
3135bdb9230aSGarrett D'Amore }
3136bdb9230aSGarrett D'Amore static int
linkset_isset(uint32_t linkset,int media)3137bdb9230aSGarrett D'Amore linkset_isset(uint32_t linkset, int media)
3138bdb9230aSGarrett D'Amore {
3139bdb9230aSGarrett D'Amore return (((1UL<<media) & linkset) ? 1:0);
3140bdb9230aSGarrett D'Amore }
3141bdb9230aSGarrett D'Amore
3142bdb9230aSGarrett D'Amore /*
3143bdb9230aSGarrett D'Amore * The following code detects which Media is connected for 21041/21140
3144bdb9230aSGarrett D'Amore * Expect to change this code to support new 21140 variants.
3145bdb9230aSGarrett D'Amore * find_active_media() - called with intrlock held.
3146bdb9230aSGarrett D'Amore */
3147bdb9230aSGarrett D'Amore static void
find_active_media(struct dnetinstance * dnetp)314898e8d175SSteven Stallion find_active_media(struct dnetinstance *dnetp)
3149bdb9230aSGarrett D'Amore {
3150bdb9230aSGarrett D'Amore int i;
3151bdb9230aSGarrett D'Amore media_block_t *block;
3152bdb9230aSGarrett D'Amore media_block_t *best_allowed = NULL;
3153bdb9230aSGarrett D'Amore media_block_t *hd_found = NULL;
3154bdb9230aSGarrett D'Amore media_block_t *fd_found = NULL;
3155bdb9230aSGarrett D'Amore LEAF_FORMAT *leaf = &dnetp->sr.leaf[dnetp->leaf];
3156bdb9230aSGarrett D'Amore uint32_t checked = 0, links_up = 0;
3157bdb9230aSGarrett D'Amore
3158bdb9230aSGarrett D'Amore ASSERT(MUTEX_HELD(&dnetp->intrlock));
315998e8d175SSteven Stallion
3160bdb9230aSGarrett D'Amore dnetp->selected_media_block = leaf->default_block;
3161bdb9230aSGarrett D'Amore
3162bdb9230aSGarrett D'Amore if (dnetp->phyaddr != -1) {
3163bdb9230aSGarrett D'Amore dnetp->selected_media_block = leaf->mii_block;
316498e8d175SSteven Stallion setup_block(dnetp);
3165bdb9230aSGarrett D'Amore
3166bdb9230aSGarrett D'Amore if (ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo,
3167bdb9230aSGarrett D'Amore DDI_PROP_DONTPASS, "portmon", 1)) {
3168bdb9230aSGarrett D'Amore /* XXX return value ignored */
3169bdb9230aSGarrett D'Amore (void) mii_start_portmon(dnetp->mii, dnet_mii_link_cb,
3170bdb9230aSGarrett D'Amore &dnetp->intrlock);
3171bdb9230aSGarrett D'Amore /*
3172bdb9230aSGarrett D'Amore * If the port monitor detects the link is already
3173bdb9230aSGarrett D'Amore * up, there is no point going through the rest of the
3174bdb9230aSGarrett D'Amore * link sense
3175bdb9230aSGarrett D'Amore */
3176bdb9230aSGarrett D'Amore if (dnetp->mii_up) {
3177bdb9230aSGarrett D'Amore return;
3178bdb9230aSGarrett D'Amore }
3179bdb9230aSGarrett D'Amore }
3180bdb9230aSGarrett D'Amore }
3181bdb9230aSGarrett D'Amore
3182bdb9230aSGarrett D'Amore /*
3183bdb9230aSGarrett D'Amore * Media is searched for in order of Precedence. This DEC SROM spec
3184bdb9230aSGarrett D'Amore * tells us that the first media entry in the SROM is the lowest
3185bdb9230aSGarrett D'Amore * precedence and should be checked last. This is why we go to the last
3186bdb9230aSGarrett D'Amore * Media block and work back to the beginning.
3187bdb9230aSGarrett D'Amore *
3188bdb9230aSGarrett D'Amore * However, some older SROMs (Cogent EM110's etc.) have this the wrong
3189bdb9230aSGarrett D'Amore * way around. As a result, following the SROM spec would result in a
3190bdb9230aSGarrett D'Amore * 10 link being chosen over a 100 link if both media are available.
3191bdb9230aSGarrett D'Amore * So we continue trying the media until we have at least tried the
3192bdb9230aSGarrett D'Amore * DEFAULT media.
3193bdb9230aSGarrett D'Amore */
3194bdb9230aSGarrett D'Amore
3195bdb9230aSGarrett D'Amore /* Search for an active medium, and select it */
3196bdb9230aSGarrett D'Amore for (block = leaf->block + leaf->block_count - 1;
3197bdb9230aSGarrett D'Amore block >= leaf->block; block--) {
3198bdb9230aSGarrett D'Amore int media = block->media_code;
3199bdb9230aSGarrett D'Amore
3200bdb9230aSGarrett D'Amore /* User settings disallow selection of this block */
3201bdb9230aSGarrett D'Amore if (dnetp->disallowed_media & (1UL<<media))
3202bdb9230aSGarrett D'Amore continue;
3203bdb9230aSGarrett D'Amore
3204bdb9230aSGarrett D'Amore /* We may not be able to pick the default */
3205bdb9230aSGarrett D'Amore if (best_allowed == NULL || block == leaf->default_block)
3206bdb9230aSGarrett D'Amore best_allowed = block;
3207bdb9230aSGarrett D'Amore #ifdef DEBUG
3208bdb9230aSGarrett D'Amore if (dnetdebug & DNETSENSE)
3209bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "Testing %s medium (block type %d)",
3210bdb9230aSGarrett D'Amore media_str[media], block->type);
3211bdb9230aSGarrett D'Amore #endif
3212bdb9230aSGarrett D'Amore
3213bdb9230aSGarrett D'Amore dnetp->selected_media_block = block;
3214bdb9230aSGarrett D'Amore switch (block->type) {
3215bdb9230aSGarrett D'Amore
3216bdb9230aSGarrett D'Amore case 2: /* SIA Media block: Best we can do is send a packet */
321798e8d175SSteven Stallion setup_block(dnetp);
321898e8d175SSteven Stallion if (send_test_packet(dnetp)) {
3219bdb9230aSGarrett D'Amore if (!is_fdmedia(media))
3220bdb9230aSGarrett D'Amore return;
3221bdb9230aSGarrett D'Amore if (!fd_found)
3222bdb9230aSGarrett D'Amore fd_found = block;
3223bdb9230aSGarrett D'Amore }
3224bdb9230aSGarrett D'Amore break;
3225bdb9230aSGarrett D'Amore
3226bdb9230aSGarrett D'Amore /* SYM/SCR or TP block: Use the link-sense bits */
3227bdb9230aSGarrett D'Amore case 0:
3228bdb9230aSGarrett D'Amore if (!linkset_isset(checked, media)) {
3229bdb9230aSGarrett D'Amore linkset_add(&checked, media);
3230bdb9230aSGarrett D'Amore if (((media == MEDIA_BNC ||
3231bdb9230aSGarrett D'Amore media == MEDIA_AUI) &&
323298e8d175SSteven Stallion send_test_packet(dnetp)) ||
323398e8d175SSteven Stallion dnet_link_sense(dnetp))
3234bdb9230aSGarrett D'Amore linkset_add(&links_up, media);
3235bdb9230aSGarrett D'Amore }
3236bdb9230aSGarrett D'Amore
3237bdb9230aSGarrett D'Amore if (linkset_isset(links_up, media)) {
3238bdb9230aSGarrett D'Amore /*
3239bdb9230aSGarrett D'Amore * Half Duplex is *always* the favoured media.
3240bdb9230aSGarrett D'Amore * Full Duplex can be set and forced via the
3241bdb9230aSGarrett D'Amore * conf file.
3242bdb9230aSGarrett D'Amore */
3243bdb9230aSGarrett D'Amore if (!is_fdmedia(media) &&
3244bdb9230aSGarrett D'Amore dnetp->selected_media_block ==
3245bdb9230aSGarrett D'Amore leaf->default_block) {
3246bdb9230aSGarrett D'Amore /*
3247bdb9230aSGarrett D'Amore * Cogent cards have the media in
3248bdb9230aSGarrett D'Amore * opposite order to the spec.,
3249bdb9230aSGarrett D'Amore * this code forces the media test to
3250bdb9230aSGarrett D'Amore * keep going until the default media
3251bdb9230aSGarrett D'Amore * is tested.
3252bdb9230aSGarrett D'Amore *
3253bdb9230aSGarrett D'Amore * In Cogent case, 10, 10FD, 100FD, 100
3254bdb9230aSGarrett D'Amore * 100 is the default but 10 could have
3255bdb9230aSGarrett D'Amore * been detected and would have been
3256bdb9230aSGarrett D'Amore * chosen but now we force it through to
3257bdb9230aSGarrett D'Amore * 100.
3258bdb9230aSGarrett D'Amore */
325998e8d175SSteven Stallion setup_block(dnetp);
3260bdb9230aSGarrett D'Amore return;
3261bdb9230aSGarrett D'Amore } else if (!is_fdmedia(media)) {
3262bdb9230aSGarrett D'Amore /*
3263bdb9230aSGarrett D'Amore * This allows all the others to work
3264bdb9230aSGarrett D'Amore * properly by remembering the media
3265bdb9230aSGarrett D'Amore * that works and not defaulting to
3266bdb9230aSGarrett D'Amore * a FD link.
3267bdb9230aSGarrett D'Amore */
3268bdb9230aSGarrett D'Amore if (hd_found == NULL)
3269bdb9230aSGarrett D'Amore hd_found = block;
3270bdb9230aSGarrett D'Amore } else if (fd_found == NULL) {
3271bdb9230aSGarrett D'Amore /*
3272bdb9230aSGarrett D'Amore * No media have already been found
3273bdb9230aSGarrett D'Amore * so far, this is FD, it works so
3274bdb9230aSGarrett D'Amore * remember it and if no others are
3275bdb9230aSGarrett D'Amore * detected, use it.
3276bdb9230aSGarrett D'Amore */
3277bdb9230aSGarrett D'Amore fd_found = block;
3278bdb9230aSGarrett D'Amore }
3279bdb9230aSGarrett D'Amore }
3280bdb9230aSGarrett D'Amore break;
3281bdb9230aSGarrett D'Amore
3282bdb9230aSGarrett D'Amore /*
3283bdb9230aSGarrett D'Amore * MII block: May take up to a second or so to settle if
3284bdb9230aSGarrett D'Amore * setup causes a PHY reset
3285bdb9230aSGarrett D'Amore */
3286bdb9230aSGarrett D'Amore case 1: case 3:
328798e8d175SSteven Stallion setup_block(dnetp);
3288bdb9230aSGarrett D'Amore for (i = 0; ; i++) {
3289bdb9230aSGarrett D'Amore if (mii_linkup(dnetp->mii, dnetp->phyaddr)) {
3290bdb9230aSGarrett D'Amore /* XXX function return value ignored */
3291bdb9230aSGarrett D'Amore (void) mii_getspeed(dnetp->mii,
3292bdb9230aSGarrett D'Amore dnetp->phyaddr,
3293bdb9230aSGarrett D'Amore &dnetp->mii_speed,
3294bdb9230aSGarrett D'Amore &dnetp->mii_duplex);
3295bdb9230aSGarrett D'Amore dnetp->mii_up = 1;
3296bdb9230aSGarrett D'Amore leaf->mii_block = block;
3297bdb9230aSGarrett D'Amore return;
3298bdb9230aSGarrett D'Amore }
3299bdb9230aSGarrett D'Amore if (i == 10)
3300bdb9230aSGarrett D'Amore break;
3301bdb9230aSGarrett D'Amore delay(drv_usectohz(150000));
3302bdb9230aSGarrett D'Amore }
3303bdb9230aSGarrett D'Amore dnetp->mii_up = 0;
3304bdb9230aSGarrett D'Amore break;
3305bdb9230aSGarrett D'Amore }
3306bdb9230aSGarrett D'Amore } /* for loop */
3307bdb9230aSGarrett D'Amore if (hd_found) {
3308bdb9230aSGarrett D'Amore dnetp->selected_media_block = hd_found;
3309bdb9230aSGarrett D'Amore } else if (fd_found) {
3310bdb9230aSGarrett D'Amore dnetp->selected_media_block = fd_found;
3311bdb9230aSGarrett D'Amore } else {
3312bdb9230aSGarrett D'Amore if (best_allowed == NULL)
3313bdb9230aSGarrett D'Amore best_allowed = leaf->default_block;
3314bdb9230aSGarrett D'Amore dnetp->selected_media_block = best_allowed;
3315bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "!dnet: Default media selected\n");
3316bdb9230aSGarrett D'Amore }
331798e8d175SSteven Stallion setup_block(dnetp);
3318bdb9230aSGarrett D'Amore }
3319bdb9230aSGarrett D'Amore
3320bdb9230aSGarrett D'Amore /*
3321bdb9230aSGarrett D'Amore * Do anything neccessary to select the selected_media_block.
3322bdb9230aSGarrett D'Amore * setup_block() - called with intrlock held.
3323bdb9230aSGarrett D'Amore */
3324bdb9230aSGarrett D'Amore static void
setup_block(struct dnetinstance * dnetp)332598e8d175SSteven Stallion setup_block(struct dnetinstance *dnetp)
3326bdb9230aSGarrett D'Amore {
332798e8d175SSteven Stallion dnet_reset_board(dnetp);
332898e8d175SSteven Stallion dnet_init_board(dnetp);
3329bdb9230aSGarrett D'Amore /* XXX function return value ignored */
333098e8d175SSteven Stallion (void) dnet_start(dnetp);
3331bdb9230aSGarrett D'Amore }
3332bdb9230aSGarrett D'Amore
3333bdb9230aSGarrett D'Amore /* dnet_link_sense() - called with intrlock held */
3334bdb9230aSGarrett D'Amore static int
dnet_link_sense(struct dnetinstance * dnetp)333598e8d175SSteven Stallion dnet_link_sense(struct dnetinstance *dnetp)
3336bdb9230aSGarrett D'Amore {
3337bdb9230aSGarrett D'Amore /*
3338bdb9230aSGarrett D'Amore * This routine makes use of the command word from the srom config.
3339bdb9230aSGarrett D'Amore * Details of the auto-sensing information contained in this can
3340bdb9230aSGarrett D'Amore * be found in the "Digital Semiconductor 21X4 Serial ROM Format v3.03"
3341bdb9230aSGarrett D'Amore * spec. Section 4.3.2.1, and 4.5.2.1.3
3342bdb9230aSGarrett D'Amore */
3343bdb9230aSGarrett D'Amore media_block_t *block = dnetp->selected_media_block;
3344bdb9230aSGarrett D'Amore uint32_t link, status, mask, polarity;
3345bdb9230aSGarrett D'Amore int settletime, stabletime, waittime, upsamples;
3346bdb9230aSGarrett D'Amore int delay_100, delay_10;
3347bdb9230aSGarrett D'Amore
3348bdb9230aSGarrett D'Amore
3349bdb9230aSGarrett D'Amore ASSERT(MUTEX_HELD(&dnetp->intrlock));
3350bdb9230aSGarrett D'Amore /* Don't autosense if the medium does not support it */
3351bdb9230aSGarrett D'Amore if (block->command & (1 << 15)) {
3352bdb9230aSGarrett D'Amore /* This should be the default block */
3353bdb9230aSGarrett D'Amore if (block->command & (1UL<<14))
3354bdb9230aSGarrett D'Amore dnetp->sr.leaf[dnetp->leaf].default_block = block;
3355bdb9230aSGarrett D'Amore return (0);
3356bdb9230aSGarrett D'Amore }
3357bdb9230aSGarrett D'Amore
3358bdb9230aSGarrett D'Amore delay_100 = ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo,
3359bdb9230aSGarrett D'Amore DDI_PROP_DONTPASS, "autosense-delay-100", 2000);
3360bdb9230aSGarrett D'Amore
3361bdb9230aSGarrett D'Amore delay_10 = ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo,
3362bdb9230aSGarrett D'Amore DDI_PROP_DONTPASS, "autosense-delay-10", 400);
3363bdb9230aSGarrett D'Amore
3364bdb9230aSGarrett D'Amore /*
3365bdb9230aSGarrett D'Amore * Scrambler may need to be disabled for link sensing
3366bdb9230aSGarrett D'Amore * to work
3367bdb9230aSGarrett D'Amore */
3368bdb9230aSGarrett D'Amore dnetp->disable_scrambler = 1;
336998e8d175SSteven Stallion setup_block(dnetp);
3370bdb9230aSGarrett D'Amore dnetp->disable_scrambler = 0;
3371bdb9230aSGarrett D'Amore
3372bdb9230aSGarrett D'Amore if (block->media_code == MEDIA_TP || block->media_code == MEDIA_TP_FD)
3373bdb9230aSGarrett D'Amore settletime = delay_10;
3374bdb9230aSGarrett D'Amore else
3375bdb9230aSGarrett D'Amore settletime = delay_100;
3376bdb9230aSGarrett D'Amore stabletime = settletime / 4;
3377bdb9230aSGarrett D'Amore
3378bdb9230aSGarrett D'Amore mask = 1 << ((block->command & CMD_MEDIABIT_MASK) >> 1);
3379bdb9230aSGarrett D'Amore polarity = block->command & CMD_POL ? 0xffffffff : 0;
3380bdb9230aSGarrett D'Amore
3381bdb9230aSGarrett D'Amore for (waittime = 0, upsamples = 0;
3382bdb9230aSGarrett D'Amore waittime <= settletime + stabletime && upsamples < 8;
3383bdb9230aSGarrett D'Amore waittime += stabletime/8) {
3384bdb9230aSGarrett D'Amore delay(drv_usectohz(stabletime*1000 / 8));
3385bdb9230aSGarrett D'Amore status = read_gpr(dnetp);
3386bdb9230aSGarrett D'Amore link = (status^polarity) & mask;
3387bdb9230aSGarrett D'Amore if (link)
3388bdb9230aSGarrett D'Amore upsamples++;
3389bdb9230aSGarrett D'Amore else
3390bdb9230aSGarrett D'Amore upsamples = 0;
3391bdb9230aSGarrett D'Amore }
3392bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
3393bdb9230aSGarrett D'Amore if (dnetdebug & DNETSENSE)
3394bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "%s upsamples:%d stat:%x polarity:%x "
3395bdb9230aSGarrett D'Amore "mask:%x link:%x",
3396bdb9230aSGarrett D'Amore upsamples == 8 ? "UP":"DOWN",
3397bdb9230aSGarrett D'Amore upsamples, status, polarity, mask, link);
3398bdb9230aSGarrett D'Amore #endif
3399bdb9230aSGarrett D'Amore if (upsamples == 8)
3400bdb9230aSGarrett D'Amore return (1);
3401bdb9230aSGarrett D'Amore return (0);
3402bdb9230aSGarrett D'Amore }
3403bdb9230aSGarrett D'Amore
3404bdb9230aSGarrett D'Amore static int
send_test_packet(struct dnetinstance * dnetp)340598e8d175SSteven Stallion send_test_packet(struct dnetinstance *dnetp)
3406bdb9230aSGarrett D'Amore {
3407bdb9230aSGarrett D'Amore int packet_delay;
3408bdb9230aSGarrett D'Amore struct tx_desc_type *desc;
3409bdb9230aSGarrett D'Amore int bufindex;
3410bdb9230aSGarrett D'Amore int media_code = dnetp->selected_media_block->media_code;
3411bdb9230aSGarrett D'Amore uint32_t del;
3412bdb9230aSGarrett D'Amore
3413bdb9230aSGarrett D'Amore ASSERT(MUTEX_HELD(&dnetp->intrlock));
3414bdb9230aSGarrett D'Amore /*
3415bdb9230aSGarrett D'Amore * For a successful test packet, the card must have settled into
3416bdb9230aSGarrett D'Amore * its current setting. Almost all cards we've tested manage to
3417bdb9230aSGarrett D'Amore * do this with all media within 50ms. However, the SMC 8432
3418bdb9230aSGarrett D'Amore * requires 300ms to settle into BNC mode. We now only do this
3419bdb9230aSGarrett D'Amore * from attach, and we do sleeping delay() instead of drv_usecwait()
3420bdb9230aSGarrett D'Amore * so we hope this .2 second delay won't cause too much suffering.
3421bdb9230aSGarrett D'Amore * ALSO: with an autonegotiating hub, an aditional 1 second delay is
3422bdb9230aSGarrett D'Amore * required. This is done if the media type is TP
3423bdb9230aSGarrett D'Amore */
3424bdb9230aSGarrett D'Amore if (media_code == MEDIA_TP || media_code == MEDIA_TP_FD) {
3425bdb9230aSGarrett D'Amore packet_delay = ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo,
3426bdb9230aSGarrett D'Amore DDI_PROP_DONTPASS, "test_packet_delay_tp", 1300000);
3427bdb9230aSGarrett D'Amore } else {
3428bdb9230aSGarrett D'Amore packet_delay = ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo,
3429bdb9230aSGarrett D'Amore DDI_PROP_DONTPASS, "test_packet_delay", 300000);
3430bdb9230aSGarrett D'Amore }
3431bdb9230aSGarrett D'Amore delay(drv_usectohz(packet_delay));
3432bdb9230aSGarrett D'Amore
3433bdb9230aSGarrett D'Amore desc = dnetp->tx_desc;
3434bdb9230aSGarrett D'Amore
3435bdb9230aSGarrett D'Amore bufindex = dnetp->tx_current_desc;
343698e8d175SSteven Stallion if (alloc_descriptor(dnetp) == FAILURE) {
3437bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "DNET: send_test_packet: alloc_descriptor"
3438bdb9230aSGarrett D'Amore "failed");
3439bdb9230aSGarrett D'Amore return (0);
3440bdb9230aSGarrett D'Amore }
3441bdb9230aSGarrett D'Amore
3442bdb9230aSGarrett D'Amore /*
3443bdb9230aSGarrett D'Amore * use setup buffer as the buffer for the test packet
3444bdb9230aSGarrett D'Amore * instead of allocating one.
3445bdb9230aSGarrett D'Amore */
3446bdb9230aSGarrett D'Amore
3447bdb9230aSGarrett D'Amore ASSERT(dnetp->setup_buf_vaddr != NULL);
3448bdb9230aSGarrett D'Amore /* Put something decent in dest address so we don't annoy other cards */
3449bdb9230aSGarrett D'Amore BCOPY((caddr_t)dnetp->curr_macaddr,
3450bdb9230aSGarrett D'Amore (caddr_t)dnetp->setup_buf_vaddr, ETHERADDRL);
3451bdb9230aSGarrett D'Amore BCOPY((caddr_t)dnetp->curr_macaddr,
3452bdb9230aSGarrett D'Amore (caddr_t)dnetp->setup_buf_vaddr+ETHERADDRL, ETHERADDRL);
3453bdb9230aSGarrett D'Amore
3454bdb9230aSGarrett D'Amore desc[bufindex].buffer1 = dnetp->setup_buf_paddr;
3455bdb9230aSGarrett D'Amore desc[bufindex].desc1.buffer_size1 = SETUPBUF_SIZE;
3456bdb9230aSGarrett D'Amore desc[bufindex].buffer2 = (uint32_t)(0);
3457bdb9230aSGarrett D'Amore desc[bufindex].desc1.first_desc = 1;
3458bdb9230aSGarrett D'Amore desc[bufindex].desc1.last_desc = 1;
3459bdb9230aSGarrett D'Amore desc[bufindex].desc1.int_on_comp = 1;
3460bdb9230aSGarrett D'Amore desc[bufindex].desc0.own = 1;
3461bdb9230aSGarrett D'Amore
3462bdb9230aSGarrett D'Amore ddi_put8(dnetp->io_handle, REG8(dnetp->io_reg, TX_POLL_REG),
3463bdb9230aSGarrett D'Amore TX_POLL_DEMAND);
3464bdb9230aSGarrett D'Amore
3465bdb9230aSGarrett D'Amore /*
3466bdb9230aSGarrett D'Amore * Give enough time for the chip to transmit the packet
3467bdb9230aSGarrett D'Amore */
3468bdb9230aSGarrett D'Amore #if 1
3469bdb9230aSGarrett D'Amore del = 1000;
3470bdb9230aSGarrett D'Amore while (desc[bufindex].desc0.own && --del)
3471bdb9230aSGarrett D'Amore drv_usecwait(10); /* quickly wait up to 10ms */
3472bdb9230aSGarrett D'Amore if (desc[bufindex].desc0.own)
3473bdb9230aSGarrett D'Amore delay(drv_usectohz(200000)); /* nicely wait a longer time */
3474bdb9230aSGarrett D'Amore #else
3475bdb9230aSGarrett D'Amore del = 0x10000;
3476bdb9230aSGarrett D'Amore while (desc[bufindex].desc0.own && --del)
3477bdb9230aSGarrett D'Amore drv_usecwait(10);
3478bdb9230aSGarrett D'Amore #endif
3479bdb9230aSGarrett D'Amore
3480bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
3481bdb9230aSGarrett D'Amore if (dnetdebug & DNETSENSE)
3482bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "desc0 bits = %u, %u, %u, %u, %u, %u",
3483bdb9230aSGarrett D'Amore desc[bufindex].desc0.own,
3484bdb9230aSGarrett D'Amore desc[bufindex].desc0.err_summary,
3485bdb9230aSGarrett D'Amore desc[bufindex].desc0.carrier_loss,
3486bdb9230aSGarrett D'Amore desc[bufindex].desc0.no_carrier,
3487bdb9230aSGarrett D'Amore desc[bufindex].desc0.late_collision,
3488bdb9230aSGarrett D'Amore desc[bufindex].desc0.link_fail);
3489bdb9230aSGarrett D'Amore #endif
3490bdb9230aSGarrett D'Amore if (desc[bufindex].desc0.own) /* it shouldn't take this long, error */
3491bdb9230aSGarrett D'Amore return (0);
3492bdb9230aSGarrett D'Amore
3493bdb9230aSGarrett D'Amore return (!desc[bufindex].desc0.err_summary);
3494bdb9230aSGarrett D'Amore }
3495bdb9230aSGarrett D'Amore
3496bdb9230aSGarrett D'Amore /* enable_interrupts - called with intrlock held */
3497bdb9230aSGarrett D'Amore static void
enable_interrupts(struct dnetinstance * dnetp)349898e8d175SSteven Stallion enable_interrupts(struct dnetinstance *dnetp)
3499bdb9230aSGarrett D'Amore {
3500bdb9230aSGarrett D'Amore ASSERT(MUTEX_HELD(&dnetp->intrlock));
3501bdb9230aSGarrett D'Amore /* Don't enable interrupts if they have been forced off */
3502bdb9230aSGarrett D'Amore if (dnetp->interrupts_disabled)
3503bdb9230aSGarrett D'Amore return;
3504bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, INT_MASK_REG),
350598e8d175SSteven Stallion ABNORMAL_INTR_MASK | NORMAL_INTR_MASK | SYSTEM_ERROR_MASK |
3506bdb9230aSGarrett D'Amore (dnetp->timer.cb ? GPTIMER_INTR : 0) |
350798e8d175SSteven Stallion RX_INTERRUPT_MASK |
350898e8d175SSteven Stallion TX_INTERRUPT_MASK | TX_JABBER_MASK | TX_UNDERFLOW_MASK);
3509bdb9230aSGarrett D'Amore }
3510bdb9230aSGarrett D'Amore
3511bdb9230aSGarrett D'Amore /*
3512bdb9230aSGarrett D'Amore * Some older multiport cards are non-PCI compliant in their interrupt routing.
3513bdb9230aSGarrett D'Amore * Second and subsequent devices are incorrectly configured by the BIOS
3514bdb9230aSGarrett D'Amore * (either in their ILINE configuration or the MP Configuration Table for PC+MP
3515bdb9230aSGarrett D'Amore * systems).
351698e8d175SSteven Stallion * The hack stops registering the interrupt routine for the FIRST
351798e8d175SSteven Stallion * device on the adapter, and registers its own. It builds up a table
351898e8d175SSteven Stallion * of dnetp structures for each device, and the new interrupt routine
351998e8d175SSteven Stallion * calls dnet_intr for each of them.
3520bdb9230aSGarrett D'Amore * Known cards that suffer from this problem are:
3521bdb9230aSGarrett D'Amore * All Cogent multiport cards;
3522bdb9230aSGarrett D'Amore * Znyx 314;
3523bdb9230aSGarrett D'Amore * Znyx 315.
3524bdb9230aSGarrett D'Amore *
3525bdb9230aSGarrett D'Amore * XXX NEEDSWORK -- see comments above get_alternative_srom_image(). This
3526bdb9230aSGarrett D'Amore * hack relies on the fact that the offending cards will have only one SROM.
3527bdb9230aSGarrett D'Amore * It uses this fact to identify devices that are on the same multiport
3528bdb9230aSGarrett D'Amore * adapter, as opposed to multiple devices from the same vendor (as
3529bdb9230aSGarrett D'Amore * indicated by "secondary")
3530bdb9230aSGarrett D'Amore */
3531bdb9230aSGarrett D'Amore static int
dnet_hack_interrupts(struct dnetinstance * dnetp,int secondary)353298e8d175SSteven Stallion dnet_hack_interrupts(struct dnetinstance *dnetp, int secondary)
3533bdb9230aSGarrett D'Amore {
3534bdb9230aSGarrett D'Amore int i;
3535bdb9230aSGarrett D'Amore struct hackintr_inf *hackintr_inf;
3536bdb9230aSGarrett D'Amore dev_info_t *devinfo = dnetp->devinfo;
3537bdb9230aSGarrett D'Amore uint32_t oui = 0; /* Organizationally Unique ID */
3538bdb9230aSGarrett D'Amore
3539bdb9230aSGarrett D'Amore if (ddi_getprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
3540bdb9230aSGarrett D'Amore "no_INTA_workaround", 0) != 0)
3541bdb9230aSGarrett D'Amore return (0);
3542bdb9230aSGarrett D'Amore
3543bdb9230aSGarrett D'Amore for (i = 0; i < 3; i++)
3544bdb9230aSGarrett D'Amore oui = (oui << 8) | dnetp->vendor_addr[i];
3545bdb9230aSGarrett D'Amore
3546bdb9230aSGarrett D'Amore /* Check wheather or not we need to implement the hack */
3547bdb9230aSGarrett D'Amore
3548bdb9230aSGarrett D'Amore switch (oui) {
3549bdb9230aSGarrett D'Amore case ZNYX_ETHER:
3550bdb9230aSGarrett D'Amore /* Znyx multiport 21040 cards <<==>> ZX314 or ZX315 */
3551bdb9230aSGarrett D'Amore if (dnetp->board_type != DEVICE_ID_21040)
3552bdb9230aSGarrett D'Amore return (0);
3553bdb9230aSGarrett D'Amore break;
3554bdb9230aSGarrett D'Amore
3555bdb9230aSGarrett D'Amore case COGENT_ETHER:
3556bdb9230aSGarrett D'Amore /* All known Cogent multiport cards */
3557bdb9230aSGarrett D'Amore break;
3558bdb9230aSGarrett D'Amore
3559bdb9230aSGarrett D'Amore case ADAPTEC_ETHER:
3560bdb9230aSGarrett D'Amore /* Adaptec multiport cards */
3561bdb9230aSGarrett D'Amore break;
3562bdb9230aSGarrett D'Amore
3563bdb9230aSGarrett D'Amore default:
3564bdb9230aSGarrett D'Amore /* Other cards work correctly */
3565bdb9230aSGarrett D'Amore return (0);
3566bdb9230aSGarrett D'Amore }
3567bdb9230aSGarrett D'Amore
3568bdb9230aSGarrett D'Amore /* card is (probably) non-PCI compliant in its interrupt routing */
3569bdb9230aSGarrett D'Amore
3570bdb9230aSGarrett D'Amore
3571bdb9230aSGarrett D'Amore if (!secondary) {
3572bdb9230aSGarrett D'Amore
3573bdb9230aSGarrett D'Amore /*
3574bdb9230aSGarrett D'Amore * If we have already registered a hacked interrupt, and
3575bdb9230aSGarrett D'Amore * this is also a 'primary' adapter, then this is NOT part of
3576bdb9230aSGarrett D'Amore * a multiport card, but a second card on the same PCI bus.
3577bdb9230aSGarrett D'Amore * BUGID: 4057747
3578bdb9230aSGarrett D'Amore */
3579bdb9230aSGarrett D'Amore if (ddi_getprop(DDI_DEV_T_ANY, ddi_get_parent(devinfo),
3580bdb9230aSGarrett D'Amore DDI_PROP_DONTPASS, hackintr_propname, 0) != 0)
3581bdb9230aSGarrett D'Amore return (0);
3582bdb9230aSGarrett D'Amore /* ... Primary not part of a multiport device */
3583bdb9230aSGarrett D'Amore
3584bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
3585bdb9230aSGarrett D'Amore if (dnetdebug & DNETTRACE)
3586bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "dnet: Implementing hardware "
3587bdb9230aSGarrett D'Amore "interrupt flaw workaround");
3588bdb9230aSGarrett D'Amore #endif
3589bdb9230aSGarrett D'Amore dnetp->hackintr_inf = hackintr_inf =
3590bdb9230aSGarrett D'Amore kmem_zalloc(sizeof (struct hackintr_inf), KM_SLEEP);
3591bdb9230aSGarrett D'Amore if (hackintr_inf == NULL)
3592bdb9230aSGarrett D'Amore goto fail;
3593bdb9230aSGarrett D'Amore
359498e8d175SSteven Stallion hackintr_inf->dnetps[0] = dnetp;
3595bdb9230aSGarrett D'Amore hackintr_inf->devinfo = devinfo;
3596bdb9230aSGarrett D'Amore
3597bdb9230aSGarrett D'Amore /*
3598bdb9230aSGarrett D'Amore * Add a property to allow successive attaches to find the
3599bdb9230aSGarrett D'Amore * table
3600bdb9230aSGarrett D'Amore */
3601bdb9230aSGarrett D'Amore
3602bdb9230aSGarrett D'Amore if (ddi_prop_update_byte_array(DDI_DEV_T_NONE,
3603bdb9230aSGarrett D'Amore ddi_get_parent(devinfo), hackintr_propname,
3604bdb9230aSGarrett D'Amore (uchar_t *)&dnetp->hackintr_inf,
3605bdb9230aSGarrett D'Amore sizeof (void *)) != DDI_PROP_SUCCESS)
3606bdb9230aSGarrett D'Amore goto fail;
3607bdb9230aSGarrett D'Amore
3608bdb9230aSGarrett D'Amore
3609bdb9230aSGarrett D'Amore /* Register our hacked interrupt routine */
361098e8d175SSteven Stallion if (ddi_add_intr(devinfo, 0, &dnetp->icookie, NULL,
3611bdb9230aSGarrett D'Amore (uint_t (*)(char *))dnet_hack_intr,
3612bdb9230aSGarrett D'Amore (caddr_t)hackintr_inf) != DDI_SUCCESS) {
3613bdb9230aSGarrett D'Amore /* XXX function return value ignored */
3614bdb9230aSGarrett D'Amore (void) ddi_prop_remove(DDI_DEV_T_NONE,
3615bdb9230aSGarrett D'Amore ddi_get_parent(devinfo),
3616bdb9230aSGarrett D'Amore hackintr_propname);
3617bdb9230aSGarrett D'Amore goto fail;
3618bdb9230aSGarrett D'Amore }
3619bdb9230aSGarrett D'Amore
3620bdb9230aSGarrett D'Amore /*
3621bdb9230aSGarrett D'Amore * Mutex required to ensure interrupt routine has completed
3622bdb9230aSGarrett D'Amore * when detaching devices
3623bdb9230aSGarrett D'Amore */
3624bdb9230aSGarrett D'Amore mutex_init(&hackintr_inf->lock, NULL, MUTEX_DRIVER,
362598e8d175SSteven Stallion dnetp->icookie);
3626bdb9230aSGarrett D'Amore
3627bdb9230aSGarrett D'Amore /* Stop GLD registering an interrupt */
3628bdb9230aSGarrett D'Amore return (-1);
3629bdb9230aSGarrett D'Amore } else {
3630bdb9230aSGarrett D'Amore
363198e8d175SSteven Stallion /* Add the dnetp for this secondary device to the table */
3632bdb9230aSGarrett D'Amore
3633bdb9230aSGarrett D'Amore hackintr_inf = (struct hackintr_inf *)(uintptr_t)
3634bdb9230aSGarrett D'Amore ddi_getprop(DDI_DEV_T_ANY, ddi_get_parent(devinfo),
3635bdb9230aSGarrett D'Amore DDI_PROP_DONTPASS, hackintr_propname, 0);
3636bdb9230aSGarrett D'Amore
3637bdb9230aSGarrett D'Amore if (hackintr_inf == NULL)
3638bdb9230aSGarrett D'Amore goto fail;
3639bdb9230aSGarrett D'Amore
3640bdb9230aSGarrett D'Amore /* Find an empty slot */
3641bdb9230aSGarrett D'Amore for (i = 0; i < MAX_INST; i++)
364298e8d175SSteven Stallion if (hackintr_inf->dnetps[i] == NULL)
3643bdb9230aSGarrett D'Amore break;
3644bdb9230aSGarrett D'Amore
3645bdb9230aSGarrett D'Amore /* More than 8 ports on adapter ?! */
3646bdb9230aSGarrett D'Amore if (i == MAX_INST)
3647bdb9230aSGarrett D'Amore goto fail;
3648bdb9230aSGarrett D'Amore
364998e8d175SSteven Stallion hackintr_inf->dnetps[i] = dnetp;
3650bdb9230aSGarrett D'Amore
3651bdb9230aSGarrett D'Amore /*
3652bdb9230aSGarrett D'Amore * Allow GLD to register a handler for this
3653bdb9230aSGarrett D'Amore * device. If the card is actually broken, as we suspect, this
3654bdb9230aSGarrett D'Amore * handler will never get called. However, by registering the
3655bdb9230aSGarrett D'Amore * interrupt handler, we can copy gracefully with new multiport
3656bdb9230aSGarrett D'Amore * Cogent cards that decide to fix the hardware problem
3657bdb9230aSGarrett D'Amore */
3658bdb9230aSGarrett D'Amore return (0);
3659bdb9230aSGarrett D'Amore }
3660bdb9230aSGarrett D'Amore
3661bdb9230aSGarrett D'Amore fail:
3662bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "dnet: Could not work around hardware interrupt"
3663bdb9230aSGarrett D'Amore " routing problem");
3664bdb9230aSGarrett D'Amore return (0);
3665bdb9230aSGarrett D'Amore }
3666bdb9230aSGarrett D'Amore
3667bdb9230aSGarrett D'Amore /*
366898e8d175SSteven Stallion * Call dnet_intr for all adapters on a multiport card
3669bdb9230aSGarrett D'Amore */
3670bdb9230aSGarrett D'Amore static uint_t
dnet_hack_intr(struct hackintr_inf * hackintr_inf)3671bdb9230aSGarrett D'Amore dnet_hack_intr(struct hackintr_inf *hackintr_inf)
3672bdb9230aSGarrett D'Amore {
3673bdb9230aSGarrett D'Amore int i;
3674bdb9230aSGarrett D'Amore int claimed = DDI_INTR_UNCLAIMED;
3675bdb9230aSGarrett D'Amore
3676bdb9230aSGarrett D'Amore /* Stop detaches while processing interrupts */
3677bdb9230aSGarrett D'Amore mutex_enter(&hackintr_inf->lock);
3678bdb9230aSGarrett D'Amore
3679bdb9230aSGarrett D'Amore for (i = 0; i < MAX_INST; i++) {
368098e8d175SSteven Stallion if (hackintr_inf->dnetps[i] &&
368198e8d175SSteven Stallion dnet_intr((caddr_t)hackintr_inf->dnetps[i]) ==
368298e8d175SSteven Stallion DDI_INTR_CLAIMED) {
3683bdb9230aSGarrett D'Amore claimed = DDI_INTR_CLAIMED;
3684bdb9230aSGarrett D'Amore }
368598e8d175SSteven Stallion }
3686bdb9230aSGarrett D'Amore mutex_exit(&hackintr_inf->lock);
3687bdb9230aSGarrett D'Amore return (claimed);
3688bdb9230aSGarrett D'Amore }
3689bdb9230aSGarrett D'Amore
3690bdb9230aSGarrett D'Amore /*
3691bdb9230aSGarrett D'Amore * This removes the detaching device from the table procesed by the hacked
3692bdb9230aSGarrett D'Amore * interrupt routine. Because the interrupts from all devices come in to the
3693bdb9230aSGarrett D'Amore * same interrupt handler, ALL devices must stop interrupting once the
3694bdb9230aSGarrett D'Amore * primary device detaches. This isn't a problem at present, because all
3695bdb9230aSGarrett D'Amore * instances of a device are detached when the driver is unloaded.
3696bdb9230aSGarrett D'Amore */
3697bdb9230aSGarrett D'Amore static int
dnet_detach_hacked_interrupt(dev_info_t * devinfo)3698bdb9230aSGarrett D'Amore dnet_detach_hacked_interrupt(dev_info_t *devinfo)
3699bdb9230aSGarrett D'Amore {
3700bdb9230aSGarrett D'Amore int i;
3701bdb9230aSGarrett D'Amore struct hackintr_inf *hackintr_inf;
370298e8d175SSteven Stallion struct dnetinstance *altdnetp, *dnetp =
370398e8d175SSteven Stallion ddi_get_driver_private(devinfo);
3704bdb9230aSGarrett D'Amore
3705bdb9230aSGarrett D'Amore hackintr_inf = (struct hackintr_inf *)(uintptr_t)
3706bdb9230aSGarrett D'Amore ddi_getprop(DDI_DEV_T_ANY, ddi_get_parent(devinfo),
3707bdb9230aSGarrett D'Amore DDI_PROP_DONTPASS, hackintr_propname, 0);
3708bdb9230aSGarrett D'Amore
3709bdb9230aSGarrett D'Amore /*
3710bdb9230aSGarrett D'Amore * No hackintr_inf implies hack was not required or the primary has
3711bdb9230aSGarrett D'Amore * detached, and our interrupts are already disabled
3712bdb9230aSGarrett D'Amore */
3713bdb9230aSGarrett D'Amore if (!hackintr_inf) {
3714bdb9230aSGarrett D'Amore /* remove the interrupt for the non-hacked case */
371598e8d175SSteven Stallion ddi_remove_intr(devinfo, 0, dnetp->icookie);
3716bdb9230aSGarrett D'Amore return (DDI_SUCCESS);
3717bdb9230aSGarrett D'Amore }
3718bdb9230aSGarrett D'Amore
3719bdb9230aSGarrett D'Amore /* Remove this device from the handled table */
3720bdb9230aSGarrett D'Amore mutex_enter(&hackintr_inf->lock);
3721bdb9230aSGarrett D'Amore for (i = 0; i < MAX_INST; i++) {
372298e8d175SSteven Stallion if (hackintr_inf->dnetps[i] == dnetp) {
372398e8d175SSteven Stallion hackintr_inf->dnetps[i] = NULL;
3724bdb9230aSGarrett D'Amore break;
3725bdb9230aSGarrett D'Amore }
3726bdb9230aSGarrett D'Amore }
3727bdb9230aSGarrett D'Amore
3728bdb9230aSGarrett D'Amore mutex_exit(&hackintr_inf->lock);
3729bdb9230aSGarrett D'Amore
3730bdb9230aSGarrett D'Amore /* Not the primary card, we are done */
3731bdb9230aSGarrett D'Amore if (devinfo != hackintr_inf->devinfo)
3732bdb9230aSGarrett D'Amore return (DDI_SUCCESS);
3733bdb9230aSGarrett D'Amore
3734bdb9230aSGarrett D'Amore /*
3735bdb9230aSGarrett D'Amore * This is the primary card. All remaining adapters on this device
3736bdb9230aSGarrett D'Amore * must have their interrupts disabled before we remove the handler
3737bdb9230aSGarrett D'Amore */
3738bdb9230aSGarrett D'Amore for (i = 0; i < MAX_INST; i++) {
373998e8d175SSteven Stallion if ((altdnetp = hackintr_inf->dnetps[i]) != NULL) {
3740bdb9230aSGarrett D'Amore altdnetp->interrupts_disabled = 1;
3741bdb9230aSGarrett D'Amore ddi_put32(altdnetp->io_handle,
3742bdb9230aSGarrett D'Amore REG32(altdnetp->io_reg, INT_MASK_REG), 0);
3743bdb9230aSGarrett D'Amore }
3744bdb9230aSGarrett D'Amore }
3745bdb9230aSGarrett D'Amore
3746bdb9230aSGarrett D'Amore /* It should now be safe to remove the interrupt handler */
3747bdb9230aSGarrett D'Amore
374898e8d175SSteven Stallion ddi_remove_intr(devinfo, 0, dnetp->icookie);
3749bdb9230aSGarrett D'Amore mutex_destroy(&hackintr_inf->lock);
3750bdb9230aSGarrett D'Amore /* XXX function return value ignored */
3751bdb9230aSGarrett D'Amore (void) ddi_prop_remove(DDI_DEV_T_NONE, ddi_get_parent(devinfo),
3752bdb9230aSGarrett D'Amore hackintr_propname);
3753bdb9230aSGarrett D'Amore kmem_free(hackintr_inf, sizeof (struct hackintr_inf));
3754bdb9230aSGarrett D'Amore return (DDI_SUCCESS);
3755bdb9230aSGarrett D'Amore }
3756bdb9230aSGarrett D'Amore
3757bdb9230aSGarrett D'Amore /* do_phy() - called with intrlock held */
3758bdb9230aSGarrett D'Amore static void
do_phy(struct dnetinstance * dnetp)375998e8d175SSteven Stallion do_phy(struct dnetinstance *dnetp)
3760bdb9230aSGarrett D'Amore {
3761bdb9230aSGarrett D'Amore dev_info_t *dip;
3762bdb9230aSGarrett D'Amore LEAF_FORMAT *leaf = dnetp->sr.leaf + dnetp->leaf;
3763bdb9230aSGarrett D'Amore media_block_t *block;
3764bdb9230aSGarrett D'Amore int phy;
3765bdb9230aSGarrett D'Amore
3766bdb9230aSGarrett D'Amore dip = dnetp->devinfo;
3767bdb9230aSGarrett D'Amore
3768bdb9230aSGarrett D'Amore /*
3769bdb9230aSGarrett D'Amore * Find and configure the PHY media block. If NO PHY blocks are
3770bdb9230aSGarrett D'Amore * found on the SROM, but a PHY device is present, we assume the card
3771bdb9230aSGarrett D'Amore * is a legacy device, and that there is ONLY a PHY interface on the
3772bdb9230aSGarrett D'Amore * card (ie, no BNC or AUI, and 10BaseT is implemented by the PHY
3773bdb9230aSGarrett D'Amore */
3774bdb9230aSGarrett D'Amore
3775bdb9230aSGarrett D'Amore for (block = leaf->block + leaf->block_count -1;
3776bdb9230aSGarrett D'Amore block >= leaf->block; block --) {
3777bdb9230aSGarrett D'Amore if (block->type == 3 || block->type == 1) {
3778bdb9230aSGarrett D'Amore leaf->mii_block = block;
3779bdb9230aSGarrett D'Amore break;
3780bdb9230aSGarrett D'Amore }
3781bdb9230aSGarrett D'Amore }
3782bdb9230aSGarrett D'Amore
3783bdb9230aSGarrett D'Amore /*
3784bdb9230aSGarrett D'Amore * If no MII block, select default, and hope this configuration will
3785bdb9230aSGarrett D'Amore * allow the phy to be read/written if it is present
3786bdb9230aSGarrett D'Amore */
3787bdb9230aSGarrett D'Amore dnetp->selected_media_block = leaf->mii_block ?
3788bdb9230aSGarrett D'Amore leaf->mii_block : leaf->default_block;
3789bdb9230aSGarrett D'Amore
379098e8d175SSteven Stallion setup_block(dnetp);
3791bdb9230aSGarrett D'Amore /* XXX function return value ignored */
3792bdb9230aSGarrett D'Amore (void) mii_create(dip, dnet_mii_write, dnet_mii_read, &dnetp->mii);
3793bdb9230aSGarrett D'Amore
3794bdb9230aSGarrett D'Amore /*
3795bdb9230aSGarrett D'Amore * We try PHY 0 LAST because it is less likely to be connected
3796bdb9230aSGarrett D'Amore */
3797bdb9230aSGarrett D'Amore for (phy = 1; phy < 33; phy++)
3798bdb9230aSGarrett D'Amore if (mii_probe_phy(dnetp->mii, phy % 32) == MII_SUCCESS &&
3799bdb9230aSGarrett D'Amore mii_init_phy(dnetp->mii, phy % 32) == MII_SUCCESS) {
3800bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
3801bdb9230aSGarrett D'Amore if (dnetdebug & DNETSENSE)
3802bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "dnet: "
3803bdb9230aSGarrett D'Amore "PHY at address %d", phy % 32);
3804bdb9230aSGarrett D'Amore #endif
3805bdb9230aSGarrett D'Amore dnetp->phyaddr = phy % 32;
3806bdb9230aSGarrett D'Amore if (!leaf->mii_block) {
3807bdb9230aSGarrett D'Amore /* Legacy card, change the leaf node */
3808bdb9230aSGarrett D'Amore set_leaf(&dnetp->sr, &leaf_phylegacy);
3809bdb9230aSGarrett D'Amore }
3810bdb9230aSGarrett D'Amore return;
3811bdb9230aSGarrett D'Amore }
3812bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
3813bdb9230aSGarrett D'Amore if (dnetdebug & DNETSENSE)
3814bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "dnet: No PHY found");
3815bdb9230aSGarrett D'Amore #endif
3816bdb9230aSGarrett D'Amore }
3817bdb9230aSGarrett D'Amore
3818bdb9230aSGarrett D'Amore static ushort_t
dnet_mii_read(dev_info_t * dip,int phy_addr,int reg_num)3819bdb9230aSGarrett D'Amore dnet_mii_read(dev_info_t *dip, int phy_addr, int reg_num)
3820bdb9230aSGarrett D'Amore {
3821bdb9230aSGarrett D'Amore struct dnetinstance *dnetp;
3822bdb9230aSGarrett D'Amore
3823bdb9230aSGarrett D'Amore uint32_t command_word;
3824bdb9230aSGarrett D'Amore uint32_t tmp;
3825bdb9230aSGarrett D'Amore uint32_t data = 0;
3826bdb9230aSGarrett D'Amore int i;
3827bdb9230aSGarrett D'Amore int bits_in_ushort = ((sizeof (ushort_t))*8);
3828bdb9230aSGarrett D'Amore int turned_around = 0;
3829bdb9230aSGarrett D'Amore
383098e8d175SSteven Stallion dnetp = ddi_get_driver_private(dip);
3831bdb9230aSGarrett D'Amore
3832bdb9230aSGarrett D'Amore ASSERT(MUTEX_HELD(&dnetp->intrlock));
3833bdb9230aSGarrett D'Amore /* Write Preamble */
3834bdb9230aSGarrett D'Amore write_mii(dnetp, MII_PRE, 2*bits_in_ushort);
3835bdb9230aSGarrett D'Amore
3836bdb9230aSGarrett D'Amore /* Prepare command word */
3837bdb9230aSGarrett D'Amore command_word = (uint32_t)phy_addr << MII_PHY_ADDR_ALIGN;
3838bdb9230aSGarrett D'Amore command_word |= (uint32_t)reg_num << MII_REG_ADDR_ALIGN;
3839bdb9230aSGarrett D'Amore command_word |= MII_READ_FRAME;
3840bdb9230aSGarrett D'Amore
3841bdb9230aSGarrett D'Amore write_mii(dnetp, command_word, bits_in_ushort-2);
3842bdb9230aSGarrett D'Amore
3843bdb9230aSGarrett D'Amore mii_tristate(dnetp);
3844bdb9230aSGarrett D'Amore
3845bdb9230aSGarrett D'Amore /* Check that the PHY generated a zero bit the 2nd clock */
3846bdb9230aSGarrett D'Amore tmp = ddi_get32(dnetp->io_handle, REG32(dnetp->io_reg, ETHER_ROM_REG));
3847bdb9230aSGarrett D'Amore
3848bdb9230aSGarrett D'Amore turned_around = (tmp & MII_DATA_IN) ? 0 : 1;
3849bdb9230aSGarrett D'Amore
3850bdb9230aSGarrett D'Amore /* read data WORD */
3851bdb9230aSGarrett D'Amore for (i = 0; i < bits_in_ushort; i++) {
3852bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle,
3853bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, ETHER_ROM_REG), MII_READ);
3854bdb9230aSGarrett D'Amore drv_usecwait(MII_DELAY);
3855bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle,
3856bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, ETHER_ROM_REG), MII_READ | MII_CLOCK);
3857bdb9230aSGarrett D'Amore drv_usecwait(MII_DELAY);
3858bdb9230aSGarrett D'Amore tmp = ddi_get32(dnetp->io_handle,
3859bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, ETHER_ROM_REG));
3860bdb9230aSGarrett D'Amore drv_usecwait(MII_DELAY);
3861bdb9230aSGarrett D'Amore data = (data << 1) | (tmp >> MII_DATA_IN_POSITION) & 0x0001;
3862bdb9230aSGarrett D'Amore }
3863bdb9230aSGarrett D'Amore
3864bdb9230aSGarrett D'Amore mii_tristate(dnetp);
3865bdb9230aSGarrett D'Amore return (turned_around ? data: -1);
3866bdb9230aSGarrett D'Amore }
3867bdb9230aSGarrett D'Amore
3868bdb9230aSGarrett D'Amore static void
dnet_mii_write(dev_info_t * dip,int phy_addr,int reg_num,int reg_dat)3869bdb9230aSGarrett D'Amore dnet_mii_write(dev_info_t *dip, int phy_addr, int reg_num, int reg_dat)
3870bdb9230aSGarrett D'Amore {
3871bdb9230aSGarrett D'Amore struct dnetinstance *dnetp;
3872bdb9230aSGarrett D'Amore uint32_t command_word;
3873bdb9230aSGarrett D'Amore int bits_in_ushort = ((sizeof (ushort_t))*8);
3874bdb9230aSGarrett D'Amore
387598e8d175SSteven Stallion dnetp = ddi_get_driver_private(dip);
3876bdb9230aSGarrett D'Amore
3877bdb9230aSGarrett D'Amore ASSERT(MUTEX_HELD(&dnetp->intrlock));
3878bdb9230aSGarrett D'Amore write_mii(dnetp, MII_PRE, 2*bits_in_ushort);
3879bdb9230aSGarrett D'Amore
3880bdb9230aSGarrett D'Amore /* Prepare command word */
3881bdb9230aSGarrett D'Amore command_word = ((uint32_t)phy_addr << MII_PHY_ADDR_ALIGN);
3882bdb9230aSGarrett D'Amore command_word |= ((uint32_t)reg_num << MII_REG_ADDR_ALIGN);
3883bdb9230aSGarrett D'Amore command_word |= (MII_WRITE_FRAME | (uint32_t)reg_dat);
3884bdb9230aSGarrett D'Amore
3885bdb9230aSGarrett D'Amore write_mii(dnetp, command_word, 2*bits_in_ushort);
3886bdb9230aSGarrett D'Amore mii_tristate(dnetp);
3887bdb9230aSGarrett D'Amore }
3888bdb9230aSGarrett D'Amore
3889bdb9230aSGarrett D'Amore /*
3890bdb9230aSGarrett D'Amore * Write data size bits from mii_data to the MII control lines.
3891bdb9230aSGarrett D'Amore */
3892bdb9230aSGarrett D'Amore static void
write_mii(struct dnetinstance * dnetp,uint32_t mii_data,int data_size)3893bdb9230aSGarrett D'Amore write_mii(struct dnetinstance *dnetp, uint32_t mii_data, int data_size)
3894bdb9230aSGarrett D'Amore {
3895bdb9230aSGarrett D'Amore int i;
3896bdb9230aSGarrett D'Amore uint32_t dbit;
3897bdb9230aSGarrett D'Amore
3898bdb9230aSGarrett D'Amore ASSERT(MUTEX_HELD(&dnetp->intrlock));
3899bdb9230aSGarrett D'Amore for (i = data_size; i > 0; i--) {
3900bdb9230aSGarrett D'Amore dbit = ((mii_data >>
3901bdb9230aSGarrett D'Amore (31 - MII_WRITE_DATA_POSITION)) & MII_WRITE_DATA);
3902bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle,
3903bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, ETHER_ROM_REG),
3904bdb9230aSGarrett D'Amore MII_WRITE | dbit);
3905bdb9230aSGarrett D'Amore drv_usecwait(MII_DELAY);
3906bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle,
3907bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, ETHER_ROM_REG),
3908bdb9230aSGarrett D'Amore MII_WRITE | MII_CLOCK | dbit);
3909bdb9230aSGarrett D'Amore drv_usecwait(MII_DELAY);
3910bdb9230aSGarrett D'Amore mii_data <<= 1;
3911bdb9230aSGarrett D'Amore }
3912bdb9230aSGarrett D'Amore }
3913bdb9230aSGarrett D'Amore
3914bdb9230aSGarrett D'Amore /*
3915bdb9230aSGarrett D'Amore * Put the MDIO port in tri-state for the turn around bits
3916bdb9230aSGarrett D'Amore * in MII read and at end of MII management sequence.
3917bdb9230aSGarrett D'Amore */
3918bdb9230aSGarrett D'Amore static void
mii_tristate(struct dnetinstance * dnetp)3919bdb9230aSGarrett D'Amore mii_tristate(struct dnetinstance *dnetp)
3920bdb9230aSGarrett D'Amore {
3921bdb9230aSGarrett D'Amore ASSERT(MUTEX_HELD(&dnetp->intrlock));
3922bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, ETHER_ROM_REG),
3923bdb9230aSGarrett D'Amore MII_WRITE_TS);
3924bdb9230aSGarrett D'Amore drv_usecwait(MII_DELAY);
3925bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, ETHER_ROM_REG),
3926bdb9230aSGarrett D'Amore MII_WRITE_TS | MII_CLOCK);
3927bdb9230aSGarrett D'Amore drv_usecwait(MII_DELAY);
3928bdb9230aSGarrett D'Amore }
3929bdb9230aSGarrett D'Amore
3930bdb9230aSGarrett D'Amore
3931bdb9230aSGarrett D'Amore static void
set_leaf(SROM_FORMAT * sr,LEAF_FORMAT * leaf)3932bdb9230aSGarrett D'Amore set_leaf(SROM_FORMAT *sr, LEAF_FORMAT *leaf)
3933bdb9230aSGarrett D'Amore {
3934bdb9230aSGarrett D'Amore if (sr->leaf && !sr->leaf->is_static)
3935bdb9230aSGarrett D'Amore kmem_free(sr->leaf, sr->adapters * sizeof (LEAF_FORMAT));
3936bdb9230aSGarrett D'Amore sr->leaf = leaf;
3937bdb9230aSGarrett D'Amore }
3938bdb9230aSGarrett D'Amore
3939bdb9230aSGarrett D'Amore /*
3940bdb9230aSGarrett D'Amore * Callback from MII module. Makes sure that the CSR registers are
3941bdb9230aSGarrett D'Amore * configured properly if the PHY changes mode.
3942bdb9230aSGarrett D'Amore */
3943bdb9230aSGarrett D'Amore /* ARGSUSED */
3944bdb9230aSGarrett D'Amore /* dnet_mii_link_cb - called with intrlock held */
3945bdb9230aSGarrett D'Amore static void
dnet_mii_link_cb(dev_info_t * dip,int phy,enum mii_phy_state state)3946bdb9230aSGarrett D'Amore dnet_mii_link_cb(dev_info_t *dip, int phy, enum mii_phy_state state)
3947bdb9230aSGarrett D'Amore {
394898e8d175SSteven Stallion struct dnetinstance *dnetp = ddi_get_driver_private(dip);
3949bdb9230aSGarrett D'Amore LEAF_FORMAT *leaf;
3950bdb9230aSGarrett D'Amore
3951bdb9230aSGarrett D'Amore ASSERT(MUTEX_HELD(&dnetp->intrlock));
395298e8d175SSteven Stallion
3953bdb9230aSGarrett D'Amore leaf = dnetp->sr.leaf + dnetp->leaf;
3954bdb9230aSGarrett D'Amore if (state == phy_state_linkup) {
3955bdb9230aSGarrett D'Amore dnetp->mii_up = 1;
395698e8d175SSteven Stallion
395798e8d175SSteven Stallion (void) mii_getspeed(dnetp->mii, dnetp->phyaddr,
395898e8d175SSteven Stallion &dnetp->mii_speed, &dnetp->mii_duplex);
395998e8d175SSteven Stallion
3960bdb9230aSGarrett D'Amore dnetp->selected_media_block = leaf->mii_block;
396198e8d175SSteven Stallion setup_block(dnetp);
3962bdb9230aSGarrett D'Amore } else {
3963bdb9230aSGarrett D'Amore /* NEEDSWORK: Probably can call find_active_media here */
3964bdb9230aSGarrett D'Amore dnetp->mii_up = 0;
396598e8d175SSteven Stallion
3966bdb9230aSGarrett D'Amore if (leaf->default_block->media_code == MEDIA_MII)
3967bdb9230aSGarrett D'Amore dnetp->selected_media_block = leaf->default_block;
396898e8d175SSteven Stallion setup_block(dnetp);
396998e8d175SSteven Stallion }
397098e8d175SSteven Stallion
397132607e28SSteven Stallion if (dnetp->running) {
397232607e28SSteven Stallion mac_link_update(dnetp->mac_handle,
397332607e28SSteven Stallion (dnetp->mii_up ? LINK_STATE_UP : LINK_STATE_DOWN));
3974bdb9230aSGarrett D'Amore }
3975bdb9230aSGarrett D'Amore }
3976bdb9230aSGarrett D'Amore
3977bdb9230aSGarrett D'Amore /*
3978bdb9230aSGarrett D'Amore * SROM parsing routines.
3979bdb9230aSGarrett D'Amore * Refer to the Digital 3.03 SROM spec while reading this! (references refer
3980bdb9230aSGarrett D'Amore * to this document)
3981bdb9230aSGarrett D'Amore * Where possible ALL vendor specific changes should be localised here. The
3982bdb9230aSGarrett D'Amore * SROM data should be capable of describing any programmatic irregularities
3983bdb9230aSGarrett D'Amore * of DNET cards (via SIA or GP registers, in particular), so vendor specific
3984bdb9230aSGarrett D'Amore * code elsewhere should not be required
3985bdb9230aSGarrett D'Amore */
3986bdb9230aSGarrett D'Amore static void
dnet_parse_srom(struct dnetinstance * dnetp,SROM_FORMAT * sr,uchar_t * vi)3987bdb9230aSGarrett D'Amore dnet_parse_srom(struct dnetinstance *dnetp, SROM_FORMAT *sr, uchar_t *vi)
3988bdb9230aSGarrett D'Amore {
3989bdb9230aSGarrett D'Amore uint32_t ether_mfg = 0;
3990bdb9230aSGarrett D'Amore int i;
3991bdb9230aSGarrett D'Amore uchar_t *p;
3992bdb9230aSGarrett D'Amore
3993bdb9230aSGarrett D'Amore if (!ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo,
3994bdb9230aSGarrett D'Amore DDI_PROP_DONTPASS, "no_sromconfig", 0))
3995bdb9230aSGarrett D'Amore dnetp->sr.init_from_srom = check_srom_valid(vi);
3996bdb9230aSGarrett D'Amore
3997bdb9230aSGarrett D'Amore if (dnetp->sr.init_from_srom && dnetp->board_type != DEVICE_ID_21040) {
3998bdb9230aSGarrett D'Amore /* Section 2/3: General SROM Format/ ID Block */
3999bdb9230aSGarrett D'Amore p = vi+18;
4000bdb9230aSGarrett D'Amore sr->version = *p++;
4001bdb9230aSGarrett D'Amore sr->adapters = *p++;
4002bdb9230aSGarrett D'Amore
4003bdb9230aSGarrett D'Amore sr->leaf =
4004bdb9230aSGarrett D'Amore kmem_zalloc(sr->adapters * sizeof (LEAF_FORMAT), KM_SLEEP);
4005bdb9230aSGarrett D'Amore for (i = 0; i < 6; i++)
4006bdb9230aSGarrett D'Amore sr->netaddr[i] = *p++;
4007bdb9230aSGarrett D'Amore
4008bdb9230aSGarrett D'Amore for (i = 0; i < sr->adapters; i++) {
4009bdb9230aSGarrett D'Amore uchar_t devno = *p++;
4010bdb9230aSGarrett D'Amore uint16_t offset = *p++;
4011bdb9230aSGarrett D'Amore offset |= *p++ << 8;
4012bdb9230aSGarrett D'Amore sr->leaf[i].device_number = devno;
4013bdb9230aSGarrett D'Amore parse_controller_leaf(dnetp, sr->leaf+i, vi+offset);
4014bdb9230aSGarrett D'Amore }
4015bdb9230aSGarrett D'Amore /*
4016bdb9230aSGarrett D'Amore * 'Orrible hack for cogent cards. The 6911A board seems to
4017bdb9230aSGarrett D'Amore * have an incorrect SROM. (From the OEMDEMO program
4018bdb9230aSGarrett D'Amore * supplied by cogent, it seems that the ROM matches a setup
4019bdb9230aSGarrett D'Amore * or a board with a QSI or ICS PHY.
4020bdb9230aSGarrett D'Amore */
4021bdb9230aSGarrett D'Amore for (i = 0; i < 3; i++)
4022bdb9230aSGarrett D'Amore ether_mfg = (ether_mfg << 8) | sr->netaddr[i];
4023bdb9230aSGarrett D'Amore
4024bdb9230aSGarrett D'Amore if (ether_mfg == ADAPTEC_ETHER) {
4025bdb9230aSGarrett D'Amore static uint16_t cogent_gprseq[] = {0x821, 0};
4026bdb9230aSGarrett D'Amore switch (vi[COGENT_SROM_ID]) {
4027bdb9230aSGarrett D'Amore case COGENT_ANA6911A_C:
4028bdb9230aSGarrett D'Amore case COGENT_ANA6911AC_C:
4029bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
4030bdb9230aSGarrett D'Amore if (dnetdebug & DNETTRACE)
4031bdb9230aSGarrett D'Amore cmn_err(CE_WARN,
4032bdb9230aSGarrett D'Amore "Suspected bad GPR sequence."
4033bdb9230aSGarrett D'Amore " Making a guess (821,0)");
4034bdb9230aSGarrett D'Amore #endif
4035bdb9230aSGarrett D'Amore
4036bdb9230aSGarrett D'Amore /* XXX function return value ignored */
4037bdb9230aSGarrett D'Amore (void) ddi_prop_update_byte_array(
4038bdb9230aSGarrett D'Amore DDI_DEV_T_NONE, dnetp->devinfo,
4039bdb9230aSGarrett D'Amore "gpr-sequence", (uchar_t *)cogent_gprseq,
4040bdb9230aSGarrett D'Amore sizeof (cogent_gprseq));
4041bdb9230aSGarrett D'Amore break;
4042bdb9230aSGarrett D'Amore }
4043bdb9230aSGarrett D'Amore }
4044bdb9230aSGarrett D'Amore } else {
4045bdb9230aSGarrett D'Amore /*
4046bdb9230aSGarrett D'Amore * Adhoc SROM, check for some cards which need special handling
4047bdb9230aSGarrett D'Amore * Assume vendor info contains ether address in first six bytes
4048bdb9230aSGarrett D'Amore */
4049bdb9230aSGarrett D'Amore
4050bdb9230aSGarrett D'Amore uchar_t *mac = vi + ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo,
4051bdb9230aSGarrett D'Amore DDI_PROP_DONTPASS, macoffset_propname, 0);
4052bdb9230aSGarrett D'Amore
4053bdb9230aSGarrett D'Amore for (i = 0; i < 6; i++)
4054bdb9230aSGarrett D'Amore sr->netaddr[i] = mac[i];
4055bdb9230aSGarrett D'Amore
4056bdb9230aSGarrett D'Amore if (dnetp->board_type == DEVICE_ID_21140) {
4057bdb9230aSGarrett D'Amore for (i = 0; i < 3; i++)
4058bdb9230aSGarrett D'Amore ether_mfg = (ether_mfg << 8) | mac[i];
4059bdb9230aSGarrett D'Amore
4060bdb9230aSGarrett D'Amore switch (ether_mfg) {
4061bdb9230aSGarrett D'Amore case ASANTE_ETHER:
4062bdb9230aSGarrett D'Amore dnetp->vendor_21140 = ASANTE_TYPE;
4063bdb9230aSGarrett D'Amore dnetp->vendor_revision = 0;
4064bdb9230aSGarrett D'Amore set_leaf(sr, &leaf_asante);
4065bdb9230aSGarrett D'Amore sr->adapters = 1;
4066bdb9230aSGarrett D'Amore break;
4067bdb9230aSGarrett D'Amore
4068bdb9230aSGarrett D'Amore case COGENT_ETHER:
4069bdb9230aSGarrett D'Amore case ADAPTEC_ETHER:
4070bdb9230aSGarrett D'Amore dnetp->vendor_21140 = COGENT_EM_TYPE;
4071bdb9230aSGarrett D'Amore dnetp->vendor_revision =
4072bdb9230aSGarrett D'Amore vi[VENDOR_REVISION_OFFSET];
4073bdb9230aSGarrett D'Amore set_leaf(sr, &leaf_cogent_100);
4074bdb9230aSGarrett D'Amore sr->adapters = 1;
4075bdb9230aSGarrett D'Amore break;
4076bdb9230aSGarrett D'Amore
4077bdb9230aSGarrett D'Amore default:
4078bdb9230aSGarrett D'Amore dnetp->vendor_21140 = DEFAULT_TYPE;
4079bdb9230aSGarrett D'Amore dnetp->vendor_revision = 0;
4080bdb9230aSGarrett D'Amore set_leaf(sr, &leaf_default_100);
4081bdb9230aSGarrett D'Amore sr->adapters = 1;
4082bdb9230aSGarrett D'Amore break;
4083bdb9230aSGarrett D'Amore }
4084bdb9230aSGarrett D'Amore } else if (dnetp->board_type == DEVICE_ID_21041) {
4085bdb9230aSGarrett D'Amore set_leaf(sr, &leaf_21041);
4086bdb9230aSGarrett D'Amore } else if (dnetp->board_type == DEVICE_ID_21040) {
4087bdb9230aSGarrett D'Amore set_leaf(sr, &leaf_21040);
4088bdb9230aSGarrett D'Amore }
4089bdb9230aSGarrett D'Amore }
4090bdb9230aSGarrett D'Amore }
4091bdb9230aSGarrett D'Amore
4092bdb9230aSGarrett D'Amore /* Section 4.2, 4.3, 4.4, 4.5 */
4093bdb9230aSGarrett D'Amore static void
parse_controller_leaf(struct dnetinstance * dnetp,LEAF_FORMAT * leaf,uchar_t * vi)4094bdb9230aSGarrett D'Amore parse_controller_leaf(struct dnetinstance *dnetp, LEAF_FORMAT *leaf,
4095bdb9230aSGarrett D'Amore uchar_t *vi)
4096bdb9230aSGarrett D'Amore {
4097bdb9230aSGarrett D'Amore int i;
4098bdb9230aSGarrett D'Amore
4099bdb9230aSGarrett D'Amore leaf->selected_contype = *vi++;
4100bdb9230aSGarrett D'Amore leaf->selected_contype |= *vi++ << 8;
4101bdb9230aSGarrett D'Amore
4102bdb9230aSGarrett D'Amore if (dnetp->board_type == DEVICE_ID_21140) /* Sect. 4.3 */
4103bdb9230aSGarrett D'Amore leaf->gpr = *vi++;
4104bdb9230aSGarrett D'Amore
4105bdb9230aSGarrett D'Amore leaf->block_count = *vi++;
4106bdb9230aSGarrett D'Amore
4107bdb9230aSGarrett D'Amore if (leaf->block_count > MAX_MEDIA) {
4108bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "dnet: Too many media in SROM!");
4109bdb9230aSGarrett D'Amore leaf->block_count = 1;
4110bdb9230aSGarrett D'Amore }
4111bdb9230aSGarrett D'Amore for (i = 0; i <= leaf->block_count; i++) {
4112bdb9230aSGarrett D'Amore vi = parse_media_block(dnetp, leaf->block + i, vi);
4113bdb9230aSGarrett D'Amore if (leaf->block[i].command & CMD_DEFAULT_MEDIUM)
4114bdb9230aSGarrett D'Amore leaf->default_block = leaf->block+i;
4115bdb9230aSGarrett D'Amore }
4116bdb9230aSGarrett D'Amore /* No explicit default block: use last in the ROM */
4117bdb9230aSGarrett D'Amore if (leaf->default_block == NULL)
4118bdb9230aSGarrett D'Amore leaf->default_block = leaf->block + leaf->block_count -1;
4119bdb9230aSGarrett D'Amore
4120bdb9230aSGarrett D'Amore }
4121bdb9230aSGarrett D'Amore
4122bdb9230aSGarrett D'Amore static uchar_t *
parse_media_block(struct dnetinstance * dnetp,media_block_t * block,uchar_t * vi)4123bdb9230aSGarrett D'Amore parse_media_block(struct dnetinstance *dnetp, media_block_t *block, uchar_t *vi)
4124bdb9230aSGarrett D'Amore {
4125bdb9230aSGarrett D'Amore int i;
4126bdb9230aSGarrett D'Amore
4127bdb9230aSGarrett D'Amore /*
4128bdb9230aSGarrett D'Amore * There are three kinds of media block we need to worry about:
4129bdb9230aSGarrett D'Amore * The 21041 blocks.
4130bdb9230aSGarrett D'Amore * 21140 blocks from a version 1 SROM
4131bdb9230aSGarrett D'Amore * 2114[023] block from a version 3 SROM
4132bdb9230aSGarrett D'Amore */
4133bdb9230aSGarrett D'Amore
4134bdb9230aSGarrett D'Amore if (dnetp->board_type == DEVICE_ID_21041) {
4135bdb9230aSGarrett D'Amore /* Section 4.2 */
4136bdb9230aSGarrett D'Amore block->media_code = *vi & 0x3f;
4137bdb9230aSGarrett D'Amore block->type = 2;
4138bdb9230aSGarrett D'Amore if (*vi++ & 0x40) {
4139bdb9230aSGarrett D'Amore block->un.sia.csr13 = *vi++;
4140bdb9230aSGarrett D'Amore block->un.sia.csr13 |= *vi++ << 8;
4141bdb9230aSGarrett D'Amore block->un.sia.csr14 = *vi++;
4142bdb9230aSGarrett D'Amore block->un.sia.csr14 |= *vi++ << 8;
4143bdb9230aSGarrett D'Amore block->un.sia.csr15 = *vi++;
4144bdb9230aSGarrett D'Amore block->un.sia.csr15 |= *vi++ << 8;
4145bdb9230aSGarrett D'Amore } else {
4146bdb9230aSGarrett D'Amore /* No media data (csrs 13,14,15). Insert defaults */
4147bdb9230aSGarrett D'Amore switch (block->media_code) {
4148bdb9230aSGarrett D'Amore case MEDIA_TP:
4149bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0xef01;
4150bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x7f3f;
4151bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x0008;
4152bdb9230aSGarrett D'Amore break;
4153bdb9230aSGarrett D'Amore case MEDIA_TP_FD:
4154bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0xef01;
4155bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x7f3d;
4156bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x0008;
4157bdb9230aSGarrett D'Amore break;
4158bdb9230aSGarrett D'Amore case MEDIA_BNC:
4159bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0xef09;
4160bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x0705;
4161bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x0006;
4162bdb9230aSGarrett D'Amore break;
4163bdb9230aSGarrett D'Amore case MEDIA_AUI:
4164bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0xef09;
4165bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x0705;
4166bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x000e;
4167bdb9230aSGarrett D'Amore break;
4168bdb9230aSGarrett D'Amore }
4169bdb9230aSGarrett D'Amore }
4170bdb9230aSGarrett D'Amore } else if (*vi & 0x80) { /* Extended format: Section 4.3.2.2 */
4171bdb9230aSGarrett D'Amore int blocklen = *vi++ & 0x7f;
4172bdb9230aSGarrett D'Amore block->type = *vi++;
4173bdb9230aSGarrett D'Amore switch (block->type) {
4174bdb9230aSGarrett D'Amore case 0: /* "non-MII": Section 4.3.2.2.1 */
4175bdb9230aSGarrett D'Amore block->media_code = (*vi++) & 0x3f;
4176bdb9230aSGarrett D'Amore block->gprseqlen = 1;
4177bdb9230aSGarrett D'Amore block->gprseq[0] = *vi++;
4178bdb9230aSGarrett D'Amore block->command = *vi++;
4179bdb9230aSGarrett D'Amore block->command |= *vi++ << 8;
4180bdb9230aSGarrett D'Amore break;
4181bdb9230aSGarrett D'Amore
4182bdb9230aSGarrett D'Amore case 1: /* MII/PHY: Section 4.3.2.2.2 */
4183bdb9230aSGarrett D'Amore block->command = CMD_PS;
4184bdb9230aSGarrett D'Amore block->media_code = MEDIA_MII;
4185bdb9230aSGarrett D'Amore /* This is whats needed in CSR6 */
4186bdb9230aSGarrett D'Amore
4187bdb9230aSGarrett D'Amore block->un.mii.phy_num = *vi++;
4188bdb9230aSGarrett D'Amore block->gprseqlen = *vi++;
4189bdb9230aSGarrett D'Amore
4190bdb9230aSGarrett D'Amore for (i = 0; i < block->gprseqlen; i++)
4191bdb9230aSGarrett D'Amore block->gprseq[i] = *vi++;
4192bdb9230aSGarrett D'Amore block->rstseqlen = *vi++;
4193bdb9230aSGarrett D'Amore for (i = 0; i < block->rstseqlen; i++)
4194bdb9230aSGarrett D'Amore block->rstseq[i] = *vi++;
4195bdb9230aSGarrett D'Amore
4196bdb9230aSGarrett D'Amore block->un.mii.mediacaps = *vi++;
4197bdb9230aSGarrett D'Amore block->un.mii.mediacaps |= *vi++ << 8;
4198bdb9230aSGarrett D'Amore block->un.mii.nwayadvert = *vi++;
4199bdb9230aSGarrett D'Amore block->un.mii.nwayadvert |= *vi++ << 8;
4200bdb9230aSGarrett D'Amore block->un.mii.fdxmask = *vi++;
4201bdb9230aSGarrett D'Amore block->un.mii.fdxmask |= *vi++ << 8;
4202bdb9230aSGarrett D'Amore block->un.mii.ttmmask = *vi++;
4203bdb9230aSGarrett D'Amore block->un.mii.ttmmask |= *vi++ << 8;
4204bdb9230aSGarrett D'Amore break;
4205bdb9230aSGarrett D'Amore
4206bdb9230aSGarrett D'Amore case 2: /* SIA Media: Section 4.4.2.1.1 */
4207bdb9230aSGarrett D'Amore block->media_code = *vi & 0x3f;
4208bdb9230aSGarrett D'Amore if (*vi++ & 0x40) {
4209bdb9230aSGarrett D'Amore block->un.sia.csr13 = *vi++;
4210bdb9230aSGarrett D'Amore block->un.sia.csr13 |= *vi++ << 8;
4211bdb9230aSGarrett D'Amore block->un.sia.csr14 = *vi++;
4212bdb9230aSGarrett D'Amore block->un.sia.csr14 |= *vi++ << 8;
4213bdb9230aSGarrett D'Amore block->un.sia.csr15 = *vi++;
4214bdb9230aSGarrett D'Amore block->un.sia.csr15 |= *vi++ << 8;
4215bdb9230aSGarrett D'Amore } else {
4216bdb9230aSGarrett D'Amore /*
4217bdb9230aSGarrett D'Amore * SIA values not provided by SROM; provide
4218bdb9230aSGarrett D'Amore * defaults. See appendix D of 2114[23] manuals.
4219bdb9230aSGarrett D'Amore */
4220bdb9230aSGarrett D'Amore switch (block->media_code) {
4221bdb9230aSGarrett D'Amore case MEDIA_BNC:
4222bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0x0009;
4223bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x0705;
4224bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x0000;
4225bdb9230aSGarrett D'Amore break;
4226bdb9230aSGarrett D'Amore case MEDIA_AUI:
4227bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0x0009;
4228bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x0705;
4229bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x0008;
4230bdb9230aSGarrett D'Amore break;
4231bdb9230aSGarrett D'Amore case MEDIA_TP:
4232bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0x0001;
4233bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x7f3f;
4234bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x0000;
4235bdb9230aSGarrett D'Amore break;
4236bdb9230aSGarrett D'Amore case MEDIA_TP_FD:
4237bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0x0001;
4238bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x7f3d;
4239bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x0000;
4240bdb9230aSGarrett D'Amore break;
4241bdb9230aSGarrett D'Amore default:
4242bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0x0000;
4243bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x0000;
4244bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x0000;
4245bdb9230aSGarrett D'Amore }
4246bdb9230aSGarrett D'Amore }
4247bdb9230aSGarrett D'Amore
4248bdb9230aSGarrett D'Amore /* Treat GP control/data as a GPR sequence */
4249bdb9230aSGarrett D'Amore block->gprseqlen = 2;
4250bdb9230aSGarrett D'Amore block->gprseq[0] = *vi++;
4251bdb9230aSGarrett D'Amore block->gprseq[0] |= *vi++ << 8;
4252bdb9230aSGarrett D'Amore block->gprseq[0] |= GPR_CONTROL_WRITE;
4253bdb9230aSGarrett D'Amore block->gprseq[1] = *vi++;
4254bdb9230aSGarrett D'Amore block->gprseq[1] |= *vi++ << 8;
4255bdb9230aSGarrett D'Amore break;
4256bdb9230aSGarrett D'Amore
4257bdb9230aSGarrett D'Amore case 3: /* MII/PHY : Section 4.4.2.1.2 */
4258bdb9230aSGarrett D'Amore block->command = CMD_PS;
4259bdb9230aSGarrett D'Amore block->media_code = MEDIA_MII;
4260bdb9230aSGarrett D'Amore block->un.mii.phy_num = *vi++;
4261bdb9230aSGarrett D'Amore
4262bdb9230aSGarrett D'Amore block->gprseqlen = *vi++;
4263bdb9230aSGarrett D'Amore for (i = 0; i < block->gprseqlen; i++) {
4264bdb9230aSGarrett D'Amore block->gprseq[i] = *vi++;
4265bdb9230aSGarrett D'Amore block->gprseq[i] |= *vi++ << 8;
4266bdb9230aSGarrett D'Amore }
4267bdb9230aSGarrett D'Amore
4268bdb9230aSGarrett D'Amore block->rstseqlen = *vi++;
4269bdb9230aSGarrett D'Amore for (i = 0; i < block->rstseqlen; i++) {
4270bdb9230aSGarrett D'Amore block->rstseq[i] = *vi++;
4271bdb9230aSGarrett D'Amore block->rstseq[i] |= *vi++ << 8;
4272bdb9230aSGarrett D'Amore }
4273bdb9230aSGarrett D'Amore block->un.mii.mediacaps = *vi++;
4274bdb9230aSGarrett D'Amore block->un.mii.mediacaps |= *vi++ << 8;
4275bdb9230aSGarrett D'Amore block->un.mii.nwayadvert = *vi++;
4276bdb9230aSGarrett D'Amore block->un.mii.nwayadvert |= *vi++ << 8;
4277bdb9230aSGarrett D'Amore block->un.mii.fdxmask = *vi++;
4278bdb9230aSGarrett D'Amore block->un.mii.fdxmask |= *vi++ << 8;
4279bdb9230aSGarrett D'Amore block->un.mii.ttmmask = *vi++;
4280bdb9230aSGarrett D'Amore block->un.mii.ttmmask |= *vi++ << 8;
4281bdb9230aSGarrett D'Amore block->un.mii.miiintr |= *vi++;
4282bdb9230aSGarrett D'Amore break;
4283bdb9230aSGarrett D'Amore
4284bdb9230aSGarrett D'Amore case 4: /* SYM Media: 4.5.2.1.3 */
4285bdb9230aSGarrett D'Amore block->media_code = *vi++ & 0x3f;
4286bdb9230aSGarrett D'Amore /* Treat GP control and data as a GPR sequence */
4287bdb9230aSGarrett D'Amore block->gprseqlen = 2;
4288bdb9230aSGarrett D'Amore block->gprseq[0] = *vi++;
4289bdb9230aSGarrett D'Amore block->gprseq[0] |= *vi++ << 8;
4290bdb9230aSGarrett D'Amore block->gprseq[0] |= GPR_CONTROL_WRITE;
4291bdb9230aSGarrett D'Amore block->gprseq[1] = *vi++;
4292bdb9230aSGarrett D'Amore block->gprseq[1] |= *vi++ << 8;
4293bdb9230aSGarrett D'Amore block->command = *vi++;
4294bdb9230aSGarrett D'Amore block->command |= *vi++ << 8;
4295bdb9230aSGarrett D'Amore break;
4296bdb9230aSGarrett D'Amore
4297bdb9230aSGarrett D'Amore case 5: /* GPR reset sequence: Section 4.5.2.1.4 */
4298bdb9230aSGarrett D'Amore block->rstseqlen = *vi++;
4299bdb9230aSGarrett D'Amore for (i = 0; i < block->rstseqlen; i++)
4300bdb9230aSGarrett D'Amore block->rstseq[i] = *vi++;
4301bdb9230aSGarrett D'Amore break;
4302bdb9230aSGarrett D'Amore
4303bdb9230aSGarrett D'Amore default: /* Unknown media block. Skip it. */
4304bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "dnet: Unsupported SROM block.");
4305bdb9230aSGarrett D'Amore vi += blocklen;
4306bdb9230aSGarrett D'Amore break;
4307bdb9230aSGarrett D'Amore }
4308bdb9230aSGarrett D'Amore } else { /* Compact format (or V1 SROM): Section 4.3.2.1 */
4309bdb9230aSGarrett D'Amore block->type = 0;
4310bdb9230aSGarrett D'Amore block->media_code = *vi++ & 0x3f;
4311bdb9230aSGarrett D'Amore block->gprseqlen = 1;
4312bdb9230aSGarrett D'Amore block->gprseq[0] = *vi++;
4313bdb9230aSGarrett D'Amore block->command = *vi++;
4314bdb9230aSGarrett D'Amore block->command |= (*vi++) << 8;
4315bdb9230aSGarrett D'Amore }
4316bdb9230aSGarrett D'Amore return (vi);
4317bdb9230aSGarrett D'Amore }
4318bdb9230aSGarrett D'Amore
4319bdb9230aSGarrett D'Amore
4320bdb9230aSGarrett D'Amore /*
4321bdb9230aSGarrett D'Amore * An alternative to doing this would be to store the legacy ROMs in binary
4322bdb9230aSGarrett D'Amore * format in the conf file, and in read_srom, pick out the data. This would
4323bdb9230aSGarrett D'Amore * then allow the parser to continue on as normal. This makes it a little
4324bdb9230aSGarrett D'Amore * easier to read.
4325bdb9230aSGarrett D'Amore */
4326bdb9230aSGarrett D'Amore static void
setup_legacy_blocks()4327bdb9230aSGarrett D'Amore setup_legacy_blocks()
4328bdb9230aSGarrett D'Amore {
4329bdb9230aSGarrett D'Amore LEAF_FORMAT *leaf;
4330bdb9230aSGarrett D'Amore media_block_t *block;
4331bdb9230aSGarrett D'Amore
4332bdb9230aSGarrett D'Amore /* Default FAKE SROM */
4333bdb9230aSGarrett D'Amore leaf = &leaf_default_100;
4334bdb9230aSGarrett D'Amore leaf->is_static = 1;
4335bdb9230aSGarrett D'Amore leaf->default_block = &leaf->block[3];
4336bdb9230aSGarrett D'Amore leaf->block_count = 4; /* 100 cards are highly unlikely to have BNC */
4337bdb9230aSGarrett D'Amore block = leaf->block;
4338bdb9230aSGarrett D'Amore block->media_code = MEDIA_TP_FD;
4339bdb9230aSGarrett D'Amore block->type = 0;
4340bdb9230aSGarrett D'Amore block->command = 0x8e; /* PCS, PS off, media sense: bit7, pol=1 */
4341bdb9230aSGarrett D'Amore block++;
4342bdb9230aSGarrett D'Amore block->media_code = MEDIA_TP;
4343bdb9230aSGarrett D'Amore block->type = 0;
4344bdb9230aSGarrett D'Amore block->command = 0x8e; /* PCS, PS off, media sense: bit7, pol=1 */
4345bdb9230aSGarrett D'Amore block++;
4346bdb9230aSGarrett D'Amore block->media_code = MEDIA_SYM_SCR_FD;
4347bdb9230aSGarrett D'Amore block->type = 0;
4348bdb9230aSGarrett D'Amore block->command = 0x6d; /* PCS, PS, SCR on, media sense: bit6, pol=0 */
4349bdb9230aSGarrett D'Amore block++;
4350bdb9230aSGarrett D'Amore block->media_code = MEDIA_SYM_SCR;
4351bdb9230aSGarrett D'Amore block->type = 0;
4352bdb9230aSGarrett D'Amore block->command = 0x406d; /* PCS, PS, SCR on, media sense: bit6, pol=0 */
4353bdb9230aSGarrett D'Amore
4354bdb9230aSGarrett D'Amore /* COGENT FAKE SROM */
4355bdb9230aSGarrett D'Amore leaf = &leaf_cogent_100;
4356bdb9230aSGarrett D'Amore leaf->is_static = 1;
4357bdb9230aSGarrett D'Amore leaf->default_block = &leaf->block[4];
4358bdb9230aSGarrett D'Amore leaf->block_count = 5; /* 100TX, 100TX-FD, 10T 10T-FD, BNC */
4359bdb9230aSGarrett D'Amore block = leaf->block; /* BNC */
4360bdb9230aSGarrett D'Amore block->media_code = MEDIA_BNC;
4361bdb9230aSGarrett D'Amore block->type = 0;
4362bdb9230aSGarrett D'Amore block->command = 0x8000; /* No media sense, PCS, SCR, PS all off */
4363bdb9230aSGarrett D'Amore block->gprseqlen = 2;
4364bdb9230aSGarrett D'Amore block->rstseqlen = 0;
4365bdb9230aSGarrett D'Amore block->gprseq[0] = 0x13f;
4366bdb9230aSGarrett D'Amore block->gprseq[1] = 1;
4367bdb9230aSGarrett D'Amore
4368bdb9230aSGarrett D'Amore block++;
4369bdb9230aSGarrett D'Amore block->media_code = MEDIA_TP_FD;
4370bdb9230aSGarrett D'Amore block->type = 0;
4371bdb9230aSGarrett D'Amore block->command = 0x8e; /* PCS, PS off, media sense: bit7, pol=1 */
4372bdb9230aSGarrett D'Amore block->gprseqlen = 2;
4373bdb9230aSGarrett D'Amore block->rstseqlen = 0;
4374bdb9230aSGarrett D'Amore block->gprseq[0] = 0x13f;
4375bdb9230aSGarrett D'Amore block->gprseq[1] = 0x26;
4376bdb9230aSGarrett D'Amore
4377bdb9230aSGarrett D'Amore block++; /* 10BaseT */
4378bdb9230aSGarrett D'Amore block->media_code = MEDIA_TP;
4379bdb9230aSGarrett D'Amore block->type = 0;
4380bdb9230aSGarrett D'Amore block->command = 0x8e; /* PCS, PS off, media sense: bit7, pol=1 */
4381bdb9230aSGarrett D'Amore block->gprseqlen = 2;
4382bdb9230aSGarrett D'Amore block->rstseqlen = 0;
4383bdb9230aSGarrett D'Amore block->gprseq[0] = 0x13f;
4384bdb9230aSGarrett D'Amore block->gprseq[1] = 0x3e;
4385bdb9230aSGarrett D'Amore
4386bdb9230aSGarrett D'Amore block++; /* 100BaseTX-FD */
4387bdb9230aSGarrett D'Amore block->media_code = MEDIA_SYM_SCR_FD;
4388bdb9230aSGarrett D'Amore block->type = 0;
4389bdb9230aSGarrett D'Amore block->command = 0x6d; /* PCS, PS, SCR on, media sense: bit6, pol=0 */
4390bdb9230aSGarrett D'Amore block->gprseqlen = 2;
4391bdb9230aSGarrett D'Amore block->rstseqlen = 0;
4392bdb9230aSGarrett D'Amore block->gprseq[0] = 0x13f;
4393bdb9230aSGarrett D'Amore block->gprseq[1] = 1;
4394bdb9230aSGarrett D'Amore
4395bdb9230aSGarrett D'Amore block++; /* 100BaseTX */
4396bdb9230aSGarrett D'Amore block->media_code = MEDIA_SYM_SCR;
4397bdb9230aSGarrett D'Amore block->type = 0;
4398bdb9230aSGarrett D'Amore block->command = 0x406d; /* PCS, PS, SCR on, media sense: bit6, pol=0 */
4399bdb9230aSGarrett D'Amore block->gprseqlen = 2;
4400bdb9230aSGarrett D'Amore block->rstseqlen = 0;
4401bdb9230aSGarrett D'Amore block->gprseq[0] = 0x13f;
4402bdb9230aSGarrett D'Amore block->gprseq[1] = 1;
4403bdb9230aSGarrett D'Amore
4404bdb9230aSGarrett D'Amore /* Generic legacy card with a PHY. */
4405bdb9230aSGarrett D'Amore leaf = &leaf_phylegacy;
4406bdb9230aSGarrett D'Amore leaf->block_count = 1;
4407bdb9230aSGarrett D'Amore leaf->mii_block = leaf->block;
4408bdb9230aSGarrett D'Amore leaf->default_block = &leaf->block[0];
4409bdb9230aSGarrett D'Amore leaf->is_static = 1;
4410bdb9230aSGarrett D'Amore block = leaf->block;
4411bdb9230aSGarrett D'Amore block->media_code = MEDIA_MII;
4412bdb9230aSGarrett D'Amore block->type = 1; /* MII Block type 1 */
4413bdb9230aSGarrett D'Amore block->command = 1; /* Port select */
4414bdb9230aSGarrett D'Amore block->gprseqlen = 0;
4415bdb9230aSGarrett D'Amore block->rstseqlen = 0;
4416bdb9230aSGarrett D'Amore
4417bdb9230aSGarrett D'Amore /* ASANTE FAKE SROM */
4418bdb9230aSGarrett D'Amore leaf = &leaf_asante;
4419bdb9230aSGarrett D'Amore leaf->is_static = 1;
4420bdb9230aSGarrett D'Amore leaf->default_block = &leaf->block[0];
4421bdb9230aSGarrett D'Amore leaf->block_count = 1;
4422bdb9230aSGarrett D'Amore block = leaf->block;
4423bdb9230aSGarrett D'Amore block->media_code = MEDIA_MII;
4424bdb9230aSGarrett D'Amore block->type = 1; /* MII Block type 1 */
4425bdb9230aSGarrett D'Amore block->command = 1; /* Port select */
4426bdb9230aSGarrett D'Amore block->gprseqlen = 3;
4427bdb9230aSGarrett D'Amore block->rstseqlen = 0;
4428bdb9230aSGarrett D'Amore block->gprseq[0] = 0x180;
4429bdb9230aSGarrett D'Amore block->gprseq[1] = 0x80;
4430bdb9230aSGarrett D'Amore block->gprseq[2] = 0x0;
4431bdb9230aSGarrett D'Amore
4432bdb9230aSGarrett D'Amore /* LEGACY 21041 card FAKE SROM */
4433bdb9230aSGarrett D'Amore leaf = &leaf_21041;
4434bdb9230aSGarrett D'Amore leaf->is_static = 1;
4435bdb9230aSGarrett D'Amore leaf->block_count = 4; /* SIA Blocks for TP, TPfd, BNC, AUI */
4436bdb9230aSGarrett D'Amore leaf->default_block = &leaf->block[3];
4437bdb9230aSGarrett D'Amore
4438bdb9230aSGarrett D'Amore block = leaf->block;
4439bdb9230aSGarrett D'Amore block->media_code = MEDIA_AUI;
4440bdb9230aSGarrett D'Amore block->type = 2;
4441bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0xef09;
4442bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x0705;
4443bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x000e;
4444bdb9230aSGarrett D'Amore
4445bdb9230aSGarrett D'Amore block++;
4446bdb9230aSGarrett D'Amore block->media_code = MEDIA_TP_FD;
4447bdb9230aSGarrett D'Amore block->type = 2;
4448bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0xef01;
4449bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x7f3d;
4450bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x0008;
4451bdb9230aSGarrett D'Amore
4452bdb9230aSGarrett D'Amore block++;
4453bdb9230aSGarrett D'Amore block->media_code = MEDIA_BNC;
4454bdb9230aSGarrett D'Amore block->type = 2;
4455bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0xef09;
4456bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x0705;
4457bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x0006;
4458bdb9230aSGarrett D'Amore
4459bdb9230aSGarrett D'Amore block++;
4460bdb9230aSGarrett D'Amore block->media_code = MEDIA_TP;
4461bdb9230aSGarrett D'Amore block->type = 2;
4462bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0xef01;
4463bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x7f3f;
4464bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x0008;
4465bdb9230aSGarrett D'Amore
4466bdb9230aSGarrett D'Amore /* LEGACY 21040 card FAKE SROM */
4467bdb9230aSGarrett D'Amore leaf = &leaf_21040;
4468bdb9230aSGarrett D'Amore leaf->is_static = 1;
4469bdb9230aSGarrett D'Amore leaf->block_count = 4; /* SIA Blocks for TP, TPfd, BNC, AUI */
4470bdb9230aSGarrett D'Amore block = leaf->block;
4471bdb9230aSGarrett D'Amore block->media_code = MEDIA_AUI;
4472bdb9230aSGarrett D'Amore block->type = 2;
4473bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0x8f09;
4474bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x0705;
4475bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x000e;
4476bdb9230aSGarrett D'Amore block++;
4477bdb9230aSGarrett D'Amore block->media_code = MEDIA_TP_FD;
4478bdb9230aSGarrett D'Amore block->type = 2;
4479bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0x0f01;
4480bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x7f3d;
4481bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x0008;
4482bdb9230aSGarrett D'Amore block++;
4483bdb9230aSGarrett D'Amore block->media_code = MEDIA_BNC;
4484bdb9230aSGarrett D'Amore block->type = 2;
4485bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0xef09;
4486bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x0705;
4487bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x0006;
4488bdb9230aSGarrett D'Amore block++;
4489bdb9230aSGarrett D'Amore block->media_code = MEDIA_TP;
4490bdb9230aSGarrett D'Amore block->type = 2;
4491bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0x8f01;
4492bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x7f3f;
4493bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x0008;
4494bdb9230aSGarrett D'Amore }
4495bdb9230aSGarrett D'Amore
4496bdb9230aSGarrett D'Amore static void
dnet_print_srom(SROM_FORMAT * sr)4497bdb9230aSGarrett D'Amore dnet_print_srom(SROM_FORMAT *sr)
4498bdb9230aSGarrett D'Amore {
4499bdb9230aSGarrett D'Amore int i;
4500bdb9230aSGarrett D'Amore uchar_t *a = sr->netaddr;
4501bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "SROM Dump: %d. ver %d, Num adapters %d,"
4502bdb9230aSGarrett D'Amore "Addr:%x:%x:%x:%x:%x:%x",
4503bdb9230aSGarrett D'Amore sr->init_from_srom, sr->version, sr->adapters,
4504bdb9230aSGarrett D'Amore a[0], a[1], a[2], a[3], a[4], a[5]);
4505bdb9230aSGarrett D'Amore
4506bdb9230aSGarrett D'Amore for (i = 0; i < sr->adapters; i++)
4507bdb9230aSGarrett D'Amore dnet_dump_leaf(sr->leaf+i);
4508bdb9230aSGarrett D'Amore }
4509bdb9230aSGarrett D'Amore
4510bdb9230aSGarrett D'Amore static void
dnet_dump_leaf(LEAF_FORMAT * leaf)4511bdb9230aSGarrett D'Amore dnet_dump_leaf(LEAF_FORMAT *leaf)
4512bdb9230aSGarrett D'Amore {
4513bdb9230aSGarrett D'Amore int i;
4514bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "Leaf: Device %d, block_count %d, gpr: %x",
4515bdb9230aSGarrett D'Amore leaf->device_number, leaf->block_count, leaf->gpr);
4516bdb9230aSGarrett D'Amore for (i = 0; i < leaf->block_count; i++)
4517bdb9230aSGarrett D'Amore dnet_dump_block(leaf->block+i);
4518bdb9230aSGarrett D'Amore }
4519bdb9230aSGarrett D'Amore
4520bdb9230aSGarrett D'Amore static void
dnet_dump_block(media_block_t * block)4521bdb9230aSGarrett D'Amore dnet_dump_block(media_block_t *block)
4522bdb9230aSGarrett D'Amore {
4523bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "Block(%p): type %x, media %s, command: %x ",
4524bdb9230aSGarrett D'Amore (void *)block,
4525bdb9230aSGarrett D'Amore block->type, media_str[block->media_code], block->command);
4526bdb9230aSGarrett D'Amore dnet_dumpbin("\tGPR Seq", (uchar_t *)block->gprseq, 2,
4527bdb9230aSGarrett D'Amore block->gprseqlen *2);
4528bdb9230aSGarrett D'Amore dnet_dumpbin("\tGPR Reset", (uchar_t *)block->rstseq, 2,
4529bdb9230aSGarrett D'Amore block->rstseqlen *2);
4530bdb9230aSGarrett D'Amore switch (block->type) {
4531bdb9230aSGarrett D'Amore case 1: case 3:
4532bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "\tMII Info: phy %d, nway %x, fdx"
4533bdb9230aSGarrett D'Amore "%x, ttm %x, mediacap %x",
4534bdb9230aSGarrett D'Amore block->un.mii.phy_num, block->un.mii.nwayadvert,
4535bdb9230aSGarrett D'Amore block->un.mii.fdxmask, block->un.mii.ttmmask,
4536bdb9230aSGarrett D'Amore block->un.mii.mediacaps);
4537bdb9230aSGarrett D'Amore break;
4538bdb9230aSGarrett D'Amore case 2:
4539bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "\tSIA Regs: CSR13:%x, CSR14:%x, CSR15:%x",
4540bdb9230aSGarrett D'Amore block->un.sia.csr13, block->un.sia.csr14,
4541bdb9230aSGarrett D'Amore block->un.sia.csr15);
4542bdb9230aSGarrett D'Amore break;
4543bdb9230aSGarrett D'Amore }
4544bdb9230aSGarrett D'Amore }
4545bdb9230aSGarrett D'Amore
4546bdb9230aSGarrett D'Amore
4547bdb9230aSGarrett D'Amore /* Utility to print out binary info dumps. Handy for SROMs, etc */
4548bdb9230aSGarrett D'Amore
4549bdb9230aSGarrett D'Amore static int
hexcode(unsigned val)4550bdb9230aSGarrett D'Amore hexcode(unsigned val)
4551bdb9230aSGarrett D'Amore {
4552bdb9230aSGarrett D'Amore if (val <= 9)
4553bdb9230aSGarrett D'Amore return (val +'0');
4554bdb9230aSGarrett D'Amore if (val <= 15)
4555bdb9230aSGarrett D'Amore return (val + 'a' - 10);
4556bdb9230aSGarrett D'Amore return (-1);
4557bdb9230aSGarrett D'Amore }
4558bdb9230aSGarrett D'Amore
4559bdb9230aSGarrett D'Amore static void
dnet_dumpbin(char * msg,unsigned char * data,int size,int len)4560bdb9230aSGarrett D'Amore dnet_dumpbin(char *msg, unsigned char *data, int size, int len)
4561bdb9230aSGarrett D'Amore {
4562bdb9230aSGarrett D'Amore char hex[128], *p = hex;
4563bdb9230aSGarrett D'Amore char ascii[128], *q = ascii;
4564bdb9230aSGarrett D'Amore int i, j;
4565bdb9230aSGarrett D'Amore
4566bdb9230aSGarrett D'Amore if (!len)
4567bdb9230aSGarrett D'Amore return;
4568bdb9230aSGarrett D'Amore
4569bdb9230aSGarrett D'Amore for (i = 0; i < len; i += size) {
4570bdb9230aSGarrett D'Amore for (j = size - 1; j >= 0; j--) { /* PORTABILITY: byte order */
4571bdb9230aSGarrett D'Amore *p++ = hexcode(data[i+j] >> 4);
4572bdb9230aSGarrett D'Amore *p++ = hexcode(data[i+j] & 0xf);
4573bdb9230aSGarrett D'Amore *q++ = (data[i+j] < 32 || data[i+j] > 127) ?
4574bdb9230aSGarrett D'Amore '.' : data[i];
4575bdb9230aSGarrett D'Amore }
4576bdb9230aSGarrett D'Amore *p++ = ' ';
4577bdb9230aSGarrett D'Amore if (q-ascii >= 8) {
4578bdb9230aSGarrett D'Amore *p = *q = 0;
4579bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "%s: %s\t%s", msg, hex, ascii);
4580bdb9230aSGarrett D'Amore p = hex;
4581bdb9230aSGarrett D'Amore q = ascii;
4582bdb9230aSGarrett D'Amore }
4583bdb9230aSGarrett D'Amore }
4584bdb9230aSGarrett D'Amore if (p != hex) {
4585bdb9230aSGarrett D'Amore while ((p - hex) < 8*3)
4586bdb9230aSGarrett D'Amore *p++ = ' ';
4587bdb9230aSGarrett D'Amore *p = *q = 0;
4588bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "%s: %s\t%s", msg, hex, ascii);
4589bdb9230aSGarrett D'Amore }
4590bdb9230aSGarrett D'Amore }
4591bdb9230aSGarrett D'Amore
4592bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
4593bdb9230aSGarrett D'Amore void
dnet_usectimeout(struct dnetinstance * dnetp,uint32_t usecs,int contin,timercb_t cback)4594bdb9230aSGarrett D'Amore dnet_usectimeout(struct dnetinstance *dnetp, uint32_t usecs, int contin,
4595bdb9230aSGarrett D'Amore timercb_t cback)
4596bdb9230aSGarrett D'Amore {
4597bdb9230aSGarrett D'Amore mutex_enter(&dnetp->intrlock);
4598bdb9230aSGarrett D'Amore dnetp->timer.start_ticks = (usecs * 100) / 8192;
4599bdb9230aSGarrett D'Amore dnetp->timer.cb = cback;
4600bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, GP_TIMER_REG),
4601bdb9230aSGarrett D'Amore dnetp->timer.start_ticks | (contin ? GPTIMER_CONT : 0));
4602bdb9230aSGarrett D'Amore if (dnetp->timer.cb)
460398e8d175SSteven Stallion enable_interrupts(dnetp);
4604bdb9230aSGarrett D'Amore mutex_exit(&dnetp->intrlock);
4605bdb9230aSGarrett D'Amore }
4606bdb9230aSGarrett D'Amore
4607bdb9230aSGarrett D'Amore uint32_t
dnet_usecelapsed(struct dnetinstance * dnetp)4608bdb9230aSGarrett D'Amore dnet_usecelapsed(struct dnetinstance *dnetp)
4609bdb9230aSGarrett D'Amore {
4610bdb9230aSGarrett D'Amore uint32_t ticks = dnetp->timer.start_ticks -
4611bdb9230aSGarrett D'Amore (ddi_get32(dnetp->io_handle, REG32(dnetp->io_reg, GP_TIMER_REG)) &
4612bdb9230aSGarrett D'Amore 0xffff);
4613bdb9230aSGarrett D'Amore return ((ticks * 8192) / 100);
4614bdb9230aSGarrett D'Amore }
4615bdb9230aSGarrett D'Amore
4616bdb9230aSGarrett D'Amore /* ARGSUSED */
4617bdb9230aSGarrett D'Amore void
dnet_timestamp(struct dnetinstance * dnetp,char * buf)4618bdb9230aSGarrett D'Amore dnet_timestamp(struct dnetinstance *dnetp, char *buf)
4619bdb9230aSGarrett D'Amore {
4620bdb9230aSGarrett D'Amore uint32_t elapsed = dnet_usecelapsed(dnetp);
4621bdb9230aSGarrett D'Amore char loc[32], *p = loc;
4622bdb9230aSGarrett D'Amore int firstdigit = 1;
4623bdb9230aSGarrett D'Amore uint32_t divisor;
4624bdb9230aSGarrett D'Amore
4625bdb9230aSGarrett D'Amore while (*p++ = *buf++)
4626bdb9230aSGarrett D'Amore ;
4627bdb9230aSGarrett D'Amore p--;
4628bdb9230aSGarrett D'Amore
4629bdb9230aSGarrett D'Amore for (divisor = 1000000000; divisor /= 10; ) {
4630bdb9230aSGarrett D'Amore int digit = (elapsed / divisor);
4631bdb9230aSGarrett D'Amore elapsed -= digit * divisor;
4632bdb9230aSGarrett D'Amore if (!firstdigit || digit) {
4633bdb9230aSGarrett D'Amore *p++ = digit + '0';
4634bdb9230aSGarrett D'Amore firstdigit = 0;
4635bdb9230aSGarrett D'Amore }
4636bdb9230aSGarrett D'Amore
4637bdb9230aSGarrett D'Amore }
4638bdb9230aSGarrett D'Amore
4639bdb9230aSGarrett D'Amore /* Actual zero, output it */
4640bdb9230aSGarrett D'Amore if (firstdigit)
4641bdb9230aSGarrett D'Amore *p++ = '0';
4642bdb9230aSGarrett D'Amore
4643bdb9230aSGarrett D'Amore *p++ = '-';
4644bdb9230aSGarrett D'Amore *p++ = '>';
4645bdb9230aSGarrett D'Amore *p++ = 0;
4646bdb9230aSGarrett D'Amore
4647bdb9230aSGarrett D'Amore printf(loc);
4648bdb9230aSGarrett D'Amore dnet_usectimeout(dnetp, 1000000, 0, 0);
4649bdb9230aSGarrett D'Amore }
4650bdb9230aSGarrett D'Amore
4651bdb9230aSGarrett D'Amore #endif
4652