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 /*
230dc2366fSVenugopal 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 */
3170dc2366fSVenugopal 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));
1334*f879aa94SToomas Soome end_index = 0;
1335bdb9230aSGarrett D'Amore
1336bdb9230aSGarrett D'Amore /* reclaim any xmit descriptors completed */
133798e8d175SSteven Stallion dnet_reclaim_Tx_desc(dnetp);
1338bdb9230aSGarrett D'Amore
1339bdb9230aSGarrett D'Amore /*
1340bdb9230aSGarrett D'Amore * Use the data buffers from the message and construct the
1341bdb9230aSGarrett D'Amore * scatter/gather list by calling ddi_dma_addr_bind_handle().
1342bdb9230aSGarrett D'Amore */
134398e8d175SSteven Stallion error = 0;
1344bdb9230aSGarrett D'Amore totlen = 0;
1345bdb9230aSGarrett D'Amore bp = mp;
1346bdb9230aSGarrett D'Amore bufn = 0;
1347bdb9230aSGarrett D'Amore index = start_index = dnetp->tx_current_desc;
1348bdb9230aSGarrett D'Amore avail = dnetp->free_desc;
1349bdb9230aSGarrett D'Amore while (bp != NULL) {
1350bdb9230aSGarrett D'Amore uint_t ncookies;
1351bdb9230aSGarrett D'Amore ddi_dma_cookie_t dma_cookie;
1352bdb9230aSGarrett D'Amore
135398e8d175SSteven Stallion mblen = MBLKL(bp);
1354bdb9230aSGarrett D'Amore
1355bdb9230aSGarrett D'Amore if (!mblen) { /* skip zero-length message blocks */
1356bdb9230aSGarrett D'Amore bp = bp->b_cont;
1357bdb9230aSGarrett D'Amore continue;
1358bdb9230aSGarrett D'Amore }
1359bdb9230aSGarrett D'Amore
1360bdb9230aSGarrett D'Amore retval = ddi_dma_addr_bind_handle(dnetp->dma_handle_tx, NULL,
1361bdb9230aSGarrett D'Amore (caddr_t)bp->b_rptr, mblen,
1362bdb9230aSGarrett D'Amore DDI_DMA_WRITE | DDI_DMA_STREAMING, DDI_DMA_SLEEP, 0,
1363bdb9230aSGarrett D'Amore &dma_cookie, &ncookies);
1364bdb9230aSGarrett D'Amore
1365bdb9230aSGarrett D'Amore switch (retval) {
1366bdb9230aSGarrett D'Amore case DDI_DMA_MAPPED:
1367bdb9230aSGarrett D'Amore break; /* everything's fine */
1368bdb9230aSGarrett D'Amore
1369bdb9230aSGarrett D'Amore case DDI_DMA_NORESOURCES:
1370bdb9230aSGarrett D'Amore error = 1; /* allow retry by gld */
1371bdb9230aSGarrett D'Amore break;
1372bdb9230aSGarrett D'Amore
1373bdb9230aSGarrett D'Amore case DDI_DMA_NOMAPPING:
1374bdb9230aSGarrett D'Amore case DDI_DMA_INUSE:
1375bdb9230aSGarrett D'Amore case DDI_DMA_TOOBIG:
1376bdb9230aSGarrett D'Amore default:
1377bdb9230aSGarrett D'Amore error = 2; /* error, no retry */
1378bdb9230aSGarrett D'Amore break;
1379bdb9230aSGarrett D'Amore }
1380bdb9230aSGarrett D'Amore
1381bdb9230aSGarrett D'Amore /*
1382bdb9230aSGarrett D'Amore * we can use two cookies per descriptor (i.e buffer1 and
1383bdb9230aSGarrett D'Amore * buffer2) so we need at least (ncookies+1)/2 descriptors.
1384bdb9230aSGarrett D'Amore */
1385bdb9230aSGarrett D'Amore if (((ncookies + 1) >> 1) > dnetp->free_desc) {
1386bdb9230aSGarrett D'Amore (void) ddi_dma_unbind_handle(dnetp->dma_handle_tx);
1387bdb9230aSGarrett D'Amore error = 1;
1388bdb9230aSGarrett D'Amore break;
1389bdb9230aSGarrett D'Amore }
1390bdb9230aSGarrett D'Amore
1391bdb9230aSGarrett D'Amore /* setup the descriptors for this data buffer */
1392bdb9230aSGarrett D'Amore while (ncookies) {
1393bdb9230aSGarrett D'Amore end_index = index;
1394bdb9230aSGarrett D'Amore if (bufn % 2) {
1395bdb9230aSGarrett D'Amore ring[index].buffer2 =
1396bdb9230aSGarrett D'Amore (uint32_t)dma_cookie.dmac_address;
1397bdb9230aSGarrett D'Amore ring[index].desc1.buffer_size2 =
1398bdb9230aSGarrett D'Amore dma_cookie.dmac_size;
1399bdb9230aSGarrett D'Amore index = NextTXIndex(index); /* goto next desc */
1400bdb9230aSGarrett D'Amore } else {
1401bdb9230aSGarrett D'Amore /* initialize the descriptor */
1402bdb9230aSGarrett D'Amore ASSERT(ring[index].desc0.own == 0);
1403bdb9230aSGarrett D'Amore *(uint32_t *)&ring[index].desc0 = 0;
1404bdb9230aSGarrett D'Amore *(uint32_t *)&ring[index].desc1 &=
1405bdb9230aSGarrett D'Amore DNET_END_OF_RING;
1406bdb9230aSGarrett D'Amore ring[index].buffer1 =
1407bdb9230aSGarrett D'Amore (uint32_t)dma_cookie.dmac_address;
1408bdb9230aSGarrett D'Amore ring[index].desc1.buffer_size1 =
1409bdb9230aSGarrett D'Amore dma_cookie.dmac_size;
1410bdb9230aSGarrett D'Amore ring[index].buffer2 = (uint32_t)(0);
1411bdb9230aSGarrett D'Amore dnetp->free_desc--;
1412bdb9230aSGarrett D'Amore ASSERT(dnetp->free_desc >= 0);
1413bdb9230aSGarrett D'Amore }
1414bdb9230aSGarrett D'Amore totlen += dma_cookie.dmac_size;
1415bdb9230aSGarrett D'Amore bufn++;
1416bdb9230aSGarrett D'Amore if (--ncookies)
1417bdb9230aSGarrett D'Amore ddi_dma_nextcookie(dnetp->dma_handle_tx,
1418bdb9230aSGarrett D'Amore &dma_cookie);
1419bdb9230aSGarrett D'Amore }
1420bdb9230aSGarrett D'Amore (void) ddi_dma_unbind_handle(dnetp->dma_handle_tx);
1421bdb9230aSGarrett D'Amore bp = bp->b_cont;
1422bdb9230aSGarrett D'Amore }
1423bdb9230aSGarrett D'Amore
1424bdb9230aSGarrett D'Amore if (error == 1) {
1425bdb9230aSGarrett D'Amore dnetp->stat_defer++;
1426bdb9230aSGarrett D'Amore dnetp->free_desc = avail;
142798e8d175SSteven Stallion dnetp->need_tx_update = B_TRUE;
142898e8d175SSteven Stallion return (B_FALSE);
1429bdb9230aSGarrett D'Amore } else if (error) {
1430bdb9230aSGarrett D'Amore dnetp->free_desc = avail;
1431bdb9230aSGarrett D'Amore freemsg(mp);
143298e8d175SSteven Stallion return (B_TRUE); /* Drop packet, don't retry */
1433bdb9230aSGarrett D'Amore }
1434bdb9230aSGarrett D'Amore
143598e8d175SSteven Stallion if (totlen > ETHERMAX + VLAN_TAGSZ) {
1436bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "DNET: tried to send large %d packet", totlen);
1437bdb9230aSGarrett D'Amore dnetp->free_desc = avail;
1438bdb9230aSGarrett D'Amore freemsg(mp);
143998e8d175SSteven Stallion return (B_TRUE); /* Don't repeat this attempt */
1440bdb9230aSGarrett D'Amore }
1441bdb9230aSGarrett D'Amore
1442bdb9230aSGarrett D'Amore /*
1443bdb9230aSGarrett D'Amore * Remeber the message buffer pointer to do freemsg() at xmit
1444bdb9230aSGarrett D'Amore * interrupt time.
1445bdb9230aSGarrett D'Amore */
1446bdb9230aSGarrett D'Amore dnetp->tx_msgbufp[end_index] = mp;
1447bdb9230aSGarrett D'Amore
1448bdb9230aSGarrett D'Amore /*
1449bdb9230aSGarrett D'Amore * Now set the first/last buffer and own bits
1450bdb9230aSGarrett D'Amore * Since the 21040 looks for these bits set in the
1451bdb9230aSGarrett D'Amore * first buffer, work backwards in multiple buffers.
1452bdb9230aSGarrett D'Amore */
1453bdb9230aSGarrett D'Amore ring[end_index].desc1.last_desc = 1;
1454bdb9230aSGarrett D'Amore ring[end_index].desc1.int_on_comp = 1;
1455bdb9230aSGarrett D'Amore for (index = end_index; index != start_index;
1456bdb9230aSGarrett D'Amore index = PrevTXIndex(index))
1457bdb9230aSGarrett D'Amore ring[index].desc0.own = 1;
1458bdb9230aSGarrett D'Amore ring[start_index].desc1.first_desc = 1;
1459bdb9230aSGarrett D'Amore ring[start_index].desc0.own = 1;
1460bdb9230aSGarrett D'Amore
1461bdb9230aSGarrett D'Amore dnetp->tx_current_desc = NextTXIndex(end_index);
1462bdb9230aSGarrett D'Amore
1463bdb9230aSGarrett D'Amore /*
1464bdb9230aSGarrett D'Amore * Safety check: make sure end-of-ring is set in last desc.
1465bdb9230aSGarrett D'Amore */
1466bdb9230aSGarrett D'Amore ASSERT(ring[dnetp->max_tx_desc-1].desc1.end_of_ring != 0);
1467bdb9230aSGarrett D'Amore
146898e8d175SSteven Stallion return (B_TRUE);
1469bdb9230aSGarrett D'Amore }
1470bdb9230aSGarrett D'Amore
1471bdb9230aSGarrett D'Amore /*
147298e8d175SSteven Stallion * dnet_intr() -- interrupt from board to inform us that a receive or
1473bdb9230aSGarrett D'Amore * transmit has completed.
1474bdb9230aSGarrett D'Amore */
1475bdb9230aSGarrett D'Amore static uint_t
dnet_intr(caddr_t arg)147698e8d175SSteven Stallion dnet_intr(caddr_t arg)
1477bdb9230aSGarrett D'Amore {
147898e8d175SSteven Stallion struct dnetinstance *dnetp = (struct dnetinstance *)arg;
1479bdb9230aSGarrett D'Amore uint32_t int_status;
1480bdb9230aSGarrett D'Amore
1481bdb9230aSGarrett D'Amore mutex_enter(&dnetp->intrlock);
148298e8d175SSteven Stallion
1483bdb9230aSGarrett D'Amore if (dnetp->suspended) {
1484bdb9230aSGarrett D'Amore mutex_exit(&dnetp->intrlock);
1485bdb9230aSGarrett D'Amore return (DDI_INTR_UNCLAIMED);
1486bdb9230aSGarrett D'Amore }
1487bdb9230aSGarrett D'Amore
1488bdb9230aSGarrett D'Amore int_status = ddi_get32(dnetp->io_handle, REG32(dnetp->io_reg,
1489bdb9230aSGarrett D'Amore STATUS_REG));
1490bdb9230aSGarrett D'Amore
1491bdb9230aSGarrett D'Amore /*
1492bdb9230aSGarrett D'Amore * If interrupt was not from this board
1493bdb9230aSGarrett D'Amore */
1494bdb9230aSGarrett D'Amore if (!(int_status & (NORMAL_INTR_SUMM | ABNORMAL_INTR_SUMM))) {
1495bdb9230aSGarrett D'Amore mutex_exit(&dnetp->intrlock);
1496bdb9230aSGarrett D'Amore return (DDI_INTR_UNCLAIMED);
1497bdb9230aSGarrett D'Amore }
1498bdb9230aSGarrett D'Amore
1499bdb9230aSGarrett D'Amore dnetp->stat_intr++;
1500bdb9230aSGarrett D'Amore
1501bdb9230aSGarrett D'Amore if (int_status & GPTIMER_INTR) {
1502bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle,
1503bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, STATUS_REG), GPTIMER_INTR);
1504bdb9230aSGarrett D'Amore if (dnetp->timer.cb)
1505bdb9230aSGarrett D'Amore dnetp->timer.cb(dnetp);
1506bdb9230aSGarrett D'Amore else
1507bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "dnet: unhandled timer interrupt");
1508bdb9230aSGarrett D'Amore }
1509bdb9230aSGarrett D'Amore
1510bdb9230aSGarrett D'Amore if (int_status & TX_INTR) {
1511bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle,
1512bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, STATUS_REG), TX_INTR);
1513bdb9230aSGarrett D'Amore mutex_enter(&dnetp->txlock);
151498e8d175SSteven Stallion if (dnetp->need_tx_update) {
1515bdb9230aSGarrett D'Amore mutex_exit(&dnetp->txlock);
1516bdb9230aSGarrett D'Amore mutex_exit(&dnetp->intrlock);
151798e8d175SSteven Stallion mac_tx_update(dnetp->mac_handle);
1518bdb9230aSGarrett D'Amore mutex_enter(&dnetp->intrlock);
1519bdb9230aSGarrett D'Amore mutex_enter(&dnetp->txlock);
152098e8d175SSteven Stallion dnetp->need_tx_update = B_FALSE;
1521bdb9230aSGarrett D'Amore }
1522bdb9230aSGarrett D'Amore /* reclaim any xmit descriptors that are completed */
152398e8d175SSteven Stallion dnet_reclaim_Tx_desc(dnetp);
1524bdb9230aSGarrett D'Amore mutex_exit(&dnetp->txlock);
1525bdb9230aSGarrett D'Amore }
1526bdb9230aSGarrett D'Amore
1527bdb9230aSGarrett D'Amore /*
1528bdb9230aSGarrett D'Amore * Check if receive interrupt bit is set
1529bdb9230aSGarrett D'Amore */
1530bdb9230aSGarrett D'Amore if (int_status & (RX_INTR | RX_UNAVAIL_INTR)) {
1531bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle,
1532bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, STATUS_REG),
1533bdb9230aSGarrett D'Amore int_status & (RX_INTR | RX_UNAVAIL_INTR));
153498e8d175SSteven Stallion dnet_getp(dnetp);
1535bdb9230aSGarrett D'Amore }
1536bdb9230aSGarrett D'Amore
1537bdb9230aSGarrett D'Amore if (int_status & ABNORMAL_INTR_SUMM) {
1538bdb9230aSGarrett D'Amore /*
1539bdb9230aSGarrett D'Amore * Check for system error
1540bdb9230aSGarrett D'Amore */
1541bdb9230aSGarrett D'Amore if (int_status & SYS_ERR) {
1542bdb9230aSGarrett D'Amore if ((int_status & SYS_ERR_BITS) == MASTER_ABORT)
1543bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "DNET: Bus Master Abort");
1544bdb9230aSGarrett D'Amore if ((int_status & SYS_ERR_BITS) == TARGET_ABORT)
1545bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "DNET: Bus Target Abort");
1546bdb9230aSGarrett D'Amore if ((int_status & SYS_ERR_BITS) == PARITY_ERROR)
1547bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "DNET: Parity error");
1548bdb9230aSGarrett D'Amore }
1549bdb9230aSGarrett D'Amore
1550bdb9230aSGarrett D'Amore /*
1551bdb9230aSGarrett D'Amore * If the jabber has timed out then reset the chip
1552bdb9230aSGarrett D'Amore */
1553bdb9230aSGarrett D'Amore if (int_status & TX_JABBER_TIMEOUT)
1554bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "DNET: Jabber timeout.");
1555bdb9230aSGarrett D'Amore
1556bdb9230aSGarrett D'Amore /*
1557bdb9230aSGarrett D'Amore * If an underflow has occurred, reset the chip
1558bdb9230aSGarrett D'Amore */
1559bdb9230aSGarrett D'Amore if (int_status & TX_UNDERFLOW)
1560bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "DNET: Tx Underflow.");
1561bdb9230aSGarrett D'Amore
1562bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
1563bdb9230aSGarrett D'Amore if (dnetdebug & DNETINT)
1564bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "Trying to reset...");
1565bdb9230aSGarrett D'Amore #endif
156698e8d175SSteven Stallion dnet_reset_board(dnetp);
156798e8d175SSteven Stallion dnet_init_board(dnetp);
1568bdb9230aSGarrett D'Amore /* XXX function return value ignored */
156998e8d175SSteven Stallion (void) dnet_start(dnetp);
1570bdb9230aSGarrett D'Amore }
1571bdb9230aSGarrett D'Amore
1572bdb9230aSGarrett D'Amore /*
157398e8d175SSteven Stallion * Enable the interrupts. Enable xmit interrupt in case we are
1574bdb9230aSGarrett D'Amore * running out of free descriptors or if there are packets
1575bdb9230aSGarrett D'Amore * in the queue waiting to be transmitted.
1576bdb9230aSGarrett D'Amore */
157798e8d175SSteven Stallion enable_interrupts(dnetp);
1578bdb9230aSGarrett D'Amore mutex_exit(&dnetp->intrlock);
1579bdb9230aSGarrett D'Amore return (DDI_INTR_CLAIMED); /* Indicate it was our interrupt */
1580bdb9230aSGarrett D'Amore }
1581bdb9230aSGarrett D'Amore
1582bdb9230aSGarrett D'Amore static void
dnet_getp(struct dnetinstance * dnetp)158398e8d175SSteven Stallion dnet_getp(struct dnetinstance *dnetp)
1584bdb9230aSGarrett D'Amore {
1585bdb9230aSGarrett D'Amore int packet_length, index;
1586bdb9230aSGarrett D'Amore mblk_t *mp;
1587bdb9230aSGarrett D'Amore caddr_t virtual_address;
1588bdb9230aSGarrett D'Amore struct rx_desc_type *desc = dnetp->rx_desc;
1589bdb9230aSGarrett D'Amore int marker = dnetp->rx_current_desc;
1590bdb9230aSGarrett D'Amore int misses;
1591bdb9230aSGarrett D'Amore
1592bdb9230aSGarrett D'Amore if (!dnetp->overrun_workaround) {
1593bdb9230aSGarrett D'Amore /*
1594bdb9230aSGarrett D'Amore * If the workaround is not in place, we must still update
1595bdb9230aSGarrett D'Amore * the missed frame statistic from the on-chip counter.
1596bdb9230aSGarrett D'Amore */
1597bdb9230aSGarrett D'Amore misses = ddi_get32(dnetp->io_handle,
1598bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, MISSED_FRAME_REG));
1599bdb9230aSGarrett D'Amore dnetp->stat_missed += (misses & MISSED_FRAME_MASK);
1600bdb9230aSGarrett D'Amore }
1601bdb9230aSGarrett D'Amore
1602bdb9230aSGarrett D'Amore /* While host owns the current descriptor */
1603bdb9230aSGarrett D'Amore while (!(desc[dnetp->rx_current_desc].desc0.own)) {
1604bdb9230aSGarrett D'Amore struct free_ptr *frp;
1605bdb9230aSGarrett D'Amore caddr_t newbuf;
1606bdb9230aSGarrett D'Amore struct rbuf_list *rp;
1607bdb9230aSGarrett D'Amore
1608bdb9230aSGarrett D'Amore index = dnetp->rx_current_desc;
1609bdb9230aSGarrett D'Amore ASSERT(desc[index].desc0.first_desc != 0);
1610bdb9230aSGarrett D'Amore
1611bdb9230aSGarrett D'Amore /*
1612bdb9230aSGarrett D'Amore * DMA overrun errata from DEC: avoid possible bus hangs
1613bdb9230aSGarrett D'Amore * and data corruption
1614bdb9230aSGarrett D'Amore */
1615bdb9230aSGarrett D'Amore if (dnetp->overrun_workaround &&
1616bdb9230aSGarrett D'Amore marker == dnetp->rx_current_desc) {
1617bdb9230aSGarrett D'Amore int opn;
1618bdb9230aSGarrett D'Amore do {
1619bdb9230aSGarrett D'Amore marker = (marker+1) % dnetp->max_rx_desc;
1620bdb9230aSGarrett D'Amore } while (!(dnetp->rx_desc[marker].desc0.own) &&
1621bdb9230aSGarrett D'Amore marker != index);
1622bdb9230aSGarrett D'Amore
1623bdb9230aSGarrett D'Amore misses = ddi_get32(dnetp->io_handle,
1624bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, MISSED_FRAME_REG));
1625bdb9230aSGarrett D'Amore dnetp->stat_missed +=
1626bdb9230aSGarrett D'Amore (misses & MISSED_FRAME_MASK);
1627bdb9230aSGarrett D'Amore if (misses & OVERFLOW_COUNTER_MASK) {
1628bdb9230aSGarrett D'Amore /*
1629bdb9230aSGarrett D'Amore * Overflow(s) have occurred : stop receiver,
1630bdb9230aSGarrett D'Amore * and wait until in stopped state
1631bdb9230aSGarrett D'Amore */
1632bdb9230aSGarrett D'Amore opn = ddi_get32(dnetp->io_handle,
1633bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, OPN_MODE_REG));
1634bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle,
1635bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, OPN_MODE_REG),
1636bdb9230aSGarrett D'Amore opn & ~(START_RECEIVE));
1637bdb9230aSGarrett D'Amore
1638bdb9230aSGarrett D'Amore do {
1639bdb9230aSGarrett D'Amore drv_usecwait(10);
1640bdb9230aSGarrett D'Amore } while ((ddi_get32(dnetp->io_handle,
1641bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, STATUS_REG)) &
1642bdb9230aSGarrett D'Amore RECEIVE_PROCESS_STATE) != 0);
1643bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
1644bdb9230aSGarrett D'Amore if (dnetdebug & DNETRECV)
1645bdb9230aSGarrett D'Amore cmn_err(CE_CONT, "^*");
1646bdb9230aSGarrett D'Amore #endif
1647bdb9230aSGarrett D'Amore /* Discard probably corrupt frames */
1648bdb9230aSGarrett D'Amore while (!(dnetp->rx_desc[index].desc0.own)) {
1649bdb9230aSGarrett D'Amore dnetp->rx_desc[index].desc0.own = 1;
1650bdb9230aSGarrett D'Amore index = (index+1) % dnetp->max_rx_desc;
1651bdb9230aSGarrett D'Amore dnetp->stat_missed++;
1652bdb9230aSGarrett D'Amore }
1653bdb9230aSGarrett D'Amore
1654bdb9230aSGarrett D'Amore /* restart the receiver */
1655bdb9230aSGarrett D'Amore opn = ddi_get32(dnetp->io_handle,
1656bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, OPN_MODE_REG));
1657bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle,
1658bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, OPN_MODE_REG),
1659bdb9230aSGarrett D'Amore opn | START_RECEIVE);
1660bdb9230aSGarrett D'Amore marker = dnetp->rx_current_desc = index;
1661bdb9230aSGarrett D'Amore continue;
1662bdb9230aSGarrett D'Amore }
1663bdb9230aSGarrett D'Amore /*
1664bdb9230aSGarrett D'Amore * At this point, we know that all packets before
1665bdb9230aSGarrett D'Amore * "marker" were received before a dma overrun occurred
1666bdb9230aSGarrett D'Amore */
1667bdb9230aSGarrett D'Amore }
1668bdb9230aSGarrett D'Amore
1669bdb9230aSGarrett D'Amore /*
1670bdb9230aSGarrett D'Amore * If we get an oversized packet it could span multiple
1671bdb9230aSGarrett D'Amore * descriptors. If this happens an error bit should be set.
1672bdb9230aSGarrett D'Amore */
1673bdb9230aSGarrett D'Amore while (desc[index].desc0.last_desc == 0) {
1674bdb9230aSGarrett D'Amore index = (index + 1) % dnetp->max_rx_desc;
1675bdb9230aSGarrett D'Amore if (desc[index].desc0.own)
1676bdb9230aSGarrett D'Amore return; /* not done receiving large packet */
1677bdb9230aSGarrett D'Amore }
1678bdb9230aSGarrett D'Amore while (dnetp->rx_current_desc != index) {
1679bdb9230aSGarrett D'Amore desc[dnetp->rx_current_desc].desc0.own = 1;
1680bdb9230aSGarrett D'Amore dnetp->rx_current_desc =
1681bdb9230aSGarrett D'Amore (dnetp->rx_current_desc + 1) % dnetp->max_rx_desc;
1682bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
1683bdb9230aSGarrett D'Amore if (dnetdebug & DNETRECV)
1684bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "dnet: received large packet");
1685bdb9230aSGarrett D'Amore #endif
1686bdb9230aSGarrett D'Amore }
1687bdb9230aSGarrett D'Amore
1688bdb9230aSGarrett D'Amore packet_length = desc[index].desc0.frame_len;
1689bdb9230aSGarrett D'Amore
1690bdb9230aSGarrett D'Amore /*
1691bdb9230aSGarrett D'Amore * Remove CRC from received data. This is an artefact of the
1692bdb9230aSGarrett D'Amore * 21x4x chip and should not be passed higher up the network
1693bdb9230aSGarrett D'Amore * stack.
1694bdb9230aSGarrett D'Amore */
1695bdb9230aSGarrett D'Amore packet_length -= ETHERFCSL;
1696bdb9230aSGarrett D'Amore
1697bdb9230aSGarrett D'Amore /* get the virtual address of the packet received */
1698bdb9230aSGarrett D'Amore virtual_address =
1699bdb9230aSGarrett D'Amore dnetp->rx_buf_vaddr[index];
1700bdb9230aSGarrett D'Amore
1701bdb9230aSGarrett D'Amore /*
1702bdb9230aSGarrett D'Amore * If no packet errors then do:
1703bdb9230aSGarrett D'Amore * 1. Allocate a new receive buffer so that we can
1704bdb9230aSGarrett D'Amore * use the current buffer as streams buffer to
1705bdb9230aSGarrett D'Amore * avoid bcopy.
1706bdb9230aSGarrett D'Amore * 2. If we got a new receive buffer then allocate
1707bdb9230aSGarrett D'Amore * an mblk using desballoc().
1708bdb9230aSGarrett D'Amore * 3. Otherwise use the mblk from allocb() and do
1709bdb9230aSGarrett D'Amore * the bcopy.
1710bdb9230aSGarrett D'Amore */
1711bdb9230aSGarrett D'Amore frp = NULL;
1712bdb9230aSGarrett D'Amore rp = NULL;
1713bdb9230aSGarrett D'Amore newbuf = NULL;
1714bdb9230aSGarrett D'Amore mp = NULL;
171598e8d175SSteven Stallion if (!desc[index].desc0.err_summary ||
171698e8d175SSteven Stallion (desc[index].desc0.frame2long &&
171798e8d175SSteven Stallion packet_length < rx_buf_size)) {
1718bdb9230aSGarrett D'Amore ASSERT(packet_length < rx_buf_size);
1719bdb9230aSGarrett D'Amore /*
1720bdb9230aSGarrett D'Amore * Allocate another receive buffer for this descriptor.
1721bdb9230aSGarrett D'Amore * If we fail to allocate then we do the normal bcopy.
1722bdb9230aSGarrett D'Amore */
1723bdb9230aSGarrett D'Amore rp = dnet_rbuf_alloc(dnetp->devinfo, 0);
1724bdb9230aSGarrett D'Amore if (rp != NULL) {
1725bdb9230aSGarrett D'Amore newbuf = rp->rbuf_vaddr;
1726bdb9230aSGarrett D'Amore frp = kmem_zalloc(sizeof (*frp), KM_NOSLEEP);
1727bdb9230aSGarrett D'Amore if (frp != NULL) {
1728bdb9230aSGarrett D'Amore frp->free_rtn.free_func =
1729bdb9230aSGarrett D'Amore dnet_freemsg_buf;
1730bdb9230aSGarrett D'Amore frp->free_rtn.free_arg = (char *)frp;
1731bdb9230aSGarrett D'Amore frp->buf = virtual_address;
1732bdb9230aSGarrett D'Amore mp = desballoc(
1733bdb9230aSGarrett D'Amore (uchar_t *)virtual_address,
1734bdb9230aSGarrett D'Amore packet_length, 0, &frp->free_rtn);
1735bdb9230aSGarrett D'Amore if (mp == NULL) {
1736bdb9230aSGarrett D'Amore kmem_free(frp, sizeof (*frp));
1737bdb9230aSGarrett D'Amore dnet_rbuf_free((caddr_t)newbuf);
1738bdb9230aSGarrett D'Amore frp = NULL;
1739bdb9230aSGarrett D'Amore newbuf = NULL;
1740bdb9230aSGarrett D'Amore }
1741bdb9230aSGarrett D'Amore }
1742bdb9230aSGarrett D'Amore }
1743bdb9230aSGarrett D'Amore if (mp == NULL) {
1744bdb9230aSGarrett D'Amore if (newbuf != NULL)
1745bdb9230aSGarrett D'Amore dnet_rbuf_free((caddr_t)newbuf);
1746bdb9230aSGarrett D'Amore mp = allocb(packet_length, 0);
1747bdb9230aSGarrett D'Amore }
1748bdb9230aSGarrett D'Amore }
1749bdb9230aSGarrett D'Amore
175098e8d175SSteven Stallion if ((desc[index].desc0.err_summary &&
175198e8d175SSteven Stallion packet_length >= rx_buf_size) || mp == NULL) {
1752bdb9230aSGarrett D'Amore
1753bdb9230aSGarrett D'Amore /* Update gld statistics */
1754bdb9230aSGarrett D'Amore if (desc[index].desc0.err_summary)
175598e8d175SSteven Stallion update_rx_stats(dnetp, index);
1756bdb9230aSGarrett D'Amore else
1757bdb9230aSGarrett D'Amore dnetp->stat_norcvbuf++;
1758bdb9230aSGarrett D'Amore
1759bdb9230aSGarrett D'Amore /*
1760bdb9230aSGarrett D'Amore * Reset ownership of the descriptor.
1761bdb9230aSGarrett D'Amore */
1762bdb9230aSGarrett D'Amore desc[index].desc0.own = 1;
1763bdb9230aSGarrett D'Amore dnetp->rx_current_desc =
1764bdb9230aSGarrett D'Amore (dnetp->rx_current_desc+1) % dnetp->max_rx_desc;
1765bdb9230aSGarrett D'Amore
1766bdb9230aSGarrett D'Amore /* Demand receive polling by the chip */
1767bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle,
1768bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, RX_POLL_REG), RX_POLL_DEMAND);
1769bdb9230aSGarrett D'Amore
1770bdb9230aSGarrett D'Amore continue;
1771bdb9230aSGarrett D'Amore }
1772bdb9230aSGarrett D'Amore
1773bdb9230aSGarrett D'Amore if (newbuf != NULL) {
1774bdb9230aSGarrett D'Amore uint32_t end_paddr;
1775bdb9230aSGarrett D'Amore /* attach the new buffer to the rx descriptor */
1776bdb9230aSGarrett D'Amore dnetp->rx_buf_vaddr[index] = newbuf;
1777bdb9230aSGarrett D'Amore dnetp->rx_buf_paddr[index] = rp->rbuf_paddr;
1778bdb9230aSGarrett D'Amore desc[index].buffer1 = rp->rbuf_paddr;
1779bdb9230aSGarrett D'Amore desc[index].desc1.buffer_size1 = rx_buf_size;
1780bdb9230aSGarrett D'Amore desc[index].desc1.buffer_size2 = 0;
1781bdb9230aSGarrett D'Amore end_paddr = rp->rbuf_endpaddr;
1782bdb9230aSGarrett D'Amore if ((desc[index].buffer1 & ~dnetp->pgmask) !=
1783bdb9230aSGarrett D'Amore (end_paddr & ~dnetp->pgmask)) {
1784bdb9230aSGarrett D'Amore /* discontiguous */
1785bdb9230aSGarrett D'Amore desc[index].buffer2 = end_paddr&~dnetp->pgmask;
1786bdb9230aSGarrett D'Amore desc[index].desc1.buffer_size2 =
1787bdb9230aSGarrett D'Amore (end_paddr & dnetp->pgmask) + 1;
1788bdb9230aSGarrett D'Amore desc[index].desc1.buffer_size1 =
1789bdb9230aSGarrett D'Amore rx_buf_size-desc[index].desc1.buffer_size2;
1790bdb9230aSGarrett D'Amore }
1791bdb9230aSGarrett D'Amore } else {
1792bdb9230aSGarrett D'Amore /* couldn't allocate another buffer; copy the data */
1793bdb9230aSGarrett D'Amore BCOPY((caddr_t)virtual_address, (caddr_t)mp->b_wptr,
1794bdb9230aSGarrett D'Amore packet_length);
1795bdb9230aSGarrett D'Amore }
1796bdb9230aSGarrett D'Amore
1797bdb9230aSGarrett D'Amore mp->b_wptr += packet_length;
1798bdb9230aSGarrett D'Amore
1799bdb9230aSGarrett D'Amore desc[dnetp->rx_current_desc].desc0.own = 1;
1800bdb9230aSGarrett D'Amore
1801bdb9230aSGarrett D'Amore /*
1802bdb9230aSGarrett D'Amore * Increment receive desc index. This is for the scan of
1803bdb9230aSGarrett D'Amore * next packet
1804bdb9230aSGarrett D'Amore */
1805bdb9230aSGarrett D'Amore dnetp->rx_current_desc =
1806bdb9230aSGarrett D'Amore (dnetp->rx_current_desc+1) % dnetp->max_rx_desc;
1807bdb9230aSGarrett D'Amore
1808bdb9230aSGarrett D'Amore /* Demand polling by chip */
1809bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle,
1810bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, RX_POLL_REG), RX_POLL_DEMAND);
1811bdb9230aSGarrett D'Amore
1812bdb9230aSGarrett D'Amore /* send the packet upstream */
1813bdb9230aSGarrett D'Amore mutex_exit(&dnetp->intrlock);
181498e8d175SSteven Stallion mac_rx(dnetp->mac_handle, NULL, mp);
1815bdb9230aSGarrett D'Amore mutex_enter(&dnetp->intrlock);
1816bdb9230aSGarrett D'Amore }
1817bdb9230aSGarrett D'Amore }
1818bdb9230aSGarrett D'Amore /*
1819bdb9230aSGarrett D'Amore * Function to update receive statistics
1820bdb9230aSGarrett D'Amore */
1821bdb9230aSGarrett D'Amore static void
update_rx_stats(struct dnetinstance * dnetp,int index)182298e8d175SSteven Stallion update_rx_stats(struct dnetinstance *dnetp, int index)
1823bdb9230aSGarrett D'Amore {
1824bdb9230aSGarrett D'Amore struct rx_desc_type *descp = &(dnetp->rx_desc[index]);
1825bdb9230aSGarrett D'Amore
1826bdb9230aSGarrett D'Amore /*
1827bdb9230aSGarrett D'Amore * Update gld statistics
1828bdb9230aSGarrett D'Amore */
1829bdb9230aSGarrett D'Amore dnetp->stat_errrcv++;
1830bdb9230aSGarrett D'Amore
1831bdb9230aSGarrett D'Amore if (descp->desc0.overflow) {
1832bdb9230aSGarrett D'Amore /* FIFO Overrun */
1833bdb9230aSGarrett D'Amore dnetp->stat_overflow++;
1834bdb9230aSGarrett D'Amore }
1835bdb9230aSGarrett D'Amore
1836bdb9230aSGarrett D'Amore if (descp->desc0.collision) {
1837bdb9230aSGarrett D'Amore /*EMPTY*/
1838bdb9230aSGarrett D'Amore /* Late Colllision on receive */
1839bdb9230aSGarrett D'Amore /* no appropriate counter */
1840bdb9230aSGarrett D'Amore }
1841bdb9230aSGarrett D'Amore
1842bdb9230aSGarrett D'Amore if (descp->desc0.crc) {
1843bdb9230aSGarrett D'Amore /* CRC Error */
1844bdb9230aSGarrett D'Amore dnetp->stat_crc++;
1845bdb9230aSGarrett D'Amore }
1846bdb9230aSGarrett D'Amore
1847bdb9230aSGarrett D'Amore if (descp->desc0.runt_frame) {
1848bdb9230aSGarrett D'Amore /* Runt Error */
1849bdb9230aSGarrett D'Amore dnetp->stat_short++;
1850bdb9230aSGarrett D'Amore }
1851bdb9230aSGarrett D'Amore
1852bdb9230aSGarrett D'Amore if (descp->desc0.desc_err) {
1853bdb9230aSGarrett D'Amore /*EMPTY*/
1854bdb9230aSGarrett D'Amore /* Not enough receive descriptors */
185598e8d175SSteven Stallion /* This condition is accounted in dnet_intr() */
1856bdb9230aSGarrett D'Amore }
1857bdb9230aSGarrett D'Amore
1858bdb9230aSGarrett D'Amore if (descp->desc0.frame2long) {
1859bdb9230aSGarrett D'Amore dnetp->stat_frame++;
1860bdb9230aSGarrett D'Amore }
1861bdb9230aSGarrett D'Amore }
1862bdb9230aSGarrett D'Amore
1863bdb9230aSGarrett D'Amore /*
1864bdb9230aSGarrett D'Amore * Function to update transmit statistics
1865bdb9230aSGarrett D'Amore */
1866bdb9230aSGarrett D'Amore static void
update_tx_stats(struct dnetinstance * dnetp,int index)186798e8d175SSteven Stallion update_tx_stats(struct dnetinstance *dnetp, int index)
1868bdb9230aSGarrett D'Amore {
1869bdb9230aSGarrett D'Amore struct tx_desc_type *descp = &(dnetp->tx_desc[index]);
1870bdb9230aSGarrett D'Amore int fd;
1871bdb9230aSGarrett D'Amore media_block_t *block = dnetp->selected_media_block;
1872bdb9230aSGarrett D'Amore
1873bdb9230aSGarrett D'Amore
1874bdb9230aSGarrett D'Amore /* Update gld statistics */
1875bdb9230aSGarrett D'Amore dnetp->stat_errxmt++;
1876bdb9230aSGarrett D'Amore
1877bdb9230aSGarrett D'Amore /* If we're in full-duplex don't count collisions or carrier loss. */
1878bdb9230aSGarrett D'Amore if (dnetp->mii_up) {
1879bdb9230aSGarrett D'Amore fd = dnetp->mii_duplex;
1880bdb9230aSGarrett D'Amore } else {
1881bdb9230aSGarrett D'Amore /* Rely on media code */
1882bdb9230aSGarrett D'Amore fd = block->media_code == MEDIA_TP_FD ||
1883bdb9230aSGarrett D'Amore block->media_code == MEDIA_SYM_SCR_FD;
1884bdb9230aSGarrett D'Amore }
1885bdb9230aSGarrett D'Amore
1886bdb9230aSGarrett D'Amore if (descp->desc0.collision_count && !fd) {
1887bdb9230aSGarrett D'Amore dnetp->stat_collisions += descp->desc0.collision_count;
1888bdb9230aSGarrett D'Amore }
1889bdb9230aSGarrett D'Amore
1890bdb9230aSGarrett D'Amore if (descp->desc0.late_collision && !fd) {
1891bdb9230aSGarrett D'Amore dnetp->stat_xmtlatecoll++;
1892bdb9230aSGarrett D'Amore }
1893bdb9230aSGarrett D'Amore
1894bdb9230aSGarrett D'Amore if (descp->desc0.excess_collision && !fd) {
1895bdb9230aSGarrett D'Amore dnetp->stat_excoll++;
1896bdb9230aSGarrett D'Amore }
1897bdb9230aSGarrett D'Amore
1898bdb9230aSGarrett D'Amore if (descp->desc0.underflow) {
1899bdb9230aSGarrett D'Amore dnetp->stat_underflow++;
1900bdb9230aSGarrett D'Amore }
1901bdb9230aSGarrett D'Amore
1902bdb9230aSGarrett D'Amore #if 0
1903bdb9230aSGarrett D'Amore if (descp->desc0.tx_jabber_to) {
1904bdb9230aSGarrett D'Amore /* no appropriate counter */
1905bdb9230aSGarrett D'Amore }
1906bdb9230aSGarrett D'Amore #endif
1907bdb9230aSGarrett D'Amore
1908bdb9230aSGarrett D'Amore if (descp->desc0.carrier_loss && !fd) {
1909bdb9230aSGarrett D'Amore dnetp->stat_nocarrier++;
1910bdb9230aSGarrett D'Amore }
1911bdb9230aSGarrett D'Amore
1912bdb9230aSGarrett D'Amore if (descp->desc0.no_carrier && !fd) {
1913bdb9230aSGarrett D'Amore dnetp->stat_nocarrier++;
1914bdb9230aSGarrett D'Amore }
1915bdb9230aSGarrett D'Amore }
1916bdb9230aSGarrett D'Amore
1917bdb9230aSGarrett D'Amore /*
1918bdb9230aSGarrett D'Amore * ========== Media Selection Setup Routines ==========
1919bdb9230aSGarrett D'Amore */
1920bdb9230aSGarrett D'Amore
1921bdb9230aSGarrett D'Amore
1922bdb9230aSGarrett D'Amore static void
write_gpr(struct dnetinstance * dnetp,uint32_t val)1923bdb9230aSGarrett D'Amore write_gpr(struct dnetinstance *dnetp, uint32_t val)
1924bdb9230aSGarrett D'Amore {
1925bdb9230aSGarrett D'Amore #ifdef DEBUG
1926bdb9230aSGarrett D'Amore if (dnetdebug & DNETREGCFG)
1927bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "GPR: %x", val);
1928bdb9230aSGarrett D'Amore #endif
1929bdb9230aSGarrett D'Amore switch (dnetp->board_type) {
1930bdb9230aSGarrett D'Amore case DEVICE_ID_21143:
1931bdb9230aSGarrett D'Amore /* Set the correct bit for a control write */
1932bdb9230aSGarrett D'Amore if (val & GPR_CONTROL_WRITE)
1933bdb9230aSGarrett D'Amore val |= CWE_21143, val &= ~GPR_CONTROL_WRITE;
1934bdb9230aSGarrett D'Amore /* Write to upper half of CSR15 */
1935bdb9230aSGarrett D'Amore dnetp->gprsia = (dnetp->gprsia & 0xffff) | (val << 16);
1936bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle,
1937bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, SIA_GENERAL_REG), dnetp->gprsia);
1938bdb9230aSGarrett D'Amore break;
1939bdb9230aSGarrett D'Amore default:
1940bdb9230aSGarrett D'Amore /* Set the correct bit for a control write */
1941bdb9230aSGarrett D'Amore if (val & GPR_CONTROL_WRITE)
1942bdb9230aSGarrett D'Amore val |= CWE_21140, val &= ~GPR_CONTROL_WRITE;
1943bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, GP_REG), val);
1944bdb9230aSGarrett D'Amore break;
1945bdb9230aSGarrett D'Amore }
1946bdb9230aSGarrett D'Amore }
1947bdb9230aSGarrett D'Amore
1948bdb9230aSGarrett D'Amore static uint32_t
read_gpr(struct dnetinstance * dnetp)1949bdb9230aSGarrett D'Amore read_gpr(struct dnetinstance *dnetp)
1950bdb9230aSGarrett D'Amore {
1951bdb9230aSGarrett D'Amore switch (dnetp->board_type) {
1952bdb9230aSGarrett D'Amore case DEVICE_ID_21143:
1953bdb9230aSGarrett D'Amore /* Read upper half of CSR15 */
1954bdb9230aSGarrett D'Amore return (ddi_get32(dnetp->io_handle,
1955bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, SIA_GENERAL_REG)) >> 16);
1956bdb9230aSGarrett D'Amore default:
1957bdb9230aSGarrett D'Amore return (ddi_get32(dnetp->io_handle,
1958bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, GP_REG)));
1959bdb9230aSGarrett D'Amore }
1960bdb9230aSGarrett D'Amore }
1961bdb9230aSGarrett D'Amore
1962bdb9230aSGarrett D'Amore static void
set_gpr(struct dnetinstance * dnetp)196398e8d175SSteven Stallion set_gpr(struct dnetinstance *dnetp)
1964bdb9230aSGarrett D'Amore {
1965bdb9230aSGarrett D'Amore uint32_t *sequence;
1966bdb9230aSGarrett D'Amore int len;
1967bdb9230aSGarrett D'Amore LEAF_FORMAT *leaf = &dnetp->sr.leaf[dnetp->leaf];
1968bdb9230aSGarrett D'Amore media_block_t *block = dnetp->selected_media_block;
1969bdb9230aSGarrett D'Amore int i;
1970bdb9230aSGarrett D'Amore
1971bdb9230aSGarrett D'Amore if (ddi_getlongprop(DDI_DEV_T_ANY, dnetp->devinfo,
1972bdb9230aSGarrett D'Amore DDI_PROP_DONTPASS, "gpr-sequence", (caddr_t)&sequence,
1973bdb9230aSGarrett D'Amore &len) == DDI_PROP_SUCCESS) {
1974bdb9230aSGarrett D'Amore for (i = 0; i < len / sizeof (uint32_t); i++)
1975bdb9230aSGarrett D'Amore write_gpr(dnetp, sequence[i]);
1976bdb9230aSGarrett D'Amore kmem_free(sequence, len);
1977bdb9230aSGarrett D'Amore } else {
1978bdb9230aSGarrett D'Amore /*
1979bdb9230aSGarrett D'Amore * Write the reset sequence if this is the first time this
1980bdb9230aSGarrett D'Amore * block has been selected.
1981bdb9230aSGarrett D'Amore */
1982bdb9230aSGarrett D'Amore if (block->rstseqlen) {
1983bdb9230aSGarrett D'Amore for (i = 0; i < block->rstseqlen; i++)
1984bdb9230aSGarrett D'Amore write_gpr(dnetp, block->rstseq[i]);
1985bdb9230aSGarrett D'Amore /*
1986bdb9230aSGarrett D'Amore * XXX Legacy blocks do not have reset sequences, so the
1987bdb9230aSGarrett D'Amore * static blocks will never be modified by this
1988bdb9230aSGarrett D'Amore */
1989bdb9230aSGarrett D'Amore block->rstseqlen = 0;
1990bdb9230aSGarrett D'Amore }
1991bdb9230aSGarrett D'Amore if (leaf->gpr)
1992bdb9230aSGarrett D'Amore write_gpr(dnetp, leaf->gpr | GPR_CONTROL_WRITE);
1993bdb9230aSGarrett D'Amore
1994bdb9230aSGarrett D'Amore /* write GPR sequence each time */
1995bdb9230aSGarrett D'Amore for (i = 0; i < block->gprseqlen; i++)
1996bdb9230aSGarrett D'Amore write_gpr(dnetp, block->gprseq[i]);
1997bdb9230aSGarrett D'Amore }
1998bdb9230aSGarrett D'Amore
1999bdb9230aSGarrett D'Amore /* This has possibly caused a PHY to reset. Let MII know */
2000bdb9230aSGarrett D'Amore if (dnetp->phyaddr != -1)
2001bdb9230aSGarrett D'Amore /* XXX function return value ignored */
2002bdb9230aSGarrett D'Amore (void) mii_sync(dnetp->mii, dnetp->phyaddr);
2003bdb9230aSGarrett D'Amore drv_usecwait(5);
2004bdb9230aSGarrett D'Amore }
2005bdb9230aSGarrett D'Amore
2006bdb9230aSGarrett D'Amore /* set_opr() - must be called with intrlock held */
2007bdb9230aSGarrett D'Amore
2008bdb9230aSGarrett D'Amore static void
set_opr(struct dnetinstance * dnetp)200998e8d175SSteven Stallion set_opr(struct dnetinstance *dnetp)
2010bdb9230aSGarrett D'Amore {
2011bdb9230aSGarrett D'Amore uint32_t fd, mb1, sf;
2012bdb9230aSGarrett D'Amore
2013bdb9230aSGarrett D'Amore int opnmode_len;
2014bdb9230aSGarrett D'Amore uint32_t val;
2015bdb9230aSGarrett D'Amore media_block_t *block = dnetp->selected_media_block;
2016bdb9230aSGarrett D'Amore
2017bdb9230aSGarrett D'Amore ASSERT(block);
2018bdb9230aSGarrett D'Amore
2019bdb9230aSGarrett D'Amore /* Check for custom "opnmode_reg" property */
2020bdb9230aSGarrett D'Amore opnmode_len = sizeof (val);
2021bdb9230aSGarrett D'Amore if (ddi_prop_op(DDI_DEV_T_ANY, dnetp->devinfo,
2022bdb9230aSGarrett D'Amore PROP_LEN_AND_VAL_BUF, DDI_PROP_DONTPASS, "opnmode_reg",
2023bdb9230aSGarrett D'Amore (caddr_t)&val, &opnmode_len) != DDI_PROP_SUCCESS)
2024bdb9230aSGarrett D'Amore opnmode_len = 0;
2025bdb9230aSGarrett D'Amore
2026bdb9230aSGarrett D'Amore /* Some bits exist only on 21140 and greater */
2027bdb9230aSGarrett D'Amore if (dnetp->board_type != DEVICE_ID_21040 &&
2028bdb9230aSGarrett D'Amore dnetp->board_type != DEVICE_ID_21041) {
2029bdb9230aSGarrett D'Amore mb1 = OPN_REG_MB1;
2030bdb9230aSGarrett D'Amore sf = STORE_AND_FORWARD;
2031bdb9230aSGarrett D'Amore } else {
2032bdb9230aSGarrett D'Amore mb1 = sf = 0;
2033bdb9230aSGarrett D'Amore mb1 = OPN_REG_MB1; /* Needed for 21040? */
2034bdb9230aSGarrett D'Amore }
2035bdb9230aSGarrett D'Amore
2036bdb9230aSGarrett D'Amore if (opnmode_len) {
2037bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle,
2038bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, OPN_MODE_REG), val);
203998e8d175SSteven Stallion dnet_reset_board(dnetp);
2040bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle,
2041bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, OPN_MODE_REG), val);
2042bdb9230aSGarrett D'Amore return;
2043bdb9230aSGarrett D'Amore }
2044bdb9230aSGarrett D'Amore
2045bdb9230aSGarrett D'Amore /*
2046bdb9230aSGarrett D'Amore * Set each bit in CSR6 that we want
2047bdb9230aSGarrett D'Amore */
2048bdb9230aSGarrett D'Amore
2049bdb9230aSGarrett D'Amore /* Always want these bits set */
2050bdb9230aSGarrett D'Amore val = HASH_FILTERING | HASH_ONLY | TX_THRESHOLD_160 | mb1 | sf;
2051bdb9230aSGarrett D'Amore
2052bdb9230aSGarrett D'Amore /* Promiscuous mode */
2053bdb9230aSGarrett D'Amore val |= dnetp->promisc ? PROM_MODE : 0;
2054bdb9230aSGarrett D'Amore
2055bdb9230aSGarrett D'Amore /* Scrambler for SYM style media */
2056bdb9230aSGarrett D'Amore val |= ((block->command & CMD_SCR) && !dnetp->disable_scrambler) ?
2057bdb9230aSGarrett D'Amore SCRAMBLER_MODE : 0;
2058bdb9230aSGarrett D'Amore
2059bdb9230aSGarrett D'Amore /* Full duplex */
2060bdb9230aSGarrett D'Amore if (dnetp->mii_up) {
2061bdb9230aSGarrett D'Amore fd = dnetp->mii_duplex;
2062bdb9230aSGarrett D'Amore } else {
2063bdb9230aSGarrett D'Amore /* Rely on media code */
2064bdb9230aSGarrett D'Amore fd = block->media_code == MEDIA_TP_FD ||
2065bdb9230aSGarrett D'Amore block->media_code == MEDIA_SYM_SCR_FD;
2066bdb9230aSGarrett D'Amore }
2067bdb9230aSGarrett D'Amore
2068bdb9230aSGarrett D'Amore /* Port select (and therefore, heartbeat disable) */
2069bdb9230aSGarrett D'Amore val |= block->command & CMD_PS ? (PORT_SELECT | HEARTBEAT_DISABLE) : 0;
2070bdb9230aSGarrett D'Amore
2071bdb9230aSGarrett D'Amore /* PCS function */
2072bdb9230aSGarrett D'Amore val |= (block->command) & CMD_PCS ? PCS_FUNCTION : 0;
2073bdb9230aSGarrett D'Amore val |= fd ? FULL_DUPLEX : 0;
2074bdb9230aSGarrett D'Amore
2075bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
2076bdb9230aSGarrett D'Amore if (dnetdebug & DNETREGCFG)
2077bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "OPN: %x", val);
2078bdb9230aSGarrett D'Amore #endif
2079bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG), val);
208098e8d175SSteven Stallion dnet_reset_board(dnetp);
2081bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG), val);
2082bdb9230aSGarrett D'Amore }
2083bdb9230aSGarrett D'Amore
2084bdb9230aSGarrett D'Amore static void
set_sia(struct dnetinstance * dnetp)208598e8d175SSteven Stallion set_sia(struct dnetinstance *dnetp)
2086bdb9230aSGarrett D'Amore {
2087bdb9230aSGarrett D'Amore media_block_t *block = dnetp->selected_media_block;
2088bdb9230aSGarrett D'Amore
2089bdb9230aSGarrett D'Amore ASSERT(MUTEX_HELD(&dnetp->intrlock));
2090bdb9230aSGarrett D'Amore if (block->type == 2) {
2091bdb9230aSGarrett D'Amore int sia_delay;
2092bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
2093bdb9230aSGarrett D'Amore if (dnetdebug & DNETREGCFG)
2094bdb9230aSGarrett D'Amore cmn_err(CE_NOTE,
2095bdb9230aSGarrett D'Amore "SIA: CSR13: %x, CSR14: %x, CSR15: %x",
2096bdb9230aSGarrett D'Amore block->un.sia.csr13,
2097bdb9230aSGarrett D'Amore block->un.sia.csr14,
2098bdb9230aSGarrett D'Amore block->un.sia.csr15);
2099bdb9230aSGarrett D'Amore #endif
2100bdb9230aSGarrett D'Amore sia_delay = ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo,
2101bdb9230aSGarrett D'Amore DDI_PROP_DONTPASS, "sia-delay", 10000);
2102bdb9230aSGarrett D'Amore
2103bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle,
2104bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, SIA_CONNECT_REG), 0);
2105bdb9230aSGarrett D'Amore
2106bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, SIA_TXRX_REG),
2107bdb9230aSGarrett D'Amore block->un.sia.csr14);
2108bdb9230aSGarrett D'Amore
2109bdb9230aSGarrett D'Amore /*
2110bdb9230aSGarrett D'Amore * For '143, we need to write through a copy of the register
2111bdb9230aSGarrett D'Amore * to keep the GP half intact
2112bdb9230aSGarrett D'Amore */
2113bdb9230aSGarrett D'Amore dnetp->gprsia = (dnetp->gprsia&0xffff0000)|block->un.sia.csr15;
2114bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle,
2115bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, SIA_GENERAL_REG),
2116bdb9230aSGarrett D'Amore dnetp->gprsia);
2117bdb9230aSGarrett D'Amore
2118bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle,
2119bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, SIA_CONNECT_REG),
2120bdb9230aSGarrett D'Amore block->un.sia.csr13);
2121bdb9230aSGarrett D'Amore
2122bdb9230aSGarrett D'Amore drv_usecwait(sia_delay);
2123bdb9230aSGarrett D'Amore
2124bdb9230aSGarrett D'Amore } else if (dnetp->board_type != DEVICE_ID_21140) {
2125bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle,
2126bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, SIA_CONNECT_REG), 0);
2127bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle,
2128bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, SIA_TXRX_REG), 0);
2129bdb9230aSGarrett D'Amore }
2130bdb9230aSGarrett D'Amore }
2131bdb9230aSGarrett D'Amore
2132bdb9230aSGarrett D'Amore /*
2133bdb9230aSGarrett D'Amore * This function (re)allocates the receive and transmit buffers and
2134bdb9230aSGarrett D'Amore * descriptors. It can be called more than once per instance, though
2135bdb9230aSGarrett D'Amore * currently it is only called from attach. It should only be called
2136bdb9230aSGarrett D'Amore * while the device is reset.
2137bdb9230aSGarrett D'Amore */
2138bdb9230aSGarrett D'Amore static int
dnet_alloc_bufs(struct dnetinstance * dnetp)213998e8d175SSteven Stallion dnet_alloc_bufs(struct dnetinstance *dnetp)
2140bdb9230aSGarrett D'Amore {
2141bdb9230aSGarrett D'Amore int i;
2142bdb9230aSGarrett D'Amore size_t len;
2143bdb9230aSGarrett D'Amore int page_size;
2144bdb9230aSGarrett D'Amore int realloc = 0;
2145bdb9230aSGarrett D'Amore int nrecv_desc_old = 0;
2146bdb9230aSGarrett D'Amore ddi_dma_cookie_t cookie;
2147bdb9230aSGarrett D'Amore uint_t ncookies;
2148bdb9230aSGarrett D'Amore
2149bdb9230aSGarrett D'Amore /*
2150bdb9230aSGarrett D'Amore * check if we are trying to reallocate with different xmit/recv
2151bdb9230aSGarrett D'Amore * descriptor ring sizes.
2152bdb9230aSGarrett D'Amore */
2153bdb9230aSGarrett D'Amore if ((dnetp->tx_desc != NULL) &&
2154bdb9230aSGarrett D'Amore (dnetp->nxmit_desc != dnetp->max_tx_desc))
2155bdb9230aSGarrett D'Amore realloc = 1;
2156bdb9230aSGarrett D'Amore
2157bdb9230aSGarrett D'Amore if ((dnetp->rx_desc != NULL) &&
2158bdb9230aSGarrett D'Amore (dnetp->nrecv_desc != dnetp->max_rx_desc))
2159bdb9230aSGarrett D'Amore realloc = 1;
2160bdb9230aSGarrett D'Amore
2161bdb9230aSGarrett D'Amore /* free up the old buffers if we are reallocating them */
2162bdb9230aSGarrett D'Amore if (realloc) {
2163bdb9230aSGarrett D'Amore nrecv_desc_old = dnetp->nrecv_desc;
216498e8d175SSteven Stallion dnet_free_bufs(dnetp); /* free the old buffers */
2165bdb9230aSGarrett D'Amore }
2166bdb9230aSGarrett D'Amore
2167bdb9230aSGarrett D'Amore if (dnetp->dma_handle == NULL)
2168bdb9230aSGarrett D'Amore if (ddi_dma_alloc_handle(dnetp->devinfo, &dma_attr,
2169bdb9230aSGarrett D'Amore DDI_DMA_SLEEP, 0, &dnetp->dma_handle) != DDI_SUCCESS)
2170bdb9230aSGarrett D'Amore return (FAILURE);
2171bdb9230aSGarrett D'Amore
2172bdb9230aSGarrett D'Amore if (dnetp->dma_handle_tx == NULL)
2173bdb9230aSGarrett D'Amore if (ddi_dma_alloc_handle(dnetp->devinfo, &dma_attr_tx,
2174bdb9230aSGarrett D'Amore DDI_DMA_SLEEP, 0, &dnetp->dma_handle_tx) != DDI_SUCCESS)
2175bdb9230aSGarrett D'Amore return (FAILURE);
2176bdb9230aSGarrett D'Amore
2177bdb9230aSGarrett D'Amore if (dnetp->dma_handle_txdesc == NULL)
2178bdb9230aSGarrett D'Amore if (ddi_dma_alloc_handle(dnetp->devinfo, &dma_attr,
2179bdb9230aSGarrett D'Amore DDI_DMA_SLEEP, 0, &dnetp->dma_handle_txdesc) != DDI_SUCCESS)
2180bdb9230aSGarrett D'Amore return (FAILURE);
2181bdb9230aSGarrett D'Amore
2182bdb9230aSGarrett D'Amore if (dnetp->dma_handle_setbuf == NULL)
2183bdb9230aSGarrett D'Amore if (ddi_dma_alloc_handle(dnetp->devinfo, &dma_attr,
2184bdb9230aSGarrett D'Amore DDI_DMA_SLEEP, 0, &dnetp->dma_handle_setbuf) != DDI_SUCCESS)
2185bdb9230aSGarrett D'Amore return (FAILURE);
2186bdb9230aSGarrett D'Amore
2187bdb9230aSGarrett D'Amore page_size = ddi_ptob(dnetp->devinfo, 1);
2188bdb9230aSGarrett D'Amore
2189bdb9230aSGarrett D'Amore dnetp->pgmask = page_size - 1;
2190bdb9230aSGarrett D'Amore
2191bdb9230aSGarrett D'Amore /* allocate setup buffer if necessary */
2192bdb9230aSGarrett D'Amore if (dnetp->setup_buf_vaddr == NULL) {
2193bdb9230aSGarrett D'Amore if (ddi_dma_mem_alloc(dnetp->dma_handle_setbuf,
2194bdb9230aSGarrett D'Amore SETUPBUF_SIZE, &accattr, DDI_DMA_STREAMING,
2195bdb9230aSGarrett D'Amore DDI_DMA_DONTWAIT, 0, (caddr_t *)&dnetp->setup_buf_vaddr,
2196bdb9230aSGarrett D'Amore &len, &dnetp->setup_buf_acchdl) != DDI_SUCCESS)
2197bdb9230aSGarrett D'Amore return (FAILURE);
2198bdb9230aSGarrett D'Amore
2199bdb9230aSGarrett D'Amore if (ddi_dma_addr_bind_handle(dnetp->dma_handle_setbuf,
2200bdb9230aSGarrett D'Amore NULL, dnetp->setup_buf_vaddr, SETUPBUF_SIZE,
2201bdb9230aSGarrett D'Amore DDI_DMA_RDWR | DDI_DMA_STREAMING, DDI_DMA_SLEEP,
2202bdb9230aSGarrett D'Amore NULL, &cookie, &ncookies) != DDI_DMA_MAPPED)
2203bdb9230aSGarrett D'Amore return (FAILURE);
2204bdb9230aSGarrett D'Amore
2205bdb9230aSGarrett D'Amore dnetp->setup_buf_paddr = cookie.dmac_address;
2206bdb9230aSGarrett D'Amore bzero(dnetp->setup_buf_vaddr, len);
2207bdb9230aSGarrett D'Amore }
2208bdb9230aSGarrett D'Amore
2209bdb9230aSGarrett D'Amore /* allocate xmit descriptor array of size dnetp->max_tx_desc */
2210bdb9230aSGarrett D'Amore if (dnetp->tx_desc == NULL) {
2211bdb9230aSGarrett D'Amore if (ddi_dma_mem_alloc(dnetp->dma_handle_txdesc,
2212bdb9230aSGarrett D'Amore sizeof (struct tx_desc_type) * dnetp->max_tx_desc,
2213bdb9230aSGarrett D'Amore &accattr, DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 0,
2214bdb9230aSGarrett D'Amore (caddr_t *)&dnetp->tx_desc, &len,
2215bdb9230aSGarrett D'Amore &dnetp->tx_desc_acchdl) != DDI_SUCCESS)
2216bdb9230aSGarrett D'Amore return (FAILURE);
2217bdb9230aSGarrett D'Amore
2218bdb9230aSGarrett D'Amore if (ddi_dma_addr_bind_handle(dnetp->dma_handle_txdesc,
2219bdb9230aSGarrett D'Amore NULL, (caddr_t)dnetp->tx_desc,
2220bdb9230aSGarrett D'Amore sizeof (struct tx_desc_type) * dnetp->max_tx_desc,
2221bdb9230aSGarrett D'Amore DDI_DMA_RDWR | DDI_DMA_STREAMING, DDI_DMA_SLEEP,
2222bdb9230aSGarrett D'Amore NULL, &cookie, &ncookies) != DDI_DMA_MAPPED)
2223bdb9230aSGarrett D'Amore return (FAILURE);
2224bdb9230aSGarrett D'Amore dnetp->tx_desc_paddr = cookie.dmac_address;
2225bdb9230aSGarrett D'Amore bzero(dnetp->tx_desc, len);
2226bdb9230aSGarrett D'Amore dnetp->nxmit_desc = dnetp->max_tx_desc;
2227bdb9230aSGarrett D'Amore
2228bdb9230aSGarrett D'Amore dnetp->tx_msgbufp =
2229bdb9230aSGarrett D'Amore kmem_zalloc(dnetp->max_tx_desc * sizeof (mblk_t **),
2230bdb9230aSGarrett D'Amore KM_SLEEP);
2231bdb9230aSGarrett D'Amore }
2232bdb9230aSGarrett D'Amore
2233bdb9230aSGarrett D'Amore /* allocate receive descriptor array of size dnetp->max_rx_desc */
2234bdb9230aSGarrett D'Amore if (dnetp->rx_desc == NULL) {
2235bdb9230aSGarrett D'Amore int ndesc;
2236bdb9230aSGarrett D'Amore
2237bdb9230aSGarrett D'Amore if (ddi_dma_mem_alloc(dnetp->dma_handle,
2238bdb9230aSGarrett D'Amore sizeof (struct rx_desc_type) * dnetp->max_rx_desc,
2239bdb9230aSGarrett D'Amore &accattr, DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 0,
2240bdb9230aSGarrett D'Amore (caddr_t *)&dnetp->rx_desc, &len,
2241bdb9230aSGarrett D'Amore &dnetp->rx_desc_acchdl) != DDI_SUCCESS)
2242bdb9230aSGarrett D'Amore return (FAILURE);
2243bdb9230aSGarrett D'Amore
2244bdb9230aSGarrett D'Amore if (ddi_dma_addr_bind_handle(dnetp->dma_handle,
2245bdb9230aSGarrett D'Amore NULL, (caddr_t)dnetp->rx_desc,
2246bdb9230aSGarrett D'Amore sizeof (struct rx_desc_type) * dnetp->max_rx_desc,
2247bdb9230aSGarrett D'Amore DDI_DMA_RDWR | DDI_DMA_STREAMING, DDI_DMA_SLEEP,
2248bdb9230aSGarrett D'Amore NULL, &cookie, &ncookies) != DDI_DMA_MAPPED)
2249bdb9230aSGarrett D'Amore return (FAILURE);
2250bdb9230aSGarrett D'Amore
2251bdb9230aSGarrett D'Amore dnetp->rx_desc_paddr = cookie.dmac_address;
2252bdb9230aSGarrett D'Amore bzero(dnetp->rx_desc, len);
2253bdb9230aSGarrett D'Amore dnetp->nrecv_desc = dnetp->max_rx_desc;
2254bdb9230aSGarrett D'Amore
2255bdb9230aSGarrett D'Amore dnetp->rx_buf_vaddr =
2256bdb9230aSGarrett D'Amore kmem_zalloc(dnetp->max_rx_desc * sizeof (caddr_t),
2257bdb9230aSGarrett D'Amore KM_SLEEP);
2258bdb9230aSGarrett D'Amore dnetp->rx_buf_paddr =
2259bdb9230aSGarrett D'Amore kmem_zalloc(dnetp->max_rx_desc * sizeof (uint32_t),
2260bdb9230aSGarrett D'Amore KM_SLEEP);
2261bdb9230aSGarrett D'Amore /*
2262bdb9230aSGarrett D'Amore * Allocate or add to the pool of receive buffers. The pool
2263bdb9230aSGarrett D'Amore * is shared among all instances of dnet.
2264bdb9230aSGarrett D'Amore *
2265bdb9230aSGarrett D'Amore * XXX NEEDSWORK
2266bdb9230aSGarrett D'Amore *
2267bdb9230aSGarrett D'Amore * We arbitrarily allocate twice as many receive buffers as
2268bdb9230aSGarrett D'Amore * receive descriptors because we use the buffers for streams
2269bdb9230aSGarrett D'Amore * messages to pass the packets up the stream. We should
2270bdb9230aSGarrett D'Amore * instead have initialized constants reflecting
2271bdb9230aSGarrett D'Amore * MAX_RX_BUF_2104x and MAX_RX_BUF_2114x, and we should also
2272bdb9230aSGarrett D'Amore * probably have a total maximum for the free pool, so that we
2273bdb9230aSGarrett D'Amore * don't get out of hand when someone puts in an 8-port board.
2274bdb9230aSGarrett D'Amore * The maximum for the entire pool should be the total number
2275bdb9230aSGarrett D'Amore * of descriptors for all attached instances together, plus the
2276bdb9230aSGarrett D'Amore * total maximum for the free pool. This maximum would only be
2277bdb9230aSGarrett D'Amore * reached after some number of instances allocate buffers:
2278bdb9230aSGarrett D'Amore * each instance would add (max_rx_buf-max_rx_desc) to the free
2279bdb9230aSGarrett D'Amore * pool.
2280bdb9230aSGarrett D'Amore */
2281bdb9230aSGarrett D'Amore ndesc = dnetp->max_rx_desc - nrecv_desc_old;
2282bdb9230aSGarrett D'Amore if ((ndesc > 0) &&
2283bdb9230aSGarrett D'Amore (dnet_rbuf_init(dnetp->devinfo, ndesc * 2) != 0))
2284bdb9230aSGarrett D'Amore return (FAILURE);
2285bdb9230aSGarrett D'Amore
2286bdb9230aSGarrett D'Amore for (i = 0; i < dnetp->max_rx_desc; i++) {
2287bdb9230aSGarrett D'Amore struct rbuf_list *rp;
2288bdb9230aSGarrett D'Amore
2289bdb9230aSGarrett D'Amore rp = dnet_rbuf_alloc(dnetp->devinfo, 1);
2290bdb9230aSGarrett D'Amore if (rp == NULL)
2291bdb9230aSGarrett D'Amore return (FAILURE);
2292bdb9230aSGarrett D'Amore dnetp->rx_buf_vaddr[i] = rp->rbuf_vaddr;
2293bdb9230aSGarrett D'Amore dnetp->rx_buf_paddr[i] = rp->rbuf_paddr;
2294bdb9230aSGarrett D'Amore }
2295bdb9230aSGarrett D'Amore }
2296bdb9230aSGarrett D'Amore
2297bdb9230aSGarrett D'Amore return (SUCCESS);
2298bdb9230aSGarrett D'Amore }
2299bdb9230aSGarrett D'Amore /*
2300bdb9230aSGarrett D'Amore * free descriptors/buffers allocated for this device instance. This routine
2301bdb9230aSGarrett D'Amore * should only be called while the device is reset.
2302bdb9230aSGarrett D'Amore */
2303bdb9230aSGarrett D'Amore static void
dnet_free_bufs(struct dnetinstance * dnetp)230498e8d175SSteven Stallion dnet_free_bufs(struct dnetinstance *dnetp)
2305bdb9230aSGarrett D'Amore {
2306bdb9230aSGarrett D'Amore int i;
2307bdb9230aSGarrett D'Amore /* free up any xmit descriptors/buffers */
2308bdb9230aSGarrett D'Amore if (dnetp->tx_desc != NULL) {
2309bdb9230aSGarrett D'Amore ddi_dma_mem_free(&dnetp->tx_desc_acchdl);
2310bdb9230aSGarrett D'Amore dnetp->tx_desc = NULL;
2311bdb9230aSGarrett D'Amore /* we use streams buffers for DMA in xmit process */
2312bdb9230aSGarrett D'Amore if (dnetp->tx_msgbufp != NULL) {
2313bdb9230aSGarrett D'Amore /* free up any streams message buffers unclaimed */
2314bdb9230aSGarrett D'Amore for (i = 0; i < dnetp->nxmit_desc; i++) {
2315bdb9230aSGarrett D'Amore if (dnetp->tx_msgbufp[i] != NULL) {
2316bdb9230aSGarrett D'Amore freemsg(dnetp->tx_msgbufp[i]);
2317bdb9230aSGarrett D'Amore }
2318bdb9230aSGarrett D'Amore }
2319bdb9230aSGarrett D'Amore kmem_free(dnetp->tx_msgbufp,
2320bdb9230aSGarrett D'Amore dnetp->nxmit_desc * sizeof (mblk_t **));
2321bdb9230aSGarrett D'Amore dnetp->tx_msgbufp = NULL;
2322bdb9230aSGarrett D'Amore }
2323bdb9230aSGarrett D'Amore dnetp->nxmit_desc = 0;
2324bdb9230aSGarrett D'Amore }
2325bdb9230aSGarrett D'Amore
2326bdb9230aSGarrett D'Amore /* free up any receive descriptors/buffers */
2327bdb9230aSGarrett D'Amore if (dnetp->rx_desc != NULL) {
2328bdb9230aSGarrett D'Amore ddi_dma_mem_free(&dnetp->rx_desc_acchdl);
2329bdb9230aSGarrett D'Amore dnetp->rx_desc = NULL;
2330bdb9230aSGarrett D'Amore if (dnetp->rx_buf_vaddr != NULL) {
2331bdb9230aSGarrett D'Amore /* free up the attached rbufs if any */
2332bdb9230aSGarrett D'Amore for (i = 0; i < dnetp->nrecv_desc; i++) {
2333bdb9230aSGarrett D'Amore if (dnetp->rx_buf_vaddr[i])
2334bdb9230aSGarrett D'Amore dnet_rbuf_free(
2335bdb9230aSGarrett D'Amore (caddr_t)dnetp->rx_buf_vaddr[i]);
2336bdb9230aSGarrett D'Amore }
2337bdb9230aSGarrett D'Amore kmem_free(dnetp->rx_buf_vaddr,
2338bdb9230aSGarrett D'Amore dnetp->nrecv_desc * sizeof (caddr_t));
2339bdb9230aSGarrett D'Amore kmem_free(dnetp->rx_buf_paddr,
2340bdb9230aSGarrett D'Amore dnetp->nrecv_desc * sizeof (uint32_t));
2341bdb9230aSGarrett D'Amore dnetp->rx_buf_vaddr = NULL;
2342bdb9230aSGarrett D'Amore dnetp->rx_buf_paddr = NULL;
2343bdb9230aSGarrett D'Amore }
2344bdb9230aSGarrett D'Amore dnetp->nrecv_desc = 0;
2345bdb9230aSGarrett D'Amore }
2346bdb9230aSGarrett D'Amore
2347bdb9230aSGarrett D'Amore if (dnetp->setup_buf_vaddr != NULL) {
2348bdb9230aSGarrett D'Amore ddi_dma_mem_free(&dnetp->setup_buf_acchdl);
2349bdb9230aSGarrett D'Amore dnetp->setup_buf_vaddr = NULL;
2350bdb9230aSGarrett D'Amore }
2351bdb9230aSGarrett D'Amore
2352bdb9230aSGarrett D'Amore if (dnetp->dma_handle != NULL) {
2353bdb9230aSGarrett D'Amore (void) ddi_dma_unbind_handle(dnetp->dma_handle);
2354bdb9230aSGarrett D'Amore ddi_dma_free_handle(&dnetp->dma_handle);
2355bdb9230aSGarrett D'Amore dnetp->dma_handle = NULL;
2356bdb9230aSGarrett D'Amore }
2357bdb9230aSGarrett D'Amore
2358bdb9230aSGarrett D'Amore if (dnetp->dma_handle_tx != NULL) {
2359bdb9230aSGarrett D'Amore (void) ddi_dma_unbind_handle(dnetp->dma_handle_tx);
2360bdb9230aSGarrett D'Amore ddi_dma_free_handle(&dnetp->dma_handle_tx);
2361bdb9230aSGarrett D'Amore dnetp->dma_handle_tx = NULL;
2362bdb9230aSGarrett D'Amore }
2363bdb9230aSGarrett D'Amore
2364bdb9230aSGarrett D'Amore if (dnetp->dma_handle_txdesc != NULL) {
2365bdb9230aSGarrett D'Amore (void) ddi_dma_unbind_handle(dnetp->dma_handle_txdesc);
2366bdb9230aSGarrett D'Amore ddi_dma_free_handle(&dnetp->dma_handle_txdesc);
2367bdb9230aSGarrett D'Amore dnetp->dma_handle_txdesc = NULL;
2368bdb9230aSGarrett D'Amore }
2369bdb9230aSGarrett D'Amore
2370bdb9230aSGarrett D'Amore if (dnetp->dma_handle_setbuf != NULL) {
2371bdb9230aSGarrett D'Amore (void) ddi_dma_unbind_handle(dnetp->dma_handle_setbuf);
2372bdb9230aSGarrett D'Amore ddi_dma_free_handle(&dnetp->dma_handle_setbuf);
2373bdb9230aSGarrett D'Amore dnetp->dma_handle_setbuf = NULL;
2374bdb9230aSGarrett D'Amore }
2375bdb9230aSGarrett D'Amore
2376bdb9230aSGarrett D'Amore }
2377bdb9230aSGarrett D'Amore
2378bdb9230aSGarrett D'Amore /*
2379bdb9230aSGarrett D'Amore * Initialize transmit and receive descriptors.
2380bdb9230aSGarrett D'Amore */
2381bdb9230aSGarrett D'Amore static void
dnet_init_txrx_bufs(struct dnetinstance * dnetp)238298e8d175SSteven Stallion dnet_init_txrx_bufs(struct dnetinstance *dnetp)
2383bdb9230aSGarrett D'Amore {
2384bdb9230aSGarrett D'Amore int i;
2385bdb9230aSGarrett D'Amore
2386bdb9230aSGarrett D'Amore /*
2387bdb9230aSGarrett D'Amore * Initilize all the Tx descriptors
2388bdb9230aSGarrett D'Amore */
2389bdb9230aSGarrett D'Amore for (i = 0; i < dnetp->nxmit_desc; i++) {
2390bdb9230aSGarrett D'Amore /*
2391bdb9230aSGarrett D'Amore * We may be resetting the device due to errors,
2392bdb9230aSGarrett D'Amore * so free up any streams message buffer unclaimed.
2393bdb9230aSGarrett D'Amore */
2394bdb9230aSGarrett D'Amore if (dnetp->tx_msgbufp[i] != NULL) {
2395bdb9230aSGarrett D'Amore freemsg(dnetp->tx_msgbufp[i]);
2396bdb9230aSGarrett D'Amore dnetp->tx_msgbufp[i] = NULL;
2397bdb9230aSGarrett D'Amore }
2398bdb9230aSGarrett D'Amore *(uint32_t *)&dnetp->tx_desc[i].desc0 = 0;
2399bdb9230aSGarrett D'Amore *(uint32_t *)&dnetp->tx_desc[i].desc1 = 0;
2400bdb9230aSGarrett D'Amore dnetp->tx_desc[i].buffer1 = 0;
2401bdb9230aSGarrett D'Amore dnetp->tx_desc[i].buffer2 = 0;
2402bdb9230aSGarrett D'Amore }
2403bdb9230aSGarrett D'Amore dnetp->tx_desc[i - 1].desc1.end_of_ring = 1;
2404bdb9230aSGarrett D'Amore
2405bdb9230aSGarrett D'Amore /*
2406bdb9230aSGarrett D'Amore * Initialize the Rx descriptors
2407bdb9230aSGarrett D'Amore */
2408bdb9230aSGarrett D'Amore for (i = 0; i < dnetp->nrecv_desc; i++) {
2409bdb9230aSGarrett D'Amore uint32_t end_paddr;
2410bdb9230aSGarrett D'Amore *(uint32_t *)&dnetp->rx_desc[i].desc0 = 0;
2411bdb9230aSGarrett D'Amore *(uint32_t *)&dnetp->rx_desc[i].desc1 = 0;
2412bdb9230aSGarrett D'Amore dnetp->rx_desc[i].desc0.own = 1;
2413bdb9230aSGarrett D'Amore dnetp->rx_desc[i].desc1.buffer_size1 = rx_buf_size;
2414bdb9230aSGarrett D'Amore dnetp->rx_desc[i].buffer1 = dnetp->rx_buf_paddr[i];
2415bdb9230aSGarrett D'Amore dnetp->rx_desc[i].buffer2 = 0;
2416bdb9230aSGarrett D'Amore end_paddr = dnetp->rx_buf_paddr[i]+rx_buf_size-1;
2417bdb9230aSGarrett D'Amore
2418bdb9230aSGarrett D'Amore if ((dnetp->rx_desc[i].buffer1 & ~dnetp->pgmask) !=
2419bdb9230aSGarrett D'Amore (end_paddr & ~dnetp->pgmask)) {
2420bdb9230aSGarrett D'Amore /* discontiguous */
2421bdb9230aSGarrett D'Amore dnetp->rx_desc[i].buffer2 = end_paddr&~dnetp->pgmask;
2422bdb9230aSGarrett D'Amore dnetp->rx_desc[i].desc1.buffer_size2 =
2423bdb9230aSGarrett D'Amore (end_paddr & dnetp->pgmask) + 1;
2424bdb9230aSGarrett D'Amore dnetp->rx_desc[i].desc1.buffer_size1 =
2425bdb9230aSGarrett D'Amore rx_buf_size-dnetp->rx_desc[i].desc1.buffer_size2;
2426bdb9230aSGarrett D'Amore }
2427bdb9230aSGarrett D'Amore }
2428bdb9230aSGarrett D'Amore dnetp->rx_desc[i - 1].desc1.end_of_ring = 1;
2429bdb9230aSGarrett D'Amore }
2430bdb9230aSGarrett D'Amore
2431bdb9230aSGarrett D'Amore static int
alloc_descriptor(struct dnetinstance * dnetp)243298e8d175SSteven Stallion alloc_descriptor(struct dnetinstance *dnetp)
2433bdb9230aSGarrett D'Amore {
2434bdb9230aSGarrett D'Amore int index;
2435bdb9230aSGarrett D'Amore struct tx_desc_type *ring = dnetp->tx_desc;
2436bdb9230aSGarrett D'Amore
2437bdb9230aSGarrett D'Amore ASSERT(MUTEX_HELD(&dnetp->intrlock));
2438bdb9230aSGarrett D'Amore alloctop:
2439bdb9230aSGarrett D'Amore mutex_enter(&dnetp->txlock);
2440bdb9230aSGarrett D'Amore index = dnetp->tx_current_desc;
2441bdb9230aSGarrett D'Amore
244298e8d175SSteven Stallion dnet_reclaim_Tx_desc(dnetp);
2443bdb9230aSGarrett D'Amore
2444bdb9230aSGarrett D'Amore /* we do have free descriptors, right? */
2445bdb9230aSGarrett D'Amore if (dnetp->free_desc <= 0) {
2446bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
2447bdb9230aSGarrett D'Amore if (dnetdebug & DNETRECV)
2448bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "dnet: Ring buffer is full");
2449bdb9230aSGarrett D'Amore #endif
2450bdb9230aSGarrett D'Amore mutex_exit(&dnetp->txlock);
2451bdb9230aSGarrett D'Amore return (FAILURE);
2452bdb9230aSGarrett D'Amore }
2453bdb9230aSGarrett D'Amore
2454bdb9230aSGarrett D'Amore /* sanity, make sure the next descriptor is free for use (should be) */
2455bdb9230aSGarrett D'Amore if (ring[index].desc0.own) {
2456bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
2457bdb9230aSGarrett D'Amore if (dnetdebug & DNETRECV)
2458bdb9230aSGarrett D'Amore cmn_err(CE_WARN,
2459bdb9230aSGarrett D'Amore "dnet: next descriptor is not free for use");
2460bdb9230aSGarrett D'Amore #endif
2461bdb9230aSGarrett D'Amore mutex_exit(&dnetp->txlock);
2462bdb9230aSGarrett D'Amore return (FAILURE);
2463bdb9230aSGarrett D'Amore }
2464bdb9230aSGarrett D'Amore if (dnetp->need_saddr) {
2465bdb9230aSGarrett D'Amore mutex_exit(&dnetp->txlock);
2466bdb9230aSGarrett D'Amore /* XXX function return value ignored */
2467bdb9230aSGarrett D'Amore if (!dnetp->suspended)
246898e8d175SSteven Stallion (void) dnet_set_addr(dnetp);
2469bdb9230aSGarrett D'Amore goto alloctop;
2470bdb9230aSGarrett D'Amore }
2471bdb9230aSGarrett D'Amore
2472bdb9230aSGarrett D'Amore *(uint32_t *)&ring[index].desc0 = 0; /* init descs */
2473bdb9230aSGarrett D'Amore *(uint32_t *)&ring[index].desc1 &= DNET_END_OF_RING;
2474bdb9230aSGarrett D'Amore
2475bdb9230aSGarrett D'Amore /* hardware will own this descriptor when poll activated */
2476bdb9230aSGarrett D'Amore dnetp->free_desc--;
2477bdb9230aSGarrett D'Amore
2478bdb9230aSGarrett D'Amore /* point to next free descriptor to be used */
2479bdb9230aSGarrett D'Amore dnetp->tx_current_desc = NextTXIndex(index);
2480bdb9230aSGarrett D'Amore
2481bdb9230aSGarrett D'Amore #ifdef DNET_NOISY
2482bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "sfree 0x%x, transmitted 0x%x, tx_current 0x%x",
2483bdb9230aSGarrett D'Amore dnetp->free_desc, dnetp->transmitted_desc, dnetp->tx_current_desc);
2484bdb9230aSGarrett D'Amore #endif
2485bdb9230aSGarrett D'Amore mutex_exit(&dnetp->txlock);
2486bdb9230aSGarrett D'Amore return (SUCCESS);
2487bdb9230aSGarrett D'Amore }
2488bdb9230aSGarrett D'Amore
2489bdb9230aSGarrett D'Amore /*
2490bdb9230aSGarrett D'Amore * dnet_reclaim_Tx_desc() - called with txlock held.
2491bdb9230aSGarrett D'Amore */
2492bdb9230aSGarrett D'Amore static void
dnet_reclaim_Tx_desc(struct dnetinstance * dnetp)249398e8d175SSteven Stallion dnet_reclaim_Tx_desc(struct dnetinstance *dnetp)
2494bdb9230aSGarrett D'Amore {
2495bdb9230aSGarrett D'Amore struct tx_desc_type *desc = dnetp->tx_desc;
2496bdb9230aSGarrett D'Amore int index;
2497bdb9230aSGarrett D'Amore
2498bdb9230aSGarrett D'Amore ASSERT(MUTEX_HELD(&dnetp->txlock));
2499bdb9230aSGarrett D'Amore
2500bdb9230aSGarrett D'Amore index = dnetp->transmitted_desc;
2501bdb9230aSGarrett D'Amore while (((dnetp->free_desc == 0) || (index != dnetp->tx_current_desc)) &&
2502bdb9230aSGarrett D'Amore !(desc[index].desc0.own)) {
2503bdb9230aSGarrett D'Amore /*
2504bdb9230aSGarrett D'Amore * Check for Tx Error that gets set
2505bdb9230aSGarrett D'Amore * in the last desc.
2506bdb9230aSGarrett D'Amore */
2507bdb9230aSGarrett D'Amore if (desc[index].desc1.setup_packet == 0 &&
2508bdb9230aSGarrett D'Amore desc[index].desc1.last_desc &&
2509bdb9230aSGarrett D'Amore desc[index].desc0.err_summary)
251098e8d175SSteven Stallion update_tx_stats(dnetp, index);
2511bdb9230aSGarrett D'Amore
2512bdb9230aSGarrett D'Amore /*
2513bdb9230aSGarrett D'Amore * If we have used the streams message buffer for this
2514bdb9230aSGarrett D'Amore * descriptor then free up the message now.
2515bdb9230aSGarrett D'Amore */
2516bdb9230aSGarrett D'Amore if (dnetp->tx_msgbufp[index] != NULL) {
2517bdb9230aSGarrett D'Amore freemsg(dnetp->tx_msgbufp[index]);
2518bdb9230aSGarrett D'Amore dnetp->tx_msgbufp[index] = NULL;
2519bdb9230aSGarrett D'Amore }
2520bdb9230aSGarrett D'Amore dnetp->free_desc++;
2521bdb9230aSGarrett D'Amore index = (index+1) % dnetp->max_tx_desc;
2522bdb9230aSGarrett D'Amore }
2523bdb9230aSGarrett D'Amore
2524bdb9230aSGarrett D'Amore dnetp->transmitted_desc = index;
2525bdb9230aSGarrett D'Amore }
2526bdb9230aSGarrett D'Amore
2527bdb9230aSGarrett D'Amore /*
2528bdb9230aSGarrett D'Amore * Receive buffer allocation/freeing routines.
2529bdb9230aSGarrett D'Amore *
2530bdb9230aSGarrett D'Amore * There is a common pool of receive buffers shared by all dnet instances.
2531bdb9230aSGarrett D'Amore *
2532bdb9230aSGarrett D'Amore * XXX NEEDSWORK
2533bdb9230aSGarrett D'Amore *
2534bdb9230aSGarrett D'Amore * We arbitrarily allocate twice as many receive buffers as
2535bdb9230aSGarrett D'Amore * receive descriptors because we use the buffers for streams
2536bdb9230aSGarrett D'Amore * messages to pass the packets up the stream. We should
2537bdb9230aSGarrett D'Amore * instead have initialized constants reflecting
2538bdb9230aSGarrett D'Amore * MAX_RX_BUF_2104x and MAX_RX_BUF_2114x, and we should also
2539bdb9230aSGarrett D'Amore * probably have a total maximum for the free pool, so that we
2540bdb9230aSGarrett D'Amore * don't get out of hand when someone puts in an 8-port board.
2541bdb9230aSGarrett D'Amore * The maximum for the entire pool should be the total number
2542bdb9230aSGarrett D'Amore * of descriptors for all attached instances together, plus the
2543bdb9230aSGarrett D'Amore * total maximum for the free pool. This maximum would only be
2544bdb9230aSGarrett D'Amore * reached after some number of instances allocate buffers:
2545bdb9230aSGarrett D'Amore * each instance would add (max_rx_buf-max_rx_desc) to the free
2546bdb9230aSGarrett D'Amore * pool.
2547bdb9230aSGarrett D'Amore */
2548bdb9230aSGarrett D'Amore
2549bdb9230aSGarrett D'Amore static struct rbuf_list *rbuf_usedlist_head;
2550bdb9230aSGarrett D'Amore static struct rbuf_list *rbuf_freelist_head;
2551bdb9230aSGarrett D'Amore static struct rbuf_list *rbuf_usedlist_end; /* last buffer allocated */
2552bdb9230aSGarrett D'Amore
2553bdb9230aSGarrett D'Amore static int rbuf_freebufs; /* no. of free buffers in the pool */
2554bdb9230aSGarrett D'Amore static int rbuf_pool_size; /* total no. of buffers in the pool */
2555bdb9230aSGarrett D'Amore
2556bdb9230aSGarrett D'Amore /* initialize/add 'nbufs' buffers to the rbuf pool */
2557bdb9230aSGarrett D'Amore /* ARGSUSED */
2558bdb9230aSGarrett D'Amore static int
dnet_rbuf_init(dev_info_t * dip,int nbufs)2559bdb9230aSGarrett D'Amore dnet_rbuf_init(dev_info_t *dip, int nbufs)
2560bdb9230aSGarrett D'Amore {
2561bdb9230aSGarrett D'Amore int i;
2562bdb9230aSGarrett D'Amore struct rbuf_list *rp;
2563bdb9230aSGarrett D'Amore ddi_dma_cookie_t cookie;
2564bdb9230aSGarrett D'Amore uint_t ncookies;
2565bdb9230aSGarrett D'Amore size_t len;
2566bdb9230aSGarrett D'Amore
2567bdb9230aSGarrett D'Amore mutex_enter(&dnet_rbuf_lock);
2568bdb9230aSGarrett D'Amore
2569bdb9230aSGarrett D'Amore /* allocate buffers and add them to the pool */
2570bdb9230aSGarrett D'Amore for (i = 0; i < nbufs; i++) {
2571bdb9230aSGarrett D'Amore /* allocate rbuf_list element */
2572bdb9230aSGarrett D'Amore rp = kmem_zalloc(sizeof (struct rbuf_list), KM_SLEEP);
2573bdb9230aSGarrett D'Amore if (ddi_dma_alloc_handle(dip, &dma_attr_rb, DDI_DMA_SLEEP,
2574bdb9230aSGarrett D'Amore 0, &rp->rbuf_dmahdl) != DDI_SUCCESS)
2575bdb9230aSGarrett D'Amore goto fail_kfree;
2576bdb9230aSGarrett D'Amore
2577bdb9230aSGarrett D'Amore /* allocate dma memory for the buffer */
2578bdb9230aSGarrett D'Amore if (ddi_dma_mem_alloc(rp->rbuf_dmahdl, rx_buf_size, &accattr,
2579bdb9230aSGarrett D'Amore DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 0,
2580bdb9230aSGarrett D'Amore &rp->rbuf_vaddr, &len,
2581bdb9230aSGarrett D'Amore &rp->rbuf_acchdl) != DDI_SUCCESS)
2582bdb9230aSGarrett D'Amore goto fail_freehdl;
2583bdb9230aSGarrett D'Amore
2584bdb9230aSGarrett D'Amore if (ddi_dma_addr_bind_handle(rp->rbuf_dmahdl, NULL,
2585bdb9230aSGarrett D'Amore rp->rbuf_vaddr, len, DDI_DMA_RDWR | DDI_DMA_STREAMING,
2586bdb9230aSGarrett D'Amore DDI_DMA_SLEEP, NULL, &cookie,
2587bdb9230aSGarrett D'Amore &ncookies) != DDI_DMA_MAPPED)
2588bdb9230aSGarrett D'Amore goto fail_free;
2589bdb9230aSGarrett D'Amore
2590bdb9230aSGarrett D'Amore if (ncookies > 2)
2591bdb9230aSGarrett D'Amore goto fail_unbind;
2592bdb9230aSGarrett D'Amore if (ncookies == 1) {
2593bdb9230aSGarrett D'Amore rp->rbuf_endpaddr =
2594bdb9230aSGarrett D'Amore cookie.dmac_address + rx_buf_size - 1;
2595bdb9230aSGarrett D'Amore } else {
2596bdb9230aSGarrett D'Amore ddi_dma_nextcookie(rp->rbuf_dmahdl, &cookie);
2597bdb9230aSGarrett D'Amore rp->rbuf_endpaddr =
2598bdb9230aSGarrett D'Amore cookie.dmac_address + cookie.dmac_size - 1;
2599bdb9230aSGarrett D'Amore }
2600bdb9230aSGarrett D'Amore rp->rbuf_paddr = cookie.dmac_address;
2601bdb9230aSGarrett D'Amore
2602bdb9230aSGarrett D'Amore rp->rbuf_next = rbuf_freelist_head;
2603bdb9230aSGarrett D'Amore rbuf_freelist_head = rp;
2604bdb9230aSGarrett D'Amore rbuf_pool_size++;
2605bdb9230aSGarrett D'Amore rbuf_freebufs++;
2606bdb9230aSGarrett D'Amore }
2607bdb9230aSGarrett D'Amore
2608bdb9230aSGarrett D'Amore mutex_exit(&dnet_rbuf_lock);
2609bdb9230aSGarrett D'Amore return (0);
2610bdb9230aSGarrett D'Amore fail_unbind:
2611bdb9230aSGarrett D'Amore (void) ddi_dma_unbind_handle(rp->rbuf_dmahdl);
2612bdb9230aSGarrett D'Amore fail_free:
2613bdb9230aSGarrett D'Amore ddi_dma_mem_free(&rp->rbuf_acchdl);
2614bdb9230aSGarrett D'Amore fail_freehdl:
2615bdb9230aSGarrett D'Amore ddi_dma_free_handle(&rp->rbuf_dmahdl);
2616bdb9230aSGarrett D'Amore fail_kfree:
2617bdb9230aSGarrett D'Amore kmem_free(rp, sizeof (struct rbuf_list));
2618bdb9230aSGarrett D'Amore
2619bdb9230aSGarrett D'Amore mutex_exit(&dnet_rbuf_lock);
2620bdb9230aSGarrett D'Amore return (-1);
2621bdb9230aSGarrett D'Amore }
2622bdb9230aSGarrett D'Amore
2623bdb9230aSGarrett D'Amore /*
2624bdb9230aSGarrett D'Amore * Try to free up all the rbufs in the pool. Returns 0 if it frees up all
2625bdb9230aSGarrett D'Amore * buffers. The buffers in the used list are considered busy so these
2626bdb9230aSGarrett D'Amore * buffers are not freed.
2627bdb9230aSGarrett D'Amore */
2628bdb9230aSGarrett D'Amore static int
dnet_rbuf_destroy()2629bdb9230aSGarrett D'Amore dnet_rbuf_destroy()
2630bdb9230aSGarrett D'Amore {
2631bdb9230aSGarrett D'Amore struct rbuf_list *rp, *next;
2632bdb9230aSGarrett D'Amore
2633bdb9230aSGarrett D'Amore mutex_enter(&dnet_rbuf_lock);
2634bdb9230aSGarrett D'Amore
2635bdb9230aSGarrett D'Amore for (rp = rbuf_freelist_head; rp; rp = next) {
2636bdb9230aSGarrett D'Amore next = rp->rbuf_next;
2637bdb9230aSGarrett D'Amore ddi_dma_mem_free(&rp->rbuf_acchdl);
2638bdb9230aSGarrett D'Amore (void) ddi_dma_unbind_handle(rp->rbuf_dmahdl);
2639bdb9230aSGarrett D'Amore kmem_free(rp, sizeof (struct rbuf_list));
2640bdb9230aSGarrett D'Amore rbuf_pool_size--;
2641bdb9230aSGarrett D'Amore rbuf_freebufs--;
2642bdb9230aSGarrett D'Amore }
2643bdb9230aSGarrett D'Amore rbuf_freelist_head = NULL;
2644bdb9230aSGarrett D'Amore
2645bdb9230aSGarrett D'Amore if (rbuf_pool_size) { /* pool is still not empty */
2646bdb9230aSGarrett D'Amore mutex_exit(&dnet_rbuf_lock);
2647bdb9230aSGarrett D'Amore return (-1);
2648bdb9230aSGarrett D'Amore }
2649bdb9230aSGarrett D'Amore mutex_exit(&dnet_rbuf_lock);
2650bdb9230aSGarrett D'Amore return (0);
2651bdb9230aSGarrett D'Amore }
2652bdb9230aSGarrett D'Amore static struct rbuf_list *
dnet_rbuf_alloc(dev_info_t * dip,int cansleep)2653bdb9230aSGarrett D'Amore dnet_rbuf_alloc(dev_info_t *dip, int cansleep)
2654bdb9230aSGarrett D'Amore {
2655bdb9230aSGarrett D'Amore struct rbuf_list *rp;
2656bdb9230aSGarrett D'Amore size_t len;
2657bdb9230aSGarrett D'Amore ddi_dma_cookie_t cookie;
2658bdb9230aSGarrett D'Amore uint_t ncookies;
2659bdb9230aSGarrett D'Amore
2660bdb9230aSGarrett D'Amore mutex_enter(&dnet_rbuf_lock);
2661bdb9230aSGarrett D'Amore
2662bdb9230aSGarrett D'Amore if (rbuf_freelist_head == NULL) {
2663bdb9230aSGarrett D'Amore
2664bdb9230aSGarrett D'Amore if (!cansleep) {
2665bdb9230aSGarrett D'Amore mutex_exit(&dnet_rbuf_lock);
2666bdb9230aSGarrett D'Amore return (NULL);
2667bdb9230aSGarrett D'Amore }
2668bdb9230aSGarrett D'Amore
2669bdb9230aSGarrett D'Amore /* allocate rbuf_list element */
2670bdb9230aSGarrett D'Amore rp = kmem_zalloc(sizeof (struct rbuf_list), KM_SLEEP);
2671bdb9230aSGarrett D'Amore if (ddi_dma_alloc_handle(dip, &dma_attr_rb, DDI_DMA_SLEEP,
2672bdb9230aSGarrett D'Amore 0, &rp->rbuf_dmahdl) != DDI_SUCCESS)
2673bdb9230aSGarrett D'Amore goto fail_kfree;
2674bdb9230aSGarrett D'Amore
2675bdb9230aSGarrett D'Amore /* allocate dma memory for the buffer */
2676bdb9230aSGarrett D'Amore if (ddi_dma_mem_alloc(rp->rbuf_dmahdl, rx_buf_size, &accattr,
2677bdb9230aSGarrett D'Amore DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 0,
2678bdb9230aSGarrett D'Amore &rp->rbuf_vaddr, &len,
2679bdb9230aSGarrett D'Amore &rp->rbuf_acchdl) != DDI_SUCCESS)
2680bdb9230aSGarrett D'Amore goto fail_freehdl;
2681bdb9230aSGarrett D'Amore
2682bdb9230aSGarrett D'Amore if (ddi_dma_addr_bind_handle(rp->rbuf_dmahdl, NULL,
2683bdb9230aSGarrett D'Amore rp->rbuf_vaddr, len, DDI_DMA_RDWR | DDI_DMA_STREAMING,
2684bdb9230aSGarrett D'Amore DDI_DMA_SLEEP, NULL, &cookie,
2685bdb9230aSGarrett D'Amore &ncookies) != DDI_DMA_MAPPED)
2686bdb9230aSGarrett D'Amore goto fail_free;
2687bdb9230aSGarrett D'Amore
2688bdb9230aSGarrett D'Amore if (ncookies > 2)
2689bdb9230aSGarrett D'Amore goto fail_unbind;
2690bdb9230aSGarrett D'Amore if (ncookies == 1) {
2691bdb9230aSGarrett D'Amore rp->rbuf_endpaddr =
2692bdb9230aSGarrett D'Amore cookie.dmac_address + rx_buf_size - 1;
2693bdb9230aSGarrett D'Amore } else {
2694bdb9230aSGarrett D'Amore ddi_dma_nextcookie(rp->rbuf_dmahdl, &cookie);
2695bdb9230aSGarrett D'Amore rp->rbuf_endpaddr =
2696bdb9230aSGarrett D'Amore cookie.dmac_address + cookie.dmac_size - 1;
2697bdb9230aSGarrett D'Amore }
2698bdb9230aSGarrett D'Amore rp->rbuf_paddr = cookie.dmac_address;
2699bdb9230aSGarrett D'Amore
2700bdb9230aSGarrett D'Amore rbuf_freelist_head = rp;
2701bdb9230aSGarrett D'Amore rbuf_pool_size++;
2702bdb9230aSGarrett D'Amore rbuf_freebufs++;
2703bdb9230aSGarrett D'Amore }
2704bdb9230aSGarrett D'Amore
2705bdb9230aSGarrett D'Amore /* take the buffer from the head of the free list */
2706bdb9230aSGarrett D'Amore rp = rbuf_freelist_head;
2707bdb9230aSGarrett D'Amore rbuf_freelist_head = rbuf_freelist_head->rbuf_next;
2708bdb9230aSGarrett D'Amore
2709bdb9230aSGarrett D'Amore /* update the used list; put the entry at the end */
2710bdb9230aSGarrett D'Amore if (rbuf_usedlist_head == NULL)
2711bdb9230aSGarrett D'Amore rbuf_usedlist_head = rp;
2712bdb9230aSGarrett D'Amore else
2713bdb9230aSGarrett D'Amore rbuf_usedlist_end->rbuf_next = rp;
2714bdb9230aSGarrett D'Amore rp->rbuf_next = NULL;
2715bdb9230aSGarrett D'Amore rbuf_usedlist_end = rp;
2716bdb9230aSGarrett D'Amore rbuf_freebufs--;
2717bdb9230aSGarrett D'Amore
2718bdb9230aSGarrett D'Amore mutex_exit(&dnet_rbuf_lock);
2719bdb9230aSGarrett D'Amore
2720bdb9230aSGarrett D'Amore return (rp);
2721bdb9230aSGarrett D'Amore fail_unbind:
2722bdb9230aSGarrett D'Amore (void) ddi_dma_unbind_handle(rp->rbuf_dmahdl);
2723bdb9230aSGarrett D'Amore fail_free:
2724bdb9230aSGarrett D'Amore ddi_dma_mem_free(&rp->rbuf_acchdl);
2725bdb9230aSGarrett D'Amore fail_freehdl:
2726bdb9230aSGarrett D'Amore ddi_dma_free_handle(&rp->rbuf_dmahdl);
2727bdb9230aSGarrett D'Amore fail_kfree:
2728bdb9230aSGarrett D'Amore kmem_free(rp, sizeof (struct rbuf_list));
2729bdb9230aSGarrett D'Amore mutex_exit(&dnet_rbuf_lock);
2730bdb9230aSGarrett D'Amore return (NULL);
2731bdb9230aSGarrett D'Amore }
2732bdb9230aSGarrett D'Amore
2733bdb9230aSGarrett D'Amore static void
dnet_rbuf_free(caddr_t vaddr)2734bdb9230aSGarrett D'Amore dnet_rbuf_free(caddr_t vaddr)
2735bdb9230aSGarrett D'Amore {
2736bdb9230aSGarrett D'Amore struct rbuf_list *rp, *prev;
2737bdb9230aSGarrett D'Amore
2738bdb9230aSGarrett D'Amore ASSERT(vaddr != NULL);
2739bdb9230aSGarrett D'Amore ASSERT(rbuf_usedlist_head != NULL);
2740bdb9230aSGarrett D'Amore
2741bdb9230aSGarrett D'Amore mutex_enter(&dnet_rbuf_lock);
2742bdb9230aSGarrett D'Amore
2743bdb9230aSGarrett D'Amore /* find the entry in the used list */
2744bdb9230aSGarrett D'Amore for (prev = rp = rbuf_usedlist_head; rp; rp = rp->rbuf_next) {
2745bdb9230aSGarrett D'Amore if (rp->rbuf_vaddr == vaddr)
2746bdb9230aSGarrett D'Amore break;
2747bdb9230aSGarrett D'Amore prev = rp;
2748bdb9230aSGarrett D'Amore }
2749bdb9230aSGarrett D'Amore
2750bdb9230aSGarrett D'Amore if (rp == NULL) {
2751bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "DNET: rbuf_free: bad addr 0x%p",
2752bdb9230aSGarrett D'Amore (void *)vaddr);
2753bdb9230aSGarrett D'Amore mutex_exit(&dnet_rbuf_lock);
2754bdb9230aSGarrett D'Amore return;
2755bdb9230aSGarrett D'Amore }
2756bdb9230aSGarrett D'Amore
2757bdb9230aSGarrett D'Amore /* update the used list and put the buffer back in the free list */
2758bdb9230aSGarrett D'Amore if (rbuf_usedlist_head != rp) {
2759bdb9230aSGarrett D'Amore prev->rbuf_next = rp->rbuf_next;
2760bdb9230aSGarrett D'Amore if (rbuf_usedlist_end == rp)
2761bdb9230aSGarrett D'Amore rbuf_usedlist_end = prev;
2762bdb9230aSGarrett D'Amore } else {
2763bdb9230aSGarrett D'Amore rbuf_usedlist_head = rp->rbuf_next;
2764bdb9230aSGarrett D'Amore if (rbuf_usedlist_end == rp)
2765bdb9230aSGarrett D'Amore rbuf_usedlist_end = NULL;
2766bdb9230aSGarrett D'Amore }
2767bdb9230aSGarrett D'Amore rp->rbuf_next = rbuf_freelist_head;
2768bdb9230aSGarrett D'Amore rbuf_freelist_head = rp;
2769bdb9230aSGarrett D'Amore rbuf_freebufs++;
2770bdb9230aSGarrett D'Amore
2771bdb9230aSGarrett D'Amore mutex_exit(&dnet_rbuf_lock);
2772bdb9230aSGarrett D'Amore }
2773bdb9230aSGarrett D'Amore
2774bdb9230aSGarrett D'Amore /*
2775bdb9230aSGarrett D'Amore * Free the receive buffer used in a stream's message block allocated
2776bdb9230aSGarrett D'Amore * thru desballoc().
2777bdb9230aSGarrett D'Amore */
2778bdb9230aSGarrett D'Amore static void
dnet_freemsg_buf(struct free_ptr * frp)2779bdb9230aSGarrett D'Amore dnet_freemsg_buf(struct free_ptr *frp)
2780bdb9230aSGarrett D'Amore {
2781bdb9230aSGarrett D'Amore dnet_rbuf_free((caddr_t)frp->buf); /* buffer goes back to the pool */
2782bdb9230aSGarrett D'Amore kmem_free(frp, sizeof (*frp)); /* free up the free_rtn structure */
2783bdb9230aSGarrett D'Amore }
2784bdb9230aSGarrett D'Amore
2785bdb9230aSGarrett D'Amore /*
2786bdb9230aSGarrett D'Amore * ========== SROM Read Routines ==========
2787bdb9230aSGarrett D'Amore */
2788bdb9230aSGarrett D'Amore
2789bdb9230aSGarrett D'Amore /*
2790bdb9230aSGarrett D'Amore * The following code gets the SROM information, either by reading it
2791bdb9230aSGarrett D'Amore * from the device or, failing that, by reading a property.
2792bdb9230aSGarrett D'Amore */
2793bdb9230aSGarrett 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)2794bdb9230aSGarrett D'Amore dnet_read_srom(dev_info_t *devinfo, int board_type, ddi_acc_handle_t io_handle,
2795bdb9230aSGarrett D'Amore caddr_t io_reg, uchar_t *vi, int maxlen)
2796bdb9230aSGarrett D'Amore {
2797bdb9230aSGarrett D'Amore int all_ones, zerocheck, i;
2798bdb9230aSGarrett D'Amore
2799bdb9230aSGarrett D'Amore /*
2800bdb9230aSGarrett D'Amore * Load SROM into vendor_info
2801bdb9230aSGarrett D'Amore */
2802bdb9230aSGarrett D'Amore if (board_type == DEVICE_ID_21040)
2803bdb9230aSGarrett D'Amore dnet_read21040addr(devinfo, io_handle, io_reg, vi, &maxlen);
2804bdb9230aSGarrett D'Amore else
2805bdb9230aSGarrett D'Amore /* 21041/21140 serial rom */
2806bdb9230aSGarrett D'Amore dnet_read21140srom(io_handle, io_reg, vi, maxlen);
2807bdb9230aSGarrett D'Amore /*
2808bdb9230aSGarrett D'Amore * If the dumpsrom property is present in the conf file, print
2809bdb9230aSGarrett D'Amore * the contents of the SROM to the console
2810bdb9230aSGarrett D'Amore */
2811bdb9230aSGarrett D'Amore if (ddi_getprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
2812bdb9230aSGarrett D'Amore "dumpsrom", 0))
2813bdb9230aSGarrett D'Amore dnet_dumpbin("SROM", vi, 1, maxlen);
2814bdb9230aSGarrett D'Amore
2815bdb9230aSGarrett D'Amore for (zerocheck = i = 0, all_ones = 0xff; i < maxlen; i++) {
2816bdb9230aSGarrett D'Amore zerocheck |= vi[i];
2817bdb9230aSGarrett D'Amore all_ones &= vi[i];
2818bdb9230aSGarrett D'Amore }
2819bdb9230aSGarrett D'Amore if (zerocheck == 0 || all_ones == 0xff) {
2820bdb9230aSGarrett D'Amore return (get_alternative_srom_image(devinfo, vi, maxlen));
2821bdb9230aSGarrett D'Amore } else {
2822bdb9230aSGarrett D'Amore #ifdef BUG_4010796
2823bdb9230aSGarrett D'Amore set_alternative_srom_image(devinfo, vi, maxlen);
2824bdb9230aSGarrett D'Amore #endif
2825bdb9230aSGarrett D'Amore return (0); /* Primary */
2826bdb9230aSGarrett D'Amore }
2827bdb9230aSGarrett D'Amore }
2828bdb9230aSGarrett D'Amore
2829bdb9230aSGarrett D'Amore /*
2830bdb9230aSGarrett D'Amore * The function reads the ethernet address of the 21040 adapter
2831bdb9230aSGarrett D'Amore */
2832bdb9230aSGarrett 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)2833bdb9230aSGarrett D'Amore dnet_read21040addr(dev_info_t *dip, ddi_acc_handle_t io_handle, caddr_t io_reg,
2834bdb9230aSGarrett D'Amore uchar_t *addr, int *len)
2835bdb9230aSGarrett D'Amore {
2836bdb9230aSGarrett D'Amore uint32_t val;
2837bdb9230aSGarrett D'Amore int i;
2838bdb9230aSGarrett D'Amore
2839bdb9230aSGarrett D'Amore /* No point reading more than the ethernet address */
2840bdb9230aSGarrett D'Amore *len = ddi_getprop(DDI_DEV_T_ANY, dip,
2841bdb9230aSGarrett D'Amore DDI_PROP_DONTPASS, macoffset_propname, 0) + ETHERADDRL;
2842bdb9230aSGarrett D'Amore
2843bdb9230aSGarrett D'Amore /* Reset ROM pointer */
2844bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG), 0);
2845bdb9230aSGarrett D'Amore for (i = 0; i < *len; i++) {
2846bdb9230aSGarrett D'Amore do {
2847bdb9230aSGarrett D'Amore val = ddi_get32(io_handle,
2848bdb9230aSGarrett D'Amore REG32(io_reg, ETHER_ROM_REG));
2849bdb9230aSGarrett D'Amore } while (val & 0x80000000);
2850bdb9230aSGarrett D'Amore addr[i] = val & 0xFF;
2851bdb9230aSGarrett D'Amore }
2852bdb9230aSGarrett D'Amore }
2853bdb9230aSGarrett D'Amore
2854bdb9230aSGarrett D'Amore #define drv_nsecwait(x) drv_usecwait(((x)+999)/1000) /* XXX */
2855bdb9230aSGarrett D'Amore
2856bdb9230aSGarrett D'Amore /*
2857bdb9230aSGarrett D'Amore * The function reads the SROM of the 21140 adapter
2858bdb9230aSGarrett D'Amore */
2859bdb9230aSGarrett D'Amore static void
dnet_read21140srom(ddi_acc_handle_t io_handle,caddr_t io_reg,uchar_t * addr,int maxlen)2860bdb9230aSGarrett D'Amore dnet_read21140srom(ddi_acc_handle_t io_handle, caddr_t io_reg, uchar_t *addr,
2861bdb9230aSGarrett D'Amore int maxlen)
2862bdb9230aSGarrett D'Amore {
2863bdb9230aSGarrett D'Amore uint32_t i, j;
2864bdb9230aSGarrett D'Amore uint32_t dout;
2865bdb9230aSGarrett D'Amore uint16_t word;
2866bdb9230aSGarrett D'Amore uint8_t rom_addr;
2867bdb9230aSGarrett D'Amore uint8_t bit;
2868bdb9230aSGarrett D'Amore
2869bdb9230aSGarrett D'Amore
2870bdb9230aSGarrett D'Amore rom_addr = 0;
2871bdb9230aSGarrett D'Amore for (i = 0; i < maxlen; i += 2) {
2872bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2873bdb9230aSGarrett D'Amore READ_OP | SEL_ROM);
2874bdb9230aSGarrett D'Amore drv_nsecwait(30);
2875bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2876bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP);
2877bdb9230aSGarrett D'Amore drv_nsecwait(50);
2878bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2879bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP | SEL_CLK);
2880bdb9230aSGarrett D'Amore drv_nsecwait(250);
2881bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2882bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP);
2883bdb9230aSGarrett D'Amore drv_nsecwait(100);
2884bdb9230aSGarrett D'Amore
2885bdb9230aSGarrett D'Amore /* command */
2886bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2887bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP | DATA_IN);
2888bdb9230aSGarrett D'Amore drv_nsecwait(150);
2889bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2890bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP | DATA_IN | SEL_CLK);
2891bdb9230aSGarrett D'Amore drv_nsecwait(250);
2892bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2893bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP | DATA_IN);
2894bdb9230aSGarrett D'Amore drv_nsecwait(250);
2895bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2896bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP | DATA_IN | SEL_CLK);
2897bdb9230aSGarrett D'Amore drv_nsecwait(250);
2898bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2899bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP | DATA_IN);
2900bdb9230aSGarrett D'Amore drv_nsecwait(100);
2901bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2902bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP);
2903bdb9230aSGarrett D'Amore drv_nsecwait(150);
2904bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2905bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP | SEL_CLK);
2906bdb9230aSGarrett D'Amore drv_nsecwait(250);
2907bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2908bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP);
2909bdb9230aSGarrett D'Amore drv_nsecwait(100);
2910bdb9230aSGarrett D'Amore
2911bdb9230aSGarrett D'Amore /* Address */
2912bdb9230aSGarrett D'Amore for (j = HIGH_ADDRESS_BIT; j >= 1; j >>= 1) {
2913bdb9230aSGarrett D'Amore bit = (rom_addr & j) ? DATA_IN : 0;
2914bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2915bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP | bit);
2916bdb9230aSGarrett D'Amore drv_nsecwait(150);
2917bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2918bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP | bit | SEL_CLK);
2919bdb9230aSGarrett D'Amore drv_nsecwait(250);
2920bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2921bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP | bit);
2922bdb9230aSGarrett D'Amore drv_nsecwait(100);
2923bdb9230aSGarrett D'Amore }
2924bdb9230aSGarrett D'Amore drv_nsecwait(150);
2925bdb9230aSGarrett D'Amore
2926bdb9230aSGarrett D'Amore /* Data */
2927bdb9230aSGarrett D'Amore word = 0;
2928bdb9230aSGarrett D'Amore for (j = 0x8000; j >= 1; j >>= 1) {
2929bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2930bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP | SEL_CLK);
2931bdb9230aSGarrett D'Amore drv_nsecwait(100);
2932bdb9230aSGarrett D'Amore dout = ddi_get32(io_handle,
2933bdb9230aSGarrett D'Amore REG32(io_reg, ETHER_ROM_REG));
2934bdb9230aSGarrett D'Amore drv_nsecwait(150);
2935bdb9230aSGarrett D'Amore if (dout & DATA_OUT)
2936bdb9230aSGarrett D'Amore word |= j;
2937bdb9230aSGarrett D'Amore ddi_put32(io_handle,
2938bdb9230aSGarrett D'Amore REG32(io_reg, ETHER_ROM_REG),
2939bdb9230aSGarrett D'Amore READ_OP | SEL_ROM | SEL_CHIP);
2940bdb9230aSGarrett D'Amore drv_nsecwait(250);
2941bdb9230aSGarrett D'Amore }
2942bdb9230aSGarrett D'Amore addr[i] = (word & 0x0000FF);
2943bdb9230aSGarrett D'Amore addr[i + 1] = (word >> 8);
2944bdb9230aSGarrett D'Amore rom_addr++;
2945bdb9230aSGarrett D'Amore ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
2946bdb9230aSGarrett D'Amore READ_OP | SEL_ROM);
2947bdb9230aSGarrett D'Amore drv_nsecwait(100);
2948bdb9230aSGarrett D'Amore }
2949bdb9230aSGarrett D'Amore }
2950bdb9230aSGarrett D'Amore
2951bdb9230aSGarrett D'Amore
2952bdb9230aSGarrett D'Amore /*
2953bdb9230aSGarrett D'Amore * XXX NEEDSWORK
2954bdb9230aSGarrett D'Amore *
2955bdb9230aSGarrett D'Amore * Some lame multiport cards have only one SROM, which can be accessed
2956bdb9230aSGarrett D'Amore * only from the "first" 21x4x chip, whichever that one is. If we can't
2957bdb9230aSGarrett D'Amore * get at our SROM, we look for its contents in a property instead, which
2958bdb9230aSGarrett D'Amore * we rely on the bootstrap to have properly set.
2959bdb9230aSGarrett D'Amore * #ifdef BUG_4010796
2960bdb9230aSGarrett D'Amore * We also have a hack to try to set it ourselves, when the "first" port
2961bdb9230aSGarrett D'Amore * attaches, if it has not already been properly set. However, this method
2962bdb9230aSGarrett D'Amore * is not reliable, since it makes the unwarrented assumption that the
2963bdb9230aSGarrett D'Amore * "first" port will attach first.
2964bdb9230aSGarrett D'Amore * #endif
2965bdb9230aSGarrett D'Amore */
2966bdb9230aSGarrett D'Amore
2967bdb9230aSGarrett D'Amore static int
get_alternative_srom_image(dev_info_t * devinfo,uchar_t * vi,int len)2968bdb9230aSGarrett D'Amore get_alternative_srom_image(dev_info_t *devinfo, uchar_t *vi, int len)
2969bdb9230aSGarrett D'Amore {
2970bdb9230aSGarrett D'Amore int l = len;
2971bdb9230aSGarrett D'Amore
2972bdb9230aSGarrett D'Amore if (ddi_getlongprop_buf(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
2973bdb9230aSGarrett D'Amore "DNET_SROM", (caddr_t)vi, &len) != DDI_PROP_SUCCESS &&
2974bdb9230aSGarrett D'Amore (len = l) && ddi_getlongprop_buf(DDI_DEV_T_ANY,
2975bdb9230aSGarrett D'Amore ddi_get_parent(devinfo), DDI_PROP_DONTPASS, "DNET_SROM",
2976bdb9230aSGarrett D'Amore (caddr_t)vi, &len) != DDI_PROP_SUCCESS)
2977bdb9230aSGarrett D'Amore return (-1); /* Can't find it! */
2978bdb9230aSGarrett D'Amore
2979bdb9230aSGarrett D'Amore /*
2980bdb9230aSGarrett D'Amore * The return value from this routine specifies which port number
2981bdb9230aSGarrett D'Amore * we are. The primary port is denoted port 0. On a QUAD card we
2982bdb9230aSGarrett D'Amore * should return 1, 2, and 3 from this routine. The return value
2983bdb9230aSGarrett D'Amore * is used to modify the ethernet address from the SROM data.
2984bdb9230aSGarrett D'Amore */
2985bdb9230aSGarrett D'Amore
2986bdb9230aSGarrett D'Amore #ifdef BUG_4010796
2987bdb9230aSGarrett D'Amore {
2988bdb9230aSGarrett D'Amore /*
2989bdb9230aSGarrett D'Amore * For the present, we remember the device number of our primary
2990bdb9230aSGarrett D'Amore * sibling and hope we and our other siblings are consecutively
2991bdb9230aSGarrett D'Amore * numbered up from there. In the future perhaps the bootstrap
2992bdb9230aSGarrett D'Amore * will pass us the necessary information telling us which physical
2993bdb9230aSGarrett D'Amore * port we really are.
2994bdb9230aSGarrett D'Amore */
2995bdb9230aSGarrett D'Amore pci_regspec_t *assignp;
2996bdb9230aSGarrett D'Amore int assign_len;
2997bdb9230aSGarrett D'Amore int devnum;
2998bdb9230aSGarrett D'Amore int primary_devnum;
2999bdb9230aSGarrett D'Amore
3000bdb9230aSGarrett D'Amore primary_devnum = ddi_getprop(DDI_DEV_T_ANY, devinfo, 0,
3001bdb9230aSGarrett D'Amore "DNET_DEVNUM", -1);
3002bdb9230aSGarrett D'Amore if (primary_devnum == -1)
3003bdb9230aSGarrett D'Amore return (1); /* XXX NEEDSWORK -- We have no better idea */
3004bdb9230aSGarrett D'Amore
3005bdb9230aSGarrett D'Amore if ((ddi_getlongprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
3006bdb9230aSGarrett D'Amore "assigned-addresses", (caddr_t)&assignp,
3007bdb9230aSGarrett D'Amore &assign_len)) != DDI_PROP_SUCCESS)
3008bdb9230aSGarrett D'Amore return (1); /* XXX NEEDSWORK -- We have no better idea */
3009bdb9230aSGarrett D'Amore
3010bdb9230aSGarrett D'Amore devnum = PCI_REG_DEV_G(assignp->pci_phys_hi);
3011bdb9230aSGarrett D'Amore kmem_free(assignp, assign_len);
3012bdb9230aSGarrett D'Amore return (devnum - primary_devnum);
3013bdb9230aSGarrett D'Amore }
3014bdb9230aSGarrett D'Amore #else
3015bdb9230aSGarrett D'Amore return (1); /* XXX NEEDSWORK -- We have no better idea */
3016bdb9230aSGarrett D'Amore #endif
3017bdb9230aSGarrett D'Amore }
3018bdb9230aSGarrett D'Amore
3019bdb9230aSGarrett D'Amore
3020bdb9230aSGarrett D'Amore #ifdef BUG_4010796
3021bdb9230aSGarrett D'Amore static void
set_alternative_srom_image(dev_info_t * devinfo,uchar_t * vi,int len)3022bdb9230aSGarrett D'Amore set_alternative_srom_image(dev_info_t *devinfo, uchar_t *vi, int len)
3023bdb9230aSGarrett D'Amore {
3024bdb9230aSGarrett D'Amore int proplen;
3025bdb9230aSGarrett D'Amore pci_regspec_t *assignp;
3026bdb9230aSGarrett D'Amore int assign_len;
3027bdb9230aSGarrett D'Amore int devnum;
3028bdb9230aSGarrett D'Amore
3029bdb9230aSGarrett D'Amore if (ddi_getproplen(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
3030bdb9230aSGarrett D'Amore "DNET_SROM", &proplen) == DDI_PROP_SUCCESS ||
3031bdb9230aSGarrett D'Amore ddi_getproplen(DDI_DEV_T_ANY, ddi_get_parent(devinfo),
3032bdb9230aSGarrett D'Amore DDI_PROP_DONTPASS, "DNET_SROM", &proplen) == DDI_PROP_SUCCESS)
3033bdb9230aSGarrett D'Amore return; /* Already done! */
3034bdb9230aSGarrett D'Amore
3035bdb9230aSGarrett D'Amore /* function return value ignored */
3036bdb9230aSGarrett D'Amore (void) ddi_prop_update_byte_array(DDI_DEV_T_NONE,
3037bdb9230aSGarrett D'Amore ddi_get_parent(devinfo), "DNET_SROM", (uchar_t *)vi, len);
3038bdb9230aSGarrett D'Amore (void) ddi_prop_update_string(DDI_DEV_T_NONE, devinfo,
3039bdb9230aSGarrett D'Amore "DNET_HACK", "hack");
3040bdb9230aSGarrett D'Amore
3041bdb9230aSGarrett D'Amore if ((ddi_getlongprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
3042bdb9230aSGarrett D'Amore "assigned-addresses", (caddr_t)&assignp,
3043bdb9230aSGarrett D'Amore &assign_len)) == DDI_PROP_SUCCESS) {
3044bdb9230aSGarrett D'Amore devnum = PCI_REG_DEV_G(assignp->pci_phys_hi);
3045bdb9230aSGarrett D'Amore kmem_free(assignp, assign_len);
3046bdb9230aSGarrett D'Amore /* function return value ignored */
3047bdb9230aSGarrett D'Amore (void) ddi_prop_update_int(DDI_DEV_T_NONE,
3048bdb9230aSGarrett D'Amore ddi_get_parent(devinfo), "DNET_DEVNUM", devnum);
3049bdb9230aSGarrett D'Amore }
3050bdb9230aSGarrett D'Amore }
3051bdb9230aSGarrett D'Amore #endif
3052bdb9230aSGarrett D'Amore
3053bdb9230aSGarrett D'Amore /*
3054bdb9230aSGarrett D'Amore * ========== SROM Parsing Routines ==========
3055bdb9230aSGarrett D'Amore */
3056bdb9230aSGarrett D'Amore
3057bdb9230aSGarrett D'Amore static int
check_srom_valid(uchar_t * vi)3058bdb9230aSGarrett D'Amore check_srom_valid(uchar_t *vi)
3059bdb9230aSGarrett D'Amore {
3060bdb9230aSGarrett D'Amore int word, bit;
3061bdb9230aSGarrett D'Amore uint8_t crc;
3062bdb9230aSGarrett D'Amore uint16_t *wvi; /* word16 pointer to vendor info */
3063bdb9230aSGarrett D'Amore uint16_t bitval;
3064bdb9230aSGarrett D'Amore
3065bdb9230aSGarrett D'Amore /* verify that the number of controllers on the card is within range */
3066bdb9230aSGarrett D'Amore if (vi[SROM_ADAPTER_CNT] < 1 || vi[SROM_ADAPTER_CNT] > MAX_ADAPTERS)
3067bdb9230aSGarrett D'Amore return (0);
3068bdb9230aSGarrett D'Amore
3069bdb9230aSGarrett D'Amore /*
3070bdb9230aSGarrett D'Amore * version 1 and 3 of this card did not check the id block CRC value
3071bdb9230aSGarrett D'Amore * and this can't be changed without retesting every supported card
3072bdb9230aSGarrett D'Amore *
3073bdb9230aSGarrett D'Amore * however version 4 of the SROM can have this test applied
3074bdb9230aSGarrett D'Amore * without fear of breaking something that used to work.
3075bdb9230aSGarrett D'Amore * the CRC algorithm is taken from the Intel document
3076bdb9230aSGarrett D'Amore * "21x4 Serial ROM Format"
3077bdb9230aSGarrett D'Amore * version 4.09
3078bdb9230aSGarrett D'Amore * 3-Mar-1999
3079bdb9230aSGarrett D'Amore */
3080bdb9230aSGarrett D'Amore
3081bdb9230aSGarrett D'Amore switch (vi[SROM_VERSION]) {
3082bdb9230aSGarrett D'Amore case 1:
3083bdb9230aSGarrett D'Amore /* fallthru */
3084bdb9230aSGarrett D'Amore case 3:
3085bdb9230aSGarrett D'Amore return (vi[SROM_MBZ] == 0 && /* must be zero */
3086bdb9230aSGarrett D'Amore vi[SROM_MBZ2] == 0 && /* must be zero */
3087bdb9230aSGarrett D'Amore vi[SROM_MBZ3] == 0); /* must be zero */
3088bdb9230aSGarrett D'Amore
3089bdb9230aSGarrett D'Amore case 4:
3090bdb9230aSGarrett D'Amore wvi = (uint16_t *)vi;
3091bdb9230aSGarrett D'Amore crc = 0xff;
3092bdb9230aSGarrett D'Amore for (word = 0; word < 9; word++)
3093bdb9230aSGarrett D'Amore for (bit = 15; bit >= 0; bit--) {
3094bdb9230aSGarrett D'Amore if (word == 8 && bit == 7)
3095bdb9230aSGarrett D'Amore return (crc == vi[16]);
3096bdb9230aSGarrett D'Amore bitval =
3097bdb9230aSGarrett D'Amore ((wvi[word] >> bit) & 1) ^ ((crc >> 7) & 1);
3098bdb9230aSGarrett D'Amore crc <<= 1;
3099bdb9230aSGarrett D'Amore if (bitval == 1) {
3100bdb9230aSGarrett D'Amore crc ^= 7;
3101bdb9230aSGarrett D'Amore }
3102bdb9230aSGarrett D'Amore }
3103daefc4e3SToomas Soome /* FALLTHROUGH */
3104bdb9230aSGarrett D'Amore
3105bdb9230aSGarrett D'Amore default:
3106bdb9230aSGarrett D'Amore return (0);
3107bdb9230aSGarrett D'Amore }
3108bdb9230aSGarrett D'Amore }
3109bdb9230aSGarrett D'Amore
3110bdb9230aSGarrett D'Amore /*
3111bdb9230aSGarrett D'Amore * ========== Active Media Determination Routines ==========
3112bdb9230aSGarrett D'Amore */
3113bdb9230aSGarrett D'Amore
3114bdb9230aSGarrett D'Amore /* This routine is also called for V3 Compact and extended type 0 SROMs */
3115bdb9230aSGarrett D'Amore static int
is_fdmedia(int media)3116bdb9230aSGarrett D'Amore is_fdmedia(int media)
3117bdb9230aSGarrett D'Amore {
3118bdb9230aSGarrett D'Amore if (media == MEDIA_TP_FD || media == MEDIA_SYM_SCR_FD)
3119bdb9230aSGarrett D'Amore return (1);
3120bdb9230aSGarrett D'Amore else
3121bdb9230aSGarrett D'Amore return (0);
3122bdb9230aSGarrett D'Amore }
3123bdb9230aSGarrett D'Amore
3124bdb9230aSGarrett D'Amore /*
3125bdb9230aSGarrett D'Amore * "Linkset" is used to merge media that use the same link test check. So,
3126bdb9230aSGarrett D'Amore * if the TP link is added to the linkset, so is the TP Full duplex link.
3127bdb9230aSGarrett D'Amore * Used to avoid checking the same link status twice.
3128bdb9230aSGarrett D'Amore */
3129bdb9230aSGarrett D'Amore static void
linkset_add(uint32_t * set,int media)3130bdb9230aSGarrett D'Amore linkset_add(uint32_t *set, int media)
3131bdb9230aSGarrett D'Amore {
3132bdb9230aSGarrett D'Amore if (media == MEDIA_TP_FD || media == MEDIA_TP)
3133bdb9230aSGarrett D'Amore *set |= (1UL<<MEDIA_TP_FD) | (1UL<<MEDIA_TP);
3134bdb9230aSGarrett D'Amore else if (media == MEDIA_SYM_SCR_FD || media == MEDIA_SYM_SCR)
3135bdb9230aSGarrett D'Amore *set |= (1UL<<MEDIA_SYM_SCR_FD) | (1UL<<MEDIA_SYM_SCR);
3136bdb9230aSGarrett D'Amore else *set |= 1UL<<media;
3137bdb9230aSGarrett D'Amore }
3138bdb9230aSGarrett D'Amore static int
linkset_isset(uint32_t linkset,int media)3139bdb9230aSGarrett D'Amore linkset_isset(uint32_t linkset, int media)
3140bdb9230aSGarrett D'Amore {
3141bdb9230aSGarrett D'Amore return (((1UL<<media) & linkset) ? 1:0);
3142bdb9230aSGarrett D'Amore }
3143bdb9230aSGarrett D'Amore
3144bdb9230aSGarrett D'Amore /*
3145bdb9230aSGarrett D'Amore * The following code detects which Media is connected for 21041/21140
3146bdb9230aSGarrett D'Amore * Expect to change this code to support new 21140 variants.
3147bdb9230aSGarrett D'Amore * find_active_media() - called with intrlock held.
3148bdb9230aSGarrett D'Amore */
3149bdb9230aSGarrett D'Amore static void
find_active_media(struct dnetinstance * dnetp)315098e8d175SSteven Stallion find_active_media(struct dnetinstance *dnetp)
3151bdb9230aSGarrett D'Amore {
3152bdb9230aSGarrett D'Amore int i;
3153bdb9230aSGarrett D'Amore media_block_t *block;
3154bdb9230aSGarrett D'Amore media_block_t *best_allowed = NULL;
3155bdb9230aSGarrett D'Amore media_block_t *hd_found = NULL;
3156bdb9230aSGarrett D'Amore media_block_t *fd_found = NULL;
3157bdb9230aSGarrett D'Amore LEAF_FORMAT *leaf = &dnetp->sr.leaf[dnetp->leaf];
3158bdb9230aSGarrett D'Amore uint32_t checked = 0, links_up = 0;
3159bdb9230aSGarrett D'Amore
3160bdb9230aSGarrett D'Amore ASSERT(MUTEX_HELD(&dnetp->intrlock));
316198e8d175SSteven Stallion
3162bdb9230aSGarrett D'Amore dnetp->selected_media_block = leaf->default_block;
3163bdb9230aSGarrett D'Amore
3164bdb9230aSGarrett D'Amore if (dnetp->phyaddr != -1) {
3165bdb9230aSGarrett D'Amore dnetp->selected_media_block = leaf->mii_block;
316698e8d175SSteven Stallion setup_block(dnetp);
3167bdb9230aSGarrett D'Amore
3168bdb9230aSGarrett D'Amore if (ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo,
3169bdb9230aSGarrett D'Amore DDI_PROP_DONTPASS, "portmon", 1)) {
3170bdb9230aSGarrett D'Amore /* XXX return value ignored */
3171bdb9230aSGarrett D'Amore (void) mii_start_portmon(dnetp->mii, dnet_mii_link_cb,
3172bdb9230aSGarrett D'Amore &dnetp->intrlock);
3173bdb9230aSGarrett D'Amore /*
3174bdb9230aSGarrett D'Amore * If the port monitor detects the link is already
3175bdb9230aSGarrett D'Amore * up, there is no point going through the rest of the
3176bdb9230aSGarrett D'Amore * link sense
3177bdb9230aSGarrett D'Amore */
3178bdb9230aSGarrett D'Amore if (dnetp->mii_up) {
3179bdb9230aSGarrett D'Amore return;
3180bdb9230aSGarrett D'Amore }
3181bdb9230aSGarrett D'Amore }
3182bdb9230aSGarrett D'Amore }
3183bdb9230aSGarrett D'Amore
3184bdb9230aSGarrett D'Amore /*
3185bdb9230aSGarrett D'Amore * Media is searched for in order of Precedence. This DEC SROM spec
3186bdb9230aSGarrett D'Amore * tells us that the first media entry in the SROM is the lowest
3187bdb9230aSGarrett D'Amore * precedence and should be checked last. This is why we go to the last
3188bdb9230aSGarrett D'Amore * Media block and work back to the beginning.
3189bdb9230aSGarrett D'Amore *
3190bdb9230aSGarrett D'Amore * However, some older SROMs (Cogent EM110's etc.) have this the wrong
3191bdb9230aSGarrett D'Amore * way around. As a result, following the SROM spec would result in a
3192bdb9230aSGarrett D'Amore * 10 link being chosen over a 100 link if both media are available.
3193bdb9230aSGarrett D'Amore * So we continue trying the media until we have at least tried the
3194bdb9230aSGarrett D'Amore * DEFAULT media.
3195bdb9230aSGarrett D'Amore */
3196bdb9230aSGarrett D'Amore
3197bdb9230aSGarrett D'Amore /* Search for an active medium, and select it */
3198bdb9230aSGarrett D'Amore for (block = leaf->block + leaf->block_count - 1;
3199bdb9230aSGarrett D'Amore block >= leaf->block; block--) {
3200bdb9230aSGarrett D'Amore int media = block->media_code;
3201bdb9230aSGarrett D'Amore
3202bdb9230aSGarrett D'Amore /* User settings disallow selection of this block */
3203bdb9230aSGarrett D'Amore if (dnetp->disallowed_media & (1UL<<media))
3204bdb9230aSGarrett D'Amore continue;
3205bdb9230aSGarrett D'Amore
3206bdb9230aSGarrett D'Amore /* We may not be able to pick the default */
3207bdb9230aSGarrett D'Amore if (best_allowed == NULL || block == leaf->default_block)
3208bdb9230aSGarrett D'Amore best_allowed = block;
3209bdb9230aSGarrett D'Amore #ifdef DEBUG
3210bdb9230aSGarrett D'Amore if (dnetdebug & DNETSENSE)
3211bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "Testing %s medium (block type %d)",
3212bdb9230aSGarrett D'Amore media_str[media], block->type);
3213bdb9230aSGarrett D'Amore #endif
3214bdb9230aSGarrett D'Amore
3215bdb9230aSGarrett D'Amore dnetp->selected_media_block = block;
3216bdb9230aSGarrett D'Amore switch (block->type) {
3217bdb9230aSGarrett D'Amore
3218bdb9230aSGarrett D'Amore case 2: /* SIA Media block: Best we can do is send a packet */
321998e8d175SSteven Stallion setup_block(dnetp);
322098e8d175SSteven Stallion if (send_test_packet(dnetp)) {
3221bdb9230aSGarrett D'Amore if (!is_fdmedia(media))
3222bdb9230aSGarrett D'Amore return;
3223bdb9230aSGarrett D'Amore if (!fd_found)
3224bdb9230aSGarrett D'Amore fd_found = block;
3225bdb9230aSGarrett D'Amore }
3226bdb9230aSGarrett D'Amore break;
3227bdb9230aSGarrett D'Amore
3228bdb9230aSGarrett D'Amore /* SYM/SCR or TP block: Use the link-sense bits */
3229bdb9230aSGarrett D'Amore case 0:
3230bdb9230aSGarrett D'Amore if (!linkset_isset(checked, media)) {
3231bdb9230aSGarrett D'Amore linkset_add(&checked, media);
3232bdb9230aSGarrett D'Amore if (((media == MEDIA_BNC ||
3233bdb9230aSGarrett D'Amore media == MEDIA_AUI) &&
323498e8d175SSteven Stallion send_test_packet(dnetp)) ||
323598e8d175SSteven Stallion dnet_link_sense(dnetp))
3236bdb9230aSGarrett D'Amore linkset_add(&links_up, media);
3237bdb9230aSGarrett D'Amore }
3238bdb9230aSGarrett D'Amore
3239bdb9230aSGarrett D'Amore if (linkset_isset(links_up, media)) {
3240bdb9230aSGarrett D'Amore /*
3241bdb9230aSGarrett D'Amore * Half Duplex is *always* the favoured media.
3242bdb9230aSGarrett D'Amore * Full Duplex can be set and forced via the
3243bdb9230aSGarrett D'Amore * conf file.
3244bdb9230aSGarrett D'Amore */
3245bdb9230aSGarrett D'Amore if (!is_fdmedia(media) &&
3246bdb9230aSGarrett D'Amore dnetp->selected_media_block ==
3247bdb9230aSGarrett D'Amore leaf->default_block) {
3248bdb9230aSGarrett D'Amore /*
3249bdb9230aSGarrett D'Amore * Cogent cards have the media in
3250bdb9230aSGarrett D'Amore * opposite order to the spec.,
3251bdb9230aSGarrett D'Amore * this code forces the media test to
3252bdb9230aSGarrett D'Amore * keep going until the default media
3253bdb9230aSGarrett D'Amore * is tested.
3254bdb9230aSGarrett D'Amore *
3255bdb9230aSGarrett D'Amore * In Cogent case, 10, 10FD, 100FD, 100
3256bdb9230aSGarrett D'Amore * 100 is the default but 10 could have
3257bdb9230aSGarrett D'Amore * been detected and would have been
3258bdb9230aSGarrett D'Amore * chosen but now we force it through to
3259bdb9230aSGarrett D'Amore * 100.
3260bdb9230aSGarrett D'Amore */
326198e8d175SSteven Stallion setup_block(dnetp);
3262bdb9230aSGarrett D'Amore return;
3263bdb9230aSGarrett D'Amore } else if (!is_fdmedia(media)) {
3264bdb9230aSGarrett D'Amore /*
3265bdb9230aSGarrett D'Amore * This allows all the others to work
3266bdb9230aSGarrett D'Amore * properly by remembering the media
3267bdb9230aSGarrett D'Amore * that works and not defaulting to
3268bdb9230aSGarrett D'Amore * a FD link.
3269bdb9230aSGarrett D'Amore */
3270bdb9230aSGarrett D'Amore if (hd_found == NULL)
3271bdb9230aSGarrett D'Amore hd_found = block;
3272bdb9230aSGarrett D'Amore } else if (fd_found == NULL) {
3273bdb9230aSGarrett D'Amore /*
3274bdb9230aSGarrett D'Amore * No media have already been found
3275bdb9230aSGarrett D'Amore * so far, this is FD, it works so
3276bdb9230aSGarrett D'Amore * remember it and if no others are
3277bdb9230aSGarrett D'Amore * detected, use it.
3278bdb9230aSGarrett D'Amore */
3279bdb9230aSGarrett D'Amore fd_found = block;
3280bdb9230aSGarrett D'Amore }
3281bdb9230aSGarrett D'Amore }
3282bdb9230aSGarrett D'Amore break;
3283bdb9230aSGarrett D'Amore
3284bdb9230aSGarrett D'Amore /*
3285bdb9230aSGarrett D'Amore * MII block: May take up to a second or so to settle if
3286bdb9230aSGarrett D'Amore * setup causes a PHY reset
3287bdb9230aSGarrett D'Amore */
3288bdb9230aSGarrett D'Amore case 1: case 3:
328998e8d175SSteven Stallion setup_block(dnetp);
3290bdb9230aSGarrett D'Amore for (i = 0; ; i++) {
3291bdb9230aSGarrett D'Amore if (mii_linkup(dnetp->mii, dnetp->phyaddr)) {
3292bdb9230aSGarrett D'Amore /* XXX function return value ignored */
3293bdb9230aSGarrett D'Amore (void) mii_getspeed(dnetp->mii,
3294bdb9230aSGarrett D'Amore dnetp->phyaddr,
3295bdb9230aSGarrett D'Amore &dnetp->mii_speed,
3296bdb9230aSGarrett D'Amore &dnetp->mii_duplex);
3297bdb9230aSGarrett D'Amore dnetp->mii_up = 1;
3298bdb9230aSGarrett D'Amore leaf->mii_block = block;
3299bdb9230aSGarrett D'Amore return;
3300bdb9230aSGarrett D'Amore }
3301bdb9230aSGarrett D'Amore if (i == 10)
3302bdb9230aSGarrett D'Amore break;
3303bdb9230aSGarrett D'Amore delay(drv_usectohz(150000));
3304bdb9230aSGarrett D'Amore }
3305bdb9230aSGarrett D'Amore dnetp->mii_up = 0;
3306bdb9230aSGarrett D'Amore break;
3307bdb9230aSGarrett D'Amore }
3308bdb9230aSGarrett D'Amore } /* for loop */
3309bdb9230aSGarrett D'Amore if (hd_found) {
3310bdb9230aSGarrett D'Amore dnetp->selected_media_block = hd_found;
3311bdb9230aSGarrett D'Amore } else if (fd_found) {
3312bdb9230aSGarrett D'Amore dnetp->selected_media_block = fd_found;
3313bdb9230aSGarrett D'Amore } else {
3314bdb9230aSGarrett D'Amore if (best_allowed == NULL)
3315bdb9230aSGarrett D'Amore best_allowed = leaf->default_block;
3316bdb9230aSGarrett D'Amore dnetp->selected_media_block = best_allowed;
3317bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "!dnet: Default media selected\n");
3318bdb9230aSGarrett D'Amore }
331998e8d175SSteven Stallion setup_block(dnetp);
3320bdb9230aSGarrett D'Amore }
3321bdb9230aSGarrett D'Amore
3322bdb9230aSGarrett D'Amore /*
3323bdb9230aSGarrett D'Amore * Do anything neccessary to select the selected_media_block.
3324bdb9230aSGarrett D'Amore * setup_block() - called with intrlock held.
3325bdb9230aSGarrett D'Amore */
3326bdb9230aSGarrett D'Amore static void
setup_block(struct dnetinstance * dnetp)332798e8d175SSteven Stallion setup_block(struct dnetinstance *dnetp)
3328bdb9230aSGarrett D'Amore {
332998e8d175SSteven Stallion dnet_reset_board(dnetp);
333098e8d175SSteven Stallion dnet_init_board(dnetp);
3331bdb9230aSGarrett D'Amore /* XXX function return value ignored */
333298e8d175SSteven Stallion (void) dnet_start(dnetp);
3333bdb9230aSGarrett D'Amore }
3334bdb9230aSGarrett D'Amore
3335bdb9230aSGarrett D'Amore /* dnet_link_sense() - called with intrlock held */
3336bdb9230aSGarrett D'Amore static int
dnet_link_sense(struct dnetinstance * dnetp)333798e8d175SSteven Stallion dnet_link_sense(struct dnetinstance *dnetp)
3338bdb9230aSGarrett D'Amore {
3339bdb9230aSGarrett D'Amore /*
3340bdb9230aSGarrett D'Amore * This routine makes use of the command word from the srom config.
3341bdb9230aSGarrett D'Amore * Details of the auto-sensing information contained in this can
3342bdb9230aSGarrett D'Amore * be found in the "Digital Semiconductor 21X4 Serial ROM Format v3.03"
3343bdb9230aSGarrett D'Amore * spec. Section 4.3.2.1, and 4.5.2.1.3
3344bdb9230aSGarrett D'Amore */
3345bdb9230aSGarrett D'Amore media_block_t *block = dnetp->selected_media_block;
3346bdb9230aSGarrett D'Amore uint32_t link, status, mask, polarity;
3347bdb9230aSGarrett D'Amore int settletime, stabletime, waittime, upsamples;
3348bdb9230aSGarrett D'Amore int delay_100, delay_10;
3349bdb9230aSGarrett D'Amore
3350bdb9230aSGarrett D'Amore
3351bdb9230aSGarrett D'Amore ASSERT(MUTEX_HELD(&dnetp->intrlock));
3352bdb9230aSGarrett D'Amore /* Don't autosense if the medium does not support it */
3353bdb9230aSGarrett D'Amore if (block->command & (1 << 15)) {
3354bdb9230aSGarrett D'Amore /* This should be the default block */
3355bdb9230aSGarrett D'Amore if (block->command & (1UL<<14))
3356bdb9230aSGarrett D'Amore dnetp->sr.leaf[dnetp->leaf].default_block = block;
3357bdb9230aSGarrett D'Amore return (0);
3358bdb9230aSGarrett D'Amore }
3359bdb9230aSGarrett D'Amore
3360bdb9230aSGarrett D'Amore delay_100 = ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo,
3361bdb9230aSGarrett D'Amore DDI_PROP_DONTPASS, "autosense-delay-100", 2000);
3362bdb9230aSGarrett D'Amore
3363bdb9230aSGarrett D'Amore delay_10 = ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo,
3364bdb9230aSGarrett D'Amore DDI_PROP_DONTPASS, "autosense-delay-10", 400);
3365bdb9230aSGarrett D'Amore
3366bdb9230aSGarrett D'Amore /*
3367bdb9230aSGarrett D'Amore * Scrambler may need to be disabled for link sensing
3368bdb9230aSGarrett D'Amore * to work
3369bdb9230aSGarrett D'Amore */
3370bdb9230aSGarrett D'Amore dnetp->disable_scrambler = 1;
337198e8d175SSteven Stallion setup_block(dnetp);
3372bdb9230aSGarrett D'Amore dnetp->disable_scrambler = 0;
3373bdb9230aSGarrett D'Amore
3374bdb9230aSGarrett D'Amore if (block->media_code == MEDIA_TP || block->media_code == MEDIA_TP_FD)
3375bdb9230aSGarrett D'Amore settletime = delay_10;
3376bdb9230aSGarrett D'Amore else
3377bdb9230aSGarrett D'Amore settletime = delay_100;
3378bdb9230aSGarrett D'Amore stabletime = settletime / 4;
3379bdb9230aSGarrett D'Amore
3380bdb9230aSGarrett D'Amore mask = 1 << ((block->command & CMD_MEDIABIT_MASK) >> 1);
3381bdb9230aSGarrett D'Amore polarity = block->command & CMD_POL ? 0xffffffff : 0;
3382bdb9230aSGarrett D'Amore
3383bdb9230aSGarrett D'Amore for (waittime = 0, upsamples = 0;
3384bdb9230aSGarrett D'Amore waittime <= settletime + stabletime && upsamples < 8;
3385bdb9230aSGarrett D'Amore waittime += stabletime/8) {
3386bdb9230aSGarrett D'Amore delay(drv_usectohz(stabletime*1000 / 8));
3387bdb9230aSGarrett D'Amore status = read_gpr(dnetp);
3388bdb9230aSGarrett D'Amore link = (status^polarity) & mask;
3389bdb9230aSGarrett D'Amore if (link)
3390bdb9230aSGarrett D'Amore upsamples++;
3391bdb9230aSGarrett D'Amore else
3392bdb9230aSGarrett D'Amore upsamples = 0;
3393bdb9230aSGarrett D'Amore }
3394bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
3395bdb9230aSGarrett D'Amore if (dnetdebug & DNETSENSE)
3396bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "%s upsamples:%d stat:%x polarity:%x "
3397bdb9230aSGarrett D'Amore "mask:%x link:%x",
3398bdb9230aSGarrett D'Amore upsamples == 8 ? "UP":"DOWN",
3399bdb9230aSGarrett D'Amore upsamples, status, polarity, mask, link);
3400bdb9230aSGarrett D'Amore #endif
3401bdb9230aSGarrett D'Amore if (upsamples == 8)
3402bdb9230aSGarrett D'Amore return (1);
3403bdb9230aSGarrett D'Amore return (0);
3404bdb9230aSGarrett D'Amore }
3405bdb9230aSGarrett D'Amore
3406bdb9230aSGarrett D'Amore static int
send_test_packet(struct dnetinstance * dnetp)340798e8d175SSteven Stallion send_test_packet(struct dnetinstance *dnetp)
3408bdb9230aSGarrett D'Amore {
3409bdb9230aSGarrett D'Amore int packet_delay;
3410bdb9230aSGarrett D'Amore struct tx_desc_type *desc;
3411bdb9230aSGarrett D'Amore int bufindex;
3412bdb9230aSGarrett D'Amore int media_code = dnetp->selected_media_block->media_code;
3413bdb9230aSGarrett D'Amore uint32_t del;
3414bdb9230aSGarrett D'Amore
3415bdb9230aSGarrett D'Amore ASSERT(MUTEX_HELD(&dnetp->intrlock));
3416bdb9230aSGarrett D'Amore /*
3417bdb9230aSGarrett D'Amore * For a successful test packet, the card must have settled into
3418bdb9230aSGarrett D'Amore * its current setting. Almost all cards we've tested manage to
3419bdb9230aSGarrett D'Amore * do this with all media within 50ms. However, the SMC 8432
3420bdb9230aSGarrett D'Amore * requires 300ms to settle into BNC mode. We now only do this
3421bdb9230aSGarrett D'Amore * from attach, and we do sleeping delay() instead of drv_usecwait()
3422bdb9230aSGarrett D'Amore * so we hope this .2 second delay won't cause too much suffering.
3423bdb9230aSGarrett D'Amore * ALSO: with an autonegotiating hub, an aditional 1 second delay is
3424bdb9230aSGarrett D'Amore * required. This is done if the media type is TP
3425bdb9230aSGarrett D'Amore */
3426bdb9230aSGarrett D'Amore if (media_code == MEDIA_TP || media_code == MEDIA_TP_FD) {
3427bdb9230aSGarrett D'Amore packet_delay = ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo,
3428bdb9230aSGarrett D'Amore DDI_PROP_DONTPASS, "test_packet_delay_tp", 1300000);
3429bdb9230aSGarrett D'Amore } else {
3430bdb9230aSGarrett D'Amore packet_delay = ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo,
3431bdb9230aSGarrett D'Amore DDI_PROP_DONTPASS, "test_packet_delay", 300000);
3432bdb9230aSGarrett D'Amore }
3433bdb9230aSGarrett D'Amore delay(drv_usectohz(packet_delay));
3434bdb9230aSGarrett D'Amore
3435bdb9230aSGarrett D'Amore desc = dnetp->tx_desc;
3436bdb9230aSGarrett D'Amore
3437bdb9230aSGarrett D'Amore bufindex = dnetp->tx_current_desc;
343898e8d175SSteven Stallion if (alloc_descriptor(dnetp) == FAILURE) {
3439bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "DNET: send_test_packet: alloc_descriptor"
3440bdb9230aSGarrett D'Amore "failed");
3441bdb9230aSGarrett D'Amore return (0);
3442bdb9230aSGarrett D'Amore }
3443bdb9230aSGarrett D'Amore
3444bdb9230aSGarrett D'Amore /*
3445bdb9230aSGarrett D'Amore * use setup buffer as the buffer for the test packet
3446bdb9230aSGarrett D'Amore * instead of allocating one.
3447bdb9230aSGarrett D'Amore */
3448bdb9230aSGarrett D'Amore
3449bdb9230aSGarrett D'Amore ASSERT(dnetp->setup_buf_vaddr != NULL);
3450bdb9230aSGarrett D'Amore /* Put something decent in dest address so we don't annoy other cards */
3451bdb9230aSGarrett D'Amore BCOPY((caddr_t)dnetp->curr_macaddr,
3452bdb9230aSGarrett D'Amore (caddr_t)dnetp->setup_buf_vaddr, ETHERADDRL);
3453bdb9230aSGarrett D'Amore BCOPY((caddr_t)dnetp->curr_macaddr,
3454bdb9230aSGarrett D'Amore (caddr_t)dnetp->setup_buf_vaddr+ETHERADDRL, ETHERADDRL);
3455bdb9230aSGarrett D'Amore
3456bdb9230aSGarrett D'Amore desc[bufindex].buffer1 = dnetp->setup_buf_paddr;
3457bdb9230aSGarrett D'Amore desc[bufindex].desc1.buffer_size1 = SETUPBUF_SIZE;
3458bdb9230aSGarrett D'Amore desc[bufindex].buffer2 = (uint32_t)(0);
3459bdb9230aSGarrett D'Amore desc[bufindex].desc1.first_desc = 1;
3460bdb9230aSGarrett D'Amore desc[bufindex].desc1.last_desc = 1;
3461bdb9230aSGarrett D'Amore desc[bufindex].desc1.int_on_comp = 1;
3462bdb9230aSGarrett D'Amore desc[bufindex].desc0.own = 1;
3463bdb9230aSGarrett D'Amore
3464bdb9230aSGarrett D'Amore ddi_put8(dnetp->io_handle, REG8(dnetp->io_reg, TX_POLL_REG),
3465bdb9230aSGarrett D'Amore TX_POLL_DEMAND);
3466bdb9230aSGarrett D'Amore
3467bdb9230aSGarrett D'Amore /*
3468bdb9230aSGarrett D'Amore * Give enough time for the chip to transmit the packet
3469bdb9230aSGarrett D'Amore */
3470bdb9230aSGarrett D'Amore #if 1
3471bdb9230aSGarrett D'Amore del = 1000;
3472bdb9230aSGarrett D'Amore while (desc[bufindex].desc0.own && --del)
3473bdb9230aSGarrett D'Amore drv_usecwait(10); /* quickly wait up to 10ms */
3474bdb9230aSGarrett D'Amore if (desc[bufindex].desc0.own)
3475bdb9230aSGarrett D'Amore delay(drv_usectohz(200000)); /* nicely wait a longer time */
3476bdb9230aSGarrett D'Amore #else
3477bdb9230aSGarrett D'Amore del = 0x10000;
3478bdb9230aSGarrett D'Amore while (desc[bufindex].desc0.own && --del)
3479bdb9230aSGarrett D'Amore drv_usecwait(10);
3480bdb9230aSGarrett D'Amore #endif
3481bdb9230aSGarrett D'Amore
3482bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
3483bdb9230aSGarrett D'Amore if (dnetdebug & DNETSENSE)
3484bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "desc0 bits = %u, %u, %u, %u, %u, %u",
3485bdb9230aSGarrett D'Amore desc[bufindex].desc0.own,
3486bdb9230aSGarrett D'Amore desc[bufindex].desc0.err_summary,
3487bdb9230aSGarrett D'Amore desc[bufindex].desc0.carrier_loss,
3488bdb9230aSGarrett D'Amore desc[bufindex].desc0.no_carrier,
3489bdb9230aSGarrett D'Amore desc[bufindex].desc0.late_collision,
3490bdb9230aSGarrett D'Amore desc[bufindex].desc0.link_fail);
3491bdb9230aSGarrett D'Amore #endif
3492bdb9230aSGarrett D'Amore if (desc[bufindex].desc0.own) /* it shouldn't take this long, error */
3493bdb9230aSGarrett D'Amore return (0);
3494bdb9230aSGarrett D'Amore
3495bdb9230aSGarrett D'Amore return (!desc[bufindex].desc0.err_summary);
3496bdb9230aSGarrett D'Amore }
3497bdb9230aSGarrett D'Amore
3498bdb9230aSGarrett D'Amore /* enable_interrupts - called with intrlock held */
3499bdb9230aSGarrett D'Amore static void
enable_interrupts(struct dnetinstance * dnetp)350098e8d175SSteven Stallion enable_interrupts(struct dnetinstance *dnetp)
3501bdb9230aSGarrett D'Amore {
3502bdb9230aSGarrett D'Amore ASSERT(MUTEX_HELD(&dnetp->intrlock));
3503bdb9230aSGarrett D'Amore /* Don't enable interrupts if they have been forced off */
3504bdb9230aSGarrett D'Amore if (dnetp->interrupts_disabled)
3505bdb9230aSGarrett D'Amore return;
3506bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, INT_MASK_REG),
350798e8d175SSteven Stallion ABNORMAL_INTR_MASK | NORMAL_INTR_MASK | SYSTEM_ERROR_MASK |
3508bdb9230aSGarrett D'Amore (dnetp->timer.cb ? GPTIMER_INTR : 0) |
350998e8d175SSteven Stallion RX_INTERRUPT_MASK |
351098e8d175SSteven Stallion TX_INTERRUPT_MASK | TX_JABBER_MASK | TX_UNDERFLOW_MASK);
3511bdb9230aSGarrett D'Amore }
3512bdb9230aSGarrett D'Amore
3513bdb9230aSGarrett D'Amore /*
3514bdb9230aSGarrett D'Amore * Some older multiport cards are non-PCI compliant in their interrupt routing.
3515bdb9230aSGarrett D'Amore * Second and subsequent devices are incorrectly configured by the BIOS
3516bdb9230aSGarrett D'Amore * (either in their ILINE configuration or the MP Configuration Table for PC+MP
3517bdb9230aSGarrett D'Amore * systems).
351898e8d175SSteven Stallion * The hack stops registering the interrupt routine for the FIRST
351998e8d175SSteven Stallion * device on the adapter, and registers its own. It builds up a table
352098e8d175SSteven Stallion * of dnetp structures for each device, and the new interrupt routine
352198e8d175SSteven Stallion * calls dnet_intr for each of them.
3522bdb9230aSGarrett D'Amore * Known cards that suffer from this problem are:
3523bdb9230aSGarrett D'Amore * All Cogent multiport cards;
3524bdb9230aSGarrett D'Amore * Znyx 314;
3525bdb9230aSGarrett D'Amore * Znyx 315.
3526bdb9230aSGarrett D'Amore *
3527bdb9230aSGarrett D'Amore * XXX NEEDSWORK -- see comments above get_alternative_srom_image(). This
3528bdb9230aSGarrett D'Amore * hack relies on the fact that the offending cards will have only one SROM.
3529bdb9230aSGarrett D'Amore * It uses this fact to identify devices that are on the same multiport
3530bdb9230aSGarrett D'Amore * adapter, as opposed to multiple devices from the same vendor (as
3531bdb9230aSGarrett D'Amore * indicated by "secondary")
3532bdb9230aSGarrett D'Amore */
3533bdb9230aSGarrett D'Amore static int
dnet_hack_interrupts(struct dnetinstance * dnetp,int secondary)353498e8d175SSteven Stallion dnet_hack_interrupts(struct dnetinstance *dnetp, int secondary)
3535bdb9230aSGarrett D'Amore {
3536bdb9230aSGarrett D'Amore int i;
3537bdb9230aSGarrett D'Amore struct hackintr_inf *hackintr_inf;
3538bdb9230aSGarrett D'Amore dev_info_t *devinfo = dnetp->devinfo;
3539bdb9230aSGarrett D'Amore uint32_t oui = 0; /* Organizationally Unique ID */
3540bdb9230aSGarrett D'Amore
3541bdb9230aSGarrett D'Amore if (ddi_getprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
3542bdb9230aSGarrett D'Amore "no_INTA_workaround", 0) != 0)
3543bdb9230aSGarrett D'Amore return (0);
3544bdb9230aSGarrett D'Amore
3545bdb9230aSGarrett D'Amore for (i = 0; i < 3; i++)
3546bdb9230aSGarrett D'Amore oui = (oui << 8) | dnetp->vendor_addr[i];
3547bdb9230aSGarrett D'Amore
3548bdb9230aSGarrett D'Amore /* Check wheather or not we need to implement the hack */
3549bdb9230aSGarrett D'Amore
3550bdb9230aSGarrett D'Amore switch (oui) {
3551bdb9230aSGarrett D'Amore case ZNYX_ETHER:
3552bdb9230aSGarrett D'Amore /* Znyx multiport 21040 cards <<==>> ZX314 or ZX315 */
3553bdb9230aSGarrett D'Amore if (dnetp->board_type != DEVICE_ID_21040)
3554bdb9230aSGarrett D'Amore return (0);
3555bdb9230aSGarrett D'Amore break;
3556bdb9230aSGarrett D'Amore
3557bdb9230aSGarrett D'Amore case COGENT_ETHER:
3558bdb9230aSGarrett D'Amore /* All known Cogent multiport cards */
3559bdb9230aSGarrett D'Amore break;
3560bdb9230aSGarrett D'Amore
3561bdb9230aSGarrett D'Amore case ADAPTEC_ETHER:
3562bdb9230aSGarrett D'Amore /* Adaptec multiport cards */
3563bdb9230aSGarrett D'Amore break;
3564bdb9230aSGarrett D'Amore
3565bdb9230aSGarrett D'Amore default:
3566bdb9230aSGarrett D'Amore /* Other cards work correctly */
3567bdb9230aSGarrett D'Amore return (0);
3568bdb9230aSGarrett D'Amore }
3569bdb9230aSGarrett D'Amore
3570bdb9230aSGarrett D'Amore /* card is (probably) non-PCI compliant in its interrupt routing */
3571bdb9230aSGarrett D'Amore
3572bdb9230aSGarrett D'Amore
3573bdb9230aSGarrett D'Amore if (!secondary) {
3574bdb9230aSGarrett D'Amore
3575bdb9230aSGarrett D'Amore /*
3576bdb9230aSGarrett D'Amore * If we have already registered a hacked interrupt, and
3577bdb9230aSGarrett D'Amore * this is also a 'primary' adapter, then this is NOT part of
3578bdb9230aSGarrett D'Amore * a multiport card, but a second card on the same PCI bus.
3579bdb9230aSGarrett D'Amore * BUGID: 4057747
3580bdb9230aSGarrett D'Amore */
3581bdb9230aSGarrett D'Amore if (ddi_getprop(DDI_DEV_T_ANY, ddi_get_parent(devinfo),
3582bdb9230aSGarrett D'Amore DDI_PROP_DONTPASS, hackintr_propname, 0) != 0)
3583bdb9230aSGarrett D'Amore return (0);
3584bdb9230aSGarrett D'Amore /* ... Primary not part of a multiport device */
3585bdb9230aSGarrett D'Amore
3586bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
3587bdb9230aSGarrett D'Amore if (dnetdebug & DNETTRACE)
3588bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "dnet: Implementing hardware "
3589bdb9230aSGarrett D'Amore "interrupt flaw workaround");
3590bdb9230aSGarrett D'Amore #endif
3591bdb9230aSGarrett D'Amore dnetp->hackintr_inf = hackintr_inf =
3592bdb9230aSGarrett D'Amore kmem_zalloc(sizeof (struct hackintr_inf), KM_SLEEP);
3593bdb9230aSGarrett D'Amore if (hackintr_inf == NULL)
3594bdb9230aSGarrett D'Amore goto fail;
3595bdb9230aSGarrett D'Amore
359698e8d175SSteven Stallion hackintr_inf->dnetps[0] = dnetp;
3597bdb9230aSGarrett D'Amore hackintr_inf->devinfo = devinfo;
3598bdb9230aSGarrett D'Amore
3599bdb9230aSGarrett D'Amore /*
3600bdb9230aSGarrett D'Amore * Add a property to allow successive attaches to find the
3601bdb9230aSGarrett D'Amore * table
3602bdb9230aSGarrett D'Amore */
3603bdb9230aSGarrett D'Amore
3604bdb9230aSGarrett D'Amore if (ddi_prop_update_byte_array(DDI_DEV_T_NONE,
3605bdb9230aSGarrett D'Amore ddi_get_parent(devinfo), hackintr_propname,
3606bdb9230aSGarrett D'Amore (uchar_t *)&dnetp->hackintr_inf,
3607bdb9230aSGarrett D'Amore sizeof (void *)) != DDI_PROP_SUCCESS)
3608bdb9230aSGarrett D'Amore goto fail;
3609bdb9230aSGarrett D'Amore
3610bdb9230aSGarrett D'Amore
3611bdb9230aSGarrett D'Amore /* Register our hacked interrupt routine */
361298e8d175SSteven Stallion if (ddi_add_intr(devinfo, 0, &dnetp->icookie, NULL,
3613bdb9230aSGarrett D'Amore (uint_t (*)(char *))dnet_hack_intr,
3614bdb9230aSGarrett D'Amore (caddr_t)hackintr_inf) != DDI_SUCCESS) {
3615bdb9230aSGarrett D'Amore /* XXX function return value ignored */
3616bdb9230aSGarrett D'Amore (void) ddi_prop_remove(DDI_DEV_T_NONE,
3617bdb9230aSGarrett D'Amore ddi_get_parent(devinfo),
3618bdb9230aSGarrett D'Amore hackintr_propname);
3619bdb9230aSGarrett D'Amore goto fail;
3620bdb9230aSGarrett D'Amore }
3621bdb9230aSGarrett D'Amore
3622bdb9230aSGarrett D'Amore /*
3623bdb9230aSGarrett D'Amore * Mutex required to ensure interrupt routine has completed
3624bdb9230aSGarrett D'Amore * when detaching devices
3625bdb9230aSGarrett D'Amore */
3626bdb9230aSGarrett D'Amore mutex_init(&hackintr_inf->lock, NULL, MUTEX_DRIVER,
362798e8d175SSteven Stallion dnetp->icookie);
3628bdb9230aSGarrett D'Amore
3629bdb9230aSGarrett D'Amore /* Stop GLD registering an interrupt */
3630bdb9230aSGarrett D'Amore return (-1);
3631bdb9230aSGarrett D'Amore } else {
3632bdb9230aSGarrett D'Amore
363398e8d175SSteven Stallion /* Add the dnetp for this secondary device to the table */
3634bdb9230aSGarrett D'Amore
3635bdb9230aSGarrett D'Amore hackintr_inf = (struct hackintr_inf *)(uintptr_t)
3636bdb9230aSGarrett D'Amore ddi_getprop(DDI_DEV_T_ANY, ddi_get_parent(devinfo),
3637bdb9230aSGarrett D'Amore DDI_PROP_DONTPASS, hackintr_propname, 0);
3638bdb9230aSGarrett D'Amore
3639bdb9230aSGarrett D'Amore if (hackintr_inf == NULL)
3640bdb9230aSGarrett D'Amore goto fail;
3641bdb9230aSGarrett D'Amore
3642bdb9230aSGarrett D'Amore /* Find an empty slot */
3643bdb9230aSGarrett D'Amore for (i = 0; i < MAX_INST; i++)
364498e8d175SSteven Stallion if (hackintr_inf->dnetps[i] == NULL)
3645bdb9230aSGarrett D'Amore break;
3646bdb9230aSGarrett D'Amore
3647bdb9230aSGarrett D'Amore /* More than 8 ports on adapter ?! */
3648bdb9230aSGarrett D'Amore if (i == MAX_INST)
3649bdb9230aSGarrett D'Amore goto fail;
3650bdb9230aSGarrett D'Amore
365198e8d175SSteven Stallion hackintr_inf->dnetps[i] = dnetp;
3652bdb9230aSGarrett D'Amore
3653bdb9230aSGarrett D'Amore /*
3654bdb9230aSGarrett D'Amore * Allow GLD to register a handler for this
3655bdb9230aSGarrett D'Amore * device. If the card is actually broken, as we suspect, this
3656bdb9230aSGarrett D'Amore * handler will never get called. However, by registering the
3657bdb9230aSGarrett D'Amore * interrupt handler, we can copy gracefully with new multiport
3658bdb9230aSGarrett D'Amore * Cogent cards that decide to fix the hardware problem
3659bdb9230aSGarrett D'Amore */
3660bdb9230aSGarrett D'Amore return (0);
3661bdb9230aSGarrett D'Amore }
3662bdb9230aSGarrett D'Amore
3663bdb9230aSGarrett D'Amore fail:
3664bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "dnet: Could not work around hardware interrupt"
3665bdb9230aSGarrett D'Amore " routing problem");
3666bdb9230aSGarrett D'Amore return (0);
3667bdb9230aSGarrett D'Amore }
3668bdb9230aSGarrett D'Amore
3669bdb9230aSGarrett D'Amore /*
367098e8d175SSteven Stallion * Call dnet_intr for all adapters on a multiport card
3671bdb9230aSGarrett D'Amore */
3672bdb9230aSGarrett D'Amore static uint_t
dnet_hack_intr(struct hackintr_inf * hackintr_inf)3673bdb9230aSGarrett D'Amore dnet_hack_intr(struct hackintr_inf *hackintr_inf)
3674bdb9230aSGarrett D'Amore {
3675bdb9230aSGarrett D'Amore int i;
3676bdb9230aSGarrett D'Amore int claimed = DDI_INTR_UNCLAIMED;
3677bdb9230aSGarrett D'Amore
3678bdb9230aSGarrett D'Amore /* Stop detaches while processing interrupts */
3679bdb9230aSGarrett D'Amore mutex_enter(&hackintr_inf->lock);
3680bdb9230aSGarrett D'Amore
3681bdb9230aSGarrett D'Amore for (i = 0; i < MAX_INST; i++) {
368298e8d175SSteven Stallion if (hackintr_inf->dnetps[i] &&
368398e8d175SSteven Stallion dnet_intr((caddr_t)hackintr_inf->dnetps[i]) ==
368498e8d175SSteven Stallion DDI_INTR_CLAIMED) {
3685bdb9230aSGarrett D'Amore claimed = DDI_INTR_CLAIMED;
3686bdb9230aSGarrett D'Amore }
368798e8d175SSteven Stallion }
3688bdb9230aSGarrett D'Amore mutex_exit(&hackintr_inf->lock);
3689bdb9230aSGarrett D'Amore return (claimed);
3690bdb9230aSGarrett D'Amore }
3691bdb9230aSGarrett D'Amore
3692bdb9230aSGarrett D'Amore /*
3693bdb9230aSGarrett D'Amore * This removes the detaching device from the table procesed by the hacked
3694bdb9230aSGarrett D'Amore * interrupt routine. Because the interrupts from all devices come in to the
3695bdb9230aSGarrett D'Amore * same interrupt handler, ALL devices must stop interrupting once the
3696bdb9230aSGarrett D'Amore * primary device detaches. This isn't a problem at present, because all
3697bdb9230aSGarrett D'Amore * instances of a device are detached when the driver is unloaded.
3698bdb9230aSGarrett D'Amore */
3699bdb9230aSGarrett D'Amore static int
dnet_detach_hacked_interrupt(dev_info_t * devinfo)3700bdb9230aSGarrett D'Amore dnet_detach_hacked_interrupt(dev_info_t *devinfo)
3701bdb9230aSGarrett D'Amore {
3702bdb9230aSGarrett D'Amore int i;
3703bdb9230aSGarrett D'Amore struct hackintr_inf *hackintr_inf;
370498e8d175SSteven Stallion struct dnetinstance *altdnetp, *dnetp =
370598e8d175SSteven Stallion ddi_get_driver_private(devinfo);
3706bdb9230aSGarrett D'Amore
3707bdb9230aSGarrett D'Amore hackintr_inf = (struct hackintr_inf *)(uintptr_t)
3708bdb9230aSGarrett D'Amore ddi_getprop(DDI_DEV_T_ANY, ddi_get_parent(devinfo),
3709bdb9230aSGarrett D'Amore DDI_PROP_DONTPASS, hackintr_propname, 0);
3710bdb9230aSGarrett D'Amore
3711bdb9230aSGarrett D'Amore /*
3712bdb9230aSGarrett D'Amore * No hackintr_inf implies hack was not required or the primary has
3713bdb9230aSGarrett D'Amore * detached, and our interrupts are already disabled
3714bdb9230aSGarrett D'Amore */
3715bdb9230aSGarrett D'Amore if (!hackintr_inf) {
3716bdb9230aSGarrett D'Amore /* remove the interrupt for the non-hacked case */
371798e8d175SSteven Stallion ddi_remove_intr(devinfo, 0, dnetp->icookie);
3718bdb9230aSGarrett D'Amore return (DDI_SUCCESS);
3719bdb9230aSGarrett D'Amore }
3720bdb9230aSGarrett D'Amore
3721bdb9230aSGarrett D'Amore /* Remove this device from the handled table */
3722bdb9230aSGarrett D'Amore mutex_enter(&hackintr_inf->lock);
3723bdb9230aSGarrett D'Amore for (i = 0; i < MAX_INST; i++) {
372498e8d175SSteven Stallion if (hackintr_inf->dnetps[i] == dnetp) {
372598e8d175SSteven Stallion hackintr_inf->dnetps[i] = NULL;
3726bdb9230aSGarrett D'Amore break;
3727bdb9230aSGarrett D'Amore }
3728bdb9230aSGarrett D'Amore }
3729bdb9230aSGarrett D'Amore
3730bdb9230aSGarrett D'Amore mutex_exit(&hackintr_inf->lock);
3731bdb9230aSGarrett D'Amore
3732bdb9230aSGarrett D'Amore /* Not the primary card, we are done */
3733bdb9230aSGarrett D'Amore if (devinfo != hackintr_inf->devinfo)
3734bdb9230aSGarrett D'Amore return (DDI_SUCCESS);
3735bdb9230aSGarrett D'Amore
3736bdb9230aSGarrett D'Amore /*
3737bdb9230aSGarrett D'Amore * This is the primary card. All remaining adapters on this device
3738bdb9230aSGarrett D'Amore * must have their interrupts disabled before we remove the handler
3739bdb9230aSGarrett D'Amore */
3740bdb9230aSGarrett D'Amore for (i = 0; i < MAX_INST; i++) {
374198e8d175SSteven Stallion if ((altdnetp = hackintr_inf->dnetps[i]) != NULL) {
3742bdb9230aSGarrett D'Amore altdnetp->interrupts_disabled = 1;
3743bdb9230aSGarrett D'Amore ddi_put32(altdnetp->io_handle,
3744bdb9230aSGarrett D'Amore REG32(altdnetp->io_reg, INT_MASK_REG), 0);
3745bdb9230aSGarrett D'Amore }
3746bdb9230aSGarrett D'Amore }
3747bdb9230aSGarrett D'Amore
3748bdb9230aSGarrett D'Amore /* It should now be safe to remove the interrupt handler */
3749bdb9230aSGarrett D'Amore
375098e8d175SSteven Stallion ddi_remove_intr(devinfo, 0, dnetp->icookie);
3751bdb9230aSGarrett D'Amore mutex_destroy(&hackintr_inf->lock);
3752bdb9230aSGarrett D'Amore /* XXX function return value ignored */
3753bdb9230aSGarrett D'Amore (void) ddi_prop_remove(DDI_DEV_T_NONE, ddi_get_parent(devinfo),
3754bdb9230aSGarrett D'Amore hackintr_propname);
3755bdb9230aSGarrett D'Amore kmem_free(hackintr_inf, sizeof (struct hackintr_inf));
3756bdb9230aSGarrett D'Amore return (DDI_SUCCESS);
3757bdb9230aSGarrett D'Amore }
3758bdb9230aSGarrett D'Amore
3759bdb9230aSGarrett D'Amore /* do_phy() - called with intrlock held */
3760bdb9230aSGarrett D'Amore static void
do_phy(struct dnetinstance * dnetp)376198e8d175SSteven Stallion do_phy(struct dnetinstance *dnetp)
3762bdb9230aSGarrett D'Amore {
3763bdb9230aSGarrett D'Amore dev_info_t *dip;
3764bdb9230aSGarrett D'Amore LEAF_FORMAT *leaf = dnetp->sr.leaf + dnetp->leaf;
3765bdb9230aSGarrett D'Amore media_block_t *block;
3766bdb9230aSGarrett D'Amore int phy;
3767bdb9230aSGarrett D'Amore
3768bdb9230aSGarrett D'Amore dip = dnetp->devinfo;
3769bdb9230aSGarrett D'Amore
3770bdb9230aSGarrett D'Amore /*
3771bdb9230aSGarrett D'Amore * Find and configure the PHY media block. If NO PHY blocks are
3772bdb9230aSGarrett D'Amore * found on the SROM, but a PHY device is present, we assume the card
3773bdb9230aSGarrett D'Amore * is a legacy device, and that there is ONLY a PHY interface on the
3774bdb9230aSGarrett D'Amore * card (ie, no BNC or AUI, and 10BaseT is implemented by the PHY
3775bdb9230aSGarrett D'Amore */
3776bdb9230aSGarrett D'Amore
3777bdb9230aSGarrett D'Amore for (block = leaf->block + leaf->block_count -1;
3778bdb9230aSGarrett D'Amore block >= leaf->block; block --) {
3779bdb9230aSGarrett D'Amore if (block->type == 3 || block->type == 1) {
3780bdb9230aSGarrett D'Amore leaf->mii_block = block;
3781bdb9230aSGarrett D'Amore break;
3782bdb9230aSGarrett D'Amore }
3783bdb9230aSGarrett D'Amore }
3784bdb9230aSGarrett D'Amore
3785bdb9230aSGarrett D'Amore /*
3786bdb9230aSGarrett D'Amore * If no MII block, select default, and hope this configuration will
3787bdb9230aSGarrett D'Amore * allow the phy to be read/written if it is present
3788bdb9230aSGarrett D'Amore */
3789bdb9230aSGarrett D'Amore dnetp->selected_media_block = leaf->mii_block ?
3790bdb9230aSGarrett D'Amore leaf->mii_block : leaf->default_block;
3791bdb9230aSGarrett D'Amore
379298e8d175SSteven Stallion setup_block(dnetp);
3793bdb9230aSGarrett D'Amore /* XXX function return value ignored */
3794bdb9230aSGarrett D'Amore (void) mii_create(dip, dnet_mii_write, dnet_mii_read, &dnetp->mii);
3795bdb9230aSGarrett D'Amore
3796bdb9230aSGarrett D'Amore /*
3797bdb9230aSGarrett D'Amore * We try PHY 0 LAST because it is less likely to be connected
3798bdb9230aSGarrett D'Amore */
3799bdb9230aSGarrett D'Amore for (phy = 1; phy < 33; phy++)
3800bdb9230aSGarrett D'Amore if (mii_probe_phy(dnetp->mii, phy % 32) == MII_SUCCESS &&
3801bdb9230aSGarrett D'Amore mii_init_phy(dnetp->mii, phy % 32) == MII_SUCCESS) {
3802bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
3803bdb9230aSGarrett D'Amore if (dnetdebug & DNETSENSE)
3804bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "dnet: "
3805bdb9230aSGarrett D'Amore "PHY at address %d", phy % 32);
3806bdb9230aSGarrett D'Amore #endif
3807bdb9230aSGarrett D'Amore dnetp->phyaddr = phy % 32;
3808bdb9230aSGarrett D'Amore if (!leaf->mii_block) {
3809bdb9230aSGarrett D'Amore /* Legacy card, change the leaf node */
3810bdb9230aSGarrett D'Amore set_leaf(&dnetp->sr, &leaf_phylegacy);
3811bdb9230aSGarrett D'Amore }
3812bdb9230aSGarrett D'Amore return;
3813bdb9230aSGarrett D'Amore }
3814bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
3815bdb9230aSGarrett D'Amore if (dnetdebug & DNETSENSE)
3816bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "dnet: No PHY found");
3817bdb9230aSGarrett D'Amore #endif
3818bdb9230aSGarrett D'Amore }
3819bdb9230aSGarrett D'Amore
3820bdb9230aSGarrett D'Amore static ushort_t
dnet_mii_read(dev_info_t * dip,int phy_addr,int reg_num)3821bdb9230aSGarrett D'Amore dnet_mii_read(dev_info_t *dip, int phy_addr, int reg_num)
3822bdb9230aSGarrett D'Amore {
3823bdb9230aSGarrett D'Amore struct dnetinstance *dnetp;
3824bdb9230aSGarrett D'Amore
3825bdb9230aSGarrett D'Amore uint32_t command_word;
3826bdb9230aSGarrett D'Amore uint32_t tmp;
3827bdb9230aSGarrett D'Amore uint32_t data = 0;
3828bdb9230aSGarrett D'Amore int i;
3829bdb9230aSGarrett D'Amore int bits_in_ushort = ((sizeof (ushort_t))*8);
3830bdb9230aSGarrett D'Amore int turned_around = 0;
3831bdb9230aSGarrett D'Amore
383298e8d175SSteven Stallion dnetp = ddi_get_driver_private(dip);
3833bdb9230aSGarrett D'Amore
3834bdb9230aSGarrett D'Amore ASSERT(MUTEX_HELD(&dnetp->intrlock));
3835bdb9230aSGarrett D'Amore /* Write Preamble */
3836bdb9230aSGarrett D'Amore write_mii(dnetp, MII_PRE, 2*bits_in_ushort);
3837bdb9230aSGarrett D'Amore
3838bdb9230aSGarrett D'Amore /* Prepare command word */
3839bdb9230aSGarrett D'Amore command_word = (uint32_t)phy_addr << MII_PHY_ADDR_ALIGN;
3840bdb9230aSGarrett D'Amore command_word |= (uint32_t)reg_num << MII_REG_ADDR_ALIGN;
3841bdb9230aSGarrett D'Amore command_word |= MII_READ_FRAME;
3842bdb9230aSGarrett D'Amore
3843bdb9230aSGarrett D'Amore write_mii(dnetp, command_word, bits_in_ushort-2);
3844bdb9230aSGarrett D'Amore
3845bdb9230aSGarrett D'Amore mii_tristate(dnetp);
3846bdb9230aSGarrett D'Amore
3847bdb9230aSGarrett D'Amore /* Check that the PHY generated a zero bit the 2nd clock */
3848bdb9230aSGarrett D'Amore tmp = ddi_get32(dnetp->io_handle, REG32(dnetp->io_reg, ETHER_ROM_REG));
3849bdb9230aSGarrett D'Amore
3850bdb9230aSGarrett D'Amore turned_around = (tmp & MII_DATA_IN) ? 0 : 1;
3851bdb9230aSGarrett D'Amore
3852bdb9230aSGarrett D'Amore /* read data WORD */
3853bdb9230aSGarrett D'Amore for (i = 0; i < bits_in_ushort; i++) {
3854bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle,
3855bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, ETHER_ROM_REG), MII_READ);
3856bdb9230aSGarrett D'Amore drv_usecwait(MII_DELAY);
3857bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle,
3858bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, ETHER_ROM_REG), MII_READ | MII_CLOCK);
3859bdb9230aSGarrett D'Amore drv_usecwait(MII_DELAY);
3860bdb9230aSGarrett D'Amore tmp = ddi_get32(dnetp->io_handle,
3861bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, ETHER_ROM_REG));
3862bdb9230aSGarrett D'Amore drv_usecwait(MII_DELAY);
3863bdb9230aSGarrett D'Amore data = (data << 1) | (tmp >> MII_DATA_IN_POSITION) & 0x0001;
3864bdb9230aSGarrett D'Amore }
3865bdb9230aSGarrett D'Amore
3866bdb9230aSGarrett D'Amore mii_tristate(dnetp);
3867bdb9230aSGarrett D'Amore return (turned_around ? data: -1);
3868bdb9230aSGarrett D'Amore }
3869bdb9230aSGarrett D'Amore
3870bdb9230aSGarrett D'Amore static void
dnet_mii_write(dev_info_t * dip,int phy_addr,int reg_num,int reg_dat)3871bdb9230aSGarrett D'Amore dnet_mii_write(dev_info_t *dip, int phy_addr, int reg_num, int reg_dat)
3872bdb9230aSGarrett D'Amore {
3873bdb9230aSGarrett D'Amore struct dnetinstance *dnetp;
3874bdb9230aSGarrett D'Amore uint32_t command_word;
3875bdb9230aSGarrett D'Amore int bits_in_ushort = ((sizeof (ushort_t))*8);
3876bdb9230aSGarrett D'Amore
387798e8d175SSteven Stallion dnetp = ddi_get_driver_private(dip);
3878bdb9230aSGarrett D'Amore
3879bdb9230aSGarrett D'Amore ASSERT(MUTEX_HELD(&dnetp->intrlock));
3880bdb9230aSGarrett D'Amore write_mii(dnetp, MII_PRE, 2*bits_in_ushort);
3881bdb9230aSGarrett D'Amore
3882bdb9230aSGarrett D'Amore /* Prepare command word */
3883bdb9230aSGarrett D'Amore command_word = ((uint32_t)phy_addr << MII_PHY_ADDR_ALIGN);
3884bdb9230aSGarrett D'Amore command_word |= ((uint32_t)reg_num << MII_REG_ADDR_ALIGN);
3885bdb9230aSGarrett D'Amore command_word |= (MII_WRITE_FRAME | (uint32_t)reg_dat);
3886bdb9230aSGarrett D'Amore
3887bdb9230aSGarrett D'Amore write_mii(dnetp, command_word, 2*bits_in_ushort);
3888bdb9230aSGarrett D'Amore mii_tristate(dnetp);
3889bdb9230aSGarrett D'Amore }
3890bdb9230aSGarrett D'Amore
3891bdb9230aSGarrett D'Amore /*
3892bdb9230aSGarrett D'Amore * Write data size bits from mii_data to the MII control lines.
3893bdb9230aSGarrett D'Amore */
3894bdb9230aSGarrett D'Amore static void
write_mii(struct dnetinstance * dnetp,uint32_t mii_data,int data_size)3895bdb9230aSGarrett D'Amore write_mii(struct dnetinstance *dnetp, uint32_t mii_data, int data_size)
3896bdb9230aSGarrett D'Amore {
3897bdb9230aSGarrett D'Amore int i;
3898bdb9230aSGarrett D'Amore uint32_t dbit;
3899bdb9230aSGarrett D'Amore
3900bdb9230aSGarrett D'Amore ASSERT(MUTEX_HELD(&dnetp->intrlock));
3901bdb9230aSGarrett D'Amore for (i = data_size; i > 0; i--) {
3902bdb9230aSGarrett D'Amore dbit = ((mii_data >>
3903bdb9230aSGarrett D'Amore (31 - MII_WRITE_DATA_POSITION)) & MII_WRITE_DATA);
3904bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle,
3905bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, ETHER_ROM_REG),
3906bdb9230aSGarrett D'Amore MII_WRITE | dbit);
3907bdb9230aSGarrett D'Amore drv_usecwait(MII_DELAY);
3908bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle,
3909bdb9230aSGarrett D'Amore REG32(dnetp->io_reg, ETHER_ROM_REG),
3910bdb9230aSGarrett D'Amore MII_WRITE | MII_CLOCK | dbit);
3911bdb9230aSGarrett D'Amore drv_usecwait(MII_DELAY);
3912bdb9230aSGarrett D'Amore mii_data <<= 1;
3913bdb9230aSGarrett D'Amore }
3914bdb9230aSGarrett D'Amore }
3915bdb9230aSGarrett D'Amore
3916bdb9230aSGarrett D'Amore /*
3917bdb9230aSGarrett D'Amore * Put the MDIO port in tri-state for the turn around bits
3918bdb9230aSGarrett D'Amore * in MII read and at end of MII management sequence.
3919bdb9230aSGarrett D'Amore */
3920bdb9230aSGarrett D'Amore static void
mii_tristate(struct dnetinstance * dnetp)3921bdb9230aSGarrett D'Amore mii_tristate(struct dnetinstance *dnetp)
3922bdb9230aSGarrett D'Amore {
3923bdb9230aSGarrett D'Amore ASSERT(MUTEX_HELD(&dnetp->intrlock));
3924bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, ETHER_ROM_REG),
3925bdb9230aSGarrett D'Amore MII_WRITE_TS);
3926bdb9230aSGarrett D'Amore drv_usecwait(MII_DELAY);
3927bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, ETHER_ROM_REG),
3928bdb9230aSGarrett D'Amore MII_WRITE_TS | MII_CLOCK);
3929bdb9230aSGarrett D'Amore drv_usecwait(MII_DELAY);
3930bdb9230aSGarrett D'Amore }
3931bdb9230aSGarrett D'Amore
3932bdb9230aSGarrett D'Amore
3933bdb9230aSGarrett D'Amore static void
set_leaf(SROM_FORMAT * sr,LEAF_FORMAT * leaf)3934bdb9230aSGarrett D'Amore set_leaf(SROM_FORMAT *sr, LEAF_FORMAT *leaf)
3935bdb9230aSGarrett D'Amore {
3936bdb9230aSGarrett D'Amore if (sr->leaf && !sr->leaf->is_static)
3937bdb9230aSGarrett D'Amore kmem_free(sr->leaf, sr->adapters * sizeof (LEAF_FORMAT));
3938bdb9230aSGarrett D'Amore sr->leaf = leaf;
3939bdb9230aSGarrett D'Amore }
3940bdb9230aSGarrett D'Amore
3941bdb9230aSGarrett D'Amore /*
3942bdb9230aSGarrett D'Amore * Callback from MII module. Makes sure that the CSR registers are
3943bdb9230aSGarrett D'Amore * configured properly if the PHY changes mode.
3944bdb9230aSGarrett D'Amore */
3945bdb9230aSGarrett D'Amore /* ARGSUSED */
3946bdb9230aSGarrett D'Amore /* dnet_mii_link_cb - called with intrlock held */
3947bdb9230aSGarrett D'Amore static void
dnet_mii_link_cb(dev_info_t * dip,int phy,enum mii_phy_state state)3948bdb9230aSGarrett D'Amore dnet_mii_link_cb(dev_info_t *dip, int phy, enum mii_phy_state state)
3949bdb9230aSGarrett D'Amore {
395098e8d175SSteven Stallion struct dnetinstance *dnetp = ddi_get_driver_private(dip);
3951bdb9230aSGarrett D'Amore LEAF_FORMAT *leaf;
3952bdb9230aSGarrett D'Amore
3953bdb9230aSGarrett D'Amore ASSERT(MUTEX_HELD(&dnetp->intrlock));
395498e8d175SSteven Stallion
3955bdb9230aSGarrett D'Amore leaf = dnetp->sr.leaf + dnetp->leaf;
3956bdb9230aSGarrett D'Amore if (state == phy_state_linkup) {
3957bdb9230aSGarrett D'Amore dnetp->mii_up = 1;
395898e8d175SSteven Stallion
395998e8d175SSteven Stallion (void) mii_getspeed(dnetp->mii, dnetp->phyaddr,
396098e8d175SSteven Stallion &dnetp->mii_speed, &dnetp->mii_duplex);
396198e8d175SSteven Stallion
3962bdb9230aSGarrett D'Amore dnetp->selected_media_block = leaf->mii_block;
396398e8d175SSteven Stallion setup_block(dnetp);
3964bdb9230aSGarrett D'Amore } else {
3965bdb9230aSGarrett D'Amore /* NEEDSWORK: Probably can call find_active_media here */
3966bdb9230aSGarrett D'Amore dnetp->mii_up = 0;
396798e8d175SSteven Stallion
3968bdb9230aSGarrett D'Amore if (leaf->default_block->media_code == MEDIA_MII)
3969bdb9230aSGarrett D'Amore dnetp->selected_media_block = leaf->default_block;
397098e8d175SSteven Stallion setup_block(dnetp);
397198e8d175SSteven Stallion }
397298e8d175SSteven Stallion
397332607e28SSteven Stallion if (dnetp->running) {
397432607e28SSteven Stallion mac_link_update(dnetp->mac_handle,
397532607e28SSteven Stallion (dnetp->mii_up ? LINK_STATE_UP : LINK_STATE_DOWN));
3976bdb9230aSGarrett D'Amore }
3977bdb9230aSGarrett D'Amore }
3978bdb9230aSGarrett D'Amore
3979bdb9230aSGarrett D'Amore /*
3980bdb9230aSGarrett D'Amore * SROM parsing routines.
3981bdb9230aSGarrett D'Amore * Refer to the Digital 3.03 SROM spec while reading this! (references refer
3982bdb9230aSGarrett D'Amore * to this document)
3983bdb9230aSGarrett D'Amore * Where possible ALL vendor specific changes should be localised here. The
3984bdb9230aSGarrett D'Amore * SROM data should be capable of describing any programmatic irregularities
3985bdb9230aSGarrett D'Amore * of DNET cards (via SIA or GP registers, in particular), so vendor specific
3986bdb9230aSGarrett D'Amore * code elsewhere should not be required
3987bdb9230aSGarrett D'Amore */
3988bdb9230aSGarrett D'Amore static void
dnet_parse_srom(struct dnetinstance * dnetp,SROM_FORMAT * sr,uchar_t * vi)3989bdb9230aSGarrett D'Amore dnet_parse_srom(struct dnetinstance *dnetp, SROM_FORMAT *sr, uchar_t *vi)
3990bdb9230aSGarrett D'Amore {
3991bdb9230aSGarrett D'Amore uint32_t ether_mfg = 0;
3992bdb9230aSGarrett D'Amore int i;
3993bdb9230aSGarrett D'Amore uchar_t *p;
3994bdb9230aSGarrett D'Amore
3995bdb9230aSGarrett D'Amore if (!ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo,
3996bdb9230aSGarrett D'Amore DDI_PROP_DONTPASS, "no_sromconfig", 0))
3997bdb9230aSGarrett D'Amore dnetp->sr.init_from_srom = check_srom_valid(vi);
3998bdb9230aSGarrett D'Amore
3999bdb9230aSGarrett D'Amore if (dnetp->sr.init_from_srom && dnetp->board_type != DEVICE_ID_21040) {
4000bdb9230aSGarrett D'Amore /* Section 2/3: General SROM Format/ ID Block */
4001bdb9230aSGarrett D'Amore p = vi+18;
4002bdb9230aSGarrett D'Amore sr->version = *p++;
4003bdb9230aSGarrett D'Amore sr->adapters = *p++;
4004bdb9230aSGarrett D'Amore
4005bdb9230aSGarrett D'Amore sr->leaf =
4006bdb9230aSGarrett D'Amore kmem_zalloc(sr->adapters * sizeof (LEAF_FORMAT), KM_SLEEP);
4007bdb9230aSGarrett D'Amore for (i = 0; i < 6; i++)
4008bdb9230aSGarrett D'Amore sr->netaddr[i] = *p++;
4009bdb9230aSGarrett D'Amore
4010bdb9230aSGarrett D'Amore for (i = 0; i < sr->adapters; i++) {
4011bdb9230aSGarrett D'Amore uchar_t devno = *p++;
4012bdb9230aSGarrett D'Amore uint16_t offset = *p++;
4013bdb9230aSGarrett D'Amore offset |= *p++ << 8;
4014bdb9230aSGarrett D'Amore sr->leaf[i].device_number = devno;
4015bdb9230aSGarrett D'Amore parse_controller_leaf(dnetp, sr->leaf+i, vi+offset);
4016bdb9230aSGarrett D'Amore }
4017bdb9230aSGarrett D'Amore /*
4018bdb9230aSGarrett D'Amore * 'Orrible hack for cogent cards. The 6911A board seems to
4019bdb9230aSGarrett D'Amore * have an incorrect SROM. (From the OEMDEMO program
4020bdb9230aSGarrett D'Amore * supplied by cogent, it seems that the ROM matches a setup
4021bdb9230aSGarrett D'Amore * or a board with a QSI or ICS PHY.
4022bdb9230aSGarrett D'Amore */
4023bdb9230aSGarrett D'Amore for (i = 0; i < 3; i++)
4024bdb9230aSGarrett D'Amore ether_mfg = (ether_mfg << 8) | sr->netaddr[i];
4025bdb9230aSGarrett D'Amore
4026bdb9230aSGarrett D'Amore if (ether_mfg == ADAPTEC_ETHER) {
4027bdb9230aSGarrett D'Amore static uint16_t cogent_gprseq[] = {0x821, 0};
4028bdb9230aSGarrett D'Amore switch (vi[COGENT_SROM_ID]) {
4029bdb9230aSGarrett D'Amore case COGENT_ANA6911A_C:
4030bdb9230aSGarrett D'Amore case COGENT_ANA6911AC_C:
4031bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
4032bdb9230aSGarrett D'Amore if (dnetdebug & DNETTRACE)
4033bdb9230aSGarrett D'Amore cmn_err(CE_WARN,
4034bdb9230aSGarrett D'Amore "Suspected bad GPR sequence."
4035bdb9230aSGarrett D'Amore " Making a guess (821,0)");
4036bdb9230aSGarrett D'Amore #endif
4037bdb9230aSGarrett D'Amore
4038bdb9230aSGarrett D'Amore /* XXX function return value ignored */
4039bdb9230aSGarrett D'Amore (void) ddi_prop_update_byte_array(
4040bdb9230aSGarrett D'Amore DDI_DEV_T_NONE, dnetp->devinfo,
4041bdb9230aSGarrett D'Amore "gpr-sequence", (uchar_t *)cogent_gprseq,
4042bdb9230aSGarrett D'Amore sizeof (cogent_gprseq));
4043bdb9230aSGarrett D'Amore break;
4044bdb9230aSGarrett D'Amore }
4045bdb9230aSGarrett D'Amore }
4046bdb9230aSGarrett D'Amore } else {
4047bdb9230aSGarrett D'Amore /*
4048bdb9230aSGarrett D'Amore * Adhoc SROM, check for some cards which need special handling
4049bdb9230aSGarrett D'Amore * Assume vendor info contains ether address in first six bytes
4050bdb9230aSGarrett D'Amore */
4051bdb9230aSGarrett D'Amore
4052bdb9230aSGarrett D'Amore uchar_t *mac = vi + ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo,
4053bdb9230aSGarrett D'Amore DDI_PROP_DONTPASS, macoffset_propname, 0);
4054bdb9230aSGarrett D'Amore
4055bdb9230aSGarrett D'Amore for (i = 0; i < 6; i++)
4056bdb9230aSGarrett D'Amore sr->netaddr[i] = mac[i];
4057bdb9230aSGarrett D'Amore
4058bdb9230aSGarrett D'Amore if (dnetp->board_type == DEVICE_ID_21140) {
4059bdb9230aSGarrett D'Amore for (i = 0; i < 3; i++)
4060bdb9230aSGarrett D'Amore ether_mfg = (ether_mfg << 8) | mac[i];
4061bdb9230aSGarrett D'Amore
4062bdb9230aSGarrett D'Amore switch (ether_mfg) {
4063bdb9230aSGarrett D'Amore case ASANTE_ETHER:
4064bdb9230aSGarrett D'Amore dnetp->vendor_21140 = ASANTE_TYPE;
4065bdb9230aSGarrett D'Amore dnetp->vendor_revision = 0;
4066bdb9230aSGarrett D'Amore set_leaf(sr, &leaf_asante);
4067bdb9230aSGarrett D'Amore sr->adapters = 1;
4068bdb9230aSGarrett D'Amore break;
4069bdb9230aSGarrett D'Amore
4070bdb9230aSGarrett D'Amore case COGENT_ETHER:
4071bdb9230aSGarrett D'Amore case ADAPTEC_ETHER:
4072bdb9230aSGarrett D'Amore dnetp->vendor_21140 = COGENT_EM_TYPE;
4073bdb9230aSGarrett D'Amore dnetp->vendor_revision =
4074bdb9230aSGarrett D'Amore vi[VENDOR_REVISION_OFFSET];
4075bdb9230aSGarrett D'Amore set_leaf(sr, &leaf_cogent_100);
4076bdb9230aSGarrett D'Amore sr->adapters = 1;
4077bdb9230aSGarrett D'Amore break;
4078bdb9230aSGarrett D'Amore
4079bdb9230aSGarrett D'Amore default:
4080bdb9230aSGarrett D'Amore dnetp->vendor_21140 = DEFAULT_TYPE;
4081bdb9230aSGarrett D'Amore dnetp->vendor_revision = 0;
4082bdb9230aSGarrett D'Amore set_leaf(sr, &leaf_default_100);
4083bdb9230aSGarrett D'Amore sr->adapters = 1;
4084bdb9230aSGarrett D'Amore break;
4085bdb9230aSGarrett D'Amore }
4086bdb9230aSGarrett D'Amore } else if (dnetp->board_type == DEVICE_ID_21041) {
4087bdb9230aSGarrett D'Amore set_leaf(sr, &leaf_21041);
4088bdb9230aSGarrett D'Amore } else if (dnetp->board_type == DEVICE_ID_21040) {
4089bdb9230aSGarrett D'Amore set_leaf(sr, &leaf_21040);
4090bdb9230aSGarrett D'Amore }
4091bdb9230aSGarrett D'Amore }
4092bdb9230aSGarrett D'Amore }
4093bdb9230aSGarrett D'Amore
4094bdb9230aSGarrett D'Amore /* Section 4.2, 4.3, 4.4, 4.5 */
4095bdb9230aSGarrett D'Amore static void
parse_controller_leaf(struct dnetinstance * dnetp,LEAF_FORMAT * leaf,uchar_t * vi)4096bdb9230aSGarrett D'Amore parse_controller_leaf(struct dnetinstance *dnetp, LEAF_FORMAT *leaf,
4097bdb9230aSGarrett D'Amore uchar_t *vi)
4098bdb9230aSGarrett D'Amore {
4099bdb9230aSGarrett D'Amore int i;
4100bdb9230aSGarrett D'Amore
4101bdb9230aSGarrett D'Amore leaf->selected_contype = *vi++;
4102bdb9230aSGarrett D'Amore leaf->selected_contype |= *vi++ << 8;
4103bdb9230aSGarrett D'Amore
4104bdb9230aSGarrett D'Amore if (dnetp->board_type == DEVICE_ID_21140) /* Sect. 4.3 */
4105bdb9230aSGarrett D'Amore leaf->gpr = *vi++;
4106bdb9230aSGarrett D'Amore
4107bdb9230aSGarrett D'Amore leaf->block_count = *vi++;
4108bdb9230aSGarrett D'Amore
4109bdb9230aSGarrett D'Amore if (leaf->block_count > MAX_MEDIA) {
4110bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "dnet: Too many media in SROM!");
4111bdb9230aSGarrett D'Amore leaf->block_count = 1;
4112bdb9230aSGarrett D'Amore }
4113bdb9230aSGarrett D'Amore for (i = 0; i <= leaf->block_count; i++) {
4114bdb9230aSGarrett D'Amore vi = parse_media_block(dnetp, leaf->block + i, vi);
4115bdb9230aSGarrett D'Amore if (leaf->block[i].command & CMD_DEFAULT_MEDIUM)
4116bdb9230aSGarrett D'Amore leaf->default_block = leaf->block+i;
4117bdb9230aSGarrett D'Amore }
4118bdb9230aSGarrett D'Amore /* No explicit default block: use last in the ROM */
4119bdb9230aSGarrett D'Amore if (leaf->default_block == NULL)
4120bdb9230aSGarrett D'Amore leaf->default_block = leaf->block + leaf->block_count -1;
4121bdb9230aSGarrett D'Amore
4122bdb9230aSGarrett D'Amore }
4123bdb9230aSGarrett D'Amore
4124bdb9230aSGarrett D'Amore static uchar_t *
parse_media_block(struct dnetinstance * dnetp,media_block_t * block,uchar_t * vi)4125bdb9230aSGarrett D'Amore parse_media_block(struct dnetinstance *dnetp, media_block_t *block, uchar_t *vi)
4126bdb9230aSGarrett D'Amore {
4127bdb9230aSGarrett D'Amore int i;
4128bdb9230aSGarrett D'Amore
4129bdb9230aSGarrett D'Amore /*
4130bdb9230aSGarrett D'Amore * There are three kinds of media block we need to worry about:
4131bdb9230aSGarrett D'Amore * The 21041 blocks.
4132bdb9230aSGarrett D'Amore * 21140 blocks from a version 1 SROM
4133bdb9230aSGarrett D'Amore * 2114[023] block from a version 3 SROM
4134bdb9230aSGarrett D'Amore */
4135bdb9230aSGarrett D'Amore
4136bdb9230aSGarrett D'Amore if (dnetp->board_type == DEVICE_ID_21041) {
4137bdb9230aSGarrett D'Amore /* Section 4.2 */
4138bdb9230aSGarrett D'Amore block->media_code = *vi & 0x3f;
4139bdb9230aSGarrett D'Amore block->type = 2;
4140bdb9230aSGarrett D'Amore if (*vi++ & 0x40) {
4141bdb9230aSGarrett D'Amore block->un.sia.csr13 = *vi++;
4142bdb9230aSGarrett D'Amore block->un.sia.csr13 |= *vi++ << 8;
4143bdb9230aSGarrett D'Amore block->un.sia.csr14 = *vi++;
4144bdb9230aSGarrett D'Amore block->un.sia.csr14 |= *vi++ << 8;
4145bdb9230aSGarrett D'Amore block->un.sia.csr15 = *vi++;
4146bdb9230aSGarrett D'Amore block->un.sia.csr15 |= *vi++ << 8;
4147bdb9230aSGarrett D'Amore } else {
4148bdb9230aSGarrett D'Amore /* No media data (csrs 13,14,15). Insert defaults */
4149bdb9230aSGarrett D'Amore switch (block->media_code) {
4150bdb9230aSGarrett D'Amore case MEDIA_TP:
4151bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0xef01;
4152bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x7f3f;
4153bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x0008;
4154bdb9230aSGarrett D'Amore break;
4155bdb9230aSGarrett D'Amore case MEDIA_TP_FD:
4156bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0xef01;
4157bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x7f3d;
4158bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x0008;
4159bdb9230aSGarrett D'Amore break;
4160bdb9230aSGarrett D'Amore case MEDIA_BNC:
4161bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0xef09;
4162bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x0705;
4163bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x0006;
4164bdb9230aSGarrett D'Amore break;
4165bdb9230aSGarrett D'Amore case MEDIA_AUI:
4166bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0xef09;
4167bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x0705;
4168bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x000e;
4169bdb9230aSGarrett D'Amore break;
4170bdb9230aSGarrett D'Amore }
4171bdb9230aSGarrett D'Amore }
4172bdb9230aSGarrett D'Amore } else if (*vi & 0x80) { /* Extended format: Section 4.3.2.2 */
4173bdb9230aSGarrett D'Amore int blocklen = *vi++ & 0x7f;
4174bdb9230aSGarrett D'Amore block->type = *vi++;
4175bdb9230aSGarrett D'Amore switch (block->type) {
4176bdb9230aSGarrett D'Amore case 0: /* "non-MII": Section 4.3.2.2.1 */
4177bdb9230aSGarrett D'Amore block->media_code = (*vi++) & 0x3f;
4178bdb9230aSGarrett D'Amore block->gprseqlen = 1;
4179bdb9230aSGarrett D'Amore block->gprseq[0] = *vi++;
4180bdb9230aSGarrett D'Amore block->command = *vi++;
4181bdb9230aSGarrett D'Amore block->command |= *vi++ << 8;
4182bdb9230aSGarrett D'Amore break;
4183bdb9230aSGarrett D'Amore
4184bdb9230aSGarrett D'Amore case 1: /* MII/PHY: Section 4.3.2.2.2 */
4185bdb9230aSGarrett D'Amore block->command = CMD_PS;
4186bdb9230aSGarrett D'Amore block->media_code = MEDIA_MII;
4187bdb9230aSGarrett D'Amore /* This is whats needed in CSR6 */
4188bdb9230aSGarrett D'Amore
4189bdb9230aSGarrett D'Amore block->un.mii.phy_num = *vi++;
4190bdb9230aSGarrett D'Amore block->gprseqlen = *vi++;
4191bdb9230aSGarrett D'Amore
4192bdb9230aSGarrett D'Amore for (i = 0; i < block->gprseqlen; i++)
4193bdb9230aSGarrett D'Amore block->gprseq[i] = *vi++;
4194bdb9230aSGarrett D'Amore block->rstseqlen = *vi++;
4195bdb9230aSGarrett D'Amore for (i = 0; i < block->rstseqlen; i++)
4196bdb9230aSGarrett D'Amore block->rstseq[i] = *vi++;
4197bdb9230aSGarrett D'Amore
4198bdb9230aSGarrett D'Amore block->un.mii.mediacaps = *vi++;
4199bdb9230aSGarrett D'Amore block->un.mii.mediacaps |= *vi++ << 8;
4200bdb9230aSGarrett D'Amore block->un.mii.nwayadvert = *vi++;
4201bdb9230aSGarrett D'Amore block->un.mii.nwayadvert |= *vi++ << 8;
4202bdb9230aSGarrett D'Amore block->un.mii.fdxmask = *vi++;
4203bdb9230aSGarrett D'Amore block->un.mii.fdxmask |= *vi++ << 8;
4204bdb9230aSGarrett D'Amore block->un.mii.ttmmask = *vi++;
4205bdb9230aSGarrett D'Amore block->un.mii.ttmmask |= *vi++ << 8;
4206bdb9230aSGarrett D'Amore break;
4207bdb9230aSGarrett D'Amore
4208bdb9230aSGarrett D'Amore case 2: /* SIA Media: Section 4.4.2.1.1 */
4209bdb9230aSGarrett D'Amore block->media_code = *vi & 0x3f;
4210bdb9230aSGarrett D'Amore if (*vi++ & 0x40) {
4211bdb9230aSGarrett D'Amore block->un.sia.csr13 = *vi++;
4212bdb9230aSGarrett D'Amore block->un.sia.csr13 |= *vi++ << 8;
4213bdb9230aSGarrett D'Amore block->un.sia.csr14 = *vi++;
4214bdb9230aSGarrett D'Amore block->un.sia.csr14 |= *vi++ << 8;
4215bdb9230aSGarrett D'Amore block->un.sia.csr15 = *vi++;
4216bdb9230aSGarrett D'Amore block->un.sia.csr15 |= *vi++ << 8;
4217bdb9230aSGarrett D'Amore } else {
4218bdb9230aSGarrett D'Amore /*
4219bdb9230aSGarrett D'Amore * SIA values not provided by SROM; provide
4220bdb9230aSGarrett D'Amore * defaults. See appendix D of 2114[23] manuals.
4221bdb9230aSGarrett D'Amore */
4222bdb9230aSGarrett D'Amore switch (block->media_code) {
4223bdb9230aSGarrett D'Amore case MEDIA_BNC:
4224bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0x0009;
4225bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x0705;
4226bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x0000;
4227bdb9230aSGarrett D'Amore break;
4228bdb9230aSGarrett D'Amore case MEDIA_AUI:
4229bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0x0009;
4230bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x0705;
4231bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x0008;
4232bdb9230aSGarrett D'Amore break;
4233bdb9230aSGarrett D'Amore case MEDIA_TP:
4234bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0x0001;
4235bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x7f3f;
4236bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x0000;
4237bdb9230aSGarrett D'Amore break;
4238bdb9230aSGarrett D'Amore case MEDIA_TP_FD:
4239bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0x0001;
4240bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x7f3d;
4241bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x0000;
4242bdb9230aSGarrett D'Amore break;
4243bdb9230aSGarrett D'Amore default:
4244bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0x0000;
4245bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x0000;
4246bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x0000;
4247bdb9230aSGarrett D'Amore }
4248bdb9230aSGarrett D'Amore }
4249bdb9230aSGarrett D'Amore
4250bdb9230aSGarrett D'Amore /* Treat GP control/data as a GPR sequence */
4251bdb9230aSGarrett D'Amore block->gprseqlen = 2;
4252bdb9230aSGarrett D'Amore block->gprseq[0] = *vi++;
4253bdb9230aSGarrett D'Amore block->gprseq[0] |= *vi++ << 8;
4254bdb9230aSGarrett D'Amore block->gprseq[0] |= GPR_CONTROL_WRITE;
4255bdb9230aSGarrett D'Amore block->gprseq[1] = *vi++;
4256bdb9230aSGarrett D'Amore block->gprseq[1] |= *vi++ << 8;
4257bdb9230aSGarrett D'Amore break;
4258bdb9230aSGarrett D'Amore
4259bdb9230aSGarrett D'Amore case 3: /* MII/PHY : Section 4.4.2.1.2 */
4260bdb9230aSGarrett D'Amore block->command = CMD_PS;
4261bdb9230aSGarrett D'Amore block->media_code = MEDIA_MII;
4262bdb9230aSGarrett D'Amore block->un.mii.phy_num = *vi++;
4263bdb9230aSGarrett D'Amore
4264bdb9230aSGarrett D'Amore block->gprseqlen = *vi++;
4265bdb9230aSGarrett D'Amore for (i = 0; i < block->gprseqlen; i++) {
4266bdb9230aSGarrett D'Amore block->gprseq[i] = *vi++;
4267bdb9230aSGarrett D'Amore block->gprseq[i] |= *vi++ << 8;
4268bdb9230aSGarrett D'Amore }
4269bdb9230aSGarrett D'Amore
4270bdb9230aSGarrett D'Amore block->rstseqlen = *vi++;
4271bdb9230aSGarrett D'Amore for (i = 0; i < block->rstseqlen; i++) {
4272bdb9230aSGarrett D'Amore block->rstseq[i] = *vi++;
4273bdb9230aSGarrett D'Amore block->rstseq[i] |= *vi++ << 8;
4274bdb9230aSGarrett D'Amore }
4275bdb9230aSGarrett D'Amore block->un.mii.mediacaps = *vi++;
4276bdb9230aSGarrett D'Amore block->un.mii.mediacaps |= *vi++ << 8;
4277bdb9230aSGarrett D'Amore block->un.mii.nwayadvert = *vi++;
4278bdb9230aSGarrett D'Amore block->un.mii.nwayadvert |= *vi++ << 8;
4279bdb9230aSGarrett D'Amore block->un.mii.fdxmask = *vi++;
4280bdb9230aSGarrett D'Amore block->un.mii.fdxmask |= *vi++ << 8;
4281bdb9230aSGarrett D'Amore block->un.mii.ttmmask = *vi++;
4282bdb9230aSGarrett D'Amore block->un.mii.ttmmask |= *vi++ << 8;
4283bdb9230aSGarrett D'Amore block->un.mii.miiintr |= *vi++;
4284bdb9230aSGarrett D'Amore break;
4285bdb9230aSGarrett D'Amore
4286bdb9230aSGarrett D'Amore case 4: /* SYM Media: 4.5.2.1.3 */
4287bdb9230aSGarrett D'Amore block->media_code = *vi++ & 0x3f;
4288bdb9230aSGarrett D'Amore /* Treat GP control and data as a GPR sequence */
4289bdb9230aSGarrett D'Amore block->gprseqlen = 2;
4290bdb9230aSGarrett D'Amore block->gprseq[0] = *vi++;
4291bdb9230aSGarrett D'Amore block->gprseq[0] |= *vi++ << 8;
4292bdb9230aSGarrett D'Amore block->gprseq[0] |= GPR_CONTROL_WRITE;
4293bdb9230aSGarrett D'Amore block->gprseq[1] = *vi++;
4294bdb9230aSGarrett D'Amore block->gprseq[1] |= *vi++ << 8;
4295bdb9230aSGarrett D'Amore block->command = *vi++;
4296bdb9230aSGarrett D'Amore block->command |= *vi++ << 8;
4297bdb9230aSGarrett D'Amore break;
4298bdb9230aSGarrett D'Amore
4299bdb9230aSGarrett D'Amore case 5: /* GPR reset sequence: Section 4.5.2.1.4 */
4300bdb9230aSGarrett D'Amore block->rstseqlen = *vi++;
4301bdb9230aSGarrett D'Amore for (i = 0; i < block->rstseqlen; i++)
4302bdb9230aSGarrett D'Amore block->rstseq[i] = *vi++;
4303bdb9230aSGarrett D'Amore break;
4304bdb9230aSGarrett D'Amore
4305bdb9230aSGarrett D'Amore default: /* Unknown media block. Skip it. */
4306bdb9230aSGarrett D'Amore cmn_err(CE_WARN, "dnet: Unsupported SROM block.");
4307bdb9230aSGarrett D'Amore vi += blocklen;
4308bdb9230aSGarrett D'Amore break;
4309bdb9230aSGarrett D'Amore }
4310bdb9230aSGarrett D'Amore } else { /* Compact format (or V1 SROM): Section 4.3.2.1 */
4311bdb9230aSGarrett D'Amore block->type = 0;
4312bdb9230aSGarrett D'Amore block->media_code = *vi++ & 0x3f;
4313bdb9230aSGarrett D'Amore block->gprseqlen = 1;
4314bdb9230aSGarrett D'Amore block->gprseq[0] = *vi++;
4315bdb9230aSGarrett D'Amore block->command = *vi++;
4316bdb9230aSGarrett D'Amore block->command |= (*vi++) << 8;
4317bdb9230aSGarrett D'Amore }
4318bdb9230aSGarrett D'Amore return (vi);
4319bdb9230aSGarrett D'Amore }
4320bdb9230aSGarrett D'Amore
4321bdb9230aSGarrett D'Amore
4322bdb9230aSGarrett D'Amore /*
4323bdb9230aSGarrett D'Amore * An alternative to doing this would be to store the legacy ROMs in binary
4324bdb9230aSGarrett D'Amore * format in the conf file, and in read_srom, pick out the data. This would
4325bdb9230aSGarrett D'Amore * then allow the parser to continue on as normal. This makes it a little
4326bdb9230aSGarrett D'Amore * easier to read.
4327bdb9230aSGarrett D'Amore */
4328bdb9230aSGarrett D'Amore static void
setup_legacy_blocks()4329bdb9230aSGarrett D'Amore setup_legacy_blocks()
4330bdb9230aSGarrett D'Amore {
4331bdb9230aSGarrett D'Amore LEAF_FORMAT *leaf;
4332bdb9230aSGarrett D'Amore media_block_t *block;
4333bdb9230aSGarrett D'Amore
4334bdb9230aSGarrett D'Amore /* Default FAKE SROM */
4335bdb9230aSGarrett D'Amore leaf = &leaf_default_100;
4336bdb9230aSGarrett D'Amore leaf->is_static = 1;
4337bdb9230aSGarrett D'Amore leaf->default_block = &leaf->block[3];
4338bdb9230aSGarrett D'Amore leaf->block_count = 4; /* 100 cards are highly unlikely to have BNC */
4339bdb9230aSGarrett D'Amore block = leaf->block;
4340bdb9230aSGarrett D'Amore block->media_code = MEDIA_TP_FD;
4341bdb9230aSGarrett D'Amore block->type = 0;
4342bdb9230aSGarrett D'Amore block->command = 0x8e; /* PCS, PS off, media sense: bit7, pol=1 */
4343bdb9230aSGarrett D'Amore block++;
4344bdb9230aSGarrett D'Amore block->media_code = MEDIA_TP;
4345bdb9230aSGarrett D'Amore block->type = 0;
4346bdb9230aSGarrett D'Amore block->command = 0x8e; /* PCS, PS off, media sense: bit7, pol=1 */
4347bdb9230aSGarrett D'Amore block++;
4348bdb9230aSGarrett D'Amore block->media_code = MEDIA_SYM_SCR_FD;
4349bdb9230aSGarrett D'Amore block->type = 0;
4350bdb9230aSGarrett D'Amore block->command = 0x6d; /* PCS, PS, SCR on, media sense: bit6, pol=0 */
4351bdb9230aSGarrett D'Amore block++;
4352bdb9230aSGarrett D'Amore block->media_code = MEDIA_SYM_SCR;
4353bdb9230aSGarrett D'Amore block->type = 0;
4354bdb9230aSGarrett D'Amore block->command = 0x406d; /* PCS, PS, SCR on, media sense: bit6, pol=0 */
4355bdb9230aSGarrett D'Amore
4356bdb9230aSGarrett D'Amore /* COGENT FAKE SROM */
4357bdb9230aSGarrett D'Amore leaf = &leaf_cogent_100;
4358bdb9230aSGarrett D'Amore leaf->is_static = 1;
4359bdb9230aSGarrett D'Amore leaf->default_block = &leaf->block[4];
4360bdb9230aSGarrett D'Amore leaf->block_count = 5; /* 100TX, 100TX-FD, 10T 10T-FD, BNC */
4361bdb9230aSGarrett D'Amore block = leaf->block; /* BNC */
4362bdb9230aSGarrett D'Amore block->media_code = MEDIA_BNC;
4363bdb9230aSGarrett D'Amore block->type = 0;
4364bdb9230aSGarrett D'Amore block->command = 0x8000; /* No media sense, PCS, SCR, PS all off */
4365bdb9230aSGarrett D'Amore block->gprseqlen = 2;
4366bdb9230aSGarrett D'Amore block->rstseqlen = 0;
4367bdb9230aSGarrett D'Amore block->gprseq[0] = 0x13f;
4368bdb9230aSGarrett D'Amore block->gprseq[1] = 1;
4369bdb9230aSGarrett D'Amore
4370bdb9230aSGarrett D'Amore block++;
4371bdb9230aSGarrett D'Amore block->media_code = MEDIA_TP_FD;
4372bdb9230aSGarrett D'Amore block->type = 0;
4373bdb9230aSGarrett D'Amore block->command = 0x8e; /* PCS, PS off, media sense: bit7, pol=1 */
4374bdb9230aSGarrett D'Amore block->gprseqlen = 2;
4375bdb9230aSGarrett D'Amore block->rstseqlen = 0;
4376bdb9230aSGarrett D'Amore block->gprseq[0] = 0x13f;
4377bdb9230aSGarrett D'Amore block->gprseq[1] = 0x26;
4378bdb9230aSGarrett D'Amore
4379bdb9230aSGarrett D'Amore block++; /* 10BaseT */
4380bdb9230aSGarrett D'Amore block->media_code = MEDIA_TP;
4381bdb9230aSGarrett D'Amore block->type = 0;
4382bdb9230aSGarrett D'Amore block->command = 0x8e; /* PCS, PS off, media sense: bit7, pol=1 */
4383bdb9230aSGarrett D'Amore block->gprseqlen = 2;
4384bdb9230aSGarrett D'Amore block->rstseqlen = 0;
4385bdb9230aSGarrett D'Amore block->gprseq[0] = 0x13f;
4386bdb9230aSGarrett D'Amore block->gprseq[1] = 0x3e;
4387bdb9230aSGarrett D'Amore
4388bdb9230aSGarrett D'Amore block++; /* 100BaseTX-FD */
4389bdb9230aSGarrett D'Amore block->media_code = MEDIA_SYM_SCR_FD;
4390bdb9230aSGarrett D'Amore block->type = 0;
4391bdb9230aSGarrett D'Amore block->command = 0x6d; /* PCS, PS, SCR on, media sense: bit6, pol=0 */
4392bdb9230aSGarrett D'Amore block->gprseqlen = 2;
4393bdb9230aSGarrett D'Amore block->rstseqlen = 0;
4394bdb9230aSGarrett D'Amore block->gprseq[0] = 0x13f;
4395bdb9230aSGarrett D'Amore block->gprseq[1] = 1;
4396bdb9230aSGarrett D'Amore
4397bdb9230aSGarrett D'Amore block++; /* 100BaseTX */
4398bdb9230aSGarrett D'Amore block->media_code = MEDIA_SYM_SCR;
4399bdb9230aSGarrett D'Amore block->type = 0;
4400bdb9230aSGarrett D'Amore block->command = 0x406d; /* PCS, PS, SCR on, media sense: bit6, pol=0 */
4401bdb9230aSGarrett D'Amore block->gprseqlen = 2;
4402bdb9230aSGarrett D'Amore block->rstseqlen = 0;
4403bdb9230aSGarrett D'Amore block->gprseq[0] = 0x13f;
4404bdb9230aSGarrett D'Amore block->gprseq[1] = 1;
4405bdb9230aSGarrett D'Amore
4406bdb9230aSGarrett D'Amore /* Generic legacy card with a PHY. */
4407bdb9230aSGarrett D'Amore leaf = &leaf_phylegacy;
4408bdb9230aSGarrett D'Amore leaf->block_count = 1;
4409bdb9230aSGarrett D'Amore leaf->mii_block = leaf->block;
4410bdb9230aSGarrett D'Amore leaf->default_block = &leaf->block[0];
4411bdb9230aSGarrett D'Amore leaf->is_static = 1;
4412bdb9230aSGarrett D'Amore block = leaf->block;
4413bdb9230aSGarrett D'Amore block->media_code = MEDIA_MII;
4414bdb9230aSGarrett D'Amore block->type = 1; /* MII Block type 1 */
4415bdb9230aSGarrett D'Amore block->command = 1; /* Port select */
4416bdb9230aSGarrett D'Amore block->gprseqlen = 0;
4417bdb9230aSGarrett D'Amore block->rstseqlen = 0;
4418bdb9230aSGarrett D'Amore
4419bdb9230aSGarrett D'Amore /* ASANTE FAKE SROM */
4420bdb9230aSGarrett D'Amore leaf = &leaf_asante;
4421bdb9230aSGarrett D'Amore leaf->is_static = 1;
4422bdb9230aSGarrett D'Amore leaf->default_block = &leaf->block[0];
4423bdb9230aSGarrett D'Amore leaf->block_count = 1;
4424bdb9230aSGarrett D'Amore block = leaf->block;
4425bdb9230aSGarrett D'Amore block->media_code = MEDIA_MII;
4426bdb9230aSGarrett D'Amore block->type = 1; /* MII Block type 1 */
4427bdb9230aSGarrett D'Amore block->command = 1; /* Port select */
4428bdb9230aSGarrett D'Amore block->gprseqlen = 3;
4429bdb9230aSGarrett D'Amore block->rstseqlen = 0;
4430bdb9230aSGarrett D'Amore block->gprseq[0] = 0x180;
4431bdb9230aSGarrett D'Amore block->gprseq[1] = 0x80;
4432bdb9230aSGarrett D'Amore block->gprseq[2] = 0x0;
4433bdb9230aSGarrett D'Amore
4434bdb9230aSGarrett D'Amore /* LEGACY 21041 card FAKE SROM */
4435bdb9230aSGarrett D'Amore leaf = &leaf_21041;
4436bdb9230aSGarrett D'Amore leaf->is_static = 1;
4437bdb9230aSGarrett D'Amore leaf->block_count = 4; /* SIA Blocks for TP, TPfd, BNC, AUI */
4438bdb9230aSGarrett D'Amore leaf->default_block = &leaf->block[3];
4439bdb9230aSGarrett D'Amore
4440bdb9230aSGarrett D'Amore block = leaf->block;
4441bdb9230aSGarrett D'Amore block->media_code = MEDIA_AUI;
4442bdb9230aSGarrett D'Amore block->type = 2;
4443bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0xef09;
4444bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x0705;
4445bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x000e;
4446bdb9230aSGarrett D'Amore
4447bdb9230aSGarrett D'Amore block++;
4448bdb9230aSGarrett D'Amore block->media_code = MEDIA_TP_FD;
4449bdb9230aSGarrett D'Amore block->type = 2;
4450bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0xef01;
4451bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x7f3d;
4452bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x0008;
4453bdb9230aSGarrett D'Amore
4454bdb9230aSGarrett D'Amore block++;
4455bdb9230aSGarrett D'Amore block->media_code = MEDIA_BNC;
4456bdb9230aSGarrett D'Amore block->type = 2;
4457bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0xef09;
4458bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x0705;
4459bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x0006;
4460bdb9230aSGarrett D'Amore
4461bdb9230aSGarrett D'Amore block++;
4462bdb9230aSGarrett D'Amore block->media_code = MEDIA_TP;
4463bdb9230aSGarrett D'Amore block->type = 2;
4464bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0xef01;
4465bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x7f3f;
4466bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x0008;
4467bdb9230aSGarrett D'Amore
4468bdb9230aSGarrett D'Amore /* LEGACY 21040 card FAKE SROM */
4469bdb9230aSGarrett D'Amore leaf = &leaf_21040;
4470bdb9230aSGarrett D'Amore leaf->is_static = 1;
4471bdb9230aSGarrett D'Amore leaf->block_count = 4; /* SIA Blocks for TP, TPfd, BNC, AUI */
4472bdb9230aSGarrett D'Amore block = leaf->block;
4473bdb9230aSGarrett D'Amore block->media_code = MEDIA_AUI;
4474bdb9230aSGarrett D'Amore block->type = 2;
4475bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0x8f09;
4476bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x0705;
4477bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x000e;
4478bdb9230aSGarrett D'Amore block++;
4479bdb9230aSGarrett D'Amore block->media_code = MEDIA_TP_FD;
4480bdb9230aSGarrett D'Amore block->type = 2;
4481bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0x0f01;
4482bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x7f3d;
4483bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x0008;
4484bdb9230aSGarrett D'Amore block++;
4485bdb9230aSGarrett D'Amore block->media_code = MEDIA_BNC;
4486bdb9230aSGarrett D'Amore block->type = 2;
4487bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0xef09;
4488bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x0705;
4489bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x0006;
4490bdb9230aSGarrett D'Amore block++;
4491bdb9230aSGarrett D'Amore block->media_code = MEDIA_TP;
4492bdb9230aSGarrett D'Amore block->type = 2;
4493bdb9230aSGarrett D'Amore block->un.sia.csr13 = 0x8f01;
4494bdb9230aSGarrett D'Amore block->un.sia.csr14 = 0x7f3f;
4495bdb9230aSGarrett D'Amore block->un.sia.csr15 = 0x0008;
4496bdb9230aSGarrett D'Amore }
4497bdb9230aSGarrett D'Amore
4498bdb9230aSGarrett D'Amore static void
dnet_print_srom(SROM_FORMAT * sr)4499bdb9230aSGarrett D'Amore dnet_print_srom(SROM_FORMAT *sr)
4500bdb9230aSGarrett D'Amore {
4501bdb9230aSGarrett D'Amore int i;
4502bdb9230aSGarrett D'Amore uchar_t *a = sr->netaddr;
4503bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "SROM Dump: %d. ver %d, Num adapters %d,"
4504bdb9230aSGarrett D'Amore "Addr:%x:%x:%x:%x:%x:%x",
4505bdb9230aSGarrett D'Amore sr->init_from_srom, sr->version, sr->adapters,
4506bdb9230aSGarrett D'Amore a[0], a[1], a[2], a[3], a[4], a[5]);
4507bdb9230aSGarrett D'Amore
4508bdb9230aSGarrett D'Amore for (i = 0; i < sr->adapters; i++)
4509bdb9230aSGarrett D'Amore dnet_dump_leaf(sr->leaf+i);
4510bdb9230aSGarrett D'Amore }
4511bdb9230aSGarrett D'Amore
4512bdb9230aSGarrett D'Amore static void
dnet_dump_leaf(LEAF_FORMAT * leaf)4513bdb9230aSGarrett D'Amore dnet_dump_leaf(LEAF_FORMAT *leaf)
4514bdb9230aSGarrett D'Amore {
4515bdb9230aSGarrett D'Amore int i;
4516bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "Leaf: Device %d, block_count %d, gpr: %x",
4517bdb9230aSGarrett D'Amore leaf->device_number, leaf->block_count, leaf->gpr);
4518bdb9230aSGarrett D'Amore for (i = 0; i < leaf->block_count; i++)
4519bdb9230aSGarrett D'Amore dnet_dump_block(leaf->block+i);
4520bdb9230aSGarrett D'Amore }
4521bdb9230aSGarrett D'Amore
4522bdb9230aSGarrett D'Amore static void
dnet_dump_block(media_block_t * block)4523bdb9230aSGarrett D'Amore dnet_dump_block(media_block_t *block)
4524bdb9230aSGarrett D'Amore {
4525bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "Block(%p): type %x, media %s, command: %x ",
4526bdb9230aSGarrett D'Amore (void *)block,
4527bdb9230aSGarrett D'Amore block->type, media_str[block->media_code], block->command);
4528bdb9230aSGarrett D'Amore dnet_dumpbin("\tGPR Seq", (uchar_t *)block->gprseq, 2,
4529bdb9230aSGarrett D'Amore block->gprseqlen *2);
4530bdb9230aSGarrett D'Amore dnet_dumpbin("\tGPR Reset", (uchar_t *)block->rstseq, 2,
4531bdb9230aSGarrett D'Amore block->rstseqlen *2);
4532bdb9230aSGarrett D'Amore switch (block->type) {
4533bdb9230aSGarrett D'Amore case 1: case 3:
4534bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "\tMII Info: phy %d, nway %x, fdx"
4535bdb9230aSGarrett D'Amore "%x, ttm %x, mediacap %x",
4536bdb9230aSGarrett D'Amore block->un.mii.phy_num, block->un.mii.nwayadvert,
4537bdb9230aSGarrett D'Amore block->un.mii.fdxmask, block->un.mii.ttmmask,
4538bdb9230aSGarrett D'Amore block->un.mii.mediacaps);
4539bdb9230aSGarrett D'Amore break;
4540bdb9230aSGarrett D'Amore case 2:
4541bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "\tSIA Regs: CSR13:%x, CSR14:%x, CSR15:%x",
4542bdb9230aSGarrett D'Amore block->un.sia.csr13, block->un.sia.csr14,
4543bdb9230aSGarrett D'Amore block->un.sia.csr15);
4544bdb9230aSGarrett D'Amore break;
4545bdb9230aSGarrett D'Amore }
4546bdb9230aSGarrett D'Amore }
4547bdb9230aSGarrett D'Amore
4548bdb9230aSGarrett D'Amore
4549bdb9230aSGarrett D'Amore /* Utility to print out binary info dumps. Handy for SROMs, etc */
4550bdb9230aSGarrett D'Amore
4551bdb9230aSGarrett D'Amore static int
hexcode(unsigned val)4552bdb9230aSGarrett D'Amore hexcode(unsigned val)
4553bdb9230aSGarrett D'Amore {
4554bdb9230aSGarrett D'Amore if (val <= 9)
4555bdb9230aSGarrett D'Amore return (val +'0');
4556bdb9230aSGarrett D'Amore if (val <= 15)
4557bdb9230aSGarrett D'Amore return (val + 'a' - 10);
4558bdb9230aSGarrett D'Amore return (-1);
4559bdb9230aSGarrett D'Amore }
4560bdb9230aSGarrett D'Amore
4561bdb9230aSGarrett D'Amore static void
dnet_dumpbin(char * msg,unsigned char * data,int size,int len)4562bdb9230aSGarrett D'Amore dnet_dumpbin(char *msg, unsigned char *data, int size, int len)
4563bdb9230aSGarrett D'Amore {
4564bdb9230aSGarrett D'Amore char hex[128], *p = hex;
4565bdb9230aSGarrett D'Amore char ascii[128], *q = ascii;
4566bdb9230aSGarrett D'Amore int i, j;
4567bdb9230aSGarrett D'Amore
4568bdb9230aSGarrett D'Amore if (!len)
4569bdb9230aSGarrett D'Amore return;
4570bdb9230aSGarrett D'Amore
4571bdb9230aSGarrett D'Amore for (i = 0; i < len; i += size) {
4572bdb9230aSGarrett D'Amore for (j = size - 1; j >= 0; j--) { /* PORTABILITY: byte order */
4573bdb9230aSGarrett D'Amore *p++ = hexcode(data[i+j] >> 4);
4574bdb9230aSGarrett D'Amore *p++ = hexcode(data[i+j] & 0xf);
4575bdb9230aSGarrett D'Amore *q++ = (data[i+j] < 32 || data[i+j] > 127) ?
4576bdb9230aSGarrett D'Amore '.' : data[i];
4577bdb9230aSGarrett D'Amore }
4578bdb9230aSGarrett D'Amore *p++ = ' ';
4579bdb9230aSGarrett D'Amore if (q-ascii >= 8) {
4580bdb9230aSGarrett D'Amore *p = *q = 0;
4581bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "%s: %s\t%s", msg, hex, ascii);
4582bdb9230aSGarrett D'Amore p = hex;
4583bdb9230aSGarrett D'Amore q = ascii;
4584bdb9230aSGarrett D'Amore }
4585bdb9230aSGarrett D'Amore }
4586bdb9230aSGarrett D'Amore if (p != hex) {
4587bdb9230aSGarrett D'Amore while ((p - hex) < 8*3)
4588bdb9230aSGarrett D'Amore *p++ = ' ';
4589bdb9230aSGarrett D'Amore *p = *q = 0;
4590bdb9230aSGarrett D'Amore cmn_err(CE_NOTE, "%s: %s\t%s", msg, hex, ascii);
4591bdb9230aSGarrett D'Amore }
4592bdb9230aSGarrett D'Amore }
4593bdb9230aSGarrett D'Amore
4594bdb9230aSGarrett D'Amore #ifdef DNETDEBUG
4595bdb9230aSGarrett D'Amore void
dnet_usectimeout(struct dnetinstance * dnetp,uint32_t usecs,int contin,timercb_t cback)4596bdb9230aSGarrett D'Amore dnet_usectimeout(struct dnetinstance *dnetp, uint32_t usecs, int contin,
4597bdb9230aSGarrett D'Amore timercb_t cback)
4598bdb9230aSGarrett D'Amore {
4599bdb9230aSGarrett D'Amore mutex_enter(&dnetp->intrlock);
4600bdb9230aSGarrett D'Amore dnetp->timer.start_ticks = (usecs * 100) / 8192;
4601bdb9230aSGarrett D'Amore dnetp->timer.cb = cback;
4602bdb9230aSGarrett D'Amore ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, GP_TIMER_REG),
4603bdb9230aSGarrett D'Amore dnetp->timer.start_ticks | (contin ? GPTIMER_CONT : 0));
4604bdb9230aSGarrett D'Amore if (dnetp->timer.cb)
460598e8d175SSteven Stallion enable_interrupts(dnetp);
4606bdb9230aSGarrett D'Amore mutex_exit(&dnetp->intrlock);
4607bdb9230aSGarrett D'Amore }
4608bdb9230aSGarrett D'Amore
4609bdb9230aSGarrett D'Amore uint32_t
dnet_usecelapsed(struct dnetinstance * dnetp)4610bdb9230aSGarrett D'Amore dnet_usecelapsed(struct dnetinstance *dnetp)
4611bdb9230aSGarrett D'Amore {
4612bdb9230aSGarrett D'Amore uint32_t ticks = dnetp->timer.start_ticks -
4613bdb9230aSGarrett D'Amore (ddi_get32(dnetp->io_handle, REG32(dnetp->io_reg, GP_TIMER_REG)) &
4614bdb9230aSGarrett D'Amore 0xffff);
4615bdb9230aSGarrett D'Amore return ((ticks * 8192) / 100);
4616bdb9230aSGarrett D'Amore }
4617bdb9230aSGarrett D'Amore
4618bdb9230aSGarrett D'Amore /* ARGSUSED */
4619bdb9230aSGarrett D'Amore void
dnet_timestamp(struct dnetinstance * dnetp,char * buf)4620bdb9230aSGarrett D'Amore dnet_timestamp(struct dnetinstance *dnetp, char *buf)
4621bdb9230aSGarrett D'Amore {
4622bdb9230aSGarrett D'Amore uint32_t elapsed = dnet_usecelapsed(dnetp);
4623bdb9230aSGarrett D'Amore char loc[32], *p = loc;
4624bdb9230aSGarrett D'Amore int firstdigit = 1;
4625bdb9230aSGarrett D'Amore uint32_t divisor;
4626bdb9230aSGarrett D'Amore
4627bdb9230aSGarrett D'Amore while (*p++ = *buf++)
4628bdb9230aSGarrett D'Amore ;
4629bdb9230aSGarrett D'Amore p--;
4630bdb9230aSGarrett D'Amore
4631bdb9230aSGarrett D'Amore for (divisor = 1000000000; divisor /= 10; ) {
4632bdb9230aSGarrett D'Amore int digit = (elapsed / divisor);
4633bdb9230aSGarrett D'Amore elapsed -= digit * divisor;
4634bdb9230aSGarrett D'Amore if (!firstdigit || digit) {
4635bdb9230aSGarrett D'Amore *p++ = digit + '0';
4636bdb9230aSGarrett D'Amore firstdigit = 0;
4637bdb9230aSGarrett D'Amore }
4638bdb9230aSGarrett D'Amore
4639bdb9230aSGarrett D'Amore }
4640bdb9230aSGarrett D'Amore
4641bdb9230aSGarrett D'Amore /* Actual zero, output it */
4642bdb9230aSGarrett D'Amore if (firstdigit)
4643bdb9230aSGarrett D'Amore *p++ = '0';
4644bdb9230aSGarrett D'Amore
4645bdb9230aSGarrett D'Amore *p++ = '-';
4646bdb9230aSGarrett D'Amore *p++ = '>';
4647bdb9230aSGarrett D'Amore *p++ = 0;
4648bdb9230aSGarrett D'Amore
4649bdb9230aSGarrett D'Amore printf(loc);
4650bdb9230aSGarrett D'Amore dnet_usectimeout(dnetp, 1000000, 0, 0);
4651bdb9230aSGarrett D'Amore }
4652bdb9230aSGarrett D'Amore
4653bdb9230aSGarrett D'Amore #endif
4654