blob: c18adaba347eff15cd60d9dbdf6a823c47827fd4 [file] [log] [blame]
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
petede447e4a62006-02-01 07:47:13 -08005 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07007 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
Zeeshanul Huq - Sun Microsystems - Beijing China7a92e702010-08-02 11:09:26 +080022 * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070023 */
24
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070025
26/*
27 * SunOS MT STREAMS FEPS(SBus)/Cheerio(PCI) 10/100Mb Ethernet Device Driver
28 */
29
30#include <sys/types.h>
31#include <sys/debug.h>
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070032#include <sys/stream.h>
33#include <sys/cmn_err.h>
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070034#include <sys/kmem.h>
35#include <sys/crc32.h>
gd7805985025c02007-07-12 10:37:47 -070036#include <sys/modctl.h>
37#include <sys/conf.h>
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070038#include <sys/strsun.h>
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070039#include <sys/kstat.h>
gd7805985025c02007-07-12 10:37:47 -070040#include <sys/pattr.h>
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070041#include <sys/dlpi.h>
gd7805985025c02007-07-12 10:37:47 -070042#include <sys/strsubr.h>
Eric Chengda14ceb2008-12-04 18:16:10 -080043#include <sys/mac_provider.h>
gd7805985025c02007-07-12 10:37:47 -070044#include <sys/mac_ether.h>
Garrett D'Amore06673d92009-10-15 22:31:12 -070045#include <sys/mii.h>
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070046#include <sys/ethernet.h>
yz147064d62bc4b2008-01-23 18:09:15 -080047#include <sys/vlan.h>
gd7805985025c02007-07-12 10:37:47 -070048#include <sys/pci.h>
49#include <sys/policy.h>
50#include <sys/ddi.h>
51#include <sys/sunddi.h>
Venugopal Iyer0dc23662010-03-09 15:30:01 -080052#include <sys/byteorder.h>
Garrett D'Amore02193462009-05-11 21:07:23 -070053#include "hme_phy.h"
54#include "hme_mac.h"
55#include "hme.h"
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070056
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070057typedef void (*fptrv_t)();
58
59typedef enum {
60 NO_MSG = 0,
Garrett D'Amore06673d92009-10-15 22:31:12 -070061 AUTOCONFIG_MSG,
62 DISPLAY_MSG,
63 INIT_MSG,
64 UNINIT_MSG,
65 CONFIG_MSG,
66 MII_MSG,
67 FATAL_ERR_MSG,
68 NFATAL_ERR_MSG,
69 XCVR_MSG,
70 NOXCVR_MSG,
71 ERX_MSG,
72 DDI_MSG,
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070073} msg_t;
74
75msg_t hme_debug_level = NO_MSG;
76
77static char *msg_string[] = {
78 "NONE ",
79 "AUTOCONFIG ",
Garrett D'Amore06673d92009-10-15 22:31:12 -070080 "DISPLAY "
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070081 "INIT ",
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070082 "UNINIT ",
83 "CONFIG ",
Garrett D'Amore06673d92009-10-15 22:31:12 -070084 "MII ",
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070085 "FATAL_ERR ",
86 "NFATAL_ERR ",
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070087 "XCVR ",
88 "NOXCVR ",
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070089 "ERX ",
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070090 "DDI ",
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070091};
92
93#define SEVERITY_NONE 0
94#define SEVERITY_LOW 0
95#define SEVERITY_MID 1
96#define SEVERITY_HIGH 2
97#define SEVERITY_UNKNOWN 99
98
99#define FEPS_URUN_BUG
100#define HME_CODEVIOL_BUG
101
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700102#define KIOIP KSTAT_INTR_PTR(hmep->hme_intrstats)
103
104/*
105 * The following variables are used for checking fixes in Sbus/FEPS 2.0
106 */
107static int hme_urun_fix = 0; /* Bug fixed in Sbus/FEPS 2.0 */
108
109/*
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700110 * The following variables are used for configuring various features
111 */
112static int hme_64bit_enable = 1; /* Use 64-bit sbus transfers */
113static int hme_reject_own = 1; /* Reject packets with own SA */
Garrett D'Amore06673d92009-10-15 22:31:12 -0700114static int hme_ngu_enable = 0; /* Never Give Up mode */
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700115
Venugopal Iyer0dc23662010-03-09 15:30:01 -0800116char *hme_priv_prop[] = {
117 "_ipg0",
118 "_ipg1",
119 "_ipg2",
120 "_lance_mode",
121 NULL
Garrett D'Amore06673d92009-10-15 22:31:12 -0700122};
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700123
124static int hme_lance_mode = 1; /* to enable lance mode */
125static int hme_ipg0 = 16;
126static int hme_ipg1 = 8;
127static int hme_ipg2 = 4;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700128
129/*
130 * The following parameters may be configured by the user. If they are not
131 * configured by the user, the values will be based on the capabilities of
132 * the transceiver.
133 * The value "HME_NOTUSR" is ORed with the parameter value to indicate values
134 * which are NOT configured by the user.
135 */
136
137#define HME_NOTUSR 0x0f000000
138#define HME_MASK_1BIT 0x1
139#define HME_MASK_5BIT 0x1f
140#define HME_MASK_8BIT 0xff
141
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700142/*
143 * All strings used by hme messaging functions
144 */
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700145
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700146static char *no_xcvr_msg =
147 "No transceiver found.";
148
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700149static char *burst_size_msg =
150 "Could not identify the burst size";
151
152static char *unk_rx_ringsz_msg =
153 "Unknown receive RINGSZ";
154
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700155static char *add_intr_fail_msg =
156 "ddi_add_intr(9F) failed";
157
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700158static char *mregs_4global_reg_fail_msg =
159 "ddi_regs_map_setup(9F) for global reg failed";
160
161static char *mregs_4etx_reg_fail_msg =
162 "ddi_map_regs for etx reg failed";
163
164static char *mregs_4erx_reg_fail_msg =
165 "ddi_map_regs for erx reg failed";
166
167static char *mregs_4bmac_reg_fail_msg =
168 "ddi_map_regs for bmac reg failed";
169
170static char *mregs_4mif_reg_fail_msg =
171 "ddi_map_regs for mif reg failed";
172
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700173static char *init_fail_gen_msg =
174 "Failed to initialize hardware/driver";
175
176static char *ddi_nregs_fail_msg =
177 "ddi_dev_nregs failed(9F), returned %d";
178
179static char *bad_num_regs_msg =
180 "Invalid number of registers.";
181
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700182
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700183/* FATAL ERR msgs */
184/*
185 * Function prototypes.
186 */
gd78059f2cd0f02007-08-24 17:45:12 -0700187/* these two are global so that qfe can use them */
188int hmeattach(dev_info_t *, ddi_attach_cmd_t);
189int hmedetach(dev_info_t *, ddi_detach_cmd_t);
Garrett D'Amore02193462009-05-11 21:07:23 -0700190int hmequiesce(dev_info_t *);
gd7805985025c02007-07-12 10:37:47 -0700191static boolean_t hmeinit_xfer_params(struct hme *);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700192static uint_t hmestop(struct hme *);
193static void hmestatinit(struct hme *);
194static int hmeallocthings(struct hme *);
Garrett D'Amore02193462009-05-11 21:07:23 -0700195static void hmefreethings(struct hme *);
196static int hmeallocbuf(struct hme *, hmebuf_t *, int);
197static int hmeallocbufs(struct hme *);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700198static void hmefreebufs(struct hme *);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700199static void hmeget_hm_rev_property(struct hme *);
gd7805985025c02007-07-12 10:37:47 -0700200static boolean_t hmestart(struct hme *, mblk_t *);
201static uint_t hmeintr(caddr_t);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700202static void hmereclaim(struct hme *);
203static int hmeinit(struct hme *);
204static void hmeuninit(struct hme *hmep);
Garrett D'Amore02193462009-05-11 21:07:23 -0700205static mblk_t *hmeread(struct hme *, hmebuf_t *, uint32_t);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700206static void hmesavecntrs(struct hme *);
207static void hme_fatal_err(struct hme *, uint_t);
208static void hme_nonfatal_err(struct hme *, uint_t);
209static int hmeburstsizes(struct hme *);
Garrett D'Amore06673d92009-10-15 22:31:12 -0700210static void send_bit(struct hme *, uint16_t);
211static uint16_t get_bit_std(uint8_t, struct hme *);
212static uint16_t hme_bb_mii_read(struct hme *, uint8_t, uint8_t);
213static void hme_bb_mii_write(struct hme *, uint8_t, uint8_t, uint16_t);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700214static void hme_bb_force_idle(struct hme *);
Garrett D'Amore06673d92009-10-15 22:31:12 -0700215static uint16_t hme_mii_read(void *, uint8_t, uint8_t);
216static void hme_mii_write(void *, uint8_t, uint8_t, uint16_t);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700217static void hme_setup_mac_address(struct hme *, dev_info_t *);
Garrett D'Amore06673d92009-10-15 22:31:12 -0700218static void hme_mii_notify(void *, link_state_t);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700219
Garrett D'Amore02193462009-05-11 21:07:23 -0700220static void hme_fault_msg(struct hme *, uint_t, msg_t, char *, ...);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700221
222static void hme_check_acc_handle(char *, uint_t, struct hme *,
gd7805985025c02007-07-12 10:37:47 -0700223 ddi_acc_handle_t);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700224
gd7805985025c02007-07-12 10:37:47 -0700225/*
226 * Nemo (GLDv3) Functions.
227 */
228static int hme_m_stat(void *, uint_t, uint64_t *);
229static int hme_m_start(void *);
230static void hme_m_stop(void *);
231static int hme_m_promisc(void *, boolean_t);
232static int hme_m_multicst(void *, boolean_t, const uint8_t *);
233static int hme_m_unicst(void *, const uint8_t *);
234static mblk_t *hme_m_tx(void *, mblk_t *);
gd7805985025c02007-07-12 10:37:47 -0700235static boolean_t hme_m_getcapab(void *, mac_capab_t, void *);
Venugopal Iyer0dc23662010-03-09 15:30:01 -0800236static int hme_m_getprop(void *, const char *, mac_prop_id_t, uint_t, void *);
237static void hme_m_propinfo(void *, const char *, mac_prop_id_t,
238 mac_prop_info_handle_t);
Garrett D'Amore06673d92009-10-15 22:31:12 -0700239static int hme_m_setprop(void *, const char *, mac_prop_id_t, uint_t,
240 const void *);
241
242static mii_ops_t hme_mii_ops = {
243 MII_OPS_VERSION,
244 hme_mii_read,
245 hme_mii_write,
246 hme_mii_notify,
247 NULL
248};
gd7805985025c02007-07-12 10:37:47 -0700249
250static mac_callbacks_t hme_m_callbacks = {
Venugopal Iyer0dc23662010-03-09 15:30:01 -0800251 MC_GETCAPAB | MC_SETPROP | MC_GETPROP | MC_PROPINFO,
gd7805985025c02007-07-12 10:37:47 -0700252 hme_m_stat,
253 hme_m_start,
254 hme_m_stop,
255 hme_m_promisc,
256 hme_m_multicst,
257 hme_m_unicst,
258 hme_m_tx,
Garrett D'Amore06673d92009-10-15 22:31:12 -0700259 NULL,
Venugopal Iyer0dc23662010-03-09 15:30:01 -0800260 NULL,
gd7805985025c02007-07-12 10:37:47 -0700261 hme_m_getcapab,
Garrett D'Amore06673d92009-10-15 22:31:12 -0700262 NULL,
263 NULL,
264 hme_m_setprop,
265 hme_m_getprop,
Venugopal Iyer0dc23662010-03-09 15:30:01 -0800266 hme_m_propinfo
gd7805985025c02007-07-12 10:37:47 -0700267};
268
269DDI_DEFINE_STREAM_OPS(hme_dev_ops, nulldev, nulldev, hmeattach, hmedetach,
Garrett D'Amore02193462009-05-11 21:07:23 -0700270 nodev, NULL, D_MP, NULL, hmequiesce);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700271
272#define HME_FAULT_MSG1(p, s, t, f) \
Garrett D'Amore02193462009-05-11 21:07:23 -0700273 hme_fault_msg((p), (s), (t), (f));
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700274
275#define HME_FAULT_MSG2(p, s, t, f, a) \
Garrett D'Amore02193462009-05-11 21:07:23 -0700276 hme_fault_msg((p), (s), (t), (f), (a));
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700277
278#define HME_FAULT_MSG3(p, s, t, f, a, b) \
Garrett D'Amore02193462009-05-11 21:07:23 -0700279 hme_fault_msg((p), (s), (t), (f), (a), (b));
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700280
281#define HME_FAULT_MSG4(p, s, t, f, a, b, c) \
Garrett D'Amore02193462009-05-11 21:07:23 -0700282 hme_fault_msg((p), (s), (t), (f), (a), (b), (c));
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700283
284#define CHECK_MIFREG() \
285 hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_mifregh)
286#define CHECK_ETXREG() \
287 hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_etxregh)
288#define CHECK_ERXREG() \
289 hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_erxregh)
290#define CHECK_MACREG() \
291 hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_bmacregh)
292#define CHECK_GLOBREG() \
293 hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_globregh)
294
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700295/*
296 * Claim the device is ultra-capable of burst in the beginning. Use
297 * the value returned by ddi_dma_burstsizes() to actually set the HME
298 * global configuration register later.
299 *
300 * Sbus/FEPS supports burst sizes of 16, 32 and 64 bytes. Also, it supports
301 * 32-bit and 64-bit Sbus transfers. Hence the dlim_burstsizes field contains
302 * the the burstsizes in both the lo and hi words.
303 */
304#define HMELIMADDRLO ((uint64_t)0x00000000)
305#define HMELIMADDRHI ((uint64_t)0xffffffff)
306
Garrett D'Amore02193462009-05-11 21:07:23 -0700307/*
308 * Note that rx and tx data buffers can be arbitrarily aligned, but
309 * that the descriptor rings need to be aligned on 2K boundaries, per
310 * the spec.
311 */
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700312static ddi_dma_attr_t hme_dma_attr = {
313 DMA_ATTR_V0, /* version number. */
314 (uint64_t)HMELIMADDRLO, /* low address */
315 (uint64_t)HMELIMADDRHI, /* high address */
316 (uint64_t)0x00ffffff, /* address counter max */
Garrett D'Amore02193462009-05-11 21:07:23 -0700317 (uint64_t)HME_HMDALIGN, /* alignment */
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700318 (uint_t)0x00700070, /* dlim_burstsizes for 32 and 64 bit xfers */
319 (uint32_t)0x1, /* minimum transfer size */
320 (uint64_t)0x7fffffff, /* maximum transfer size */
321 (uint64_t)0x00ffffff, /* maximum segment size */
322 1, /* scatter/gather list length */
323 512, /* granularity */
324 0 /* attribute flags */
325};
326
Garrett D'Amore02193462009-05-11 21:07:23 -0700327static ddi_device_acc_attr_t hme_buf_attr = {
328 DDI_DEVICE_ATTR_V0,
329 DDI_NEVERSWAP_ACC,
330 DDI_STRICTORDER_ACC, /* probably could allow merging & caching */
331 DDI_DEFAULT_ACC,
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700332};
333
334static uchar_t pci_latency_timer = 0;
335
336/*
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700337 * Module linkage information for the kernel.
338 */
339static struct modldrv modldrv = {
340 &mod_driverops, /* Type of module. This one is a driver */
gd7805985025c02007-07-12 10:37:47 -0700341 "Sun HME 10/100 Mb Ethernet",
342 &hme_dev_ops, /* driver ops */
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700343};
344
345static struct modlinkage modlinkage = {
346 MODREV_1, &modldrv, NULL
347};
348
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700349/* <<<<<<<<<<<<<<<<<<<<<< Register operations >>>>>>>>>>>>>>>>>>>>> */
350
351#define GET_MIFREG(reg) \
352 ddi_get32(hmep->hme_mifregh, (uint32_t *)&hmep->hme_mifregp->reg)
353#define PUT_MIFREG(reg, value) \
354 ddi_put32(hmep->hme_mifregh, (uint32_t *)&hmep->hme_mifregp->reg, value)
355
356#define GET_ETXREG(reg) \
357 ddi_get32(hmep->hme_etxregh, (uint32_t *)&hmep->hme_etxregp->reg)
358#define PUT_ETXREG(reg, value) \
359 ddi_put32(hmep->hme_etxregh, (uint32_t *)&hmep->hme_etxregp->reg, value)
360#define GET_ERXREG(reg) \
361 ddi_get32(hmep->hme_erxregh, (uint32_t *)&hmep->hme_erxregp->reg)
362#define PUT_ERXREG(reg, value) \
363 ddi_put32(hmep->hme_erxregh, (uint32_t *)&hmep->hme_erxregp->reg, value)
364#define GET_MACREG(reg) \
365 ddi_get32(hmep->hme_bmacregh, (uint32_t *)&hmep->hme_bmacregp->reg)
366#define PUT_MACREG(reg, value) \
367 ddi_put32(hmep->hme_bmacregh, \
368 (uint32_t *)&hmep->hme_bmacregp->reg, value)
369#define GET_GLOBREG(reg) \
370 ddi_get32(hmep->hme_globregh, (uint32_t *)&hmep->hme_globregp->reg)
371#define PUT_GLOBREG(reg, value) \
372 ddi_put32(hmep->hme_globregh, \
373 (uint32_t *)&hmep->hme_globregp->reg, value)
Garrett D'Amore02193462009-05-11 21:07:23 -0700374#define PUT_TMD(ptr, paddr, len, flags) \
375 ddi_put32(hmep->hme_tmd_acch, &hmep->hme_tmdp[ptr].tmd_addr, paddr); \
376 ddi_put32(hmep->hme_tmd_acch, &hmep->hme_tmdp[ptr].tmd_flags, \
377 len | flags)
378#define GET_TMD_FLAGS(ptr) \
379 ddi_get32(hmep->hme_tmd_acch, &hmep->hme_tmdp[ptr].tmd_flags)
380#define PUT_RMD(ptr, paddr) \
381 ddi_put32(hmep->hme_rmd_acch, &hmep->hme_rmdp[ptr].rmd_addr, paddr); \
382 ddi_put32(hmep->hme_rmd_acch, &hmep->hme_rmdp[ptr].rmd_flags, \
383 (uint32_t)(HMEBUFSIZE << HMERMD_BUFSIZE_SHIFT) | HMERMD_OWN)
384#define GET_RMD_FLAGS(ptr) \
385 ddi_get32(hmep->hme_rmd_acch, &hmep->hme_rmdp[ptr].rmd_flags)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700386
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700387#define GET_ROM8(offset) \
388 ddi_get8((hmep->hme_romh), (offset))
389
390/*
391 * Ether_copy is not endian-correct. Define an endian-correct version.
392 */
393#define ether_bcopy(a, b) (bcopy(a, b, 6))
394
395/*
396 * Ether-type is specifically big-endian, but data region is unknown endian
397 */
gd7805985025c02007-07-12 10:37:47 -0700398#define get_ether_type(ptr) \
399 (((((uint8_t *)ptr)[12] << 8) | (((uint8_t *)ptr)[13])))
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700400
401/* <<<<<<<<<<<<<<<<<<<<<< Configuration Parameters >>>>>>>>>>>>>>>>>>>>> */
402
403#define BMAC_DEFAULT_JAMSIZE (0x04) /* jamsize equals 4 */
404#define BMAC_LONG_JAMSIZE (0x10) /* jamsize equals 0x10 */
405static int jamsize = BMAC_DEFAULT_JAMSIZE;
406
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700407
408/*
409 * Calculate the bit in the multicast address filter that selects the given
410 * address.
411 */
412
413static uint32_t
gd7805985025c02007-07-12 10:37:47 -0700414hmeladrf_bit(const uint8_t *addr)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700415{
416 uint32_t crc;
417
418 CRC32(crc, addr, ETHERADDRL, -1U, crc32_table);
419
420 /*
421 * Just want the 6 most significant bits.
422 */
423 return (crc >> 26);
424}
425
426/* <<<<<<<<<<<<<<<<<<<<<<<< Bit Bang Operations >>>>>>>>>>>>>>>>>>>>>>>> */
427
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700428static void
Garrett D'Amore06673d92009-10-15 22:31:12 -0700429send_bit(struct hme *hmep, uint16_t x)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700430{
431 PUT_MIFREG(mif_bbdata, x);
432 PUT_MIFREG(mif_bbclk, HME_BBCLK_LOW);
433 PUT_MIFREG(mif_bbclk, HME_BBCLK_HIGH);
434}
435
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700436
437/*
438 * To read the MII register bits according to the IEEE Standard
439 */
Garrett D'Amore06673d92009-10-15 22:31:12 -0700440static uint16_t
441get_bit_std(uint8_t phyad, struct hme *hmep)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700442{
Garrett D'Amore06673d92009-10-15 22:31:12 -0700443 uint16_t x;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700444
445 PUT_MIFREG(mif_bbclk, HME_BBCLK_LOW);
446 drv_usecwait(1); /* wait for >330 ns for stable data */
Garrett D'Amore06673d92009-10-15 22:31:12 -0700447 if (phyad == HME_INTERNAL_PHYAD)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700448 x = (GET_MIFREG(mif_cfg) & HME_MIF_CFGM0) ? 1 : 0;
449 else
450 x = (GET_MIFREG(mif_cfg) & HME_MIF_CFGM1) ? 1 : 0;
451 PUT_MIFREG(mif_bbclk, HME_BBCLK_HIGH);
452 return (x);
453}
454
455#define SEND_BIT(x) send_bit(hmep, x)
Garrett D'Amore06673d92009-10-15 22:31:12 -0700456#define GET_BIT_STD(phyad, x) x = get_bit_std(phyad, hmep)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700457
458
459static void
Garrett D'Amore06673d92009-10-15 22:31:12 -0700460hme_bb_mii_write(struct hme *hmep, uint8_t phyad, uint8_t regad, uint16_t data)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700461{
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700462 int i;
463
464 PUT_MIFREG(mif_bbopenb, 1); /* Enable the MII driver */
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700465 (void) hme_bb_force_idle(hmep);
466 SEND_BIT(0); SEND_BIT(1); /* <ST> */
467 SEND_BIT(0); SEND_BIT(1); /* <OP> */
468
469 for (i = 4; i >= 0; i--) { /* <AAAAA> */
470 SEND_BIT((phyad >> i) & 1);
471 }
472
473 for (i = 4; i >= 0; i--) { /* <RRRRR> */
474 SEND_BIT((regad >> i) & 1);
475 }
476
477 SEND_BIT(1); SEND_BIT(0); /* <TA> */
478
479 for (i = 0xf; i >= 0; i--) { /* <DDDDDDDDDDDDDDDD> */
480 SEND_BIT((data >> i) & 1);
481 }
482
483 PUT_MIFREG(mif_bbopenb, 0); /* Disable the MII driver */
484 CHECK_MIFREG();
485}
486
487/* Return 0 if OK, 1 if error (Transceiver does not talk management) */
Garrett D'Amore06673d92009-10-15 22:31:12 -0700488static uint16_t
489hme_bb_mii_read(struct hme *hmep, uint8_t phyad, uint8_t regad)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700490{
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700491 int i;
492 uint32_t x;
Garrett D'Amore06673d92009-10-15 22:31:12 -0700493 uint16_t data = 0;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700494
495 PUT_MIFREG(mif_bbopenb, 1); /* Enable the MII driver */
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700496 (void) hme_bb_force_idle(hmep);
497 SEND_BIT(0); SEND_BIT(1); /* <ST> */
498 SEND_BIT(1); SEND_BIT(0); /* <OP> */
499 for (i = 4; i >= 0; i--) { /* <AAAAA> */
500 SEND_BIT((phyad >> i) & 1);
501 }
502 for (i = 4; i >= 0; i--) { /* <RRRRR> */
503 SEND_BIT((regad >> i) & 1);
504 }
505
506 PUT_MIFREG(mif_bbopenb, 0); /* Disable the MII driver */
507
Garrett D'Amore06673d92009-10-15 22:31:12 -0700508 GET_BIT_STD(phyad, x);
509 GET_BIT_STD(phyad, x); /* <TA> */
510 for (i = 0xf; i >= 0; i--) { /* <DDDDDDDDDDDDDDDD> */
511 GET_BIT_STD(phyad, x);
512 data += (x << i);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700513 }
Garrett D'Amore06673d92009-10-15 22:31:12 -0700514 /*
515 * Kludge to get the Transceiver out of hung mode
516 */
517 GET_BIT_STD(phyad, x);
518 GET_BIT_STD(phyad, x);
519 GET_BIT_STD(phyad, x);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700520 CHECK_MIFREG();
Garrett D'Amore06673d92009-10-15 22:31:12 -0700521 return (data);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700522}
523
524
525static void
526hme_bb_force_idle(struct hme *hmep)
527{
528 int i;
529
530 for (i = 0; i < 33; i++) {
531 SEND_BIT(1);
532 }
533}
534
535/* <<<<<<<<<<<<<<<<<<<<End of Bit Bang Operations >>>>>>>>>>>>>>>>>>>>>>>> */
536
537
538/* <<<<<<<<<<<<< Frame Register used for MII operations >>>>>>>>>>>>>>>>>>>> */
539
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700540/* Return 0 if OK, 1 if error (Transceiver does not talk management) */
Garrett D'Amore06673d92009-10-15 22:31:12 -0700541static uint16_t
542hme_mii_read(void *arg, uint8_t phyad, uint8_t regad)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700543{
Garrett D'Amore06673d92009-10-15 22:31:12 -0700544 struct hme *hmep = arg;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700545 uint32_t frame;
Garrett D'Amoree8717ca2010-01-04 12:31:54 -0800546 uint32_t tmp_mif;
547 uint32_t tmp_xif;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700548
Garrett D'Amoree8717ca2010-01-04 12:31:54 -0800549 tmp_mif = GET_MIFREG(mif_cfg);
550 tmp_xif = GET_MACREG(xifc);
551
552 switch (phyad) {
553 case HME_EXTERNAL_PHYAD:
554 PUT_MIFREG(mif_cfg, tmp_mif | HME_MIF_CFGPS);
555 PUT_MACREG(xifc, tmp_xif | BMAC_XIFC_MIIBUFDIS);
556 break;
557 case HME_INTERNAL_PHYAD:
558 PUT_MIFREG(mif_cfg, tmp_mif & ~(HME_MIF_CFGPS));
559 PUT_MACREG(xifc, tmp_xif & ~(BMAC_XIFC_MIIBUFDIS));
560 break;
561 default:
562 return (0xffff);
563 }
564
565 if (!hmep->hme_frame_enable) {
566 frame = (hme_bb_mii_read(hmep, phyad, regad));
567 PUT_MACREG(xifc, tmp_xif);
568 PUT_MIFREG(mif_cfg, tmp_mif);
569 return (frame & 0xffff);
570 }
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700571
Garrett D'Amore02193462009-05-11 21:07:23 -0700572 PUT_MIFREG(mif_frame,
573 HME_MIF_FRREAD | (phyad << HME_MIF_FRPHYAD_SHIFT) |
574 (regad << HME_MIF_FRREGAD_SHIFT));
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700575/*
576 * HMEDELAY((*framerp & HME_MIF_FRTA0), HMEMAXRSTDELAY);
577 */
Garrett D'Amore02193462009-05-11 21:07:23 -0700578 HMEDELAY((GET_MIFREG(mif_frame) & HME_MIF_FRTA0), 300);
579 frame = GET_MIFREG(mif_frame);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700580 CHECK_MIFREG();
Garrett D'Amoree8717ca2010-01-04 12:31:54 -0800581
582 PUT_MACREG(xifc, tmp_xif);
583 PUT_MIFREG(mif_cfg, tmp_mif);
584
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700585 if ((frame & HME_MIF_FRTA0) == 0) {
586
587
Garrett D'Amore06673d92009-10-15 22:31:12 -0700588 HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, MII_MSG,
Garrett D'Amore02193462009-05-11 21:07:23 -0700589 "MIF Read failure");
Garrett D'Amore06673d92009-10-15 22:31:12 -0700590 return (0xffff);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700591 }
Garrett D'Amore06673d92009-10-15 22:31:12 -0700592 return ((uint16_t)(frame & HME_MIF_FRDATA));
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700593}
594
595static void
Garrett D'Amore06673d92009-10-15 22:31:12 -0700596hme_mii_write(void *arg, uint8_t phyad, uint8_t regad, uint16_t data)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700597{
Garrett D'Amore06673d92009-10-15 22:31:12 -0700598 struct hme *hmep = arg;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700599 uint32_t frame;
Garrett D'Amoree8717ca2010-01-04 12:31:54 -0800600 uint32_t tmp_mif;
601 uint32_t tmp_xif;
602
603 tmp_mif = GET_MIFREG(mif_cfg);
604 tmp_xif = GET_MACREG(xifc);
605
606 switch (phyad) {
607 case HME_EXTERNAL_PHYAD:
608 PUT_MIFREG(mif_cfg, tmp_mif | HME_MIF_CFGPS);
609 PUT_MACREG(xifc, tmp_xif | BMAC_XIFC_MIIBUFDIS);
610 break;
611 case HME_INTERNAL_PHYAD:
612 PUT_MIFREG(mif_cfg, tmp_mif & ~(HME_MIF_CFGPS));
613 PUT_MACREG(xifc, tmp_xif & ~(BMAC_XIFC_MIIBUFDIS));
614 break;
615 default:
616 return;
617 }
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700618
619 if (!hmep->hme_frame_enable) {
Garrett D'Amore06673d92009-10-15 22:31:12 -0700620 hme_bb_mii_write(hmep, phyad, regad, data);
Garrett D'Amoree8717ca2010-01-04 12:31:54 -0800621 PUT_MACREG(xifc, tmp_xif);
622 PUT_MIFREG(mif_cfg, tmp_mif);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700623 return;
624 }
625
Garrett D'Amore02193462009-05-11 21:07:23 -0700626 PUT_MIFREG(mif_frame,
627 HME_MIF_FRWRITE | (phyad << HME_MIF_FRPHYAD_SHIFT) |
628 (regad << HME_MIF_FRREGAD_SHIFT) | data);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700629/*
630 * HMEDELAY((*framerp & HME_MIF_FRTA0), HMEMAXRSTDELAY);
631 */
Garrett D'Amore02193462009-05-11 21:07:23 -0700632 HMEDELAY((GET_MIFREG(mif_frame) & HME_MIF_FRTA0), 300);
633 frame = GET_MIFREG(mif_frame);
Garrett D'Amoree8717ca2010-01-04 12:31:54 -0800634 PUT_MACREG(xifc, tmp_xif);
635 PUT_MIFREG(mif_cfg, tmp_mif);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700636 CHECK_MIFREG();
637 if ((frame & HME_MIF_FRTA0) == 0) {
Garrett D'Amore06673d92009-10-15 22:31:12 -0700638 HME_FAULT_MSG1(hmep, SEVERITY_MID, MII_MSG,
Garrett D'Amore02193462009-05-11 21:07:23 -0700639 "MIF Write failure");
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700640 }
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700641}
642
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700643static void
Garrett D'Amore06673d92009-10-15 22:31:12 -0700644hme_mii_notify(void *arg, link_state_t link)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700645{
646 struct hme *hmep = arg;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700647
Garrett D'Amore06673d92009-10-15 22:31:12 -0700648 if (link == LINK_STATE_UP) {
649 (void) hmeinit(hmep);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700650 }
Garrett D'Amore06673d92009-10-15 22:31:12 -0700651 mac_link_update(hmep->hme_mh, link);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700652}
653
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700654/* <<<<<<<<<<<<<<<<<<<<<<<<<<< LOADABLE ENTRIES >>>>>>>>>>>>>>>>>>>>>>> */
655
656int
657_init(void)
658{
659 int status;
660
gd7805985025c02007-07-12 10:37:47 -0700661 mac_init_ops(&hme_dev_ops, "hme");
662 if ((status = mod_install(&modlinkage)) != 0) {
663 mac_fini_ops(&hme_dev_ops);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700664 }
665 return (status);
666}
667
668int
669_fini(void)
670{
671 int status;
672
gd7805985025c02007-07-12 10:37:47 -0700673 if ((status = mod_remove(&modlinkage)) == 0) {
674 mac_fini_ops(&hme_dev_ops);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700675 }
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700676 return (status);
677}
678
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700679int
680_info(struct modinfo *modinfop)
681{
682 return (mod_info(&modlinkage, modinfop));
683}
684
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700685/*
686 * ddi_dma_sync() a TMD or RMD descriptor.
687 */
Garrett D'Amore02193462009-05-11 21:07:23 -0700688#define HMESYNCRMD(num, who) \
689 (void) ddi_dma_sync(hmep->hme_rmd_dmah, \
690 (num * sizeof (struct hme_rmd)), \
691 sizeof (struct hme_rmd), \
692 who)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700693
Garrett D'Amore02193462009-05-11 21:07:23 -0700694#define HMESYNCTMD(num, who) \
695 (void) ddi_dma_sync(hmep->hme_tmd_dmah, \
696 (num * sizeof (struct hme_tmd)), \
697 sizeof (struct hme_tmd), \
698 who)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700699
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700700/*
701 * Ethernet broadcast address definition.
702 */
703static struct ether_addr etherbroadcastaddr = {
704 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
705};
706
707/*
708 * MIB II broadcast/multicast packets
709 */
gd7805985025c02007-07-12 10:37:47 -0700710#define IS_BROADCAST(pkt) (bcmp(pkt, &etherbroadcastaddr, ETHERADDRL) == 0)
711#define IS_MULTICAST(pkt) ((pkt[0] & 01) == 1)
712#define BUMP_InNUcast(hmep, pkt) \
Garrett D'Amore02193462009-05-11 21:07:23 -0700713 if (IS_MULTICAST(pkt)) { \
714 if (IS_BROADCAST(pkt)) { \
715 hmep->hme_brdcstrcv++; \
716 } else { \
717 hmep->hme_multircv++; \
718 } \
719 }
gd7805985025c02007-07-12 10:37:47 -0700720#define BUMP_OutNUcast(hmep, pkt) \
Garrett D'Amore02193462009-05-11 21:07:23 -0700721 if (IS_MULTICAST(pkt)) { \
722 if (IS_BROADCAST(pkt)) { \
723 hmep->hme_brdcstxmt++; \
724 } else { \
725 hmep->hme_multixmt++; \
726 } \
727 }
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700728
729static int
730hme_create_prop_from_kw(dev_info_t *dip, char *vpdname, char *vpdstr)
731{
732 char propstr[80];
733 int i, needprop = 0;
734 struct ether_addr local_mac;
735
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700736 if (strcmp(vpdname, "NA") == 0) {
737 (void) strcpy(propstr, "local-mac-address");
738 needprop = 1;
739 } else if (strcmp(vpdname, "Z0") == 0) {
740 (void) strcpy(propstr, "model");
741 needprop = 1;
742 } else if (strcmp(vpdname, "Z1") == 0) {
743 (void) strcpy(propstr, "board-model");
744 needprop = 1;
745 }
746
747 if (needprop == 1) {
Garrett D'Amore02193462009-05-11 21:07:23 -0700748
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700749 if (strcmp(propstr, "local-mac-address") == 0) {
750 for (i = 0; i < ETHERADDRL; i++)
751 local_mac.ether_addr_octet[i] =
gd7805985025c02007-07-12 10:37:47 -0700752 (uchar_t)vpdstr[i];
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700753 if (ddi_prop_create(DDI_DEV_T_NONE, dip,
gd7805985025c02007-07-12 10:37:47 -0700754 DDI_PROP_CANSLEEP, propstr,
755 (char *)local_mac.ether_addr_octet, ETHERADDRL)
756 != DDI_SUCCESS) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700757 return (DDI_FAILURE);
758 }
759 } else {
760 if (ddi_prop_create(DDI_DEV_T_NONE, dip,
gd7805985025c02007-07-12 10:37:47 -0700761 DDI_PROP_CANSLEEP, propstr, vpdstr,
762 strlen(vpdstr)+1) != DDI_SUCCESS) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700763 return (DDI_FAILURE);
764 }
765 }
766 }
767 return (0);
768}
769
770/*
771 * Get properties from old VPD
772 * for PCI cards
773 */
774static int
775hme_get_oldvpd_props(dev_info_t *dip, int vpd_base)
776{
777 struct hme *hmep;
778 int vpd_start, vpd_len, kw_start, kw_len, kw_ptr;
779 char kw_namestr[3];
780 char kw_fieldstr[256];
781 int i;
782
783 hmep = ddi_get_driver_private(dip);
784
785 vpd_start = vpd_base;
786
787 if ((GET_ROM8(&hmep->hme_romp[vpd_start]) & 0xff) != 0x90) {
788 return (1); /* error */
789 } else {
790 vpd_len = 9;
791 }
792
793 /* Get local-mac-address */
794 kw_start = vpd_start + 3; /* Location of 1st keyword */
795 kw_ptr = kw_start;
796 while ((kw_ptr - kw_start) < vpd_len) { /* Get all keywords */
797 kw_namestr[0] = GET_ROM8(&hmep->hme_romp[kw_ptr]);
798 kw_namestr[1] = GET_ROM8(&hmep->hme_romp[kw_ptr+1]);
799 kw_namestr[2] = '\0';
800 kw_len = (int)(GET_ROM8(&hmep->hme_romp[kw_ptr+2]) & 0xff);
801 for (i = 0, kw_ptr += 3; i < kw_len; i++)
802 kw_fieldstr[i] = GET_ROM8(&hmep->hme_romp[kw_ptr+i]);
803 kw_fieldstr[i] = '\0';
804 if (hme_create_prop_from_kw(dip, kw_namestr, kw_fieldstr)) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700805 return (DDI_FAILURE);
806 }
807 kw_ptr += kw_len;
808 } /* next keyword */
809
gd7805985025c02007-07-12 10:37:47 -0700810 if (ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, "model",
811 "SUNW,cheerio", strlen("SUNW,cheerio")+1) != DDI_SUCCESS) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700812 return (DDI_FAILURE);
813 }
814 return (0);
815}
816
817
818/*
819 * Get properties from new VPD
820 * for CompactPCI cards
821 */
822static int
823hme_get_newvpd_props(dev_info_t *dip, int vpd_base)
824{
825 struct hme *hmep;
826 int vpd_start, vpd_len, kw_start, kw_len, kw_ptr;
827 char kw_namestr[3];
828 char kw_fieldstr[256];
829 int maxvpdsize, i;
830
831 hmep = ddi_get_driver_private(dip);
832
833 maxvpdsize = 1024; /* Real size not known until after it is read */
834
835 vpd_start = (int)((GET_ROM8(&(hmep->hme_romp[vpd_base+1])) & 0xff) |
gd7805985025c02007-07-12 10:37:47 -0700836 ((GET_ROM8(&hmep->hme_romp[vpd_base+2]) & 0xff) << 8)) +3;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700837 vpd_start = vpd_base + vpd_start;
838 while (vpd_start < (vpd_base + maxvpdsize)) { /* Get all VPDs */
839 if ((GET_ROM8(&hmep->hme_romp[vpd_start]) & 0xff) != 0x90) {
840 break; /* no VPD found */
841 } else {
842 vpd_len = (int)((GET_ROM8(&hmep->hme_romp[vpd_start
gd7805985025c02007-07-12 10:37:47 -0700843 + 1]) & 0xff) | (GET_ROM8(&hmep->hme_romp[vpd_start
844 + 2]) & 0xff) << 8);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700845 }
846 /* Get all keywords in this VPD */
847 kw_start = vpd_start + 3; /* Location of 1st keyword */
848 kw_ptr = kw_start;
849 while ((kw_ptr - kw_start) < vpd_len) { /* Get all keywords */
850 kw_namestr[0] = GET_ROM8(&hmep->hme_romp[kw_ptr]);
851 kw_namestr[1] = GET_ROM8(&hmep->hme_romp[kw_ptr+1]);
852 kw_namestr[2] = '\0';
gd7805985025c02007-07-12 10:37:47 -0700853 kw_len =
854 (int)(GET_ROM8(&hmep->hme_romp[kw_ptr+2]) & 0xff);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700855 for (i = 0, kw_ptr += 3; i < kw_len; i++)
gd7805985025c02007-07-12 10:37:47 -0700856 kw_fieldstr[i] =
857 GET_ROM8(&hmep->hme_romp[kw_ptr+i]);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700858 kw_fieldstr[i] = '\0';
859 if (hme_create_prop_from_kw(dip, kw_namestr,
gd7805985025c02007-07-12 10:37:47 -0700860 kw_fieldstr)) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700861 return (DDI_FAILURE);
862 }
863 kw_ptr += kw_len;
864 } /* next keyword */
865 vpd_start += (vpd_len + 3);
866 } /* next VPD */
867 return (0);
868}
869
870
871/*
872 * Get properties from VPD
873 */
874static int
875hme_get_vpd_props(dev_info_t *dip)
876{
877 struct hme *hmep;
878 int v0, v1, vpd_base;
879 int i, epromsrchlimit;
880
881
882 hmep = ddi_get_driver_private(dip);
883
884 v0 = (int)(GET_ROM8(&(hmep->hme_romp[0])));
885 v1 = (int)(GET_ROM8(&(hmep->hme_romp[1])));
886 v0 = ((v0 & 0xff) << 8 | v1);
887
888 if ((v0 & 0xffff) != 0x55aa) {
889 cmn_err(CE_NOTE, " Valid pci prom not found \n");
890 return (1);
891 }
892
893 epromsrchlimit = 4096;
894 for (i = 2; i < epromsrchlimit; i++) {
gd7805985025c02007-07-12 10:37:47 -0700895 /* "PCIR" */
896 if (((GET_ROM8(&(hmep->hme_romp[i])) & 0xff) == 'P') &&
897 ((GET_ROM8(&(hmep->hme_romp[i+1])) & 0xff) == 'C') &&
898 ((GET_ROM8(&(hmep->hme_romp[i+2])) & 0xff) == 'I') &&
899 ((GET_ROM8(&(hmep->hme_romp[i+3])) & 0xff) == 'R')) {
900 vpd_base =
901 (int)((GET_ROM8(&(hmep->hme_romp[i+8])) & 0xff) |
902 (GET_ROM8(&(hmep->hme_romp[i+9])) & 0xff) << 8);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700903 break; /* VPD pointer found */
904 }
905 }
906
907 /* No VPD found */
908 if (vpd_base == 0) {
909 cmn_err(CE_NOTE, " Vital Product Data pointer not found \n");
910 return (1);
911 }
912
913 v0 = (int)(GET_ROM8(&(hmep->hme_romp[vpd_base])));
914 if (v0 == 0x82) {
915 if (hme_get_newvpd_props(dip, vpd_base))
916 return (1);
917 return (0);
918 } else if (v0 == 0x90) {
Garrett D'Amore02193462009-05-11 21:07:23 -0700919 /* If we are are SUNW,qfe card, look for the Nth "NA" descr */
920 if ((GET_ROM8(&hmep->hme_romp[vpd_base + 12]) != 0x79) &&
921 GET_ROM8(&hmep->hme_romp[vpd_base + 4 * 12]) == 0x79) {
922 vpd_base += hmep->hme_devno * 12;
923 }
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700924 if (hme_get_oldvpd_props(dip, vpd_base))
925 return (1);
926 return (0);
927 } else
928 return (1); /* unknown start byte in VPD */
929}
930
Garrett D'Amore02193462009-05-11 21:07:23 -0700931/*
932 * For x86, the BIOS doesn't map the PCI Rom register for the qfe
933 * cards, so we have to extract it from the ebus bridge that is
934 * function zero of the same device. This is a bit of an ugly hack.
935 * (The ebus bridge leaves the entire ROM mapped at base address
936 * register 0x10.)
937 */
938
939typedef struct {
940 struct hme *hmep;
941 dev_info_t *parent;
942 uint8_t bus, dev;
943 ddi_acc_handle_t acch;
944 caddr_t romp;
945} ebus_rom_t;
946
947static int
948hme_mapebusrom(dev_info_t *dip, void *arg)
949{
950 int *regs;
951 unsigned nregs;
952 int reg;
953 ebus_rom_t *rom = arg;
954 struct hme *hmep = rom->hmep;
955
956 /*
957 * We only want to look at our peers. Skip our parent.
958 */
959 if (dip == rom->parent) {
960 return (DDI_WALK_PRUNESIB);
961 }
962
Garrett D'Amore06673d92009-10-15 22:31:12 -0700963 if (ddi_get_parent(dip) != rom->parent)
964 return (DDI_WALK_CONTINUE);
965
Garrett D'Amore02193462009-05-11 21:07:23 -0700966 if ((ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 0,
967 "reg", &regs, &nregs)) != DDI_PROP_SUCCESS) {
968 return (DDI_WALK_PRUNECHILD);
969 }
970
971 if (nregs < 1) {
972 ddi_prop_free(regs);
973 return (DDI_WALK_PRUNECHILD);
974 }
975 reg = regs[0];
976 ddi_prop_free(regs);
977
978 /*
979 * Look for function 0 on our bus and device. If the device doesn't
980 * match, it might be an alternate peer, in which case we don't want
981 * to examine any of its children.
982 */
983 if ((PCI_REG_BUS_G(reg) != rom->bus) ||
984 (PCI_REG_DEV_G(reg) != rom->dev) ||
985 (PCI_REG_FUNC_G(reg) != 0)) {
986 return (DDI_WALK_PRUNECHILD);
987 }
988
989 (void) ddi_regs_map_setup(dip, 1, &rom->romp, 0, 0, &hmep->hme_dev_attr,
990 &rom->acch);
991 /*
992 * If we can't map the registers, the caller will notice that
993 * the acch is NULL.
994 */
995 return (DDI_WALK_TERMINATE);
996}
997
998static int
999hmeget_promebus(dev_info_t *dip)
1000{
1001 ebus_rom_t rom;
1002 int *regs;
1003 unsigned nregs;
1004 struct hme *hmep;
1005
1006 hmep = ddi_get_driver_private(dip);
1007
1008 bzero(&rom, sizeof (rom));
1009
1010 /*
1011 * For x86, the BIOS doesn't map the PCI Rom register for the qfe
1012 * cards, so we have to extract it from the eBus bridge that is
1013 * function zero. This is a bit of an ugly hack.
1014 */
1015 if ((ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 0,
1016 "reg", &regs, &nregs)) != DDI_PROP_SUCCESS) {
1017 return (DDI_FAILURE);
1018 }
1019
1020 if (nregs < 5) {
1021 ddi_prop_free(regs);
1022 return (DDI_FAILURE);
1023 }
1024 rom.hmep = hmep;
1025 rom.bus = PCI_REG_BUS_G(regs[0]);
1026 rom.dev = PCI_REG_DEV_G(regs[0]);
1027 hmep->hme_devno = rom.dev;
1028 rom.parent = ddi_get_parent(dip);
1029
1030 /*
1031 * The implementation of ddi_walk_devs says that we must not
Garrett D'Amore06673d92009-10-15 22:31:12 -07001032 * be called during autoconfiguration. However, it turns out
1033 * that it is safe to call this during our attach routine,
1034 * because we are not a nexus device.
Garrett D'Amore02193462009-05-11 21:07:23 -07001035 *
Garrett D'Amore06673d92009-10-15 22:31:12 -07001036 * Previously we rooted our search at our immediate parent,
1037 * but this triggered an assertion panic in debug kernels.
Garrett D'Amore02193462009-05-11 21:07:23 -07001038 */
Garrett D'Amore06673d92009-10-15 22:31:12 -07001039 ddi_walk_devs(ddi_root_node(), hme_mapebusrom, &rom);
Garrett D'Amore02193462009-05-11 21:07:23 -07001040
1041 if (rom.acch) {
1042 hmep->hme_romh = rom.acch;
1043 hmep->hme_romp = (unsigned char *)rom.romp;
1044 return (DDI_SUCCESS);
1045 }
1046 return (DDI_FAILURE);
1047}
1048
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001049static int
1050hmeget_promprops(dev_info_t *dip)
1051{
1052 struct hme *hmep;
1053 int rom_bar;
1054 ddi_acc_handle_t cfg_handle;
1055 struct {
1056 uint16_t vendorid;
1057 uint16_t devid;
1058 uint16_t command;
1059 uint16_t status;
1060 uint32_t junk1;
1061 uint8_t cache_line;
1062 uint8_t latency;
1063 uint8_t header;
1064 uint8_t bist;
1065 uint32_t base;
1066 uint32_t base14;
1067 uint32_t base18;
1068 uint32_t base1c;
1069 uint32_t base20;
1070 uint32_t base24;
1071 uint32_t base28;
1072 uint32_t base2c;
1073 uint32_t base30;
1074 } *cfg_ptr;
1075
1076 hmep = ddi_get_driver_private(dip);
1077
1078
1079 /*
1080 * map configuration space
1081 */
1082 if (ddi_regs_map_setup(hmep->dip, 0, (caddr_t *)&cfg_ptr,
gd7805985025c02007-07-12 10:37:47 -07001083 0, 0, &hmep->hme_dev_attr, &cfg_handle)) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001084 return (DDI_FAILURE);
1085 }
1086
1087 /*
1088 * Enable bus-master and memory accesses
1089 */
1090 ddi_put16(cfg_handle, &cfg_ptr->command,
gd7805985025c02007-07-12 10:37:47 -07001091 PCI_COMM_SERR_ENABLE | PCI_COMM_PARITY_DETECT |
1092 PCI_COMM_MAE | PCI_COMM_ME);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001093
1094 /*
1095 * Enable rom accesses
1096 */
1097 rom_bar = ddi_get32(cfg_handle, &cfg_ptr->base30);
1098 ddi_put32(cfg_handle, &cfg_ptr->base30, rom_bar | 1);
1099
1100
Garrett D'Amore02193462009-05-11 21:07:23 -07001101 if ((ddi_regs_map_setup(dip, 2, (caddr_t *)&(hmep->hme_romp), 0, 0,
1102 &hmep->hme_dev_attr, &hmep->hme_romh) != DDI_SUCCESS) &&
1103 (hmeget_promebus(dip) != DDI_SUCCESS)) {
1104
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001105 if (cfg_ptr)
1106 ddi_regs_map_free(&cfg_handle);
1107 return (DDI_FAILURE);
1108 } else {
1109 if (hme_get_vpd_props(dip))
Garrett D'Amore02193462009-05-11 21:07:23 -07001110 return (DDI_FAILURE);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001111 }
1112 if (hmep->hme_romp)
1113 ddi_regs_map_free(&hmep->hme_romh);
1114 if (cfg_ptr)
1115 ddi_regs_map_free(&cfg_handle);
Garrett D'Amore02193462009-05-11 21:07:23 -07001116 return (DDI_SUCCESS);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001117
1118}
1119
1120static void
1121hmeget_hm_rev_property(struct hme *hmep)
1122{
1123 int hm_rev;
1124
1125
1126 hm_rev = hmep->asic_rev;
1127 switch (hm_rev) {
1128 case HME_2P1_REVID:
1129 case HME_2P1_REVID_OBP:
1130 HME_FAULT_MSG2(hmep, SEVERITY_NONE, DISPLAY_MSG,
gd7805985025c02007-07-12 10:37:47 -07001131 "SBus 2.1 Found (Rev Id = %x)", hm_rev);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001132 hmep->hme_frame_enable = 1;
1133 break;
1134
1135 case HME_2P0_REVID:
1136 HME_FAULT_MSG2(hmep, SEVERITY_NONE, DISPLAY_MSG,
gd7805985025c02007-07-12 10:37:47 -07001137 "SBus 2.0 Found (Rev Id = %x)", hm_rev);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001138 break;
1139
1140 case HME_1C0_REVID:
1141 HME_FAULT_MSG2(hmep, SEVERITY_NONE, DISPLAY_MSG,
gd7805985025c02007-07-12 10:37:47 -07001142 "PCI IO 1.0 Found (Rev Id = %x)", hm_rev);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001143 break;
1144
1145 default:
Garrett D'Amore06673d92009-10-15 22:31:12 -07001146 HME_FAULT_MSG3(hmep, SEVERITY_NONE, DISPLAY_MSG,
gd7805985025c02007-07-12 10:37:47 -07001147 "%s (Rev Id = %x) Found",
1148 (hm_rev == HME_2C0_REVID) ? "PCI IO 2.0" : "Sbus", hm_rev);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001149 hmep->hme_frame_enable = 1;
1150 hmep->hme_lance_mode_enable = 1;
1151 hmep->hme_rxcv_enable = 1;
1152 break;
1153 }
1154}
1155
1156/*
1157 * Interface exists: make available by filling in network interface
1158 * record. System will initialize the interface when it is ready
1159 * to accept packets.
1160 */
gd78059f2cd0f02007-08-24 17:45:12 -07001161int
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001162hmeattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
1163{
1164 struct hme *hmep;
gd7805985025c02007-07-12 10:37:47 -07001165 mac_register_t *macp = NULL;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001166 int regno;
1167 int hm_rev = 0;
1168 int prop_len = sizeof (int);
1169 ddi_acc_handle_t cfg_handle;
1170 struct {
1171 uint16_t vendorid;
1172 uint16_t devid;
1173 uint16_t command;
1174 uint16_t status;
1175 uint8_t revid;
1176 uint8_t j1;
1177 uint16_t j2;
1178 } *cfg_ptr;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001179
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001180 switch (cmd) {
1181 case DDI_ATTACH:
1182 break;
1183
1184 case DDI_RESUME:
1185 if ((hmep = ddi_get_driver_private(dip)) == NULL)
gd7805985025c02007-07-12 10:37:47 -07001186 return (DDI_FAILURE);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001187
1188 hmep->hme_flags &= ~HMESUSPENDED;
Garrett D'Amore06673d92009-10-15 22:31:12 -07001189
1190 mii_resume(hmep->hme_mii);
gd7805985025c02007-07-12 10:37:47 -07001191
gd78059228fdff2007-08-23 20:40:28 -07001192 if (hmep->hme_started)
gd7805985025c02007-07-12 10:37:47 -07001193 (void) hmeinit(hmep);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001194 return (DDI_SUCCESS);
1195
1196 default:
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001197 return (DDI_FAILURE);
1198 }
1199
1200 /*
1201 * Allocate soft device data structure
1202 */
Garrett D'Amore02193462009-05-11 21:07:23 -07001203 hmep = kmem_zalloc(sizeof (*hmep), KM_SLEEP);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001204
1205 /*
1206 * Might as well set up elements of data structure
1207 */
1208 hmep->dip = dip;
1209 hmep->instance = ddi_get_instance(dip);
1210 hmep->pagesize = ddi_ptob(dip, (ulong_t)1); /* IOMMU PSize */
1211
1212 /*
1213 * Might as well setup the driver private
1214 * structure as part of the dip.
1215 */
1216 ddi_set_driver_private(dip, hmep);
1217
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001218 /*
1219 * Reject this device if it's in a slave-only slot.
1220 */
1221 if (ddi_slaveonly(dip) == DDI_SUCCESS) {
1222 HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
Garrett D'Amore02193462009-05-11 21:07:23 -07001223 "Dev not used - dev in slave only slot");
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001224 goto error_state;
1225 }
1226
1227 /*
1228 * Map in the device registers.
1229 *
1230 * Reg # 0 is the Global register set
1231 * Reg # 1 is the ETX register set
1232 * Reg # 2 is the ERX register set
1233 * Reg # 3 is the BigMAC register set.
1234 * Reg # 4 is the MIF register set
1235 */
1236 if (ddi_dev_nregs(dip, &regno) != (DDI_SUCCESS)) {
1237 HME_FAULT_MSG2(hmep, SEVERITY_HIGH, INIT_MSG,
gd7805985025c02007-07-12 10:37:47 -07001238 ddi_nregs_fail_msg, regno);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001239 goto error_state;
1240 }
1241
1242 switch (regno) {
1243 case 5:
1244 hmep->hme_cheerio_mode = 0;
1245 break;
1246 case 2:
1247 case 3: /* for hot swap/plug, there will be 3 entries in "reg" prop */
1248 hmep->hme_cheerio_mode = 1;
1249 break;
1250 default:
gd7805985025c02007-07-12 10:37:47 -07001251 HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
1252 bad_num_regs_msg);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001253 goto error_state;
1254 }
1255
1256 /* Initialize device attributes structure */
1257 hmep->hme_dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
1258
1259 if (hmep->hme_cheerio_mode)
gd7805985025c02007-07-12 10:37:47 -07001260 hmep->hme_dev_attr.devacc_attr_endian_flags =
1261 DDI_STRUCTURE_LE_ACC;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001262 else
gd7805985025c02007-07-12 10:37:47 -07001263 hmep->hme_dev_attr.devacc_attr_endian_flags =
1264 DDI_STRUCTURE_BE_ACC;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001265
1266 hmep->hme_dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
1267
1268 if (hmep->hme_cheerio_mode) {
1269 uint8_t oldLT;
1270 uint8_t newLT = 0;
1271 dev_info_t *pdip;
1272 const char *pdrvname;
1273
1274 /*
1275 * Map the PCI config space
1276 */
1277 if (pci_config_setup(dip, &hmep->pci_config_handle) !=
gd7805985025c02007-07-12 10:37:47 -07001278 DDI_SUCCESS) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001279 HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
gd7805985025c02007-07-12 10:37:47 -07001280 "pci_config_setup() failed..");
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001281 goto error_state;
1282 }
1283
1284 if (ddi_regs_map_setup(dip, 1,
gd7805985025c02007-07-12 10:37:47 -07001285 (caddr_t *)&(hmep->hme_globregp), 0, 0,
1286 &hmep->hme_dev_attr, &hmep->hme_globregh)) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001287 HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
gd7805985025c02007-07-12 10:37:47 -07001288 mregs_4global_reg_fail_msg);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001289 goto error_unmap;
1290 }
1291 hmep->hme_etxregh = hmep->hme_erxregh = hmep->hme_bmacregh =
1292 hmep->hme_mifregh = hmep->hme_globregh;
1293
gd7805985025c02007-07-12 10:37:47 -07001294 hmep->hme_etxregp =
1295 (void *)(((caddr_t)hmep->hme_globregp) + 0x2000);
1296 hmep->hme_erxregp =
1297 (void *)(((caddr_t)hmep->hme_globregp) + 0x4000);
1298 hmep->hme_bmacregp =
1299 (void *)(((caddr_t)hmep->hme_globregp) + 0x6000);
1300 hmep->hme_mifregp =
1301 (void *)(((caddr_t)hmep->hme_globregp) + 0x7000);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001302
1303 /*
1304 * Get parent pci bridge info.
1305 */
1306 pdip = ddi_get_parent(dip);
1307 pdrvname = ddi_driver_name(pdip);
1308
1309 oldLT = pci_config_get8(hmep->pci_config_handle,
gd7805985025c02007-07-12 10:37:47 -07001310 PCI_CONF_LATENCY_TIMER);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001311 /*
1312 * Honor value set in /etc/system
1313 * "set hme:pci_latency_timer=0xYY"
1314 */
1315 if (pci_latency_timer)
1316 newLT = pci_latency_timer;
1317 /*
1318 * Modify LT for simba
1319 */
1320 else if (strcmp("simba", pdrvname) == 0)
1321 newLT = 0xf0;
1322 /*
1323 * Ensure minimum cheerio latency timer of 0x50
1324 * Usually OBP or pci bridge should set this value
1325 * based on cheerio
1326 * min_grant * 8(33MHz) = 0x50 = 0xa * 0x8
1327 * Some system set cheerio LT at 0x40
1328 */
1329 else if (oldLT < 0x40)
1330 newLT = 0x50;
1331
1332 /*
1333 * Now program cheerio's pci latency timer with newLT
1334 */
1335 if (newLT)
1336 pci_config_put8(hmep->pci_config_handle,
gd7805985025c02007-07-12 10:37:47 -07001337 PCI_CONF_LATENCY_TIMER, (uchar_t)newLT);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001338 } else { /* Map register sets */
1339 if (ddi_regs_map_setup(dip, 0,
gd7805985025c02007-07-12 10:37:47 -07001340 (caddr_t *)&(hmep->hme_globregp), 0, 0,
1341 &hmep->hme_dev_attr, &hmep->hme_globregh)) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001342 HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
gd7805985025c02007-07-12 10:37:47 -07001343 mregs_4global_reg_fail_msg);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001344 goto error_state;
1345 }
1346 if (ddi_regs_map_setup(dip, 1,
gd7805985025c02007-07-12 10:37:47 -07001347 (caddr_t *)&(hmep->hme_etxregp), 0, 0,
1348 &hmep->hme_dev_attr, &hmep->hme_etxregh)) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001349 HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
gd7805985025c02007-07-12 10:37:47 -07001350 mregs_4etx_reg_fail_msg);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001351 goto error_unmap;
1352 }
1353 if (ddi_regs_map_setup(dip, 2,
gd7805985025c02007-07-12 10:37:47 -07001354 (caddr_t *)&(hmep->hme_erxregp), 0, 0,
1355 &hmep->hme_dev_attr, &hmep->hme_erxregh)) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001356 HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
gd7805985025c02007-07-12 10:37:47 -07001357 mregs_4erx_reg_fail_msg);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001358 goto error_unmap;
1359 }
1360 if (ddi_regs_map_setup(dip, 3,
gd7805985025c02007-07-12 10:37:47 -07001361 (caddr_t *)&(hmep->hme_bmacregp), 0, 0,
1362 &hmep->hme_dev_attr, &hmep->hme_bmacregh)) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001363 HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
gd7805985025c02007-07-12 10:37:47 -07001364 mregs_4bmac_reg_fail_msg);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001365 goto error_unmap;
1366 }
1367
1368 if (ddi_regs_map_setup(dip, 4,
gd7805985025c02007-07-12 10:37:47 -07001369 (caddr_t *)&(hmep->hme_mifregp), 0, 0,
1370 &hmep->hme_dev_attr, &hmep->hme_mifregh)) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001371 HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
gd7805985025c02007-07-12 10:37:47 -07001372 mregs_4mif_reg_fail_msg);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001373 goto error_unmap;
1374 }
1375 } /* Endif cheerio_mode */
1376
1377 /*
1378 * Based on the hm-rev, set some capabilities
1379 * Set up default capabilities for HM 2.0
1380 */
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001381 hmep->hme_frame_enable = 0;
1382 hmep->hme_lance_mode_enable = 0;
1383 hmep->hme_rxcv_enable = 0;
1384
1385 /* NEW routine to get the properties */
1386
1387 if (ddi_getlongprop_buf(DDI_DEV_T_ANY, hmep->dip, 0, "hm-rev",
gd7805985025c02007-07-12 10:37:47 -07001388 (caddr_t)&hm_rev, &prop_len) == DDI_PROP_SUCCESS) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001389
1390 hmep->asic_rev = hm_rev;
1391 hmeget_hm_rev_property(hmep);
1392 } else {
1393 /*
1394 * hm_rev property not found so, this is
1395 * case of hot insertion of card without interpreting fcode.
1396 * Get it from revid in config space after mapping it.
1397 */
1398 if (ddi_regs_map_setup(hmep->dip, 0, (caddr_t *)&cfg_ptr,
gd7805985025c02007-07-12 10:37:47 -07001399 0, 0, &hmep->hme_dev_attr, &cfg_handle)) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001400 return (DDI_FAILURE);
1401 }
1402 /*
1403 * Since this is cheerio-based PCI card, we write 0xC in the
1404 * top 4 bits(4-7) of hm-rev and retain the bottom(0-3) bits
1405 * for Cheerio version(1.0 or 2.0 = 0xC0 or 0xC1)
1406 */
1407 hm_rev = ddi_get8(cfg_handle, &cfg_ptr->revid);
1408 hm_rev = HME_1C0_REVID | (hm_rev & HME_REV_VERS_MASK);
1409 hmep->asic_rev = hm_rev;
1410 if (ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
gd7805985025c02007-07-12 10:37:47 -07001411 "hm-rev", (caddr_t)&hm_rev, sizeof (hm_rev)) !=
1412 DDI_SUCCESS) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001413 HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, AUTOCONFIG_MSG,
Garrett D'Amore06673d92009-10-15 22:31:12 -07001414 "ddi_prop_create error for hm_rev");
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001415 }
1416 ddi_regs_map_free(&cfg_handle);
1417
1418 hmeget_hm_rev_property(hmep);
1419
1420 /* get info via VPD */
Garrett D'Amore02193462009-05-11 21:07:23 -07001421 if (hmeget_promprops(dip) != DDI_SUCCESS) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001422 HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, AUTOCONFIG_MSG,
Garrett D'Amore06673d92009-10-15 22:31:12 -07001423 "no promprops");
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001424 }
1425 }
1426
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001427 if (ddi_intr_hilevel(dip, 0)) {
1428 HME_FAULT_MSG1(hmep, SEVERITY_HIGH, NFATAL_ERR_MSG,
gd7805985025c02007-07-12 10:37:47 -07001429 " high-level interrupts are not supported");
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001430 goto error_unmap;
1431 }
1432
1433 /*
1434 * Get intr. block cookie so that mutex locks can be initialized.
1435 */
1436 if (ddi_get_iblock_cookie(dip, 0, &hmep->hme_cookie) != DDI_SUCCESS)
1437 goto error_unmap;
1438
1439 /*
1440 * Initialize mutex's for this device.
1441 */
gd7805985025c02007-07-12 10:37:47 -07001442 mutex_init(&hmep->hme_xmitlock, NULL, MUTEX_DRIVER, hmep->hme_cookie);
1443 mutex_init(&hmep->hme_intrlock, NULL, MUTEX_DRIVER, hmep->hme_cookie);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001444
1445 /*
1446 * Quiesce the hardware.
1447 */
1448 (void) hmestop(hmep);
1449
1450 /*
1451 * Add interrupt to system
1452 */
1453 if (ddi_add_intr(dip, 0, (ddi_iblock_cookie_t *)NULL,
1454 (ddi_idevice_cookie_t *)NULL, hmeintr, (caddr_t)hmep)) {
1455 HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
gd7805985025c02007-07-12 10:37:47 -07001456 add_intr_fail_msg);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001457 goto error_mutex;
1458 }
1459
1460 /*
1461 * Set up the ethernet mac address.
1462 */
1463 hme_setup_mac_address(hmep, dip);
1464
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001465 if (!hmeinit_xfer_params(hmep))
gd7805985025c02007-07-12 10:37:47 -07001466 goto error_intr;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001467
1468 if (hmeburstsizes(hmep) == DDI_FAILURE) {
1469 HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, burst_size_msg);
gd7805985025c02007-07-12 10:37:47 -07001470 goto error_intr;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001471 }
1472
Garrett D'Amore02193462009-05-11 21:07:23 -07001473 if (hmeallocthings(hmep) != DDI_SUCCESS) {
1474 HME_FAULT_MSG1(hmep, SEVERITY_HIGH, CONFIG_MSG,
1475 "resource allocation failed");
1476 goto error_intr;
1477 }
1478
1479 if (hmeallocbufs(hmep) != DDI_SUCCESS) {
1480 HME_FAULT_MSG1(hmep, SEVERITY_HIGH, CONFIG_MSG,
1481 "buffer allocation failed");
1482 goto error_intr;
1483 }
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001484
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001485 hmestatinit(hmep);
gd7805985025c02007-07-12 10:37:47 -07001486
Garrett D'Amoree8717ca2010-01-04 12:31:54 -08001487 /* our external (preferred) PHY is at address 0 */
1488 (void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, "first-phy", 0);
1489
Garrett D'Amore06673d92009-10-15 22:31:12 -07001490 hmep->hme_mii = mii_alloc(hmep, dip, &hme_mii_ops);
1491 if (hmep->hme_mii == NULL) {
1492 HME_FAULT_MSG1(hmep, SEVERITY_HIGH, CONFIG_MSG,
1493 "mii_alloc failed");
1494 goto error_intr;
1495 }
1496 /* force a probe for the PHY */
1497 mii_probe(hmep->hme_mii);
1498
gd7805985025c02007-07-12 10:37:47 -07001499 if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
1500 HME_FAULT_MSG1(hmep, SEVERITY_HIGH, CONFIG_MSG,
1501 "mac_alloc failed");
1502 goto error_intr;
1503 }
1504 macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
1505 macp->m_driver = hmep;
1506 macp->m_dip = dip;
1507 macp->m_src_addr = hmep->hme_ouraddr.ether_addr_octet;
1508 macp->m_callbacks = &hme_m_callbacks;
1509 macp->m_min_sdu = 0;
1510 macp->m_max_sdu = ETHERMTU;
yz147064d62bc4b2008-01-23 18:09:15 -08001511 macp->m_margin = VLAN_TAGSZ;
Garrett D'Amore06673d92009-10-15 22:31:12 -07001512 macp->m_priv_props = hme_priv_prop;
gd7805985025c02007-07-12 10:37:47 -07001513 if (mac_register(macp, &hmep->hme_mh) != 0) {
1514 mac_free(macp);
1515 goto error_intr;
1516 }
1517
1518 mac_free(macp);
1519
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001520 ddi_report_dev(dip);
1521 return (DDI_SUCCESS);
1522
1523 /*
1524 * Failure Exit
1525 */
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001526
1527error_intr:
1528 if (hmep->hme_cookie)
1529 ddi_remove_intr(dip, 0, (ddi_iblock_cookie_t)0);
1530
Garrett D'Amore06673d92009-10-15 22:31:12 -07001531 if (hmep->hme_mii)
1532 mii_free(hmep->hme_mii);
1533
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001534error_mutex:
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001535 mutex_destroy(&hmep->hme_xmitlock);
1536 mutex_destroy(&hmep->hme_intrlock);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001537
1538error_unmap:
1539 if (hmep->hme_globregh)
gd7805985025c02007-07-12 10:37:47 -07001540 ddi_regs_map_free(&hmep->hme_globregh);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001541 if (hmep->hme_cheerio_mode == 0) {
1542 if (hmep->hme_etxregh)
gd7805985025c02007-07-12 10:37:47 -07001543 ddi_regs_map_free(&hmep->hme_etxregh);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001544 if (hmep->hme_erxregh)
gd7805985025c02007-07-12 10:37:47 -07001545 ddi_regs_map_free(&hmep->hme_erxregh);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001546 if (hmep->hme_bmacregh)
gd7805985025c02007-07-12 10:37:47 -07001547 ddi_regs_map_free(&hmep->hme_bmacregh);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001548 if (hmep->hme_mifregh)
gd7805985025c02007-07-12 10:37:47 -07001549 ddi_regs_map_free(&hmep->hme_mifregh);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001550 } else {
1551 if (hmep->pci_config_handle)
1552 (void) pci_config_teardown(&hmep->pci_config_handle);
1553 hmep->hme_etxregh = hmep->hme_erxregh = hmep->hme_bmacregh =
1554 hmep->hme_mifregh = hmep->hme_globregh = NULL;
1555 }
1556
1557error_state:
Garrett D'Amore02193462009-05-11 21:07:23 -07001558 hmefreethings(hmep);
1559 hmefreebufs(hmep);
1560
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001561 if (hmep) {
1562 kmem_free((caddr_t)hmep, sizeof (*hmep));
1563 ddi_set_driver_private(dip, NULL);
1564 }
1565
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001566 return (DDI_FAILURE);
1567}
1568
gd78059f2cd0f02007-08-24 17:45:12 -07001569int
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001570hmedetach(dev_info_t *dip, ddi_detach_cmd_t cmd)
1571{
gd7805985025c02007-07-12 10:37:47 -07001572 struct hme *hmep;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001573
1574 if ((hmep = ddi_get_driver_private(dip)) == NULL)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001575 return (DDI_FAILURE);
1576
1577 switch (cmd) {
1578 case DDI_DETACH:
1579 break;
1580
1581 case DDI_SUSPEND:
Garrett D'Amore06673d92009-10-15 22:31:12 -07001582 mii_suspend(hmep->hme_mii);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001583 hmep->hme_flags |= HMESUSPENDED;
1584 hmeuninit(hmep);
1585 return (DDI_SUCCESS);
1586
1587 default:
gd7805985025c02007-07-12 10:37:47 -07001588 return (DDI_FAILURE);
1589 }
1590
1591
1592 if (mac_unregister(hmep->hme_mh) != 0) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001593 return (DDI_FAILURE);
1594 }
1595
1596 /*
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001597 * Make driver quiescent, we don't want to prevent the
gd780594dd87b62008-03-20 20:18:47 -07001598 * detach on failure. Note that this should be redundant,
1599 * since mac_stop should already have called hmeuninit().
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001600 */
gd780594dd87b62008-03-20 20:18:47 -07001601 if (!(hmep->hme_flags & HMESUSPENDED)) {
1602 (void) hmestop(hmep);
1603 }
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001604
Garrett D'Amore06673d92009-10-15 22:31:12 -07001605 if (hmep->hme_mii)
1606 mii_free(hmep->hme_mii);
1607
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001608 /*
1609 * Remove instance of the intr
1610 */
1611 ddi_remove_intr(dip, 0, (ddi_iblock_cookie_t)0);
1612
1613 /*
gd7805985025c02007-07-12 10:37:47 -07001614 * Unregister kstats.
1615 */
1616 if (hmep->hme_ksp != NULL)
1617 kstat_delete(hmep->hme_ksp);
1618 if (hmep->hme_intrstats != NULL)
1619 kstat_delete(hmep->hme_intrstats);
1620
1621 hmep->hme_ksp = NULL;
1622 hmep->hme_intrstats = NULL;
1623
1624 /*
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001625 * Destroy all mutexes and data structures allocated during
1626 * attach time.
gd7805985025c02007-07-12 10:37:47 -07001627 *
1628 * Note: at this time we should be the only thread accessing
1629 * the structures for this instance.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001630 */
1631
1632 if (hmep->hme_globregh)
1633 ddi_regs_map_free(&hmep->hme_globregh);
1634 if (hmep->hme_cheerio_mode == 0) {
1635 if (hmep->hme_etxregh)
gd7805985025c02007-07-12 10:37:47 -07001636 ddi_regs_map_free(&hmep->hme_etxregh);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001637 if (hmep->hme_erxregh)
gd7805985025c02007-07-12 10:37:47 -07001638 ddi_regs_map_free(&hmep->hme_erxregh);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001639 if (hmep->hme_bmacregh)
gd7805985025c02007-07-12 10:37:47 -07001640 ddi_regs_map_free(&hmep->hme_bmacregh);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001641 if (hmep->hme_mifregh)
gd7805985025c02007-07-12 10:37:47 -07001642 ddi_regs_map_free(&hmep->hme_mifregh);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001643 } else {
1644 if (hmep->pci_config_handle)
1645 (void) pci_config_teardown(&hmep->pci_config_handle);
1646 hmep->hme_etxregh = hmep->hme_erxregh = hmep->hme_bmacregh =
1647 hmep->hme_mifregh = hmep->hme_globregh = NULL;
1648 }
1649
gd7805985025c02007-07-12 10:37:47 -07001650 mutex_destroy(&hmep->hme_xmitlock);
1651 mutex_destroy(&hmep->hme_intrlock);
gd7805985025c02007-07-12 10:37:47 -07001652
Garrett D'Amore02193462009-05-11 21:07:23 -07001653 hmefreethings(hmep);
gd7805985025c02007-07-12 10:37:47 -07001654 hmefreebufs(hmep);
1655
gd7805985025c02007-07-12 10:37:47 -07001656 ddi_set_driver_private(dip, NULL);
1657 kmem_free(hmep, sizeof (struct hme));
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001658
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001659 return (DDI_SUCCESS);
1660}
1661
Garrett D'Amore02193462009-05-11 21:07:23 -07001662int
1663hmequiesce(dev_info_t *dip)
1664{
1665 struct hme *hmep;
1666
1667 if ((hmep = ddi_get_driver_private(dip)) == NULL)
1668 return (DDI_FAILURE);
1669
Garrett D'Amore02193462009-05-11 21:07:23 -07001670 (void) hmestop(hmep);
1671 return (DDI_SUCCESS);
1672}
1673
gd7805985025c02007-07-12 10:37:47 -07001674static boolean_t
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001675hmeinit_xfer_params(struct hme *hmep)
1676{
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001677 int hme_ipg1_conf, hme_ipg2_conf;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001678 int hme_ipg0_conf, hme_lance_mode_conf;
1679 int prop_len = sizeof (int);
1680 dev_info_t *dip;
1681
1682 dip = hmep->dip;
1683
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001684 /*
1685 * Set up the start-up values for user-configurable parameters
1686 * Get the values from the global variables first.
1687 * Use the MASK to limit the value to allowed maximum.
1688 */
Garrett D'Amore06673d92009-10-15 22:31:12 -07001689 hmep->hme_ipg1 = hme_ipg1 & HME_MASK_8BIT;
1690 hmep->hme_ipg2 = hme_ipg2 & HME_MASK_8BIT;
1691 hmep->hme_ipg0 = hme_ipg0 & HME_MASK_5BIT;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001692
1693 /*
1694 * Get the parameter values configured in .conf file.
1695 */
1696 if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "ipg1",
gd7805985025c02007-07-12 10:37:47 -07001697 (caddr_t)&hme_ipg1_conf, &prop_len) == DDI_PROP_SUCCESS) {
Garrett D'Amore06673d92009-10-15 22:31:12 -07001698 hmep->hme_ipg1 = hme_ipg1_conf & HME_MASK_8BIT;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001699 }
1700
1701 if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "ipg2",
gd7805985025c02007-07-12 10:37:47 -07001702 (caddr_t)&hme_ipg2_conf, &prop_len) == DDI_PROP_SUCCESS) {
Garrett D'Amore06673d92009-10-15 22:31:12 -07001703 hmep->hme_ipg2 = hme_ipg2_conf & HME_MASK_8BIT;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001704 }
1705
1706 if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "ipg0",
gd7805985025c02007-07-12 10:37:47 -07001707 (caddr_t)&hme_ipg0_conf, &prop_len) == DDI_PROP_SUCCESS) {
Garrett D'Amore06673d92009-10-15 22:31:12 -07001708 hmep->hme_ipg0 = hme_ipg0_conf & HME_MASK_5BIT;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001709 }
1710
1711 if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "lance_mode",
gd7805985025c02007-07-12 10:37:47 -07001712 (caddr_t)&hme_lance_mode_conf, &prop_len) == DDI_PROP_SUCCESS) {
Garrett D'Amore06673d92009-10-15 22:31:12 -07001713 hmep->hme_lance_mode = hme_lance_mode_conf & HME_MASK_1BIT;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001714 }
1715
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001716 return (B_TRUE);
1717}
1718
1719/*
1720 * Return 0 upon success, 1 on failure.
1721 */
1722static uint_t
1723hmestop(struct hme *hmep)
1724{
1725 /*
1726 * Disable the Tx dma engine.
1727 */
1728 PUT_ETXREG(config, (GET_ETXREG(config) & ~HMET_CONFIG_TXDMA_EN));
1729 HMEDELAY(((GET_ETXREG(state_mach) & 0x1f) == 0x1), HMEMAXRSTDELAY);
1730
1731 /*
1732 * Disable the Rx dma engine.
1733 */
1734 PUT_ERXREG(config, (GET_ERXREG(config) & ~HMER_CONFIG_RXDMA_EN));
1735 HMEDELAY(((GET_ERXREG(state_mach) & 0x3f) == 0), HMEMAXRSTDELAY);
1736
1737 /*
1738 * By this time all things should be quiet, so hit the
1739 * chip with a reset.
1740 */
1741 PUT_GLOBREG(reset, HMEG_RESET_GLOBAL);
1742
1743 HMEDELAY((GET_GLOBREG(reset) == 0), HMEMAXRSTDELAY);
1744 if (GET_GLOBREG(reset)) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001745 return (1);
1746 }
1747
1748 CHECK_GLOBREG();
1749 return (0);
1750}
1751
1752static int
1753hmestat_kstat_update(kstat_t *ksp, int rw)
1754{
1755 struct hme *hmep;
1756 struct hmekstat *hkp;
1757
1758 hmep = (struct hme *)ksp->ks_private;
1759 hkp = (struct hmekstat *)ksp->ks_data;
1760
gd7805985025c02007-07-12 10:37:47 -07001761 if (rw != KSTAT_READ)
1762 return (EACCES);
1763
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001764 /*
1765 * Update all the stats by reading all the counter registers.
1766 * Counter register stats are not updated till they overflow
1767 * and interrupt.
1768 */
1769
1770 mutex_enter(&hmep->hme_xmitlock);
gd780594dd87b62008-03-20 20:18:47 -07001771 if (hmep->hme_flags & HMERUNNING) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001772 hmereclaim(hmep);
gd780594dd87b62008-03-20 20:18:47 -07001773 hmesavecntrs(hmep);
1774 }
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001775 mutex_exit(&hmep->hme_xmitlock);
1776
gd7805985025c02007-07-12 10:37:47 -07001777 hkp->hk_cvc.value.ul = hmep->hme_cvc;
1778 hkp->hk_lenerr.value.ul = hmep->hme_lenerr;
1779 hkp->hk_buff.value.ul = hmep->hme_buff;
1780 hkp->hk_missed.value.ul = hmep->hme_missed;
1781 hkp->hk_allocbfail.value.ul = hmep->hme_allocbfail;
1782 hkp->hk_babl.value.ul = hmep->hme_babl;
1783 hkp->hk_tmder.value.ul = hmep->hme_tmder;
1784 hkp->hk_txlaterr.value.ul = hmep->hme_txlaterr;
1785 hkp->hk_rxlaterr.value.ul = hmep->hme_rxlaterr;
1786 hkp->hk_slvparerr.value.ul = hmep->hme_slvparerr;
1787 hkp->hk_txparerr.value.ul = hmep->hme_txparerr;
1788 hkp->hk_rxparerr.value.ul = hmep->hme_rxparerr;
1789 hkp->hk_slverrack.value.ul = hmep->hme_slverrack;
1790 hkp->hk_txerrack.value.ul = hmep->hme_txerrack;
1791 hkp->hk_rxerrack.value.ul = hmep->hme_rxerrack;
1792 hkp->hk_txtagerr.value.ul = hmep->hme_txtagerr;
1793 hkp->hk_rxtagerr.value.ul = hmep->hme_rxtagerr;
1794 hkp->hk_eoperr.value.ul = hmep->hme_eoperr;
1795 hkp->hk_notmds.value.ul = hmep->hme_notmds;
1796 hkp->hk_notbufs.value.ul = hmep->hme_notbufs;
1797 hkp->hk_norbufs.value.ul = hmep->hme_norbufs;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001798
gd7805985025c02007-07-12 10:37:47 -07001799 /*
1800 * Debug kstats
1801 */
1802 hkp->hk_inits.value.ul = hmep->inits;
gd7805985025c02007-07-12 10:37:47 -07001803 hkp->hk_phyfail.value.ul = hmep->phyfail;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001804
gd7805985025c02007-07-12 10:37:47 -07001805 /*
1806 * xcvr kstats
1807 */
1808 hkp->hk_asic_rev.value.ul = hmep->asic_rev;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001809
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001810 return (0);
1811}
1812
1813static void
1814hmestatinit(struct hme *hmep)
1815{
1816 struct kstat *ksp;
1817 struct hmekstat *hkp;
gd78059f2cd0f02007-08-24 17:45:12 -07001818 const char *driver;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001819 int instance;
1820 char buf[16];
1821
1822 instance = hmep->instance;
gd78059f2cd0f02007-08-24 17:45:12 -07001823 driver = ddi_driver_name(hmep->dip);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001824
gd78059f2cd0f02007-08-24 17:45:12 -07001825 if ((ksp = kstat_create(driver, instance,
gd7805985025c02007-07-12 10:37:47 -07001826 "driver_info", "net", KSTAT_TYPE_NAMED,
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001827 sizeof (struct hmekstat) / sizeof (kstat_named_t), 0)) == NULL) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001828 HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, INIT_MSG,
Garrett D'Amore02193462009-05-11 21:07:23 -07001829 "kstat_create failed");
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001830 return;
1831 }
1832
gd78059f2cd0f02007-08-24 17:45:12 -07001833 (void) snprintf(buf, sizeof (buf), "%sc%d", driver, instance);
1834 hmep->hme_intrstats = kstat_create(driver, instance, buf, "controller",
gd7805985025c02007-07-12 10:37:47 -07001835 KSTAT_TYPE_INTR, 1, KSTAT_FLAG_PERSISTENT);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001836 if (hmep->hme_intrstats)
1837 kstat_install(hmep->hme_intrstats);
1838
1839 hmep->hme_ksp = ksp;
1840 hkp = (struct hmekstat *)ksp->ks_data;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001841 kstat_named_init(&hkp->hk_cvc, "code_violations",
gd7805985025c02007-07-12 10:37:47 -07001842 KSTAT_DATA_ULONG);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001843 kstat_named_init(&hkp->hk_lenerr, "len_errors",
gd7805985025c02007-07-12 10:37:47 -07001844 KSTAT_DATA_ULONG);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001845 kstat_named_init(&hkp->hk_buff, "buff",
gd7805985025c02007-07-12 10:37:47 -07001846 KSTAT_DATA_ULONG);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001847 kstat_named_init(&hkp->hk_missed, "missed",
gd7805985025c02007-07-12 10:37:47 -07001848 KSTAT_DATA_ULONG);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001849 kstat_named_init(&hkp->hk_nocanput, "nocanput",
gd7805985025c02007-07-12 10:37:47 -07001850 KSTAT_DATA_ULONG);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001851 kstat_named_init(&hkp->hk_allocbfail, "allocbfail",
gd7805985025c02007-07-12 10:37:47 -07001852 KSTAT_DATA_ULONG);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001853 kstat_named_init(&hkp->hk_babl, "babble",
gd7805985025c02007-07-12 10:37:47 -07001854 KSTAT_DATA_ULONG);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001855 kstat_named_init(&hkp->hk_tmder, "tmd_error",
gd7805985025c02007-07-12 10:37:47 -07001856 KSTAT_DATA_ULONG);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001857 kstat_named_init(&hkp->hk_txlaterr, "tx_late_error",
gd7805985025c02007-07-12 10:37:47 -07001858 KSTAT_DATA_ULONG);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001859 kstat_named_init(&hkp->hk_rxlaterr, "rx_late_error",
gd7805985025c02007-07-12 10:37:47 -07001860 KSTAT_DATA_ULONG);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001861 kstat_named_init(&hkp->hk_slvparerr, "slv_parity_error",
gd7805985025c02007-07-12 10:37:47 -07001862 KSTAT_DATA_ULONG);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001863 kstat_named_init(&hkp->hk_txparerr, "tx_parity_error",
gd7805985025c02007-07-12 10:37:47 -07001864 KSTAT_DATA_ULONG);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001865 kstat_named_init(&hkp->hk_rxparerr, "rx_parity_error",
gd7805985025c02007-07-12 10:37:47 -07001866 KSTAT_DATA_ULONG);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001867 kstat_named_init(&hkp->hk_slverrack, "slv_error_ack",
gd7805985025c02007-07-12 10:37:47 -07001868 KSTAT_DATA_ULONG);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001869 kstat_named_init(&hkp->hk_txerrack, "tx_error_ack",
gd7805985025c02007-07-12 10:37:47 -07001870 KSTAT_DATA_ULONG);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001871 kstat_named_init(&hkp->hk_rxerrack, "rx_error_ack",
gd7805985025c02007-07-12 10:37:47 -07001872 KSTAT_DATA_ULONG);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001873 kstat_named_init(&hkp->hk_txtagerr, "tx_tag_error",
gd7805985025c02007-07-12 10:37:47 -07001874 KSTAT_DATA_ULONG);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001875 kstat_named_init(&hkp->hk_rxtagerr, "rx_tag_error",
gd7805985025c02007-07-12 10:37:47 -07001876 KSTAT_DATA_ULONG);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001877 kstat_named_init(&hkp->hk_eoperr, "eop_error",
gd7805985025c02007-07-12 10:37:47 -07001878 KSTAT_DATA_ULONG);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001879 kstat_named_init(&hkp->hk_notmds, "no_tmds",
gd7805985025c02007-07-12 10:37:47 -07001880 KSTAT_DATA_ULONG);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001881 kstat_named_init(&hkp->hk_notbufs, "no_tbufs",
gd7805985025c02007-07-12 10:37:47 -07001882 KSTAT_DATA_ULONG);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001883 kstat_named_init(&hkp->hk_norbufs, "no_rbufs",
gd7805985025c02007-07-12 10:37:47 -07001884 KSTAT_DATA_ULONG);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001885
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001886 /*
1887 * Debugging kstats
1888 */
1889 kstat_named_init(&hkp->hk_inits, "inits",
gd7805985025c02007-07-12 10:37:47 -07001890 KSTAT_DATA_ULONG);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001891 kstat_named_init(&hkp->hk_phyfail, "phy_failures",
gd7805985025c02007-07-12 10:37:47 -07001892 KSTAT_DATA_ULONG);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001893
1894 /*
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001895 * xcvr kstats
1896 */
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001897 kstat_named_init(&hkp->hk_asic_rev, "asic_rev",
gd7805985025c02007-07-12 10:37:47 -07001898 KSTAT_DATA_ULONG);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001899
1900 ksp->ks_update = hmestat_kstat_update;
1901 ksp->ks_private = (void *) hmep;
1902 kstat_install(ksp);
1903}
1904
Garrett D'Amore06673d92009-10-15 22:31:12 -07001905int
Venugopal Iyer0dc23662010-03-09 15:30:01 -08001906hme_m_getprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz,
1907 void *val)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001908{
Garrett D'Amore06673d92009-10-15 22:31:12 -07001909 struct hme *hmep = arg;
1910 int value;
Garrett D'Amore06673d92009-10-15 22:31:12 -07001911 int rv;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001912
Venugopal Iyer0dc23662010-03-09 15:30:01 -08001913 rv = mii_m_getprop(hmep->hme_mii, name, num, sz, val);
Garrett D'Amore06673d92009-10-15 22:31:12 -07001914 if (rv != ENOTSUP)
1915 return (rv);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001916
Garrett D'Amore06673d92009-10-15 22:31:12 -07001917 switch (num) {
1918 case MAC_PROP_PRIVATE:
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001919 break;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001920 default:
Garrett D'Amore06673d92009-10-15 22:31:12 -07001921 return (ENOTSUP);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001922 }
Garrett D'Amore06673d92009-10-15 22:31:12 -07001923
Garrett D'Amore06673d92009-10-15 22:31:12 -07001924 if (strcmp(name, "_ipg0") == 0) {
Venugopal Iyer0dc23662010-03-09 15:30:01 -08001925 value = hmep->hme_ipg0;
Garrett D'Amore06673d92009-10-15 22:31:12 -07001926 } else if (strcmp(name, "_ipg1") == 0) {
Venugopal Iyer0dc23662010-03-09 15:30:01 -08001927 value = hmep->hme_ipg1;
Garrett D'Amore06673d92009-10-15 22:31:12 -07001928 } else if (strcmp(name, "_ipg2") == 0) {
Venugopal Iyer0dc23662010-03-09 15:30:01 -08001929 value = hmep->hme_ipg2;
Garrett D'Amore06673d92009-10-15 22:31:12 -07001930 } else if (strcmp(name, "_lance_mode") == 0) {
Venugopal Iyer0dc23662010-03-09 15:30:01 -08001931 value = hmep->hme_lance_mode;
Garrett D'Amore06673d92009-10-15 22:31:12 -07001932 } else {
1933 return (ENOTSUP);
1934 }
1935 (void) snprintf(val, sz, "%d", value);
1936 return (0);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001937}
1938
Venugopal Iyer0dc23662010-03-09 15:30:01 -08001939static void
1940hme_m_propinfo(void *arg, const char *name, mac_prop_id_t num,
1941 mac_prop_info_handle_t mph)
1942{
1943 struct hme *hmep = arg;
1944
1945 mii_m_propinfo(hmep->hme_mii, name, num, mph);
1946
1947 switch (num) {
1948 case MAC_PROP_PRIVATE: {
1949 char valstr[64];
1950 int default_val;
1951
1952 if (strcmp(name, "_ipg0") == 0) {
1953 default_val = hme_ipg0;
1954 } else if (strcmp(name, "_ipg1") == 0) {
1955 default_val = hme_ipg1;
1956 } else if (strcmp(name, "_ipg2") == 0) {
1957 default_val = hme_ipg2;
1958 } if (strcmp(name, "_lance_mode") == 0) {
1959 default_val = hme_lance_mode;
1960 } else {
1961 return;
1962 }
1963
1964 (void) snprintf(valstr, sizeof (valstr), "%d", default_val);
1965 mac_prop_info_set_default_str(mph, valstr);
1966 break;
1967 }
1968 }
1969}
1970
Garrett D'Amore06673d92009-10-15 22:31:12 -07001971int
1972hme_m_setprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz,
1973 const void *val)
1974{
1975 struct hme *hmep = arg;
1976 int rv;
1977 long lval;
1978 boolean_t init = B_FALSE;
1979
1980 rv = mii_m_setprop(hmep->hme_mii, name, num, sz, val);
1981 if (rv != ENOTSUP)
1982 return (rv);
1983 rv = 0;
1984
1985 switch (num) {
1986 case MAC_PROP_PRIVATE:
1987 break;
1988 default:
1989 return (ENOTSUP);
1990 }
1991
1992 (void) ddi_strtol(val, NULL, 0, &lval);
1993
1994 if (strcmp(name, "_ipg1") == 0) {
1995 if ((lval >= 0) && (lval <= 255)) {
1996 hmep->hme_ipg1 = lval & 0xff;
1997 init = B_TRUE;
1998 } else {
1999 return (EINVAL);
2000 }
2001
2002 } else if (strcmp(name, "_ipg2") == 0) {
2003 if ((lval >= 0) && (lval <= 255)) {
2004 hmep->hme_ipg2 = lval & 0xff;
2005 init = B_TRUE;
2006 } else {
2007 return (EINVAL);
2008 }
2009
2010 } else if (strcmp(name, "_ipg0") == 0) {
2011 if ((lval >= 0) && (lval <= 31)) {
2012 hmep->hme_ipg0 = lval & 0xff;
2013 init = B_TRUE;
2014 } else {
2015 return (EINVAL);
2016 }
2017 } else if (strcmp(name, "_lance_mode") == 0) {