10219346bSGarrett D'Amore /*
20219346bSGarrett D'Amore * CDDL HEADER START
30219346bSGarrett D'Amore *
40219346bSGarrett D'Amore * The contents of this file are subject to the terms of the
50219346bSGarrett D'Amore * Common Development and Distribution License (the "License").
60219346bSGarrett D'Amore * You may not use this file except in compliance with the License.
70219346bSGarrett D'Amore *
80219346bSGarrett D'Amore * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90219346bSGarrett D'Amore * or http://www.opensolaris.org/os/licensing.
100219346bSGarrett D'Amore * See the License for the specific language governing permissions
110219346bSGarrett D'Amore * and limitations under the License.
120219346bSGarrett D'Amore *
130219346bSGarrett D'Amore * When distributing Covered Code, include this CDDL HEADER in each
140219346bSGarrett D'Amore * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150219346bSGarrett D'Amore * If applicable, add the following below this CDDL HEADER, with the
160219346bSGarrett D'Amore * fields enclosed by brackets "[]" replaced with your own identifying
170219346bSGarrett D'Amore * information: Portions Copyright [yyyy] [name of copyright owner]
180219346bSGarrett D'Amore *
190219346bSGarrett D'Amore * CDDL HEADER END
200219346bSGarrett D'Amore */
210219346bSGarrett D'Amore /*
22*7a92e70fSZeeshanul Huq - Sun Microsystems - Beijing China * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
230219346bSGarrett D'Amore */
240219346bSGarrett D'Amore
250219346bSGarrett D'Amore
260219346bSGarrett D'Amore /*
270219346bSGarrett D'Amore * SunOS MT STREAMS FEPS(SBus)/Cheerio(PCI) 10/100Mb Ethernet Device Driver
280219346bSGarrett D'Amore */
290219346bSGarrett D'Amore
300219346bSGarrett D'Amore #include <sys/types.h>
310219346bSGarrett D'Amore #include <sys/debug.h>
320219346bSGarrett D'Amore #include <sys/stream.h>
330219346bSGarrett D'Amore #include <sys/cmn_err.h>
340219346bSGarrett D'Amore #include <sys/kmem.h>
350219346bSGarrett D'Amore #include <sys/crc32.h>
360219346bSGarrett D'Amore #include <sys/modctl.h>
370219346bSGarrett D'Amore #include <sys/conf.h>
380219346bSGarrett D'Amore #include <sys/strsun.h>
390219346bSGarrett D'Amore #include <sys/kstat.h>
400219346bSGarrett D'Amore #include <sys/pattr.h>
410219346bSGarrett D'Amore #include <sys/dlpi.h>
420219346bSGarrett D'Amore #include <sys/strsubr.h>
430219346bSGarrett D'Amore #include <sys/mac_provider.h>
440219346bSGarrett D'Amore #include <sys/mac_ether.h>
4506673d9bSGarrett D'Amore #include <sys/mii.h>
460219346bSGarrett D'Amore #include <sys/ethernet.h>
470219346bSGarrett D'Amore #include <sys/vlan.h>
480219346bSGarrett D'Amore #include <sys/pci.h>
490219346bSGarrett D'Amore #include <sys/policy.h>
500219346bSGarrett D'Amore #include <sys/ddi.h>
510219346bSGarrett D'Amore #include <sys/sunddi.h>
520dc2366fSVenugopal Iyer #include <sys/byteorder.h>
530219346bSGarrett D'Amore #include "hme_phy.h"
540219346bSGarrett D'Amore #include "hme_mac.h"
550219346bSGarrett D'Amore #include "hme.h"
560219346bSGarrett D'Amore
570219346bSGarrett D'Amore typedef void (*fptrv_t)();
580219346bSGarrett D'Amore
590219346bSGarrett D'Amore typedef enum {
600219346bSGarrett D'Amore NO_MSG = 0,
6106673d9bSGarrett D'Amore AUTOCONFIG_MSG,
6206673d9bSGarrett D'Amore DISPLAY_MSG,
6306673d9bSGarrett D'Amore INIT_MSG,
6406673d9bSGarrett D'Amore UNINIT_MSG,
6506673d9bSGarrett D'Amore CONFIG_MSG,
6606673d9bSGarrett D'Amore MII_MSG,
6706673d9bSGarrett D'Amore FATAL_ERR_MSG,
6806673d9bSGarrett D'Amore NFATAL_ERR_MSG,
6906673d9bSGarrett D'Amore XCVR_MSG,
7006673d9bSGarrett D'Amore NOXCVR_MSG,
7106673d9bSGarrett D'Amore ERX_MSG,
7206673d9bSGarrett D'Amore DDI_MSG,
730219346bSGarrett D'Amore } msg_t;
740219346bSGarrett D'Amore
750219346bSGarrett D'Amore msg_t hme_debug_level = NO_MSG;
760219346bSGarrett D'Amore
770219346bSGarrett D'Amore static char *msg_string[] = {
780219346bSGarrett D'Amore "NONE ",
790219346bSGarrett D'Amore "AUTOCONFIG ",
8006673d9bSGarrett D'Amore "DISPLAY "
810219346bSGarrett D'Amore "INIT ",
820219346bSGarrett D'Amore "UNINIT ",
830219346bSGarrett D'Amore "CONFIG ",
8406673d9bSGarrett D'Amore "MII ",
850219346bSGarrett D'Amore "FATAL_ERR ",
860219346bSGarrett D'Amore "NFATAL_ERR ",
870219346bSGarrett D'Amore "XCVR ",
880219346bSGarrett D'Amore "NOXCVR ",
890219346bSGarrett D'Amore "ERX ",
900219346bSGarrett D'Amore "DDI ",
910219346bSGarrett D'Amore };
920219346bSGarrett D'Amore
930219346bSGarrett D'Amore #define SEVERITY_NONE 0
940219346bSGarrett D'Amore #define SEVERITY_LOW 0
950219346bSGarrett D'Amore #define SEVERITY_MID 1
960219346bSGarrett D'Amore #define SEVERITY_HIGH 2
970219346bSGarrett D'Amore #define SEVERITY_UNKNOWN 99
980219346bSGarrett D'Amore
990219346bSGarrett D'Amore #define FEPS_URUN_BUG
1000219346bSGarrett D'Amore #define HME_CODEVIOL_BUG
1010219346bSGarrett D'Amore
1020219346bSGarrett D'Amore #define KIOIP KSTAT_INTR_PTR(hmep->hme_intrstats)
1030219346bSGarrett D'Amore
1040219346bSGarrett D'Amore /*
1050219346bSGarrett D'Amore * The following variables are used for checking fixes in Sbus/FEPS 2.0
1060219346bSGarrett D'Amore */
1070219346bSGarrett D'Amore static int hme_urun_fix = 0; /* Bug fixed in Sbus/FEPS 2.0 */
1080219346bSGarrett D'Amore
1090219346bSGarrett D'Amore /*
1100219346bSGarrett D'Amore * The following variables are used for configuring various features
1110219346bSGarrett D'Amore */
1120219346bSGarrett D'Amore static int hme_64bit_enable = 1; /* Use 64-bit sbus transfers */
1130219346bSGarrett D'Amore static int hme_reject_own = 1; /* Reject packets with own SA */
11406673d9bSGarrett D'Amore static int hme_ngu_enable = 0; /* Never Give Up mode */
1150219346bSGarrett D'Amore
1160dc2366fSVenugopal Iyer char *hme_priv_prop[] = {
1170dc2366fSVenugopal Iyer "_ipg0",
1180dc2366fSVenugopal Iyer "_ipg1",
1190dc2366fSVenugopal Iyer "_ipg2",
1200dc2366fSVenugopal Iyer "_lance_mode",
1210dc2366fSVenugopal Iyer NULL
12206673d9bSGarrett D'Amore };
1230219346bSGarrett D'Amore
1240219346bSGarrett D'Amore static int hme_lance_mode = 1; /* to enable lance mode */
1250219346bSGarrett D'Amore static int hme_ipg0 = 16;
1260219346bSGarrett D'Amore static int hme_ipg1 = 8;
1270219346bSGarrett D'Amore static int hme_ipg2 = 4;
1280219346bSGarrett D'Amore
1290219346bSGarrett D'Amore /*
1300219346bSGarrett D'Amore * The following parameters may be configured by the user. If they are not
1310219346bSGarrett D'Amore * configured by the user, the values will be based on the capabilities of
1320219346bSGarrett D'Amore * the transceiver.
1330219346bSGarrett D'Amore * The value "HME_NOTUSR" is ORed with the parameter value to indicate values
1340219346bSGarrett D'Amore * which are NOT configured by the user.
1350219346bSGarrett D'Amore */
1360219346bSGarrett D'Amore
1370219346bSGarrett D'Amore #define HME_NOTUSR 0x0f000000
1380219346bSGarrett D'Amore #define HME_MASK_1BIT 0x1
1390219346bSGarrett D'Amore #define HME_MASK_5BIT 0x1f
1400219346bSGarrett D'Amore #define HME_MASK_8BIT 0xff
1410219346bSGarrett D'Amore
1420219346bSGarrett D'Amore /*
1430219346bSGarrett D'Amore * All strings used by hme messaging functions
1440219346bSGarrett D'Amore */
1450219346bSGarrett D'Amore
1460219346bSGarrett D'Amore static char *no_xcvr_msg =
1470219346bSGarrett D'Amore "No transceiver found.";
1480219346bSGarrett D'Amore
1490219346bSGarrett D'Amore static char *burst_size_msg =
1500219346bSGarrett D'Amore "Could not identify the burst size";
1510219346bSGarrett D'Amore
1520219346bSGarrett D'Amore static char *unk_rx_ringsz_msg =
1530219346bSGarrett D'Amore "Unknown receive RINGSZ";
1540219346bSGarrett D'Amore
1550219346bSGarrett D'Amore static char *add_intr_fail_msg =
1560219346bSGarrett D'Amore "ddi_add_intr(9F) failed";
1570219346bSGarrett D'Amore
1580219346bSGarrett D'Amore static char *mregs_4global_reg_fail_msg =
1590219346bSGarrett D'Amore "ddi_regs_map_setup(9F) for global reg failed";
1600219346bSGarrett D'Amore
1610219346bSGarrett D'Amore static char *mregs_4etx_reg_fail_msg =
1620219346bSGarrett D'Amore "ddi_map_regs for etx reg failed";
1630219346bSGarrett D'Amore
1640219346bSGarrett D'Amore static char *mregs_4erx_reg_fail_msg =
1650219346bSGarrett D'Amore "ddi_map_regs for erx reg failed";
1660219346bSGarrett D'Amore
1670219346bSGarrett D'Amore static char *mregs_4bmac_reg_fail_msg =
1680219346bSGarrett D'Amore "ddi_map_regs for bmac reg failed";
1690219346bSGarrett D'Amore
1700219346bSGarrett D'Amore static char *mregs_4mif_reg_fail_msg =
1710219346bSGarrett D'Amore "ddi_map_regs for mif reg failed";
1720219346bSGarrett D'Amore
1730219346bSGarrett D'Amore static char *init_fail_gen_msg =
1740219346bSGarrett D'Amore "Failed to initialize hardware/driver";
1750219346bSGarrett D'Amore
1760219346bSGarrett D'Amore static char *ddi_nregs_fail_msg =
1770219346bSGarrett D'Amore "ddi_dev_nregs failed(9F), returned %d";
1780219346bSGarrett D'Amore
1790219346bSGarrett D'Amore static char *bad_num_regs_msg =
1800219346bSGarrett D'Amore "Invalid number of registers.";
1810219346bSGarrett D'Amore
1820219346bSGarrett D'Amore
1830219346bSGarrett D'Amore /* FATAL ERR msgs */
1840219346bSGarrett D'Amore /*
1850219346bSGarrett D'Amore * Function prototypes.
1860219346bSGarrett D'Amore */
1870219346bSGarrett D'Amore /* these two are global so that qfe can use them */
1880219346bSGarrett D'Amore int hmeattach(dev_info_t *, ddi_attach_cmd_t);
1890219346bSGarrett D'Amore int hmedetach(dev_info_t *, ddi_detach_cmd_t);
1900219346bSGarrett D'Amore int hmequiesce(dev_info_t *);
1910219346bSGarrett D'Amore static boolean_t hmeinit_xfer_params(struct hme *);
1920219346bSGarrett D'Amore static uint_t hmestop(struct hme *);
1930219346bSGarrett D'Amore static void hmestatinit(struct hme *);
1940219346bSGarrett D'Amore static int hmeallocthings(struct hme *);
1950219346bSGarrett D'Amore static void hmefreethings(struct hme *);
1960219346bSGarrett D'Amore static int hmeallocbuf(struct hme *, hmebuf_t *, int);
1970219346bSGarrett D'Amore static int hmeallocbufs(struct hme *);
1980219346bSGarrett D'Amore static void hmefreebufs(struct hme *);
1990219346bSGarrett D'Amore static void hmeget_hm_rev_property(struct hme *);
2000219346bSGarrett D'Amore static boolean_t hmestart(struct hme *, mblk_t *);
2010219346bSGarrett D'Amore static uint_t hmeintr(caddr_t);
2020219346bSGarrett D'Amore static void hmereclaim(struct hme *);
2030219346bSGarrett D'Amore static int hmeinit(struct hme *);
2040219346bSGarrett D'Amore static void hmeuninit(struct hme *hmep);
2050219346bSGarrett D'Amore static mblk_t *hmeread(struct hme *, hmebuf_t *, uint32_t);
2060219346bSGarrett D'Amore static void hmesavecntrs(struct hme *);
2070219346bSGarrett D'Amore static void hme_fatal_err(struct hme *, uint_t);
2080219346bSGarrett D'Amore static void hme_nonfatal_err(struct hme *, uint_t);
2090219346bSGarrett D'Amore static int hmeburstsizes(struct hme *);
21006673d9bSGarrett D'Amore static void send_bit(struct hme *, uint16_t);
21106673d9bSGarrett D'Amore static uint16_t get_bit_std(uint8_t, struct hme *);
21206673d9bSGarrett D'Amore static uint16_t hme_bb_mii_read(struct hme *, uint8_t, uint8_t);
21306673d9bSGarrett D'Amore static void hme_bb_mii_write(struct hme *, uint8_t, uint8_t, uint16_t);
2140219346bSGarrett D'Amore static void hme_bb_force_idle(struct hme *);
21506673d9bSGarrett D'Amore static uint16_t hme_mii_read(void *, uint8_t, uint8_t);
21606673d9bSGarrett D'Amore static void hme_mii_write(void *, uint8_t, uint8_t, uint16_t);
2170219346bSGarrett D'Amore static void hme_setup_mac_address(struct hme *, dev_info_t *);
21806673d9bSGarrett D'Amore static void hme_mii_notify(void *, link_state_t);
2190219346bSGarrett D'Amore
2200219346bSGarrett D'Amore static void hme_fault_msg(struct hme *, uint_t, msg_t, char *, ...);
2210219346bSGarrett D'Amore
2220219346bSGarrett D'Amore static void hme_check_acc_handle(char *, uint_t, struct hme *,
2230219346bSGarrett D'Amore ddi_acc_handle_t);
2240219346bSGarrett D'Amore
2250219346bSGarrett D'Amore /*
2260219346bSGarrett D'Amore * Nemo (GLDv3) Functions.
2270219346bSGarrett D'Amore */
2280219346bSGarrett D'Amore static int hme_m_stat(void *, uint_t, uint64_t *);
2290219346bSGarrett D'Amore static int hme_m_start(void *);
2300219346bSGarrett D'Amore static void hme_m_stop(void *);
2310219346bSGarrett D'Amore static int hme_m_promisc(void *, boolean_t);
2320219346bSGarrett D'Amore static int hme_m_multicst(void *, boolean_t, const uint8_t *);
2330219346bSGarrett D'Amore static int hme_m_unicst(void *, const uint8_t *);
2340219346bSGarrett D'Amore static mblk_t *hme_m_tx(void *, mblk_t *);
2350219346bSGarrett D'Amore static boolean_t hme_m_getcapab(void *, mac_capab_t, void *);
2360dc2366fSVenugopal Iyer static int hme_m_getprop(void *, const char *, mac_prop_id_t, uint_t, void *);
2370dc2366fSVenugopal Iyer static void hme_m_propinfo(void *, const char *, mac_prop_id_t,
2380dc2366fSVenugopal Iyer mac_prop_info_handle_t);
23906673d9bSGarrett D'Amore static int hme_m_setprop(void *, const char *, mac_prop_id_t, uint_t,
24006673d9bSGarrett D'Amore const void *);
24106673d9bSGarrett D'Amore
24206673d9bSGarrett D'Amore static mii_ops_t hme_mii_ops = {
24306673d9bSGarrett D'Amore MII_OPS_VERSION,
24406673d9bSGarrett D'Amore hme_mii_read,
24506673d9bSGarrett D'Amore hme_mii_write,
24606673d9bSGarrett D'Amore hme_mii_notify,
24706673d9bSGarrett D'Amore NULL
24806673d9bSGarrett D'Amore };
2490219346bSGarrett D'Amore
2500219346bSGarrett D'Amore static mac_callbacks_t hme_m_callbacks = {
2510dc2366fSVenugopal Iyer MC_GETCAPAB | MC_SETPROP | MC_GETPROP | MC_PROPINFO,
2520219346bSGarrett D'Amore hme_m_stat,
2530219346bSGarrett D'Amore hme_m_start,
2540219346bSGarrett D'Amore hme_m_stop,
2550219346bSGarrett D'Amore hme_m_promisc,
2560219346bSGarrett D'Amore hme_m_multicst,
2570219346bSGarrett D'Amore hme_m_unicst,
2580219346bSGarrett D'Amore hme_m_tx,
25906673d9bSGarrett D'Amore NULL,
2600dc2366fSVenugopal Iyer NULL,
2610219346bSGarrett D'Amore hme_m_getcapab,
26206673d9bSGarrett D'Amore NULL,
26306673d9bSGarrett D'Amore NULL,
26406673d9bSGarrett D'Amore hme_m_setprop,
26506673d9bSGarrett D'Amore hme_m_getprop,
2660dc2366fSVenugopal Iyer hme_m_propinfo
2670219346bSGarrett D'Amore };
2680219346bSGarrett D'Amore
2690219346bSGarrett D'Amore DDI_DEFINE_STREAM_OPS(hme_dev_ops, nulldev, nulldev, hmeattach, hmedetach,
2700219346bSGarrett D'Amore nodev, NULL, D_MP, NULL, hmequiesce);
2710219346bSGarrett D'Amore
2720219346bSGarrett D'Amore #define HME_FAULT_MSG1(p, s, t, f) \
2730219346bSGarrett D'Amore hme_fault_msg((p), (s), (t), (f));
2740219346bSGarrett D'Amore
2750219346bSGarrett D'Amore #define HME_FAULT_MSG2(p, s, t, f, a) \
2760219346bSGarrett D'Amore hme_fault_msg((p), (s), (t), (f), (a));
2770219346bSGarrett D'Amore
2780219346bSGarrett D'Amore #define HME_FAULT_MSG3(p, s, t, f, a, b) \
2790219346bSGarrett D'Amore hme_fault_msg((p), (s), (t), (f), (a), (b));
2800219346bSGarrett D'Amore
2810219346bSGarrett D'Amore #define HME_FAULT_MSG4(p, s, t, f, a, b, c) \
2820219346bSGarrett D'Amore hme_fault_msg((p), (s), (t), (f), (a), (b), (c));
2830219346bSGarrett D'Amore
2840219346bSGarrett D'Amore #define CHECK_MIFREG() \
2850219346bSGarrett D'Amore hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_mifregh)
2860219346bSGarrett D'Amore #define CHECK_ETXREG() \
2870219346bSGarrett D'Amore hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_etxregh)
2880219346bSGarrett D'Amore #define CHECK_ERXREG() \
2890219346bSGarrett D'Amore hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_erxregh)
2900219346bSGarrett D'Amore #define CHECK_MACREG() \
2910219346bSGarrett D'Amore hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_bmacregh)
2920219346bSGarrett D'Amore #define CHECK_GLOBREG() \
2930219346bSGarrett D'Amore hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_globregh)
2940219346bSGarrett D'Amore
2950219346bSGarrett D'Amore /*
2960219346bSGarrett D'Amore * Claim the device is ultra-capable of burst in the beginning. Use
2970219346bSGarrett D'Amore * the value returned by ddi_dma_burstsizes() to actually set the HME
2980219346bSGarrett D'Amore * global configuration register later.
2990219346bSGarrett D'Amore *
3000219346bSGarrett D'Amore * Sbus/FEPS supports burst sizes of 16, 32 and 64 bytes. Also, it supports
3010219346bSGarrett D'Amore * 32-bit and 64-bit Sbus transfers. Hence the dlim_burstsizes field contains
3020219346bSGarrett D'Amore * the the burstsizes in both the lo and hi words.
3030219346bSGarrett D'Amore */
3040219346bSGarrett D'Amore #define HMELIMADDRLO ((uint64_t)0x00000000)
3050219346bSGarrett D'Amore #define HMELIMADDRHI ((uint64_t)0xffffffff)
3060219346bSGarrett D'Amore
3070219346bSGarrett D'Amore /*
3080219346bSGarrett D'Amore * Note that rx and tx data buffers can be arbitrarily aligned, but
3090219346bSGarrett D'Amore * that the descriptor rings need to be aligned on 2K boundaries, per
3100219346bSGarrett D'Amore * the spec.
3110219346bSGarrett D'Amore */
3120219346bSGarrett D'Amore static ddi_dma_attr_t hme_dma_attr = {
3130219346bSGarrett D'Amore DMA_ATTR_V0, /* version number. */
3140219346bSGarrett D'Amore (uint64_t)HMELIMADDRLO, /* low address */
3150219346bSGarrett D'Amore (uint64_t)HMELIMADDRHI, /* high address */
3160219346bSGarrett D'Amore (uint64_t)0x00ffffff, /* address counter max */
3170219346bSGarrett D'Amore (uint64_t)HME_HMDALIGN, /* alignment */
3180219346bSGarrett D'Amore (uint_t)0x00700070, /* dlim_burstsizes for 32 and 64 bit xfers */
3190219346bSGarrett D'Amore (uint32_t)0x1, /* minimum transfer size */
3200219346bSGarrett D'Amore (uint64_t)0x7fffffff, /* maximum transfer size */
3210219346bSGarrett D'Amore (uint64_t)0x00ffffff, /* maximum segment size */
3220219346bSGarrett D'Amore 1, /* scatter/gather list length */
3230219346bSGarrett D'Amore 512, /* granularity */
3240219346bSGarrett D'Amore 0 /* attribute flags */
3250219346bSGarrett D'Amore };
3260219346bSGarrett D'Amore
3270219346bSGarrett D'Amore static ddi_device_acc_attr_t hme_buf_attr = {
3280219346bSGarrett D'Amore DDI_DEVICE_ATTR_V0,
3290219346bSGarrett D'Amore DDI_NEVERSWAP_ACC,
3300219346bSGarrett D'Amore DDI_STRICTORDER_ACC, /* probably could allow merging & caching */
3310219346bSGarrett D'Amore DDI_DEFAULT_ACC,
3320219346bSGarrett D'Amore };
3330219346bSGarrett D'Amore
3340219346bSGarrett D'Amore static uchar_t pci_latency_timer = 0;
3350219346bSGarrett D'Amore
3360219346bSGarrett D'Amore /*
3370219346bSGarrett D'Amore * Module linkage information for the kernel.
3380219346bSGarrett D'Amore */
3390219346bSGarrett D'Amore static struct modldrv modldrv = {
3400219346bSGarrett D'Amore &mod_driverops, /* Type of module. This one is a driver */
3410219346bSGarrett D'Amore "Sun HME 10/100 Mb Ethernet",
3420219346bSGarrett D'Amore &hme_dev_ops, /* driver ops */
3430219346bSGarrett D'Amore };
3440219346bSGarrett D'Amore
3450219346bSGarrett D'Amore static struct modlinkage modlinkage = {
3460219346bSGarrett D'Amore MODREV_1, &modldrv, NULL
3470219346bSGarrett D'Amore };
3480219346bSGarrett D'Amore
3490219346bSGarrett D'Amore /* <<<<<<<<<<<<<<<<<<<<<< Register operations >>>>>>>>>>>>>>>>>>>>> */
3500219346bSGarrett D'Amore
3510219346bSGarrett D'Amore #define GET_MIFREG(reg) \
3520219346bSGarrett D'Amore ddi_get32(hmep->hme_mifregh, (uint32_t *)&hmep->hme_mifregp->reg)
3530219346bSGarrett D'Amore #define PUT_MIFREG(reg, value) \
3540219346bSGarrett D'Amore ddi_put32(hmep->hme_mifregh, (uint32_t *)&hmep->hme_mifregp->reg, value)
3550219346bSGarrett D'Amore
3560219346bSGarrett D'Amore #define GET_ETXREG(reg) \
3570219346bSGarrett D'Amore ddi_get32(hmep->hme_etxregh, (uint32_t *)&hmep->hme_etxregp->reg)
3580219346bSGarrett D'Amore #define PUT_ETXREG(reg, value) \
3590219346bSGarrett D'Amore ddi_put32(hmep->hme_etxregh, (uint32_t *)&hmep->hme_etxregp->reg, value)
3600219346bSGarrett D'Amore #define GET_ERXREG(reg) \
3610219346bSGarrett D'Amore ddi_get32(hmep->hme_erxregh, (uint32_t *)&hmep->hme_erxregp->reg)
3620219346bSGarrett D'Amore #define PUT_ERXREG(reg, value) \
3630219346bSGarrett D'Amore ddi_put32(hmep->hme_erxregh, (uint32_t *)&hmep->hme_erxregp->reg, value)
3640219346bSGarrett D'Amore #define GET_MACREG(reg) \
3650219346bSGarrett D'Amore ddi_get32(hmep->hme_bmacregh, (uint32_t *)&hmep->hme_bmacregp->reg)
3660219346bSGarrett D'Amore #define PUT_MACREG(reg, value) \
3670219346bSGarrett D'Amore ddi_put32(hmep->hme_bmacregh, \
3680219346bSGarrett D'Amore (uint32_t *)&hmep->hme_bmacregp->reg, value)
3690219346bSGarrett D'Amore #define GET_GLOBREG(reg) \
3700219346bSGarrett D'Amore ddi_get32(hmep->hme_globregh, (uint32_t *)&hmep->hme_globregp->reg)
3710219346bSGarrett D'Amore #define PUT_GLOBREG(reg, value) \
3720219346bSGarrett D'Amore ddi_put32(hmep->hme_globregh, \
3730219346bSGarrett D'Amore (uint32_t *)&hmep->hme_globregp->reg, value)
3740219346bSGarrett D'Amore #define PUT_TMD(ptr, paddr, len, flags) \
3750219346bSGarrett D'Amore ddi_put32(hmep->hme_tmd_acch, &hmep->hme_tmdp[ptr].tmd_addr, paddr); \
3760219346bSGarrett D'Amore ddi_put32(hmep->hme_tmd_acch, &hmep->hme_tmdp[ptr].tmd_flags, \
3770219346bSGarrett D'Amore len | flags)
3780219346bSGarrett D'Amore #define GET_TMD_FLAGS(ptr) \
3790219346bSGarrett D'Amore ddi_get32(hmep->hme_tmd_acch, &hmep->hme_tmdp[ptr].tmd_flags)
3800219346bSGarrett D'Amore #define PUT_RMD(ptr, paddr) \
3810219346bSGarrett D'Amore ddi_put32(hmep->hme_rmd_acch, &hmep->hme_rmdp[ptr].rmd_addr, paddr); \
3820219346bSGarrett D'Amore ddi_put32(hmep->hme_rmd_acch, &hmep->hme_rmdp[ptr].rmd_flags, \
3830219346bSGarrett D'Amore (uint32_t)(HMEBUFSIZE << HMERMD_BUFSIZE_SHIFT) | HMERMD_OWN)
3840219346bSGarrett D'Amore #define GET_RMD_FLAGS(ptr) \
3850219346bSGarrett D'Amore ddi_get32(hmep->hme_rmd_acch, &hmep->hme_rmdp[ptr].rmd_flags)
3860219346bSGarrett D'Amore
3870219346bSGarrett D'Amore #define GET_ROM8(offset) \
3880219346bSGarrett D'Amore ddi_get8((hmep->hme_romh), (offset))
3890219346bSGarrett D'Amore
3900219346bSGarrett D'Amore /*
3910219346bSGarrett D'Amore * Ether_copy is not endian-correct. Define an endian-correct version.
3920219346bSGarrett D'Amore */
3930219346bSGarrett D'Amore #define ether_bcopy(a, b) (bcopy(a, b, 6))
3940219346bSGarrett D'Amore
3950219346bSGarrett D'Amore /*
3960219346bSGarrett D'Amore * Ether-type is specifically big-endian, but data region is unknown endian
3970219346bSGarrett D'Amore */
3980219346bSGarrett D'Amore #define get_ether_type(ptr) \
3990219346bSGarrett D'Amore (((((uint8_t *)ptr)[12] << 8) | (((uint8_t *)ptr)[13])))
4000219346bSGarrett D'Amore
4010219346bSGarrett D'Amore /* <<<<<<<<<<<<<<<<<<<<<< Configuration Parameters >>>>>>>>>>>>>>>>>>>>> */
4020219346bSGarrett D'Amore
4030219346bSGarrett D'Amore #define BMAC_DEFAULT_JAMSIZE (0x04) /* jamsize equals 4 */
4040219346bSGarrett D'Amore #define BMAC_LONG_JAMSIZE (0x10) /* jamsize equals 0x10 */
4050219346bSGarrett D'Amore static int jamsize = BMAC_DEFAULT_JAMSIZE;
4060219346bSGarrett D'Amore
4070219346bSGarrett D'Amore
4080219346bSGarrett D'Amore /*
4090219346bSGarrett D'Amore * Calculate the bit in the multicast address filter that selects the given
4100219346bSGarrett D'Amore * address.
4110219346bSGarrett D'Amore */
4120219346bSGarrett D'Amore
4130219346bSGarrett D'Amore static uint32_t
hmeladrf_bit(const uint8_t * addr)4140219346bSGarrett D'Amore hmeladrf_bit(const uint8_t *addr)
4150219346bSGarrett D'Amore {
4160219346bSGarrett D'Amore uint32_t crc;
4170219346bSGarrett D'Amore
4180219346bSGarrett D'Amore CRC32(crc, addr, ETHERADDRL, -1U, crc32_table);
4190219346bSGarrett D'Amore
4200219346bSGarrett D'Amore /*
4210219346bSGarrett D'Amore * Just want the 6 most significant bits.
4220219346bSGarrett D'Amore */
4230219346bSGarrett D'Amore return (crc >> 26);
4240219346bSGarrett D'Amore }
4250219346bSGarrett D'Amore
4260219346bSGarrett D'Amore /* <<<<<<<<<<<<<<<<<<<<<<<< Bit Bang Operations >>>>>>>>>>>>>>>>>>>>>>>> */
4270219346bSGarrett D'Amore
4280219346bSGarrett D'Amore static void
send_bit(struct hme * hmep,uint16_t x)42906673d9bSGarrett D'Amore send_bit(struct hme *hmep, uint16_t x)
4300219346bSGarrett D'Amore {
4310219346bSGarrett D'Amore PUT_MIFREG(mif_bbdata, x);
4320219346bSGarrett D'Amore PUT_MIFREG(mif_bbclk, HME_BBCLK_LOW);
4330219346bSGarrett D'Amore PUT_MIFREG(mif_bbclk, HME_BBCLK_HIGH);
4340219346bSGarrett D'Amore }
4350219346bSGarrett D'Amore
4360219346bSGarrett D'Amore
4370219346bSGarrett D'Amore /*
4380219346bSGarrett D'Amore * To read the MII register bits according to the IEEE Standard
4390219346bSGarrett D'Amore */
44006673d9bSGarrett D'Amore static uint16_t
get_bit_std(uint8_t phyad,struct hme * hmep)44106673d9bSGarrett D'Amore get_bit_std(uint8_t phyad, struct hme *hmep)
4420219346bSGarrett D'Amore {
44306673d9bSGarrett D'Amore uint16_t x;
4440219346bSGarrett D'Amore
4450219346bSGarrett D'Amore PUT_MIFREG(mif_bbclk, HME_BBCLK_LOW);
4460219346bSGarrett D'Amore drv_usecwait(1); /* wait for >330 ns for stable data */
44706673d9bSGarrett D'Amore if (phyad == HME_INTERNAL_PHYAD)
4480219346bSGarrett D'Amore x = (GET_MIFREG(mif_cfg) & HME_MIF_CFGM0) ? 1 : 0;
4490219346bSGarrett D'Amore else
4500219346bSGarrett D'Amore x = (GET_MIFREG(mif_cfg) & HME_MIF_CFGM1) ? 1 : 0;
4510219346bSGarrett D'Amore PUT_MIFREG(mif_bbclk, HME_BBCLK_HIGH);
4520219346bSGarrett D'Amore return (x);
4530219346bSGarrett D'Amore }
4540219346bSGarrett D'Amore
4550219346bSGarrett D'Amore #define SEND_BIT(x) send_bit(hmep, x)
45606673d9bSGarrett D'Amore #define GET_BIT_STD(phyad, x) x = get_bit_std(phyad, hmep)
4570219346bSGarrett D'Amore
4580219346bSGarrett D'Amore
4590219346bSGarrett D'Amore static void
hme_bb_mii_write(struct hme * hmep,uint8_t phyad,uint8_t regad,uint16_t data)46006673d9bSGarrett D'Amore hme_bb_mii_write(struct hme *hmep, uint8_t phyad, uint8_t regad, uint16_t data)
4610219346bSGarrett D'Amore {
4620219346bSGarrett D'Amore int i;
4630219346bSGarrett D'Amore
4640219346bSGarrett D'Amore PUT_MIFREG(mif_bbopenb, 1); /* Enable the MII driver */
4650219346bSGarrett D'Amore (void) hme_bb_force_idle(hmep);
4660219346bSGarrett D'Amore SEND_BIT(0); SEND_BIT(1); /* <ST> */
4670219346bSGarrett D'Amore SEND_BIT(0); SEND_BIT(1); /* <OP> */
4680219346bSGarrett D'Amore
4690219346bSGarrett D'Amore for (i = 4; i >= 0; i--) { /* <AAAAA> */
4700219346bSGarrett D'Amore SEND_BIT((phyad >> i) & 1);
4710219346bSGarrett D'Amore }
4720219346bSGarrett D'Amore
4730219346bSGarrett D'Amore for (i = 4; i >= 0; i--) { /* <RRRRR> */
4740219346bSGarrett D'Amore SEND_BIT((regad >> i) & 1);
4750219346bSGarrett D'Amore }
4760219346bSGarrett D'Amore
4770219346bSGarrett D'Amore SEND_BIT(1); SEND_BIT(0); /* <TA> */
4780219346bSGarrett D'Amore
4790219346bSGarrett D'Amore for (i = 0xf; i >= 0; i--) { /* <DDDDDDDDDDDDDDDD> */
4800219346bSGarrett D'Amore SEND_BIT((data >> i) & 1);
4810219346bSGarrett D'Amore }
4820219346bSGarrett D'Amore
4830219346bSGarrett D'Amore PUT_MIFREG(mif_bbopenb, 0); /* Disable the MII driver */
4840219346bSGarrett D'Amore CHECK_MIFREG();
4850219346bSGarrett D'Amore }
4860219346bSGarrett D'Amore
4870219346bSGarrett D'Amore /* Return 0 if OK, 1 if error (Transceiver does not talk management) */
48806673d9bSGarrett D'Amore static uint16_t
hme_bb_mii_read(struct hme * hmep,uint8_t phyad,uint8_t regad)48906673d9bSGarrett D'Amore hme_bb_mii_read(struct hme *hmep, uint8_t phyad, uint8_t regad)
4900219346bSGarrett D'Amore {
4910219346bSGarrett D'Amore int i;
4920219346bSGarrett D'Amore uint32_t x;
49306673d9bSGarrett D'Amore uint16_t data = 0;
4940219346bSGarrett D'Amore
4950219346bSGarrett D'Amore PUT_MIFREG(mif_bbopenb, 1); /* Enable the MII driver */
4960219346bSGarrett D'Amore (void) hme_bb_force_idle(hmep);
4970219346bSGarrett D'Amore SEND_BIT(0); SEND_BIT(1); /* <ST> */
4980219346bSGarrett D'Amore SEND_BIT(1); SEND_BIT(0); /* <OP> */
4990219346bSGarrett D'Amore for (i = 4; i >= 0; i--) { /* <AAAAA> */
5000219346bSGarrett D'Amore SEND_BIT((phyad >> i) & 1);
5010219346bSGarrett D'Amore }
5020219346bSGarrett D'Amore for (i = 4; i >= 0; i--) { /* <RRRRR> */
5030219346bSGarrett D'Amore SEND_BIT((regad >> i) & 1);
5040219346bSGarrett D'Amore }
5050219346bSGarrett D'Amore
5060219346bSGarrett D'Amore PUT_MIFREG(mif_bbopenb, 0); /* Disable the MII driver */
5070219346bSGarrett D'Amore
50806673d9bSGarrett D'Amore GET_BIT_STD(phyad, x);
50906673d9bSGarrett D'Amore GET_BIT_STD(phyad, x); /* <TA> */
5100219346bSGarrett D'Amore for (i = 0xf; i >= 0; i--) { /* <DDDDDDDDDDDDDDDD> */
51106673d9bSGarrett D'Amore GET_BIT_STD(phyad, x);
51206673d9bSGarrett D'Amore data += (x << i);
5130219346bSGarrett D'Amore }
5140219346bSGarrett D'Amore /*
5150219346bSGarrett D'Amore * Kludge to get the Transceiver out of hung mode
5160219346bSGarrett D'Amore */
51706673d9bSGarrett D'Amore GET_BIT_STD(phyad, x);
51806673d9bSGarrett D'Amore GET_BIT_STD(phyad, x);
51906673d9bSGarrett D'Amore GET_BIT_STD(phyad, x);
5200219346bSGarrett D'Amore CHECK_MIFREG();
52106673d9bSGarrett D'Amore return (data);
5220219346bSGarrett D'Amore }
5230219346bSGarrett D'Amore
5240219346bSGarrett D'Amore
5250219346bSGarrett D'Amore static void
hme_bb_force_idle(struct hme * hmep)5260219346bSGarrett D'Amore hme_bb_force_idle(struct hme *hmep)
5270219346bSGarrett D'Amore {
5280219346bSGarrett D'Amore int i;
5290219346bSGarrett D'Amore
5300219346bSGarrett D'Amore for (i = 0; i < 33; i++) {
5310219346bSGarrett D'Amore SEND_BIT(1);
5320219346bSGarrett D'Amore }
5330219346bSGarrett D'Amore }
5340219346bSGarrett D'Amore
5350219346bSGarrett D'Amore /* <<<<<<<<<<<<<<<<<<<<End of Bit Bang Operations >>>>>>>>>>>>>>>>>>>>>>>> */
5360219346bSGarrett D'Amore
5370219346bSGarrett D'Amore
5380219346bSGarrett D'Amore /* <<<<<<<<<<<<< Frame Register used for MII operations >>>>>>>>>>>>>>>>>>>> */
5390219346bSGarrett D'Amore
5400219346bSGarrett D'Amore /* Return 0 if OK, 1 if error (Transceiver does not talk management) */
54106673d9bSGarrett D'Amore static uint16_t
hme_mii_read(void * arg,uint8_t phyad,uint8_t regad)54206673d9bSGarrett D'Amore hme_mii_read(void *arg, uint8_t phyad, uint8_t regad)
5430219346bSGarrett D'Amore {
54406673d9bSGarrett D'Amore struct hme *hmep = arg;
5450219346bSGarrett D'Amore uint32_t frame;
546e8717ca2SGarrett D'Amore uint32_t tmp_mif;
547e8717ca2SGarrett D'Amore uint32_t tmp_xif;
5480219346bSGarrett D'Amore
549e8717ca2SGarrett D'Amore tmp_mif = GET_MIFREG(mif_cfg);
550e8717ca2SGarrett D'Amore tmp_xif = GET_MACREG(xifc);
551e8717ca2SGarrett D'Amore
552e8717ca2SGarrett D'Amore switch (phyad) {
553e8717ca2SGarrett D'Amore case HME_EXTERNAL_PHYAD:
554e8717ca2SGarrett D'Amore PUT_MIFREG(mif_cfg, tmp_mif | HME_MIF_CFGPS);
555e8717ca2SGarrett D'Amore PUT_MACREG(xifc, tmp_xif | BMAC_XIFC_MIIBUFDIS);
556e8717ca2SGarrett D'Amore break;
557e8717ca2SGarrett D'Amore case HME_INTERNAL_PHYAD:
558e8717ca2SGarrett D'Amore PUT_MIFREG(mif_cfg, tmp_mif & ~(HME_MIF_CFGPS));
559e8717ca2SGarrett D'Amore PUT_MACREG(xifc, tmp_xif & ~(BMAC_XIFC_MIIBUFDIS));
560e8717ca2SGarrett D'Amore break;
561e8717ca2SGarrett D'Amore default:
562e8717ca2SGarrett D'Amore return (0xffff);
563e8717ca2SGarrett D'Amore }
564e8717ca2SGarrett D'Amore
565e8717ca2SGarrett D'Amore if (!hmep->hme_frame_enable) {
566e8717ca2SGarrett D'Amore frame = (hme_bb_mii_read(hmep, phyad, regad));
567e8717ca2SGarrett D'Amore PUT_MACREG(xifc, tmp_xif);
568e8717ca2SGarrett D'Amore PUT_MIFREG(mif_cfg, tmp_mif);
569e8717ca2SGarrett D'Amore return (frame & 0xffff);
570e8717ca2SGarrett D'Amore }
5710219346bSGarrett D'Amore
5720219346bSGarrett D'Amore PUT_MIFREG(mif_frame,
5730219346bSGarrett D'Amore HME_MIF_FRREAD | (phyad << HME_MIF_FRPHYAD_SHIFT) |
5740219346bSGarrett D'Amore (regad << HME_MIF_FRREGAD_SHIFT));
5750219346bSGarrett D'Amore /*
5760219346bSGarrett D'Amore * HMEDELAY((*framerp & HME_MIF_FRTA0), HMEMAXRSTDELAY);
5770219346bSGarrett D'Amore */
5780219346bSGarrett D'Amore HMEDELAY((GET_MIFREG(mif_frame) & HME_MIF_FRTA0), 300);
5790219346bSGarrett D'Amore frame = GET_MIFREG(mif_frame);
5800219346bSGarrett D'Amore CHECK_MIFREG();
581e8717ca2SGarrett D'Amore
582e8717ca2SGarrett D'Amore PUT_MACREG(xifc, tmp_xif);
583e8717ca2SGarrett D'Amore PUT_MIFREG(mif_cfg, tmp_mif);
584e8717ca2SGarrett D'Amore
5850219346bSGarrett D'Amore if ((frame & HME_MIF_FRTA0) == 0) {
5860219346bSGarrett D'Amore
5870219346bSGarrett D'Amore
58806673d9bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, MII_MSG,
5890219346bSGarrett D'Amore "MIF Read failure");
59006673d9bSGarrett D'Amore return (0xffff);
5910219346bSGarrett D'Amore }
59206673d9bSGarrett D'Amore return ((uint16_t)(frame & HME_MIF_FRDATA));
5930219346bSGarrett D'Amore }
5940219346bSGarrett D'Amore
5950219346bSGarrett D'Amore static void
hme_mii_write(void * arg,uint8_t phyad,uint8_t regad,uint16_t data)59606673d9bSGarrett D'Amore hme_mii_write(void *arg, uint8_t phyad, uint8_t regad, uint16_t data)
5970219346bSGarrett D'Amore {
59806673d9bSGarrett D'Amore struct hme *hmep = arg;
5990219346bSGarrett D'Amore uint32_t frame;
600e8717ca2SGarrett D'Amore uint32_t tmp_mif;
601e8717ca2SGarrett D'Amore uint32_t tmp_xif;
602e8717ca2SGarrett D'Amore
603e8717ca2SGarrett D'Amore tmp_mif = GET_MIFREG(mif_cfg);
604e8717ca2SGarrett D'Amore tmp_xif = GET_MACREG(xifc);
605e8717ca2SGarrett D'Amore
606e8717ca2SGarrett D'Amore switch (phyad) {
607e8717ca2SGarrett D'Amore case HME_EXTERNAL_PHYAD:
608e8717ca2SGarrett D'Amore PUT_MIFREG(mif_cfg, tmp_mif | HME_MIF_CFGPS);
609e8717ca2SGarrett D'Amore PUT_MACREG(xifc, tmp_xif | BMAC_XIFC_MIIBUFDIS);
610e8717ca2SGarrett D'Amore break;
611e8717ca2SGarrett D'Amore case HME_INTERNAL_PHYAD:
612e8717ca2SGarrett D'Amore PUT_MIFREG(mif_cfg, tmp_mif & ~(HME_MIF_CFGPS));
613e8717ca2SGarrett D'Amore PUT_MACREG(xifc, tmp_xif & ~(BMAC_XIFC_MIIBUFDIS));
614e8717ca2SGarrett D'Amore break;
615e8717ca2SGarrett D'Amore default:
616e8717ca2SGarrett D'Amore return;
617e8717ca2SGarrett D'Amore }
6180219346bSGarrett D'Amore
6190219346bSGarrett D'Amore if (!hmep->hme_frame_enable) {
62006673d9bSGarrett D'Amore hme_bb_mii_write(hmep, phyad, regad, data);
621e8717ca2SGarrett D'Amore PUT_MACREG(xifc, tmp_xif);
622e8717ca2SGarrett D'Amore PUT_MIFREG(mif_cfg, tmp_mif);
6230219346bSGarrett D'Amore return;
6240219346bSGarrett D'Amore }
6250219346bSGarrett D'Amore
6260219346bSGarrett D'Amore PUT_MIFREG(mif_frame,
6270219346bSGarrett D'Amore HME_MIF_FRWRITE | (phyad << HME_MIF_FRPHYAD_SHIFT) |
6280219346bSGarrett D'Amore (regad << HME_MIF_FRREGAD_SHIFT) | data);
6290219346bSGarrett D'Amore /*
6300219346bSGarrett D'Amore * HMEDELAY((*framerp & HME_MIF_FRTA0), HMEMAXRSTDELAY);
6310219346bSGarrett D'Amore */
6320219346bSGarrett D'Amore HMEDELAY((GET_MIFREG(mif_frame) & HME_MIF_FRTA0), 300);
6330219346bSGarrett D'Amore frame = GET_MIFREG(mif_frame);
634e8717ca2SGarrett D'Amore PUT_MACREG(xifc, tmp_xif);
635e8717ca2SGarrett D'Amore PUT_MIFREG(mif_cfg, tmp_mif);
6360219346bSGarrett D'Amore CHECK_MIFREG();
6370219346bSGarrett D'Amore if ((frame & HME_MIF_FRTA0) == 0) {
63806673d9bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_MID, MII_MSG,
6390219346bSGarrett D'Amore "MIF Write failure");
6400219346bSGarrett D'Amore }
6410219346bSGarrett D'Amore }
6420219346bSGarrett D'Amore
6430219346bSGarrett D'Amore static void
hme_mii_notify(void * arg,link_state_t link)64406673d9bSGarrett D'Amore hme_mii_notify(void *arg, link_state_t link)
6450219346bSGarrett D'Amore {
6460219346bSGarrett D'Amore struct hme *hmep = arg;
6470219346bSGarrett D'Amore
64806673d9bSGarrett D'Amore if (link == LINK_STATE_UP) {
6490219346bSGarrett D'Amore (void) hmeinit(hmep);
6500219346bSGarrett D'Amore }
65106673d9bSGarrett D'Amore mac_link_update(hmep->hme_mh, link);
6520219346bSGarrett D'Amore }
6530219346bSGarrett D'Amore
6540219346bSGarrett D'Amore /* <<<<<<<<<<<<<<<<<<<<<<<<<<< LOADABLE ENTRIES >>>>>>>>>>>>>>>>>>>>>>> */
6550219346bSGarrett D'Amore
6560219346bSGarrett D'Amore int
_init(void)6570219346bSGarrett D'Amore _init(void)
6580219346bSGarrett D'Amore {
6590219346bSGarrett D'Amore int status;
6600219346bSGarrett D'Amore
6610219346bSGarrett D'Amore mac_init_ops(&hme_dev_ops, "hme");
6620219346bSGarrett D'Amore if ((status = mod_install(&modlinkage)) != 0) {
6630219346bSGarrett D'Amore mac_fini_ops(&hme_dev_ops);
6640219346bSGarrett D'Amore }
6650219346bSGarrett D'Amore return (status);
6660219346bSGarrett D'Amore }
6670219346bSGarrett D'Amore
6680219346bSGarrett D'Amore int
_fini(void)6690219346bSGarrett D'Amore _fini(void)
6700219346bSGarrett D'Amore {
6710219346bSGarrett D'Amore int status;
6720219346bSGarrett D'Amore
6730219346bSGarrett D'Amore if ((status = mod_remove(&modlinkage)) == 0) {
6740219346bSGarrett D'Amore mac_fini_ops(&hme_dev_ops);
6750219346bSGarrett D'Amore }
6760219346bSGarrett D'Amore return (status);
6770219346bSGarrett D'Amore }
6780219346bSGarrett D'Amore
6790219346bSGarrett D'Amore int
_info(struct modinfo * modinfop)6800219346bSGarrett D'Amore _info(struct modinfo *modinfop)
6810219346bSGarrett D'Amore {
6820219346bSGarrett D'Amore return (mod_info(&modlinkage, modinfop));
6830219346bSGarrett D'Amore }
6840219346bSGarrett D'Amore
6850219346bSGarrett D'Amore /*
6860219346bSGarrett D'Amore * ddi_dma_sync() a TMD or RMD descriptor.
6870219346bSGarrett D'Amore */
6880219346bSGarrett D'Amore #define HMESYNCRMD(num, who) \
6890219346bSGarrett D'Amore (void) ddi_dma_sync(hmep->hme_rmd_dmah, \
6900219346bSGarrett D'Amore (num * sizeof (struct hme_rmd)), \
6910219346bSGarrett D'Amore sizeof (struct hme_rmd), \
6920219346bSGarrett D'Amore who)
6930219346bSGarrett D'Amore
6940219346bSGarrett D'Amore #define HMESYNCTMD(num, who) \
6950219346bSGarrett D'Amore (void) ddi_dma_sync(hmep->hme_tmd_dmah, \
6960219346bSGarrett D'Amore (num * sizeof (struct hme_tmd)), \
6970219346bSGarrett D'Amore sizeof (struct hme_tmd), \
6980219346bSGarrett D'Amore who)
6990219346bSGarrett D'Amore
7000219346bSGarrett D'Amore /*
7010219346bSGarrett D'Amore * Ethernet broadcast address definition.
7020219346bSGarrett D'Amore */
7030219346bSGarrett D'Amore static struct ether_addr etherbroadcastaddr = {
7040219346bSGarrett D'Amore 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
7050219346bSGarrett D'Amore };
7060219346bSGarrett D'Amore
7070219346bSGarrett D'Amore /*
7080219346bSGarrett D'Amore * MIB II broadcast/multicast packets
7090219346bSGarrett D'Amore */
7100219346bSGarrett D'Amore #define IS_BROADCAST(pkt) (bcmp(pkt, ðerbroadcastaddr, ETHERADDRL) == 0)
7110219346bSGarrett D'Amore #define IS_MULTICAST(pkt) ((pkt[0] & 01) == 1)
7120219346bSGarrett D'Amore #define BUMP_InNUcast(hmep, pkt) \
7130219346bSGarrett D'Amore if (IS_MULTICAST(pkt)) { \
7140219346bSGarrett D'Amore if (IS_BROADCAST(pkt)) { \
7150219346bSGarrett D'Amore hmep->hme_brdcstrcv++; \
7160219346bSGarrett D'Amore } else { \
7170219346bSGarrett D'Amore hmep->hme_multircv++; \
7180219346bSGarrett D'Amore } \
7190219346bSGarrett D'Amore }
7200219346bSGarrett D'Amore #define BUMP_OutNUcast(hmep, pkt) \
7210219346bSGarrett D'Amore if (IS_MULTICAST(pkt)) { \
7220219346bSGarrett D'Amore if (IS_BROADCAST(pkt)) { \
7230219346bSGarrett D'Amore hmep->hme_brdcstxmt++; \
7240219346bSGarrett D'Amore } else { \
7250219346bSGarrett D'Amore hmep->hme_multixmt++; \
7260219346bSGarrett D'Amore } \
7270219346bSGarrett D'Amore }
7280219346bSGarrett D'Amore
7290219346bSGarrett D'Amore static int
hme_create_prop_from_kw(dev_info_t * dip,char * vpdname,char * vpdstr)7300219346bSGarrett D'Amore hme_create_prop_from_kw(dev_info_t *dip, char *vpdname, char *vpdstr)
7310219346bSGarrett D'Amore {
7320219346bSGarrett D'Amore char propstr[80];
7330219346bSGarrett D'Amore int i, needprop = 0;
7340219346bSGarrett D'Amore struct ether_addr local_mac;
7350219346bSGarrett D'Amore
7360219346bSGarrett D'Amore if (strcmp(vpdname, "NA") == 0) {
7370219346bSGarrett D'Amore (void) strcpy(propstr, "local-mac-address");
7380219346bSGarrett D'Amore needprop = 1;
7390219346bSGarrett D'Amore } else if (strcmp(vpdname, "Z0") == 0) {
7400219346bSGarrett D'Amore (void) strcpy(propstr, "model");
7410219346bSGarrett D'Amore needprop = 1;
7420219346bSGarrett D'Amore } else if (strcmp(vpdname, "Z1") == 0) {
7430219346bSGarrett D'Amore (void) strcpy(propstr, "board-model");
7440219346bSGarrett D'Amore needprop = 1;
7450219346bSGarrett D'Amore }
7460219346bSGarrett D'Amore
7470219346bSGarrett D'Amore if (needprop == 1) {
7480219346bSGarrett D'Amore
7490219346bSGarrett D'Amore if (strcmp(propstr, "local-mac-address") == 0) {
7500219346bSGarrett D'Amore for (i = 0; i < ETHERADDRL; i++)
7510219346bSGarrett D'Amore local_mac.ether_addr_octet[i] =
7520219346bSGarrett D'Amore (uchar_t)vpdstr[i];
7530219346bSGarrett D'Amore if (ddi_prop_create(DDI_DEV_T_NONE, dip,
7540219346bSGarrett D'Amore DDI_PROP_CANSLEEP, propstr,
7550219346bSGarrett D'Amore (char *)local_mac.ether_addr_octet, ETHERADDRL)
7560219346bSGarrett D'Amore != DDI_SUCCESS) {
7570219346bSGarrett D'Amore return (DDI_FAILURE);
7580219346bSGarrett D'Amore }
7590219346bSGarrett D'Amore } else {
7600219346bSGarrett D'Amore if (ddi_prop_create(DDI_DEV_T_NONE, dip,
7610219346bSGarrett D'Amore DDI_PROP_CANSLEEP, propstr, vpdstr,
7620219346bSGarrett D'Amore strlen(vpdstr)+1) != DDI_SUCCESS) {
7630219346bSGarrett D'Amore return (DDI_FAILURE);
7640219346bSGarrett D'Amore }
7650219346bSGarrett D'Amore }
7660219346bSGarrett D'Amore }
7670219346bSGarrett D'Amore return (0);
7680219346bSGarrett D'Amore }
7690219346bSGarrett D'Amore
7700219346bSGarrett D'Amore /*
7710219346bSGarrett D'Amore * Get properties from old VPD
7720219346bSGarrett D'Amore * for PCI cards
7730219346bSGarrett D'Amore */
7740219346bSGarrett D'Amore static int
hme_get_oldvpd_props(dev_info_t * dip,int vpd_base)7750219346bSGarrett D'Amore hme_get_oldvpd_props(dev_info_t *dip, int vpd_base)
7760219346bSGarrett D'Amore {
7770219346bSGarrett D'Amore struct hme *hmep;
7780219346bSGarrett D'Amore int vpd_start, vpd_len, kw_start, kw_len, kw_ptr;
7790219346bSGarrett D'Amore char kw_namestr[3];
7800219346bSGarrett D'Amore char kw_fieldstr[256];
7810219346bSGarrett D'Amore int i;
7820219346bSGarrett D'Amore
7830219346bSGarrett D'Amore hmep = ddi_get_driver_private(dip);
7840219346bSGarrett D'Amore
7850219346bSGarrett D'Amore vpd_start = vpd_base;
7860219346bSGarrett D'Amore
7870219346bSGarrett D'Amore if ((GET_ROM8(&hmep->hme_romp[vpd_start]) & 0xff) != 0x90) {
7880219346bSGarrett D'Amore return (1); /* error */
7890219346bSGarrett D'Amore } else {
7900219346bSGarrett D'Amore vpd_len = 9;
7910219346bSGarrett D'Amore }
7920219346bSGarrett D'Amore
7930219346bSGarrett D'Amore /* Get local-mac-address */
7940219346bSGarrett D'Amore kw_start = vpd_start + 3; /* Location of 1st keyword */
7950219346bSGarrett D'Amore kw_ptr = kw_start;
7960219346bSGarrett D'Amore while ((kw_ptr - kw_start) < vpd_len) { /* Get all keywords */
7970219346bSGarrett D'Amore kw_namestr[0] = GET_ROM8(&hmep->hme_romp[kw_ptr]);
7980219346bSGarrett D'Amore kw_namestr[1] = GET_ROM8(&hmep->hme_romp[kw_ptr+1]);
7990219346bSGarrett D'Amore kw_namestr[2] = '\0';
8000219346bSGarrett D'Amore kw_len = (int)(GET_ROM8(&hmep->hme_romp[kw_ptr+2]) & 0xff);
8010219346bSGarrett D'Amore for (i = 0, kw_ptr += 3; i < kw_len; i++)
8020219346bSGarrett D'Amore kw_fieldstr[i] = GET_ROM8(&hmep->hme_romp[kw_ptr+i]);
8030219346bSGarrett D'Amore kw_fieldstr[i] = '\0';
8040219346bSGarrett D'Amore if (hme_create_prop_from_kw(dip, kw_namestr, kw_fieldstr)) {
8050219346bSGarrett D'Amore return (DDI_FAILURE);
8060219346bSGarrett D'Amore }
8070219346bSGarrett D'Amore kw_ptr += kw_len;
8080219346bSGarrett D'Amore } /* next keyword */
8090219346bSGarrett D'Amore
8100219346bSGarrett D'Amore if (ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, "model",
8110219346bSGarrett D'Amore "SUNW,cheerio", strlen("SUNW,cheerio")+1) != DDI_SUCCESS) {
8120219346bSGarrett D'Amore return (DDI_FAILURE);
8130219346bSGarrett D'Amore }
8140219346bSGarrett D'Amore return (0);
8150219346bSGarrett D'Amore }
8160219346bSGarrett D'Amore
8170219346bSGarrett D'Amore
8180219346bSGarrett D'Amore /*
8190219346bSGarrett D'Amore * Get properties from new VPD
8200219346bSGarrett D'Amore * for CompactPCI cards
8210219346bSGarrett D'Amore */
8220219346bSGarrett D'Amore static int
hme_get_newvpd_props(dev_info_t * dip,int vpd_base)8230219346bSGarrett D'Amore hme_get_newvpd_props(dev_info_t *dip, int vpd_base)
8240219346bSGarrett D'Amore {
8250219346bSGarrett D'Amore struct hme *hmep;
8260219346bSGarrett D'Amore int vpd_start, vpd_len, kw_start, kw_len, kw_ptr;
8270219346bSGarrett D'Amore char kw_namestr[3];
8280219346bSGarrett D'Amore char kw_fieldstr[256];
8290219346bSGarrett D'Amore int maxvpdsize, i;
8300219346bSGarrett D'Amore
8310219346bSGarrett D'Amore hmep = ddi_get_driver_private(dip);
8320219346bSGarrett D'Amore
8330219346bSGarrett D'Amore maxvpdsize = 1024; /* Real size not known until after it is read */
8340219346bSGarrett D'Amore
8350219346bSGarrett D'Amore vpd_start = (int)((GET_ROM8(&(hmep->hme_romp[vpd_base+1])) & 0xff) |
8360219346bSGarrett D'Amore ((GET_ROM8(&hmep->hme_romp[vpd_base+2]) & 0xff) << 8)) +3;
8370219346bSGarrett D'Amore vpd_start = vpd_base + vpd_start;
8380219346bSGarrett D'Amore while (vpd_start < (vpd_base + maxvpdsize)) { /* Get all VPDs */
8390219346bSGarrett D'Amore if ((GET_ROM8(&hmep->hme_romp[vpd_start]) & 0xff) != 0x90) {
8400219346bSGarrett D'Amore break; /* no VPD found */
8410219346bSGarrett D'Amore } else {
8420219346bSGarrett D'Amore vpd_len = (int)((GET_ROM8(&hmep->hme_romp[vpd_start
8430219346bSGarrett D'Amore + 1]) & 0xff) | (GET_ROM8(&hmep->hme_romp[vpd_start
8440219346bSGarrett D'Amore + 2]) & 0xff) << 8);
8450219346bSGarrett D'Amore }
8460219346bSGarrett D'Amore /* Get all keywords in this VPD */
8470219346bSGarrett D'Amore kw_start = vpd_start + 3; /* Location of 1st keyword */
8480219346bSGarrett D'Amore kw_ptr = kw_start;
8490219346bSGarrett D'Amore while ((kw_ptr - kw_start) < vpd_len) { /* Get all keywords */
8500219346bSGarrett D'Amore kw_namestr[0] = GET_ROM8(&hmep->hme_romp[kw_ptr]);
8510219346bSGarrett D'Amore kw_namestr[1] = GET_ROM8(&hmep->hme_romp[kw_ptr+1]);
8520219346bSGarrett D'Amore kw_namestr[2] = '\0';
8530219346bSGarrett D'Amore kw_len =
8540219346bSGarrett D'Amore (int)(GET_ROM8(&hmep->hme_romp[kw_ptr+2]) & 0xff);
8550219346bSGarrett D'Amore for (i = 0, kw_ptr += 3; i < kw_len; i++)
8560219346bSGarrett D'Amore kw_fieldstr[i] =
8570219346bSGarrett D'Amore GET_ROM8(&hmep->hme_romp[kw_ptr+i]);
8580219346bSGarrett D'Amore kw_fieldstr[i] = '\0';
8590219346bSGarrett D'Amore if (hme_create_prop_from_kw(dip, kw_namestr,
8600219346bSGarrett D'Amore kw_fieldstr)) {
8610219346bSGarrett D'Amore return (DDI_FAILURE);
8620219346bSGarrett D'Amore }
8630219346bSGarrett D'Amore kw_ptr += kw_len;
8640219346bSGarrett D'Amore } /* next keyword */
8650219346bSGarrett D'Amore vpd_start += (vpd_len + 3);
8660219346bSGarrett D'Amore } /* next VPD */
8670219346bSGarrett D'Amore return (0);
8680219346bSGarrett D'Amore }
8690219346bSGarrett D'Amore
8700219346bSGarrett D'Amore
8710219346bSGarrett D'Amore /*
8720219346bSGarrett D'Amore * Get properties from VPD
8730219346bSGarrett D'Amore */
8740219346bSGarrett D'Amore static int
hme_get_vpd_props(dev_info_t * dip)8750219346bSGarrett D'Amore hme_get_vpd_props(dev_info_t *dip)
8760219346bSGarrett D'Amore {
8770219346bSGarrett D'Amore struct hme *hmep;
8780219346bSGarrett D'Amore int v0, v1, vpd_base;
8790219346bSGarrett D'Amore int i, epromsrchlimit;
8800219346bSGarrett D'Amore
8810219346bSGarrett D'Amore
8820219346bSGarrett D'Amore hmep = ddi_get_driver_private(dip);
8830219346bSGarrett D'Amore
8840219346bSGarrett D'Amore v0 = (int)(GET_ROM8(&(hmep->hme_romp[0])));
8850219346bSGarrett D'Amore v1 = (int)(GET_ROM8(&(hmep->hme_romp[1])));
8860219346bSGarrett D'Amore v0 = ((v0 & 0xff) << 8 | v1);
8870219346bSGarrett D'Amore
8880219346bSGarrett D'Amore if ((v0 & 0xffff) != 0x55aa) {
8890219346bSGarrett D'Amore cmn_err(CE_NOTE, " Valid pci prom not found \n");
8900219346bSGarrett D'Amore return (1);
8910219346bSGarrett D'Amore }
8920219346bSGarrett D'Amore
8930219346bSGarrett D'Amore epromsrchlimit = 4096;
8940219346bSGarrett D'Amore for (i = 2; i < epromsrchlimit; i++) {
8950219346bSGarrett D'Amore /* "PCIR" */
8960219346bSGarrett D'Amore if (((GET_ROM8(&(hmep->hme_romp[i])) & 0xff) == 'P') &&
8970219346bSGarrett D'Amore ((GET_ROM8(&(hmep->hme_romp[i+1])) & 0xff) == 'C') &&
8980219346bSGarrett D'Amore ((GET_ROM8(&(hmep->hme_romp[i+2])) & 0xff) == 'I') &&
8990219346bSGarrett D'Amore ((GET_ROM8(&(hmep->hme_romp[i+3])) & 0xff) == 'R')) {
9000219346bSGarrett D'Amore vpd_base =
9010219346bSGarrett D'Amore (int)((GET_ROM8(&(hmep->hme_romp[i+8])) & 0xff) |
9020219346bSGarrett D'Amore (GET_ROM8(&(hmep->hme_romp[i+9])) & 0xff) << 8);
9030219346bSGarrett D'Amore break; /* VPD pointer found */
9040219346bSGarrett D'Amore }
9050219346bSGarrett D'Amore }
9060219346bSGarrett D'Amore
9070219346bSGarrett D'Amore /* No VPD found */
9080219346bSGarrett D'Amore if (vpd_base == 0) {
9090219346bSGarrett D'Amore cmn_err(CE_NOTE, " Vital Product Data pointer not found \n");
9100219346bSGarrett D'Amore return (1);
9110219346bSGarrett D'Amore }
9120219346bSGarrett D'Amore
9130219346bSGarrett D'Amore v0 = (int)(GET_ROM8(&(hmep->hme_romp[vpd_base])));
9140219346bSGarrett D'Amore if (v0 == 0x82) {
9150219346bSGarrett D'Amore if (hme_get_newvpd_props(dip, vpd_base))
9160219346bSGarrett D'Amore return (1);
9170219346bSGarrett D'Amore return (0);
9180219346bSGarrett D'Amore } else if (v0 == 0x90) {
9190219346bSGarrett D'Amore /* If we are are SUNW,qfe card, look for the Nth "NA" descr */
9200219346bSGarrett D'Amore if ((GET_ROM8(&hmep->hme_romp[vpd_base + 12]) != 0x79) &&
9210219346bSGarrett D'Amore GET_ROM8(&hmep->hme_romp[vpd_base + 4 * 12]) == 0x79) {
9220219346bSGarrett D'Amore vpd_base += hmep->hme_devno * 12;
9230219346bSGarrett D'Amore }
9240219346bSGarrett D'Amore if (hme_get_oldvpd_props(dip, vpd_base))
9250219346bSGarrett D'Amore return (1);
9260219346bSGarrett D'Amore return (0);
9270219346bSGarrett D'Amore } else
9280219346bSGarrett D'Amore return (1); /* unknown start byte in VPD */
9290219346bSGarrett D'Amore }
9300219346bSGarrett D'Amore
9310219346bSGarrett D'Amore /*
9320219346bSGarrett D'Amore * For x86, the BIOS doesn't map the PCI Rom register for the qfe
9330219346bSGarrett D'Amore * cards, so we have to extract it from the ebus bridge that is
9340219346bSGarrett D'Amore * function zero of the same device. This is a bit of an ugly hack.
9350219346bSGarrett D'Amore * (The ebus bridge leaves the entire ROM mapped at base address
9360219346bSGarrett D'Amore * register 0x10.)
9370219346bSGarrett D'Amore */
9380219346bSGarrett D'Amore
9390219346bSGarrett D'Amore typedef struct {
9400219346bSGarrett D'Amore struct hme *hmep;
9410219346bSGarrett D'Amore dev_info_t *parent;
9420219346bSGarrett D'Amore uint8_t bus, dev;
9430219346bSGarrett D'Amore ddi_acc_handle_t acch;
9440219346bSGarrett D'Amore caddr_t romp;
9450219346bSGarrett D'Amore } ebus_rom_t;
9460219346bSGarrett D'Amore
9470219346bSGarrett D'Amore static int
hme_mapebusrom(dev_info_t * dip,void * arg)9480219346bSGarrett D'Amore hme_mapebusrom(dev_info_t *dip, void *arg)
9490219346bSGarrett D'Amore {
9500219346bSGarrett D'Amore int *regs;
9510219346bSGarrett D'Amore unsigned nregs;
9520219346bSGarrett D'Amore int reg;
9530219346bSGarrett D'Amore ebus_rom_t *rom = arg;
9540219346bSGarrett D'Amore struct hme *hmep = rom->hmep;
9550219346bSGarrett D'Amore
9560219346bSGarrett D'Amore /*
9570219346bSGarrett D'Amore * We only want to look at our peers. Skip our parent.
9580219346bSGarrett D'Amore */
9590219346bSGarrett D'Amore if (dip == rom->parent) {
9600219346bSGarrett D'Amore return (DDI_WALK_PRUNESIB);
9610219346bSGarrett D'Amore }
9620219346bSGarrett D'Amore
96306673d9bSGarrett D'Amore if (ddi_get_parent(dip) != rom->parent)
96406673d9bSGarrett D'Amore return (DDI_WALK_CONTINUE);
96506673d9bSGarrett D'Amore
9660219346bSGarrett D'Amore if ((ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 0,
9670219346bSGarrett D'Amore "reg", ®s, &nregs)) != DDI_PROP_SUCCESS) {
9680219346bSGarrett D'Amore return (DDI_WALK_PRUNECHILD);
9690219346bSGarrett D'Amore }
9700219346bSGarrett D'Amore
9710219346bSGarrett D'Amore if (nregs < 1) {
9720219346bSGarrett D'Amore ddi_prop_free(regs);
9730219346bSGarrett D'Amore return (DDI_WALK_PRUNECHILD);
9740219346bSGarrett D'Amore }
9750219346bSGarrett D'Amore reg = regs[0];
9760219346bSGarrett D'Amore ddi_prop_free(regs);
9770219346bSGarrett D'Amore
9780219346bSGarrett D'Amore /*
9790219346bSGarrett D'Amore * Look for function 0 on our bus and device. If the device doesn't
9800219346bSGarrett D'Amore * match, it might be an alternate peer, in which case we don't want
9810219346bSGarrett D'Amore * to examine any of its children.
9820219346bSGarrett D'Amore */
9830219346bSGarrett D'Amore if ((PCI_REG_BUS_G(reg) != rom->bus) ||
9840219346bSGarrett D'Amore (PCI_REG_DEV_G(reg) != rom->dev) ||
9850219346bSGarrett D'Amore (PCI_REG_FUNC_G(reg) != 0)) {
9860219346bSGarrett D'Amore return (DDI_WALK_PRUNECHILD);
9870219346bSGarrett D'Amore }
9880219346bSGarrett D'Amore
9890219346bSGarrett D'Amore (void) ddi_regs_map_setup(dip, 1, &rom->romp, 0, 0, &hmep->hme_dev_attr,
9900219346bSGarrett D'Amore &rom->acch);
9910219346bSGarrett D'Amore /*
9920219346bSGarrett D'Amore * If we can't map the registers, the caller will notice that
9930219346bSGarrett D'Amore * the acch is NULL.
9940219346bSGarrett D'Amore */
9950219346bSGarrett D'Amore return (DDI_WALK_TERMINATE);
9960219346bSGarrett D'Amore }
9970219346bSGarrett D'Amore
9980219346bSGarrett D'Amore static int
hmeget_promebus(dev_info_t * dip)9990219346bSGarrett D'Amore hmeget_promebus(dev_info_t *dip)
10000219346bSGarrett D'Amore {
10010219346bSGarrett D'Amore ebus_rom_t rom;
10020219346bSGarrett D'Amore int *regs;
10030219346bSGarrett D'Amore unsigned nregs;
10040219346bSGarrett D'Amore struct hme *hmep;
10050219346bSGarrett D'Amore
10060219346bSGarrett D'Amore hmep = ddi_get_driver_private(dip);
10070219346bSGarrett D'Amore
10080219346bSGarrett D'Amore bzero(&rom, sizeof (rom));
10090219346bSGarrett D'Amore
10100219346bSGarrett D'Amore /*
10110219346bSGarrett D'Amore * For x86, the BIOS doesn't map the PCI Rom register for the qfe
10120219346bSGarrett D'Amore * cards, so we have to extract it from the eBus bridge that is
10130219346bSGarrett D'Amore * function zero. This is a bit of an ugly hack.
10140219346bSGarrett D'Amore */
10150219346bSGarrett D'Amore if ((ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 0,
10160219346bSGarrett D'Amore "reg", ®s, &nregs)) != DDI_PROP_SUCCESS) {
10170219346bSGarrett D'Amore return (DDI_FAILURE);
10180219346bSGarrett D'Amore }
10190219346bSGarrett D'Amore
10200219346bSGarrett D'Amore if (nregs < 5) {
10210219346bSGarrett D'Amore ddi_prop_free(regs);
10220219346bSGarrett D'Amore return (DDI_FAILURE);
10230219346bSGarrett D'Amore }
10240219346bSGarrett D'Amore rom.hmep = hmep;
10250219346bSGarrett D'Amore rom.bus = PCI_REG_BUS_G(regs[0]);
10260219346bSGarrett D'Amore rom.dev = PCI_REG_DEV_G(regs[0]);
10270219346bSGarrett D'Amore hmep->hme_devno = rom.dev;
10280219346bSGarrett D'Amore rom.parent = ddi_get_parent(dip);
10290219346bSGarrett D'Amore
10300219346bSGarrett D'Amore /*
10310219346bSGarrett D'Amore * The implementation of ddi_walk_devs says that we must not
103206673d9bSGarrett D'Amore * be called during autoconfiguration. However, it turns out
103306673d9bSGarrett D'Amore * that it is safe to call this during our attach routine,
103406673d9bSGarrett D'Amore * because we are not a nexus device.
10350219346bSGarrett D'Amore *
103606673d9bSGarrett D'Amore * Previously we rooted our search at our immediate parent,
103706673d9bSGarrett D'Amore * but this triggered an assertion panic in debug kernels.
10380219346bSGarrett D'Amore */
103906673d9bSGarrett D'Amore ddi_walk_devs(ddi_root_node(), hme_mapebusrom, &rom);
10400219346bSGarrett D'Amore
10410219346bSGarrett D'Amore if (rom.acch) {
10420219346bSGarrett D'Amore hmep->hme_romh = rom.acch;
10430219346bSGarrett D'Amore hmep->hme_romp = (unsigned char *)rom.romp;
10440219346bSGarrett D'Amore return (DDI_SUCCESS);
10450219346bSGarrett D'Amore }
10460219346bSGarrett D'Amore return (DDI_FAILURE);
10470219346bSGarrett D'Amore }
10480219346bSGarrett D'Amore
10490219346bSGarrett D'Amore static int
hmeget_promprops(dev_info_t * dip)10500219346bSGarrett D'Amore hmeget_promprops(dev_info_t *dip)
10510219346bSGarrett D'Amore {
10520219346bSGarrett D'Amore struct hme *hmep;
10530219346bSGarrett D'Amore int rom_bar;
10540219346bSGarrett D'Amore ddi_acc_handle_t cfg_handle;
10550219346bSGarrett D'Amore struct {
10560219346bSGarrett D'Amore uint16_t vendorid;
10570219346bSGarrett D'Amore uint16_t devid;
10580219346bSGarrett D'Amore uint16_t command;
10590219346bSGarrett D'Amore uint16_t status;
10600219346bSGarrett D'Amore uint32_t junk1;
10610219346bSGarrett D'Amore uint8_t cache_line;
10620219346bSGarrett D'Amore uint8_t latency;
10630219346bSGarrett D'Amore uint8_t header;
10640219346bSGarrett D'Amore uint8_t bist;
10650219346bSGarrett D'Amore uint32_t base;
10660219346bSGarrett D'Amore uint32_t base14;
10670219346bSGarrett D'Amore uint32_t base18;
10680219346bSGarrett D'Amore uint32_t base1c;
10690219346bSGarrett D'Amore uint32_t base20;
10700219346bSGarrett D'Amore uint32_t base24;
10710219346bSGarrett D'Amore uint32_t base28;
10720219346bSGarrett D'Amore uint32_t base2c;
10730219346bSGarrett D'Amore uint32_t base30;
10740219346bSGarrett D'Amore } *cfg_ptr;
10750219346bSGarrett D'Amore
10760219346bSGarrett D'Amore hmep = ddi_get_driver_private(dip);
10770219346bSGarrett D'Amore
10780219346bSGarrett D'Amore
10790219346bSGarrett D'Amore /*
10800219346bSGarrett D'Amore * map configuration space
10810219346bSGarrett D'Amore */
10820219346bSGarrett D'Amore if (ddi_regs_map_setup(hmep->dip, 0, (caddr_t *)&cfg_ptr,
10830219346bSGarrett D'Amore 0, 0, &hmep->hme_dev_attr, &cfg_handle)) {
10840219346bSGarrett D'Amore return (DDI_FAILURE);
10850219346bSGarrett D'Amore }
10860219346bSGarrett D'Amore
10870219346bSGarrett D'Amore /*
10880219346bSGarrett D'Amore * Enable bus-master and memory accesses
10890219346bSGarrett D'Amore */
10900219346bSGarrett D'Amore ddi_put16(cfg_handle, &cfg_ptr->command,
10910219346bSGarrett D'Amore PCI_COMM_SERR_ENABLE | PCI_COMM_PARITY_DETECT |
10920219346bSGarrett D'Amore PCI_COMM_MAE | PCI_COMM_ME);
10930219346bSGarrett D'Amore
10940219346bSGarrett D'Amore /*
10950219346bSGarrett D'Amore * Enable rom accesses
10960219346bSGarrett D'Amore */
10970219346bSGarrett D'Amore rom_bar = ddi_get32(cfg_handle, &cfg_ptr->base30);
10980219346bSGarrett D'Amore ddi_put32(cfg_handle, &cfg_ptr->base30, rom_bar | 1);
10990219346bSGarrett D'Amore
11000219346bSGarrett D'Amore
11010219346bSGarrett D'Amore if ((ddi_regs_map_setup(dip, 2, (caddr_t *)&(hmep->hme_romp), 0, 0,
11020219346bSGarrett D'Amore &hmep->hme_dev_attr, &hmep->hme_romh) != DDI_SUCCESS) &&
11030219346bSGarrett D'Amore (hmeget_promebus(dip) != DDI_SUCCESS)) {
11040219346bSGarrett D'Amore
11050219346bSGarrett D'Amore if (cfg_ptr)
11060219346bSGarrett D'Amore ddi_regs_map_free(&cfg_handle);
11070219346bSGarrett D'Amore return (DDI_FAILURE);
11080219346bSGarrett D'Amore } else {
11090219346bSGarrett D'Amore if (hme_get_vpd_props(dip))
11100219346bSGarrett D'Amore return (DDI_FAILURE);
11110219346bSGarrett D'Amore }
11120219346bSGarrett D'Amore if (hmep->hme_romp)
11130219346bSGarrett D'Amore ddi_regs_map_free(&hmep->hme_romh);
11140219346bSGarrett D'Amore if (cfg_ptr)
11150219346bSGarrett D'Amore ddi_regs_map_free(&cfg_handle);
11160219346bSGarrett D'Amore return (DDI_SUCCESS);
11170219346bSGarrett D'Amore
11180219346bSGarrett D'Amore }
11190219346bSGarrett D'Amore
11200219346bSGarrett D'Amore static void
hmeget_hm_rev_property(struct hme * hmep)11210219346bSGarrett D'Amore hmeget_hm_rev_property(struct hme *hmep)
11220219346bSGarrett D'Amore {
11230219346bSGarrett D'Amore int hm_rev;
11240219346bSGarrett D'Amore
11250219346bSGarrett D'Amore
11260219346bSGarrett D'Amore hm_rev = hmep->asic_rev;
11270219346bSGarrett D'Amore switch (hm_rev) {
11280219346bSGarrett D'Amore case HME_2P1_REVID:
11290219346bSGarrett D'Amore case HME_2P1_REVID_OBP:
11300219346bSGarrett D'Amore HME_FAULT_MSG2(hmep, SEVERITY_NONE, DISPLAY_MSG,
11310219346bSGarrett D'Amore "SBus 2.1 Found (Rev Id = %x)", hm_rev);
11320219346bSGarrett D'Amore hmep->hme_frame_enable = 1;
11330219346bSGarrett D'Amore break;
11340219346bSGarrett D'Amore
11350219346bSGarrett D'Amore case HME_2P0_REVID:
11360219346bSGarrett D'Amore HME_FAULT_MSG2(hmep, SEVERITY_NONE, DISPLAY_MSG,
11370219346bSGarrett D'Amore "SBus 2.0 Found (Rev Id = %x)", hm_rev);
11380219346bSGarrett D'Amore break;
11390219346bSGarrett D'Amore
11400219346bSGarrett D'Amore case HME_1C0_REVID:
11410219346bSGarrett D'Amore HME_FAULT_MSG2(hmep, SEVERITY_NONE, DISPLAY_MSG,
11420219346bSGarrett D'Amore "PCI IO 1.0 Found (Rev Id = %x)", hm_rev);
11430219346bSGarrett D'Amore break;
11440219346bSGarrett D'Amore
11450219346bSGarrett D'Amore default:
114606673d9bSGarrett D'Amore HME_FAULT_MSG3(hmep, SEVERITY_NONE, DISPLAY_MSG,
11470219346bSGarrett D'Amore "%s (Rev Id = %x) Found",
11480219346bSGarrett D'Amore (hm_rev == HME_2C0_REVID) ? "PCI IO 2.0" : "Sbus", hm_rev);
11490219346bSGarrett D'Amore hmep->hme_frame_enable = 1;
11500219346bSGarrett D'Amore hmep->hme_lance_mode_enable = 1;
11510219346bSGarrett D'Amore hmep->hme_rxcv_enable = 1;
11520219346bSGarrett D'Amore break;
11530219346bSGarrett D'Amore }
11540219346bSGarrett D'Amore }
11550219346bSGarrett D'Amore
11560219346bSGarrett D'Amore /*
11570219346bSGarrett D'Amore * Interface exists: make available by filling in network interface
11580219346bSGarrett D'Amore * record. System will initialize the interface when it is ready
11590219346bSGarrett D'Amore * to accept packets.
11600219346bSGarrett D'Amore */
11610219346bSGarrett D'Amore int
hmeattach(dev_info_t * dip,ddi_attach_cmd_t cmd)11620219346bSGarrett D'Amore hmeattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
11630219346bSGarrett D'Amore {
11640219346bSGarrett D'Amore struct hme *hmep;
11650219346bSGarrett D'Amore mac_register_t *macp = NULL;
11660219346bSGarrett D'Amore int regno;
11670219346bSGarrett D'Amore int hm_rev = 0;
11680219346bSGarrett D'Amore int prop_len = sizeof (int);
11690219346bSGarrett D'Amore ddi_acc_handle_t cfg_handle;
11700219346bSGarrett D'Amore struct {
11710219346bSGarrett D'Amore uint16_t vendorid;
11720219346bSGarrett D'Amore uint16_t devid;
11730219346bSGarrett D'Amore uint16_t command;
11740219346bSGarrett D'Amore uint16_t status;
11750219346bSGarrett D'Amore uint8_t revid;
11760219346bSGarrett D'Amore uint8_t j1;
11770219346bSGarrett D'Amore uint16_t j2;
11780219346bSGarrett D'Amore } *cfg_ptr;
11790219346bSGarrett D'Amore
11800219346bSGarrett D'Amore switch (cmd) {
11810219346bSGarrett D'Amore case DDI_ATTACH:
11820219346bSGarrett D'Amore break;
11830219346bSGarrett D'Amore
11840219346bSGarrett D'Amore case DDI_RESUME:
11850219346bSGarrett D'Amore if ((hmep = ddi_get_driver_private(dip)) == NULL)
11860219346bSGarrett D'Amore return (DDI_FAILURE);
11870219346bSGarrett D'Amore
11880219346bSGarrett D'Amore hmep->hme_flags &= ~HMESUSPENDED;
118906673d9bSGarrett D'Amore
119006673d9bSGarrett D'Amore mii_resume(hmep->hme_mii);
11910219346bSGarrett D'Amore
11920219346bSGarrett D'Amore if (hmep->hme_started)
11930219346bSGarrett D'Amore (void) hmeinit(hmep);
11940219346bSGarrett D'Amore return (DDI_SUCCESS);
11950219346bSGarrett D'Amore
11960219346bSGarrett D'Amore default:
11970219346bSGarrett D'Amore return (DDI_FAILURE);
11980219346bSGarrett D'Amore }
11990219346bSGarrett D'Amore
12000219346bSGarrett D'Amore /*
12010219346bSGarrett D'Amore * Allocate soft device data structure
12020219346bSGarrett D'Amore */
12030219346bSGarrett D'Amore hmep = kmem_zalloc(sizeof (*hmep), KM_SLEEP);
12040219346bSGarrett D'Amore
12050219346bSGarrett D'Amore /*
12060219346bSGarrett D'Amore * Might as well set up elements of data structure
12070219346bSGarrett D'Amore */
12080219346bSGarrett D'Amore hmep->dip = dip;
12090219346bSGarrett D'Amore hmep->instance = ddi_get_instance(dip);
12100219346bSGarrett D'Amore hmep->pagesize = ddi_ptob(dip, (ulong_t)1); /* IOMMU PSize */
12110219346bSGarrett D'Amore
12120219346bSGarrett D'Amore /*
12130219346bSGarrett D'Amore * Might as well setup the driver private
12140219346bSGarrett D'Amore * structure as part of the dip.
12150219346bSGarrett D'Amore */
12160219346bSGarrett D'Amore ddi_set_driver_private(dip, hmep);
12170219346bSGarrett D'Amore
12180219346bSGarrett D'Amore /*
12190219346bSGarrett D'Amore * Reject this device if it's in a slave-only slot.
12200219346bSGarrett D'Amore */
12210219346bSGarrett D'Amore if (ddi_slaveonly(dip) == DDI_SUCCESS) {
12220219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
12230219346bSGarrett D'Amore "Dev not used - dev in slave only slot");
12240219346bSGarrett D'Amore goto error_state;
12250219346bSGarrett D'Amore }
12260219346bSGarrett D'Amore
12270219346bSGarrett D'Amore /*
12280219346bSGarrett D'Amore * Map in the device registers.
12290219346bSGarrett D'Amore *
12300219346bSGarrett D'Amore * Reg # 0 is the Global register set
12310219346bSGarrett D'Amore * Reg # 1 is the ETX register set
12320219346bSGarrett D'Amore * Reg # 2 is the ERX register set
12330219346bSGarrett D'Amore * Reg # 3 is the BigMAC register set.
12340219346bSGarrett D'Amore * Reg # 4 is the MIF register set
12350219346bSGarrett D'Amore */
12360219346bSGarrett D'Amore if (ddi_dev_nregs(dip, ®no) != (DDI_SUCCESS)) {
12370219346bSGarrett D'Amore HME_FAULT_MSG2(hmep, SEVERITY_HIGH, INIT_MSG,
12380219346bSGarrett D'Amore ddi_nregs_fail_msg, regno);
12390219346bSGarrett D'Amore goto error_state;
12400219346bSGarrett D'Amore }
12410219346bSGarrett D'Amore
12420219346bSGarrett D'Amore switch (regno) {
12430219346bSGarrett D'Amore case 5:
12440219346bSGarrett D'Amore hmep->hme_cheerio_mode = 0;
12450219346bSGarrett D'Amore break;
12460219346bSGarrett D'Amore case 2:
12470219346bSGarrett D'Amore case 3: /* for hot swap/plug, there will be 3 entries in "reg" prop */
12480219346bSGarrett D'Amore hmep->hme_cheerio_mode = 1;
12490219346bSGarrett D'Amore break;
12500219346bSGarrett D'Amore default:
12510219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
12520219346bSGarrett D'Amore bad_num_regs_msg);
12530219346bSGarrett D'Amore goto error_state;
12540219346bSGarrett D'Amore }
12550219346bSGarrett D'Amore
12560219346bSGarrett D'Amore /* Initialize device attributes structure */
12570219346bSGarrett D'Amore hmep->hme_dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
12580219346bSGarrett D'Amore
12590219346bSGarrett D'Amore if (hmep->hme_cheerio_mode)
12600219346bSGarrett D'Amore hmep->hme_dev_attr.devacc_attr_endian_flags =
12610219346bSGarrett D'Amore DDI_STRUCTURE_LE_ACC;
12620219346bSGarrett D'Amore else
12630219346bSGarrett D'Amore hmep->hme_dev_attr.devacc_attr_endian_flags =
12640219346bSGarrett D'Amore DDI_STRUCTURE_BE_ACC;
12650219346bSGarrett D'Amore
12660219346bSGarrett D'Amore hmep->hme_dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
12670219346bSGarrett D'Amore
12680219346bSGarrett D'Amore if (hmep->hme_cheerio_mode) {
12690219346bSGarrett D'Amore uint8_t oldLT;
12700219346bSGarrett D'Amore uint8_t newLT = 0;
12710219346bSGarrett D'Amore dev_info_t *pdip;
12720219346bSGarrett D'Amore const char *pdrvname;
12730219346bSGarrett D'Amore
12740219346bSGarrett D'Amore /*
12750219346bSGarrett D'Amore * Map the PCI config space
12760219346bSGarrett D'Amore */
12770219346bSGarrett D'Amore if (pci_config_setup(dip, &hmep->pci_config_handle) !=
12780219346bSGarrett D'Amore DDI_SUCCESS) {
12790219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
12800219346bSGarrett D'Amore "pci_config_setup() failed..");
12810219346bSGarrett D'Amore goto error_state;
12820219346bSGarrett D'Amore }
12830219346bSGarrett D'Amore
12840219346bSGarrett D'Amore if (ddi_regs_map_setup(dip, 1,
12850219346bSGarrett D'Amore (caddr_t *)&(hmep->hme_globregp), 0, 0,
12860219346bSGarrett D'Amore &hmep->hme_dev_attr, &hmep->hme_globregh)) {
12870219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
12880219346bSGarrett D'Amore mregs_4global_reg_fail_msg);
12890219346bSGarrett D'Amore goto error_unmap;
12900219346bSGarrett D'Amore }
12910219346bSGarrett D'Amore hmep->hme_etxregh = hmep->hme_erxregh = hmep->hme_bmacregh =
12920219346bSGarrett D'Amore hmep->hme_mifregh = hmep->hme_globregh;
12930219346bSGarrett D'Amore
12940219346bSGarrett D'Amore hmep->hme_etxregp =
12950219346bSGarrett D'Amore (void *)(((caddr_t)hmep->hme_globregp) + 0x2000);
12960219346bSGarrett D'Amore hmep->hme_erxregp =
12970219346bSGarrett D'Amore (void *)(((caddr_t)hmep->hme_globregp) + 0x4000);
12980219346bSGarrett D'Amore hmep->hme_bmacregp =
12990219346bSGarrett D'Amore (void *)(((caddr_t)hmep->hme_globregp) + 0x6000);
13000219346bSGarrett D'Amore hmep->hme_mifregp =
13010219346bSGarrett D'Amore (void *)(((caddr_t)hmep->hme_globregp) + 0x7000);
13020219346bSGarrett D'Amore
13030219346bSGarrett D'Amore /*
13040219346bSGarrett D'Amore * Get parent pci bridge info.
13050219346bSGarrett D'Amore */
13060219346bSGarrett D'Amore pdip = ddi_get_parent(dip);
13070219346bSGarrett D'Amore pdrvname = ddi_driver_name(pdip);
13080219346bSGarrett D'Amore
13090219346bSGarrett D'Amore oldLT = pci_config_get8(hmep->pci_config_handle,
13100219346bSGarrett D'Amore PCI_CONF_LATENCY_TIMER);
13110219346bSGarrett D'Amore /*
13120219346bSGarrett D'Amore * Honor value set in /etc/system
13130219346bSGarrett D'Amore * "set hme:pci_latency_timer=0xYY"
13140219346bSGarrett D'Amore */
13150219346bSGarrett D'Amore if (pci_latency_timer)
13160219346bSGarrett D'Amore newLT = pci_latency_timer;
13170219346bSGarrett D'Amore /*
13180219346bSGarrett D'Amore * Modify LT for simba
13190219346bSGarrett D'Amore */
13200219346bSGarrett D'Amore else if (strcmp("simba", pdrvname) == 0)
13210219346bSGarrett D'Amore newLT = 0xf0;
13220219346bSGarrett D'Amore /*
13230219346bSGarrett D'Amore * Ensure minimum cheerio latency timer of 0x50
13240219346bSGarrett D'Amore * Usually OBP or pci bridge should set this value
13250219346bSGarrett D'Amore * based on cheerio
13260219346bSGarrett D'Amore * min_grant * 8(33MHz) = 0x50 = 0xa * 0x8
13270219346bSGarrett D'Amore * Some system set cheerio LT at 0x40
13280219346bSGarrett D'Amore */
13290219346bSGarrett D'Amore else if (oldLT < 0x40)
13300219346bSGarrett D'Amore newLT = 0x50;
13310219346bSGarrett D'Amore
13320219346bSGarrett D'Amore /*
13330219346bSGarrett D'Amore * Now program cheerio's pci latency timer with newLT
13340219346bSGarrett D'Amore */
13350219346bSGarrett D'Amore if (newLT)
13360219346bSGarrett D'Amore pci_config_put8(hmep->pci_config_handle,
13370219346bSGarrett D'Amore PCI_CONF_LATENCY_TIMER, (uchar_t)newLT);
13380219346bSGarrett D'Amore } else { /* Map register sets */
13390219346bSGarrett D'Amore if (ddi_regs_map_setup(dip, 0,
13400219346bSGarrett D'Amore (caddr_t *)&(hmep->hme_globregp), 0, 0,
13410219346bSGarrett D'Amore &hmep->hme_dev_attr, &hmep->hme_globregh)) {
13420219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
13430219346bSGarrett D'Amore mregs_4global_reg_fail_msg);
13440219346bSGarrett D'Amore goto error_state;
13450219346bSGarrett D'Amore }
13460219346bSGarrett D'Amore if (ddi_regs_map_setup(dip, 1,
13470219346bSGarrett D'Amore (caddr_t *)&(hmep->hme_etxregp), 0, 0,
13480219346bSGarrett D'Amore &hmep->hme_dev_attr, &hmep->hme_etxregh)) {
13490219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
13500219346bSGarrett D'Amore mregs_4etx_reg_fail_msg);
13510219346bSGarrett D'Amore goto error_unmap;
13520219346bSGarrett D'Amore }
13530219346bSGarrett D'Amore if (ddi_regs_map_setup(dip, 2,
13540219346bSGarrett D'Amore (caddr_t *)&(hmep->hme_erxregp), 0, 0,
13550219346bSGarrett D'Amore &hmep->hme_dev_attr, &hmep->hme_erxregh)) {
13560219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
13570219346bSGarrett D'Amore mregs_4erx_reg_fail_msg);
13580219346bSGarrett D'Amore goto error_unmap;
13590219346bSGarrett D'Amore }
13600219346bSGarrett D'Amore if (ddi_regs_map_setup(dip, 3,
13610219346bSGarrett D'Amore (caddr_t *)&(hmep->hme_bmacregp), 0, 0,
13620219346bSGarrett D'Amore &hmep->hme_dev_attr, &hmep->hme_bmacregh)) {
13630219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
13640219346bSGarrett D'Amore mregs_4bmac_reg_fail_msg);
13650219346bSGarrett D'Amore goto error_unmap;
13660219346bSGarrett D'Amore }
13670219346bSGarrett D'Amore
13680219346bSGarrett D'Amore if (ddi_regs_map_setup(dip, 4,
13690219346bSGarrett D'Amore (caddr_t *)&(hmep->hme_mifregp), 0, 0,
13700219346bSGarrett D'Amore &hmep->hme_dev_attr, &hmep->hme_mifregh)) {
13710219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
13720219346bSGarrett D'Amore mregs_4mif_reg_fail_msg);
13730219346bSGarrett D'Amore goto error_unmap;
13740219346bSGarrett D'Amore }
13750219346bSGarrett D'Amore } /* Endif cheerio_mode */
13760219346bSGarrett D'Amore
13770219346bSGarrett D'Amore /*
13780219346bSGarrett D'Amore * Based on the hm-rev, set some capabilities
13790219346bSGarrett D'Amore * Set up default capabilities for HM 2.0
13800219346bSGarrett D'Amore */
13810219346bSGarrett D'Amore hmep->hme_frame_enable = 0;
13820219346bSGarrett D'Amore hmep->hme_lance_mode_enable = 0;
13830219346bSGarrett D'Amore hmep->hme_rxcv_enable = 0;
13840219346bSGarrett D'Amore
13850219346bSGarrett D'Amore /* NEW routine to get the properties */
13860219346bSGarrett D'Amore
13870219346bSGarrett D'Amore if (ddi_getlongprop_buf(DDI_DEV_T_ANY, hmep->dip, 0, "hm-rev",
13880219346bSGarrett D'Amore (caddr_t)&hm_rev, &prop_len) == DDI_PROP_SUCCESS) {
13890219346bSGarrett D'Amore
13900219346bSGarrett D'Amore hmep->asic_rev = hm_rev;
13910219346bSGarrett D'Amore hmeget_hm_rev_property(hmep);
13920219346bSGarrett D'Amore } else {
13930219346bSGarrett D'Amore /*
13940219346bSGarrett D'Amore * hm_rev property not found so, this is
13950219346bSGarrett D'Amore * case of hot insertion of card without interpreting fcode.
13960219346bSGarrett D'Amore * Get it from revid in config space after mapping it.
13970219346bSGarrett D'Amore */
13980219346bSGarrett D'Amore if (ddi_regs_map_setup(hmep->dip, 0, (caddr_t *)&cfg_ptr,
13990219346bSGarrett D'Amore 0, 0, &hmep->hme_dev_attr, &cfg_handle)) {
14000219346bSGarrett D'Amore return (DDI_FAILURE);
14010219346bSGarrett D'Amore }
14020219346bSGarrett D'Amore /*
14030219346bSGarrett D'Amore * Since this is cheerio-based PCI card, we write 0xC in the
14040219346bSGarrett D'Amore * top 4 bits(4-7) of hm-rev and retain the bottom(0-3) bits
14050219346bSGarrett D'Amore * for Cheerio version(1.0 or 2.0 = 0xC0 or 0xC1)
14060219346bSGarrett D'Amore */
14070219346bSGarrett D'Amore hm_rev = ddi_get8(cfg_handle, &cfg_ptr->revid);
14080219346bSGarrett D'Amore hm_rev = HME_1C0_REVID | (hm_rev & HME_REV_VERS_MASK);
14090219346bSGarrett D'Amore hmep->asic_rev = hm_rev;
14100219346bSGarrett D'Amore if (ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
14110219346bSGarrett D'Amore "hm-rev", (caddr_t)&hm_rev, sizeof (hm_rev)) !=
14120219346bSGarrett D'Amore DDI_SUCCESS) {
14130219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, AUTOCONFIG_MSG,
141406673d9bSGarrett D'Amore "ddi_prop_create error for hm_rev");
14150219346bSGarrett D'Amore }
14160219346bSGarrett D'Amore ddi_regs_map_free(&cfg_handle);
14170219346bSGarrett D'Amore
14180219346bSGarrett D'Amore hmeget_hm_rev_property(hmep);
14190219346bSGarrett D'Amore
14200219346bSGarrett D'Amore /* get info via VPD */
14210219346bSGarrett D'Amore if (hmeget_promprops(dip) != DDI_SUCCESS) {
14220219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, AUTOCONFIG_MSG,
142306673d9bSGarrett D'Amore "no promprops");
14240219346bSGarrett D'Amore }
14250219346bSGarrett D'Amore }
14260219346bSGarrett D'Amore
14270219346bSGarrett D'Amore if (ddi_intr_hilevel(dip, 0)) {
14280219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, NFATAL_ERR_MSG,
14290219346bSGarrett D'Amore " high-level interrupts are not supported");
14300219346bSGarrett D'Amore goto error_unmap;
14310219346bSGarrett D'Amore }
14320219346bSGarrett D'Amore
14330219346bSGarrett D'Amore /*
14340219346bSGarrett D'Amore * Get intr. block cookie so that mutex locks can be initialized.
14350219346bSGarrett D'Amore */
14360219346bSGarrett D'Amore if (ddi_get_iblock_cookie(dip, 0, &hmep->hme_cookie) != DDI_SUCCESS)
14370219346bSGarrett D'Amore goto error_unmap;
14380219346bSGarrett D'Amore
14390219346bSGarrett D'Amore /*
14400219346bSGarrett D'Amore * Initialize mutex's for this device.
14410219346bSGarrett D'Amore */
14420219346bSGarrett D'Amore mutex_init(&hmep->hme_xmitlock, NULL, MUTEX_DRIVER, hmep->hme_cookie);
14430219346bSGarrett D'Amore mutex_init(&hmep->hme_intrlock, NULL, MUTEX_DRIVER, hmep->hme_cookie);
14440219346bSGarrett D'Amore
14450219346bSGarrett D'Amore /*
14460219346bSGarrett D'Amore * Quiesce the hardware.
14470219346bSGarrett D'Amore */
14480219346bSGarrett D'Amore (void) hmestop(hmep);
14490219346bSGarrett D'Amore
14500219346bSGarrett D'Amore /*
14510219346bSGarrett D'Amore * Add interrupt to system
14520219346bSGarrett D'Amore */
14530219346bSGarrett D'Amore if (ddi_add_intr(dip, 0, (ddi_iblock_cookie_t *)NULL,
14540219346bSGarrett D'Amore (ddi_idevice_cookie_t *)NULL, hmeintr, (caddr_t)hmep)) {
14550219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
14560219346bSGarrett D'Amore add_intr_fail_msg);
14570219346bSGarrett D'Amore goto error_mutex;
14580219346bSGarrett D'Amore }
14590219346bSGarrett D'Amore
14600219346bSGarrett D'Amore /*
14610219346bSGarrett D'Amore * Set up the ethernet mac address.
14620219346bSGarrett D'Amore */
14630219346bSGarrett D'Amore hme_setup_mac_address(hmep, dip);
14640219346bSGarrett D'Amore
14650219346bSGarrett D'Amore if (!hmeinit_xfer_params(hmep))
14660219346bSGarrett D'Amore goto error_intr;
14670219346bSGarrett D'Amore
14680219346bSGarrett D'Amore if (hmeburstsizes(hmep) == DDI_FAILURE) {
14690219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, burst_size_msg);
14700219346bSGarrett D'Amore goto error_intr;
14710219346bSGarrett D'Amore }
14720219346bSGarrett D'Amore
14730219346bSGarrett D'Amore if (hmeallocthings(hmep) != DDI_SUCCESS) {
14740219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, CONFIG_MSG,
14750219346bSGarrett D'Amore "resource allocation failed");
14760219346bSGarrett D'Amore goto error_intr;
14770219346bSGarrett D'Amore }
14780219346bSGarrett D'Amore
14790219346bSGarrett D'Amore if (hmeallocbufs(hmep) != DDI_SUCCESS) {
14800219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, CONFIG_MSG,
14810219346bSGarrett D'Amore "buffer allocation failed");
14820219346bSGarrett D'Amore goto error_intr;
14830219346bSGarrett D'Amore }
14840219346bSGarrett D'Amore
14850219346bSGarrett D'Amore hmestatinit(hmep);
14860219346bSGarrett D'Amore
1487e8717ca2SGarrett D'Amore /* our external (preferred) PHY is at address 0 */
1488e8717ca2SGarrett D'Amore (void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, "first-phy", 0);
1489e8717ca2SGarrett D'Amore
149006673d9bSGarrett D'Amore hmep->hme_mii = mii_alloc(hmep, dip, &hme_mii_ops);
149106673d9bSGarrett D'Amore if (hmep->hme_mii == NULL) {
149206673d9bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, CONFIG_MSG,
149306673d9bSGarrett D'Amore "mii_alloc failed");
149406673d9bSGarrett D'Amore goto error_intr;
149506673d9bSGarrett D'Amore }
149606673d9bSGarrett D'Amore /* force a probe for the PHY */
149706673d9bSGarrett D'Amore mii_probe(hmep->hme_mii);
149806673d9bSGarrett D'Amore
14990219346bSGarrett D'Amore if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
15000219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, CONFIG_MSG,
15010219346bSGarrett D'Amore "mac_alloc failed");
15020219346bSGarrett D'Amore goto error_intr;
15030219346bSGarrett D'Amore }
15040219346bSGarrett D'Amore macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
15050219346bSGarrett D'Amore macp->m_driver = hmep;
15060219346bSGarrett D'Amore macp->m_dip = dip;
15070219346bSGarrett D'Amore macp->m_src_addr = hmep->hme_ouraddr.ether_addr_octet;
15080219346bSGarrett D'Amore macp->m_callbacks = &hme_m_callbacks;
15090219346bSGarrett D'Amore macp->m_min_sdu = 0;
15100219346bSGarrett D'Amore macp->m_max_sdu = ETHERMTU;
15110219346bSGarrett D'Amore macp->m_margin = VLAN_TAGSZ;
151206673d9bSGarrett D'Amore macp->m_priv_props = hme_priv_prop;
15130219346bSGarrett D'Amore if (mac_register(macp, &hmep->hme_mh) != 0) {
15140219346bSGarrett D'Amore mac_free(macp);
15150219346bSGarrett D'Amore goto error_intr;
15160219346bSGarrett D'Amore }
15170219346bSGarrett D'Amore
15180219346bSGarrett D'Amore mac_free(macp);
15190219346bSGarrett D'Amore
15200219346bSGarrett D'Amore ddi_report_dev(dip);
15210219346bSGarrett D'Amore return (DDI_SUCCESS);
15220219346bSGarrett D'Amore
15230219346bSGarrett D'Amore /*
15240219346bSGarrett D'Amore * Failure Exit
15250219346bSGarrett D'Amore */
15260219346bSGarrett D'Amore
15270219346bSGarrett D'Amore error_intr:
15280219346bSGarrett D'Amore if (hmep->hme_cookie)
15290219346bSGarrett D'Amore ddi_remove_intr(dip, 0, (ddi_iblock_cookie_t)0);
15300219346bSGarrett D'Amore
153106673d9bSGarrett D'Amore if (hmep->hme_mii)
153206673d9bSGarrett D'Amore mii_free(hmep->hme_mii);
153306673d9bSGarrett D'Amore
15340219346bSGarrett D'Amore error_mutex:
15350219346bSGarrett D'Amore mutex_destroy(&hmep->hme_xmitlock);
15360219346bSGarrett D'Amore mutex_destroy(&hmep->hme_intrlock);
15370219346bSGarrett D'Amore
15380219346bSGarrett D'Amore error_unmap:
15390219346bSGarrett D'Amore if (hmep->hme_globregh)
15400219346bSGarrett D'Amore ddi_regs_map_free(&hmep->hme_globregh);
15410219346bSGarrett D'Amore if (hmep->hme_cheerio_mode == 0) {
15420219346bSGarrett D'Amore if (hmep->hme_etxregh)
15430219346bSGarrett D'Amore ddi_regs_map_free(&hmep->hme_etxregh);
15440219346bSGarrett D'Amore if (hmep->hme_erxregh)
15450219346bSGarrett D'Amore ddi_regs_map_free(&hmep->hme_erxregh);
15460219346bSGarrett D'Amore if (hmep->hme_bmacregh)
15470219346bSGarrett D'Amore ddi_regs_map_free(&hmep->hme_bmacregh);
15480219346bSGarrett D'Amore if (hmep->hme_mifregh)
15490219346bSGarrett D'Amore ddi_regs_map_free(&hmep->hme_mifregh);
15500219346bSGarrett D'Amore } else {
15510219346bSGarrett D'Amore if (hmep->pci_config_handle)
15520219346bSGarrett D'Amore (void) pci_config_teardown(&hmep->pci_config_handle);
15530219346bSGarrett D'Amore hmep->hme_etxregh = hmep->hme_erxregh = hmep->hme_bmacregh =
15540219346bSGarrett D'Amore hmep->hme_mifregh = hmep->hme_globregh = NULL;
15550219346bSGarrett D'Amore }
15560219346bSGarrett D'Amore
15570219346bSGarrett D'Amore error_state:
15580219346bSGarrett D'Amore hmefreethings(hmep);
15590219346bSGarrett D'Amore hmefreebufs(hmep);
15600219346bSGarrett D'Amore
15610219346bSGarrett D'Amore if (hmep) {
15620219346bSGarrett D'Amore kmem_free((caddr_t)hmep, sizeof (*hmep));
15630219346bSGarrett D'Amore ddi_set_driver_private(dip, NULL);
15640219346bSGarrett D'Amore }
15650219346bSGarrett D'Amore
15660219346bSGarrett D'Amore return (DDI_FAILURE);
15670219346bSGarrett D'Amore }
15680219346bSGarrett D'Amore
15690219346bSGarrett D'Amore int
hmedetach(dev_info_t * dip,ddi_detach_cmd_t cmd)15700219346bSGarrett D'Amore hmedetach(dev_info_t *dip, ddi_detach_cmd_t cmd)
15710219346bSGarrett D'Amore {
15720219346bSGarrett D'Amore struct hme *hmep;
15730219346bSGarrett D'Amore
15740219346bSGarrett D'Amore if ((hmep = ddi_get_driver_private(dip)) == NULL)
15750219346bSGarrett D'Amore return (DDI_FAILURE);
15760219346bSGarrett D'Amore
15770219346bSGarrett D'Amore switch (cmd) {
15780219346bSGarrett D'Amore case DDI_DETACH:
15790219346bSGarrett D'Amore break;
15800219346bSGarrett D'Amore
15810219346bSGarrett D'Amore case DDI_SUSPEND:
158206673d9bSGarrett D'Amore mii_suspend(hmep->hme_mii);
15830219346bSGarrett D'Amore hmep->hme_flags |= HMESUSPENDED;
15840219346bSGarrett D'Amore hmeuninit(hmep);
15850219346bSGarrett D'Amore return (DDI_SUCCESS);
15860219346bSGarrett D'Amore
15870219346bSGarrett D'Amore default:
15880219346bSGarrett D'Amore return (DDI_FAILURE);
15890219346bSGarrett D'Amore }
15900219346bSGarrett D'Amore
15910219346bSGarrett D'Amore
15920219346bSGarrett D'Amore if (mac_unregister(hmep->hme_mh) != 0) {
15930219346bSGarrett D'Amore return (DDI_FAILURE);
15940219346bSGarrett D'Amore }
15950219346bSGarrett D'Amore
15960219346bSGarrett D'Amore /*
15970219346bSGarrett D'Amore * Make driver quiescent, we don't want to prevent the
15980219346bSGarrett D'Amore * detach on failure. Note that this should be redundant,
15990219346bSGarrett D'Amore * since mac_stop should already have called hmeuninit().
16000219346bSGarrett D'Amore */
16010219346bSGarrett D'Amore if (!(hmep->hme_flags & HMESUSPENDED)) {
16020219346bSGarrett D'Amore (void) hmestop(hmep);
16030219346bSGarrett D'Amore }
16040219346bSGarrett D'Amore
160506673d9bSGarrett D'Amore if (hmep->hme_mii)
160606673d9bSGarrett D'Amore mii_free(hmep->hme_mii);
160706673d9bSGarrett D'Amore
16080219346bSGarrett D'Amore /*
16090219346bSGarrett D'Amore * Remove instance of the intr
16100219346bSGarrett D'Amore */
16110219346bSGarrett D'Amore ddi_remove_intr(dip, 0, (ddi_iblock_cookie_t)0);
16120219346bSGarrett D'Amore
16130219346bSGarrett D'Amore /*
16140219346bSGarrett D'Amore * Unregister kstats.
16150219346bSGarrett D'Amore */
16160219346bSGarrett D'Amore if (hmep->hme_ksp != NULL)
16170219346bSGarrett D'Amore kstat_delete(hmep->hme_ksp);
16180219346bSGarrett D'Amore if (hmep->hme_intrstats != NULL)
16190219346bSGarrett D'Amore kstat_delete(hmep->hme_intrstats);
16200219346bSGarrett D'Amore
16210219346bSGarrett D'Amore hmep->hme_ksp = NULL;
16220219346bSGarrett D'Amore hmep->hme_intrstats = NULL;
16230219346bSGarrett D'Amore
16240219346bSGarrett D'Amore /*
16250219346bSGarrett D'Amore * Destroy all mutexes and data structures allocated during
16260219346bSGarrett D'Amore * attach time.
16270219346bSGarrett D'Amore *
16280219346bSGarrett D'Amore * Note: at this time we should be the only thread accessing
16290219346bSGarrett D'Amore * the structures for this instance.
16300219346bSGarrett D'Amore */
16310219346bSGarrett D'Amore
16320219346bSGarrett D'Amore if (hmep->hme_globregh)
16330219346bSGarrett D'Amore ddi_regs_map_free(&hmep->hme_globregh);
16340219346bSGarrett D'Amore if (hmep->hme_cheerio_mode == 0) {
16350219346bSGarrett D'Amore if (hmep->hme_etxregh)
16360219346bSGarrett D'Amore ddi_regs_map_free(&hmep->hme_etxregh);
16370219346bSGarrett D'Amore if (hmep->hme_erxregh)
16380219346bSGarrett D'Amore ddi_regs_map_free(&hmep->hme_erxregh);
16390219346bSGarrett D'Amore if (hmep->hme_bmacregh)
16400219346bSGarrett D'Amore ddi_regs_map_free(&hmep->hme_bmacregh);
16410219346bSGarrett D'Amore if (hmep->hme_mifregh)
16420219346bSGarrett D'Amore ddi_regs_map_free(&hmep->hme_mifregh);
16430219346bSGarrett D'Amore } else {
16440219346bSGarrett D'Amore if (hmep->pci_config_handle)
16450219346bSGarrett D'Amore (void) pci_config_teardown(&hmep->pci_config_handle);
16460219346bSGarrett D'Amore hmep->hme_etxregh = hmep->hme_erxregh = hmep->hme_bmacregh =
16470219346bSGarrett D'Amore hmep->hme_mifregh = hmep->hme_globregh = NULL;
16480219346bSGarrett D'Amore }
16490219346bSGarrett D'Amore
16500219346bSGarrett D'Amore mutex_destroy(&hmep->hme_xmitlock);
16510219346bSGarrett D'Amore mutex_destroy(&hmep->hme_intrlock);
16520219346bSGarrett D'Amore
16530219346bSGarrett D'Amore hmefreethings(hmep);
16540219346bSGarrett D'Amore hmefreebufs(hmep);
16550219346bSGarrett D'Amore
16560219346bSGarrett D'Amore ddi_set_driver_private(dip, NULL);
16570219346bSGarrett D'Amore kmem_free(hmep, sizeof (struct hme));
16580219346bSGarrett D'Amore
16590219346bSGarrett D'Amore return (DDI_SUCCESS);
16600219346bSGarrett D'Amore }
16610219346bSGarrett D'Amore
16620219346bSGarrett D'Amore int
hmequiesce(dev_info_t * dip)16630219346bSGarrett D'Amore hmequiesce(dev_info_t *dip)
16640219346bSGarrett D'Amore {
16650219346bSGarrett D'Amore struct hme *hmep;
16660219346bSGarrett D'Amore
16670219346bSGarrett D'Amore if ((hmep = ddi_get_driver_private(dip)) == NULL)
16680219346bSGarrett D'Amore return (DDI_FAILURE);
16690219346bSGarrett D'Amore
16700219346bSGarrett D'Amore (void) hmestop(hmep);
16710219346bSGarrett D'Amore return (DDI_SUCCESS);
16720219346bSGarrett D'Amore }
16730219346bSGarrett D'Amore
16740219346bSGarrett D'Amore static boolean_t
hmeinit_xfer_params(struct hme * hmep)16750219346bSGarrett D'Amore hmeinit_xfer_params(struct hme *hmep)
16760219346bSGarrett D'Amore {
16770219346bSGarrett D'Amore int hme_ipg1_conf, hme_ipg2_conf;
16780219346bSGarrett D'Amore int hme_ipg0_conf, hme_lance_mode_conf;
16790219346bSGarrett D'Amore int prop_len = sizeof (int);
16800219346bSGarrett D'Amore dev_info_t *dip;
16810219346bSGarrett D'Amore
16820219346bSGarrett D'Amore dip = hmep->dip;
16830219346bSGarrett D'Amore
16840219346bSGarrett D'Amore /*
16850219346bSGarrett D'Amore * Set up the start-up values for user-configurable parameters
16860219346bSGarrett D'Amore * Get the values from the global variables first.
16870219346bSGarrett D'Amore * Use the MASK to limit the value to allowed maximum.
16880219346bSGarrett D'Amore */
168906673d9bSGarrett D'Amore hmep->hme_ipg1 = hme_ipg1 & HME_MASK_8BIT;
169006673d9bSGarrett D'Amore hmep->hme_ipg2 = hme_ipg2 & HME_MASK_8BIT;
169106673d9bSGarrett D'Amore hmep->hme_ipg0 = hme_ipg0 & HME_MASK_5BIT;
16920219346bSGarrett D'Amore
16930219346bSGarrett D'Amore /*
16940219346bSGarrett D'Amore * Get the parameter values configured in .conf file.
16950219346bSGarrett D'Amore */
16960219346bSGarrett D'Amore if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "ipg1",
16970219346bSGarrett D'Amore (caddr_t)&hme_ipg1_conf, &prop_len) == DDI_PROP_SUCCESS) {
169806673d9bSGarrett D'Amore hmep->hme_ipg1 = hme_ipg1_conf & HME_MASK_8BIT;
16990219346bSGarrett D'Amore }
17000219346bSGarrett D'Amore
17010219346bSGarrett D'Amore if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "ipg2",
17020219346bSGarrett D'Amore (caddr_t)&hme_ipg2_conf, &prop_len) == DDI_PROP_SUCCESS) {
170306673d9bSGarrett D'Amore hmep->hme_ipg2 = hme_ipg2_conf & HME_MASK_8BIT;
17040219346bSGarrett D'Amore }
17050219346bSGarrett D'Amore
17060219346bSGarrett D'Amore if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "ipg0",
17070219346bSGarrett D'Amore (caddr_t)&hme_ipg0_conf, &prop_len) == DDI_PROP_SUCCESS) {
170806673d9bSGarrett D'Amore hmep->hme_ipg0 = hme_ipg0_conf & HME_MASK_5BIT;
17090219346bSGarrett D'Amore }
17100219346bSGarrett D'Amore
17110219346bSGarrett D'Amore if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "lance_mode",
17120219346bSGarrett D'Amore (caddr_t)&hme_lance_mode_conf, &prop_len) == DDI_PROP_SUCCESS) {
171306673d9bSGarrett D'Amore hmep->hme_lance_mode = hme_lance_mode_conf & HME_MASK_1BIT;
17140219346bSGarrett D'Amore }
17150219346bSGarrett D'Amore
17160219346bSGarrett D'Amore return (B_TRUE);
17170219346bSGarrett D'Amore }
17180219346bSGarrett D'Amore
17190219346bSGarrett D'Amore /*
17200219346bSGarrett D'Amore * Return 0 upon success, 1 on failure.
17210219346bSGarrett D'Amore */
17220219346bSGarrett D'Amore static uint_t
hmestop(struct hme * hmep)17230219346bSGarrett D'Amore hmestop(struct hme *hmep)
17240219346bSGarrett D'Amore {
17250219346bSGarrett D'Amore /*
17260219346bSGarrett D'Amore * Disable the Tx dma engine.
17270219346bSGarrett D'Amore */
17280219346bSGarrett D'Amore PUT_ETXREG(config, (GET_ETXREG(config) & ~HMET_CONFIG_TXDMA_EN));
17290219346bSGarrett D'Amore HMEDELAY(((GET_ETXREG(state_mach) & 0x1f) == 0x1), HMEMAXRSTDELAY);
17300219346bSGarrett D'Amore
17310219346bSGarrett D'Amore /*
17320219346bSGarrett D'Amore * Disable the Rx dma engine.
17330219346bSGarrett D'Amore */
17340219346bSGarrett D'Amore PUT_ERXREG(config, (GET_ERXREG(config) & ~HMER_CONFIG_RXDMA_EN));
17350219346bSGarrett D'Amore HMEDELAY(((GET_ERXREG(state_mach) & 0x3f) == 0), HMEMAXRSTDELAY);
17360219346bSGarrett D'Amore
17370219346bSGarrett D'Amore /*
17380219346bSGarrett D'Amore * By this time all things should be quiet, so hit the
17390219346bSGarrett D'Amore * chip with a reset.
17400219346bSGarrett D'Amore */
17410219346bSGarrett D'Amore PUT_GLOBREG(reset, HMEG_RESET_GLOBAL);
17420219346bSGarrett D'Amore
17430219346bSGarrett D'Amore HMEDELAY((GET_GLOBREG(reset) == 0), HMEMAXRSTDELAY);
17440219346bSGarrett D'Amore if (GET_GLOBREG(reset)) {
17450219346bSGarrett D'Amore return (1);
17460219346bSGarrett D'Amore }
17470219346bSGarrett D'Amore
17480219346bSGarrett D'Amore CHECK_GLOBREG();
17490219346bSGarrett D'Amore return (0);
17500219346bSGarrett D'Amore }
17510219346bSGarrett D'Amore
17520219346bSGarrett D'Amore static int
hmestat_kstat_update(kstat_t * ksp,int rw)17530219346bSGarrett D'Amore hmestat_kstat_update(kstat_t *ksp, int rw)
17540219346bSGarrett D'Amore {
17550219346bSGarrett D'Amore struct hme *hmep;
17560219346bSGarrett D'Amore struct hmekstat *hkp;
17570219346bSGarrett D'Amore
17580219346bSGarrett D'Amore hmep = (struct hme *)ksp->ks_private;
17590219346bSGarrett D'Amore hkp = (struct hmekstat *)ksp->ks_data;
17600219346bSGarrett D'Amore
17610219346bSGarrett D'Amore if (rw != KSTAT_READ)
17620219346bSGarrett D'Amore return (EACCES);
17630219346bSGarrett D'Amore
17640219346bSGarrett D'Amore /*
17650219346bSGarrett D'Amore * Update all the stats by reading all the counter registers.
17660219346bSGarrett D'Amore * Counter register stats are not updated till they overflow
17670219346bSGarrett D'Amore * and interrupt.
17680219346bSGarrett D'Amore */
17690219346bSGarrett D'Amore
17700219346bSGarrett D'Amore mutex_enter(&hmep->hme_xmitlock);
17710219346bSGarrett D'Amore if (hmep->hme_flags & HMERUNNING) {
17720219346bSGarrett D'Amore hmereclaim(hmep);
17730219346bSGarrett D'Amore hmesavecntrs(hmep);
17740219346bSGarrett D'Amore }
17750219346bSGarrett D'Amore mutex_exit(&hmep->hme_xmitlock);
17760219346bSGarrett D'Amore
17770219346bSGarrett D'Amore hkp->hk_cvc.value.ul = hmep->hme_cvc;
17780219346bSGarrett D'Amore hkp->hk_lenerr.value.ul = hmep->hme_lenerr;
17790219346bSGarrett D'Amore hkp->hk_buff.value.ul = hmep->hme_buff;
17800219346bSGarrett D'Amore hkp->hk_missed.value.ul = hmep->hme_missed;
17810219346bSGarrett D'Amore hkp->hk_allocbfail.value.ul = hmep->hme_allocbfail;
17820219346bSGarrett D'Amore hkp->hk_babl.value.ul = hmep->hme_babl;
17830219346bSGarrett D'Amore hkp->hk_tmder.value.ul = hmep->hme_tmder;
17840219346bSGarrett D'Amore hkp->hk_txlaterr.value.ul = hmep->hme_txlaterr;
17850219346bSGarrett D'Amore hkp->hk_rxlaterr.value.ul = hmep->hme_rxlaterr;
17860219346bSGarrett D'Amore hkp->hk_slvparerr.value.ul = hmep->hme_slvparerr;
17870219346bSGarrett D'Amore hkp->hk_txparerr.value.ul = hmep->hme_txparerr;
17880219346bSGarrett D'Amore hkp->hk_rxparerr.value.ul = hmep->hme_rxparerr;
17890219346bSGarrett D'Amore hkp->hk_slverrack.value.ul = hmep->hme_slverrack;
17900219346bSGarrett D'Amore hkp->hk_txerrack.value.ul = hmep->hme_txerrack;
17910219346bSGarrett D'Amore hkp->hk_rxerrack.value.ul = hmep->hme_rxerrack;
17920219346bSGarrett D'Amore hkp->hk_txtagerr.value.ul = hmep->hme_txtagerr;
17930219346bSGarrett D'Amore hkp->hk_rxtagerr.value.ul = hmep->hme_rxtagerr;
17940219346bSGarrett D'Amore hkp->hk_eoperr.value.ul = hmep->hme_eoperr;
17950219346bSGarrett D'Amore hkp->hk_notmds.value.ul = hmep->hme_notmds;
17960219346bSGarrett D'Amore hkp->hk_notbufs.value.ul = hmep->hme_notbufs;
17970219346bSGarrett D'Amore hkp->hk_norbufs.value.ul = hmep->hme_norbufs;
17980219346bSGarrett D'Amore
17990219346bSGarrett D'Amore /*
18000219346bSGarrett D'Amore * Debug kstats
18010219346bSGarrett D'Amore */
18020219346bSGarrett D'Amore hkp->hk_inits.value.ul = hmep->inits;
18030219346bSGarrett D'Amore hkp->hk_phyfail.value.ul = hmep->phyfail;
18040219346bSGarrett D'Amore
18050219346bSGarrett D'Amore /*
18060219346bSGarrett D'Amore * xcvr kstats
18070219346bSGarrett D'Amore */
18080219346bSGarrett D'Amore hkp->hk_asic_rev.value.ul = hmep->asic_rev;
18090219346bSGarrett D'Amore
18100219346bSGarrett D'Amore return (0);
18110219346bSGarrett D'Amore }
18120219346bSGarrett D'Amore
18130219346bSGarrett D'Amore static void
hmestatinit(struct hme * hmep)18140219346bSGarrett D'Amore hmestatinit(struct hme *hmep)
18150219346bSGarrett D'Amore {
18160219346bSGarrett D'Amore struct kstat *ksp;
18170219346bSGarrett D'Amore struct hmekstat *hkp;
18180219346bSGarrett D'Amore const char *driver;
18190219346bSGarrett D'Amore int instance;
18200219346bSGarrett D'Amore char buf[16];
18210219346bSGarrett D'Amore
18220219346bSGarrett D'Amore instance = hmep->instance;
18230219346bSGarrett D'Amore driver = ddi_driver_name(hmep->dip);
18240219346bSGarrett D'Amore
18250219346bSGarrett D'Amore if ((ksp = kstat_create(driver, instance,
18260219346bSGarrett D'Amore "driver_info", "net", KSTAT_TYPE_NAMED,
18270219346bSGarrett D'Amore sizeof (struct hmekstat) / sizeof (kstat_named_t), 0)) == NULL) {
18280219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, INIT_MSG,
18290219346bSGarrett D'Amore "kstat_create failed");
18300219346bSGarrett D'Amore return;
18310219346bSGarrett D'Amore }
18320219346bSGarrett D'Amore
18330219346bSGarrett D'Amore (void) snprintf(buf, sizeof (buf), "%sc%d", driver, instance);
18340219346bSGarrett D'Amore hmep->hme_intrstats = kstat_create(driver, instance, buf, "controller",
18350219346bSGarrett D'Amore KSTAT_TYPE_INTR, 1, KSTAT_FLAG_PERSISTENT);
18360219346bSGarrett D'Amore if (hmep->hme_intrstats)
18370219346bSGarrett D'Amore kstat_install(hmep->hme_intrstats);
18380219346bSGarrett D'Amore
18390219346bSGarrett D'Amore hmep->hme_ksp = ksp;
18400219346bSGarrett D'Amore hkp = (struct hmekstat *)ksp->ks_data;
18410219346bSGarrett D'Amore kstat_named_init(&hkp->hk_cvc, "code_violations",
18420219346bSGarrett D'Amore KSTAT_DATA_ULONG);
18430219346bSGarrett D'Amore kstat_named_init(&hkp->hk_lenerr, "len_errors",
18440219346bSGarrett D'Amore KSTAT_DATA_ULONG);
18450219346bSGarrett D'Amore kstat_named_init(&hkp->hk_buff, "buff",
18460219346bSGarrett D'Amore KSTAT_DATA_ULONG);
18470219346bSGarrett D'Amore kstat_named_init(&hkp->hk_missed, "missed",
18480219346bSGarrett D'Amore KSTAT_DATA_ULONG);
18490219346bSGarrett D'Amore kstat_named_init(&hkp->hk_nocanput, "nocanput",
18500219346bSGarrett D'Amore KSTAT_DATA_ULONG);
18510219346bSGarrett D'Amore kstat_named_init(&hkp->hk_allocbfail, "allocbfail",
18520219346bSGarrett D'Amore KSTAT_DATA_ULONG);
18530219346bSGarrett D'Amore kstat_named_init(&hkp->hk_babl, "babble",
18540219346bSGarrett D'Amore KSTAT_DATA_ULONG);
18550219346bSGarrett D'Amore kstat_named_init(&hkp->hk_tmder, "tmd_error",
18560219346bSGarrett D'Amore KSTAT_DATA_ULONG);
18570219346bSGarrett D'Amore kstat_named_init(&hkp->hk_txlaterr, "tx_late_error",
18580219346bSGarrett D'Amore KSTAT_DATA_ULONG);
18590219346bSGarrett D'Amore kstat_named_init(&hkp->hk_rxlaterr, "rx_late_error",
18600219346bSGarrett D'Amore KSTAT_DATA_ULONG);
18610219346bSGarrett D'Amore kstat_named_init(&hkp->hk_slvparerr, "slv_parity_error",
18620219346bSGarrett D'Amore KSTAT_DATA_ULONG);
18630219346bSGarrett D'Amore kstat_named_init(&hkp->hk_txparerr, "tx_parity_error",
18640219346bSGarrett D'Amore KSTAT_DATA_ULONG);
18650219346bSGarrett D'Amore kstat_named_init(&hkp->hk_rxparerr, "rx_parity_error",
18660219346bSGarrett D'Amore KSTAT_DATA_ULONG);
18670219346bSGarrett D'Amore kstat_named_init(&hkp->hk_slverrack, "slv_error_ack",
18680219346bSGarrett D'Amore KSTAT_DATA_ULONG);
18690219346bSGarrett D'Amore kstat_named_init(&hkp->hk_txerrack, "tx_error_ack",
18700219346bSGarrett D'Amore KSTAT_DATA_ULONG);
18710219346bSGarrett D'Amore kstat_named_init(&hkp->hk_rxerrack, "rx_error_ack",
18720219346bSGarrett D'Amore KSTAT_DATA_ULONG);
18730219346bSGarrett D'Amore kstat_named_init(&hkp->hk_txtagerr, "tx_tag_error",
18740219346bSGarrett D'Amore KSTAT_DATA_ULONG);
18750219346bSGarrett D'Amore kstat_named_init(&hkp->hk_rxtagerr, "rx_tag_error",
18760219346bSGarrett D'Amore KSTAT_DATA_ULONG);
18770219346bSGarrett D'Amore kstat_named_init(&hkp->hk_eoperr, "eop_error",
18780219346bSGarrett D'Amore KSTAT_DATA_ULONG);
18790219346bSGarrett D'Amore kstat_named_init(&hkp->hk_notmds, "no_tmds",
18800219346bSGarrett D'Amore KSTAT_DATA_ULONG);
18810219346bSGarrett D'Amore kstat_named_init(&hkp->hk_notbufs, "no_tbufs",
18820219346bSGarrett D'Amore KSTAT_DATA_ULONG);
18830219346bSGarrett D'Amore kstat_named_init(&hkp->hk_norbufs, "no_rbufs",
18840219346bSGarrett D'Amore KSTAT_DATA_ULONG);
18850219346bSGarrett D'Amore
18860219346bSGarrett D'Amore /*
18870219346bSGarrett D'Amore * Debugging kstats
18880219346bSGarrett D'Amore */
18890219346bSGarrett D'Amore kstat_named_init(&hkp->hk_inits, "inits",
18900219346bSGarrett D'Amore KSTAT_DATA_ULONG);
18910219346bSGarrett D'Amore kstat_named_init(&hkp->hk_phyfail, "phy_failures",
18920219346bSGarrett D'Amore KSTAT_DATA_ULONG);
18930219346bSGarrett D'Amore
18940219346bSGarrett D'Amore /*
18950219346bSGarrett D'Amore * xcvr kstats
18960219346bSGarrett D'Amore */
18970219346bSGarrett D'Amore kstat_named_init(&hkp->hk_asic_rev, "asic_rev",
18980219346bSGarrett D'Amore KSTAT_DATA_ULONG);
18990219346bSGarrett D'Amore
19000219346bSGarrett D'Amore ksp->ks_update = hmestat_kstat_update;
19010219346bSGarrett D'Amore ksp->ks_private = (void *) hmep;
19020219346bSGarrett D'Amore kstat_install(ksp);
19030219346bSGarrett D'Amore }
19040219346bSGarrett D'Amore
190506673d9bSGarrett D'Amore int
hme_m_getprop(void * arg,const char * name,mac_prop_id_t num,uint_t sz,void * val)19060dc2366fSVenugopal Iyer hme_m_getprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz,
19070dc2366fSVenugopal Iyer void *val)
19080219346bSGarrett D'Amore {
19090219346bSGarrett D'Amore struct hme *hmep = arg;
191006673d9bSGarrett D'Amore int value;
191106673d9bSGarrett D'Amore int rv;
19120219346bSGarrett D'Amore
19130dc2366fSVenugopal Iyer rv = mii_m_getprop(hmep->hme_mii, name, num, sz, val);
191406673d9bSGarrett D'Amore if (rv != ENOTSUP)
191506673d9bSGarrett D'Amore return (rv);
19160219346bSGarrett D'Amore
191706673d9bSGarrett D'Amore switch (num) {
191806673d9bSGarrett D'Amore case MAC_PROP_PRIVATE:
19190219346bSGarrett D'Amore break;
19200219346bSGarrett D'Amore default:
192106673d9bSGarrett D'Amore return (ENOTSUP);
192206673d9bSGarrett D'Amore }
192306673d9bSGarrett D'Amore
192406673d9bSGarrett D'Amore if (strcmp(name, "_ipg0") == 0) {
19250dc2366fSVenugopal Iyer value = hmep->hme_ipg0;
192606673d9bSGarrett D'Amore } else if (strcmp(name, "_ipg1") == 0) {
19270dc2366fSVenugopal Iyer value = hmep->hme_ipg1;
192806673d9bSGarrett D'Amore } else if (strcmp(name, "_ipg2") == 0) {
19290dc2366fSVenugopal Iyer value = hmep->hme_ipg2;
193006673d9bSGarrett D'Amore } else if (strcmp(name, "_lance_mode") == 0) {
19310dc2366fSVenugopal Iyer value = hmep->hme_lance_mode;
193206673d9bSGarrett D'Amore } else {
193306673d9bSGarrett D'Amore return (ENOTSUP);
193406673d9bSGarrett D'Amore }
193506673d9bSGarrett D'Amore (void) snprintf(val, sz, "%d", value);
193606673d9bSGarrett D'Amore return (0);
193706673d9bSGarrett D'Amore }
193806673d9bSGarrett D'Amore
19390dc2366fSVenugopal Iyer static void
hme_m_propinfo(void * arg,const char * name,mac_prop_id_t num,mac_prop_info_handle_t mph)19400dc2366fSVenugopal Iyer hme_m_propinfo(void *arg, const char *name, mac_prop_id_t num,
19410dc2366fSVenugopal Iyer mac_prop_info_handle_t mph)
19420dc2366fSVenugopal Iyer {
19430dc2366fSVenugopal Iyer struct hme *hmep = arg;
19440dc2366fSVenugopal Iyer
19450dc2366fSVenugopal Iyer mii_m_propinfo(hmep->hme_mii, name, num, mph);
19460dc2366fSVenugopal Iyer
19470dc2366fSVenugopal Iyer switch (num) {
19480dc2366fSVenugopal Iyer case MAC_PROP_PRIVATE: {
19490dc2366fSVenugopal Iyer char valstr[64];
19500dc2366fSVenugopal Iyer int default_val;
19510dc2366fSVenugopal Iyer
19520dc2366fSVenugopal Iyer if (strcmp(name, "_ipg0") == 0) {
19530dc2366fSVenugopal Iyer default_val = hme_ipg0;
19540dc2366fSVenugopal Iyer } else if (strcmp(name, "_ipg1") == 0) {
19550dc2366fSVenugopal Iyer default_val = hme_ipg1;
19560dc2366fSVenugopal Iyer } else if (strcmp(name, "_ipg2") == 0) {
19570dc2366fSVenugopal Iyer default_val = hme_ipg2;
19580dc2366fSVenugopal Iyer } if (strcmp(name, "_lance_mode") == 0) {
19590dc2366fSVenugopal Iyer default_val = hme_lance_mode;
19600dc2366fSVenugopal Iyer } else {
19610dc2366fSVenugopal Iyer return;
19620dc2366fSVenugopal Iyer }
19630dc2366fSVenugopal Iyer
19640dc2366fSVenugopal Iyer (void) snprintf(valstr, sizeof (valstr), "%d", default_val);
19650dc2366fSVenugopal Iyer mac_prop_info_set_default_str(mph, valstr);
19660dc2366fSVenugopal Iyer break;
19670dc2366fSVenugopal Iyer }
19680dc2366fSVenugopal Iyer }
19690dc2366fSVenugopal Iyer }
19700dc2366fSVenugopal Iyer
197106673d9bSGarrett D'Amore int
hme_m_setprop(void * arg,const char * name,mac_prop_id_t num,uint_t sz,const void * val)197206673d9bSGarrett D'Amore hme_m_setprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz,
197306673d9bSGarrett D'Amore const void *val)
197406673d9bSGarrett D'Amore {
197506673d9bSGarrett D'Amore struct hme *hmep = arg;
197606673d9bSGarrett D'Amore int rv;
197706673d9bSGarrett D'Amore long lval;
197806673d9bSGarrett D'Amore boolean_t init = B_FALSE;
197906673d9bSGarrett D'Amore
198006673d9bSGarrett D'Amore rv = mii_m_setprop(hmep->hme_mii, name, num, sz, val);
198106673d9bSGarrett D'Amore if (rv != ENOTSUP)
198206673d9bSGarrett D'Amore return (rv);
198306673d9bSGarrett D'Amore rv = 0;
198406673d9bSGarrett D'Amore
198506673d9bSGarrett D'Amore switch (num) {
198606673d9bSGarrett D'Amore case MAC_PROP_PRIVATE:
19870219346bSGarrett D'Amore break;
198806673d9bSGarrett D'Amore default:
198906673d9bSGarrett D'Amore return (ENOTSUP);
19900219346bSGarrett D'Amore }
199106673d9bSGarrett D'Amore
199206673d9bSGarrett D'Amore (void) ddi_strtol(val, NULL, 0, &lval);
199306673d9bSGarrett D'Amore
199406673d9bSGarrett D'Amore if (strcmp(name, "_ipg1") == 0) {
199506673d9bSGarrett D'Amore if ((lval >= 0) && (lval <= 255)) {
199606673d9bSGarrett D'Amore hmep->hme_ipg1 = lval & 0xff;
199706673d9bSGarrett D'Amore init = B_TRUE;
199806673d9bSGarrett D'Amore } else {
199906673d9bSGarrett D'Amore return (EINVAL);
20000219346bSGarrett D'Amore }
20010219346bSGarrett D'Amore
200206673d9bSGarrett D'Amore } else if (strcmp(name, "_ipg2") == 0) {
200306673d9bSGarrett D'Amore if ((lval >= 0) && (lval <= 255)) {
200406673d9bSGarrett D'Amore hmep->hme_ipg2 = lval & 0xff;
200506673d9bSGarrett D'Amore init = B_TRUE;
200606673d9bSGarrett D'Amore } else {
200706673d9bSGarrett D'Amore return (EINVAL);
200806673d9bSGarrett D'Amore }
200906673d9bSGarrett D'Amore
201006673d9bSGarrett D'Amore } else if (strcmp(name, "_ipg0") == 0) {
201106673d9bSGarrett D'Amore if ((lval >= 0) && (lval <= 31)) {
201206673d9bSGarrett D'Amore hmep->hme_ipg0 = lval & 0xff;
201306673d9bSGarrett D'Amore init = B_TRUE;
201406673d9bSGarrett D'Amore } else {
201506673d9bSGarrett D'Amore return (EINVAL);
201606673d9bSGarrett D'Amore }
201706673d9bSGarrett D'Amore } else if (strcmp(name, "_lance_mode") == 0) {
201806673d9bSGarrett D'Amore if ((lval >= 0) && (lval <= 1)) {
201906673d9bSGarrett D'Amore hmep->hme_lance_mode = lval & 0xff;
202006673d9bSGarrett D'Amore init = B_TRUE;
202106673d9bSGarrett D'Amore } else {
202206673d9bSGarrett D'Amore return (EINVAL);
202306673d9bSGarrett D'Amore }
202406673d9bSGarrett D'Amore
202506673d9bSGarrett D'Amore } else {
202606673d9bSGarrett D'Amore rv = ENOTSUP;
202706673d9bSGarrett D'Amore }
202806673d9bSGarrett D'Amore
202906673d9bSGarrett D'Amore if (init) {
203006673d9bSGarrett D'Amore (void) hmeinit(hmep);
203106673d9bSGarrett D'Amore }
203206673d9bSGarrett D'Amore return (rv);
203306673d9bSGarrett D'Amore }
203406673d9bSGarrett D'Amore
203506673d9bSGarrett D'Amore
20360219346bSGarrett D'Amore /*ARGSUSED*/
20370219346bSGarrett D'Amore static boolean_t
hme_m_getcapab(void * arg,mac_capab_t cap,void * cap_data)20380219346bSGarrett D'Amore hme_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
20390219346bSGarrett D'Amore {
20400219346bSGarrett D'Amore switch (cap) {
20410219346bSGarrett D'Amore case MAC_CAPAB_HCKSUM:
20420219346bSGarrett D'Amore *(uint32_t *)cap_data = HCKSUM_INET_PARTIAL;
20430219346bSGarrett D'Amore return (B_TRUE);
20440219346bSGarrett D'Amore default:
20450219346bSGarrett D'Amore return (B_FALSE);
20460219346bSGarrett D'Amore }
20470219346bSGarrett D'Amore }
20480219346bSGarrett D'Amore
20490219346bSGarrett D'Amore static int
hme_m_promisc(void * arg,boolean_t on)20500219346bSGarrett D'Amore hme_m_promisc(void *arg, boolean_t on)
20510219346bSGarrett D'Amore {
20520219346bSGarrett D'Amore struct hme *hmep = arg;
20530219346bSGarrett D'Amore
20540219346bSGarrett D'Amore hmep->hme_promisc = on;
20550219346bSGarrett D'Amore (void) hmeinit(hmep);
20560219346bSGarrett D'Amore return (0);
20570219346bSGarrett D'Amore }
20580219346bSGarrett D'Amore
20590219346bSGarrett D'Amore static int
hme_m_unicst(void * arg,const uint8_t * macaddr)20600219346bSGarrett D'Amore hme_m_unicst(void *arg, const uint8_t *macaddr)
20610219346bSGarrett D'Amore {
20620219346bSGarrett D'Amore struct hme *hmep = arg;
20630219346bSGarrett D'Amore
20640219346bSGarrett D'Amore /*
20650219346bSGarrett D'Amore * Set new interface local address and re-init device.
20660219346bSGarrett D'Amore * This is destructive to any other streams attached
20670219346bSGarrett D'Amore * to this device.
20680219346bSGarrett D'Amore */
20690219346bSGarrett D'Amore mutex_enter(&hmep->hme_intrlock);
20700219346bSGarrett D'Amore bcopy(macaddr, &hmep->hme_ouraddr, ETHERADDRL);
20710219346bSGarrett D'Amore mutex_exit(&hmep->hme_intrlock);
20720219346bSGarrett D'Amore (void) hmeinit(hmep);
20730219346bSGarrett D'Amore return (0);
20740219346bSGarrett D'Amore }
20750219346bSGarrett D'Amore
20760219346bSGarrett D'Amore static int
hme_m_multicst(void * arg,boolean_t add,const uint8_t * macaddr)20770219346bSGarrett D'Amore hme_m_multicst(void *arg, boolean_t add, const uint8_t *macaddr)
20780219346bSGarrett D'Amore {
20790219346bSGarrett D'Amore struct hme *hmep = arg;
20800219346bSGarrett D'Amore uint32_t ladrf_bit;
20810219346bSGarrett D'Amore boolean_t doinit = B_FALSE;
20820219346bSGarrett D'Amore
20830219346bSGarrett D'Amore /*
20840219346bSGarrett D'Amore * If this address's bit was not already set in the local address
20850219346bSGarrett D'Amore * filter, add it and re-initialize the Hardware.
20860219346bSGarrett D'Amore */
20870219346bSGarrett D'Amore ladrf_bit = hmeladrf_bit(macaddr);
20880219346bSGarrett D'Amore
20890219346bSGarrett D'Amore mutex_enter(&hmep->hme_intrlock);
20900219346bSGarrett D'Amore if (add) {
20910219346bSGarrett D'Amore hmep->hme_ladrf_refcnt[ladrf_bit]++;
20920219346bSGarrett D'Amore if (hmep->hme_ladrf_refcnt[ladrf_bit] == 1) {
20930219346bSGarrett D'Amore hmep->hme_ladrf[ladrf_bit >> 4] |=
20940219346bSGarrett D'Amore 1 << (ladrf_bit & 0xf);
20950219346bSGarrett D'Amore hmep->hme_multi++;
20960219346bSGarrett D'Amore doinit = B_TRUE;
20970219346bSGarrett D'Amore }
20980219346bSGarrett D'Amore } else {
20990219346bSGarrett D'Amore hmep->hme_ladrf_refcnt[ladrf_bit]--;
21000219346bSGarrett D'Amore if (hmep->hme_ladrf_refcnt[ladrf_bit] == 0) {
21010219346bSGarrett D'Amore hmep->hme_ladrf[ladrf_bit >> 4] &=
21020219346bSGarrett D'Amore ~(1 << (ladrf_bit & 0xf));
21030219346bSGarrett D'Amore doinit = B_TRUE;
21040219346bSGarrett D'Amore }
21050219346bSGarrett D'Amore }
21060219346bSGarrett D'Amore mutex_exit(&hmep->hme_intrlock);
21070219346bSGarrett D'Amore
21080219346bSGarrett D'Amore if (doinit) {
21090219346bSGarrett D'Amore (void) hmeinit(hmep);
21100219346bSGarrett D'Amore }
21110219346bSGarrett D'Amore
21120219346bSGarrett D'Amore return (0);
21130219346bSGarrett D'Amore }
21140219346bSGarrett D'Amore
21150219346bSGarrett D'Amore static int
hme_m_start(void * arg)21160219346bSGarrett D'Amore hme_m_start(void *arg)
21170219346bSGarrett D'Amore {
21180219346bSGarrett D'Amore struct hme *hmep = arg;
21190219346bSGarrett D'Amore
21200219346bSGarrett D'Amore if (hmeinit(hmep) != 0) {
21210219346bSGarrett D'Amore /* initialization failed -- really want DL_INITFAILED */
21220219346bSGarrett D'Amore return (EIO);
21230219346bSGarrett D'Amore } else {
21240219346bSGarrett D'Amore hmep->hme_started = B_TRUE;
212506673d9bSGarrett D'Amore mii_start(hmep->hme_mii);
21260219346bSGarrett D'Amore return (0);
21270219346bSGarrett D'Amore }
21280219346bSGarrett D'Amore }
21290219346bSGarrett D'Amore
21300219346bSGarrett D'Amore static void
hme_m_stop(void * arg)21310219346bSGarrett D'Amore hme_m_stop(void *arg)
21320219346bSGarrett D'Amore {
21330219346bSGarrett D'Amore struct hme *hmep = arg;
21340219346bSGarrett D'Amore
213506673d9bSGarrett D'Amore mii_stop(hmep->hme_mii);
21360219346bSGarrett D'Amore hmep->hme_started = B_FALSE;
21370219346bSGarrett D'Amore hmeuninit(hmep);
21380219346bSGarrett D'Amore }
21390219346bSGarrett D'Amore
21400219346bSGarrett D'Amore static int
hme_m_stat(void * arg,uint_t stat,uint64_t * val)21410219346bSGarrett D'Amore hme_m_stat(void *arg, uint_t stat, uint64_t *val)
21420219346bSGarrett D'Amore {
21430219346bSGarrett D'Amore struct hme *hmep = arg;
21440219346bSGarrett D'Amore
21450219346bSGarrett D'Amore mutex_enter(&hmep->hme_xmitlock);
21460219346bSGarrett D'Amore if (hmep->hme_flags & HMERUNNING) {
21470219346bSGarrett D'Amore hmereclaim(hmep);
21480219346bSGarrett D'Amore hmesavecntrs(hmep);
21490219346bSGarrett D'Amore }
21500219346bSGarrett D'Amore mutex_exit(&hmep->hme_xmitlock);
21510219346bSGarrett D'Amore
21520219346bSGarrett D'Amore
215306673d9bSGarrett D'Amore if (mii_m_getstat(hmep->hme_mii, stat, val) == 0) {
215406673d9bSGarrett D'Amore return (0);
215506673d9bSGarrett D'Amore }
21560219346bSGarrett D'Amore switch (stat) {
21570219346bSGarrett D'Amore case MAC_STAT_IPACKETS:
21580219346bSGarrett D'Amore *val = hmep->hme_ipackets;
21590219346bSGarrett D'Amore break;
21600219346bSGarrett D'Amore case MAC_STAT_RBYTES:
21610219346bSGarrett D'Amore *val = hmep->hme_rbytes;
21620219346bSGarrett D'Amore break;
21630219346bSGarrett D'Amore case MAC_STAT_IERRORS:
21640219346bSGarrett D'Amore *val = hmep->hme_ierrors;
21650219346bSGarrett D'Amore break;
21660219346bSGarrett D'Amore case MAC_STAT_OPACKETS:
21670219346bSGarrett D'Amore *val = hmep->hme_opackets;
21680219346bSGarrett D'Amore break;
21690219346bSGarrett D'Amore case MAC_STAT_OBYTES:
21700219346bSGarrett D'Amore *val = hmep->hme_obytes;
21710219346bSGarrett D'Amore break;
21720219346bSGarrett D'Amore case MAC_STAT_OERRORS:
21730219346bSGarrett D'Amore *val = hmep->hme_oerrors;
21740219346bSGarrett D'Amore break;
21750219346bSGarrett D'Amore case MAC_STAT_MULTIRCV:
21760219346bSGarrett D'Amore *val = hmep->hme_multircv;
21770219346bSGarrett D'Amore break;
21780219346bSGarrett D'Amore case MAC_STAT_MULTIXMT:
21790219346bSGarrett D'Amore *val = hmep->hme_multixmt;
21800219346bSGarrett D'Amore break;
21810219346bSGarrett D'Amore case MAC_STAT_BRDCSTRCV:
21820219346bSGarrett D'Amore *val = hmep->hme_brdcstrcv;
21830219346bSGarrett D'Amore break;
21840219346bSGarrett D'Amore case MAC_STAT_BRDCSTXMT:
21850219346bSGarrett D'Amore *val = hmep->hme_brdcstxmt;
21860219346bSGarrett D'Amore break;
21870219346bSGarrett D'Amore case MAC_STAT_UNDERFLOWS:
21880219346bSGarrett D'Amore *val = hmep->hme_uflo;
21890219346bSGarrett D'Amore break;
21900219346bSGarrett D'Amore case MAC_STAT_OVERFLOWS:
21910219346bSGarrett D'Amore *val = hmep->hme_oflo;
21920219346bSGarrett D'Amore break;
21930219346bSGarrett D'Amore case MAC_STAT_COLLISIONS:
21940219346bSGarrett D'Amore *val = hmep->hme_coll;
21950219346bSGarrett D'Amore break;
21960219346bSGarrett D'Amore case MAC_STAT_NORCVBUF:
21970219346bSGarrett D'Amore *val = hmep->hme_norcvbuf;
21980219346bSGarrett D'Amore break;
21990219346bSGarrett D'Amore case MAC_STAT_NOXMTBUF:
22000219346bSGarrett D'Amore *val = hmep->hme_noxmtbuf;
22010219346bSGarrett D'Amore break;
22020219346bSGarrett D'Amore case ETHER_STAT_LINK_DUPLEX:
22030219346bSGarrett D'Amore *val = hmep->hme_duplex;
22040219346bSGarrett D'Amore break;
22050219346bSGarrett D'Amore case ETHER_STAT_ALIGN_ERRORS:
22060219346bSGarrett D'Amore *val = hmep->hme_align_errors;
22070219346bSGarrett D'Amore break;
22080219346bSGarrett D'Amore case ETHER_STAT_FCS_ERRORS:
22090219346bSGarrett D'Amore *val = hmep->hme_fcs_errors;
22100219346bSGarrett D'Amore break;
22110219346bSGarrett D'Amore case ETHER_STAT_EX_COLLISIONS:
22120219346bSGarrett D'Amore *val = hmep->hme_excol;
22130219346bSGarrett D'Amore break;
22140219346bSGarrett D'Amore case ETHER_STAT_DEFER_XMTS:
22150219346bSGarrett D'Amore *val = hmep->hme_defer_xmts;
22160219346bSGarrett D'Amore break;
22170219346bSGarrett D'Amore case ETHER_STAT_SQE_ERRORS:
22180219346bSGarrett D'Amore *val = hmep->hme_sqe_errors;
22190219346bSGarrett D'Amore break;
22200219346bSGarrett D'Amore case ETHER_STAT_FIRST_COLLISIONS:
22210219346bSGarrett D'Amore *val = hmep->hme_fstcol;
22220219346bSGarrett D'Amore break;
22230219346bSGarrett D'Amore case ETHER_STAT_TX_LATE_COLLISIONS:
22240219346bSGarrett D'Amore *val = hmep->hme_tlcol;
22250219346bSGarrett D'Amore break;
22260219346bSGarrett D'Amore case ETHER_STAT_TOOLONG_ERRORS:
22270219346bSGarrett D'Amore *val = hmep->hme_toolong_errors;
22280219346bSGarrett D'Amore break;
22290219346bSGarrett D'Amore case ETHER_STAT_TOOSHORT_ERRORS:
22300219346bSGarrett D'Amore *val = hmep->hme_runt;
22310219346bSGarrett D'Amore break;
22320219346bSGarrett D'Amore case ETHER_STAT_CARRIER_ERRORS:
22330219346bSGarrett D'Amore *val = hmep->hme_carrier_errors;
22340219346bSGarrett D'Amore break;
22350219346bSGarrett D'Amore default:
22360219346bSGarrett D'Amore return (EINVAL);
22370219346bSGarrett D'Amore }
22380219346bSGarrett D'Amore return (0);
22390219346bSGarrett D'Amore }
22400219346bSGarrett D'Amore
22410219346bSGarrett D'Amore static mblk_t *
hme_m_tx(void * arg,mblk_t * mp)22420219346bSGarrett D'Amore hme_m_tx(void *arg, mblk_t *mp)
22430219346bSGarrett D'Amore {
22440219346bSGarrett D'Amore struct hme *hmep = arg;
22450219346bSGarrett D'Amore mblk_t *next;
22460219346bSGarrett D'Amore
22470219346bSGarrett D'Amore while (mp != NULL) {
22480219346bSGarrett D'Amore next = mp->b_next;
22490219346bSGarrett D'Amore mp->b_next = NULL;
22500219346bSGarrett D'Amore if (!hmestart(hmep, mp)) {
22510219346bSGarrett D'Amore mp->b_next = next;
22520219346bSGarrett D'Amore break;
22530219346bSGarrett D'Amore }
22540219346bSGarrett D'Amore mp = next;
22550219346bSGarrett D'Amore }
22560219346bSGarrett D'Amore return (mp);
22570219346bSGarrett D'Amore }
22580219346bSGarrett D'Amore
22590219346bSGarrett D'Amore /*
22600219346bSGarrett D'Amore * Software IP checksum, for the edge cases that the
22610219346bSGarrett D'Amore * hardware can't handle. See hmestart for more info.
22620219346bSGarrett D'Amore */
22630219346bSGarrett D'Amore static uint16_t
hme_cksum(void * data,int len)22640219346bSGarrett D'Amore hme_cksum(void *data, int len)
22650219346bSGarrett D'Amore {
22660219346bSGarrett D'Amore uint16_t *words = data;
22670219346bSGarrett D'Amore int i, nwords = len / 2;
22680219346bSGarrett D'Amore uint32_t sum = 0;
22690219346bSGarrett D'Amore
22700219346bSGarrett D'Amore /* just add up the words */
22710219346bSGarrett D'Amore for (i = 0; i < nwords; i++) {
22720219346bSGarrett D'Amore sum += *words++;
22730219346bSGarrett D'Amore }
22740219346bSGarrett D'Amore
22750219346bSGarrett D'Amore /* pick up residual byte ... assume even half-word allocations */
22760219346bSGarrett D'Amore if (len % 2) {
22770219346bSGarrett D'Amore sum += (*words & htons(0xff00));
22780219346bSGarrett D'Amore }
22790219346bSGarrett D'Amore
22800219346bSGarrett D'Amore sum = (sum >> 16) + (sum & 0xffff);
22810219346bSGarrett D'Amore sum = (sum >> 16) + (sum & 0xffff);
22820219346bSGarrett D'Amore
22830219346bSGarrett D'Amore return (~(sum & 0xffff));
22840219346bSGarrett D'Amore }
22850219346bSGarrett D'Amore
22860219346bSGarrett D'Amore static boolean_t
hmestart(struct hme * hmep,mblk_t * mp)22870219346bSGarrett D'Amore hmestart(struct hme *hmep, mblk_t *mp)
22880219346bSGarrett D'Amore {
22890219346bSGarrett D'Amore uint32_t len;
22900219346bSGarrett D'Amore boolean_t retval = B_TRUE;
22910219346bSGarrett D'Amore hmebuf_t *tbuf;
22920219346bSGarrett D'Amore uint32_t txptr;
22930219346bSGarrett D'Amore
22940219346bSGarrett D'Amore uint32_t csflags = 0;
22950219346bSGarrett D'Amore uint32_t flags;
22960219346bSGarrett D'Amore uint32_t start_offset;
22970219346bSGarrett D'Amore uint32_t stuff_offset;
22980219346bSGarrett D'Amore
22990dc2366fSVenugopal Iyer mac_hcksum_get(mp, &start_offset, &stuff_offset, NULL, NULL, &flags);
23000219346bSGarrett D'Amore
23010219346bSGarrett D'Amore if (flags & HCK_PARTIALCKSUM) {
23020219346bSGarrett D'Amore if (get_ether_type(mp->b_rptr) == ETHERTYPE_VLAN) {
23030219346bSGarrett D'Amore start_offset += sizeof (struct ether_header) + 4;
23040219346bSGarrett D'Amore stuff_offset += sizeof (struct ether_header) + 4;
23050219346bSGarrett D'Amore } else {
23060219346bSGarrett D'Amore start_offset += sizeof (struct ether_header);
23070219346bSGarrett D'Amore stuff_offset += sizeof (struct ether_header);
23080219346bSGarrett D'Amore }
23090219346bSGarrett D'Amore csflags = HMETMD_CSENABL |
23100219346bSGarrett D'Amore (start_offset << HMETMD_CSSTART_SHIFT) |
23110219346bSGarrett D'Amore (stuff_offset << HMETMD_CSSTUFF_SHIFT);
23120219346bSGarrett D'Amore }
23130219346bSGarrett D'Amore
23140219346bSGarrett D'Amore mutex_enter(&hmep->hme_xmitlock);
23150219346bSGarrett D'Amore
23160219346bSGarrett D'Amore if (hmep->hme_flags & HMESUSPENDED) {
23170219346bSGarrett D'Amore hmep->hme_carrier_errors++;
23180219346bSGarrett D'Amore hmep->hme_oerrors++;
23190219346bSGarrett D'Amore goto bad;
23200219346bSGarrett D'Amore }
23210219346bSGarrett D'Amore
23220219346bSGarrett D'Amore if (hmep->hme_txindex != hmep->hme_txreclaim) {
23230219346bSGarrett D'Amore hmereclaim(hmep);
23240219346bSGarrett D'Amore }
23250219346bSGarrett D'Amore if ((hmep->hme_txindex - HME_TMDMAX) == hmep->hme_txreclaim)
23260219346bSGarrett D'Amore goto notmds;
23270219346bSGarrett D'Amore txptr = hmep->hme_txindex % HME_TMDMAX;
23280219346bSGarrett D'Amore tbuf = &hmep->hme_tbuf[txptr];
23290219346bSGarrett D'Amore
23300219346bSGarrett D'Amore /*
23310219346bSGarrett D'Amore * Note that for checksum offload, the hardware cannot
23320219346bSGarrett D'Amore * generate correct checksums if the packet is smaller than
23330219346bSGarrett D'Amore * 64-bytes. In such a case, we bcopy the packet and use
23340219346bSGarrett D'Amore * a software checksum.
23350219346bSGarrett D'Amore */
23360219346bSGarrett D'Amore
23370219346bSGarrett D'Amore len = msgsize(mp);
23380219346bSGarrett D'Amore if (len < 64) {
23390219346bSGarrett D'Amore /* zero fill the padding */
23400219346bSGarrett D'Amore bzero(tbuf->kaddr, 64);
23410219346bSGarrett D'Amore }
23420219346bSGarrett D'Amore mcopymsg(mp, tbuf->kaddr);
23430219346bSGarrett D'Amore
2344*7a92e70fSZeeshanul Huq - Sun Microsystems - Beijing China if ((csflags != 0) && ((len < 64) ||
2345*7a92e70fSZeeshanul Huq - Sun Microsystems - Beijing China (start_offset > HMETMD_CSSTART_MAX) ||
2346*7a92e70fSZeeshanul Huq - Sun Microsystems - Beijing China (stuff_offset > HMETMD_CSSTUFF_MAX))) {
23470219346bSGarrett D'Amore uint16_t sum;
23480219346bSGarrett D'Amore sum = hme_cksum(tbuf->kaddr + start_offset,
23490219346bSGarrett D'Amore len - start_offset);
23500219346bSGarrett D'Amore bcopy(&sum, tbuf->kaddr + stuff_offset, sizeof (sum));
23510219346bSGarrett D'Amore csflags = 0;
23520219346bSGarrett D'Amore }
23530219346bSGarrett D'Amore
23540219346bSGarrett D'Amore if (ddi_dma_sync(tbuf->dmah, 0, len, DDI_DMA_SYNC_FORDEV) ==
23550219346bSGarrett D'Amore DDI_FAILURE) {
23560219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, DDI_MSG,
23570219346bSGarrett D'Amore "ddi_dma_sync failed");
23580219346bSGarrett D'Amore }
23590219346bSGarrett D'Amore
23600219346bSGarrett D'Amore /*
23610219346bSGarrett D'Amore * update MIB II statistics
23620219346bSGarrett D'Amore */
23630219346bSGarrett D'Amore BUMP_OutNUcast(hmep, tbuf->kaddr);
23640219346bSGarrett D'Amore
23650219346bSGarrett D'Amore PUT_TMD(txptr, tbuf->paddr, len,
23660219346bSGarrett D'Amore HMETMD_OWN | HMETMD_SOP | HMETMD_EOP | csflags);
23670219346bSGarrett D'Amore
23680219346bSGarrett D'Amore HMESYNCTMD(txptr, DDI_DMA_SYNC_FORDEV);
23690219346bSGarrett D'Amore hmep->hme_txindex++;
23700219346bSGarrett D'Amore
23710219346bSGarrett D'Amore PUT_ETXREG(txpend, HMET_TXPEND_TDMD);
23720219346bSGarrett D'Amore CHECK_ETXREG();
23730219346bSGarrett D'Amore
23740219346bSGarrett D'Amore mutex_exit(&hmep->hme_xmitlock);
23750219346bSGarrett D'Amore
23760219346bSGarrett D'Amore hmep->hme_starts++;
23770219346bSGarrett D'Amore return (B_TRUE);
23780219346bSGarrett D'Amore
23790219346bSGarrett D'Amore bad:
23800219346bSGarrett D'Amore mutex_exit(&hmep->hme_xmitlock);
23810219346bSGarrett D'Amore freemsg(mp);
23820219346bSGarrett D'Amore return (B_TRUE);
23830219346bSGarrett D'Amore
23840219346bSGarrett D'Amore notmds:
23850219346bSGarrett D'Amore hmep->hme_notmds++;
23860219346bSGarrett D'Amore hmep->hme_wantw = B_TRUE;
23870219346bSGarrett D'Amore hmereclaim(hmep);
23880219346bSGarrett D'Amore retval = B_FALSE;
23890219346bSGarrett D'Amore done:
23900219346bSGarrett D'Amore mutex_exit(&hmep->hme_xmitlock);
23910219346bSGarrett D'Amore
23920219346bSGarrett D'Amore return (retval);
23930219346bSGarrett D'Amore }
23940219346bSGarrett D'Amore
23950219346bSGarrett D'Amore /*
23960219346bSGarrett D'Amore * Initialize channel.
23970219346bSGarrett D'Amore * Return 0 on success, nonzero on error.
23980219346bSGarrett D'Amore *
23990219346bSGarrett D'Amore * The recommended sequence for initialization is:
24000219346bSGarrett D'Amore * 1. Issue a Global Reset command to the Ethernet Channel.
24010219346bSGarrett D'Amore * 2. Poll the Global_Reset bits until the execution of the reset has been
24020219346bSGarrett D'Amore * completed.
24030219346bSGarrett D'Amore * 2(a). Use the MIF Frame/Output register to reset the transceiver.
24040219346bSGarrett D'Amore * Poll Register 0 to till the Resetbit is 0.
24050219346bSGarrett D'Amore * 2(b). Use the MIF Frame/Output register to set the PHY in in Normal-Op,
24060219346bSGarrett D'Amore * 100Mbps and Non-Isolated mode. The main point here is to bring the
24070219346bSGarrett D'Amore * PHY out of Isolate mode so that it can generate the rx_clk and tx_clk
24080219346bSGarrett D'Amore * to the MII interface so that the Bigmac core can correctly reset
24090219346bSGarrett D'Amore * upon a software reset.
24100219346bSGarrett D'Amore * 2(c). Issue another Global Reset command to the Ethernet Channel and poll
24110219346bSGarrett D'Amore * the Global_Reset bits till completion.
24120219346bSGarrett D'Amore * 3. Set up all the data structures in the host memory.
24130219346bSGarrett D'Amore * 4. Program the TX_MAC registers/counters (excluding the TX_MAC Configuration
24140219346bSGarrett D'Amore * Register).
24150219346bSGarrett D'Amore * 5. Program the RX_MAC registers/counters (excluding the RX_MAC Configuration
24160219346bSGarrett D'Amore * Register).
24170219346bSGarrett D'Amore * 6. Program the Transmit Descriptor Ring Base Address in the ETX.
24180219346bSGarrett D'Amore * 7. Program the Receive Descriptor Ring Base Address in the ERX.
24190219346bSGarrett D'Amore * 8. Program the Global Configuration and the Global Interrupt Mask Registers.
24200219346bSGarrett D'Amore * 9. Program the ETX Configuration register (enable the Transmit DMA channel).
24210219346bSGarrett D'Amore * 10. Program the ERX Configuration register (enable the Receive DMA channel).
24220219346bSGarrett D'Amore * 11. Program the XIF Configuration Register (enable the XIF).
24230219346bSGarrett D'Amore * 12. Program the RX_MAC Configuration Register (Enable the RX_MAC).
24240219346bSGarrett D'Amore * 13. Program the TX_MAC Configuration Register (Enable the TX_MAC).
24250219346bSGarrett D'Amore */
24260219346bSGarrett D'Amore
24270219346bSGarrett D'Amore
24280219346bSGarrett D'Amore #ifdef FEPS_URUN_BUG
24290219346bSGarrett D'Amore static int hme_palen = 32;
24300219346bSGarrett D'Amore #endif
24310219346bSGarrett D'Amore
24320219346bSGarrett D'Amore static int
hmeinit(struct hme * hmep)24330219346bSGarrett D'Amore hmeinit(struct hme *hmep)
24340219346bSGarrett D'Amore {
24350219346bSGarrett D'Amore uint32_t i;
24360219346bSGarrett D'Amore int ret;
243706673d9bSGarrett D'Amore boolean_t fdx;
243806673d9bSGarrett D'Amore int phyad;
24390219346bSGarrett D'Amore
24400219346bSGarrett D'Amore /*
24410219346bSGarrett D'Amore * Lock sequence:
24420219346bSGarrett D'Amore * hme_intrlock, hme_xmitlock.
24430219346bSGarrett D'Amore */
24440219346bSGarrett D'Amore mutex_enter(&hmep->hme_intrlock);
24450219346bSGarrett D'Amore
24460219346bSGarrett D'Amore /*
24470219346bSGarrett D'Amore * Don't touch the hardware if we are suspended. But don't
24480219346bSGarrett D'Amore * fail either. Some time later we may be resumed, and then
24490219346bSGarrett D'Amore * we'll be back here to program the device using the settings
24500219346bSGarrett D'Amore * in the soft state.
24510219346bSGarrett D'Amore */
24520219346bSGarrett D'Amore if (hmep->hme_flags & HMESUSPENDED) {
24530219346bSGarrett D'Amore mutex_exit(&hmep->hme_intrlock);
24540219346bSGarrett D'Amore return (0);
24550219346bSGarrett D'Amore }
24560219346bSGarrett D'Amore
24570219346bSGarrett D'Amore /*
24580219346bSGarrett D'Amore * This should prevent us from clearing any interrupts that
24590219346bSGarrett D'Amore * may occur by temporarily stopping interrupts from occurring
24600219346bSGarrett D'Amore * for a short time. We need to update the interrupt mask
24610219346bSGarrett D'Amore * later in this function.
24620219346bSGarrett D'Amore */
24630219346bSGarrett D'Amore PUT_GLOBREG(intmask, ~HMEG_MASK_MIF_INTR);
24640219346bSGarrett D'Amore
24650219346bSGarrett D'Amore
24660219346bSGarrett D'Amore /*
24670219346bSGarrett D'Amore * Rearranged the mutex acquisition order to solve the deadlock
24680219346bSGarrett D'Amore * situation as described in bug ID 4065896.
24690219346bSGarrett D'Amore */
24700219346bSGarrett D'Amore
24710219346bSGarrett D'Amore mutex_enter(&hmep->hme_xmitlock);
24720219346bSGarrett D'Amore
24730219346bSGarrett D'Amore hmep->hme_flags = 0;
24740219346bSGarrett D'Amore hmep->hme_wantw = B_FALSE;
24750219346bSGarrett D'Amore
24760219346bSGarrett D'Amore if (hmep->inits)
24770219346bSGarrett D'Amore hmesavecntrs(hmep);
24780219346bSGarrett D'Amore
24790219346bSGarrett D'Amore /*
24800219346bSGarrett D'Amore * Perform Global reset of the Sbus/FEPS ENET channel.
24810219346bSGarrett D'Amore */
24820219346bSGarrett D'Amore (void) hmestop(hmep);
24830219346bSGarrett D'Amore
24840219346bSGarrett D'Amore /*
24850219346bSGarrett D'Amore * Clear all descriptors.
24860219346bSGarrett D'Amore */
24870219346bSGarrett D'Amore bzero(hmep->hme_rmdp, HME_RMDMAX * sizeof (struct hme_rmd));
24880219346bSGarrett D'Amore bzero(hmep->hme_tmdp, HME_TMDMAX * sizeof (struct hme_tmd));
24890219346bSGarrett D'Amore
24900219346bSGarrett D'Amore /*
24910219346bSGarrett D'Amore * Hang out receive buffers.
24920219346bSGarrett D'Amore */
24930219346bSGarrett D'Amore for (i = 0; i < HME_RMDMAX; i++) {
24940219346bSGarrett D'Amore PUT_RMD(i, hmep->hme_rbuf[i].paddr);
24950219346bSGarrett D'Amore }
24960219346bSGarrett D'Amore
24970219346bSGarrett D'Amore /*
24980219346bSGarrett D'Amore * DMA sync descriptors.
24990219346bSGarrett D'Amore */
25000219346bSGarrett D'Amore (void) ddi_dma_sync(hmep->hme_rmd_dmah, 0, 0, DDI_DMA_SYNC_FORDEV);
25010219346bSGarrett D'Amore (void) ddi_dma_sync(hmep->hme_tmd_dmah, 0, 0, DDI_DMA_SYNC_FORDEV);
25020219346bSGarrett D'Amore
25030219346bSGarrett D'Amore /*
25040219346bSGarrett D'Amore * Reset RMD and TMD 'walking' pointers.
25050219346bSGarrett D'Amore */
25060219346bSGarrett D'Amore hmep->hme_rxindex = 0;
25070219346bSGarrett D'Amore hmep->hme_txindex = hmep->hme_txreclaim = 0;
25080219346bSGarrett D'Amore
25090219346bSGarrett D'Amore /*
25100219346bSGarrett D'Amore * This is the right place to initialize MIF !!!
25110219346bSGarrett D'Amore */
25120219346bSGarrett D'Amore
25130219346bSGarrett D'Amore PUT_MIFREG(mif_imask, HME_MIF_INTMASK); /* mask all interrupts */
25140219346bSGarrett D'Amore
25150219346bSGarrett D'Amore if (!hmep->hme_frame_enable)
25160219346bSGarrett D'Amore PUT_MIFREG(mif_cfg, GET_MIFREG(mif_cfg) | HME_MIF_CFGBB);
25170219346bSGarrett D'Amore else
25180219346bSGarrett D'Amore PUT_MIFREG(mif_cfg, GET_MIFREG(mif_cfg) & ~HME_MIF_CFGBB);
25190219346bSGarrett D'Amore /* enable frame mode */
25200219346bSGarrett D'Amore
25210219346bSGarrett D'Amore /*
25220219346bSGarrett D'Amore * Depending on the transceiver detected, select the source
25230219346bSGarrett D'Amore * of the clocks for the MAC. Without the clocks, TX_MAC does
25240219346bSGarrett D'Amore * not reset. When the Global Reset is issued to the Sbus/FEPS
25250219346bSGarrett D'Amore * ASIC, it selects Internal by default.
25260219346bSGarrett D'Amore */
25270219346bSGarrett D'Amore
252806673d9bSGarrett D'Amore switch ((phyad = mii_get_addr(hmep->hme_mii))) {
252906673d9bSGarrett D'Amore case -1:
25300219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, XCVR_MSG, no_xcvr_msg);
25310219346bSGarrett D'Amore goto init_fail; /* abort initialization */
25320219346bSGarrett D'Amore
253306673d9bSGarrett D'Amore case HME_INTERNAL_PHYAD:
25340219346bSGarrett D'Amore PUT_MACREG(xifc, 0);
253506673d9bSGarrett D'Amore break;
253606673d9bSGarrett D'Amore case HME_EXTERNAL_PHYAD:
25370219346bSGarrett D'Amore /* Isolate the Int. xcvr */
253806673d9bSGarrett D'Amore PUT_MACREG(xifc, BMAC_XIFC_MIIBUFDIS);
253906673d9bSGarrett D'Amore break;
25400219346bSGarrett D'Amore }
254106673d9bSGarrett D'Amore
25420219346bSGarrett D'Amore hmep->inits++;
25430219346bSGarrett D'Amore
25440219346bSGarrett D'Amore /*
25450219346bSGarrett D'Amore * Initialize BigMAC registers.
25460219346bSGarrett D'Amore * First set the tx enable bit in tx config reg to 0 and poll on
25470219346bSGarrett D'Amore * it till it turns to 0. Same for rx config, hash and address
25480219346bSGarrett D'Amore * filter reg.
25490219346bSGarrett D'Amore * Here is the sequence per the spec.
25500219346bSGarrett D'Amore * MADD2 - MAC Address 2
25510219346bSGarrett D'Amore * MADD1 - MAC Address 1
25520219346bSGarrett D'Amore * MADD0 - MAC Address 0
25530219346bSGarrett D'Amore * HASH3, HASH2, HASH1, HASH0 for group address
25540219346bSGarrett D'Amore * AFR2, AFR1, AFR0 and AFMR for address filter mask
25550219346bSGarrett D'Amore * Program RXMIN and RXMAX for packet length if not 802.3
25560219346bSGarrett D'Amore * RXCFG - Rx config for not stripping CRC
25570219346bSGarrett D'Amore * XXX Anything else to hme configured in RXCFG
25580219346bSGarrett D'Amore * IPG1, IPG2, ALIMIT, SLOT, PALEN, PAPAT, TXSFD, JAM, TXMAX, TXMIN
25590219346bSGarrett D'Amore * if not 802.3 compliant
25600219346bSGarrett D'Amore * XIF register for speed selection
25610219346bSGarrett D'Amore * MASK - Interrupt mask
25620219346bSGarrett D'Amore * Set bit 0 of TXCFG
25630219346bSGarrett D'Amore * Set bit 0 of RXCFG
25640219346bSGarrett D'Amore */
25650219346bSGarrett D'Amore
25660219346bSGarrett D'Amore /*
25670219346bSGarrett D'Amore * Initialize the TX_MAC registers
25680219346bSGarrett D'Amore * Initialization of jamsize to work around rx crc bug
25690219346bSGarrett D'Amore */
25700219346bSGarrett D'Amore PUT_MACREG(jam, jamsize);
25710219346bSGarrett D'Amore
25720219346bSGarrett D'Amore #ifdef FEPS_URUN_BUG
25730219346bSGarrett D'Amore if (hme_urun_fix)
25740219346bSGarrett D'Amore PUT_MACREG(palen, hme_palen);
25750219346bSGarrett D'Amore #endif
25760219346bSGarrett D'Amore
257706673d9bSGarrett D'Amore PUT_MACREG(ipg1, hmep->hme_ipg1);
257806673d9bSGarrett D'Amore PUT_MACREG(ipg2, hmep->hme_ipg2);
25790219346bSGarrett D'Amore
25800219346bSGarrett D'Amore PUT_MACREG(rseed,
25810219346bSGarrett D'Amore ((hmep->hme_ouraddr.ether_addr_octet[0] << 8) & 0x3) |
25820219346bSGarrett D'Amore hmep->hme_ouraddr.ether_addr_octet[1]);
25830219346bSGarrett D'Amore
25840219346bSGarrett D'Amore /* Initialize the RX_MAC registers */
25850219346bSGarrett D'Amore
25860219346bSGarrett D'Amore /*
25870219346bSGarrett D'Amore * Program BigMAC with local individual ethernet address.
25880219346bSGarrett D'Amore */
25890219346bSGarrett D'Amore PUT_MACREG(madd2, (hmep->hme_ouraddr.ether_addr_octet[4] << 8) |
25900219346bSGarrett D'Amore hmep->hme_ouraddr.ether_addr_octet[5]);
25910219346bSGarrett D'Amore PUT_MACREG(madd1, (hmep->hme_ouraddr.ether_addr_octet[2] << 8) |
25920219346bSGarrett D'Amore hmep->hme_ouraddr.ether_addr_octet[3]);
25930219346bSGarrett D'Amore PUT_MACREG(madd0, (hmep->hme_ouraddr.ether_addr_octet[0] << 8) |
25940219346bSGarrett D'Amore hmep->hme_ouraddr.ether_addr_octet[1]);
25950219346bSGarrett D'Amore
25960219346bSGarrett D'Amore /*
25970219346bSGarrett D'Amore * Set up multicast address filter by passing all multicast
25980219346bSGarrett D'Amore * addresses through a crc generator, and then using the
25990219346bSGarrett D'Amore * low order 6 bits as a index into the 64 bit logical
26000219346bSGarrett D'Amore * address filter. The high order three bits select the word,
26010219346bSGarrett D'Amore * while the rest of the bits select the bit within the word.
26020219346bSGarrett D'Amore */
26030219346bSGarrett D'Amore PUT_MACREG(hash0, hmep->hme_ladrf[0]);
26040219346bSGarrett D'Amore PUT_MACREG(hash1, hmep->hme_ladrf[1]);
26050219346bSGarrett D'Amore PUT_MACREG(hash2, hmep->hme_ladrf[2]);
26060219346bSGarrett D'Amore PUT_MACREG(hash3, hmep->hme_ladrf[3]);
26070219346bSGarrett D'Amore
26080219346bSGarrett D'Amore /*
26090219346bSGarrett D'Amore * Configure parameters to support VLAN. (VLAN encapsulation adds
26100219346bSGarrett D'Amore * four bytes.)
26110219346bSGarrett D'Amore */
26120219346bSGarrett D'Amore PUT_MACREG(txmax, ETHERMAX + ETHERFCSL + 4);
26130219346bSGarrett D'Amore PUT_MACREG(rxmax, ETHERMAX + ETHERFCSL + 4);
26140219346bSGarrett D'Amore
26150219346bSGarrett D'Amore /*
26160219346bSGarrett D'Amore * Initialize HME Global registers, ETX registers and ERX registers.
26170219346bSGarrett D'Amore */
26180219346bSGarrett D'Amore
26190219346bSGarrett D'Amore PUT_ETXREG(txring, hmep->hme_tmd_paddr);
26200219346bSGarrett D'Amore PUT_ERXREG(rxring, hmep->hme_rmd_paddr);
26210219346bSGarrett D'Amore
26220219346bSGarrett D'Amore /*
26230219346bSGarrett D'Amore * ERX registers can be written only if they have even no. of bits set.
26240219346bSGarrett D'Amore * So, if the value written is not read back, set the lsb and write
26250219346bSGarrett D'Amore * again.
26260219346bSGarrett D'Amore * static int hme_erx_fix = 1; : Use the fix for erx bug
26270219346bSGarrett D'Amore */
26280219346bSGarrett D'Amore {
26290219346bSGarrett D'Amore uint32_t temp;
26300219346bSGarrett D'Amore temp = hmep->hme_rmd_paddr;
26310219346bSGarrett D'Amore
26320219346bSGarrett D'Amore if (GET_ERXREG(rxring) != temp)
26330219346bSGarrett D'Amore PUT_ERXREG(rxring, (temp | 4));
26340219346bSGarrett D'Amore }
26350219346bSGarrett D'Amore
26360219346bSGarrett D'Amore PUT_GLOBREG(config, (hmep->hme_config |
26370219346bSGarrett D'Amore (hmep->hme_64bit_xfer << HMEG_CONFIG_64BIT_SHIFT)));
26380219346bSGarrett D'Amore
26390219346bSGarrett D'Amore /*
26400219346bSGarrett D'Amore * Significant performance improvements can be achieved by
26410219346bSGarrett D'Amore * disabling transmit interrupt. Thus TMD's are reclaimed only
26420219346bSGarrett D'Amore * when we run out of them in hmestart().
26430219346bSGarrett D'Amore */
26440219346bSGarrett D'Amore PUT_GLOBREG(intmask,
26450219346bSGarrett D'Amore HMEG_MASK_INTR | HMEG_MASK_TINT | HMEG_MASK_TX_ALL);
26460219346bSGarrett D'Amore
26470219346bSGarrett D'Amore PUT_ETXREG(txring_size, ((HME_TMDMAX -1)>> HMET_RINGSZ_SHIFT));
26480219346bSGarrett D'Amore PUT_ETXREG(config, (GET_ETXREG(config) | HMET_CONFIG_TXDMA_EN
26490219346bSGarrett D'Amore | HMET_CONFIG_TXFIFOTH));
26500219346bSGarrett D'Amore /* get the rxring size bits */
26510219346bSGarrett D'Amore switch (HME_RMDMAX) {
26520219346bSGarrett D'Amore case 32:
26530219346bSGarrett D'Amore i = HMER_CONFIG_RXRINGSZ32;
26540219346bSGarrett D'Amore break;
26550219346bSGarrett D'Amore case 64:
26560219346bSGarrett D'Amore i = HMER_CONFIG_RXRINGSZ64;
26570219346bSGarrett D'Amore break;
26580219346bSGarrett D'Amore case 128:
26590219346bSGarrett D'Amore i = HMER_CONFIG_RXRINGSZ128;
26600219346bSGarrett D'Amore break;
26610219346bSGarrett D'Amore case 256:
26620219346bSGarrett D'Amore i = HMER_CONFIG_RXRINGSZ256;
26630219346bSGarrett D'Amore break;
26640219346bSGarrett D'Amore default:
26650219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
26660219346bSGarrett D'Amore unk_rx_ringsz_msg);
26670219346bSGarrett D'Amore goto init_fail;
26680219346bSGarrett D'Amore }
26690219346bSGarrett D'Amore i |= (HME_FSTBYTE_OFFSET << HMER_CONFIG_FBO_SHIFT)
26700219346bSGarrett D'Amore | HMER_CONFIG_RXDMA_EN;
26710219346bSGarrett D'Amore
26720219346bSGarrett D'Amore /* h/w checks start offset in half words */
26730219346bSGarrett D'Amore i |= ((sizeof (struct ether_header) / 2) << HMER_RX_CSSTART_SHIFT);
26740219346bSGarrett D'Amore
26750219346bSGarrett D'Amore PUT_ERXREG(config, i);
26760219346bSGarrett D'Amore
26770219346bSGarrett D'Amore /*
26780219346bSGarrett D'Amore * Bug related to the parity handling in ERX. When erxp-config is
26790219346bSGarrett D'Amore * read back.
26800219346bSGarrett D'Amore * Sbus/FEPS drives the parity bit. This value is used while
26810219346bSGarrett D'Amore * writing again.
26820219346bSGarrett D'Amore * This fixes the RECV problem in SS5.
26830219346bSGarrett D'Amore * static int hme_erx_fix = 1; : Use the fix for erx bug
26840219346bSGarrett D'Amore */
26850219346bSGarrett D'Amore {
26860219346bSGarrett D'Amore uint32_t temp;
26870219346bSGarrett D'Amore temp = GET_ERXREG(config);
26880219346bSGarrett D'Amore PUT_ERXREG(config, i);
26890219346bSGarrett D'Amore
26900219346bSGarrett D'Amore if (GET_ERXREG(config) != i)
26910219346bSGarrett D'Amore HME_FAULT_MSG4(hmep, SEVERITY_UNKNOWN, ERX_MSG,
26920219346bSGarrett D'Amore "error:temp = %x erxp->config = %x, should be %x",
26930219346bSGarrett D'Amore temp, GET_ERXREG(config), i);
26940219346bSGarrett D'Amore }
26950219346bSGarrett D'Amore
26960219346bSGarrett D'Amore /*
26970219346bSGarrett D'Amore * Set up the rxconfig, txconfig and seed register without enabling
26980219346bSGarrett D'Amore * them the former two at this time
26990219346bSGarrett D'Amore *
27000219346bSGarrett D'Amore * BigMAC strips the CRC bytes by default. Since this is
27010219346bSGarrett D'Amore * contrary to other pieces of hardware, this bit needs to
27020219346bSGarrett D'Amore * enabled to tell BigMAC not to strip the CRC bytes.
27030219346bSGarrett D'Amore * Do not filter this node's own packets.
27040219346bSGarrett D'Amore */
27050219346bSGarrett D'Amore
27060219346bSGarrett D'Amore if (hme_reject_own) {
27070219346bSGarrett D'Amore PUT_MACREG(rxcfg,
27080219346bSGarrett D'Amore ((hmep->hme_promisc ? BMAC_RXCFG_PROMIS : 0) |
27090219346bSGarrett D'Amore BMAC_RXCFG_MYOWN | BMAC_RXCFG_HASH));
27100219346bSGarrett D'Amore } else {
27110219346bSGarrett D'Amore PUT_MACREG(rxcfg,
27120219346bSGarrett D'Amore ((hmep->hme_promisc ? BMAC_RXCFG_PROMIS : 0) |
27130219346bSGarrett D'Amore BMAC_RXCFG_HASH));
27140219346bSGarrett D'Amore }
27150219346bSGarrett D'Amore
27160219346bSGarrett D'Amore drv_usecwait(10); /* wait after setting Hash Enable bit */
27170219346bSGarrett D'Amore
271806673d9bSGarrett D'Amore fdx = (mii_get_duplex(hmep->hme_mii) == LINK_DUPLEX_FULL);
271906673d9bSGarrett D'Amore
27200219346bSGarrett D'Amore if (hme_ngu_enable)
272106673d9bSGarrett D'Amore PUT_MACREG(txcfg, (fdx ? BMAC_TXCFG_FDX : 0) |
27220219346bSGarrett D'Amore BMAC_TXCFG_NGU);
27230219346bSGarrett D'Amore else
272406673d9bSGarrett D'Amore PUT_MACREG(txcfg, (fdx ? BMAC_TXCFG_FDX: 0));
27250219346bSGarrett D'Amore
27260219346bSGarrett D'Amore i = 0;
272706673d9bSGarrett D'Amore if ((hmep->hme_lance_mode) && (hmep->hme_lance_mode_enable))
272806673d9bSGarrett D'Amore i = ((hmep->hme_ipg0 & HME_MASK_5BIT) << BMAC_XIFC_IPG0_SHIFT)
27290219346bSGarrett D'Amore | BMAC_XIFC_LANCE_ENAB;
273006673d9bSGarrett D'Amore if (phyad == HME_INTERNAL_PHYAD)
27310219346bSGarrett D'Amore PUT_MACREG(xifc, i | (BMAC_XIFC_ENAB));
27320219346bSGarrett D'Amore else
27330219346bSGarrett D'Amore PUT_MACREG(xifc, i | (BMAC_XIFC_ENAB | BMAC_XIFC_MIIBUFDIS));
27340219346bSGarrett D'Amore
27350219346bSGarrett D'Amore PUT_MACREG(rxcfg, GET_MACREG(rxcfg) | BMAC_RXCFG_ENAB);
27360219346bSGarrett D'Amore PUT_MACREG(txcfg, GET_MACREG(txcfg) | BMAC_TXCFG_ENAB);
27370219346bSGarrett D'Amore
27380219346bSGarrett D'Amore hmep->hme_flags |= (HMERUNNING | HMEINITIALIZED);
27390219346bSGarrett D'Amore /*
27400219346bSGarrett D'Amore * Update the interrupt mask : this will re-allow interrupts to occur
27410219346bSGarrett D'Amore */
27420219346bSGarrett D'Amore PUT_GLOBREG(intmask, HMEG_MASK_INTR);
27430219346bSGarrett D'Amore mac_tx_update(hmep->hme_mh);
27440219346bSGarrett D'Amore
27450219346bSGarrett D'Amore init_fail:
27460219346bSGarrett D'Amore /*
27470219346bSGarrett D'Amore * Release the locks in reverse order
27480219346bSGarrett D'Amore */
27490219346bSGarrett D'Amore mutex_exit(&hmep->hme_xmitlock);
27500219346bSGarrett D'Amore mutex_exit(&hmep->hme_intrlock);
27510219346bSGarrett D'Amore
27520219346bSGarrett D'Amore ret = !(hmep->hme_flags & HMERUNNING);
27530219346bSGarrett D'Amore if (ret) {
27540219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
27550219346bSGarrett D'Amore init_fail_gen_msg);
27560219346bSGarrett D'Amore }
27570219346bSGarrett D'Amore
27580219346bSGarrett D'Amore /*
27590219346bSGarrett D'Amore * Hardware checks.
27600219346bSGarrett D'Amore */
27610219346bSGarrett D'Amore CHECK_GLOBREG();
27620219346bSGarrett D'Amore CHECK_MIFREG();
27630219346bSGarrett D'Amore CHECK_MACREG();
27640219346bSGarrett D'Amore CHECK_ERXREG();
27650219346bSGarrett D'Amore CHECK_ETXREG();
27660219346bSGarrett D'Amore
27670219346bSGarrett D'Amore init_exit:
27680219346bSGarrett D'Amore return (ret);
27690219346bSGarrett D'Amore }
27700219346bSGarrett D'Amore
27710219346bSGarrett D'Amore /*
27720219346bSGarrett D'Amore * Calculate the dvma burstsize by setting up a dvma temporarily. Return
27730219346bSGarrett D'Amore * 0 as burstsize upon failure as it signifies no burst size.
27740219346bSGarrett D'Amore * Requests for 64-bit transfer setup, if the platform supports it.
27750219346bSGarrett D'Amore * NOTE: Do not use ddi_dma_alloc_handle(9f) then ddi_dma_burstsize(9f),
27760219346bSGarrett D'Amore * sun4u Ultra-2 incorrectly returns a 32bit transfer.
27770219346bSGarrett D'Amore */
27780219346bSGarrett D'Amore static int
hmeburstsizes(struct hme * hmep)27790219346bSGarrett D'Amore hmeburstsizes(struct hme *hmep)
27800219346bSGarrett D'Amore {
27810219346bSGarrett D'Amore int burstsizes;
27820219346bSGarrett D'Amore ddi_dma_handle_t handle;
27830219346bSGarrett D'Amore
27840219346bSGarrett D'Amore if (ddi_dma_alloc_handle(hmep->dip, &hme_dma_attr,
27850219346bSGarrett D'Amore DDI_DMA_DONTWAIT, NULL, &handle)) {
27860219346bSGarrett D'Amore return (0);
27870219346bSGarrett D'Amore }
27880219346bSGarrett D'Amore
27890219346bSGarrett D'Amore hmep->hme_burstsizes = burstsizes = ddi_dma_burstsizes(handle);
27900219346bSGarrett D'Amore ddi_dma_free_handle(&handle);
27910219346bSGarrett D'Amore
27920219346bSGarrett D'Amore /*
27930219346bSGarrett D'Amore * Use user-configurable parameter for enabling 64-bit transfers
27940219346bSGarrett D'Amore */
27950219346bSGarrett D'Amore burstsizes = (hmep->hme_burstsizes >> 16);
27960219346bSGarrett D'Amore if (burstsizes)
27970219346bSGarrett D'Amore hmep->hme_64bit_xfer = hme_64bit_enable; /* user config value */
27980219346bSGarrett D'Amore else
27990219346bSGarrett D'Amore burstsizes = hmep->hme_burstsizes;
28000219346bSGarrett D'Amore
28010219346bSGarrett D'Amore if (hmep->hme_cheerio_mode)
28020219346bSGarrett D'Amore hmep->hme_64bit_xfer = 0; /* Disable for cheerio */
28030219346bSGarrett D'Amore
28040219346bSGarrett D'Amore if (burstsizes & 0x40)
28050219346bSGarrett D'Amore hmep->hme_config = HMEG_CONFIG_BURST64;
28060219346bSGarrett D'Amore else if (burstsizes & 0x20)
28070219346bSGarrett D'Amore hmep->hme_config = HMEG_CONFIG_BURST32;
28080219346bSGarrett D'Amore else
28090219346bSGarrett D'Amore hmep->hme_config = HMEG_CONFIG_BURST16;
28100219346bSGarrett D'Amore
28110219346bSGarrett D'Amore return (DDI_SUCCESS);
28120219346bSGarrett D'Amore }
28130219346bSGarrett D'Amore
28140219346bSGarrett D'Amore static int
hmeallocbuf(struct hme * hmep,hmebuf_t * buf,int dir)28150219346bSGarrett D'Amore hmeallocbuf(struct hme *hmep, hmebuf_t *buf, int dir)
28160219346bSGarrett D'Amore {
28170219346bSGarrett D'Amore ddi_dma_cookie_t dmac;
28180219346bSGarrett D'Amore size_t len;
28190219346bSGarrett D'Amore unsigned ccnt;
28200219346bSGarrett D'Amore
28210219346bSGarrett D'Amore if (ddi_dma_alloc_handle(hmep->dip, &hme_dma_attr,
28220219346bSGarrett D'Amore DDI_DMA_DONTWAIT, NULL, &buf->dmah) != DDI_SUCCESS) {
28230219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
28240219346bSGarrett D'Amore "cannot allocate buf dma handle - failed");
28250219346bSGarrett D'Amore return (DDI_FAILURE);
28260219346bSGarrett D'Amore }
28270219346bSGarrett D'Amore
28280219346bSGarrett D'Amore if (ddi_dma_mem_alloc(buf->dmah, ROUNDUP(HMEBUFSIZE, 512),
28290219346bSGarrett D'Amore &hme_buf_attr, DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, NULL,
28300219346bSGarrett D'Amore &buf->kaddr, &len, &buf->acch) != DDI_SUCCESS) {
28310219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
28320219346bSGarrett D'Amore "cannot allocate buf memory - failed");
28330219346bSGarrett D'Amore return (DDI_FAILURE);
28340219346bSGarrett D'Amore }
28350219346bSGarrett D'Amore
28360219346bSGarrett D'Amore if (ddi_dma_addr_bind_handle(buf->dmah, NULL, buf->kaddr,
28370219346bSGarrett D'Amore len, dir | DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
28380219346bSGarrett D'Amore &dmac, &ccnt) != DDI_DMA_MAPPED) {
28390219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
28400219346bSGarrett D'Amore "cannot map buf for dma - failed");
28410219346bSGarrett D'Amore return (DDI_FAILURE);
28420219346bSGarrett D'Amore }
28430219346bSGarrett D'Amore buf->paddr = dmac.dmac_address;
28440219346bSGarrett D'Amore
28450219346bSGarrett D'Amore /* apparently they don't handle multiple cookies */
28460219346bSGarrett D'Amore if (ccnt > 1) {
28470219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
28480219346bSGarrett D'Amore "too many buf dma cookies");
28490219346bSGarrett D'Amore return (DDI_FAILURE);
28500219346bSGarrett D'Amore }
28510219346bSGarrett D'Amore return (DDI_SUCCESS);
28520219346bSGarrett D'Amore }
28530219346bSGarrett D'Amore
28540219346bSGarrett D'Amore static int
hmeallocbufs(struct hme * hmep)28550219346bSGarrett D'Amore hmeallocbufs(struct hme *hmep)
28560219346bSGarrett D'Amore {
28570219346bSGarrett D'Amore hmep->hme_tbuf = kmem_zalloc(HME_TMDMAX * sizeof (hmebuf_t), KM_SLEEP);
28580219346bSGarrett D'Amore hmep->hme_rbuf = kmem_zalloc(HME_RMDMAX * sizeof (hmebuf_t), KM_SLEEP);
28590219346bSGarrett D'Amore
28600219346bSGarrett D'Amore /* Alloc RX buffers. */
28610219346bSGarrett D'Amore for (int i = 0; i < HME_RMDMAX; i++) {
28620219346bSGarrett D'Amore if (hmeallocbuf(hmep, &hmep->hme_rbuf[i], DDI_DMA_READ) !=
28630219346bSGarrett D'Amore DDI_SUCCESS) {
28640219346bSGarrett D'Amore return (DDI_FAILURE);
28650219346bSGarrett D'Amore }
28660219346bSGarrett D'Amore }
28670219346bSGarrett D'Amore
28680219346bSGarrett D'Amore /* Alloc TX buffers. */
28690219346bSGarrett D'Amore for (int i = 0; i < HME_TMDMAX; i++) {
28700219346bSGarrett D'Amore if (hmeallocbuf(hmep, &hmep->hme_tbuf[i], DDI_DMA_WRITE) !=
28710219346bSGarrett D'Amore DDI_SUCCESS) {
28720219346bSGarrett D'Amore return (DDI_FAILURE);
28730219346bSGarrett D'Amore }
28740219346bSGarrett D'Amore }
28750219346bSGarrett D'Amore return (DDI_SUCCESS);
28760219346bSGarrett D'Amore }
28770219346bSGarrett D'Amore
28780219346bSGarrett D'Amore static void
hmefreebufs(struct hme * hmep)28790219346bSGarrett D'Amore hmefreebufs(struct hme *hmep)
28800219346bSGarrett D'Amore {
28810219346bSGarrett D'Amore int i;
28820219346bSGarrett D'Amore
28830219346bSGarrett D'Amore if (hmep->hme_rbuf == NULL)
28840219346bSGarrett D'Amore return;
28850219346bSGarrett D'Amore
28860219346bSGarrett D'Amore /*
28870219346bSGarrett D'Amore * Free and unload pending xmit and recv buffers.
28880219346bSGarrett D'Amore * Maintaining the 1-to-1 ordered sequence of
28890219346bSGarrett D'Amore * We have written the routine to be idempotent.
28900219346bSGarrett D'Amore */
28910219346bSGarrett D'Amore
28920219346bSGarrett D'Amore for (i = 0; i < HME_TMDMAX; i++) {
28930219346bSGarrett D'Amore hmebuf_t *tbuf = &hmep->hme_tbuf[i];
28940219346bSGarrett D'Amore if (tbuf->paddr) {
28950219346bSGarrett D'Amore (void) ddi_dma_unbind_handle(tbuf->dmah);
28960219346bSGarrett D'Amore }
28970219346bSGarrett D'Amore if (tbuf->kaddr) {
28980219346bSGarrett D'Amore ddi_dma_mem_free(&tbuf->acch);
28990219346bSGarrett D'Amore }
29000219346bSGarrett D'Amore if (tbuf->dmah) {
29010219346bSGarrett D'Amore ddi_dma_free_handle(&tbuf->dmah);
29020219346bSGarrett D'Amore }
29030219346bSGarrett D'Amore }
29040219346bSGarrett D'Amore for (i = 0; i < HME_RMDMAX; i++) {
29050219346bSGarrett D'Amore hmebuf_t *rbuf = &hmep->hme_rbuf[i];
29060219346bSGarrett D'Amore if (rbuf->paddr) {
29070219346bSGarrett D'Amore (void) ddi_dma_unbind_handle(rbuf->dmah);
29080219346bSGarrett D'Amore }
29090219346bSGarrett D'Amore if (rbuf->kaddr) {
29100219346bSGarrett D'Amore ddi_dma_mem_free(&rbuf->acch);
29110219346bSGarrett D'Amore }
29120219346bSGarrett D'Amore if (rbuf->dmah) {
29130219346bSGarrett D'Amore ddi_dma_free_handle(&rbuf->dmah);
29140219346bSGarrett D'Amore }
29150219346bSGarrett D'Amore }
29160219346bSGarrett D'Amore kmem_free(hmep->hme_rbuf, HME_RMDMAX * sizeof (hmebuf_t));
29170219346bSGarrett D'Amore kmem_free(hmep->hme_tbuf, HME_TMDMAX * sizeof (hmebuf_t));
29180219346bSGarrett D'Amore }
29190219346bSGarrett D'Amore
29200219346bSGarrett D'Amore /*
29210219346bSGarrett D'Amore * Un-initialize (STOP) HME channel.
29220219346bSGarrett D'Amore */
29230219346bSGarrett D'Amore static void
hmeuninit(struct hme * hmep)29240219346bSGarrett D'Amore hmeuninit(struct hme *hmep)
29250219346bSGarrett D'Amore {
29260219346bSGarrett D'Amore /*
29270219346bSGarrett D'Amore * Allow up to 'HMEDRAINTIME' for pending xmit's to complete.
29280219346bSGarrett D'Amore */
29290219346bSGarrett D'Amore HMEDELAY((hmep->hme_txindex == hmep->hme_txreclaim), HMEDRAINTIME);
29300219346bSGarrett D'Amore
29310219346bSGarrett D'Amore mutex_enter(&hmep->hme_intrlock);
29320219346bSGarrett D'Amore mutex_enter(&hmep->hme_xmitlock);
29330219346bSGarrett D'Amore
29340219346bSGarrett D'Amore hmep->hme_flags &= ~HMERUNNING;
29350219346bSGarrett D'Amore
29360219346bSGarrett D'Amore (void) hmestop(hmep);
29370219346bSGarrett D'Amore
29380219346bSGarrett D'Amore mutex_exit(&hmep->hme_xmitlock);
29390219346bSGarrett D'Amore mutex_exit(&hmep->hme_intrlock);
29400219346bSGarrett D'Amore }
29410219346bSGarrett D'Amore
29420219346bSGarrett D'Amore /*
29430219346bSGarrett D'Amore * Allocate CONSISTENT memory for rmds and tmds with appropriate alignment and
29440219346bSGarrett D'Amore * map it in IO space. Allocate space for transmit and receive ddi_dma_handle
29450219346bSGarrett D'Amore * structures to use the DMA interface.
29460219346bSGarrett D'Amore */
29470219346bSGarrett D'Amore static int
hmeallocthings(struct hme * hmep)29480219346bSGarrett D'Amore hmeallocthings(struct hme *hmep)
29490219346bSGarrett D'Amore {
29500219346bSGarrett D'Amore int size;
29510219346bSGarrett D'Amore int rval;
29520219346bSGarrett D'Amore size_t real_len;
29530219346bSGarrett D'Amore uint_t cookiec;
29540219346bSGarrett D'Amore ddi_dma_cookie_t dmac;
29550219346bSGarrett D'Amore dev_info_t *dip = hmep->dip;
29560219346bSGarrett D'Amore
29570219346bSGarrett D'Amore /*
29580219346bSGarrett D'Amore * Allocate the TMD and RMD descriptors and extra for page alignment.
29590219346bSGarrett D'Amore */
29600219346bSGarrett D'Amore
29610219346bSGarrett D'Amore rval = ddi_dma_alloc_handle(dip, &hme_dma_attr, DDI_DMA_DONTWAIT, NULL,
29620219346bSGarrett D'Amore &hmep->hme_rmd_dmah);
29630219346bSGarrett D'Amore if (rval != DDI_SUCCESS) {
29640219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
29650219346bSGarrett D'Amore "cannot allocate rmd handle - failed");
29660219346bSGarrett D'Amore return (DDI_FAILURE);
29670219346bSGarrett D'Amore }
29680219346bSGarrett D'Amore size = HME_RMDMAX * sizeof (struct hme_rmd);
29690219346bSGarrett D'Amore rval = ddi_dma_mem_alloc(hmep->hme_rmd_dmah, size,
29700219346bSGarrett D'Amore &hmep->hme_dev_attr, DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
29710219346bSGarrett D'Amore &hmep->hme_rmd_kaddr, &real_len, &hmep->hme_rmd_acch);
29720219346bSGarrett D'Amore if (rval != DDI_SUCCESS) {
29730219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
29740219346bSGarrett D'Amore "cannot allocate rmd dma mem - failed");
29750219346bSGarrett D'Amore return (DDI_FAILURE);
29760219346bSGarrett D'Amore }
29770219346bSGarrett D'Amore hmep->hme_rmdp = (void *)(hmep->hme_rmd_kaddr);
29780219346bSGarrett D'Amore rval = ddi_dma_addr_bind_handle(hmep->hme_rmd_dmah, NULL,
29790219346bSGarrett D'Amore hmep->hme_rmd_kaddr, size, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
29800219346bSGarrett D'Amore DDI_DMA_DONTWAIT, NULL, &dmac, &cookiec);
29810219346bSGarrett D'Amore if (rval != DDI_DMA_MAPPED) {
29820219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
29830219346bSGarrett D'Amore "cannot allocate rmd dma - failed");
29840219346bSGarrett D'Amore return (DDI_FAILURE);
29850219346bSGarrett D'Amore }
29860219346bSGarrett D'Amore hmep->hme_rmd_paddr = dmac.dmac_address;
29870219346bSGarrett D'Amore if (cookiec != 1) {
29880219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
29890219346bSGarrett D'Amore "too many rmd cookies - failed");
29900219346bSGarrett D'Amore return (DDI_FAILURE);
29910219346bSGarrett D'Amore }
29920219346bSGarrett D'Amore
29930219346bSGarrett D'Amore rval = ddi_dma_alloc_handle(dip, &hme_dma_attr, DDI_DMA_DONTWAIT, NULL,
29940219346bSGarrett D'Amore &hmep->hme_tmd_dmah);
29950219346bSGarrett D'Amore if (rval != DDI_SUCCESS) {
29960219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
29970219346bSGarrett D'Amore "cannot allocate tmd handle - failed");
29980219346bSGarrett D'Amore return (DDI_FAILURE);
29990219346bSGarrett D'Amore }
30000219346bSGarrett D'Amore size = HME_TMDMAX * sizeof (struct hme_rmd);
30010219346bSGarrett D'Amore rval = ddi_dma_mem_alloc(hmep->hme_tmd_dmah, size,
30020219346bSGarrett D'Amore &hmep->hme_dev_attr, DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
30030219346bSGarrett D'Amore &hmep->hme_tmd_kaddr, &real_len, &hmep->hme_tmd_acch);
30040219346bSGarrett D'Amore if (rval != DDI_SUCCESS) {
30050219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
30060219346bSGarrett D'Amore "cannot allocate tmd dma mem - failed");
30070219346bSGarrett D'Amore return (DDI_FAILURE);
30080219346bSGarrett D'Amore }
30090219346bSGarrett D'Amore hmep->hme_tmdp = (void *)(hmep->hme_tmd_kaddr);
30100219346bSGarrett D'Amore rval = ddi_dma_addr_bind_handle(hmep->hme_tmd_dmah, NULL,
30110219346bSGarrett D'Amore hmep->hme_tmd_kaddr, size, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
30120219346bSGarrett D'Amore DDI_DMA_DONTWAIT, NULL, &dmac, &cookiec);
30130219346bSGarrett D'Amore if (rval != DDI_DMA_MAPPED) {
30140219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
30150219346bSGarrett D'Amore "cannot allocate tmd dma - failed");
30160219346bSGarrett D'Amore return (DDI_FAILURE);
30170219346bSGarrett D'Amore }
30180219346bSGarrett D'Amore hmep->hme_tmd_paddr = dmac.dmac_address;
30190219346bSGarrett D'Amore if (cookiec != 1) {
30200219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
30210219346bSGarrett D'Amore "too many tmd cookies - failed");
30220219346bSGarrett D'Amore return (DDI_FAILURE);
30230219346bSGarrett D'Amore }
30240219346bSGarrett D'Amore
30250219346bSGarrett D'Amore return (DDI_SUCCESS);
30260219346bSGarrett D'Amore }
30270219346bSGarrett D'Amore
30280219346bSGarrett D'Amore static void
hmefreethings(struct hme * hmep)30290219346bSGarrett D'Amore hmefreethings(struct hme *hmep)
30300219346bSGarrett D'Amore {
30310219346bSGarrett D'Amore if (hmep->hme_rmd_paddr) {
30320219346bSGarrett D'Amore (void) ddi_dma_unbind_handle(hmep->hme_rmd_dmah);
30330219346bSGarrett D'Amore hmep->hme_rmd_paddr = 0;
30340219346bSGarrett D'Amore }
30350219346bSGarrett D'Amore if (hmep->hme_rmd_acch)
30360219346bSGarrett D'Amore ddi_dma_mem_free(&hmep->hme_rmd_acch);
30370219346bSGarrett D'Amore if (hmep->hme_rmd_dmah)
30380219346bSGarrett D'Amore ddi_dma_free_handle(&hmep->hme_rmd_dmah);
30390219346bSGarrett D'Amore
30400219346bSGarrett D'Amore if (hmep->hme_tmd_paddr) {
30410219346bSGarrett D'Amore (void) ddi_dma_unbind_handle(hmep->hme_tmd_dmah);
30420219346bSGarrett D'Amore hmep->hme_tmd_paddr = 0;
30430219346bSGarrett D'Amore }
30440219346bSGarrett D'Amore if (hmep->hme_tmd_acch)
30450219346bSGarrett D'Amore ddi_dma_mem_free(&hmep->hme_tmd_acch);
30460219346bSGarrett D'Amore if (hmep->hme_tmd_dmah)
30470219346bSGarrett D'Amore ddi_dma_free_handle(&hmep->hme_tmd_dmah);
30480219346bSGarrett D'Amore }
30490219346bSGarrett D'Amore
30500219346bSGarrett D'Amore /*
30510219346bSGarrett D'Amore * First check to see if it our device interrupting.
30520219346bSGarrett D'Amore */
30530219346bSGarrett D'Amore static uint_t
hmeintr(caddr_t arg)30540219346bSGarrett D'Amore hmeintr(caddr_t arg)
30550219346bSGarrett D'Amore {
30560219346bSGarrett D'Amore struct hme *hmep = (void *)arg;
30570219346bSGarrett D'Amore uint32_t hmesbits;
30580219346bSGarrett D'Amore uint32_t serviced = DDI_INTR_UNCLAIMED;
30590219346bSGarrett D'Amore uint32_t num_reads = 0;
30600219346bSGarrett D'Amore uint32_t rflags;
30610219346bSGarrett D'Amore mblk_t *mp, *head, **tail;
30620219346bSGarrett D'Amore
30630219346bSGarrett D'Amore
30640219346bSGarrett D'Amore head = NULL;
30650219346bSGarrett D'Amore tail = &head;
30660219346bSGarrett D'Amore
30670219346bSGarrett D'Amore mutex_enter(&hmep->hme_intrlock);
30680219346bSGarrett D'Amore
30690219346bSGarrett D'Amore /*
30700219346bSGarrett D'Amore * The status register auto-clears on read except for
30710219346bSGarrett D'Amore * MIF Interrupt bit
30720219346bSGarrett D'Amore */
30730219346bSGarrett D'Amore hmesbits = GET_GLOBREG(status);
30740219346bSGarrett D'Amore CHECK_GLOBREG();
30750219346bSGarrett D'Amore
30760219346bSGarrett D'Amore /*
30770219346bSGarrett D'Amore * Note: TINT is sometimes enabled in thr hmereclaim()
30780219346bSGarrett D'Amore */
30790219346bSGarrett D'Amore
30800219346bSGarrett D'Amore /*
30810219346bSGarrett D'Amore * Bugid 1227832 - to handle spurious interrupts on fusion systems.
30820219346bSGarrett D'Amore * Claim the first interrupt after initialization
30830219346bSGarrett D'Amore */
30840219346bSGarrett D'Amore if (hmep->hme_flags & HMEINITIALIZED) {
30850219346bSGarrett D'Amore hmep->hme_flags &= ~HMEINITIALIZED;
30860219346bSGarrett D'Amore serviced = DDI_INTR_CLAIMED;
30870219346bSGarrett D'Amore }
30880219346bSGarrett D'Amore
30890219346bSGarrett D'Amore if ((hmesbits & (HMEG_STATUS_INTR | HMEG_STATUS_TINT)) == 0) {
30900219346bSGarrett D'Amore /* No interesting interrupt */
30910219346bSGarrett D'Amore if (hmep->hme_intrstats) {
30920219346bSGarrett D'Amore if (serviced == DDI_INTR_UNCLAIMED)
30930219346bSGarrett D'Amore KIOIP->intrs[KSTAT_INTR_SPURIOUS]++;
30940219346bSGarrett D'Amore else
30950219346bSGarrett D'Amore KIOIP->intrs[KSTAT_INTR_HARD]++;
30960219346bSGarrett D'Amore }
30970219346bSGarrett D'Amore mutex_exit(&hmep->hme_intrlock);
30980219346bSGarrett D'Amore return (serviced);
30990219346bSGarrett D'Amore }
31000219346bSGarrett D'Amore
31010219346bSGarrett D'Amore serviced = DDI_INTR_CLAIMED;
31020219346bSGarrett D'Amore
31030219346bSGarrett D'Amore if (!(hmep->hme_flags & HMERUNNING)) {
31040219346bSGarrett D'Amore if (hmep->hme_intrstats)
31050219346bSGarrett D'Amore KIOIP->intrs[KSTAT_INTR_HARD]++;
31060219346bSGarrett D'Amore mutex_exit(&hmep->hme_intrlock);
31070219346bSGarrett D'Amore hmeuninit(hmep);
31080219346bSGarrett D'Amore return (serviced);
31090219346bSGarrett D'Amore }
31100219346bSGarrett D'Amore
31110219346bSGarrett D'Amore if (hmesbits & (HMEG_STATUS_FATAL_ERR | HMEG_STATUS_NONFATAL_ERR)) {
31120219346bSGarrett D'Amore if (hmesbits & HMEG_STATUS_FATAL_ERR) {
31130219346bSGarrett D'Amore
31140219346bSGarrett D'Amore if (hmep->hme_intrstats)
31150219346bSGarrett D'Amore KIOIP->intrs[KSTAT_INTR_HARD]++;
31160219346bSGarrett D'Amore hme_fatal_err(hmep, hmesbits);
31170219346bSGarrett D'Amore
31180219346bSGarrett D'Amore mutex_exit(&hmep->hme_intrlock);
31190219346bSGarrett D'Amore (void) hmeinit(hmep);
31200219346bSGarrett D'Amore return (serviced);
31210219346bSGarrett D'Amore }
31220219346bSGarrett D'Amore hme_nonfatal_err(hmep, hmesbits);
31230219346bSGarrett D'Amore }
31240219346bSGarrett D'Amore
31250219346bSGarrett D'Amore if (hmesbits & (HMEG_STATUS_TX_ALL | HMEG_STATUS_TINT)) {
31260219346bSGarrett D'Amore mutex_enter(&hmep->hme_xmitlock);
31270219346bSGarrett D'Amore
31280219346bSGarrett D'Amore hmereclaim(hmep);
31290219346bSGarrett D'Amore mutex_exit(&hmep->hme_xmitlock);
31300219346bSGarrett D'Amore }
31310219346bSGarrett D'Amore
31320219346bSGarrett D'Amore if (hmesbits & HMEG_STATUS_RINT) {
31330219346bSGarrett D'Amore
31340219346bSGarrett D'Amore /*
31350219346bSGarrett D'Amore * This dummy PIO is required to flush the SBus
31360219346bSGarrett D'Amore * Bridge buffers in QFE.
31370219346bSGarrett D'Amore */
31380219346bSGarrett D'Amore (void) GET_GLOBREG(config);
31390219346bSGarrett D'Amore
31400219346bSGarrett D'Amore /*
31410219346bSGarrett D'Amore * Loop through each RMD no more than once.
31420219346bSGarrett D'Amore */
31430219346bSGarrett D'Amore while (num_reads++ < HME_RMDMAX) {
31440219346bSGarrett D'Amore hmebuf_t *rbuf;
31450219346bSGarrett D'Amore int rxptr;
31460219346bSGarrett D'Amore
31470219346bSGarrett D'Amore rxptr = hmep->hme_rxindex % HME_RMDMAX;
31480219346bSGarrett D'Amore HMESYNCRMD(rxptr, DDI_DMA_SYNC_FORKERNEL);
31490219346bSGarrett D'Amore
31500219346bSGarrett D'Amore rflags = GET_RMD_FLAGS(rxptr);
31510219346bSGarrett D'Amore if (rflags & HMERMD_OWN) {
31520219346bSGarrett D'Amore /*
31530219346bSGarrett D'Amore * Chip still owns it. We're done.
31540219346bSGarrett D'Amore */
31550219346bSGarrett D'Amore break;
31560219346bSGarrett D'Amore }
31570219346bSGarrett D'Amore
31580219346bSGarrett D'Amore /*
31590219346bSGarrett D'Amore * Retrieve the packet.
31600219346bSGarrett D'Amore */
31610219346bSGarrett D'Amore rbuf = &hmep->hme_rbuf[rxptr];
31620219346bSGarrett D'Amore mp = hmeread(hmep, rbuf, rflags);
31630219346bSGarrett D'Amore
31640219346bSGarrett D'Amore /*
31650219346bSGarrett D'Amore * Return ownership of the RMD.
31660219346bSGarrett D'Amore */
31670219346bSGarrett D'Amore PUT_RMD(rxptr, rbuf->paddr);
31680219346bSGarrett D'Amore HMESYNCRMD(rxptr, DDI_DMA_SYNC_FORDEV);
31690219346bSGarrett D'Amore
31700219346bSGarrett D'Amore if (mp != NULL) {
31710219346bSGarrett D'Amore *tail = mp;
31720219346bSGarrett D'Amore tail = &mp->b_next;
31730219346bSGarrett D'Amore }
31740219346bSGarrett D'Amore
31750219346bSGarrett D'Amore /*
31760219346bSGarrett D'Amore * Advance to the next RMD.
31770219346bSGarrett D'Amore */
31780219346bSGarrett D'Amore hmep->hme_rxindex++;
31790219346bSGarrett D'Amore }
31800219346bSGarrett D'Amore }
31810219346bSGarrett D'Amore
31820219346bSGarrett D'Amore if (hmep->hme_intrstats)
31830219346bSGarrett D'Amore KIOIP->intrs[KSTAT_INTR_HARD]++;
31840219346bSGarrett D'Amore
31850219346bSGarrett D'Amore mutex_exit(&hmep->hme_intrlock);
31860219346bSGarrett D'Amore
31870219346bSGarrett D'Amore if (head != NULL)
31880219346bSGarrett D'Amore mac_rx(hmep->hme_mh, NULL, head);
31890219346bSGarrett D'Amore
31900219346bSGarrett D'Amore return (serviced);
31910219346bSGarrett D'Amore }
31920219346bSGarrett D'Amore
31930219346bSGarrett D'Amore /*
31940219346bSGarrett D'Amore * Transmit completion reclaiming.
31950219346bSGarrett D'Amore */
31960219346bSGarrett D'Amore static void
hmereclaim(struct hme * hmep)31970219346bSGarrett D'Amore hmereclaim(struct hme *hmep)
31980219346bSGarrett D'Amore {
31990219346bSGarrett D'Amore boolean_t reclaimed = B_FALSE;
32000219346bSGarrett D'Amore
32010219346bSGarrett D'Amore /*
32020219346bSGarrett D'Amore * Loop through each TMD.
32030219346bSGarrett D'Amore */
32040219346bSGarrett D'Amore while (hmep->hme_txindex > hmep->hme_txreclaim) {
32050219346bSGarrett D'Amore
32060219346bSGarrett D'Amore int reclaim;
32070219346bSGarrett D'Amore uint32_t flags;
32080219346bSGarrett D'Amore
32090219346bSGarrett D'Amore reclaim = hmep->hme_txreclaim % HME_TMDMAX;
32100219346bSGarrett D'Amore HMESYNCTMD(reclaim, DDI_DMA_SYNC_FORKERNEL);
32110219346bSGarrett D'Amore
32120219346bSGarrett D'Amore flags = GET_TMD_FLAGS(reclaim);
32130219346bSGarrett D'Amore if (flags & HMETMD_OWN) {
32140219346bSGarrett D'Amore /*
32150219346bSGarrett D'Amore * Chip still owns it. We're done.
32160219346bSGarrett D'Amore */
32170219346bSGarrett D'Amore break;
32180219346bSGarrett D'Amore }
32190219346bSGarrett D'Amore
32200219346bSGarrett D'Amore /*
32210219346bSGarrett D'Amore * Count a chained packet only once.
32220219346bSGarrett D'Amore */
32230219346bSGarrett D'Amore if (flags & HMETMD_SOP) {
32240219346bSGarrett D'Amore hmep->hme_opackets++;
32250219346bSGarrett D'Amore }
32260219346bSGarrett D'Amore
32270219346bSGarrett D'Amore /*
32280219346bSGarrett D'Amore * MIB II
32290219346bSGarrett D'Amore */
32300219346bSGarrett D'Amore hmep->hme_obytes += flags & HMETMD_BUFSIZE;
32310219346bSGarrett D'Amore
32320219346bSGarrett D'Amore reclaimed = B_TRUE;
32330219346bSGarrett D'Amore hmep->hme_txreclaim++;
32340219346bSGarrett D'Amore }
32350219346bSGarrett D'Amore
32360219346bSGarrett D'Amore if (reclaimed) {
32370219346bSGarrett D'Amore /*
32380219346bSGarrett D'Amore * we could reclaim some TMDs so turn off interrupts
32390219346bSGarrett D'Amore */
32400219346bSGarrett D'Amore if (hmep->hme_wantw) {
32410219346bSGarrett D'Amore PUT_GLOBREG(intmask,
32420219346bSGarrett D'Amore HMEG_MASK_INTR | HMEG_MASK_TINT |
32430219346bSGarrett D'Amore HMEG_MASK_TX_ALL);
32440219346bSGarrett D'Amore hmep->hme_wantw = B_FALSE;
32450219346bSGarrett D'Amore mac_tx_update(hmep->hme_mh);
32460219346bSGarrett D'Amore }
32470219346bSGarrett D'Amore } else {
32480219346bSGarrett D'Amore /*
32490219346bSGarrett D'Amore * enable TINTS: so that even if there is no further activity
32500219346bSGarrett D'Amore * hmereclaim will get called
32510219346bSGarrett D'Amore */
32520219346bSGarrett D'Amore if (hmep->hme_wantw)
32530219346bSGarrett D'Amore PUT_GLOBREG(intmask,
32540219346bSGarrett D'Amore GET_GLOBREG(intmask) & ~HMEG_MASK_TX_ALL);
32550219346bSGarrett D'Amore }
32560219346bSGarrett D'Amore CHECK_GLOBREG();
32570219346bSGarrett D'Amore }
32580219346bSGarrett D'Amore
32590219346bSGarrett D'Amore /*
32600219346bSGarrett D'Amore * Handle interrupts for fatal errors
32610219346bSGarrett D'Amore * Need reinitialization of the ENET channel.
32620219346bSGarrett D'Amore */
32630219346bSGarrett D'Amore static void
hme_fatal_err(struct hme * hmep,uint_t hmesbits)32640219346bSGarrett D'Amore hme_fatal_err(struct hme *hmep, uint_t hmesbits)
32650219346bSGarrett D'Amore {
32660219346bSGarrett D'Amore
32670219346bSGarrett D'Amore if (hmesbits & HMEG_STATUS_SLV_PAR_ERR) {
32680219346bSGarrett D'Amore hmep->hme_slvparerr++;
32690219346bSGarrett D'Amore }
32700219346bSGarrett D'Amore
32710219346bSGarrett D'Amore if (hmesbits & HMEG_STATUS_SLV_ERR_ACK) {
32720219346bSGarrett D'Amore hmep->hme_slverrack++;
32730219346bSGarrett D'Amore }
32740219346bSGarrett D'Amore
32750219346bSGarrett D'Amore if (hmesbits & HMEG_STATUS_TX_TAG_ERR) {
32760219346bSGarrett D'Amore hmep->hme_txtagerr++;
32770219346bSGarrett D'Amore hmep->hme_oerrors++;
32780219346bSGarrett D'Amore }
32790219346bSGarrett D'Amore
32800219346bSGarrett D'Amore if (hmesbits & HMEG_STATUS_TX_PAR_ERR) {
32810219346bSGarrett D'Amore hmep->hme_txparerr++;
32820219346bSGarrett D'Amore hmep->hme_oerrors++;
32830219346bSGarrett D'Amore }
32840219346bSGarrett D'Amore
32850219346bSGarrett D'Amore if (hmesbits & HMEG_STATUS_TX_LATE_ERR) {
32860219346bSGarrett D'Amore hmep->hme_txlaterr++;
32870219346bSGarrett D'Amore hmep->hme_oerrors++;
32880219346bSGarrett D'Amore }
32890219346bSGarrett D'Amore
32900219346bSGarrett D'Amore if (hmesbits & HMEG_STATUS_TX_ERR_ACK) {
32910219346bSGarrett D'Amore hmep->hme_txerrack++;
32920219346bSGarrett D'Amore hmep->hme_oerrors++;
32930219346bSGarrett D'Amore }
32940219346bSGarrett D'Amore
32950219346bSGarrett D'Amore if (hmesbits & HMEG_STATUS_EOP_ERR) {
32960219346bSGarrett D'Amore hmep->hme_eoperr++;
32970219346bSGarrett D'Amore }
32980219346bSGarrett D'Amore
32990219346bSGarrett D'Amore if (hmesbits & HMEG_STATUS_RX_TAG_ERR) {
33000219346bSGarrett D'Amore hmep->hme_rxtagerr++;
33010219346bSGarrett D'Amore hmep->hme_ierrors++;
33020219346bSGarrett D'Amore }
33030219346bSGarrett D'Amore
33040219346bSGarrett D'Amore if (hmesbits & HMEG_STATUS_RX_PAR_ERR) {
33050219346bSGarrett D'Amore hmep->hme_rxparerr++;
33060219346bSGarrett D'Amore hmep->hme_ierrors++;
33070219346bSGarrett D'Amore }
33080219346bSGarrett D'Amore
33090219346bSGarrett D'Amore if (hmesbits & HMEG_STATUS_RX_LATE_ERR) {
33100219346bSGarrett D'Amore hmep->hme_rxlaterr++;
33110219346bSGarrett D'Amore hmep->hme_ierrors++;
33120219346bSGarrett D'Amore }
33130219346bSGarrett D'Amore
33140219346bSGarrett D'Amore if (hmesbits & HMEG_STATUS_RX_ERR_ACK) {
33150219346bSGarrett D'Amore hmep->hme_rxerrack++;
33160219346bSGarrett D'Amore hmep->hme_ierrors++;
33170219346bSGarrett D'Amore }
33180219346bSGarrett D'Amore }
33190219346bSGarrett D'Amore
33200219346bSGarrett D'Amore /*
33210219346bSGarrett D'Amore * Handle interrupts regarding non-fatal errors.
33220219346bSGarrett D'Amore */
33230219346bSGarrett D'Amore static void
hme_nonfatal_err(struct hme * hmep,uint_t hmesbits)33240219346bSGarrett D'Amore hme_nonfatal_err(struct hme *hmep, uint_t hmesbits)
33250219346bSGarrett D'Amore {
33260219346bSGarrett D'Amore
33270219346bSGarrett D'Amore if (hmesbits & HMEG_STATUS_RX_DROP) {
33280219346bSGarrett D'Amore hmep->hme_missed++;
33290219346bSGarrett D'Amore hmep->hme_ierrors++;
33300219346bSGarrett D'Amore }
33310219346bSGarrett D'Amore
33320219346bSGarrett D'Amore if (hmesbits & HMEG_STATUS_DEFTIMR_EXP) {
33330219346bSGarrett D'Amore hmep->hme_defer_xmts++;
33340219346bSGarrett D'Amore }
33350219346bSGarrett D'Amore
33360219346bSGarrett D'Amore if (hmesbits & HMEG_STATUS_FSTCOLC_EXP) {
33370219346bSGarrett D'Amore hmep->hme_fstcol += 256;
33380219346bSGarrett D'Amore }
33390219346bSGarrett D'Amore
33400219346bSGarrett D'Amore if (hmesbits & HMEG_STATUS_LATCOLC_EXP) {
33410219346bSGarrett D'Amore hmep->hme_tlcol += 256;
33420219346bSGarrett D'Amore hmep->hme_oerrors += 256;
33430219346bSGarrett D'Amore }
33440219346bSGarrett D'Amore
33450219346bSGarrett D'Amore if (hmesbits & HMEG_STATUS_EXCOLC_EXP) {
33460219346bSGarrett D'Amore hmep->hme_excol += 256;
33470219346bSGarrett D'Amore hmep->hme_oerrors += 256;
33480219346bSGarrett D'Amore }
33490219346bSGarrett D'Amore
33500219346bSGarrett D'Amore if (hmesbits & HMEG_STATUS_NRMCOLC_EXP) {
33510219346bSGarrett D'Amore hmep->hme_coll += 256;
33520219346bSGarrett D'Amore }
33530219346bSGarrett D'Amore
33540219346bSGarrett D'Amore if (hmesbits & HMEG_STATUS_MXPKTSZ_ERR) {
33550219346bSGarrett D'Amore hmep->hme_babl++;
33560219346bSGarrett D'Amore hmep->hme_oerrors++;
33570219346bSGarrett D'Amore }
33580219346bSGarrett D'Amore
33590219346bSGarrett D'Amore /*
33600219346bSGarrett D'Amore * This error is fatal and the board needs to
33610219346bSGarrett D'Amore * be reinitialized. Comments?
33620219346bSGarrett D'Amore */
33630219346bSGarrett D'Amore if (hmesbits & HMEG_STATUS_TXFIFO_UNDR) {
33640219346bSGarrett D'Amore hmep->hme_uflo++;
33650219346bSGarrett D'Amore hmep->hme_oerrors++;
33660219346bSGarrett D'Amore }
33670219346bSGarrett D'Amore
33680219346bSGarrett D'Amore if (hmesbits & HMEG_STATUS_SQE_TST_ERR) {
33690219346bSGarrett D'Amore hmep->hme_sqe_errors++;
33700219346bSGarrett D'Amore }
33710219346bSGarrett D'Amore
33720219346bSGarrett D'Amore if (hmesbits & HMEG_STATUS_RCV_CNT_EXP) {
33730219346bSGarrett D'Amore if (hmep->hme_rxcv_enable) {
33740219346bSGarrett D'Amore hmep->hme_cvc += 256;
33750219346bSGarrett D'Amore }
33760219346bSGarrett D'Amore }
33770219346bSGarrett D'Amore
33780219346bSGarrett D'Amore if (hmesbits & HMEG_STATUS_RXFIFO_OVFL) {
33790219346bSGarrett D'Amore hmep->hme_oflo++;
33800219346bSGarrett D'Amore hmep->hme_ierrors++;
33810219346bSGarrett D'Amore }
33820219346bSGarrett D'Amore
33830219346bSGarrett D'Amore if (hmesbits & HMEG_STATUS_LEN_CNT_EXP) {
33840219346bSGarrett D'Amore hmep->hme_lenerr += 256;
33850219346bSGarrett D'Amore hmep->hme_ierrors += 256;
33860219346bSGarrett D'Amore }
33870219346bSGarrett D'Amore
33880219346bSGarrett D'Amore if (hmesbits & HMEG_STATUS_ALN_CNT_EXP) {
33890219346bSGarrett D'Amore hmep->hme_align_errors += 256;
33900219346bSGarrett D'Amore hmep->hme_ierrors += 256;
33910219346bSGarrett D'Amore }
33920219346bSGarrett D'Amore
33930219346bSGarrett D'Amore if (hmesbits & HMEG_STATUS_CRC_CNT_EXP) {
33940219346bSGarrett D'Amore hmep->hme_fcs_errors += 256;
33950219346bSGarrett D'Amore hmep->hme_ierrors += 256;
33960219346bSGarrett D'Amore }
33970219346bSGarrett D'Amore }
33980219346bSGarrett D'Amore
33990219346bSGarrett D'Amore static mblk_t *
hmeread(struct hme * hmep,hmebuf_t * rbuf,uint32_t rflags)34000219346bSGarrett D'Amore hmeread(struct hme *hmep, hmebuf_t *rbuf, uint32_t rflags)
34010219346bSGarrett D'Amore {
34020219346bSGarrett D'Amore mblk_t *bp;
34030219346bSGarrett D'Amore uint32_t len;
34040219346bSGarrett D'Amore t_uscalar_t type;
34050219346bSGarrett D'Amore
34060219346bSGarrett D'Amore len = (rflags & HMERMD_BUFSIZE) >> HMERMD_BUFSIZE_SHIFT;
34070219346bSGarrett D'Amore
34080219346bSGarrett D'Amore /*
34090219346bSGarrett D'Amore * Check for short packet
34100219346bSGarrett D'Amore * and check for overflow packet also. The processing is the
34110219346bSGarrett D'Amore * same for both the cases - reuse the buffer. Update the Buffer
34120219346bSGarrett D'Amore * overflow counter.
34130219346bSGarrett D'Amore */
34140219346bSGarrett D'Amore if ((len < ETHERMIN) || (rflags & HMERMD_OVFLOW) ||
34150219346bSGarrett D'Amore (len > (ETHERMAX + 4))) {
34160219346bSGarrett D'Amore if (len < ETHERMIN)
34170219346bSGarrett D'Amore hmep->hme_runt++;
34180219346bSGarrett D'Amore
34190219346bSGarrett D'Amore else {
34200219346bSGarrett D'Amore hmep->hme_buff++;
34210219346bSGarrett D'Amore hmep->hme_toolong_errors++;
34220219346bSGarrett D'Amore }
34230219346bSGarrett D'Amore hmep->hme_ierrors++;
34240219346bSGarrett D'Amore return (NULL);
34250219346bSGarrett D'Amore }
34260219346bSGarrett D'Amore
34270219346bSGarrett D'Amore /*
34280219346bSGarrett D'Amore * Sync the received buffer before looking at it.
34290219346bSGarrett D'Amore */
34300219346bSGarrett D'Amore
34310219346bSGarrett D'Amore (void) ddi_dma_sync(rbuf->dmah, 0, 0, DDI_DMA_SYNC_FORKERNEL);
34320219346bSGarrett D'Amore
34330219346bSGarrett D'Amore /*
34340219346bSGarrett D'Amore * copy the packet data and then recycle the descriptor.
34350219346bSGarrett D'Amore */
34360219346bSGarrett D'Amore
34370219346bSGarrett D'Amore if ((bp = allocb(len + HME_FSTBYTE_OFFSET, BPRI_HI)) == NULL) {
34380219346bSGarrett D'Amore
34390219346bSGarrett D'Amore hmep->hme_allocbfail++;
34400219346bSGarrett D'Amore hmep->hme_norcvbuf++;
34410219346bSGarrett D'Amore
34420219346bSGarrett D'Amore return (NULL);
34430219346bSGarrett D'Amore }
34440219346bSGarrett D'Amore
34450219346bSGarrett D'Amore bcopy(rbuf->kaddr, bp->b_rptr, len + HME_FSTBYTE_OFFSET);
34460219346bSGarrett D'Amore
34470219346bSGarrett D'Amore hmep->hme_ipackets++;
34480219346bSGarrett D'Amore
34490219346bSGarrett D'Amore /* Add the First Byte offset to the b_rptr and copy */
34500219346bSGarrett D'Amore bp->b_rptr += HME_FSTBYTE_OFFSET;
34510219346bSGarrett D'Amore bp->b_wptr = bp->b_rptr + len;
34520219346bSGarrett D'Amore
34530219346bSGarrett D'Amore /*
34540219346bSGarrett D'Amore * update MIB II statistics
34550219346bSGarrett D'Amore */
34560219346bSGarrett D'Amore BUMP_InNUcast(hmep, bp->b_rptr);
34570219346bSGarrett D'Amore hmep->hme_rbytes += len;
34580219346bSGarrett D'Amore
34590219346bSGarrett D'Amore type = get_ether_type(bp->b_rptr);
34600219346bSGarrett D'Amore
34610219346bSGarrett D'Amore /*
34620219346bSGarrett D'Amore * TCP partial checksum in hardware
34630219346bSGarrett D'Amore */
34640219346bSGarrett D'Amore if (type == ETHERTYPE_IP || type == ETHERTYPE_IPV6) {
34650219346bSGarrett D'Amore uint16_t cksum = ~rflags & HMERMD_CKSUM;
34660219346bSGarrett D'Amore uint_t end = len - sizeof (struct ether_header);
34670dc2366fSVenugopal Iyer mac_hcksum_set(bp, 0, 0, end, htons(cksum), HCK_PARTIALCKSUM);
34680219346bSGarrett D'Amore }
34690219346bSGarrett D'Amore
34700219346bSGarrett D'Amore return (bp);
34710219346bSGarrett D'Amore }
34720219346bSGarrett D'Amore
34730219346bSGarrett D'Amore /*VARARGS*/
34740219346bSGarrett D'Amore static void
hme_fault_msg(struct hme * hmep,uint_t severity,msg_t type,char * fmt,...)34750219346bSGarrett D'Amore hme_fault_msg(struct hme *hmep, uint_t severity, msg_t type, char *fmt, ...)
34760219346bSGarrett D'Amore {
34770219346bSGarrett D'Amore char msg_buffer[255];
34780219346bSGarrett D'Amore va_list ap;
34790219346bSGarrett D'Amore
34800219346bSGarrett D'Amore va_start(ap, fmt);
34810219346bSGarrett D'Amore (void) vsnprintf(msg_buffer, sizeof (msg_buffer), fmt, ap);
34820219346bSGarrett D'Amore
34830219346bSGarrett D'Amore if (hmep == NULL) {
34840219346bSGarrett D'Amore cmn_err(CE_NOTE, "hme : %s", msg_buffer);
34850219346bSGarrett D'Amore
34860219346bSGarrett D'Amore } else if (type == DISPLAY_MSG) {
34870219346bSGarrett D'Amore cmn_err(CE_CONT, "?%s%d : %s\n", ddi_driver_name(hmep->dip),
34880219346bSGarrett D'Amore hmep->instance, msg_buffer);
34890219346bSGarrett D'Amore } else if (severity == SEVERITY_HIGH) {
34900219346bSGarrett D'Amore cmn_err(CE_WARN, "%s%d : %s, SEVERITY_HIGH, %s\n",
34910219346bSGarrett D'Amore ddi_driver_name(hmep->dip), hmep->instance,
34920219346bSGarrett D'Amore msg_buffer, msg_string[type]);
34930219346bSGarrett D'Amore } else {
34940219346bSGarrett D'Amore cmn_err(CE_CONT, "%s%d : %s\n", ddi_driver_name(hmep->dip),
34950219346bSGarrett D'Amore hmep->instance, msg_buffer);
34960219346bSGarrett D'Amore }
34970219346bSGarrett D'Amore va_end(ap);
34980219346bSGarrett D'Amore }
34990219346bSGarrett D'Amore
35000219346bSGarrett D'Amore /*
35010219346bSGarrett D'Amore * if this is the first init do not bother to save the
35020219346bSGarrett D'Amore * counters. They should be 0, but do not count on it.
35030219346bSGarrett D'Amore */
35040219346bSGarrett D'Amore static void
hmesavecntrs(struct hme * hmep)35050219346bSGarrett D'Amore hmesavecntrs(struct hme *hmep)
35060219346bSGarrett D'Amore {
35070219346bSGarrett D'Amore uint32_t fecnt, aecnt, lecnt, rxcv;
35080219346bSGarrett D'Amore uint32_t ltcnt, excnt;
35090219346bSGarrett D'Amore
35100219346bSGarrett D'Amore /* XXX What all gets added in ierrors and oerrors? */
35110219346bSGarrett D'Amore fecnt = GET_MACREG(fecnt);
35120219346bSGarrett D'Amore PUT_MACREG(fecnt, 0);
35130219346bSGarrett D'Amore
35140219346bSGarrett D'Amore aecnt = GET_MACREG(aecnt);
35150219346bSGarrett D'Amore hmep->hme_align_errors += aecnt;
35160219346bSGarrett D'Amore PUT_MACREG(aecnt, 0);
35170219346bSGarrett D'Amore
35180219346bSGarrett D'Amore lecnt = GET_MACREG(lecnt);
35190219346bSGarrett D'Amore hmep->hme_lenerr += lecnt;
35200219346bSGarrett D'Amore PUT_MACREG(lecnt, 0);
35210219346bSGarrett D'Amore
35220219346bSGarrett D'Amore rxcv = GET_MACREG(rxcv);
35230219346bSGarrett D'Amore #ifdef HME_CODEVIOL_BUG
35240219346bSGarrett D'Amore /*
35250219346bSGarrett D'Amore * Ignore rxcv errors for Sbus/FEPS 2.1 or earlier
35260219346bSGarrett D'Amore */
35270219346bSGarrett D'Amore if (!hmep->hme_rxcv_enable) {
35280219346bSGarrett D'Amore rxcv = 0;
35290219346bSGarrett D'Amore }
35300219346bSGarrett D'Amore #endif
35310219346bSGarrett D'Amore hmep->hme_cvc += rxcv;
35320219346bSGarrett D'Amore PUT_MACREG(rxcv, 0);
35330219346bSGarrett D'Amore
35340219346bSGarrett D'Amore ltcnt = GET_MACREG(ltcnt);
35350219346bSGarrett D'Amore hmep->hme_tlcol += ltcnt;
35360219346bSGarrett D'Amore PUT_MACREG(ltcnt, 0);
35370219346bSGarrett D'Amore
35380219346bSGarrett D'Amore excnt = GET_MACREG(excnt);
35390219346bSGarrett D'Amore hmep->hme_excol += excnt;
35400219346bSGarrett D'Amore PUT_MACREG(excnt, 0);
35410219346bSGarrett D'Amore
35420219346bSGarrett D'Amore hmep->hme_fcs_errors += fecnt;
35430219346bSGarrett D'Amore hmep->hme_ierrors += (fecnt + aecnt + lecnt);
35440219346bSGarrett D'Amore hmep->hme_oerrors += (ltcnt + excnt);
35450219346bSGarrett D'Amore hmep->hme_coll += (GET_MACREG(nccnt) + ltcnt);
35460219346bSGarrett D'Amore
35470219346bSGarrett D'Amore PUT_MACREG(nccnt, 0);
35480219346bSGarrett D'Amore CHECK_MACREG();
35490219346bSGarrett D'Amore }
35500219346bSGarrett D'Amore
35510219346bSGarrett D'Amore /*
35520219346bSGarrett D'Amore * To set up the mac address for the network interface:
35530219346bSGarrett D'Amore * The adapter card may support a local mac address which is published
35540219346bSGarrett D'Amore * in a device node property "local-mac-address". This mac address is
35550219346bSGarrett D'Amore * treated as the factory-installed mac address for DLPI interface.
35560219346bSGarrett D'Amore * If the adapter firmware has used the device for diskless boot
35570219346bSGarrett D'Amore * operation it publishes a property called "mac-address" for use by
35580219346bSGarrett D'Amore * inetboot and the device driver.
35590219346bSGarrett D'Amore * If "mac-address" is not found, the system options property
35600219346bSGarrett D'Amore * "local-mac-address" is used to select the mac-address. If this option
35610219346bSGarrett D'Amore * is set to "true", and "local-mac-address" has been found, then
35620219346bSGarrett D'Amore * local-mac-address is used; otherwise the system mac address is used
35630219346bSGarrett D'Amore * by calling the "localetheraddr()" function.
35640219346bSGarrett D'Amore */
35650219346bSGarrett D'Amore static void
hme_setup_mac_address(struct hme * hmep,dev_info_t * dip)35660219346bSGarrett D'Amore hme_setup_mac_address(struct hme *hmep, dev_info_t *dip)
35670219346bSGarrett D'Amore {
35680219346bSGarrett D'Amore char *prop;
35690219346bSGarrett D'Amore int prop_len = sizeof (int);
35700219346bSGarrett D'Amore
35710219346bSGarrett D'Amore hmep->hme_addrflags = 0;
35720219346bSGarrett D'Amore
35730219346bSGarrett D'Amore /*
35740219346bSGarrett D'Amore * Check if it is an adapter with its own local mac address
35750219346bSGarrett D'Amore * If it is present, save it as the "factory-address"
35760219346bSGarrett D'Amore * for this adapter.
35770219346bSGarrett D'Amore */
35780219346bSGarrett D'Amore if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
35790219346bSGarrett D'Amore "local-mac-address",
35800219346bSGarrett D'Amore (caddr_t)&prop, &prop_len) == DDI_PROP_SUCCESS) {
35810219346bSGarrett D'Amore if (prop_len == ETHERADDRL) {
35820219346bSGarrett D'Amore hmep->hme_addrflags = HME_FACTADDR_PRESENT;
35830219346bSGarrett D'Amore ether_bcopy(prop, &hmep->hme_factaddr);
35840219346bSGarrett D'Amore HME_FAULT_MSG2(hmep, SEVERITY_NONE, DISPLAY_MSG,
35850219346bSGarrett D'Amore "Local Ethernet address = %s",
35860219346bSGarrett D'Amore ether_sprintf(&hmep->hme_factaddr));
35870219346bSGarrett D'Amore }
35880219346bSGarrett D'Amore kmem_free(prop, prop_len);
35890219346bSGarrett D'Amore }
35900219346bSGarrett D'Amore
35910219346bSGarrett D'Amore /*
35920219346bSGarrett D'Amore * Check if the adapter has published "mac-address" property.
35930219346bSGarrett D'Amore * If it is present, use it as the mac address for this device.
35940219346bSGarrett D'Amore */
35950219346bSGarrett D'Amore if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
35960219346bSGarrett D'Amore "mac-address", (caddr_t)&prop, &prop_len) == DDI_PROP_SUCCESS) {
35970219346bSGarrett D'Amore if (prop_len >= ETHERADDRL) {
35980219346bSGarrett D'Amore ether_bcopy(prop, &hmep->hme_ouraddr);
35990219346bSGarrett D'Amore kmem_free(prop, prop_len);
36000219346bSGarrett D'Amore return;
36010219346bSGarrett D'Amore }
36020219346bSGarrett D'Amore kmem_free(prop, prop_len);
36030219346bSGarrett D'Amore }
36040219346bSGarrett D'Amore
36050219346bSGarrett D'Amore #ifdef __sparc
36060219346bSGarrett D'Amore /*
36070219346bSGarrett D'Amore * On sparc, we might be able to use the mac address from the
36080219346bSGarrett D'Amore * system. However, on all other systems, we need to use the
36090219346bSGarrett D'Amore * address from the PROM.
36100219346bSGarrett D'Amore */
36110219346bSGarrett D'Amore if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 0, "local-mac-address?",
36120219346bSGarrett D'Amore (caddr_t)&prop, &prop_len) == DDI_PROP_SUCCESS) {
36130219346bSGarrett D'Amore if ((strncmp("true", prop, prop_len) == 0) &&
36140219346bSGarrett D'Amore (hmep->hme_addrflags & HME_FACTADDR_PRESENT)) {
36150219346bSGarrett D'Amore hmep->hme_addrflags |= HME_FACTADDR_USE;
36160219346bSGarrett D'Amore ether_bcopy(&hmep->hme_factaddr, &hmep->hme_ouraddr);
36170219346bSGarrett D'Amore kmem_free(prop, prop_len);
36180219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_NONE, DISPLAY_MSG,
36190219346bSGarrett D'Amore "Using local MAC address");
36200219346bSGarrett D'Amore return;
36210219346bSGarrett D'Amore }
36220219346bSGarrett D'Amore kmem_free(prop, prop_len);
36230219346bSGarrett D'Amore }
36240219346bSGarrett D'Amore
36250219346bSGarrett D'Amore /*
36260219346bSGarrett D'Amore * Get the system ethernet address.
36270219346bSGarrett D'Amore */
36280219346bSGarrett D'Amore (void) localetheraddr((struct ether_addr *)NULL, &hmep->hme_ouraddr);
36290219346bSGarrett D'Amore #else
36300219346bSGarrett D'Amore ether_bcopy(&hmep->hme_factaddr, &hmep->hme_ouraddr);
36310219346bSGarrett D'Amore #endif
36320219346bSGarrett D'Amore }
36330219346bSGarrett D'Amore
36340219346bSGarrett D'Amore /* ARGSUSED */
36350219346bSGarrett D'Amore static void
hme_check_acc_handle(char * file,uint_t line,struct hme * hmep,ddi_acc_handle_t handle)36360219346bSGarrett D'Amore hme_check_acc_handle(char *file, uint_t line, struct hme *hmep,
36370219346bSGarrett D'Amore ddi_acc_handle_t handle)
36380219346bSGarrett D'Amore {
36390219346bSGarrett D'Amore }
3640