17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5447e4a63Spetede * Common Development and Distribution License (the "License"). 6447e4a63Spetede * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 220219346bSGarrett D'Amore * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate /* 287c478bd9Sstevel@tonic-gate * SunOS MT STREAMS FEPS(SBus)/Cheerio(PCI) 10/100Mb Ethernet Device Driver 297c478bd9Sstevel@tonic-gate */ 307c478bd9Sstevel@tonic-gate 317c478bd9Sstevel@tonic-gate #include <sys/types.h> 327c478bd9Sstevel@tonic-gate #include <sys/debug.h> 337c478bd9Sstevel@tonic-gate #include <sys/stream.h> 347c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 357c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 367c478bd9Sstevel@tonic-gate #include <sys/crc32.h> 3785025c03Sgd #include <sys/modctl.h> 3885025c03Sgd #include <sys/conf.h> 397c478bd9Sstevel@tonic-gate #include <sys/strsun.h> 407c478bd9Sstevel@tonic-gate #include <sys/kstat.h> 4185025c03Sgd #include <sys/pattr.h> 427c478bd9Sstevel@tonic-gate #include <sys/dlpi.h> 4385025c03Sgd #include <sys/strsubr.h> 44da14cebeSEric Cheng #include <sys/mac_provider.h> 4585025c03Sgd #include <sys/mac_ether.h> 46*06673d9bSGarrett D'Amore #include <sys/mii.h> 477c478bd9Sstevel@tonic-gate #include <sys/ethernet.h> 48d62bc4baSyz #include <sys/vlan.h> 4985025c03Sgd #include <sys/pci.h> 5085025c03Sgd #include <sys/policy.h> 5185025c03Sgd #include <sys/ddi.h> 5285025c03Sgd #include <sys/sunddi.h> 530219346bSGarrett D'Amore #include "hme_phy.h" 540219346bSGarrett D'Amore #include "hme_mac.h" 550219346bSGarrett D'Amore #include "hme.h" 567c478bd9Sstevel@tonic-gate 577c478bd9Sstevel@tonic-gate typedef void (*fptrv_t)(); 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate typedef enum { 607c478bd9Sstevel@tonic-gate NO_MSG = 0, 61*06673d9bSGarrett D'Amore AUTOCONFIG_MSG, 62*06673d9bSGarrett D'Amore DISPLAY_MSG, 63*06673d9bSGarrett D'Amore INIT_MSG, 64*06673d9bSGarrett D'Amore UNINIT_MSG, 65*06673d9bSGarrett D'Amore CONFIG_MSG, 66*06673d9bSGarrett D'Amore MII_MSG, 67*06673d9bSGarrett D'Amore FATAL_ERR_MSG, 68*06673d9bSGarrett D'Amore NFATAL_ERR_MSG, 69*06673d9bSGarrett D'Amore XCVR_MSG, 70*06673d9bSGarrett D'Amore NOXCVR_MSG, 71*06673d9bSGarrett D'Amore ERX_MSG, 72*06673d9bSGarrett D'Amore DDI_MSG, 737c478bd9Sstevel@tonic-gate } msg_t; 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate msg_t hme_debug_level = NO_MSG; 767c478bd9Sstevel@tonic-gate 777c478bd9Sstevel@tonic-gate static char *msg_string[] = { 787c478bd9Sstevel@tonic-gate "NONE ", 797c478bd9Sstevel@tonic-gate "AUTOCONFIG ", 80*06673d9bSGarrett D'Amore "DISPLAY " 817c478bd9Sstevel@tonic-gate "INIT ", 827c478bd9Sstevel@tonic-gate "UNINIT ", 837c478bd9Sstevel@tonic-gate "CONFIG ", 84*06673d9bSGarrett D'Amore "MII ", 857c478bd9Sstevel@tonic-gate "FATAL_ERR ", 867c478bd9Sstevel@tonic-gate "NFATAL_ERR ", 877c478bd9Sstevel@tonic-gate "XCVR ", 887c478bd9Sstevel@tonic-gate "NOXCVR ", 897c478bd9Sstevel@tonic-gate "ERX ", 907c478bd9Sstevel@tonic-gate "DDI ", 917c478bd9Sstevel@tonic-gate }; 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate #define SEVERITY_NONE 0 947c478bd9Sstevel@tonic-gate #define SEVERITY_LOW 0 957c478bd9Sstevel@tonic-gate #define SEVERITY_MID 1 967c478bd9Sstevel@tonic-gate #define SEVERITY_HIGH 2 977c478bd9Sstevel@tonic-gate #define SEVERITY_UNKNOWN 99 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate #define FEPS_URUN_BUG 1007c478bd9Sstevel@tonic-gate #define HME_CODEVIOL_BUG 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate #define KIOIP KSTAT_INTR_PTR(hmep->hme_intrstats) 1037c478bd9Sstevel@tonic-gate 1047c478bd9Sstevel@tonic-gate /* 1057c478bd9Sstevel@tonic-gate * The following variables are used for checking fixes in Sbus/FEPS 2.0 1067c478bd9Sstevel@tonic-gate */ 1077c478bd9Sstevel@tonic-gate static int hme_urun_fix = 0; /* Bug fixed in Sbus/FEPS 2.0 */ 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate /* 1107c478bd9Sstevel@tonic-gate * The following variables are used for configuring various features 1117c478bd9Sstevel@tonic-gate */ 1127c478bd9Sstevel@tonic-gate static int hme_64bit_enable = 1; /* Use 64-bit sbus transfers */ 1137c478bd9Sstevel@tonic-gate static int hme_reject_own = 1; /* Reject packets with own SA */ 114*06673d9bSGarrett D'Amore static int hme_ngu_enable = 0; /* Never Give Up mode */ 1157c478bd9Sstevel@tonic-gate 116*06673d9bSGarrett D'Amore mac_priv_prop_t hme_priv_prop[] = { 117*06673d9bSGarrett D'Amore { "_ipg0", MAC_PROP_PERM_RW }, 118*06673d9bSGarrett D'Amore { "_ipg1", MAC_PROP_PERM_RW }, 119*06673d9bSGarrett D'Amore { "_ipg2", MAC_PROP_PERM_RW }, 120*06673d9bSGarrett D'Amore { "_lance_mode", MAC_PROP_PERM_RW }, 121*06673d9bSGarrett D'Amore }; 1227c478bd9Sstevel@tonic-gate 1237c478bd9Sstevel@tonic-gate static int hme_lance_mode = 1; /* to enable lance mode */ 1247c478bd9Sstevel@tonic-gate static int hme_ipg0 = 16; 1257c478bd9Sstevel@tonic-gate static int hme_ipg1 = 8; 1267c478bd9Sstevel@tonic-gate static int hme_ipg2 = 4; 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate /* 1297c478bd9Sstevel@tonic-gate * The following parameters may be configured by the user. If they are not 1307c478bd9Sstevel@tonic-gate * configured by the user, the values will be based on the capabilities of 1317c478bd9Sstevel@tonic-gate * the transceiver. 1327c478bd9Sstevel@tonic-gate * The value "HME_NOTUSR" is ORed with the parameter value to indicate values 1337c478bd9Sstevel@tonic-gate * which are NOT configured by the user. 1347c478bd9Sstevel@tonic-gate */ 1357c478bd9Sstevel@tonic-gate 1367c478bd9Sstevel@tonic-gate #define HME_NOTUSR 0x0f000000 1377c478bd9Sstevel@tonic-gate #define HME_MASK_1BIT 0x1 1387c478bd9Sstevel@tonic-gate #define HME_MASK_5BIT 0x1f 1397c478bd9Sstevel@tonic-gate #define HME_MASK_8BIT 0xff 1407c478bd9Sstevel@tonic-gate 1417c478bd9Sstevel@tonic-gate /* 1427c478bd9Sstevel@tonic-gate * All strings used by hme messaging functions 1437c478bd9Sstevel@tonic-gate */ 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate static char *no_xcvr_msg = 1467c478bd9Sstevel@tonic-gate "No transceiver found."; 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate static char *burst_size_msg = 1497c478bd9Sstevel@tonic-gate "Could not identify the burst size"; 1507c478bd9Sstevel@tonic-gate 1517c478bd9Sstevel@tonic-gate static char *unk_rx_ringsz_msg = 1527c478bd9Sstevel@tonic-gate "Unknown receive RINGSZ"; 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate static char *add_intr_fail_msg = 1557c478bd9Sstevel@tonic-gate "ddi_add_intr(9F) failed"; 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate static char *mregs_4global_reg_fail_msg = 1587c478bd9Sstevel@tonic-gate "ddi_regs_map_setup(9F) for global reg failed"; 1597c478bd9Sstevel@tonic-gate 1607c478bd9Sstevel@tonic-gate static char *mregs_4etx_reg_fail_msg = 1617c478bd9Sstevel@tonic-gate "ddi_map_regs for etx reg failed"; 1627c478bd9Sstevel@tonic-gate 1637c478bd9Sstevel@tonic-gate static char *mregs_4erx_reg_fail_msg = 1647c478bd9Sstevel@tonic-gate "ddi_map_regs for erx reg failed"; 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate static char *mregs_4bmac_reg_fail_msg = 1677c478bd9Sstevel@tonic-gate "ddi_map_regs for bmac reg failed"; 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate static char *mregs_4mif_reg_fail_msg = 1707c478bd9Sstevel@tonic-gate "ddi_map_regs for mif reg failed"; 1717c478bd9Sstevel@tonic-gate 1727c478bd9Sstevel@tonic-gate static char *init_fail_gen_msg = 1737c478bd9Sstevel@tonic-gate "Failed to initialize hardware/driver"; 1747c478bd9Sstevel@tonic-gate 1757c478bd9Sstevel@tonic-gate static char *ddi_nregs_fail_msg = 1767c478bd9Sstevel@tonic-gate "ddi_dev_nregs failed(9F), returned %d"; 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate static char *bad_num_regs_msg = 1797c478bd9Sstevel@tonic-gate "Invalid number of registers."; 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate /* FATAL ERR msgs */ 1837c478bd9Sstevel@tonic-gate /* 1847c478bd9Sstevel@tonic-gate * Function prototypes. 1857c478bd9Sstevel@tonic-gate */ 186f2cd0f02Sgd /* these two are global so that qfe can use them */ 187f2cd0f02Sgd int hmeattach(dev_info_t *, ddi_attach_cmd_t); 188f2cd0f02Sgd int hmedetach(dev_info_t *, ddi_detach_cmd_t); 1890219346bSGarrett D'Amore int hmequiesce(dev_info_t *); 19085025c03Sgd static boolean_t hmeinit_xfer_params(struct hme *); 1917c478bd9Sstevel@tonic-gate static uint_t hmestop(struct hme *); 1927c478bd9Sstevel@tonic-gate static void hmestatinit(struct hme *); 1937c478bd9Sstevel@tonic-gate static int hmeallocthings(struct hme *); 1940219346bSGarrett D'Amore static void hmefreethings(struct hme *); 1950219346bSGarrett D'Amore static int hmeallocbuf(struct hme *, hmebuf_t *, int); 1960219346bSGarrett D'Amore static int hmeallocbufs(struct hme *); 1977c478bd9Sstevel@tonic-gate static void hmefreebufs(struct hme *); 1987c478bd9Sstevel@tonic-gate static void hmeget_hm_rev_property(struct hme *); 19985025c03Sgd static boolean_t hmestart(struct hme *, mblk_t *); 20085025c03Sgd static uint_t hmeintr(caddr_t); 2017c478bd9Sstevel@tonic-gate static void hmereclaim(struct hme *); 2027c478bd9Sstevel@tonic-gate static int hmeinit(struct hme *); 2037c478bd9Sstevel@tonic-gate static void hmeuninit(struct hme *hmep); 2040219346bSGarrett D'Amore static mblk_t *hmeread(struct hme *, hmebuf_t *, uint32_t); 2057c478bd9Sstevel@tonic-gate static void hmesavecntrs(struct hme *); 2067c478bd9Sstevel@tonic-gate static void hme_fatal_err(struct hme *, uint_t); 2077c478bd9Sstevel@tonic-gate static void hme_nonfatal_err(struct hme *, uint_t); 2087c478bd9Sstevel@tonic-gate static int hmeburstsizes(struct hme *); 209*06673d9bSGarrett D'Amore static void send_bit(struct hme *, uint16_t); 210*06673d9bSGarrett D'Amore static uint16_t get_bit_std(uint8_t, struct hme *); 211*06673d9bSGarrett D'Amore static uint16_t hme_bb_mii_read(struct hme *, uint8_t, uint8_t); 212*06673d9bSGarrett D'Amore static void hme_bb_mii_write(struct hme *, uint8_t, uint8_t, uint16_t); 2137c478bd9Sstevel@tonic-gate static void hme_bb_force_idle(struct hme *); 214*06673d9bSGarrett D'Amore static uint16_t hme_mii_read(void *, uint8_t, uint8_t); 215*06673d9bSGarrett D'Amore static void hme_mii_write(void *, uint8_t, uint8_t, uint16_t); 2167c478bd9Sstevel@tonic-gate static void hme_setup_mac_address(struct hme *, dev_info_t *); 217*06673d9bSGarrett D'Amore static void hme_mii_notify(void *, link_state_t); 2187c478bd9Sstevel@tonic-gate 2190219346bSGarrett D'Amore static void hme_fault_msg(struct hme *, uint_t, msg_t, char *, ...); 2207c478bd9Sstevel@tonic-gate 2217c478bd9Sstevel@tonic-gate static void hme_check_acc_handle(char *, uint_t, struct hme *, 22285025c03Sgd ddi_acc_handle_t); 2237c478bd9Sstevel@tonic-gate 22485025c03Sgd /* 22585025c03Sgd * Nemo (GLDv3) Functions. 22685025c03Sgd */ 22785025c03Sgd static int hme_m_stat(void *, uint_t, uint64_t *); 22885025c03Sgd static int hme_m_start(void *); 22985025c03Sgd static void hme_m_stop(void *); 23085025c03Sgd static int hme_m_promisc(void *, boolean_t); 23185025c03Sgd static int hme_m_multicst(void *, boolean_t, const uint8_t *); 23285025c03Sgd static int hme_m_unicst(void *, const uint8_t *); 23385025c03Sgd static mblk_t *hme_m_tx(void *, mblk_t *); 23485025c03Sgd static boolean_t hme_m_getcapab(void *, mac_capab_t, void *); 235*06673d9bSGarrett D'Amore static int hme_m_getprop(void *, const char *, mac_prop_id_t, uint_t, 236*06673d9bSGarrett D'Amore uint_t, void *, uint_t *); 237*06673d9bSGarrett D'Amore static int hme_m_setprop(void *, const char *, mac_prop_id_t, uint_t, 238*06673d9bSGarrett D'Amore const void *); 239*06673d9bSGarrett D'Amore 240*06673d9bSGarrett D'Amore static mii_ops_t hme_mii_ops = { 241*06673d9bSGarrett D'Amore MII_OPS_VERSION, 242*06673d9bSGarrett D'Amore hme_mii_read, 243*06673d9bSGarrett D'Amore hme_mii_write, 244*06673d9bSGarrett D'Amore hme_mii_notify, 245*06673d9bSGarrett D'Amore NULL 246*06673d9bSGarrett D'Amore }; 24785025c03Sgd 24885025c03Sgd static mac_callbacks_t hme_m_callbacks = { 249*06673d9bSGarrett D'Amore MC_GETCAPAB | MC_SETPROP | MC_GETPROP, 25085025c03Sgd hme_m_stat, 25185025c03Sgd hme_m_start, 25285025c03Sgd hme_m_stop, 25385025c03Sgd hme_m_promisc, 25485025c03Sgd hme_m_multicst, 25585025c03Sgd hme_m_unicst, 25685025c03Sgd hme_m_tx, 257*06673d9bSGarrett D'Amore NULL, 25885025c03Sgd hme_m_getcapab, 259*06673d9bSGarrett D'Amore NULL, 260*06673d9bSGarrett D'Amore NULL, 261*06673d9bSGarrett D'Amore hme_m_setprop, 262*06673d9bSGarrett D'Amore hme_m_getprop, 26385025c03Sgd }; 26485025c03Sgd 26585025c03Sgd DDI_DEFINE_STREAM_OPS(hme_dev_ops, nulldev, nulldev, hmeattach, hmedetach, 2660219346bSGarrett D'Amore nodev, NULL, D_MP, NULL, hmequiesce); 2677c478bd9Sstevel@tonic-gate 2687c478bd9Sstevel@tonic-gate #define HME_FAULT_MSG1(p, s, t, f) \ 2690219346bSGarrett D'Amore hme_fault_msg((p), (s), (t), (f)); 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate #define HME_FAULT_MSG2(p, s, t, f, a) \ 2720219346bSGarrett D'Amore hme_fault_msg((p), (s), (t), (f), (a)); 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate #define HME_FAULT_MSG3(p, s, t, f, a, b) \ 2750219346bSGarrett D'Amore hme_fault_msg((p), (s), (t), (f), (a), (b)); 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate #define HME_FAULT_MSG4(p, s, t, f, a, b, c) \ 2780219346bSGarrett D'Amore hme_fault_msg((p), (s), (t), (f), (a), (b), (c)); 2797c478bd9Sstevel@tonic-gate 2807c478bd9Sstevel@tonic-gate #define CHECK_MIFREG() \ 2817c478bd9Sstevel@tonic-gate hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_mifregh) 2827c478bd9Sstevel@tonic-gate #define CHECK_ETXREG() \ 2837c478bd9Sstevel@tonic-gate hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_etxregh) 2847c478bd9Sstevel@tonic-gate #define CHECK_ERXREG() \ 2857c478bd9Sstevel@tonic-gate hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_erxregh) 2867c478bd9Sstevel@tonic-gate #define CHECK_MACREG() \ 2877c478bd9Sstevel@tonic-gate hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_bmacregh) 2887c478bd9Sstevel@tonic-gate #define CHECK_GLOBREG() \ 2897c478bd9Sstevel@tonic-gate hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_globregh) 2907c478bd9Sstevel@tonic-gate 2917c478bd9Sstevel@tonic-gate /* 2927c478bd9Sstevel@tonic-gate * Claim the device is ultra-capable of burst in the beginning. Use 2937c478bd9Sstevel@tonic-gate * the value returned by ddi_dma_burstsizes() to actually set the HME 2947c478bd9Sstevel@tonic-gate * global configuration register later. 2957c478bd9Sstevel@tonic-gate * 2967c478bd9Sstevel@tonic-gate * Sbus/FEPS supports burst sizes of 16, 32 and 64 bytes. Also, it supports 2977c478bd9Sstevel@tonic-gate * 32-bit and 64-bit Sbus transfers. Hence the dlim_burstsizes field contains 2987c478bd9Sstevel@tonic-gate * the the burstsizes in both the lo and hi words. 2997c478bd9Sstevel@tonic-gate */ 3007c478bd9Sstevel@tonic-gate #define HMELIMADDRLO ((uint64_t)0x00000000) 3017c478bd9Sstevel@tonic-gate #define HMELIMADDRHI ((uint64_t)0xffffffff) 3027c478bd9Sstevel@tonic-gate 3030219346bSGarrett D'Amore /* 3040219346bSGarrett D'Amore * Note that rx and tx data buffers can be arbitrarily aligned, but 3050219346bSGarrett D'Amore * that the descriptor rings need to be aligned on 2K boundaries, per 3060219346bSGarrett D'Amore * the spec. 3070219346bSGarrett D'Amore */ 3087c478bd9Sstevel@tonic-gate static ddi_dma_attr_t hme_dma_attr = { 3097c478bd9Sstevel@tonic-gate DMA_ATTR_V0, /* version number. */ 3107c478bd9Sstevel@tonic-gate (uint64_t)HMELIMADDRLO, /* low address */ 3117c478bd9Sstevel@tonic-gate (uint64_t)HMELIMADDRHI, /* high address */ 3127c478bd9Sstevel@tonic-gate (uint64_t)0x00ffffff, /* address counter max */ 3130219346bSGarrett D'Amore (uint64_t)HME_HMDALIGN, /* alignment */ 3147c478bd9Sstevel@tonic-gate (uint_t)0x00700070, /* dlim_burstsizes for 32 and 64 bit xfers */ 3157c478bd9Sstevel@tonic-gate (uint32_t)0x1, /* minimum transfer size */ 3167c478bd9Sstevel@tonic-gate (uint64_t)0x7fffffff, /* maximum transfer size */ 3177c478bd9Sstevel@tonic-gate (uint64_t)0x00ffffff, /* maximum segment size */ 3187c478bd9Sstevel@tonic-gate 1, /* scatter/gather list length */ 3197c478bd9Sstevel@tonic-gate 512, /* granularity */ 3207c478bd9Sstevel@tonic-gate 0 /* attribute flags */ 3217c478bd9Sstevel@tonic-gate }; 3227c478bd9Sstevel@tonic-gate 3230219346bSGarrett D'Amore static ddi_device_acc_attr_t hme_buf_attr = { 3240219346bSGarrett D'Amore DDI_DEVICE_ATTR_V0, 3250219346bSGarrett D'Amore DDI_NEVERSWAP_ACC, 3260219346bSGarrett D'Amore DDI_STRICTORDER_ACC, /* probably could allow merging & caching */ 3270219346bSGarrett D'Amore DDI_DEFAULT_ACC, 3287c478bd9Sstevel@tonic-gate }; 3297c478bd9Sstevel@tonic-gate 3307c478bd9Sstevel@tonic-gate static uchar_t pci_latency_timer = 0; 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate /* 3337c478bd9Sstevel@tonic-gate * Module linkage information for the kernel. 3347c478bd9Sstevel@tonic-gate */ 3357c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 3367c478bd9Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a driver */ 33785025c03Sgd "Sun HME 10/100 Mb Ethernet", 33885025c03Sgd &hme_dev_ops, /* driver ops */ 3397c478bd9Sstevel@tonic-gate }; 3407c478bd9Sstevel@tonic-gate 3417c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 3427c478bd9Sstevel@tonic-gate MODREV_1, &modldrv, NULL 3437c478bd9Sstevel@tonic-gate }; 3447c478bd9Sstevel@tonic-gate 3457c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<<<<<<<<<<< Register operations >>>>>>>>>>>>>>>>>>>>> */ 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate #define GET_MIFREG(reg) \ 3487c478bd9Sstevel@tonic-gate ddi_get32(hmep->hme_mifregh, (uint32_t *)&hmep->hme_mifregp->reg) 3497c478bd9Sstevel@tonic-gate #define PUT_MIFREG(reg, value) \ 3507c478bd9Sstevel@tonic-gate ddi_put32(hmep->hme_mifregh, (uint32_t *)&hmep->hme_mifregp->reg, value) 3517c478bd9Sstevel@tonic-gate 3527c478bd9Sstevel@tonic-gate #define GET_ETXREG(reg) \ 3537c478bd9Sstevel@tonic-gate ddi_get32(hmep->hme_etxregh, (uint32_t *)&hmep->hme_etxregp->reg) 3547c478bd9Sstevel@tonic-gate #define PUT_ETXREG(reg, value) \ 3557c478bd9Sstevel@tonic-gate ddi_put32(hmep->hme_etxregh, (uint32_t *)&hmep->hme_etxregp->reg, value) 3567c478bd9Sstevel@tonic-gate #define GET_ERXREG(reg) \ 3577c478bd9Sstevel@tonic-gate ddi_get32(hmep->hme_erxregh, (uint32_t *)&hmep->hme_erxregp->reg) 3587c478bd9Sstevel@tonic-gate #define PUT_ERXREG(reg, value) \ 3597c478bd9Sstevel@tonic-gate ddi_put32(hmep->hme_erxregh, (uint32_t *)&hmep->hme_erxregp->reg, value) 3607c478bd9Sstevel@tonic-gate #define GET_MACREG(reg) \ 3617c478bd9Sstevel@tonic-gate ddi_get32(hmep->hme_bmacregh, (uint32_t *)&hmep->hme_bmacregp->reg) 3627c478bd9Sstevel@tonic-gate #define PUT_MACREG(reg, value) \ 3637c478bd9Sstevel@tonic-gate ddi_put32(hmep->hme_bmacregh, \ 3647c478bd9Sstevel@tonic-gate (uint32_t *)&hmep->hme_bmacregp->reg, value) 3657c478bd9Sstevel@tonic-gate #define GET_GLOBREG(reg) \ 3667c478bd9Sstevel@tonic-gate ddi_get32(hmep->hme_globregh, (uint32_t *)&hmep->hme_globregp->reg) 3677c478bd9Sstevel@tonic-gate #define PUT_GLOBREG(reg, value) \ 3687c478bd9Sstevel@tonic-gate ddi_put32(hmep->hme_globregh, \ 3697c478bd9Sstevel@tonic-gate (uint32_t *)&hmep->hme_globregp->reg, value) 3700219346bSGarrett D'Amore #define PUT_TMD(ptr, paddr, len, flags) \ 3710219346bSGarrett D'Amore ddi_put32(hmep->hme_tmd_acch, &hmep->hme_tmdp[ptr].tmd_addr, paddr); \ 3720219346bSGarrett D'Amore ddi_put32(hmep->hme_tmd_acch, &hmep->hme_tmdp[ptr].tmd_flags, \ 3730219346bSGarrett D'Amore len | flags) 3740219346bSGarrett D'Amore #define GET_TMD_FLAGS(ptr) \ 3750219346bSGarrett D'Amore ddi_get32(hmep->hme_tmd_acch, &hmep->hme_tmdp[ptr].tmd_flags) 3760219346bSGarrett D'Amore #define PUT_RMD(ptr, paddr) \ 3770219346bSGarrett D'Amore ddi_put32(hmep->hme_rmd_acch, &hmep->hme_rmdp[ptr].rmd_addr, paddr); \ 3780219346bSGarrett D'Amore ddi_put32(hmep->hme_rmd_acch, &hmep->hme_rmdp[ptr].rmd_flags, \ 3790219346bSGarrett D'Amore (uint32_t)(HMEBUFSIZE << HMERMD_BUFSIZE_SHIFT) | HMERMD_OWN) 3800219346bSGarrett D'Amore #define GET_RMD_FLAGS(ptr) \ 3810219346bSGarrett D'Amore ddi_get32(hmep->hme_rmd_acch, &hmep->hme_rmdp[ptr].rmd_flags) 3820219346bSGarrett D'Amore 3837c478bd9Sstevel@tonic-gate #define GET_ROM8(offset) \ 3847c478bd9Sstevel@tonic-gate ddi_get8((hmep->hme_romh), (offset)) 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate /* 3877c478bd9Sstevel@tonic-gate * Ether_copy is not endian-correct. Define an endian-correct version. 3887c478bd9Sstevel@tonic-gate */ 3897c478bd9Sstevel@tonic-gate #define ether_bcopy(a, b) (bcopy(a, b, 6)) 3907c478bd9Sstevel@tonic-gate 3917c478bd9Sstevel@tonic-gate /* 3927c478bd9Sstevel@tonic-gate * Ether-type is specifically big-endian, but data region is unknown endian 3937c478bd9Sstevel@tonic-gate */ 39485025c03Sgd #define get_ether_type(ptr) \ 39585025c03Sgd (((((uint8_t *)ptr)[12] << 8) | (((uint8_t *)ptr)[13]))) 3967c478bd9Sstevel@tonic-gate 3977c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<<<<<<<<<<< Configuration Parameters >>>>>>>>>>>>>>>>>>>>> */ 3987c478bd9Sstevel@tonic-gate 3997c478bd9Sstevel@tonic-gate #define BMAC_DEFAULT_JAMSIZE (0x04) /* jamsize equals 4 */ 4007c478bd9Sstevel@tonic-gate #define BMAC_LONG_JAMSIZE (0x10) /* jamsize equals 0x10 */ 4017c478bd9Sstevel@tonic-gate static int jamsize = BMAC_DEFAULT_JAMSIZE; 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate 4047c478bd9Sstevel@tonic-gate /* 4057c478bd9Sstevel@tonic-gate * Calculate the bit in the multicast address filter that selects the given 4067c478bd9Sstevel@tonic-gate * address. 4077c478bd9Sstevel@tonic-gate */ 4087c478bd9Sstevel@tonic-gate 4097c478bd9Sstevel@tonic-gate static uint32_t 41085025c03Sgd hmeladrf_bit(const uint8_t *addr) 4117c478bd9Sstevel@tonic-gate { 4127c478bd9Sstevel@tonic-gate uint32_t crc; 4137c478bd9Sstevel@tonic-gate 4147c478bd9Sstevel@tonic-gate CRC32(crc, addr, ETHERADDRL, -1U, crc32_table); 4157c478bd9Sstevel@tonic-gate 4167c478bd9Sstevel@tonic-gate /* 4177c478bd9Sstevel@tonic-gate * Just want the 6 most significant bits. 4187c478bd9Sstevel@tonic-gate */ 4197c478bd9Sstevel@tonic-gate return (crc >> 26); 4207c478bd9Sstevel@tonic-gate } 4217c478bd9Sstevel@tonic-gate 4227c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<<<<<<<<<<<<< Bit Bang Operations >>>>>>>>>>>>>>>>>>>>>>>> */ 4237c478bd9Sstevel@tonic-gate 4247c478bd9Sstevel@tonic-gate static void 425*06673d9bSGarrett D'Amore send_bit(struct hme *hmep, uint16_t x) 4267c478bd9Sstevel@tonic-gate { 4277c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbdata, x); 4287c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbclk, HME_BBCLK_LOW); 4297c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbclk, HME_BBCLK_HIGH); 4307c478bd9Sstevel@tonic-gate } 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate 4337c478bd9Sstevel@tonic-gate /* 4347c478bd9Sstevel@tonic-gate * To read the MII register bits according to the IEEE Standard 4357c478bd9Sstevel@tonic-gate */ 436*06673d9bSGarrett D'Amore static uint16_t 437*06673d9bSGarrett D'Amore get_bit_std(uint8_t phyad, struct hme *hmep) 4387c478bd9Sstevel@tonic-gate { 439*06673d9bSGarrett D'Amore uint16_t x; 4407c478bd9Sstevel@tonic-gate 4417c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbclk, HME_BBCLK_LOW); 4427c478bd9Sstevel@tonic-gate drv_usecwait(1); /* wait for >330 ns for stable data */ 443*06673d9bSGarrett D'Amore if (phyad == HME_INTERNAL_PHYAD) 4447c478bd9Sstevel@tonic-gate x = (GET_MIFREG(mif_cfg) & HME_MIF_CFGM0) ? 1 : 0; 4457c478bd9Sstevel@tonic-gate else 4467c478bd9Sstevel@tonic-gate x = (GET_MIFREG(mif_cfg) & HME_MIF_CFGM1) ? 1 : 0; 4477c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbclk, HME_BBCLK_HIGH); 4487c478bd9Sstevel@tonic-gate return (x); 4497c478bd9Sstevel@tonic-gate } 4507c478bd9Sstevel@tonic-gate 4517c478bd9Sstevel@tonic-gate #define SEND_BIT(x) send_bit(hmep, x) 452*06673d9bSGarrett D'Amore #define GET_BIT_STD(phyad, x) x = get_bit_std(phyad, hmep) 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate 4557c478bd9Sstevel@tonic-gate static void 456*06673d9bSGarrett D'Amore hme_bb_mii_write(struct hme *hmep, uint8_t phyad, uint8_t regad, uint16_t data) 4577c478bd9Sstevel@tonic-gate { 4587c478bd9Sstevel@tonic-gate int i; 4597c478bd9Sstevel@tonic-gate 4607c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbopenb, 1); /* Enable the MII driver */ 4617c478bd9Sstevel@tonic-gate (void) hme_bb_force_idle(hmep); 4627c478bd9Sstevel@tonic-gate SEND_BIT(0); SEND_BIT(1); /* <ST> */ 4637c478bd9Sstevel@tonic-gate SEND_BIT(0); SEND_BIT(1); /* <OP> */ 4647c478bd9Sstevel@tonic-gate 4657c478bd9Sstevel@tonic-gate for (i = 4; i >= 0; i--) { /* <AAAAA> */ 4667c478bd9Sstevel@tonic-gate SEND_BIT((phyad >> i) & 1); 4677c478bd9Sstevel@tonic-gate } 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate for (i = 4; i >= 0; i--) { /* <RRRRR> */ 4707c478bd9Sstevel@tonic-gate SEND_BIT((regad >> i) & 1); 4717c478bd9Sstevel@tonic-gate } 4727c478bd9Sstevel@tonic-gate 4737c478bd9Sstevel@tonic-gate SEND_BIT(1); SEND_BIT(0); /* <TA> */ 4747c478bd9Sstevel@tonic-gate 4757c478bd9Sstevel@tonic-gate for (i = 0xf; i >= 0; i--) { /* <DDDDDDDDDDDDDDDD> */ 4767c478bd9Sstevel@tonic-gate SEND_BIT((data >> i) & 1); 4777c478bd9Sstevel@tonic-gate } 4787c478bd9Sstevel@tonic-gate 4797c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbopenb, 0); /* Disable the MII driver */ 4807c478bd9Sstevel@tonic-gate CHECK_MIFREG(); 4817c478bd9Sstevel@tonic-gate } 4827c478bd9Sstevel@tonic-gate 4837c478bd9Sstevel@tonic-gate /* Return 0 if OK, 1 if error (Transceiver does not talk management) */ 484*06673d9bSGarrett D'Amore static uint16_t 485*06673d9bSGarrett D'Amore hme_bb_mii_read(struct hme *hmep, uint8_t phyad, uint8_t regad) 4867c478bd9Sstevel@tonic-gate { 4877c478bd9Sstevel@tonic-gate int i; 4887c478bd9Sstevel@tonic-gate uint32_t x; 489*06673d9bSGarrett D'Amore uint16_t data = 0; 4907c478bd9Sstevel@tonic-gate 4917c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbopenb, 1); /* Enable the MII driver */ 4927c478bd9Sstevel@tonic-gate (void) hme_bb_force_idle(hmep); 4937c478bd9Sstevel@tonic-gate SEND_BIT(0); SEND_BIT(1); /* <ST> */ 4947c478bd9Sstevel@tonic-gate SEND_BIT(1); SEND_BIT(0); /* <OP> */ 4957c478bd9Sstevel@tonic-gate for (i = 4; i >= 0; i--) { /* <AAAAA> */ 4967c478bd9Sstevel@tonic-gate SEND_BIT((phyad >> i) & 1); 4977c478bd9Sstevel@tonic-gate } 4987c478bd9Sstevel@tonic-gate for (i = 4; i >= 0; i--) { /* <RRRRR> */ 4997c478bd9Sstevel@tonic-gate SEND_BIT((regad >> i) & 1); 5007c478bd9Sstevel@tonic-gate } 5017c478bd9Sstevel@tonic-gate 5027c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbopenb, 0); /* Disable the MII driver */ 5037c478bd9Sstevel@tonic-gate 504*06673d9bSGarrett D'Amore GET_BIT_STD(phyad, x); 505*06673d9bSGarrett D'Amore GET_BIT_STD(phyad, x); /* <TA> */ 506*06673d9bSGarrett D'Amore for (i = 0xf; i >= 0; i--) { /* <DDDDDDDDDDDDDDDD> */ 507*06673d9bSGarrett D'Amore GET_BIT_STD(phyad, x); 508*06673d9bSGarrett D'Amore data += (x << i); 5097c478bd9Sstevel@tonic-gate } 510*06673d9bSGarrett D'Amore /* 511*06673d9bSGarrett D'Amore * Kludge to get the Transceiver out of hung mode 512*06673d9bSGarrett D'Amore */ 513*06673d9bSGarrett D'Amore GET_BIT_STD(phyad, x); 514*06673d9bSGarrett D'Amore GET_BIT_STD(phyad, x); 515*06673d9bSGarrett D'Amore GET_BIT_STD(phyad, x); 5167c478bd9Sstevel@tonic-gate CHECK_MIFREG(); 517*06673d9bSGarrett D'Amore return (data); 5187c478bd9Sstevel@tonic-gate } 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate 5217c478bd9Sstevel@tonic-gate static void 5227c478bd9Sstevel@tonic-gate hme_bb_force_idle(struct hme *hmep) 5237c478bd9Sstevel@tonic-gate { 5247c478bd9Sstevel@tonic-gate int i; 5257c478bd9Sstevel@tonic-gate 5267c478bd9Sstevel@tonic-gate for (i = 0; i < 33; i++) { 5277c478bd9Sstevel@tonic-gate SEND_BIT(1); 5287c478bd9Sstevel@tonic-gate } 5297c478bd9Sstevel@tonic-gate } 5307c478bd9Sstevel@tonic-gate 5317c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<<<<<<<<<End of Bit Bang Operations >>>>>>>>>>>>>>>>>>>>>>>> */ 5327c478bd9Sstevel@tonic-gate 5337c478bd9Sstevel@tonic-gate 5347c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<< Frame Register used for MII operations >>>>>>>>>>>>>>>>>>>> */ 5357c478bd9Sstevel@tonic-gate 5367c478bd9Sstevel@tonic-gate /* Return 0 if OK, 1 if error (Transceiver does not talk management) */ 537*06673d9bSGarrett D'Amore static uint16_t 538*06673d9bSGarrett D'Amore hme_mii_read(void *arg, uint8_t phyad, uint8_t regad) 5397c478bd9Sstevel@tonic-gate { 540*06673d9bSGarrett D'Amore struct hme *hmep = arg; 5417c478bd9Sstevel@tonic-gate uint32_t frame; 5427c478bd9Sstevel@tonic-gate 5437c478bd9Sstevel@tonic-gate if (!hmep->hme_frame_enable) 544*06673d9bSGarrett D'Amore return (hme_bb_mii_read(hmep, phyad, regad)); 5457c478bd9Sstevel@tonic-gate 5460219346bSGarrett D'Amore PUT_MIFREG(mif_frame, 5470219346bSGarrett D'Amore HME_MIF_FRREAD | (phyad << HME_MIF_FRPHYAD_SHIFT) | 5480219346bSGarrett D'Amore (regad << HME_MIF_FRREGAD_SHIFT)); 5497c478bd9Sstevel@tonic-gate /* 5507c478bd9Sstevel@tonic-gate * HMEDELAY((*framerp & HME_MIF_FRTA0), HMEMAXRSTDELAY); 5517c478bd9Sstevel@tonic-gate */ 5520219346bSGarrett D'Amore HMEDELAY((GET_MIFREG(mif_frame) & HME_MIF_FRTA0), 300); 5530219346bSGarrett D'Amore frame = GET_MIFREG(mif_frame); 5547c478bd9Sstevel@tonic-gate CHECK_MIFREG(); 5557c478bd9Sstevel@tonic-gate if ((frame & HME_MIF_FRTA0) == 0) { 5567c478bd9Sstevel@tonic-gate 5577c478bd9Sstevel@tonic-gate 558*06673d9bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, MII_MSG, 5590219346bSGarrett D'Amore "MIF Read failure"); 560*06673d9bSGarrett D'Amore return (0xffff); 5617c478bd9Sstevel@tonic-gate } 562*06673d9bSGarrett D'Amore return ((uint16_t)(frame & HME_MIF_FRDATA)); 5637c478bd9Sstevel@tonic-gate } 5647c478bd9Sstevel@tonic-gate 5657c478bd9Sstevel@tonic-gate static void 566*06673d9bSGarrett D'Amore hme_mii_write(void *arg, uint8_t phyad, uint8_t regad, uint16_t data) 5677c478bd9Sstevel@tonic-gate { 568*06673d9bSGarrett D'Amore struct hme *hmep = arg; 5697c478bd9Sstevel@tonic-gate uint32_t frame; 5707c478bd9Sstevel@tonic-gate 5717c478bd9Sstevel@tonic-gate if (!hmep->hme_frame_enable) { 572*06673d9bSGarrett D'Amore hme_bb_mii_write(hmep, phyad, regad, data); 5737c478bd9Sstevel@tonic-gate return; 5747c478bd9Sstevel@tonic-gate } 5757c478bd9Sstevel@tonic-gate 5760219346bSGarrett D'Amore PUT_MIFREG(mif_frame, 5770219346bSGarrett D'Amore HME_MIF_FRWRITE | (phyad << HME_MIF_FRPHYAD_SHIFT) | 5780219346bSGarrett D'Amore (regad << HME_MIF_FRREGAD_SHIFT) | data); 5797c478bd9Sstevel@tonic-gate /* 5807c478bd9Sstevel@tonic-gate * HMEDELAY((*framerp & HME_MIF_FRTA0), HMEMAXRSTDELAY); 5817c478bd9Sstevel@tonic-gate */ 5820219346bSGarrett D'Amore HMEDELAY((GET_MIFREG(mif_frame) & HME_MIF_FRTA0), 300); 5830219346bSGarrett D'Amore frame = GET_MIFREG(mif_frame); 5847c478bd9Sstevel@tonic-gate CHECK_MIFREG(); 5857c478bd9Sstevel@tonic-gate if ((frame & HME_MIF_FRTA0) == 0) { 586*06673d9bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_MID, MII_MSG, 5870219346bSGarrett D'Amore "MIF Write failure"); 5887c478bd9Sstevel@tonic-gate } 5897c478bd9Sstevel@tonic-gate } 5907c478bd9Sstevel@tonic-gate 5917c478bd9Sstevel@tonic-gate static void 592*06673d9bSGarrett D'Amore hme_mii_notify(void *arg, link_state_t link) 5937c478bd9Sstevel@tonic-gate { 5947c478bd9Sstevel@tonic-gate struct hme *hmep = arg; 5957c478bd9Sstevel@tonic-gate 596*06673d9bSGarrett D'Amore if (link == LINK_STATE_UP) { 597*06673d9bSGarrett D'Amore (void) hmeinit(hmep); 5987c478bd9Sstevel@tonic-gate } 599*06673d9bSGarrett D'Amore mac_link_update(hmep->hme_mh, link); 6007c478bd9Sstevel@tonic-gate } 6017c478bd9Sstevel@tonic-gate 6027c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<<<<<<<<<<<<<<<< LOADABLE ENTRIES >>>>>>>>>>>>>>>>>>>>>>> */ 6037c478bd9Sstevel@tonic-gate 6047c478bd9Sstevel@tonic-gate int 6057c478bd9Sstevel@tonic-gate _init(void) 6067c478bd9Sstevel@tonic-gate { 6077c478bd9Sstevel@tonic-gate int status; 6087c478bd9Sstevel@tonic-gate 60985025c03Sgd mac_init_ops(&hme_dev_ops, "hme"); 61085025c03Sgd if ((status = mod_install(&modlinkage)) != 0) { 61185025c03Sgd mac_fini_ops(&hme_dev_ops); 6127c478bd9Sstevel@tonic-gate } 6137c478bd9Sstevel@tonic-gate return (status); 6147c478bd9Sstevel@tonic-gate } 6157c478bd9Sstevel@tonic-gate 6167c478bd9Sstevel@tonic-gate int 6177c478bd9Sstevel@tonic-gate _fini(void) 6187c478bd9Sstevel@tonic-gate { 6197c478bd9Sstevel@tonic-gate int status; 6207c478bd9Sstevel@tonic-gate 62185025c03Sgd if ((status = mod_remove(&modlinkage)) == 0) { 62285025c03Sgd mac_fini_ops(&hme_dev_ops); 6237c478bd9Sstevel@tonic-gate } 6247c478bd9Sstevel@tonic-gate return (status); 6257c478bd9Sstevel@tonic-gate } 6267c478bd9Sstevel@tonic-gate 6277c478bd9Sstevel@tonic-gate int 6287c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 6297c478bd9Sstevel@tonic-gate { 6307c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 6317c478bd9Sstevel@tonic-gate } 6327c478bd9Sstevel@tonic-gate 6337c478bd9Sstevel@tonic-gate /* 6347c478bd9Sstevel@tonic-gate * ddi_dma_sync() a TMD or RMD descriptor. 6357c478bd9Sstevel@tonic-gate */ 6360219346bSGarrett D'Amore #define HMESYNCRMD(num, who) \ 6370219346bSGarrett D'Amore (void) ddi_dma_sync(hmep->hme_rmd_dmah, \ 6380219346bSGarrett D'Amore (num * sizeof (struct hme_rmd)), \ 6390219346bSGarrett D'Amore sizeof (struct hme_rmd), \ 6400219346bSGarrett D'Amore who) 6410219346bSGarrett D'Amore 6420219346bSGarrett D'Amore #define HMESYNCTMD(num, who) \ 6430219346bSGarrett D'Amore (void) ddi_dma_sync(hmep->hme_tmd_dmah, \ 6440219346bSGarrett D'Amore (num * sizeof (struct hme_tmd)), \ 6450219346bSGarrett D'Amore sizeof (struct hme_tmd), \ 6460219346bSGarrett D'Amore who) 6477c478bd9Sstevel@tonic-gate 6487c478bd9Sstevel@tonic-gate /* 6497c478bd9Sstevel@tonic-gate * Ethernet broadcast address definition. 6507c478bd9Sstevel@tonic-gate */ 6517c478bd9Sstevel@tonic-gate static struct ether_addr etherbroadcastaddr = { 6527c478bd9Sstevel@tonic-gate 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 6537c478bd9Sstevel@tonic-gate }; 6547c478bd9Sstevel@tonic-gate 6557c478bd9Sstevel@tonic-gate /* 6567c478bd9Sstevel@tonic-gate * MIB II broadcast/multicast packets 6577c478bd9Sstevel@tonic-gate */ 65885025c03Sgd #define IS_BROADCAST(pkt) (bcmp(pkt, ðerbroadcastaddr, ETHERADDRL) == 0) 65985025c03Sgd #define IS_MULTICAST(pkt) ((pkt[0] & 01) == 1) 66085025c03Sgd #define BUMP_InNUcast(hmep, pkt) \ 6610219346bSGarrett D'Amore if (IS_MULTICAST(pkt)) { \ 6620219346bSGarrett D'Amore if (IS_BROADCAST(pkt)) { \ 6630219346bSGarrett D'Amore hmep->hme_brdcstrcv++; \ 6640219346bSGarrett D'Amore } else { \ 6650219346bSGarrett D'Amore hmep->hme_multircv++; \ 6660219346bSGarrett D'Amore } \ 6670219346bSGarrett D'Amore } 66885025c03Sgd #define BUMP_OutNUcast(hmep, pkt) \ 6690219346bSGarrett D'Amore if (IS_MULTICAST(pkt)) { \ 6700219346bSGarrett D'Amore if (IS_BROADCAST(pkt)) { \ 6710219346bSGarrett D'Amore hmep->hme_brdcstxmt++; \ 6720219346bSGarrett D'Amore } else { \ 6730219346bSGarrett D'Amore hmep->hme_multixmt++; \ 6740219346bSGarrett D'Amore } \ 6750219346bSGarrett D'Amore } 6767c478bd9Sstevel@tonic-gate 6777c478bd9Sstevel@tonic-gate static int 6787c478bd9Sstevel@tonic-gate hme_create_prop_from_kw(dev_info_t *dip, char *vpdname, char *vpdstr) 6797c478bd9Sstevel@tonic-gate { 6807c478bd9Sstevel@tonic-gate char propstr[80]; 6817c478bd9Sstevel@tonic-gate int i, needprop = 0; 6827c478bd9Sstevel@tonic-gate struct ether_addr local_mac; 6837c478bd9Sstevel@tonic-gate 6847c478bd9Sstevel@tonic-gate if (strcmp(vpdname, "NA") == 0) { 6857c478bd9Sstevel@tonic-gate (void) strcpy(propstr, "local-mac-address"); 6867c478bd9Sstevel@tonic-gate needprop = 1; 6877c478bd9Sstevel@tonic-gate } else if (strcmp(vpdname, "Z0") == 0) { 6887c478bd9Sstevel@tonic-gate (void) strcpy(propstr, "model"); 6897c478bd9Sstevel@tonic-gate needprop = 1; 6907c478bd9Sstevel@tonic-gate } else if (strcmp(vpdname, "Z1") == 0) { 6917c478bd9Sstevel@tonic-gate (void) strcpy(propstr, "board-model"); 6927c478bd9Sstevel@tonic-gate needprop = 1; 6937c478bd9Sstevel@tonic-gate } 6947c478bd9Sstevel@tonic-gate 6957c478bd9Sstevel@tonic-gate if (needprop == 1) { 6960219346bSGarrett D'Amore 6977c478bd9Sstevel@tonic-gate if (strcmp(propstr, "local-mac-address") == 0) { 6987c478bd9Sstevel@tonic-gate for (i = 0; i < ETHERADDRL; i++) 6997c478bd9Sstevel@tonic-gate local_mac.ether_addr_octet[i] = 70085025c03Sgd (uchar_t)vpdstr[i]; 7017c478bd9Sstevel@tonic-gate if (ddi_prop_create(DDI_DEV_T_NONE, dip, 70285025c03Sgd DDI_PROP_CANSLEEP, propstr, 70385025c03Sgd (char *)local_mac.ether_addr_octet, ETHERADDRL) 70485025c03Sgd != DDI_SUCCESS) { 7057c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7067c478bd9Sstevel@tonic-gate } 7077c478bd9Sstevel@tonic-gate } else { 7087c478bd9Sstevel@tonic-gate if (ddi_prop_create(DDI_DEV_T_NONE, dip, 70985025c03Sgd DDI_PROP_CANSLEEP, propstr, vpdstr, 71085025c03Sgd strlen(vpdstr)+1) != DDI_SUCCESS) { 7117c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7127c478bd9Sstevel@tonic-gate } 7137c478bd9Sstevel@tonic-gate } 7147c478bd9Sstevel@tonic-gate } 7157c478bd9Sstevel@tonic-gate return (0); 7167c478bd9Sstevel@tonic-gate } 7177c478bd9Sstevel@tonic-gate 7187c478bd9Sstevel@tonic-gate /* 7197c478bd9Sstevel@tonic-gate * Get properties from old VPD 7207c478bd9Sstevel@tonic-gate * for PCI cards 7217c478bd9Sstevel@tonic-gate */ 7227c478bd9Sstevel@tonic-gate static int 7237c478bd9Sstevel@tonic-gate hme_get_oldvpd_props(dev_info_t *dip, int vpd_base) 7247c478bd9Sstevel@tonic-gate { 7257c478bd9Sstevel@tonic-gate struct hme *hmep; 7267c478bd9Sstevel@tonic-gate int vpd_start, vpd_len, kw_start, kw_len, kw_ptr; 7277c478bd9Sstevel@tonic-gate char kw_namestr[3]; 7287c478bd9Sstevel@tonic-gate char kw_fieldstr[256]; 7297c478bd9Sstevel@tonic-gate int i; 7307c478bd9Sstevel@tonic-gate 7317c478bd9Sstevel@tonic-gate hmep = ddi_get_driver_private(dip); 7327c478bd9Sstevel@tonic-gate 7337c478bd9Sstevel@tonic-gate vpd_start = vpd_base; 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate if ((GET_ROM8(&hmep->hme_romp[vpd_start]) & 0xff) != 0x90) { 7367c478bd9Sstevel@tonic-gate return (1); /* error */ 7377c478bd9Sstevel@tonic-gate } else { 7387c478bd9Sstevel@tonic-gate vpd_len = 9; 7397c478bd9Sstevel@tonic-gate } 7407c478bd9Sstevel@tonic-gate 7417c478bd9Sstevel@tonic-gate /* Get local-mac-address */ 7427c478bd9Sstevel@tonic-gate kw_start = vpd_start + 3; /* Location of 1st keyword */ 7437c478bd9Sstevel@tonic-gate kw_ptr = kw_start; 7447c478bd9Sstevel@tonic-gate while ((kw_ptr - kw_start) < vpd_len) { /* Get all keywords */ 7457c478bd9Sstevel@tonic-gate kw_namestr[0] = GET_ROM8(&hmep->hme_romp[kw_ptr]); 7467c478bd9Sstevel@tonic-gate kw_namestr[1] = GET_ROM8(&hmep->hme_romp[kw_ptr+1]); 7477c478bd9Sstevel@tonic-gate kw_namestr[2] = '\0'; 7487c478bd9Sstevel@tonic-gate kw_len = (int)(GET_ROM8(&hmep->hme_romp[kw_ptr+2]) & 0xff); 7497c478bd9Sstevel@tonic-gate for (i = 0, kw_ptr += 3; i < kw_len; i++) 7507c478bd9Sstevel@tonic-gate kw_fieldstr[i] = GET_ROM8(&hmep->hme_romp[kw_ptr+i]); 7517c478bd9Sstevel@tonic-gate kw_fieldstr[i] = '\0'; 7527c478bd9Sstevel@tonic-gate if (hme_create_prop_from_kw(dip, kw_namestr, kw_fieldstr)) { 7537c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7547c478bd9Sstevel@tonic-gate } 7557c478bd9Sstevel@tonic-gate kw_ptr += kw_len; 7567c478bd9Sstevel@tonic-gate } /* next keyword */ 7577c478bd9Sstevel@tonic-gate 75885025c03Sgd if (ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, "model", 75985025c03Sgd "SUNW,cheerio", strlen("SUNW,cheerio")+1) != DDI_SUCCESS) { 7607c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7617c478bd9Sstevel@tonic-gate } 7627c478bd9Sstevel@tonic-gate return (0); 7637c478bd9Sstevel@tonic-gate } 7647c478bd9Sstevel@tonic-gate 7657c478bd9Sstevel@tonic-gate 7667c478bd9Sstevel@tonic-gate /* 7677c478bd9Sstevel@tonic-gate * Get properties from new VPD 7687c478bd9Sstevel@tonic-gate * for CompactPCI cards 7697c478bd9Sstevel@tonic-gate */ 7707c478bd9Sstevel@tonic-gate static int 7717c478bd9Sstevel@tonic-gate hme_get_newvpd_props(dev_info_t *dip, int vpd_base) 7727c478bd9Sstevel@tonic-gate { 7737c478bd9Sstevel@tonic-gate struct hme *hmep; 7747c478bd9Sstevel@tonic-gate int vpd_start, vpd_len, kw_start, kw_len, kw_ptr; 7757c478bd9Sstevel@tonic-gate char kw_namestr[3]; 7767c478bd9Sstevel@tonic-gate char kw_fieldstr[256]; 7777c478bd9Sstevel@tonic-gate int maxvpdsize, i; 7787c478bd9Sstevel@tonic-gate 7797c478bd9Sstevel@tonic-gate hmep = ddi_get_driver_private(dip); 7807c478bd9Sstevel@tonic-gate 7817c478bd9Sstevel@tonic-gate maxvpdsize = 1024; /* Real size not known until after it is read */ 7827c478bd9Sstevel@tonic-gate 7837c478bd9Sstevel@tonic-gate vpd_start = (int)((GET_ROM8(&(hmep->hme_romp[vpd_base+1])) & 0xff) | 78485025c03Sgd ((GET_ROM8(&hmep->hme_romp[vpd_base+2]) & 0xff) << 8)) +3; 7857c478bd9Sstevel@tonic-gate vpd_start = vpd_base + vpd_start; 7867c478bd9Sstevel@tonic-gate while (vpd_start < (vpd_base + maxvpdsize)) { /* Get all VPDs */ 7877c478bd9Sstevel@tonic-gate if ((GET_ROM8(&hmep->hme_romp[vpd_start]) & 0xff) != 0x90) { 7887c478bd9Sstevel@tonic-gate break; /* no VPD found */ 7897c478bd9Sstevel@tonic-gate } else { 7907c478bd9Sstevel@tonic-gate vpd_len = (int)((GET_ROM8(&hmep->hme_romp[vpd_start 79185025c03Sgd + 1]) & 0xff) | (GET_ROM8(&hmep->hme_romp[vpd_start 79285025c03Sgd + 2]) & 0xff) << 8); 7937c478bd9Sstevel@tonic-gate } 7947c478bd9Sstevel@tonic-gate /* Get all keywords in this VPD */ 7957c478bd9Sstevel@tonic-gate kw_start = vpd_start + 3; /* Location of 1st keyword */ 7967c478bd9Sstevel@tonic-gate kw_ptr = kw_start; 7977c478bd9Sstevel@tonic-gate while ((kw_ptr - kw_start) < vpd_len) { /* Get all keywords */ 7987c478bd9Sstevel@tonic-gate kw_namestr[0] = GET_ROM8(&hmep->hme_romp[kw_ptr]); 7997c478bd9Sstevel@tonic-gate kw_namestr[1] = GET_ROM8(&hmep->hme_romp[kw_ptr+1]); 8007c478bd9Sstevel@tonic-gate kw_namestr[2] = '\0'; 80185025c03Sgd kw_len = 80285025c03Sgd (int)(GET_ROM8(&hmep->hme_romp[kw_ptr+2]) & 0xff); 8037c478bd9Sstevel@tonic-gate for (i = 0, kw_ptr += 3; i < kw_len; i++) 80485025c03Sgd kw_fieldstr[i] = 80585025c03Sgd GET_ROM8(&hmep->hme_romp[kw_ptr+i]); 8067c478bd9Sstevel@tonic-gate kw_fieldstr[i] = '\0'; 8077c478bd9Sstevel@tonic-gate if (hme_create_prop_from_kw(dip, kw_namestr, 80885025c03Sgd kw_fieldstr)) { 8097c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 8107c478bd9Sstevel@tonic-gate } 8117c478bd9Sstevel@tonic-gate kw_ptr += kw_len; 8127c478bd9Sstevel@tonic-gate } /* next keyword */ 8137c478bd9Sstevel@tonic-gate vpd_start += (vpd_len + 3); 8147c478bd9Sstevel@tonic-gate } /* next VPD */ 8157c478bd9Sstevel@tonic-gate return (0); 8167c478bd9Sstevel@tonic-gate } 8177c478bd9Sstevel@tonic-gate 8187c478bd9Sstevel@tonic-gate 8197c478bd9Sstevel@tonic-gate /* 8207c478bd9Sstevel@tonic-gate * Get properties from VPD 8217c478bd9Sstevel@tonic-gate */ 8227c478bd9Sstevel@tonic-gate static int 8237c478bd9Sstevel@tonic-gate hme_get_vpd_props(dev_info_t *dip) 8247c478bd9Sstevel@tonic-gate { 8257c478bd9Sstevel@tonic-gate struct hme *hmep; 8267c478bd9Sstevel@tonic-gate int v0, v1, vpd_base; 8277c478bd9Sstevel@tonic-gate int i, epromsrchlimit; 8287c478bd9Sstevel@tonic-gate 8297c478bd9Sstevel@tonic-gate 8307c478bd9Sstevel@tonic-gate hmep = ddi_get_driver_private(dip); 8317c478bd9Sstevel@tonic-gate 8327c478bd9Sstevel@tonic-gate v0 = (int)(GET_ROM8(&(hmep->hme_romp[0]))); 8337c478bd9Sstevel@tonic-gate v1 = (int)(GET_ROM8(&(hmep->hme_romp[1]))); 8347c478bd9Sstevel@tonic-gate v0 = ((v0 & 0xff) << 8 | v1); 8357c478bd9Sstevel@tonic-gate 8367c478bd9Sstevel@tonic-gate if ((v0 & 0xffff) != 0x55aa) { 8377c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, " Valid pci prom not found \n"); 8387c478bd9Sstevel@tonic-gate return (1); 8397c478bd9Sstevel@tonic-gate } 8407c478bd9Sstevel@tonic-gate 8417c478bd9Sstevel@tonic-gate epromsrchlimit = 4096; 8427c478bd9Sstevel@tonic-gate for (i = 2; i < epromsrchlimit; i++) { 84385025c03Sgd /* "PCIR" */ 84485025c03Sgd if (((GET_ROM8(&(hmep->hme_romp[i])) & 0xff) == 'P') && 84585025c03Sgd ((GET_ROM8(&(hmep->hme_romp[i+1])) & 0xff) == 'C') && 84685025c03Sgd ((GET_ROM8(&(hmep->hme_romp[i+2])) & 0xff) == 'I') && 84785025c03Sgd ((GET_ROM8(&(hmep->hme_romp[i+3])) & 0xff) == 'R')) { 84885025c03Sgd vpd_base = 84985025c03Sgd (int)((GET_ROM8(&(hmep->hme_romp[i+8])) & 0xff) | 85085025c03Sgd (GET_ROM8(&(hmep->hme_romp[i+9])) & 0xff) << 8); 8517c478bd9Sstevel@tonic-gate break; /* VPD pointer found */ 8527c478bd9Sstevel@tonic-gate } 8537c478bd9Sstevel@tonic-gate } 8547c478bd9Sstevel@tonic-gate 8557c478bd9Sstevel@tonic-gate /* No VPD found */ 8567c478bd9Sstevel@tonic-gate if (vpd_base == 0) { 8577c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, " Vital Product Data pointer not found \n"); 8587c478bd9Sstevel@tonic-gate return (1); 8597c478bd9Sstevel@tonic-gate } 8607c478bd9Sstevel@tonic-gate 8617c478bd9Sstevel@tonic-gate v0 = (int)(GET_ROM8(&(hmep->hme_romp[vpd_base]))); 8627c478bd9Sstevel@tonic-gate if (v0 == 0x82) { 8637c478bd9Sstevel@tonic-gate if (hme_get_newvpd_props(dip, vpd_base)) 8647c478bd9Sstevel@tonic-gate return (1); 8657c478bd9Sstevel@tonic-gate return (0); 8667c478bd9Sstevel@tonic-gate } else if (v0 == 0x90) { 8670219346bSGarrett D'Amore /* If we are are SUNW,qfe card, look for the Nth "NA" descr */ 8680219346bSGarrett D'Amore if ((GET_ROM8(&hmep->hme_romp[vpd_base + 12]) != 0x79) && 8690219346bSGarrett D'Amore GET_ROM8(&hmep->hme_romp[vpd_base + 4 * 12]) == 0x79) { 8700219346bSGarrett D'Amore vpd_base += hmep->hme_devno * 12; 8710219346bSGarrett D'Amore } 8727c478bd9Sstevel@tonic-gate if (hme_get_oldvpd_props(dip, vpd_base)) 8737c478bd9Sstevel@tonic-gate return (1); 8747c478bd9Sstevel@tonic-gate return (0); 8757c478bd9Sstevel@tonic-gate } else 8767c478bd9Sstevel@tonic-gate return (1); /* unknown start byte in VPD */ 8777c478bd9Sstevel@tonic-gate } 8787c478bd9Sstevel@tonic-gate 8790219346bSGarrett D'Amore /* 8800219346bSGarrett D'Amore * For x86, the BIOS doesn't map the PCI Rom register for the qfe 8810219346bSGarrett D'Amore * cards, so we have to extract it from the ebus bridge that is 8820219346bSGarrett D'Amore * function zero of the same device. This is a bit of an ugly hack. 8830219346bSGarrett D'Amore * (The ebus bridge leaves the entire ROM mapped at base address 8840219346bSGarrett D'Amore * register 0x10.) 8850219346bSGarrett D'Amore */ 8860219346bSGarrett D'Amore 8870219346bSGarrett D'Amore typedef struct { 8880219346bSGarrett D'Amore struct hme *hmep; 8890219346bSGarrett D'Amore dev_info_t *parent; 8900219346bSGarrett D'Amore uint8_t bus, dev; 8910219346bSGarrett D'Amore ddi_acc_handle_t acch; 8920219346bSGarrett D'Amore caddr_t romp; 8930219346bSGarrett D'Amore } ebus_rom_t; 8940219346bSGarrett D'Amore 8950219346bSGarrett D'Amore static int 8960219346bSGarrett D'Amore hme_mapebusrom(dev_info_t *dip, void *arg) 8970219346bSGarrett D'Amore { 8980219346bSGarrett D'Amore int *regs; 8990219346bSGarrett D'Amore unsigned nregs; 9000219346bSGarrett D'Amore int reg; 9010219346bSGarrett D'Amore ebus_rom_t *rom = arg; 9020219346bSGarrett D'Amore struct hme *hmep = rom->hmep; 9030219346bSGarrett D'Amore 9040219346bSGarrett D'Amore /* 9050219346bSGarrett D'Amore * We only want to look at our peers. Skip our parent. 9060219346bSGarrett D'Amore */ 9070219346bSGarrett D'Amore if (dip == rom->parent) { 9080219346bSGarrett D'Amore return (DDI_WALK_PRUNESIB); 9090219346bSGarrett D'Amore } 9100219346bSGarrett D'Amore 911*06673d9bSGarrett D'Amore if (ddi_get_parent(dip) != rom->parent) 912*06673d9bSGarrett D'Amore return (DDI_WALK_CONTINUE); 913*06673d9bSGarrett D'Amore 9140219346bSGarrett D'Amore if ((ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 0, 9150219346bSGarrett D'Amore "reg", ®s, &nregs)) != DDI_PROP_SUCCESS) { 9160219346bSGarrett D'Amore return (DDI_WALK_PRUNECHILD); 9170219346bSGarrett D'Amore } 9180219346bSGarrett D'Amore 9190219346bSGarrett D'Amore if (nregs < 1) { 9200219346bSGarrett D'Amore ddi_prop_free(regs); 9210219346bSGarrett D'Amore return (DDI_WALK_PRUNECHILD); 9220219346bSGarrett D'Amore } 9230219346bSGarrett D'Amore reg = regs[0]; 9240219346bSGarrett D'Amore ddi_prop_free(regs); 9250219346bSGarrett D'Amore 9260219346bSGarrett D'Amore /* 9270219346bSGarrett D'Amore * Look for function 0 on our bus and device. If the device doesn't 9280219346bSGarrett D'Amore * match, it might be an alternate peer, in which case we don't want 9290219346bSGarrett D'Amore * to examine any of its children. 9300219346bSGarrett D'Amore */ 9310219346bSGarrett D'Amore if ((PCI_REG_BUS_G(reg) != rom->bus) || 9320219346bSGarrett D'Amore (PCI_REG_DEV_G(reg) != rom->dev) || 9330219346bSGarrett D'Amore (PCI_REG_FUNC_G(reg) != 0)) { 9340219346bSGarrett D'Amore return (DDI_WALK_PRUNECHILD); 9350219346bSGarrett D'Amore } 9360219346bSGarrett D'Amore 9370219346bSGarrett D'Amore (void) ddi_regs_map_setup(dip, 1, &rom->romp, 0, 0, &hmep->hme_dev_attr, 9380219346bSGarrett D'Amore &rom->acch); 9390219346bSGarrett D'Amore /* 9400219346bSGarrett D'Amore * If we can't map the registers, the caller will notice that 9410219346bSGarrett D'Amore * the acch is NULL. 9420219346bSGarrett D'Amore */ 9430219346bSGarrett D'Amore return (DDI_WALK_TERMINATE); 9440219346bSGarrett D'Amore } 9450219346bSGarrett D'Amore 9460219346bSGarrett D'Amore static int 9470219346bSGarrett D'Amore hmeget_promebus(dev_info_t *dip) 9480219346bSGarrett D'Amore { 9490219346bSGarrett D'Amore ebus_rom_t rom; 9500219346bSGarrett D'Amore int *regs; 9510219346bSGarrett D'Amore unsigned nregs; 9520219346bSGarrett D'Amore struct hme *hmep; 9530219346bSGarrett D'Amore 9540219346bSGarrett D'Amore hmep = ddi_get_driver_private(dip); 9550219346bSGarrett D'Amore 9560219346bSGarrett D'Amore bzero(&rom, sizeof (rom)); 9570219346bSGarrett D'Amore 9580219346bSGarrett D'Amore /* 9590219346bSGarrett D'Amore * For x86, the BIOS doesn't map the PCI Rom register for the qfe 9600219346bSGarrett D'Amore * cards, so we have to extract it from the eBus bridge that is 9610219346bSGarrett D'Amore * function zero. This is a bit of an ugly hack. 9620219346bSGarrett D'Amore */ 9630219346bSGarrett D'Amore if ((ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 0, 9640219346bSGarrett D'Amore "reg", ®s, &nregs)) != DDI_PROP_SUCCESS) { 9650219346bSGarrett D'Amore return (DDI_FAILURE); 9660219346bSGarrett D'Amore } 9670219346bSGarrett D'Amore 9680219346bSGarrett D'Amore if (nregs < 5) { 9690219346bSGarrett D'Amore ddi_prop_free(regs); 9700219346bSGarrett D'Amore return (DDI_FAILURE); 9710219346bSGarrett D'Amore } 9720219346bSGarrett D'Amore rom.hmep = hmep; 9730219346bSGarrett D'Amore rom.bus = PCI_REG_BUS_G(regs[0]); 9740219346bSGarrett D'Amore rom.dev = PCI_REG_DEV_G(regs[0]); 9750219346bSGarrett D'Amore hmep->hme_devno = rom.dev; 9760219346bSGarrett D'Amore rom.parent = ddi_get_parent(dip); 9770219346bSGarrett D'Amore 9780219346bSGarrett D'Amore /* 9790219346bSGarrett D'Amore * The implementation of ddi_walk_devs says that we must not 980*06673d9bSGarrett D'Amore * be called during autoconfiguration. However, it turns out 981*06673d9bSGarrett D'Amore * that it is safe to call this during our attach routine, 982*06673d9bSGarrett D'Amore * because we are not a nexus device. 9830219346bSGarrett D'Amore * 984*06673d9bSGarrett D'Amore * Previously we rooted our search at our immediate parent, 985*06673d9bSGarrett D'Amore * but this triggered an assertion panic in debug kernels. 9860219346bSGarrett D'Amore */ 987*06673d9bSGarrett D'Amore ddi_walk_devs(ddi_root_node(), hme_mapebusrom, &rom); 9880219346bSGarrett D'Amore 9890219346bSGarrett D'Amore if (rom.acch) { 9900219346bSGarrett D'Amore hmep->hme_romh = rom.acch; 9910219346bSGarrett D'Amore hmep->hme_romp = (unsigned char *)rom.romp; 9920219346bSGarrett D'Amore return (DDI_SUCCESS); 9930219346bSGarrett D'Amore } 9940219346bSGarrett D'Amore return (DDI_FAILURE); 9950219346bSGarrett D'Amore } 9960219346bSGarrett D'Amore 9977c478bd9Sstevel@tonic-gate static int 9987c478bd9Sstevel@tonic-gate hmeget_promprops(dev_info_t *dip) 9997c478bd9Sstevel@tonic-gate { 10007c478bd9Sstevel@tonic-gate struct hme *hmep; 10017c478bd9Sstevel@tonic-gate int rom_bar; 10027c478bd9Sstevel@tonic-gate ddi_acc_handle_t cfg_handle; 10037c478bd9Sstevel@tonic-gate struct { 10047c478bd9Sstevel@tonic-gate uint16_t vendorid; 10057c478bd9Sstevel@tonic-gate uint16_t devid; 10067c478bd9Sstevel@tonic-gate uint16_t command; 10077c478bd9Sstevel@tonic-gate uint16_t status; 10087c478bd9Sstevel@tonic-gate uint32_t junk1; 10097c478bd9Sstevel@tonic-gate uint8_t cache_line; 10107c478bd9Sstevel@tonic-gate uint8_t latency; 10117c478bd9Sstevel@tonic-gate uint8_t header; 10127c478bd9Sstevel@tonic-gate uint8_t bist; 10137c478bd9Sstevel@tonic-gate uint32_t base; 10147c478bd9Sstevel@tonic-gate uint32_t base14; 10157c478bd9Sstevel@tonic-gate uint32_t base18; 10167c478bd9Sstevel@tonic-gate uint32_t base1c; 10177c478bd9Sstevel@tonic-gate uint32_t base20; 10187c478bd9Sstevel@tonic-gate uint32_t base24; 10197c478bd9Sstevel@tonic-gate uint32_t base28; 10207c478bd9Sstevel@tonic-gate uint32_t base2c; 10217c478bd9Sstevel@tonic-gate uint32_t base30; 10227c478bd9Sstevel@tonic-gate } *cfg_ptr; 10237c478bd9Sstevel@tonic-gate 10247c478bd9Sstevel@tonic-gate hmep = ddi_get_driver_private(dip); 10257c478bd9Sstevel@tonic-gate 10267c478bd9Sstevel@tonic-gate 10277c478bd9Sstevel@tonic-gate /* 10287c478bd9Sstevel@tonic-gate * map configuration space 10297c478bd9Sstevel@tonic-gate */ 10307c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(hmep->dip, 0, (caddr_t *)&cfg_ptr, 103185025c03Sgd 0, 0, &hmep->hme_dev_attr, &cfg_handle)) { 10327c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 10337c478bd9Sstevel@tonic-gate } 10347c478bd9Sstevel@tonic-gate 10357c478bd9Sstevel@tonic-gate /* 10367c478bd9Sstevel@tonic-gate * Enable bus-master and memory accesses 10377c478bd9Sstevel@tonic-gate */ 10387c478bd9Sstevel@tonic-gate ddi_put16(cfg_handle, &cfg_ptr->command, 103985025c03Sgd PCI_COMM_SERR_ENABLE | PCI_COMM_PARITY_DETECT | 104085025c03Sgd PCI_COMM_MAE | PCI_COMM_ME); 10417c478bd9Sstevel@tonic-gate 10427c478bd9Sstevel@tonic-gate /* 10437c478bd9Sstevel@tonic-gate * Enable rom accesses 10447c478bd9Sstevel@tonic-gate */ 10457c478bd9Sstevel@tonic-gate rom_bar = ddi_get32(cfg_handle, &cfg_ptr->base30); 10467c478bd9Sstevel@tonic-gate ddi_put32(cfg_handle, &cfg_ptr->base30, rom_bar | 1); 10477c478bd9Sstevel@tonic-gate 10487c478bd9Sstevel@tonic-gate 10490219346bSGarrett D'Amore if ((ddi_regs_map_setup(dip, 2, (caddr_t *)&(hmep->hme_romp), 0, 0, 10500219346bSGarrett D'Amore &hmep->hme_dev_attr, &hmep->hme_romh) != DDI_SUCCESS) && 10510219346bSGarrett D'Amore (hmeget_promebus(dip) != DDI_SUCCESS)) { 10520219346bSGarrett D'Amore 10537c478bd9Sstevel@tonic-gate if (cfg_ptr) 10547c478bd9Sstevel@tonic-gate ddi_regs_map_free(&cfg_handle); 10557c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 10567c478bd9Sstevel@tonic-gate } else { 10577c478bd9Sstevel@tonic-gate if (hme_get_vpd_props(dip)) 10580219346bSGarrett D'Amore return (DDI_FAILURE); 10597c478bd9Sstevel@tonic-gate } 10607c478bd9Sstevel@tonic-gate if (hmep->hme_romp) 10617c478bd9Sstevel@tonic-gate ddi_regs_map_free(&hmep->hme_romh); 10627c478bd9Sstevel@tonic-gate if (cfg_ptr) 10637c478bd9Sstevel@tonic-gate ddi_regs_map_free(&cfg_handle); 10640219346bSGarrett D'Amore return (DDI_SUCCESS); 10657c478bd9Sstevel@tonic-gate 10667c478bd9Sstevel@tonic-gate } 10677c478bd9Sstevel@tonic-gate 10687c478bd9Sstevel@tonic-gate static void 10697c478bd9Sstevel@tonic-gate hmeget_hm_rev_property(struct hme *hmep) 10707c478bd9Sstevel@tonic-gate { 10717c478bd9Sstevel@tonic-gate int hm_rev; 10727c478bd9Sstevel@tonic-gate 10737c478bd9Sstevel@tonic-gate 10747c478bd9Sstevel@tonic-gate hm_rev = hmep->asic_rev; 10757c478bd9Sstevel@tonic-gate switch (hm_rev) { 10767c478bd9Sstevel@tonic-gate case HME_2P1_REVID: 10777c478bd9Sstevel@tonic-gate case HME_2P1_REVID_OBP: 10787c478bd9Sstevel@tonic-gate HME_FAULT_MSG2(hmep, SEVERITY_NONE, DISPLAY_MSG, 107985025c03Sgd "SBus 2.1 Found (Rev Id = %x)", hm_rev); 10807c478bd9Sstevel@tonic-gate hmep->hme_frame_enable = 1; 10817c478bd9Sstevel@tonic-gate break; 10827c478bd9Sstevel@tonic-gate 10837c478bd9Sstevel@tonic-gate case HME_2P0_REVID: 10847c478bd9Sstevel@tonic-gate HME_FAULT_MSG2(hmep, SEVERITY_NONE, DISPLAY_MSG, 108585025c03Sgd "SBus 2.0 Found (Rev Id = %x)", hm_rev); 10867c478bd9Sstevel@tonic-gate break; 10877c478bd9Sstevel@tonic-gate 10887c478bd9Sstevel@tonic-gate case HME_1C0_REVID: 10897c478bd9Sstevel@tonic-gate HME_FAULT_MSG2(hmep, SEVERITY_NONE, DISPLAY_MSG, 109085025c03Sgd "PCI IO 1.0 Found (Rev Id = %x)", hm_rev); 10917c478bd9Sstevel@tonic-gate break; 10927c478bd9Sstevel@tonic-gate 10937c478bd9Sstevel@tonic-gate default: 1094*06673d9bSGarrett D'Amore HME_FAULT_MSG3(hmep, SEVERITY_NONE, DISPLAY_MSG, 109585025c03Sgd "%s (Rev Id = %x) Found", 109685025c03Sgd (hm_rev == HME_2C0_REVID) ? "PCI IO 2.0" : "Sbus", hm_rev); 10977c478bd9Sstevel@tonic-gate hmep->hme_frame_enable = 1; 10987c478bd9Sstevel@tonic-gate hmep->hme_lance_mode_enable = 1; 10997c478bd9Sstevel@tonic-gate hmep->hme_rxcv_enable = 1; 11007c478bd9Sstevel@tonic-gate break; 11017c478bd9Sstevel@tonic-gate } 11027c478bd9Sstevel@tonic-gate } 11037c478bd9Sstevel@tonic-gate 11047c478bd9Sstevel@tonic-gate /* 11057c478bd9Sstevel@tonic-gate * Interface exists: make available by filling in network interface 11067c478bd9Sstevel@tonic-gate * record. System will initialize the interface when it is ready 11077c478bd9Sstevel@tonic-gate * to accept packets. 11087c478bd9Sstevel@tonic-gate */ 1109f2cd0f02Sgd int 11107c478bd9Sstevel@tonic-gate hmeattach(dev_info_t *dip, ddi_attach_cmd_t cmd) 11117c478bd9Sstevel@tonic-gate { 11127c478bd9Sstevel@tonic-gate struct hme *hmep; 111385025c03Sgd mac_register_t *macp = NULL; 11147c478bd9Sstevel@tonic-gate int regno; 11157c478bd9Sstevel@tonic-gate int hm_rev = 0; 11167c478bd9Sstevel@tonic-gate int prop_len = sizeof (int); 11177c478bd9Sstevel@tonic-gate ddi_acc_handle_t cfg_handle; 11187c478bd9Sstevel@tonic-gate struct { 11197c478bd9Sstevel@tonic-gate uint16_t vendorid; 11207c478bd9Sstevel@tonic-gate uint16_t devid; 11217c478bd9Sstevel@tonic-gate uint16_t command; 11227c478bd9Sstevel@tonic-gate uint16_t status; 11237c478bd9Sstevel@tonic-gate uint8_t revid; 11247c478bd9Sstevel@tonic-gate uint8_t j1; 11257c478bd9Sstevel@tonic-gate uint16_t j2; 11267c478bd9Sstevel@tonic-gate } *cfg_ptr; 11277c478bd9Sstevel@tonic-gate 11287c478bd9Sstevel@tonic-gate switch (cmd) { 11297c478bd9Sstevel@tonic-gate case DDI_ATTACH: 11307c478bd9Sstevel@tonic-gate break; 11317c478bd9Sstevel@tonic-gate 11327c478bd9Sstevel@tonic-gate case DDI_RESUME: 11337c478bd9Sstevel@tonic-gate if ((hmep = ddi_get_driver_private(dip)) == NULL) 113485025c03Sgd return (DDI_FAILURE); 11357c478bd9Sstevel@tonic-gate 11367c478bd9Sstevel@tonic-gate hmep->hme_flags &= ~HMESUSPENDED; 1137*06673d9bSGarrett D'Amore 1138*06673d9bSGarrett D'Amore mii_resume(hmep->hme_mii); 113985025c03Sgd 1140228fdff0Sgd if (hmep->hme_started) 114185025c03Sgd (void) hmeinit(hmep); 11427c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 11437c478bd9Sstevel@tonic-gate 11447c478bd9Sstevel@tonic-gate default: 11457c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 11467c478bd9Sstevel@tonic-gate } 11477c478bd9Sstevel@tonic-gate 11487c478bd9Sstevel@tonic-gate /* 11497c478bd9Sstevel@tonic-gate * Allocate soft device data structure 11507c478bd9Sstevel@tonic-gate */ 11510219346bSGarrett D'Amore hmep = kmem_zalloc(sizeof (*hmep), KM_SLEEP); 11527c478bd9Sstevel@tonic-gate 11537c478bd9Sstevel@tonic-gate /* 11547c478bd9Sstevel@tonic-gate * Might as well set up elements of data structure 11557c478bd9Sstevel@tonic-gate */ 11567c478bd9Sstevel@tonic-gate hmep->dip = dip; 11577c478bd9Sstevel@tonic-gate hmep->instance = ddi_get_instance(dip); 11587c478bd9Sstevel@tonic-gate hmep->pagesize = ddi_ptob(dip, (ulong_t)1); /* IOMMU PSize */ 11597c478bd9Sstevel@tonic-gate 11607c478bd9Sstevel@tonic-gate /* 11617c478bd9Sstevel@tonic-gate * Might as well setup the driver private 11627c478bd9Sstevel@tonic-gate * structure as part of the dip. 11637c478bd9Sstevel@tonic-gate */ 11647c478bd9Sstevel@tonic-gate ddi_set_driver_private(dip, hmep); 11657c478bd9Sstevel@tonic-gate 11667c478bd9Sstevel@tonic-gate /* 11677c478bd9Sstevel@tonic-gate * Reject this device if it's in a slave-only slot. 11687c478bd9Sstevel@tonic-gate */ 11697c478bd9Sstevel@tonic-gate if (ddi_slaveonly(dip) == DDI_SUCCESS) { 11707c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG, 11710219346bSGarrett D'Amore "Dev not used - dev in slave only slot"); 11727c478bd9Sstevel@tonic-gate goto error_state; 11737c478bd9Sstevel@tonic-gate } 11747c478bd9Sstevel@tonic-gate 11757c478bd9Sstevel@tonic-gate /* 11767c478bd9Sstevel@tonic-gate * Map in the device registers. 11777c478bd9Sstevel@tonic-gate * 11787c478bd9Sstevel@tonic-gate * Reg # 0 is the Global register set 11797c478bd9Sstevel@tonic-gate * Reg # 1 is the ETX register set 11807c478bd9Sstevel@tonic-gate * Reg # 2 is the ERX register set 11817c478bd9Sstevel@tonic-gate * Reg # 3 is the BigMAC register set. 11827c478bd9Sstevel@tonic-gate * Reg # 4 is the MIF register set 11837c478bd9Sstevel@tonic-gate */ 11847c478bd9Sstevel@tonic-gate if (ddi_dev_nregs(dip, ®no) != (DDI_SUCCESS)) { 11857c478bd9Sstevel@tonic-gate HME_FAULT_MSG2(hmep, SEVERITY_HIGH, INIT_MSG, 118685025c03Sgd ddi_nregs_fail_msg, regno); 11877c478bd9Sstevel@tonic-gate goto error_state; 11887c478bd9Sstevel@tonic-gate } 11897c478bd9Sstevel@tonic-gate 11907c478bd9Sstevel@tonic-gate switch (regno) { 11917c478bd9Sstevel@tonic-gate case 5: 11927c478bd9Sstevel@tonic-gate hmep->hme_cheerio_mode = 0; 11937c478bd9Sstevel@tonic-gate break; 11947c478bd9Sstevel@tonic-gate case 2: 11957c478bd9Sstevel@tonic-gate case 3: /* for hot swap/plug, there will be 3 entries in "reg" prop */ 11967c478bd9Sstevel@tonic-gate hmep->hme_cheerio_mode = 1; 11977c478bd9Sstevel@tonic-gate break; 11987c478bd9Sstevel@tonic-gate default: 119985025c03Sgd HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 120085025c03Sgd bad_num_regs_msg); 12017c478bd9Sstevel@tonic-gate goto error_state; 12027c478bd9Sstevel@tonic-gate } 12037c478bd9Sstevel@tonic-gate 12047c478bd9Sstevel@tonic-gate /* Initialize device attributes structure */ 12057c478bd9Sstevel@tonic-gate hmep->hme_dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 12067c478bd9Sstevel@tonic-gate 12077c478bd9Sstevel@tonic-gate if (hmep->hme_cheerio_mode) 120885025c03Sgd hmep->hme_dev_attr.devacc_attr_endian_flags = 120985025c03Sgd DDI_STRUCTURE_LE_ACC; 12107c478bd9Sstevel@tonic-gate else 121185025c03Sgd hmep->hme_dev_attr.devacc_attr_endian_flags = 121285025c03Sgd DDI_STRUCTURE_BE_ACC; 12137c478bd9Sstevel@tonic-gate 12147c478bd9Sstevel@tonic-gate hmep->hme_dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 12157c478bd9Sstevel@tonic-gate 12167c478bd9Sstevel@tonic-gate if (hmep->hme_cheerio_mode) { 12177c478bd9Sstevel@tonic-gate uint8_t oldLT; 12187c478bd9Sstevel@tonic-gate uint8_t newLT = 0; 12197c478bd9Sstevel@tonic-gate dev_info_t *pdip; 12207c478bd9Sstevel@tonic-gate const char *pdrvname; 12217c478bd9Sstevel@tonic-gate 12227c478bd9Sstevel@tonic-gate /* 12237c478bd9Sstevel@tonic-gate * Map the PCI config space 12247c478bd9Sstevel@tonic-gate */ 12257c478bd9Sstevel@tonic-gate if (pci_config_setup(dip, &hmep->pci_config_handle) != 122685025c03Sgd DDI_SUCCESS) { 12277c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG, 122885025c03Sgd "pci_config_setup() failed.."); 12297c478bd9Sstevel@tonic-gate goto error_state; 12307c478bd9Sstevel@tonic-gate } 12317c478bd9Sstevel@tonic-gate 12327c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(dip, 1, 123385025c03Sgd (caddr_t *)&(hmep->hme_globregp), 0, 0, 123485025c03Sgd &hmep->hme_dev_attr, &hmep->hme_globregh)) { 12357c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG, 123685025c03Sgd mregs_4global_reg_fail_msg); 12377c478bd9Sstevel@tonic-gate goto error_unmap; 12387c478bd9Sstevel@tonic-gate } 12397c478bd9Sstevel@tonic-gate hmep->hme_etxregh = hmep->hme_erxregh = hmep->hme_bmacregh = 12407c478bd9Sstevel@tonic-gate hmep->hme_mifregh = hmep->hme_globregh; 12417c478bd9Sstevel@tonic-gate 124285025c03Sgd hmep->hme_etxregp = 124385025c03Sgd (void *)(((caddr_t)hmep->hme_globregp) + 0x2000); 124485025c03Sgd hmep->hme_erxregp = 124585025c03Sgd (void *)(((caddr_t)hmep->hme_globregp) + 0x4000); 124685025c03Sgd hmep->hme_bmacregp = 124785025c03Sgd (void *)(((caddr_t)hmep->hme_globregp) + 0x6000); 124885025c03Sgd hmep->hme_mifregp = 124985025c03Sgd (void *)(((caddr_t)hmep->hme_globregp) + 0x7000); 12507c478bd9Sstevel@tonic-gate 12517c478bd9Sstevel@tonic-gate /* 12527c478bd9Sstevel@tonic-gate * Get parent pci bridge info. 12537c478bd9Sstevel@tonic-gate */ 12547c478bd9Sstevel@tonic-gate pdip = ddi_get_parent(dip); 12557c478bd9Sstevel@tonic-gate pdrvname = ddi_driver_name(pdip); 12567c478bd9Sstevel@tonic-gate 12577c478bd9Sstevel@tonic-gate oldLT = pci_config_get8(hmep->pci_config_handle, 125885025c03Sgd PCI_CONF_LATENCY_TIMER); 12597c478bd9Sstevel@tonic-gate /* 12607c478bd9Sstevel@tonic-gate * Honor value set in /etc/system 12617c478bd9Sstevel@tonic-gate * "set hme:pci_latency_timer=0xYY" 12627c478bd9Sstevel@tonic-gate */ 12637c478bd9Sstevel@tonic-gate if (pci_latency_timer) 12647c478bd9Sstevel@tonic-gate newLT = pci_latency_timer; 12657c478bd9Sstevel@tonic-gate /* 12667c478bd9Sstevel@tonic-gate * Modify LT for simba 12677c478bd9Sstevel@tonic-gate */ 12687c478bd9Sstevel@tonic-gate else if (strcmp("simba", pdrvname) == 0) 12697c478bd9Sstevel@tonic-gate newLT = 0xf0; 12707c478bd9Sstevel@tonic-gate /* 12717c478bd9Sstevel@tonic-gate * Ensure minimum cheerio latency timer of 0x50 12727c478bd9Sstevel@tonic-gate * Usually OBP or pci bridge should set this value 12737c478bd9Sstevel@tonic-gate * based on cheerio 12747c478bd9Sstevel@tonic-gate * min_grant * 8(33MHz) = 0x50 = 0xa * 0x8 12757c478bd9Sstevel@tonic-gate * Some system set cheerio LT at 0x40 12767c478bd9Sstevel@tonic-gate */ 12777c478bd9Sstevel@tonic-gate else if (oldLT < 0x40) 12787c478bd9Sstevel@tonic-gate newLT = 0x50; 12797c478bd9Sstevel@tonic-gate 12807c478bd9Sstevel@tonic-gate /* 12817c478bd9Sstevel@tonic-gate * Now program cheerio's pci latency timer with newLT 12827c478bd9Sstevel@tonic-gate */ 12837c478bd9Sstevel@tonic-gate if (newLT) 12847c478bd9Sstevel@tonic-gate pci_config_put8(hmep->pci_config_handle, 128585025c03Sgd PCI_CONF_LATENCY_TIMER, (uchar_t)newLT); 12867c478bd9Sstevel@tonic-gate } else { /* Map register sets */ 12877c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(dip, 0, 128885025c03Sgd (caddr_t *)&(hmep->hme_globregp), 0, 0, 128985025c03Sgd &hmep->hme_dev_attr, &hmep->hme_globregh)) { 12907c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG, 129185025c03Sgd mregs_4global_reg_fail_msg); 12927c478bd9Sstevel@tonic-gate goto error_state; 12937c478bd9Sstevel@tonic-gate } 12947c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(dip, 1, 129585025c03Sgd (caddr_t *)&(hmep->hme_etxregp), 0, 0, 129685025c03Sgd &hmep->hme_dev_attr, &hmep->hme_etxregh)) { 12977c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG, 129885025c03Sgd mregs_4etx_reg_fail_msg); 12997c478bd9Sstevel@tonic-gate goto error_unmap; 13007c478bd9Sstevel@tonic-gate } 13017c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(dip, 2, 130285025c03Sgd (caddr_t *)&(hmep->hme_erxregp), 0, 0, 130385025c03Sgd &hmep->hme_dev_attr, &hmep->hme_erxregh)) { 13047c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG, 130585025c03Sgd mregs_4erx_reg_fail_msg); 13067c478bd9Sstevel@tonic-gate goto error_unmap; 13077c478bd9Sstevel@tonic-gate } 13087c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(dip, 3, 130985025c03Sgd (caddr_t *)&(hmep->hme_bmacregp), 0, 0, 131085025c03Sgd &hmep->hme_dev_attr, &hmep->hme_bmacregh)) { 13117c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG, 131285025c03Sgd mregs_4bmac_reg_fail_msg); 13137c478bd9Sstevel@tonic-gate goto error_unmap; 13147c478bd9Sstevel@tonic-gate } 13157c478bd9Sstevel@tonic-gate 13167c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(dip, 4, 131785025c03Sgd (caddr_t *)&(hmep->hme_mifregp), 0, 0, 131885025c03Sgd &hmep->hme_dev_attr, &hmep->hme_mifregh)) { 13197c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG, 132085025c03Sgd mregs_4mif_reg_fail_msg); 13217c478bd9Sstevel@tonic-gate goto error_unmap; 13227c478bd9Sstevel@tonic-gate } 13237c478bd9Sstevel@tonic-gate } /* Endif cheerio_mode */ 13247c478bd9Sstevel@tonic-gate 13257c478bd9Sstevel@tonic-gate /* 13267c478bd9Sstevel@tonic-gate * Based on the hm-rev, set some capabilities 13277c478bd9Sstevel@tonic-gate * Set up default capabilities for HM 2.0 13287c478bd9Sstevel@tonic-gate */ 13297c478bd9Sstevel@tonic-gate hmep->hme_frame_enable = 0; 13307c478bd9Sstevel@tonic-gate hmep->hme_lance_mode_enable = 0; 13317c478bd9Sstevel@tonic-gate hmep->hme_rxcv_enable = 0; 13327c478bd9Sstevel@tonic-gate 13337c478bd9Sstevel@tonic-gate /* NEW routine to get the properties */ 13347c478bd9Sstevel@tonic-gate 13357c478bd9Sstevel@tonic-gate if (ddi_getlongprop_buf(DDI_DEV_T_ANY, hmep->dip, 0, "hm-rev", 133685025c03Sgd (caddr_t)&hm_rev, &prop_len) == DDI_PROP_SUCCESS) { 13377c478bd9Sstevel@tonic-gate 13387c478bd9Sstevel@tonic-gate hmep->asic_rev = hm_rev; 13397c478bd9Sstevel@tonic-gate hmeget_hm_rev_property(hmep); 13407c478bd9Sstevel@tonic-gate } else { 13417c478bd9Sstevel@tonic-gate /* 13427c478bd9Sstevel@tonic-gate * hm_rev property not found so, this is 13437c478bd9Sstevel@tonic-gate * case of hot insertion of card without interpreting fcode. 13447c478bd9Sstevel@tonic-gate * Get it from revid in config space after mapping it. 13457c478bd9Sstevel@tonic-gate */ 13467c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(hmep->dip, 0, (caddr_t *)&cfg_ptr, 134785025c03Sgd 0, 0, &hmep->hme_dev_attr, &cfg_handle)) { 13487c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 13497c478bd9Sstevel@tonic-gate } 13507c478bd9Sstevel@tonic-gate /* 13517c478bd9Sstevel@tonic-gate * Since this is cheerio-based PCI card, we write 0xC in the 13527c478bd9Sstevel@tonic-gate * top 4 bits(4-7) of hm-rev and retain the bottom(0-3) bits 13537c478bd9Sstevel@tonic-gate * for Cheerio version(1.0 or 2.0 = 0xC0 or 0xC1) 13547c478bd9Sstevel@tonic-gate */ 13557c478bd9Sstevel@tonic-gate hm_rev = ddi_get8(cfg_handle, &cfg_ptr->revid); 13567c478bd9Sstevel@tonic-gate hm_rev = HME_1C0_REVID | (hm_rev & HME_REV_VERS_MASK); 13577c478bd9Sstevel@tonic-gate hmep->asic_rev = hm_rev; 13587c478bd9Sstevel@tonic-gate if (ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, 135985025c03Sgd "hm-rev", (caddr_t)&hm_rev, sizeof (hm_rev)) != 136085025c03Sgd DDI_SUCCESS) { 13617c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, AUTOCONFIG_MSG, 1362*06673d9bSGarrett D'Amore "ddi_prop_create error for hm_rev"); 13637c478bd9Sstevel@tonic-gate } 13647c478bd9Sstevel@tonic-gate ddi_regs_map_free(&cfg_handle); 13657c478bd9Sstevel@tonic-gate 13667c478bd9Sstevel@tonic-gate hmeget_hm_rev_property(hmep); 13677c478bd9Sstevel@tonic-gate 13687c478bd9Sstevel@tonic-gate /* get info via VPD */ 13690219346bSGarrett D'Amore if (hmeget_promprops(dip) != DDI_SUCCESS) { 13707c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, AUTOCONFIG_MSG, 1371*06673d9bSGarrett D'Amore "no promprops"); 13727c478bd9Sstevel@tonic-gate } 13737c478bd9Sstevel@tonic-gate } 13747c478bd9Sstevel@tonic-gate 13757c478bd9Sstevel@tonic-gate if (ddi_intr_hilevel(dip, 0)) { 13767c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_HIGH, NFATAL_ERR_MSG, 137785025c03Sgd " high-level interrupts are not supported"); 13787c478bd9Sstevel@tonic-gate goto error_unmap; 13797c478bd9Sstevel@tonic-gate } 13807c478bd9Sstevel@tonic-gate 13817c478bd9Sstevel@tonic-gate /* 13827c478bd9Sstevel@tonic-gate * Get intr. block cookie so that mutex locks can be initialized. 13837c478bd9Sstevel@tonic-gate */ 13847c478bd9Sstevel@tonic-gate if (ddi_get_iblock_cookie(dip, 0, &hmep->hme_cookie) != DDI_SUCCESS) 13857c478bd9Sstevel@tonic-gate goto error_unmap; 13867c478bd9Sstevel@tonic-gate 13877c478bd9Sstevel@tonic-gate /* 13887c478bd9Sstevel@tonic-gate * Initialize mutex's for this device. 13897c478bd9Sstevel@tonic-gate */ 139085025c03Sgd mutex_init(&hmep->hme_xmitlock, NULL, MUTEX_DRIVER, hmep->hme_cookie); 139185025c03Sgd mutex_init(&hmep->hme_intrlock, NULL, MUTEX_DRIVER, hmep->hme_cookie); 13927c478bd9Sstevel@tonic-gate 13937c478bd9Sstevel@tonic-gate /* 13947c478bd9Sstevel@tonic-gate * Quiesce the hardware. 13957c478bd9Sstevel@tonic-gate */ 13967c478bd9Sstevel@tonic-gate (void) hmestop(hmep); 13977c478bd9Sstevel@tonic-gate 13987c478bd9Sstevel@tonic-gate /* 13997c478bd9Sstevel@tonic-gate * Add interrupt to system 14007c478bd9Sstevel@tonic-gate */ 14017c478bd9Sstevel@tonic-gate if (ddi_add_intr(dip, 0, (ddi_iblock_cookie_t *)NULL, 14027c478bd9Sstevel@tonic-gate (ddi_idevice_cookie_t *)NULL, hmeintr, (caddr_t)hmep)) { 14037c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG, 140485025c03Sgd add_intr_fail_msg); 14057c478bd9Sstevel@tonic-gate goto error_mutex; 14067c478bd9Sstevel@tonic-gate } 14077c478bd9Sstevel@tonic-gate 14087c478bd9Sstevel@tonic-gate /* 14097c478bd9Sstevel@tonic-gate * Set up the ethernet mac address. 14107c478bd9Sstevel@tonic-gate */ 14117c478bd9Sstevel@tonic-gate hme_setup_mac_address(hmep, dip); 14127c478bd9Sstevel@tonic-gate 14137c478bd9Sstevel@tonic-gate if (!hmeinit_xfer_params(hmep)) 141485025c03Sgd goto error_intr; 14157c478bd9Sstevel@tonic-gate 14167c478bd9Sstevel@tonic-gate if (hmeburstsizes(hmep) == DDI_FAILURE) { 14177c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, burst_size_msg); 141885025c03Sgd goto error_intr; 14197c478bd9Sstevel@tonic-gate } 14207c478bd9Sstevel@tonic-gate 14210219346bSGarrett D'Amore if (hmeallocthings(hmep) != DDI_SUCCESS) { 14220219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, CONFIG_MSG, 14230219346bSGarrett D'Amore "resource allocation failed"); 14240219346bSGarrett D'Amore goto error_intr; 14250219346bSGarrett D'Amore } 14260219346bSGarrett D'Amore 14270219346bSGarrett D'Amore if (hmeallocbufs(hmep) != DDI_SUCCESS) { 14280219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, CONFIG_MSG, 14290219346bSGarrett D'Amore "buffer allocation failed"); 14300219346bSGarrett D'Amore goto error_intr; 14310219346bSGarrett D'Amore } 14327c478bd9Sstevel@tonic-gate 14337c478bd9Sstevel@tonic-gate hmestatinit(hmep); 143485025c03Sgd 1435*06673d9bSGarrett D'Amore hmep->hme_mii = mii_alloc(hmep, dip, &hme_mii_ops); 1436*06673d9bSGarrett D'Amore if (hmep->hme_mii == NULL) { 1437*06673d9bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, CONFIG_MSG, 1438*06673d9bSGarrett D'Amore "mii_alloc failed"); 1439*06673d9bSGarrett D'Amore goto error_intr; 1440*06673d9bSGarrett D'Amore } 1441*06673d9bSGarrett D'Amore /* force a probe for the PHY */ 1442*06673d9bSGarrett D'Amore mii_probe(hmep->hme_mii); 1443*06673d9bSGarrett D'Amore 144485025c03Sgd if ((macp = mac_alloc(MAC_VERSION)) == NULL) { 144585025c03Sgd HME_FAULT_MSG1(hmep, SEVERITY_HIGH, CONFIG_MSG, 144685025c03Sgd "mac_alloc failed"); 144785025c03Sgd goto error_intr; 144885025c03Sgd } 144985025c03Sgd macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 145085025c03Sgd macp->m_driver = hmep; 145185025c03Sgd macp->m_dip = dip; 145285025c03Sgd macp->m_src_addr = hmep->hme_ouraddr.ether_addr_octet; 145385025c03Sgd macp->m_callbacks = &hme_m_callbacks; 145485025c03Sgd macp->m_min_sdu = 0; 145585025c03Sgd macp->m_max_sdu = ETHERMTU; 1456d62bc4baSyz macp->m_margin = VLAN_TAGSZ; 1457*06673d9bSGarrett D'Amore macp->m_priv_props = hme_priv_prop; 1458*06673d9bSGarrett D'Amore macp->m_priv_prop_count = 1459*06673d9bSGarrett D'Amore sizeof (hme_priv_prop) / sizeof (hme_priv_prop[0]); 146085025c03Sgd if (mac_register(macp, &hmep->hme_mh) != 0) { 146185025c03Sgd mac_free(macp); 146285025c03Sgd goto error_intr; 146385025c03Sgd } 146485025c03Sgd 146585025c03Sgd mac_free(macp); 146685025c03Sgd 14677c478bd9Sstevel@tonic-gate ddi_report_dev(dip); 14687c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 14697c478bd9Sstevel@tonic-gate 14707c478bd9Sstevel@tonic-gate /* 14717c478bd9Sstevel@tonic-gate * Failure Exit 14727c478bd9Sstevel@tonic-gate */ 14737c478bd9Sstevel@tonic-gate 14747c478bd9Sstevel@tonic-gate error_intr: 14757c478bd9Sstevel@tonic-gate if (hmep->hme_cookie) 14767c478bd9Sstevel@tonic-gate ddi_remove_intr(dip, 0, (ddi_iblock_cookie_t)0); 14777c478bd9Sstevel@tonic-gate 1478*06673d9bSGarrett D'Amore if (hmep->hme_mii) 1479*06673d9bSGarrett D'Amore mii_free(hmep->hme_mii); 1480*06673d9bSGarrett D'Amore 14817c478bd9Sstevel@tonic-gate error_mutex: 14827c478bd9Sstevel@tonic-gate mutex_destroy(&hmep->hme_xmitlock); 14837c478bd9Sstevel@tonic-gate mutex_destroy(&hmep->hme_intrlock); 14847c478bd9Sstevel@tonic-gate 14857c478bd9Sstevel@tonic-gate error_unmap: 14867c478bd9Sstevel@tonic-gate if (hmep->hme_globregh) 148785025c03Sgd ddi_regs_map_free(&hmep->hme_globregh); 14887c478bd9Sstevel@tonic-gate if (hmep->hme_cheerio_mode == 0) { 14897c478bd9Sstevel@tonic-gate if (hmep->hme_etxregh) 149085025c03Sgd ddi_regs_map_free(&hmep->hme_etxregh); 14917c478bd9Sstevel@tonic-gate if (hmep->hme_erxregh) 149285025c03Sgd ddi_regs_map_free(&hmep->hme_erxregh); 14937c478bd9Sstevel@tonic-gate if (hmep->hme_bmacregh) 149485025c03Sgd ddi_regs_map_free(&hmep->hme_bmacregh); 14957c478bd9Sstevel@tonic-gate if (hmep->hme_mifregh) 149685025c03Sgd ddi_regs_map_free(&hmep->hme_mifregh); 14977c478bd9Sstevel@tonic-gate } else { 14987c478bd9Sstevel@tonic-gate if (hmep->pci_config_handle) 14997c478bd9Sstevel@tonic-gate (void) pci_config_teardown(&hmep->pci_config_handle); 15007c478bd9Sstevel@tonic-gate hmep->hme_etxregh = hmep->hme_erxregh = hmep->hme_bmacregh = 15017c478bd9Sstevel@tonic-gate hmep->hme_mifregh = hmep->hme_globregh = NULL; 15027c478bd9Sstevel@tonic-gate } 15037c478bd9Sstevel@tonic-gate 15047c478bd9Sstevel@tonic-gate error_state: 15050219346bSGarrett D'Amore hmefreethings(hmep); 15060219346bSGarrett D'Amore hmefreebufs(hmep); 15070219346bSGarrett D'Amore 15087c478bd9Sstevel@tonic-gate if (hmep) { 15097c478bd9Sstevel@tonic-gate kmem_free((caddr_t)hmep, sizeof (*hmep)); 15107c478bd9Sstevel@tonic-gate ddi_set_driver_private(dip, NULL); 15117c478bd9Sstevel@tonic-gate } 15127c478bd9Sstevel@tonic-gate 15137c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 15147c478bd9Sstevel@tonic-gate } 15157c478bd9Sstevel@tonic-gate 1516f2cd0f02Sgd int 15177c478bd9Sstevel@tonic-gate hmedetach(dev_info_t *dip, ddi_detach_cmd_t cmd) 15187c478bd9Sstevel@tonic-gate { 151985025c03Sgd struct hme *hmep; 15207c478bd9Sstevel@tonic-gate 15217c478bd9Sstevel@tonic-gate if ((hmep = ddi_get_driver_private(dip)) == NULL) 15227c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 15237c478bd9Sstevel@tonic-gate 15247c478bd9Sstevel@tonic-gate switch (cmd) { 15257c478bd9Sstevel@tonic-gate case DDI_DETACH: 15267c478bd9Sstevel@tonic-gate break; 15277c478bd9Sstevel@tonic-gate 15287c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 1529*06673d9bSGarrett D'Amore mii_suspend(hmep->hme_mii); 15307c478bd9Sstevel@tonic-gate hmep->hme_flags |= HMESUSPENDED; 15317c478bd9Sstevel@tonic-gate hmeuninit(hmep); 15327c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 15337c478bd9Sstevel@tonic-gate 15347c478bd9Sstevel@tonic-gate default: 153585025c03Sgd return (DDI_FAILURE); 153685025c03Sgd } 153785025c03Sgd 153885025c03Sgd 153985025c03Sgd if (mac_unregister(hmep->hme_mh) != 0) { 15407c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 15417c478bd9Sstevel@tonic-gate } 15427c478bd9Sstevel@tonic-gate 15437c478bd9Sstevel@tonic-gate /* 15447c478bd9Sstevel@tonic-gate * Make driver quiescent, we don't want to prevent the 15454dd87b61Sgd * detach on failure. Note that this should be redundant, 15464dd87b61Sgd * since mac_stop should already have called hmeuninit(). 15477c478bd9Sstevel@tonic-gate */ 15484dd87b61Sgd if (!(hmep->hme_flags & HMESUSPENDED)) { 15494dd87b61Sgd (void) hmestop(hmep); 15504dd87b61Sgd } 15517c478bd9Sstevel@tonic-gate 1552*06673d9bSGarrett D'Amore if (hmep->hme_mii) 1553*06673d9bSGarrett D'Amore mii_free(hmep->hme_mii); 1554*06673d9bSGarrett D'Amore 15557c478bd9Sstevel@tonic-gate /* 15567c478bd9Sstevel@tonic-gate * Remove instance of the intr 15577c478bd9Sstevel@tonic-gate */ 15587c478bd9Sstevel@tonic-gate ddi_remove_intr(dip, 0, (ddi_iblock_cookie_t)0); 15597c478bd9Sstevel@tonic-gate 156085025c03Sgd /* 156185025c03Sgd * Unregister kstats. 156285025c03Sgd */ 156385025c03Sgd if (hmep->hme_ksp != NULL) 156485025c03Sgd kstat_delete(hmep->hme_ksp); 156585025c03Sgd if (hmep->hme_intrstats != NULL) 156685025c03Sgd kstat_delete(hmep->hme_intrstats); 156785025c03Sgd 1568*06673d9bSGarrett D'Amore hmep->hme_ksp = NULL; 1569*06673d9bSGarrett D'Amore hmep->hme_intrstats = NULL; 157085025c03Sgd 15717c478bd9Sstevel@tonic-gate /* 15727c478bd9Sstevel@tonic-gate * Destroy all mutexes and data structures allocated during 15737c478bd9Sstevel@tonic-gate * attach time. 157485025c03Sgd * 157585025c03Sgd * Note: at this time we should be the only thread accessing 157685025c03Sgd * the structures for this instance. 15777c478bd9Sstevel@tonic-gate */ 15787c478bd9Sstevel@tonic-gate 15797c478bd9Sstevel@tonic-gate if (hmep->hme_globregh) 15807c478bd9Sstevel@tonic-gate ddi_regs_map_free(&hmep->hme_globregh); 15817c478bd9Sstevel@tonic-gate if (hmep->hme_cheerio_mode == 0) { 15827c478bd9Sstevel@tonic-gate if (hmep->hme_etxregh) 158385025c03Sgd ddi_regs_map_free(&hmep->hme_etxregh); 15847c478bd9Sstevel@tonic-gate if (hmep->hme_erxregh) 158585025c03Sgd ddi_regs_map_free(&hmep->hme_erxregh); 15867c478bd9Sstevel@tonic-gate if (hmep->hme_bmacregh) 158785025c03Sgd ddi_regs_map_free(&hmep->hme_bmacregh); 15887c478bd9Sstevel@tonic-gate if (hmep->hme_mifregh) 158985025c03Sgd ddi_regs_map_free(&hmep->hme_mifregh); 15907c478bd9Sstevel@tonic-gate } else { 15917c478bd9Sstevel@tonic-gate if (hmep->pci_config_handle) 15927c478bd9Sstevel@tonic-gate (void) pci_config_teardown(&hmep->pci_config_handle); 15937c478bd9Sstevel@tonic-gate hmep->hme_etxregh = hmep->hme_erxregh = hmep->hme_bmacregh = 15947c478bd9Sstevel@tonic-gate hmep->hme_mifregh = hmep->hme_globregh = NULL; 15957c478bd9Sstevel@tonic-gate } 15967c478bd9Sstevel@tonic-gate 159785025c03Sgd mutex_destroy(&hmep->hme_xmitlock); 159885025c03Sgd mutex_destroy(&hmep->hme_intrlock); 15997c478bd9Sstevel@tonic-gate 16000219346bSGarrett D'Amore hmefreethings(hmep); 160185025c03Sgd hmefreebufs(hmep); 16027c478bd9Sstevel@tonic-gate 160385025c03Sgd ddi_set_driver_private(dip, NULL); 160485025c03Sgd kmem_free(hmep, sizeof (struct hme)); 16057c478bd9Sstevel@tonic-gate 16067c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 16077c478bd9Sstevel@tonic-gate } 16087c478bd9Sstevel@tonic-gate 16090219346bSGarrett D'Amore int 16100219346bSGarrett D'Amore hmequiesce(dev_info_t *dip) 16110219346bSGarrett D'Amore { 16120219346bSGarrett D'Amore struct hme *hmep; 16130219346bSGarrett D'Amore 16140219346bSGarrett D'Amore if ((hmep = ddi_get_driver_private(dip)) == NULL) 16150219346bSGarrett D'Amore return (DDI_FAILURE); 16160219346bSGarrett D'Amore 16170219346bSGarrett D'Amore (void) hmestop(hmep); 16180219346bSGarrett D'Amore return (DDI_SUCCESS); 16190219346bSGarrett D'Amore } 16200219346bSGarrett D'Amore 162185025c03Sgd static boolean_t 16227c478bd9Sstevel@tonic-gate hmeinit_xfer_params(struct hme *hmep) 16237c478bd9Sstevel@tonic-gate { 16247c478bd9Sstevel@tonic-gate int hme_ipg1_conf, hme_ipg2_conf; 16257c478bd9Sstevel@tonic-gate int hme_ipg0_conf, hme_lance_mode_conf; 16267c478bd9Sstevel@tonic-gate int prop_len = sizeof (int); 16277c478bd9Sstevel@tonic-gate dev_info_t *dip; 16287c478bd9Sstevel@tonic-gate 16297c478bd9Sstevel@tonic-gate dip = hmep->dip; 16307c478bd9Sstevel@tonic-gate 16317c478bd9Sstevel@tonic-gate /* 16327c478bd9Sstevel@tonic-gate * Set up the start-up values for user-configurable parameters 16337c478bd9Sstevel@tonic-gate * Get the values from the global variables first. 16347c478bd9Sstevel@tonic-gate * Use the MASK to limit the value to allowed maximum. 16357c478bd9Sstevel@tonic-gate */ 1636*06673d9bSGarrett D'Amore hmep->hme_ipg1 = hme_ipg1 & HME_MASK_8BIT; 1637*06673d9bSGarrett D'Amore hmep->hme_ipg2 = hme_ipg2 & HME_MASK_8BIT; 1638*06673d9bSGarrett D'Amore hmep->hme_ipg0 = hme_ipg0 & HME_MASK_5BIT; 16397c478bd9Sstevel@tonic-gate 16407c478bd9Sstevel@tonic-gate /* 16417c478bd9Sstevel@tonic-gate * Get the parameter values configured in .conf file. 16427c478bd9Sstevel@tonic-gate */ 16437c478bd9Sstevel@tonic-gate if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "ipg1", 164485025c03Sgd (caddr_t)&hme_ipg1_conf, &prop_len) == DDI_PROP_SUCCESS) { 1645*06673d9bSGarrett D'Amore hmep->hme_ipg1 = hme_ipg1_conf & HME_MASK_8BIT; 16467c478bd9Sstevel@tonic-gate } 16477c478bd9Sstevel@tonic-gate 16487c478bd9Sstevel@tonic-gate if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "ipg2", 164985025c03Sgd (caddr_t)&hme_ipg2_conf, &prop_len) == DDI_PROP_SUCCESS) { 1650*06673d9bSGarrett D'Amore hmep->hme_ipg2 = hme_ipg2_conf & HME_MASK_8BIT; 16517c478bd9Sstevel@tonic-gate } 16527c478bd9Sstevel@tonic-gate 16537c478bd9Sstevel@tonic-gate if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "ipg0", 165485025c03Sgd (caddr_t)&hme_ipg0_conf, &prop_len) == DDI_PROP_SUCCESS) { 1655*06673d9bSGarrett D'Amore hmep->hme_ipg0 = hme_ipg0_conf & HME_MASK_5BIT; 16567c478bd9Sstevel@tonic-gate } 16577c478bd9Sstevel@tonic-gate 16587c478bd9Sstevel@tonic-gate if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "lance_mode", 165985025c03Sgd (caddr_t)&hme_lance_mode_conf, &prop_len) == DDI_PROP_SUCCESS) { 1660*06673d9bSGarrett D'Amore hmep->hme_lance_mode = hme_lance_mode_conf & HME_MASK_1BIT; 16617c478bd9Sstevel@tonic-gate } 16627c478bd9Sstevel@tonic-gate 16637c478bd9Sstevel@tonic-gate return (B_TRUE); 16647c478bd9Sstevel@tonic-gate } 16657c478bd9Sstevel@tonic-gate 16667c478bd9Sstevel@tonic-gate /* 16677c478bd9Sstevel@tonic-gate * Return 0 upon success, 1 on failure. 16687c478bd9Sstevel@tonic-gate */ 16697c478bd9Sstevel@tonic-gate static uint_t 16707c478bd9Sstevel@tonic-gate hmestop(struct hme *hmep) 16717c478bd9Sstevel@tonic-gate { 16727c478bd9Sstevel@tonic-gate /* 16737c478bd9Sstevel@tonic-gate * Disable the Tx dma engine. 16747c478bd9Sstevel@tonic-gate */ 16757c478bd9Sstevel@tonic-gate PUT_ETXREG(config, (GET_ETXREG(config) & ~HMET_CONFIG_TXDMA_EN)); 16767c478bd9Sstevel@tonic-gate HMEDELAY(((GET_ETXREG(state_mach) & 0x1f) == 0x1), HMEMAXRSTDELAY); 16777c478bd9Sstevel@tonic-gate 16787c478bd9Sstevel@tonic-gate /* 16797c478bd9Sstevel@tonic-gate * Disable the Rx dma engine. 16807c478bd9Sstevel@tonic-gate */ 16817c478bd9Sstevel@tonic-gate PUT_ERXREG(config, (GET_ERXREG(config) & ~HMER_CONFIG_RXDMA_EN)); 16827c478bd9Sstevel@tonic-gate HMEDELAY(((GET_ERXREG(state_mach) & 0x3f) == 0), HMEMAXRSTDELAY); 16837c478bd9Sstevel@tonic-gate 16847c478bd9Sstevel@tonic-gate /* 16857c478bd9Sstevel@tonic-gate * By this time all things should be quiet, so hit the 16867c478bd9Sstevel@tonic-gate * chip with a reset. 16877c478bd9Sstevel@tonic-gate */ 16887c478bd9Sstevel@tonic-gate PUT_GLOBREG(reset, HMEG_RESET_GLOBAL); 16897c478bd9Sstevel@tonic-gate 16907c478bd9Sstevel@tonic-gate HMEDELAY((GET_GLOBREG(reset) == 0), HMEMAXRSTDELAY); 16917c478bd9Sstevel@tonic-gate if (GET_GLOBREG(reset)) { 16927c478bd9Sstevel@tonic-gate return (1); 16937c478bd9Sstevel@tonic-gate } 16947c478bd9Sstevel@tonic-gate 16957c478bd9Sstevel@tonic-gate CHECK_GLOBREG(); 16967c478bd9Sstevel@tonic-gate return (0); 16977c478bd9Sstevel@tonic-gate } 16987c478bd9Sstevel@tonic-gate 16997c478bd9Sstevel@tonic-gate static int 17007c478bd9Sstevel@tonic-gate hmestat_kstat_update(kstat_t *ksp, int rw) 17017c478bd9Sstevel@tonic-gate { 17027c478bd9Sstevel@tonic-gate struct hme *hmep; 17037c478bd9Sstevel@tonic-gate struct hmekstat *hkp; 17047c478bd9Sstevel@tonic-gate 17057c478bd9Sstevel@tonic-gate hmep = (struct hme *)ksp->ks_private; 17067c478bd9Sstevel@tonic-gate hkp = (struct hmekstat *)ksp->ks_data; 17077c478bd9Sstevel@tonic-gate 170885025c03Sgd if (rw != KSTAT_READ) 170985025c03Sgd return (EACCES); 171085025c03Sgd 17117c478bd9Sstevel@tonic-gate /* 17127c478bd9Sstevel@tonic-gate * Update all the stats by reading all the counter registers. 17137c478bd9Sstevel@tonic-gate * Counter register stats are not updated till they overflow 17147c478bd9Sstevel@tonic-gate * and interrupt. 17157c478bd9Sstevel@tonic-gate */ 17167c478bd9Sstevel@tonic-gate 17177c478bd9Sstevel@tonic-gate mutex_enter(&hmep->hme_xmitlock); 17184dd87b61Sgd if (hmep->hme_flags & HMERUNNING) { 17197c478bd9Sstevel@tonic-gate hmereclaim(hmep); 17204dd87b61Sgd hmesavecntrs(hmep); 17214dd87b61Sgd } 17227c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_xmitlock); 17237c478bd9Sstevel@tonic-gate 172485025c03Sgd hkp->hk_cvc.value.ul = hmep->hme_cvc; 172585025c03Sgd hkp->hk_lenerr.value.ul = hmep->hme_lenerr; 172685025c03Sgd hkp->hk_buff.value.ul = hmep->hme_buff; 172785025c03Sgd hkp->hk_missed.value.ul = hmep->hme_missed; 172885025c03Sgd hkp->hk_allocbfail.value.ul = hmep->hme_allocbfail; 172985025c03Sgd hkp->hk_babl.value.ul = hmep->hme_babl; 173085025c03Sgd hkp->hk_tmder.value.ul = hmep->hme_tmder; 173185025c03Sgd hkp->hk_txlaterr.value.ul = hmep->hme_txlaterr; 173285025c03Sgd hkp->hk_rxlaterr.value.ul = hmep->hme_rxlaterr; 173385025c03Sgd hkp->hk_slvparerr.value.ul = hmep->hme_slvparerr; 173485025c03Sgd hkp->hk_txparerr.value.ul = hmep->hme_txparerr; 173585025c03Sgd hkp->hk_rxparerr.value.ul = hmep->hme_rxparerr; 173685025c03Sgd hkp->hk_slverrack.value.ul = hmep->hme_slverrack; 173785025c03Sgd hkp->hk_txerrack.value.ul = hmep->hme_txerrack; 173885025c03Sgd hkp->hk_rxerrack.value.ul = hmep->hme_rxerrack; 173985025c03Sgd hkp->hk_txtagerr.value.ul = hmep->hme_txtagerr; 174085025c03Sgd hkp->hk_rxtagerr.value.ul = hmep->hme_rxtagerr; 174185025c03Sgd hkp->hk_eoperr.value.ul = hmep->hme_eoperr; 174285025c03Sgd hkp->hk_notmds.value.ul = hmep->hme_notmds; 174385025c03Sgd hkp->hk_notbufs.value.ul = hmep->hme_notbufs; 174485025c03Sgd hkp->hk_norbufs.value.ul = hmep->hme_norbufs; 17457c478bd9Sstevel@tonic-gate 174685025c03Sgd /* 174785025c03Sgd * Debug kstats 174885025c03Sgd */ 174985025c03Sgd hkp->hk_inits.value.ul = hmep->inits; 175085025c03Sgd hkp->hk_phyfail.value.ul = hmep->phyfail; 17517c478bd9Sstevel@tonic-gate 175285025c03Sgd /* 175385025c03Sgd * xcvr kstats 175485025c03Sgd */ 175585025c03Sgd hkp->hk_asic_rev.value.ul = hmep->asic_rev; 17567c478bd9Sstevel@tonic-gate 17577c478bd9Sstevel@tonic-gate return (0); 17587c478bd9Sstevel@tonic-gate } 17597c478bd9Sstevel@tonic-gate 17607c478bd9Sstevel@tonic-gate static void 17617c478bd9Sstevel@tonic-gate hmestatinit(struct hme *hmep) 17627c478bd9Sstevel@tonic-gate { 17637c478bd9Sstevel@tonic-gate struct kstat *ksp; 17647c478bd9Sstevel@tonic-gate struct hmekstat *hkp; 1765f2cd0f02Sgd const char *driver; 17667c478bd9Sstevel@tonic-gate int instance; 17677c478bd9Sstevel@tonic-gate char buf[16]; 17687c478bd9Sstevel@tonic-gate 17697c478bd9Sstevel@tonic-gate instance = hmep->instance; 1770f2cd0f02Sgd driver = ddi_driver_name(hmep->dip); 17717c478bd9Sstevel@tonic-gate 1772f2cd0f02Sgd if ((ksp = kstat_create(driver, instance, 177385025c03Sgd "driver_info", "net", KSTAT_TYPE_NAMED, 17747c478bd9Sstevel@tonic-gate sizeof (struct hmekstat) / sizeof (kstat_named_t), 0)) == NULL) { 17757c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, INIT_MSG, 17760219346bSGarrett D'Amore "kstat_create failed"); 17777c478bd9Sstevel@tonic-gate return; 17787c478bd9Sstevel@tonic-gate } 17797c478bd9Sstevel@tonic-gate 1780f2cd0f02Sgd (void) snprintf(buf, sizeof (buf), "%sc%d", driver, instance); 1781f2cd0f02Sgd hmep->hme_intrstats = kstat_create(driver, instance, buf, "controller", 178285025c03Sgd KSTAT_TYPE_INTR, 1, KSTAT_FLAG_PERSISTENT); 17837c478bd9Sstevel@tonic-gate if (hmep->hme_intrstats) 17847c478bd9Sstevel@tonic-gate kstat_install(hmep->hme_intrstats); 17857c478bd9Sstevel@tonic-gate 17867c478bd9Sstevel@tonic-gate hmep->hme_ksp = ksp; 17877c478bd9Sstevel@tonic-gate hkp = (struct hmekstat *)ksp->ks_data; 17887c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_cvc, "code_violations", 178985025c03Sgd KSTAT_DATA_ULONG); 17907c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_lenerr, "len_errors", 179185025c03Sgd KSTAT_DATA_ULONG); 17927c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_buff, "buff", 179385025c03Sgd KSTAT_DATA_ULONG); 17947c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_missed, "missed", 179585025c03Sgd KSTAT_DATA_ULONG); 17967c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_nocanput, "nocanput", 179785025c03Sgd KSTAT_DATA_ULONG); 17987c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_allocbfail, "allocbfail", 179985025c03Sgd KSTAT_DATA_ULONG); 18007c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_babl, "babble", 180185025c03Sgd KSTAT_DATA_ULONG); 18027c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_tmder, "tmd_error", 180385025c03Sgd KSTAT_DATA_ULONG); 18047c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_txlaterr, "tx_late_error", 180585025c03Sgd KSTAT_DATA_ULONG); 18067c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_rxlaterr, "rx_late_error", 180785025c03Sgd KSTAT_DATA_ULONG); 18087c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_slvparerr, "slv_parity_error", 180985025c03Sgd KSTAT_DATA_ULONG); 18107c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_txparerr, "tx_parity_error", 181185025c03Sgd KSTAT_DATA_ULONG); 18127c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_rxparerr, "rx_parity_error", 181385025c03Sgd KSTAT_DATA_ULONG); 18147c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_slverrack, "slv_error_ack", 181585025c03Sgd KSTAT_DATA_ULONG); 18167c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_txerrack, "tx_error_ack", 181785025c03Sgd KSTAT_DATA_ULONG); 18187c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_rxerrack, "rx_error_ack", 181985025c03Sgd KSTAT_DATA_ULONG); 18207c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_txtagerr, "tx_tag_error", 182185025c03Sgd KSTAT_DATA_ULONG); 18227c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_rxtagerr, "rx_tag_error", 182385025c03Sgd KSTAT_DATA_ULONG); 18247c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_eoperr, "eop_error", 182585025c03Sgd KSTAT_DATA_ULONG); 18267c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_notmds, "no_tmds", 182785025c03Sgd KSTAT_DATA_ULONG); 18287c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_notbufs, "no_tbufs", 182985025c03Sgd KSTAT_DATA_ULONG); 18307c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_norbufs, "no_rbufs", 183185025c03Sgd KSTAT_DATA_ULONG); 18327c478bd9Sstevel@tonic-gate 18337c478bd9Sstevel@tonic-gate /* 18347c478bd9Sstevel@tonic-gate * Debugging kstats 18357c478bd9Sstevel@tonic-gate */ 18367c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_inits, "inits", 183785025c03Sgd KSTAT_DATA_ULONG); 18387c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_phyfail, "phy_failures", 183985025c03Sgd KSTAT_DATA_ULONG); 18407c478bd9Sstevel@tonic-gate 18417c478bd9Sstevel@tonic-gate /* 18427c478bd9Sstevel@tonic-gate * xcvr kstats 18437c478bd9Sstevel@tonic-gate */ 18447c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_asic_rev, "asic_rev", 184585025c03Sgd KSTAT_DATA_ULONG); 18467c478bd9Sstevel@tonic-gate 18477c478bd9Sstevel@tonic-gate ksp->ks_update = hmestat_kstat_update; 18487c478bd9Sstevel@tonic-gate ksp->ks_private = (void *) hmep; 18497c478bd9Sstevel@tonic-gate kstat_install(ksp); 18507c478bd9Sstevel@tonic-gate } 18517c478bd9Sstevel@tonic-gate 1852*06673d9bSGarrett D'Amore int 1853*06673d9bSGarrett D'Amore hme_m_getprop(void *arg, const char *name, mac_prop_id_t num, uint_t flags, 1854*06673d9bSGarrett D'Amore uint_t sz, void *val, uint_t *perm) 18557c478bd9Sstevel@tonic-gate { 1856*06673d9bSGarrett D'Amore struct hme *hmep = arg; 1857*06673d9bSGarrett D'Amore int value; 1858*06673d9bSGarrett D'Amore boolean_t is_default; 1859*06673d9bSGarrett D'Amore int rv; 1860*06673d9bSGarrett D'Amore 1861*06673d9bSGarrett D'Amore rv = mii_m_getprop(hmep->hme_mii, name, num, flags, sz, val, perm); 1862*06673d9bSGarrett D'Amore if (rv != ENOTSUP) 1863*06673d9bSGarrett D'Amore return (rv); 1864*06673d9bSGarrett D'Amore 1865*06673d9bSGarrett D'Amore switch (num) { 1866*06673d9bSGarrett D'Amore case MAC_PROP_PRIVATE: 1867*06673d9bSGarrett D'Amore break; 1868*06673d9bSGarrett D'Amore default: 1869*06673d9bSGarrett D'Amore return (ENOTSUP); 1870*06673d9bSGarrett D'Amore } 1871*06673d9bSGarrett D'Amore 1872*06673d9bSGarrett D'Amore *perm = MAC_PROP_PERM_RW; 1873*06673d9bSGarrett D'Amore 1874*06673d9bSGarrett D'Amore is_default = (flags & MAC_PROP_DEFAULT) ? B_TRUE : B_FALSE; 1875*06673d9bSGarrett D'Amore if (strcmp(name, "_ipg0") == 0) { 1876*06673d9bSGarrett D'Amore value = is_default ? hme_ipg0 : hmep->hme_ipg0; 1877*06673d9bSGarrett D'Amore 1878*06673d9bSGarrett D'Amore } else if (strcmp(name, "_ipg1") == 0) { 1879*06673d9bSGarrett D'Amore value = is_default ? hme_ipg1 : hmep->hme_ipg1; 1880*06673d9bSGarrett D'Amore } else if (strcmp(name, "_ipg2") == 0) { 1881*06673d9bSGarrett D'Amore value = is_default ? hme_ipg2 : hmep->hme_ipg2; 1882*06673d9bSGarrett D'Amore } else if (strcmp(name, "_lance_mode") == 0) { 1883*06673d9bSGarrett D'Amore value = is_default ? hme_lance_mode : hmep->hme_lance_mode; 1884*06673d9bSGarrett D'Amore } else { 1885*06673d9bSGarrett D'Amore return (ENOTSUP); 1886*06673d9bSGarrett D'Amore } 1887*06673d9bSGarrett D'Amore (void) snprintf(val, sz, "%d", value); 1888*06673d9bSGarrett D'Amore return (0); 1889*06673d9bSGarrett D'Amore } 1890*06673d9bSGarrett D'Amore 1891*06673d9bSGarrett D'Amore int 1892*06673d9bSGarrett D'Amore hme_m_setprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz, 1893*06673d9bSGarrett D'Amore const void *val) 1894*06673d9bSGarrett D'Amore { 1895*06673d9bSGarrett D'Amore struct hme *hmep = arg; 1896*06673d9bSGarrett D'Amore int rv; 1897*06673d9bSGarrett D'Amore long lval; 1898*06673d9bSGarrett D'Amore boolean_t init = B_FALSE; 1899*06673d9bSGarrett D'Amore 1900*06673d9bSGarrett D'Amore rv = mii_m_setprop(hmep->hme_mii, name, num, sz, val); 1901*06673d9bSGarrett D'Amore if (rv != ENOTSUP) 1902*06673d9bSGarrett D'Amore return (rv); 1903*06673d9bSGarrett D'Amore rv = 0; 1904*06673d9bSGarrett D'Amore 1905*06673d9bSGarrett D'Amore switch (num) { 1906*06673d9bSGarrett D'Amore case MAC_PROP_PRIVATE: 190785025c03Sgd break; 1908*06673d9bSGarrett D'Amore default: 1909*06673d9bSGarrett D'Amore return (ENOTSUP); 1910*06673d9bSGarrett D'Amore } 19117c478bd9Sstevel@tonic-gate 1912*06673d9bSGarrett D'Amore (void) ddi_strtol(val, NULL, 0, &lval); 1913*06673d9bSGarrett D'Amore 1914*06673d9bSGarrett D'Amore if (strcmp(name, "_ipg1") == 0) { 1915*06673d9bSGarrett D'Amore if ((lval >= 0) && (lval <= 255)) { 1916*06673d9bSGarrett D'Amore hmep->hme_ipg1 = lval & 0xff; 1917*06673d9bSGarrett D'Amore init = B_TRUE; 1918*06673d9bSGarrett D'Amore } else { 1919*06673d9bSGarrett D'Amore return (EINVAL); 192085025c03Sgd } 19217c478bd9Sstevel@tonic-gate 1922*06673d9bSGarrett D'Amore } else if (strcmp(name, "_ipg2") == 0) { 1923*06673d9bSGarrett D'Amore if ((lval >= 0) && (lval <= 255)) { 1924*06673d9bSGarrett D'Amore hmep->hme_ipg2 = lval & 0xff; 1925*06673d9bSGarrett D'Amore init = B_TRUE; 1926*06673d9bSGarrett D'Amore } else { 1927*06673d9bSGarrett D'Amore return (EINVAL); 1928*06673d9bSGarrett D'Amore } 19297c478bd9Sstevel@tonic-gate 1930*06673d9bSGarrett D'Amore } else if (strcmp(name, "_ipg0") == 0) { 1931*06673d9bSGarrett D'Amore if ((lval >= 0) && (lval <= 31)) { 1932*06673d9bSGarrett D'Amore hmep->hme_ipg0 = lval & 0xff; 1933*06673d9bSGarrett D'Amore init = B_TRUE; 193485025c03Sgd } else { 1935*06673d9bSGarrett D'Amore return (EINVAL); 1936*06673d9bSGarrett D'Amore } 1937*06673d9bSGarrett D'Amore } else if (strcmp(name, "_lance_mode") == 0) { 1938*06673d9bSGarrett D'Amore if ((lval >= 0) && (lval <= 1)) { 1939*06673d9bSGarrett D'Amore hmep->hme_lance_mode = lval & 0xff; 1940*06673d9bSGarrett D'Amore init = B_TRUE; 1941*06673d9bSGarrett D'Amore } else { 1942*06673d9bSGarrett D'Amore return (EINVAL); 19437c478bd9Sstevel@tonic-gate } 19447c478bd9Sstevel@tonic-gate 1945*06673d9bSGarrett D'Amore } else { 1946*06673d9bSGarrett D'Amore rv = ENOTSUP; 1947*06673d9bSGarrett D'Amore } 1948*06673d9bSGarrett D'Amore 1949*06673d9bSGarrett D'Amore if (init) { 1950*06673d9bSGarrett D'Amore (void) hmeinit(hmep); 19517c478bd9Sstevel@tonic-gate } 1952*06673d9bSGarrett D'Amore return (rv); 19537c478bd9Sstevel@tonic-gate } 19547c478bd9Sstevel@tonic-gate 1955*06673d9bSGarrett D'Amore 195685025c03Sgd /*ARGSUSED*/ 195785025c03Sgd static boolean_t 195885025c03Sgd hme_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) 19597c478bd9Sstevel@tonic-gate { 196085025c03Sgd switch (cap) { 196185025c03Sgd case MAC_CAPAB_HCKSUM: 196285025c03Sgd *(uint32_t *)cap_data = HCKSUM_INET_PARTIAL; 196385025c03Sgd return (B_TRUE); 196485025c03Sgd default: 196585025c03Sgd return (B_FALSE); 19667c478bd9Sstevel@tonic-gate } 196785025c03Sgd } 19687c478bd9Sstevel@tonic-gate 196985025c03Sgd static int 197085025c03Sgd hme_m_promisc(void *arg, boolean_t on) 197185025c03Sgd { 197285025c03Sgd struct hme *hmep = arg; 19737c478bd9Sstevel@tonic-gate 197485025c03Sgd hmep->hme_promisc = on; 197585025c03Sgd (void) hmeinit(hmep); 197685025c03Sgd return (0); 197785025c03Sgd } 19787c478bd9Sstevel@tonic-gate 197985025c03Sgd static int 198085025c03Sgd hme_m_unicst(void *arg, const uint8_t *macaddr) 198185025c03Sgd { 198285025c03Sgd struct hme *hmep = arg; 19837c478bd9Sstevel@tonic-gate 19847c478bd9Sstevel@tonic-gate /* 19857c478bd9Sstevel@tonic-gate * Set new interface local address and re-init device. 19867c478bd9Sstevel@tonic-gate * This is destructive to any other streams attached 19877c478bd9Sstevel@tonic-gate * to this device. 19887c478bd9Sstevel@tonic-gate */ 198985025c03Sgd mutex_enter(&hmep->hme_intrlock); 199085025c03Sgd bcopy(macaddr, &hmep->hme_ouraddr, ETHERADDRL); 199185025c03Sgd mutex_exit(&hmep->hme_intrlock); 199285025c03Sgd (void) hmeinit(hmep); 199385025c03Sgd return (0); 19947c478bd9Sstevel@tonic-gate } 19957c478bd9Sstevel@tonic-gate 199685025c03Sgd static int 199785025c03Sgd hme_m_multicst(void *arg, boolean_t add, const uint8_t *macaddr) 19987c478bd9Sstevel@tonic-gate { 199985025c03Sgd struct hme *hmep = arg; 200085025c03Sgd uint32_t ladrf_bit; 200185025c03Sgd boolean_t doinit = B_FALSE; 20027c478bd9Sstevel@tonic-gate 20037c478bd9Sstevel@tonic-gate /* 200485025c03Sgd * If this address's bit was not already set in the local address 200585025c03Sgd * filter, add it and re-initialize the Hardware. 20067c478bd9Sstevel@tonic-gate */ 200785025c03Sgd ladrf_bit = hmeladrf_bit(macaddr); 20087c478bd9Sstevel@tonic-gate 200985025c03Sgd mutex_enter(&hmep->hme_intrlock); 201085025c03Sgd if (add) { 201185025c03Sgd hmep->hme_ladrf_refcnt[ladrf_bit]++; 201285025c03Sgd if (hmep->hme_ladrf_refcnt[ladrf_bit] == 1) { 201385025c03Sgd hmep->hme_ladrf[ladrf_bit >> 4] |= 201485025c03Sgd 1 << (ladrf_bit & 0xf); 201585025c03Sgd hmep->hme_multi++; 201685025c03Sgd doinit = B_TRUE; 201785025c03Sgd } 20187c478bd9Sstevel@tonic-gate } else { 201985025c03Sgd hmep->hme_ladrf_refcnt[ladrf_bit]--; 202085025c03Sgd if (hmep->hme_ladrf_refcnt[ladrf_bit] == 0) { 202185025c03Sgd hmep->hme_ladrf[ladrf_bit >> 4] &= 202285025c03Sgd ~(1 << (ladrf_bit & 0xf)); 202385025c03Sgd doinit = B_TRUE; 20247c478bd9Sstevel@tonic-gate } 20257c478bd9Sstevel@tonic-gate } 202685025c03Sgd mutex_exit(&hmep->hme_intrlock); 20277c478bd9Sstevel@tonic-gate 20280219346bSGarrett D'Amore if (doinit) { 202985025c03Sgd (void) hmeinit(hmep); 20300219346bSGarrett D'Amore } 20317c478bd9Sstevel@tonic-gate 203285025c03Sgd return (0); 20337c478bd9Sstevel@tonic-gate } 20347c478bd9Sstevel@tonic-gate 203585025c03Sgd static int 203685025c03Sgd hme_m_start(void *arg) 20377c478bd9Sstevel@tonic-gate { 203885025c03Sgd struct hme *hmep = arg; 20397c478bd9Sstevel@tonic-gate 2040228fdff0Sgd if (hmeinit(hmep) != 0) { 2041228fdff0Sgd /* initialization failed -- really want DL_INITFAILED */ 2042228fdff0Sgd return (EIO); 2043228fdff0Sgd } else { 2044228fdff0Sgd hmep->hme_started = B_TRUE; 2045*06673d9bSGarrett D'Amore mii_start(hmep->hme_mii); 2046228fdff0Sgd return (0); 2047228fdff0Sgd } 204885025c03Sgd } 20497c478bd9Sstevel@tonic-gate 205085025c03Sgd static void 205185025c03Sgd hme_m_stop(void *arg) 205285025c03Sgd { 205385025c03Sgd struct hme *hmep = arg; 20547c478bd9Sstevel@tonic-gate 2055*06673d9bSGarrett D'Amore mii_stop(hmep->hme_mii); 2056228fdff0Sgd hmep->hme_started = B_FALSE; 205785025c03Sgd hmeuninit(hmep); 205885025c03Sgd } 20597c478bd9Sstevel@tonic-gate 206085025c03Sgd static int 206185025c03Sgd hme_m_stat(void *arg, uint_t stat, uint64_t *val) 206285025c03Sgd { 206385025c03Sgd struct hme *hmep = arg; 20647c478bd9Sstevel@tonic-gate 206585025c03Sgd mutex_enter(&hmep->hme_xmitlock); 20664dd87b61Sgd if (hmep->hme_flags & HMERUNNING) { 206785025c03Sgd hmereclaim(hmep); 20684dd87b61Sgd hmesavecntrs(hmep); 20694dd87b61Sgd } 207085025c03Sgd mutex_exit(&hmep->hme_xmitlock); 20717c478bd9Sstevel@tonic-gate 20727c478bd9Sstevel@tonic-gate 2073*06673d9bSGarrett D'Amore if (mii_m_getstat(hmep->hme_mii, stat, val) == 0) { 2074*06673d9bSGarrett D'Amore return (0); 2075*06673d9bSGarrett D'Amore } 207685025c03Sgd switch (stat) { 207785025c03Sgd case MAC_STAT_IPACKETS: 207885025c03Sgd *val = hmep->hme_ipackets; 207985025c03Sgd break; 208085025c03Sgd case MAC_STAT_RBYTES: 208185025c03Sgd *val = hmep->hme_rbytes; 208285025c03Sgd break; 208385025c03Sgd case MAC_STAT_IERRORS: 208485025c03Sgd *val = hmep->hme_ierrors; 208585025c03Sgd break; 208685025c03Sgd case MAC_STAT_OPACKETS: 208785025c03Sgd *val = hmep->hme_opackets; 208885025c03Sgd break; 208985025c03Sgd case MAC_STAT_OBYTES: 209085025c03Sgd *val = hmep->hme_obytes; 209185025c03Sgd break; 209285025c03Sgd case MAC_STAT_OERRORS: 209385025c03Sgd *val = hmep->hme_oerrors; 209485025c03Sgd break; 209585025c03Sgd case MAC_STAT_MULTIRCV: 209685025c03Sgd *val = hmep->hme_multircv; 209785025c03Sgd break; 209885025c03Sgd case MAC_STAT_MULTIXMT: 209985025c03Sgd *val = hmep->hme_multixmt; 210085025c03Sgd break; 210185025c03Sgd case MAC_STAT_BRDCSTRCV: 210285025c03Sgd *val = hmep->hme_brdcstrcv; 210385025c03Sgd break; 210485025c03Sgd case MAC_STAT_BRDCSTXMT: 210585025c03Sgd *val = hmep->hme_brdcstxmt; 210685025c03Sgd break; 210785025c03Sgd case MAC_STAT_UNDERFLOWS: 210885025c03Sgd *val = hmep->hme_uflo; 210985025c03Sgd break; 211085025c03Sgd case MAC_STAT_OVERFLOWS: 211185025c03Sgd *val = hmep->hme_oflo; 211285025c03Sgd break; 211385025c03Sgd case MAC_STAT_COLLISIONS: 211485025c03Sgd *val = hmep->hme_coll; 211585025c03Sgd break; 211685025c03Sgd case MAC_STAT_NORCVBUF: 211785025c03Sgd *val = hmep->hme_norcvbuf; 211885025c03Sgd break; 211985025c03Sgd case MAC_STAT_NOXMTBUF: 212085025c03Sgd *val = hmep->hme_noxmtbuf; 212185025c03Sgd break; 212285025c03Sgd case ETHER_STAT_LINK_DUPLEX: 212385025c03Sgd *val = hmep->hme_duplex; 212485025c03Sgd break; 212585025c03Sgd case ETHER_STAT_ALIGN_ERRORS: 212685025c03Sgd *val = hmep->hme_align_errors; 212785025c03Sgd break; 212885025c03Sgd case ETHER_STAT_FCS_ERRORS: 212985025c03Sgd *val = hmep->hme_fcs_errors; 213085025c03Sgd break; 213185025c03Sgd case ETHER_STAT_EX_COLLISIONS: 213285025c03Sgd *val = hmep->hme_excol; 213385025c03Sgd break; 213485025c03Sgd case ETHER_STAT_DEFER_XMTS: 213585025c03Sgd *val = hmep->hme_defer_xmts; 213685025c03Sgd break; 213785025c03Sgd case ETHER_STAT_SQE_ERRORS: 213885025c03Sgd *val = hmep->hme_sqe_errors; 213985025c03Sgd break; 214085025c03Sgd case ETHER_STAT_FIRST_COLLISIONS: 214185025c03Sgd *val = hmep->hme_fstcol; 214285025c03Sgd break; 214385025c03Sgd case ETHER_STAT_TX_LATE_COLLISIONS: 214485025c03Sgd *val = hmep->hme_tlcol; 214585025c03Sgd break; 214685025c03Sgd case ETHER_STAT_TOOLONG_ERRORS: 214785025c03Sgd *val = hmep->hme_toolong_errors; 214885025c03Sgd break; 214985025c03Sgd case ETHER_STAT_TOOSHORT_ERRORS: 215085025c03Sgd *val = hmep->hme_runt; 215185025c03Sgd break; 21524dd87b61Sgd case ETHER_STAT_CARRIER_ERRORS: 21534dd87b61Sgd *val = hmep->hme_carrier_errors; 21544dd87b61Sgd break; 215585025c03Sgd default: 215685025c03Sgd return (EINVAL); 21577c478bd9Sstevel@tonic-gate } 215885025c03Sgd return (0); 21597c478bd9Sstevel@tonic-gate } 21607c478bd9Sstevel@tonic-gate 216185025c03Sgd static mblk_t * 216285025c03Sgd hme_m_tx(void *arg, mblk_t *mp) 21637c478bd9Sstevel@tonic-gate { 216485025c03Sgd struct hme *hmep = arg; 216585025c03Sgd mblk_t *next; 21667c478bd9Sstevel@tonic-gate 216785025c03Sgd while (mp != NULL) { 216885025c03Sgd next = mp->b_next; 216985025c03Sgd mp->b_next = NULL; 217085025c03Sgd if (!hmestart(hmep, mp)) { 217185025c03Sgd mp->b_next = next; 217285025c03Sgd break; 21737c478bd9Sstevel@tonic-gate } 217485025c03Sgd mp = next; 21757c478bd9Sstevel@tonic-gate } 217685025c03Sgd return (mp); 21777c478bd9Sstevel@tonic-gate } 21787c478bd9Sstevel@tonic-gate 2179eb7b3d20Sgd /* 2180eb7b3d20Sgd * Software IP checksum, for the edge cases that the 2181eb7b3d20Sgd * hardware can't handle. See hmestart for more info. 2182eb7b3d20Sgd */ 2183eb7b3d20Sgd static uint16_t 2184eb7b3d20Sgd hme_cksum(void *data, int len) 2185eb7b3d20Sgd { 2186eb7b3d20Sgd uint16_t *words = data; 2187eb7b3d20Sgd int i, nwords = len / 2; 2188eb7b3d20Sgd uint32_t sum = 0; 2189eb7b3d20Sgd 2190eb7b3d20Sgd /* just add up the words */ 2191eb7b3d20Sgd for (i = 0; i < nwords; i++) { 2192eb7b3d20Sgd sum += *words++; 2193eb7b3d20Sgd } 2194eb7b3d20Sgd 2195eb7b3d20Sgd /* pick up residual byte ... assume even half-word allocations */ 2196eb7b3d20Sgd if (len % 2) { 21970219346bSGarrett D'Amore sum += (*words & htons(0xff00)); 2198eb7b3d20Sgd } 2199eb7b3d20Sgd 2200eb7b3d20Sgd sum = (sum >> 16) + (sum & 0xffff); 2201eb7b3d20Sgd sum = (sum >> 16) + (sum & 0xffff); 2202eb7b3d20Sgd 2203eb7b3d20Sgd return (~(sum & 0xffff)); 2204eb7b3d20Sgd } 2205eb7b3d20Sgd 220685025c03Sgd static boolean_t 22070219346bSGarrett D'Amore hmestart(struct hme *hmep, mblk_t *mp) 22087c478bd9Sstevel@tonic-gate { 22090219346bSGarrett D'Amore uint32_t len; 22100219346bSGarrett D'Amore boolean_t retval = B_TRUE; 22110219346bSGarrett D'Amore hmebuf_t *tbuf; 22120219346bSGarrett D'Amore uint32_t txptr; 22137c478bd9Sstevel@tonic-gate 221485025c03Sgd uint32_t csflags = 0; 221585025c03Sgd uint32_t flags; 221685025c03Sgd uint32_t start_offset; 221785025c03Sgd uint32_t stuff_offset; 22187c478bd9Sstevel@tonic-gate 221985025c03Sgd hcksum_retrieve(mp, NULL, NULL, &start_offset, &stuff_offset, 222085025c03Sgd NULL, NULL, &flags); 22217c478bd9Sstevel@tonic-gate 222285025c03Sgd if (flags & HCK_PARTIALCKSUM) { 222385025c03Sgd if (get_ether_type(mp->b_rptr) == ETHERTYPE_VLAN) { 222485025c03Sgd start_offset += sizeof (struct ether_header) + 4; 222585025c03Sgd stuff_offset += sizeof (struct ether_header) + 4; 222685025c03Sgd } else { 222785025c03Sgd start_offset += sizeof (struct ether_header); 222885025c03Sgd stuff_offset += sizeof (struct ether_header); 22297c478bd9Sstevel@tonic-gate } 223085025c03Sgd csflags = HMETMD_CSENABL | 223185025c03Sgd (start_offset << HMETMD_CSSTART_SHIFT) | 223285025c03Sgd (stuff_offset << HMETMD_CSSTUFF_SHIFT); 223385025c03Sgd } 22347c478bd9Sstevel@tonic-gate 22357c478bd9Sstevel@tonic-gate mutex_enter(&hmep->hme_xmitlock); 22367c478bd9Sstevel@tonic-gate 22374dd87b61Sgd if (hmep->hme_flags & HMESUSPENDED) { 22384dd87b61Sgd hmep->hme_carrier_errors++; 22394dd87b61Sgd hmep->hme_oerrors++; 22404dd87b61Sgd goto bad; 22414dd87b61Sgd } 22424dd87b61Sgd 22430219346bSGarrett D'Amore if (hmep->hme_txindex != hmep->hme_txreclaim) { 22440219346bSGarrett D'Amore hmereclaim(hmep); 22457c478bd9Sstevel@tonic-gate } 22460219346bSGarrett D'Amore if ((hmep->hme_txindex - HME_TMDMAX) == hmep->hme_txreclaim) 22477c478bd9Sstevel@tonic-gate goto notmds; 22480219346bSGarrett D'Amore txptr = hmep->hme_txindex % HME_TMDMAX; 22490219346bSGarrett D'Amore tbuf = &hmep->hme_tbuf[txptr]; 22507c478bd9Sstevel@tonic-gate 2251eb7b3d20Sgd /* 2252eb7b3d20Sgd * Note that for checksum offload, the hardware cannot 2253eb7b3d20Sgd * generate correct checksums if the packet is smaller than 2254eb7b3d20Sgd * 64-bytes. In such a case, we bcopy the packet and use 2255eb7b3d20Sgd * a software checksum. 2256eb7b3d20Sgd */ 2257eb7b3d20Sgd 22580219346bSGarrett D'Amore len = msgsize(mp); 22590219346bSGarrett D'Amore if (len < 64) { 22600219346bSGarrett D'Amore /* zero fill the padding */ 22610219346bSGarrett D'Amore bzero(tbuf->kaddr, 64); 22627c478bd9Sstevel@tonic-gate } 22630219346bSGarrett D'Amore mcopymsg(mp, tbuf->kaddr); 22647c478bd9Sstevel@tonic-gate 22650219346bSGarrett D'Amore if ((csflags != 0) && (len < 64)) { 22660219346bSGarrett D'Amore uint16_t sum; 22670219346bSGarrett D'Amore sum = hme_cksum(tbuf->kaddr + start_offset, 22680219346bSGarrett D'Amore len - start_offset); 22690219346bSGarrett D'Amore bcopy(&sum, tbuf->kaddr + stuff_offset, sizeof (sum)); 22700219346bSGarrett D'Amore csflags = 0; 22717c478bd9Sstevel@tonic-gate } 22727c478bd9Sstevel@tonic-gate 22730219346bSGarrett D'Amore if (ddi_dma_sync(tbuf->dmah, 0, len, DDI_DMA_SYNC_FORDEV) == 22740219346bSGarrett D'Amore DDI_FAILURE) { 22757c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_HIGH, DDI_MSG, 227685025c03Sgd "ddi_dma_sync failed"); 22777c478bd9Sstevel@tonic-gate } 22787c478bd9Sstevel@tonic-gate 22790219346bSGarrett D'Amore /* 22800219346bSGarrett D'Amore * update MIB II statistics 22810219346bSGarrett D'Amore */ 22820219346bSGarrett D'Amore BUMP_OutNUcast(hmep, tbuf->kaddr); 22830219346bSGarrett D'Amore 22840219346bSGarrett D'Amore PUT_TMD(txptr, tbuf->paddr, len, 22850219346bSGarrett D'Amore HMETMD_OWN | HMETMD_SOP | HMETMD_EOP | csflags); 22867c478bd9Sstevel@tonic-gate 22870219346bSGarrett D'Amore HMESYNCTMD(txptr, DDI_DMA_SYNC_FORDEV); 22880219346bSGarrett D'Amore hmep->hme_txindex++; 22897c478bd9Sstevel@tonic-gate 22907c478bd9Sstevel@tonic-gate PUT_ETXREG(txpend, HMET_TXPEND_TDMD); 22917c478bd9Sstevel@tonic-gate CHECK_ETXREG(); 22927c478bd9Sstevel@tonic-gate 22937c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_xmitlock); 22947c478bd9Sstevel@tonic-gate 22957c478bd9Sstevel@tonic-gate hmep->hme_starts++; 229685025c03Sgd return (B_TRUE); 22977c478bd9Sstevel@tonic-gate 22987c478bd9Sstevel@tonic-gate bad: 22997c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_xmitlock); 23007c478bd9Sstevel@tonic-gate freemsg(mp); 230185025c03Sgd return (B_TRUE); 23027c478bd9Sstevel@tonic-gate 23037c478bd9Sstevel@tonic-gate notmds: 23047c478bd9Sstevel@tonic-gate hmep->hme_notmds++; 230585025c03Sgd hmep->hme_wantw = B_TRUE; 23067c478bd9Sstevel@tonic-gate hmereclaim(hmep); 230785025c03Sgd retval = B_FALSE; 23087c478bd9Sstevel@tonic-gate done: 23097c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_xmitlock); 23107c478bd9Sstevel@tonic-gate 231185025c03Sgd return (retval); 23127c478bd9Sstevel@tonic-gate } 23137c478bd9Sstevel@tonic-gate 23147c478bd9Sstevel@tonic-gate /* 23157c478bd9Sstevel@tonic-gate * Initialize channel. 23167c478bd9Sstevel@tonic-gate * Return 0 on success, nonzero on error. 23177c478bd9Sstevel@tonic-gate * 23187c478bd9Sstevel@tonic-gate * The recommended sequence for initialization is: 23197c478bd9Sstevel@tonic-gate * 1. Issue a Global Reset command to the Ethernet Channel. 23207c478bd9Sstevel@tonic-gate * 2. Poll the Global_Reset bits until the execution of the reset has been 23217c478bd9Sstevel@tonic-gate * completed. 23227c478bd9Sstevel@tonic-gate * 2(a). Use the MIF Frame/Output register to reset the transceiver. 23237c478bd9Sstevel@tonic-gate * Poll Register 0 to till the Resetbit is 0. 23247c478bd9Sstevel@tonic-gate * 2(b). Use the MIF Frame/Output register to set the PHY in in Normal-Op, 23257c478bd9Sstevel@tonic-gate * 100Mbps and Non-Isolated mode. The main point here is to bring the 23267c478bd9Sstevel@tonic-gate * PHY out of Isolate mode so that it can generate the rx_clk and tx_clk 23277c478bd9Sstevel@tonic-gate * to the MII interface so that the Bigmac core can correctly reset 23287c478bd9Sstevel@tonic-gate * upon a software reset. 23297c478bd9Sstevel@tonic-gate * 2(c). Issue another Global Reset command to the Ethernet Channel and poll 23307c478bd9Sstevel@tonic-gate * the Global_Reset bits till completion. 23317c478bd9Sstevel@tonic-gate * 3. Set up all the data structures in the host memory. 23327c478bd9Sstevel@tonic-gate * 4. Program the TX_MAC registers/counters (excluding the TX_MAC Configuration 23337c478bd9Sstevel@tonic-gate * Register). 23347c478bd9Sstevel@tonic-gate * 5. Program the RX_MAC registers/counters (excluding the RX_MAC Configuration 23357c478bd9Sstevel@tonic-gate * Register). 23367c478bd9Sstevel@tonic-gate * 6. Program the Transmit Descriptor Ring Base Address in the ETX. 23377c478bd9Sstevel@tonic-gate * 7. Program the Receive Descriptor Ring Base Address in the ERX. 23387c478bd9Sstevel@tonic-gate * 8. Program the Global Configuration and the Global Interrupt Mask Registers. 23397c478bd9Sstevel@tonic-gate * 9. Program the ETX Configuration register (enable the Transmit DMA channel). 23407c478bd9Sstevel@tonic-gate * 10. Program the ERX Configuration register (enable the Receive DMA channel). 23417c478bd9Sstevel@tonic-gate * 11. Program the XIF Configuration Register (enable the XIF). 23427c478bd9Sstevel@tonic-gate * 12. Program the RX_MAC Configuration Register (Enable the RX_MAC). 23437c478bd9Sstevel@tonic-gate * 13. Program the TX_MAC Configuration Register (Enable the TX_MAC). 23447c478bd9Sstevel@tonic-gate */ 23457c478bd9Sstevel@tonic-gate 23467c478bd9Sstevel@tonic-gate 23477c478bd9Sstevel@tonic-gate #ifdef FEPS_URUN_BUG 23487c478bd9Sstevel@tonic-gate static int hme_palen = 32; 23497c478bd9Sstevel@tonic-gate #endif 23507c478bd9Sstevel@tonic-gate 23517c478bd9Sstevel@tonic-gate static int 23527c478bd9Sstevel@tonic-gate hmeinit(struct hme *hmep) 23537c478bd9Sstevel@tonic-gate { 23540219346bSGarrett D'Amore uint32_t i; 23550219346bSGarrett D'Amore int ret; 2356*06673d9bSGarrett D'Amore boolean_t fdx; 2357*06673d9bSGarrett D'Amore int phyad; 23587c478bd9Sstevel@tonic-gate 235985025c03Sgd /* 236085025c03Sgd * Lock sequence: 236185025c03Sgd * hme_intrlock, hme_xmitlock. 236285025c03Sgd */ 236385025c03Sgd mutex_enter(&hmep->hme_intrlock); 23647c478bd9Sstevel@tonic-gate 23657c478bd9Sstevel@tonic-gate /* 236685025c03Sgd * Don't touch the hardware if we are suspended. But don't 236785025c03Sgd * fail either. Some time later we may be resumed, and then 236885025c03Sgd * we'll be back here to program the device using the settings 236985025c03Sgd * in the soft state. 23707c478bd9Sstevel@tonic-gate */ 237185025c03Sgd if (hmep->hme_flags & HMESUSPENDED) { 237285025c03Sgd mutex_exit(&hmep->hme_intrlock); 237385025c03Sgd return (0); 237485025c03Sgd } 23757c478bd9Sstevel@tonic-gate 23767c478bd9Sstevel@tonic-gate /* 237785025c03Sgd * This should prevent us from clearing any interrupts that 237885025c03Sgd * may occur by temporarily stopping interrupts from occurring 237985025c03Sgd * for a short time. We need to update the interrupt mask 238085025c03Sgd * later in this function. 23817c478bd9Sstevel@tonic-gate */ 238285025c03Sgd PUT_GLOBREG(intmask, ~HMEG_MASK_MIF_INTR); 23837c478bd9Sstevel@tonic-gate 23847c478bd9Sstevel@tonic-gate 23857c478bd9Sstevel@tonic-gate /* 23867c478bd9Sstevel@tonic-gate * Rearranged the mutex acquisition order to solve the deadlock 23877c478bd9Sstevel@tonic-gate * situation as described in bug ID 4065896. 23887c478bd9Sstevel@tonic-gate */ 23897c478bd9Sstevel@tonic-gate 23907c478bd9Sstevel@tonic-gate mutex_enter(&hmep->hme_xmitlock); 23917c478bd9Sstevel@tonic-gate 23927c478bd9Sstevel@tonic-gate hmep->hme_flags = 0; 239385025c03Sgd hmep->hme_wantw = B_FALSE; 23947c478bd9Sstevel@tonic-gate 23957c478bd9Sstevel@tonic-gate if (hmep->inits) 23967c478bd9Sstevel@tonic-gate hmesavecntrs(hmep); 23977c478bd9Sstevel@tonic-gate 23987c478bd9Sstevel@tonic-gate /* 23997c478bd9Sstevel@tonic-gate * Perform Global reset of the Sbus/FEPS ENET channel. 24007c478bd9Sstevel@tonic-gate */ 24017c478bd9Sstevel@tonic-gate (void) hmestop(hmep); 24027c478bd9Sstevel@tonic-gate 24037c478bd9Sstevel@tonic-gate /* 24047c478bd9Sstevel@tonic-gate * Clear all descriptors. 24057c478bd9Sstevel@tonic-gate */ 24067c478bd9Sstevel@tonic-gate bzero(hmep->hme_rmdp, HME_RMDMAX * sizeof (struct hme_rmd)); 24077c478bd9Sstevel@tonic-gate bzero(hmep->hme_tmdp, HME_TMDMAX * sizeof (struct hme_tmd)); 24087c478bd9Sstevel@tonic-gate 24097c478bd9Sstevel@tonic-gate /* 24107c478bd9Sstevel@tonic-gate * Hang out receive buffers. 24117c478bd9Sstevel@tonic-gate */ 24120219346bSGarrett D'Amore for (i = 0; i < HME_RMDMAX; i++) { 24130219346bSGarrett D'Amore PUT_RMD(i, hmep->hme_rbuf[i].paddr); 24147c478bd9Sstevel@tonic-gate } 24157c478bd9Sstevel@tonic-gate 24167c478bd9Sstevel@tonic-gate /* 24177c478bd9Sstevel@tonic-gate * DMA sync descriptors. 24187c478bd9Sstevel@tonic-gate */ 24190219346bSGarrett D'Amore (void) ddi_dma_sync(hmep->hme_rmd_dmah, 0, 0, DDI_DMA_SYNC_FORDEV); 24200219346bSGarrett D'Amore (void) ddi_dma_sync(hmep->hme_tmd_dmah, 0, 0, DDI_DMA_SYNC_FORDEV); 24217c478bd9Sstevel@tonic-gate 24227c478bd9Sstevel@tonic-gate /* 24237c478bd9Sstevel@tonic-gate * Reset RMD and TMD 'walking' pointers. 24247c478bd9Sstevel@tonic-gate */ 24250219346bSGarrett D'Amore hmep->hme_rxindex = 0; 24260219346bSGarrett D'Amore hmep->hme_txindex = hmep->hme_txreclaim = 0; 24277c478bd9Sstevel@tonic-gate 24287c478bd9Sstevel@tonic-gate /* 24297c478bd9Sstevel@tonic-gate * This is the right place to initialize MIF !!! 24307c478bd9Sstevel@tonic-gate */ 24317c478bd9Sstevel@tonic-gate 24327c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_imask, HME_MIF_INTMASK); /* mask all interrupts */ 24337c478bd9Sstevel@tonic-gate 24347c478bd9Sstevel@tonic-gate if (!hmep->hme_frame_enable) 24357c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_cfg, GET_MIFREG(mif_cfg) | HME_MIF_CFGBB); 24367c478bd9Sstevel@tonic-gate else 24377c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_cfg, GET_MIFREG(mif_cfg) & ~HME_MIF_CFGBB); 24387c478bd9Sstevel@tonic-gate /* enable frame mode */ 24397c478bd9Sstevel@tonic-gate 24407c478bd9Sstevel@tonic-gate /* 24417c478bd9Sstevel@tonic-gate * Depending on the transceiver detected, select the source 24427c478bd9Sstevel@tonic-gate * of the clocks for the MAC. Without the clocks, TX_MAC does 24437c478bd9Sstevel@tonic-gate * not reset. When the Global Reset is issued to the Sbus/FEPS 24447c478bd9Sstevel@tonic-gate * ASIC, it selects Internal by default. 24457c478bd9Sstevel@tonic-gate */ 24467c478bd9Sstevel@tonic-gate 2447*06673d9bSGarrett D'Amore switch ((phyad = mii_get_addr(hmep->hme_mii))) { 2448*06673d9bSGarrett D'Amore case -1: 24497c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_HIGH, XCVR_MSG, no_xcvr_msg); 24507c478bd9Sstevel@tonic-gate goto init_fail; /* abort initialization */ 24517c478bd9Sstevel@tonic-gate 2452*06673d9bSGarrett D'Amore case HME_INTERNAL_PHYAD: 24537c478bd9Sstevel@tonic-gate PUT_MACREG(xifc, 0); 2454*06673d9bSGarrett D'Amore break; 2455*06673d9bSGarrett D'Amore case HME_EXTERNAL_PHYAD: 2456*06673d9bSGarrett D'Amore /* Isolate the Int. xcvr */ 24577c478bd9Sstevel@tonic-gate PUT_MACREG(xifc, BMAC_XIFC_MIIBUFDIS); 2458*06673d9bSGarrett D'Amore break; 24597c478bd9Sstevel@tonic-gate } 2460*06673d9bSGarrett D'Amore 24617c478bd9Sstevel@tonic-gate hmep->inits++; 24627c478bd9Sstevel@tonic-gate 24637c478bd9Sstevel@tonic-gate /* 24647c478bd9Sstevel@tonic-gate * Initialize BigMAC registers. 24657c478bd9Sstevel@tonic-gate * First set the tx enable bit in tx config reg to 0 and poll on 24667c478bd9Sstevel@tonic-gate * it till it turns to 0. Same for rx config, hash and address 24677c478bd9Sstevel@tonic-gate * filter reg. 24687c478bd9Sstevel@tonic-gate * Here is the sequence per the spec. 24697c478bd9Sstevel@tonic-gate * MADD2 - MAC Address 2 24707c478bd9Sstevel@tonic-gate * MADD1 - MAC Address 1 24717c478bd9Sstevel@tonic-gate * MADD0 - MAC Address 0 24727c478bd9Sstevel@tonic-gate * HASH3, HASH2, HASH1, HASH0 for group address 24737c478bd9Sstevel@tonic-gate * AFR2, AFR1, AFR0 and AFMR for address filter mask 24747c478bd9Sstevel@tonic-gate * Program RXMIN and RXMAX for packet length if not 802.3 24757c478bd9Sstevel@tonic-gate * RXCFG - Rx config for not stripping CRC 24767c478bd9Sstevel@tonic-gate * XXX Anything else to hme configured in RXCFG 24777c478bd9Sstevel@tonic-gate * IPG1, IPG2, ALIMIT, SLOT, PALEN, PAPAT, TXSFD, JAM, TXMAX, TXMIN 24787c478bd9Sstevel@tonic-gate * if not 802.3 compliant 24797c478bd9Sstevel@tonic-gate * XIF register for speed selection 24807c478bd9Sstevel@tonic-gate * MASK - Interrupt mask 24817c478bd9Sstevel@tonic-gate * Set bit 0 of TXCFG 24827c478bd9Sstevel@tonic-gate * Set bit 0 of RXCFG 24837c478bd9Sstevel@tonic-gate */ 24847c478bd9Sstevel@tonic-gate 24857c478bd9Sstevel@tonic-gate /* 24867c478bd9Sstevel@tonic-gate * Initialize the TX_MAC registers 24877c478bd9Sstevel@tonic-gate * Initialization of jamsize to work around rx crc bug 24887c478bd9Sstevel@tonic-gate */ 24897c478bd9Sstevel@tonic-gate PUT_MACREG(jam, jamsize); 24907c478bd9Sstevel@tonic-gate 24917c478bd9Sstevel@tonic-gate #ifdef FEPS_URUN_BUG 24927c478bd9Sstevel@tonic-gate if (hme_urun_fix) 24937c478bd9Sstevel@tonic-gate PUT_MACREG(palen, hme_palen); 24947c478bd9Sstevel@tonic-gate #endif 24957c478bd9Sstevel@tonic-gate 2496*06673d9bSGarrett D'Amore PUT_MACREG(ipg1, hmep->hme_ipg1); 2497*06673d9bSGarrett D'Amore PUT_MACREG(ipg2, hmep->hme_ipg2); 24987c478bd9Sstevel@tonic-gate 24997c478bd9Sstevel@tonic-gate PUT_MACREG(rseed, 250085025c03Sgd ((hmep->hme_ouraddr.ether_addr_octet[0] << 8) & 0x3) | 250185025c03Sgd hmep->hme_ouraddr.ether_addr_octet[1]); 25027c478bd9Sstevel@tonic-gate 25037c478bd9Sstevel@tonic-gate /* Initialize the RX_MAC registers */ 25047c478bd9Sstevel@tonic-gate 25057c478bd9Sstevel@tonic-gate /* 25067c478bd9Sstevel@tonic-gate * Program BigMAC with local individual ethernet address. 25077c478bd9Sstevel@tonic-gate */ 25087c478bd9Sstevel@tonic-gate PUT_MACREG(madd2, (hmep->hme_ouraddr.ether_addr_octet[4] << 8) | 250985025c03Sgd hmep->hme_ouraddr.ether_addr_octet[5]); 25107c478bd9Sstevel@tonic-gate PUT_MACREG(madd1, (hmep->hme_ouraddr.ether_addr_octet[2] << 8) | 251185025c03Sgd hmep->hme_ouraddr.ether_addr_octet[3]); 25127c478bd9Sstevel@tonic-gate PUT_MACREG(madd0, (hmep->hme_ouraddr.ether_addr_octet[0] << 8) | 251385025c03Sgd hmep->hme_ouraddr.ether_addr_octet[1]); 25147c478bd9Sstevel@tonic-gate 25157c478bd9Sstevel@tonic-gate /* 25167c478bd9Sstevel@tonic-gate * Set up multicast address filter by passing all multicast 25177c478bd9Sstevel@tonic-gate * addresses through a crc generator, and then using the 25187c478bd9Sstevel@tonic-gate * low order 6 bits as a index into the 64 bit logical 25197c478bd9Sstevel@tonic-gate * address filter. The high order three bits select the word, 25207c478bd9Sstevel@tonic-gate * while the rest of the bits select the bit within the word. 25217c478bd9Sstevel@tonic-gate */ 252285025c03Sgd PUT_MACREG(hash0, hmep->hme_ladrf[0]); 252385025c03Sgd PUT_MACREG(hash1, hmep->hme_ladrf[1]); 252485025c03Sgd PUT_MACREG(hash2, hmep->hme_ladrf[2]); 252585025c03Sgd PUT_MACREG(hash3, hmep->hme_ladrf[3]); 25267c478bd9Sstevel@tonic-gate 25277c478bd9Sstevel@tonic-gate /* 252885025c03Sgd * Configure parameters to support VLAN. (VLAN encapsulation adds 252985025c03Sgd * four bytes.) 25307c478bd9Sstevel@tonic-gate */ 253185025c03Sgd PUT_MACREG(txmax, ETHERMAX + ETHERFCSL + 4); 253285025c03Sgd PUT_MACREG(rxmax, ETHERMAX + ETHERFCSL + 4); 25337c478bd9Sstevel@tonic-gate 25347c478bd9Sstevel@tonic-gate /* 25357c478bd9Sstevel@tonic-gate * Initialize HME Global registers, ETX registers and ERX registers. 25367c478bd9Sstevel@tonic-gate */ 25377c478bd9Sstevel@tonic-gate 25380219346bSGarrett D'Amore PUT_ETXREG(txring, hmep->hme_tmd_paddr); 25390219346bSGarrett D'Amore PUT_ERXREG(rxring, hmep->hme_rmd_paddr); 25407c478bd9Sstevel@tonic-gate 25417c478bd9Sstevel@tonic-gate /* 25427c478bd9Sstevel@tonic-gate * ERX registers can be written only if they have even no. of bits set. 25437c478bd9Sstevel@tonic-gate * So, if the value written is not read back, set the lsb and write 25447c478bd9Sstevel@tonic-gate * again. 25457c478bd9Sstevel@tonic-gate * static int hme_erx_fix = 1; : Use the fix for erx bug 25467c478bd9Sstevel@tonic-gate */ 25477c478bd9Sstevel@tonic-gate { 25487c478bd9Sstevel@tonic-gate uint32_t temp; 25490219346bSGarrett D'Amore temp = hmep->hme_rmd_paddr; 25507c478bd9Sstevel@tonic-gate 25517c478bd9Sstevel@tonic-gate if (GET_ERXREG(rxring) != temp) 25527c478bd9Sstevel@tonic-gate PUT_ERXREG(rxring, (temp | 4)); 25537c478bd9Sstevel@tonic-gate } 25547c478bd9Sstevel@tonic-gate 255585025c03Sgd PUT_GLOBREG(config, (hmep->hme_config | 255685025c03Sgd (hmep->hme_64bit_xfer << HMEG_CONFIG_64BIT_SHIFT))); 25577c478bd9Sstevel@tonic-gate 25587c478bd9Sstevel@tonic-gate /* 25597c478bd9Sstevel@tonic-gate * Significant performance improvements can be achieved by 25607c478bd9Sstevel@tonic-gate * disabling transmit interrupt. Thus TMD's are reclaimed only 25617c478bd9Sstevel@tonic-gate * when we run out of them in hmestart(). 25627c478bd9Sstevel@tonic-gate */ 25637c478bd9Sstevel@tonic-gate PUT_GLOBREG(intmask, 256485025c03Sgd HMEG_MASK_INTR | HMEG_MASK_TINT | HMEG_MASK_TX_ALL); 25657c478bd9Sstevel@tonic-gate 25667c478bd9Sstevel@tonic-gate PUT_ETXREG(txring_size, ((HME_TMDMAX -1)>> HMET_RINGSZ_SHIFT)); 25677c478bd9Sstevel@tonic-gate PUT_ETXREG(config, (GET_ETXREG(config) | HMET_CONFIG_TXDMA_EN 256885025c03Sgd | HMET_CONFIG_TXFIFOTH)); 25697c478bd9Sstevel@tonic-gate /* get the rxring size bits */ 25707c478bd9Sstevel@tonic-gate switch (HME_RMDMAX) { 25717c478bd9Sstevel@tonic-gate case 32: 25727c478bd9Sstevel@tonic-gate i = HMER_CONFIG_RXRINGSZ32; 25737c478bd9Sstevel@tonic-gate break; 25747c478bd9Sstevel@tonic-gate case 64: 25757c478bd9Sstevel@tonic-gate i = HMER_CONFIG_RXRINGSZ64; 25767c478bd9Sstevel@tonic-gate break; 25777c478bd9Sstevel@tonic-gate case 128: 25787c478bd9Sstevel@tonic-gate i = HMER_CONFIG_RXRINGSZ128; 25797c478bd9Sstevel@tonic-gate break; 25807c478bd9Sstevel@tonic-gate case 256: 25817c478bd9Sstevel@tonic-gate i = HMER_CONFIG_RXRINGSZ256; 25827c478bd9Sstevel@tonic-gate break; 25837c478bd9Sstevel@tonic-gate default: 25847c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 258585025c03Sgd unk_rx_ringsz_msg); 25867c478bd9Sstevel@tonic-gate goto init_fail; 25877c478bd9Sstevel@tonic-gate } 25887c478bd9Sstevel@tonic-gate i |= (HME_FSTBYTE_OFFSET << HMER_CONFIG_FBO_SHIFT) 258985025c03Sgd | HMER_CONFIG_RXDMA_EN; 259085025c03Sgd 259185025c03Sgd /* h/w checks start offset in half words */ 259285025c03Sgd i |= ((sizeof (struct ether_header) / 2) << HMER_RX_CSSTART_SHIFT); 259385025c03Sgd 25947c478bd9Sstevel@tonic-gate PUT_ERXREG(config, i); 25957c478bd9Sstevel@tonic-gate 25967c478bd9Sstevel@tonic-gate /* 25977c478bd9Sstevel@tonic-gate * Bug related to the parity handling in ERX. When erxp-config is 25987c478bd9Sstevel@tonic-gate * read back. 25997c478bd9Sstevel@tonic-gate * Sbus/FEPS drives the parity bit. This value is used while 26007c478bd9Sstevel@tonic-gate * writing again. 26017c478bd9Sstevel@tonic-gate * This fixes the RECV problem in SS5. 26027c478bd9Sstevel@tonic-gate * static int hme_erx_fix = 1; : Use the fix for erx bug 26037c478bd9Sstevel@tonic-gate */ 26047c478bd9Sstevel@tonic-gate { 26057c478bd9Sstevel@tonic-gate uint32_t temp; 26067c478bd9Sstevel@tonic-gate temp = GET_ERXREG(config); 26077c478bd9Sstevel@tonic-gate PUT_ERXREG(config, i); 26087c478bd9Sstevel@tonic-gate 26097c478bd9Sstevel@tonic-gate if (GET_ERXREG(config) != i) 26107c478bd9Sstevel@tonic-gate HME_FAULT_MSG4(hmep, SEVERITY_UNKNOWN, ERX_MSG, 261185025c03Sgd "error:temp = %x erxp->config = %x, should be %x", 261285025c03Sgd temp, GET_ERXREG(config), i); 26137c478bd9Sstevel@tonic-gate } 26147c478bd9Sstevel@tonic-gate 26157c478bd9Sstevel@tonic-gate /* 26167c478bd9Sstevel@tonic-gate * Set up the rxconfig, txconfig and seed register without enabling 26177c478bd9Sstevel@tonic-gate * them the former two at this time 26187c478bd9Sstevel@tonic-gate * 26197c478bd9Sstevel@tonic-gate * BigMAC strips the CRC bytes by default. Since this is 26207c478bd9Sstevel@tonic-gate * contrary to other pieces of hardware, this bit needs to 26217c478bd9Sstevel@tonic-gate * enabled to tell BigMAC not to strip the CRC bytes. 26227c478bd9Sstevel@tonic-gate * Do not filter this node's own packets. 26237c478bd9Sstevel@tonic-gate */ 26247c478bd9Sstevel@tonic-gate 26257c478bd9Sstevel@tonic-gate if (hme_reject_own) { 26267c478bd9Sstevel@tonic-gate PUT_MACREG(rxcfg, 2627228fdff0Sgd ((hmep->hme_promisc ? BMAC_RXCFG_PROMIS : 0) | 262885025c03Sgd BMAC_RXCFG_MYOWN | BMAC_RXCFG_HASH)); 26297c478bd9Sstevel@tonic-gate } else { 26307c478bd9Sstevel@tonic-gate PUT_MACREG(rxcfg, 2631228fdff0Sgd ((hmep->hme_promisc ? BMAC_RXCFG_PROMIS : 0) | 263285025c03Sgd BMAC_RXCFG_HASH)); 26337c478bd9Sstevel@tonic-gate } 26347c478bd9Sstevel@tonic-gate 26357c478bd9Sstevel@tonic-gate drv_usecwait(10); /* wait after setting Hash Enable bit */ 26367c478bd9Sstevel@tonic-gate 2637*06673d9bSGarrett D'Amore fdx = (mii_get_duplex(hmep->hme_mii) == LINK_DUPLEX_FULL); 2638*06673d9bSGarrett D'Amore 26397c478bd9Sstevel@tonic-gate if (hme_ngu_enable) 2640*06673d9bSGarrett D'Amore PUT_MACREG(txcfg, (fdx ? BMAC_TXCFG_FDX : 0) | 264185025c03Sgd BMAC_TXCFG_NGU); 26427c478bd9Sstevel@tonic-gate else 2643*06673d9bSGarrett D'Amore PUT_MACREG(txcfg, (fdx ? BMAC_TXCFG_FDX: 0)); 26447c478bd9Sstevel@tonic-gate 26457c478bd9Sstevel@tonic-gate i = 0; 2646*06673d9bSGarrett D'Amore if ((hmep->hme_lance_mode) && (hmep->hme_lance_mode_enable)) 2647*06673d9bSGarrett D'Amore i = ((hmep->hme_ipg0 & HME_MASK_5BIT) << BMAC_XIFC_IPG0_SHIFT) 264885025c03Sgd | BMAC_XIFC_LANCE_ENAB; 2649*06673d9bSGarrett D'Amore if (phyad == HME_INTERNAL_PHYAD) 26507c478bd9Sstevel@tonic-gate PUT_MACREG(xifc, i | (BMAC_XIFC_ENAB)); 26517c478bd9Sstevel@tonic-gate else 26527c478bd9Sstevel@tonic-gate PUT_MACREG(xifc, i | (BMAC_XIFC_ENAB | BMAC_XIFC_MIIBUFDIS)); 26537c478bd9Sstevel@tonic-gate 26547c478bd9Sstevel@tonic-gate PUT_MACREG(rxcfg, GET_MACREG(rxcfg) | BMAC_RXCFG_ENAB); 26557c478bd9Sstevel@tonic-gate PUT_MACREG(txcfg, GET_MACREG(txcfg) | BMAC_TXCFG_ENAB); 26567c478bd9Sstevel@tonic-gate 26577c478bd9Sstevel@tonic-gate hmep->hme_flags |= (HMERUNNING | HMEINITIALIZED); 26587c478bd9Sstevel@tonic-gate /* 26597c478bd9Sstevel@tonic-gate * Update the interrupt mask : this will re-allow interrupts to occur 26607c478bd9Sstevel@tonic-gate */ 266185025c03Sgd PUT_GLOBREG(intmask, HMEG_MASK_INTR); 266285025c03Sgd mac_tx_update(hmep->hme_mh); 26637c478bd9Sstevel@tonic-gate 26647c478bd9Sstevel@tonic-gate init_fail: 26657c478bd9Sstevel@tonic-gate /* 26667c478bd9Sstevel@tonic-gate * Release the locks in reverse order 26677c478bd9Sstevel@tonic-gate */ 26687c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_xmitlock); 26697c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_intrlock); 26707c478bd9Sstevel@tonic-gate 26717c478bd9Sstevel@tonic-gate ret = !(hmep->hme_flags & HMERUNNING); 26727c478bd9Sstevel@tonic-gate if (ret) { 26737c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 267485025c03Sgd init_fail_gen_msg); 26757c478bd9Sstevel@tonic-gate } 26767c478bd9Sstevel@tonic-gate 26777c478bd9Sstevel@tonic-gate /* 26787c478bd9Sstevel@tonic-gate * Hardware checks. 26797c478bd9Sstevel@tonic-gate */ 26807c478bd9Sstevel@tonic-gate CHECK_GLOBREG(); 26817c478bd9Sstevel@tonic-gate CHECK_MIFREG(); 26827c478bd9Sstevel@tonic-gate CHECK_MACREG(); 26837c478bd9Sstevel@tonic-gate CHECK_ERXREG(); 26847c478bd9Sstevel@tonic-gate CHECK_ETXREG(); 26857c478bd9Sstevel@tonic-gate 26867c478bd9Sstevel@tonic-gate init_exit: 26877c478bd9Sstevel@tonic-gate return (ret); 26887c478bd9Sstevel@tonic-gate } 26897c478bd9Sstevel@tonic-gate 26907c478bd9Sstevel@tonic-gate /* 26917c478bd9Sstevel@tonic-gate * Calculate the dvma burstsize by setting up a dvma temporarily. Return 26927c478bd9Sstevel@tonic-gate * 0 as burstsize upon failure as it signifies no burst size. 26937c478bd9Sstevel@tonic-gate * Requests for 64-bit transfer setup, if the platform supports it. 26947c478bd9Sstevel@tonic-gate * NOTE: Do not use ddi_dma_alloc_handle(9f) then ddi_dma_burstsize(9f), 26957c478bd9Sstevel@tonic-gate * sun4u Ultra-2 incorrectly returns a 32bit transfer. 26967c478bd9Sstevel@tonic-gate */ 26977c478bd9Sstevel@tonic-gate static int 26987c478bd9Sstevel@tonic-gate hmeburstsizes(struct hme *hmep) 26997c478bd9Sstevel@tonic-gate { 27007c478bd9Sstevel@tonic-gate int burstsizes; 27017c478bd9Sstevel@tonic-gate ddi_dma_handle_t handle; 27027c478bd9Sstevel@tonic-gate 27037c478bd9Sstevel@tonic-gate if (ddi_dma_alloc_handle(hmep->dip, &hme_dma_attr, 27047c478bd9Sstevel@tonic-gate DDI_DMA_DONTWAIT, NULL, &handle)) { 27057c478bd9Sstevel@tonic-gate return (0); 27067c478bd9Sstevel@tonic-gate } 27077c478bd9Sstevel@tonic-gate 27087c478bd9Sstevel@tonic-gate hmep->hme_burstsizes = burstsizes = ddi_dma_burstsizes(handle); 27097c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&handle); 27107c478bd9Sstevel@tonic-gate 27117c478bd9Sstevel@tonic-gate /* 27127c478bd9Sstevel@tonic-gate * Use user-configurable parameter for enabling 64-bit transfers 27137c478bd9Sstevel@tonic-gate */ 27147c478bd9Sstevel@tonic-gate burstsizes = (hmep->hme_burstsizes >> 16); 27157c478bd9Sstevel@tonic-gate if (burstsizes) 27167c478bd9Sstevel@tonic-gate hmep->hme_64bit_xfer = hme_64bit_enable; /* user config value */ 27177c478bd9Sstevel@tonic-gate else 27187c478bd9Sstevel@tonic-gate burstsizes = hmep->hme_burstsizes; 27197c478bd9Sstevel@tonic-gate 27207c478bd9Sstevel@tonic-gate if (hmep->hme_cheerio_mode) 27217c478bd9Sstevel@tonic-gate hmep->hme_64bit_xfer = 0; /* Disable for cheerio */ 27227c478bd9Sstevel@tonic-gate 27237c478bd9Sstevel@tonic-gate if (burstsizes & 0x40) 27247c478bd9Sstevel@tonic-gate hmep->hme_config = HMEG_CONFIG_BURST64; 27257c478bd9Sstevel@tonic-gate else if (burstsizes & 0x20) 27267c478bd9Sstevel@tonic-gate hmep->hme_config = HMEG_CONFIG_BURST32; 27277c478bd9Sstevel@tonic-gate else 27287c478bd9Sstevel@tonic-gate hmep->hme_config = HMEG_CONFIG_BURST16; 27297c478bd9Sstevel@tonic-gate 27300219346bSGarrett D'Amore return (DDI_SUCCESS); 27310219346bSGarrett D'Amore } 27320219346bSGarrett D'Amore 27330219346bSGarrett D'Amore static int 27340219346bSGarrett D'Amore hmeallocbuf(struct hme *hmep, hmebuf_t *buf, int dir) 27350219346bSGarrett D'Amore { 27360219346bSGarrett D'Amore ddi_dma_cookie_t dmac; 27370219346bSGarrett D'Amore size_t len; 27380219346bSGarrett D'Amore unsigned ccnt; 27390219346bSGarrett D'Amore 27400219346bSGarrett D'Amore if (ddi_dma_alloc_handle(hmep->dip, &hme_dma_attr, 27410219346bSGarrett D'Amore DDI_DMA_DONTWAIT, NULL, &buf->dmah) != DDI_SUCCESS) { 27420219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 27430219346bSGarrett D'Amore "cannot allocate buf dma handle - failed"); 27440219346bSGarrett D'Amore return (DDI_FAILURE); 27450219346bSGarrett D'Amore } 27460219346bSGarrett D'Amore 27470219346bSGarrett D'Amore if (ddi_dma_mem_alloc(buf->dmah, ROUNDUP(HMEBUFSIZE, 512), 27480219346bSGarrett D'Amore &hme_buf_attr, DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, NULL, 27490219346bSGarrett D'Amore &buf->kaddr, &len, &buf->acch) != DDI_SUCCESS) { 27500219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 27510219346bSGarrett D'Amore "cannot allocate buf memory - failed"); 27520219346bSGarrett D'Amore return (DDI_FAILURE); 27530219346bSGarrett D'Amore } 27540219346bSGarrett D'Amore 27550219346bSGarrett D'Amore if (ddi_dma_addr_bind_handle(buf->dmah, NULL, buf->kaddr, 27560219346bSGarrett D'Amore len, dir | DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL, 27570219346bSGarrett D'Amore &dmac, &ccnt) != DDI_DMA_MAPPED) { 27580219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 27590219346bSGarrett D'Amore "cannot map buf for dma - failed"); 27600219346bSGarrett D'Amore return (DDI_FAILURE); 27610219346bSGarrett D'Amore } 27620219346bSGarrett D'Amore buf->paddr = dmac.dmac_address; 27630219346bSGarrett D'Amore 27640219346bSGarrett D'Amore /* apparently they don't handle multiple cookies */ 27650219346bSGarrett D'Amore if (ccnt > 1) { 27660219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 27670219346bSGarrett D'Amore "too many buf dma cookies"); 27680219346bSGarrett D'Amore return (DDI_FAILURE); 27690219346bSGarrett D'Amore } 27700219346bSGarrett D'Amore return (DDI_SUCCESS); 27710219346bSGarrett D'Amore } 27720219346bSGarrett D'Amore 27730219346bSGarrett D'Amore static int 27740219346bSGarrett D'Amore hmeallocbufs(struct hme *hmep) 27750219346bSGarrett D'Amore { 27760219346bSGarrett D'Amore hmep->hme_tbuf = kmem_zalloc(HME_TMDMAX * sizeof (hmebuf_t), KM_SLEEP); 27770219346bSGarrett D'Amore hmep->hme_rbuf = kmem_zalloc(HME_RMDMAX * sizeof (hmebuf_t), KM_SLEEP); 27780219346bSGarrett D'Amore 27790219346bSGarrett D'Amore /* Alloc RX buffers. */ 27800219346bSGarrett D'Amore for (int i = 0; i < HME_RMDMAX; i++) { 27810219346bSGarrett D'Amore if (hmeallocbuf(hmep, &hmep->hme_rbuf[i], DDI_DMA_READ) != 27820219346bSGarrett D'Amore DDI_SUCCESS) { 27830219346bSGarrett D'Amore return (DDI_FAILURE); 27840219346bSGarrett D'Amore } 27850219346bSGarrett D'Amore } 27860219346bSGarrett D'Amore 27870219346bSGarrett D'Amore /* Alloc TX buffers. */ 27880219346bSGarrett D'Amore for (int i = 0; i < HME_TMDMAX; i++) { 27890219346bSGarrett D'Amore if (hmeallocbuf(hmep, &hmep->hme_tbuf[i], DDI_DMA_WRITE) != 27900219346bSGarrett D'Amore DDI_SUCCESS) { 27910219346bSGarrett D'Amore return (DDI_FAILURE); 27920219346bSGarrett D'Amore } 27930219346bSGarrett D'Amore } 27947c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 27957c478bd9Sstevel@tonic-gate } 27967c478bd9Sstevel@tonic-gate 27977c478bd9Sstevel@tonic-gate static void 27987c478bd9Sstevel@tonic-gate hmefreebufs(struct hme *hmep) 27997c478bd9Sstevel@tonic-gate { 28007c478bd9Sstevel@tonic-gate int i; 28010219346bSGarrett D'Amore 28020219346bSGarrett D'Amore if (hmep->hme_rbuf == NULL) 28030219346bSGarrett D'Amore return; 28047c478bd9Sstevel@tonic-gate 28057c478bd9Sstevel@tonic-gate /* 28060219346bSGarrett D'Amore * Free and unload pending xmit and recv buffers. 28077c478bd9Sstevel@tonic-gate * Maintaining the 1-to-1 ordered sequence of 28080219346bSGarrett D'Amore * We have written the routine to be idempotent. 28097c478bd9Sstevel@tonic-gate */ 28107c478bd9Sstevel@tonic-gate 28117c478bd9Sstevel@tonic-gate for (i = 0; i < HME_TMDMAX; i++) { 28120219346bSGarrett D'Amore hmebuf_t *tbuf = &hmep->hme_tbuf[i]; 28130219346bSGarrett D'Amore if (tbuf->paddr) { 28140219346bSGarrett D'Amore (void) ddi_dma_unbind_handle(tbuf->dmah); 28150219346bSGarrett D'Amore } 28160219346bSGarrett D'Amore if (tbuf->kaddr) { 28170219346bSGarrett D'Amore ddi_dma_mem_free(&tbuf->acch); 28180219346bSGarrett D'Amore } 28190219346bSGarrett D'Amore if (tbuf->dmah) { 28200219346bSGarrett D'Amore ddi_dma_free_handle(&tbuf->dmah); 28217c478bd9Sstevel@tonic-gate } 28227c478bd9Sstevel@tonic-gate } 28237c478bd9Sstevel@tonic-gate for (i = 0; i < HME_RMDMAX; i++) { 28240219346bSGarrett D'Amore hmebuf_t *rbuf = &hmep->hme_rbuf[i]; 28250219346bSGarrett D'Amore if (rbuf->paddr) { 28260219346bSGarrett D'Amore (void) ddi_dma_unbind_handle(rbuf->dmah); 28270219346bSGarrett D'Amore } 28280219346bSGarrett D'Amore if (rbuf->kaddr) { 28290219346bSGarrett D'Amore ddi_dma_mem_free(&rbuf->acch); 28300219346bSGarrett D'Amore } 28310219346bSGarrett D'Amore if (rbuf->dmah) { 28320219346bSGarrett D'Amore ddi_dma_free_handle(&rbuf->dmah); 28337c478bd9Sstevel@tonic-gate } 28347c478bd9Sstevel@tonic-gate } 28350219346bSGarrett D'Amore kmem_free(hmep->hme_rbuf, HME_RMDMAX * sizeof (hmebuf_t)); 28360219346bSGarrett D'Amore kmem_free(hmep->hme_tbuf, HME_TMDMAX * sizeof (hmebuf_t)); 28377c478bd9Sstevel@tonic-gate } 28387c478bd9Sstevel@tonic-gate 28397c478bd9Sstevel@tonic-gate /* 28407c478bd9Sstevel@tonic-gate * Un-initialize (STOP) HME channel. 28417c478bd9Sstevel@tonic-gate */ 28427c478bd9Sstevel@tonic-gate static void 28437c478bd9Sstevel@tonic-gate hmeuninit(struct hme *hmep) 28447c478bd9Sstevel@tonic-gate { 28457c478bd9Sstevel@tonic-gate /* 28467c478bd9Sstevel@tonic-gate * Allow up to 'HMEDRAINTIME' for pending xmit's to complete. 28477c478bd9Sstevel@tonic-gate */ 28480219346bSGarrett D'Amore HMEDELAY((hmep->hme_txindex == hmep->hme_txreclaim), HMEDRAINTIME); 28497c478bd9Sstevel@tonic-gate 28507c478bd9Sstevel@tonic-gate mutex_enter(&hmep->hme_intrlock); 28517c478bd9Sstevel@tonic-gate mutex_enter(&hmep->hme_xmitlock); 28527c478bd9Sstevel@tonic-gate 28537c478bd9Sstevel@tonic-gate hmep->hme_flags &= ~HMERUNNING; 28547c478bd9Sstevel@tonic-gate 28557c478bd9Sstevel@tonic-gate (void) hmestop(hmep); 28567c478bd9Sstevel@tonic-gate 28577c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_xmitlock); 28587c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_intrlock); 28597c478bd9Sstevel@tonic-gate } 28607c478bd9Sstevel@tonic-gate 28617c478bd9Sstevel@tonic-gate /* 28627c478bd9Sstevel@tonic-gate * Allocate CONSISTENT memory for rmds and tmds with appropriate alignment and 28637c478bd9Sstevel@tonic-gate * map it in IO space. Allocate space for transmit and receive ddi_dma_handle 28647c478bd9Sstevel@tonic-gate * structures to use the DMA interface. 28657c478bd9Sstevel@tonic-gate */ 28667c478bd9Sstevel@tonic-gate static int 28677c478bd9Sstevel@tonic-gate hmeallocthings(struct hme *hmep) 28687c478bd9Sstevel@tonic-gate { 28690219346bSGarrett D'Amore int size; 28700219346bSGarrett D'Amore int rval; 28710219346bSGarrett D'Amore size_t real_len; 28720219346bSGarrett D'Amore uint_t cookiec; 28730219346bSGarrett D'Amore ddi_dma_cookie_t dmac; 28740219346bSGarrett D'Amore dev_info_t *dip = hmep->dip; 28757c478bd9Sstevel@tonic-gate 28767c478bd9Sstevel@tonic-gate /* 28777c478bd9Sstevel@tonic-gate * Allocate the TMD and RMD descriptors and extra for page alignment. 28787c478bd9Sstevel@tonic-gate */ 28797c478bd9Sstevel@tonic-gate 28800219346bSGarrett D'Amore rval = ddi_dma_alloc_handle(dip, &hme_dma_attr, DDI_DMA_DONTWAIT, NULL, 28810219346bSGarrett D'Amore &hmep->hme_rmd_dmah); 28827c478bd9Sstevel@tonic-gate if (rval != DDI_SUCCESS) { 288385025c03Sgd HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 288485025c03Sgd "cannot allocate rmd handle - failed"); 28850219346bSGarrett D'Amore return (DDI_FAILURE); 28867c478bd9Sstevel@tonic-gate } 28870219346bSGarrett D'Amore size = HME_RMDMAX * sizeof (struct hme_rmd); 28880219346bSGarrett D'Amore rval = ddi_dma_mem_alloc(hmep->hme_rmd_dmah, size, 28890219346bSGarrett D'Amore &hmep->hme_dev_attr, DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL, 28900219346bSGarrett D'Amore &hmep->hme_rmd_kaddr, &real_len, &hmep->hme_rmd_acch); 28917c478bd9Sstevel@tonic-gate if (rval != DDI_SUCCESS) { 289285025c03Sgd HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 28930219346bSGarrett D'Amore "cannot allocate rmd dma mem - failed"); 28940219346bSGarrett D'Amore return (DDI_FAILURE); 28957c478bd9Sstevel@tonic-gate } 28960219346bSGarrett D'Amore hmep->hme_rmdp = (void *)(hmep->hme_rmd_kaddr); 28970219346bSGarrett D'Amore rval = ddi_dma_addr_bind_handle(hmep->hme_rmd_dmah, NULL, 28980219346bSGarrett D'Amore hmep->hme_rmd_kaddr, size, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 28990219346bSGarrett D'Amore DDI_DMA_DONTWAIT, NULL, &dmac, &cookiec); 29007c478bd9Sstevel@tonic-gate if (rval != DDI_DMA_MAPPED) { 290185025c03Sgd HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 29020219346bSGarrett D'Amore "cannot allocate rmd dma - failed"); 29030219346bSGarrett D'Amore return (DDI_FAILURE); 29047c478bd9Sstevel@tonic-gate } 29050219346bSGarrett D'Amore hmep->hme_rmd_paddr = dmac.dmac_address; 29067c478bd9Sstevel@tonic-gate if (cookiec != 1) { 290785025c03Sgd HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 29080219346bSGarrett D'Amore "too many rmd cookies - failed"); 29090219346bSGarrett D'Amore return (DDI_FAILURE); 29107c478bd9Sstevel@tonic-gate } 29117c478bd9Sstevel@tonic-gate 29120219346bSGarrett D'Amore rval = ddi_dma_alloc_handle(dip, &hme_dma_attr, DDI_DMA_DONTWAIT, NULL, 29130219346bSGarrett D'Amore &hmep->hme_tmd_dmah); 29140219346bSGarrett D'Amore if (rval != DDI_SUCCESS) { 29150219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 29160219346bSGarrett D'Amore "cannot allocate tmd handle - failed"); 29170219346bSGarrett D'Amore return (DDI_FAILURE); 29180219346bSGarrett D'Amore } 29190219346bSGarrett D'Amore size = HME_TMDMAX * sizeof (struct hme_rmd); 29200219346bSGarrett D'Amore rval = ddi_dma_mem_alloc(hmep->hme_tmd_dmah, size, 29210219346bSGarrett D'Amore &hmep->hme_dev_attr, DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL, 29220219346bSGarrett D'Amore &hmep->hme_tmd_kaddr, &real_len, &hmep->hme_tmd_acch); 29230219346bSGarrett D'Amore if (rval != DDI_SUCCESS) { 29240219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 29250219346bSGarrett D'Amore "cannot allocate tmd dma mem - failed"); 29260219346bSGarrett D'Amore return (DDI_FAILURE); 29270219346bSGarrett D'Amore } 29280219346bSGarrett D'Amore hmep->hme_tmdp = (void *)(hmep->hme_tmd_kaddr); 29290219346bSGarrett D'Amore rval = ddi_dma_addr_bind_handle(hmep->hme_tmd_dmah, NULL, 29300219346bSGarrett D'Amore hmep->hme_tmd_kaddr, size, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 29310219346bSGarrett D'Amore DDI_DMA_DONTWAIT, NULL, &dmac, &cookiec); 29320219346bSGarrett D'Amore if (rval != DDI_DMA_MAPPED) { 29330219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 29340219346bSGarrett D'Amore "cannot allocate tmd dma - failed"); 29350219346bSGarrett D'Amore return (DDI_FAILURE); 29360219346bSGarrett D'Amore } 29370219346bSGarrett D'Amore hmep->hme_tmd_paddr = dmac.dmac_address; 29380219346bSGarrett D'Amore if (cookiec != 1) { 29390219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 29400219346bSGarrett D'Amore "too many tmd cookies - failed"); 29410219346bSGarrett D'Amore return (DDI_FAILURE); 29427c478bd9Sstevel@tonic-gate } 29437c478bd9Sstevel@tonic-gate 29440219346bSGarrett D'Amore return (DDI_SUCCESS); 29457c478bd9Sstevel@tonic-gate } 29467c478bd9Sstevel@tonic-gate 29470219346bSGarrett D'Amore static void 29480219346bSGarrett D'Amore hmefreethings(struct hme *hmep) 29490219346bSGarrett D'Amore { 29500219346bSGarrett D'Amore if (hmep->hme_rmd_paddr) { 29510219346bSGarrett D'Amore (void) ddi_dma_unbind_handle(hmep->hme_rmd_dmah); 29520219346bSGarrett D'Amore hmep->hme_rmd_paddr = 0; 29530219346bSGarrett D'Amore } 29540219346bSGarrett D'Amore if (hmep->hme_rmd_acch) 29550219346bSGarrett D'Amore ddi_dma_mem_free(&hmep->hme_rmd_acch); 29560219346bSGarrett D'Amore if (hmep->hme_rmd_dmah) 29570219346bSGarrett D'Amore ddi_dma_free_handle(&hmep->hme_rmd_dmah); 29580219346bSGarrett D'Amore 29590219346bSGarrett D'Amore if (hmep->hme_tmd_paddr) { 29600219346bSGarrett D'Amore (void) ddi_dma_unbind_handle(hmep->hme_tmd_dmah); 29610219346bSGarrett D'Amore hmep->hme_tmd_paddr = 0; 29620219346bSGarrett D'Amore } 29630219346bSGarrett D'Amore if (hmep->hme_tmd_acch) 29640219346bSGarrett D'Amore ddi_dma_mem_free(&hmep->hme_tmd_acch); 29650219346bSGarrett D'Amore if (hmep->hme_tmd_dmah) 29660219346bSGarrett D'Amore ddi_dma_free_handle(&hmep->hme_tmd_dmah); 29670219346bSGarrett D'Amore } 29687c478bd9Sstevel@tonic-gate 29697c478bd9Sstevel@tonic-gate /* 29707c478bd9Sstevel@tonic-gate * First check to see if it our device interrupting. 29717c478bd9Sstevel@tonic-gate */ 29727c478bd9Sstevel@tonic-gate static uint_t 297385025c03Sgd hmeintr(caddr_t arg) 29747c478bd9Sstevel@tonic-gate { 297585025c03Sgd struct hme *hmep = (void *)arg; 29767c478bd9Sstevel@tonic-gate uint32_t hmesbits; 29777c478bd9Sstevel@tonic-gate uint32_t serviced = DDI_INTR_UNCLAIMED; 29787c478bd9Sstevel@tonic-gate uint32_t num_reads = 0; 297985025c03Sgd uint32_t rflags; 298085025c03Sgd mblk_t *mp, *head, **tail; 29817c478bd9Sstevel@tonic-gate 29827c478bd9Sstevel@tonic-gate 298385025c03Sgd head = NULL; 298485025c03Sgd tail = &head; 29857c478bd9Sstevel@tonic-gate 29867c478bd9Sstevel@tonic-gate mutex_enter(&hmep->hme_intrlock); 29877c478bd9Sstevel@tonic-gate 29887c478bd9Sstevel@tonic-gate /* 29897c478bd9Sstevel@tonic-gate * The status register auto-clears on read except for 29907c478bd9Sstevel@tonic-gate * MIF Interrupt bit 29917c478bd9Sstevel@tonic-gate */ 29927c478bd9Sstevel@tonic-gate hmesbits = GET_GLOBREG(status); 29937c478bd9Sstevel@tonic-gate CHECK_GLOBREG(); 29947c478bd9Sstevel@tonic-gate 29957c478bd9Sstevel@tonic-gate /* 29967c478bd9Sstevel@tonic-gate * Note: TINT is sometimes enabled in thr hmereclaim() 29977c478bd9Sstevel@tonic-gate */ 29987c478bd9Sstevel@tonic-gate 29997c478bd9Sstevel@tonic-gate /* 30007c478bd9Sstevel@tonic-gate * Bugid 1227832 - to handle spurious interrupts on fusion systems. 30017c478bd9Sstevel@tonic-gate * Claim the first interrupt after initialization 30027c478bd9Sstevel@tonic-gate */ 30037c478bd9Sstevel@tonic-gate if (hmep->hme_flags & HMEINITIALIZED) { 30047c478bd9Sstevel@tonic-gate hmep->hme_flags &= ~HMEINITIALIZED; 30057c478bd9Sstevel@tonic-gate serviced = DDI_INTR_CLAIMED; 30067c478bd9Sstevel@tonic-gate } 30077c478bd9Sstevel@tonic-gate 30087c478bd9Sstevel@tonic-gate if ((hmesbits & (HMEG_STATUS_INTR | HMEG_STATUS_TINT)) == 0) { 30097c478bd9Sstevel@tonic-gate /* No interesting interrupt */ 30107c478bd9Sstevel@tonic-gate if (hmep->hme_intrstats) { 30117c478bd9Sstevel@tonic-gate if (serviced == DDI_INTR_UNCLAIMED) 30127c478bd9Sstevel@tonic-gate KIOIP->intrs[KSTAT_INTR_SPURIOUS]++; 30137c478bd9Sstevel@tonic-gate else 30147c478bd9Sstevel@tonic-gate KIOIP->intrs[KSTAT_INTR_HARD]++; 30157c478bd9Sstevel@tonic-gate } 30167c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_intrlock); 30177c478bd9Sstevel@tonic-gate return (serviced); 30187c478bd9Sstevel@tonic-gate } 30197c478bd9Sstevel@tonic-gate 30207c478bd9Sstevel@tonic-gate serviced = DDI_INTR_CLAIMED; 30217c478bd9Sstevel@tonic-gate 30227c478bd9Sstevel@tonic-gate if (!(hmep->hme_flags & HMERUNNING)) { 30237c478bd9Sstevel@tonic-gate if (hmep->hme_intrstats) 30247c478bd9Sstevel@tonic-gate KIOIP->intrs[KSTAT_INTR_HARD]++; 30257c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_intrlock); 30267c478bd9Sstevel@tonic-gate hmeuninit(hmep); 30277c478bd9Sstevel@tonic-gate return (serviced); 30287c478bd9Sstevel@tonic-gate } 30297c478bd9Sstevel@tonic-gate 30307c478bd9Sstevel@tonic-gate if (hmesbits & (HMEG_STATUS_FATAL_ERR | HMEG_STATUS_NONFATAL_ERR)) { 30317c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_FATAL_ERR) { 30327c478bd9Sstevel@tonic-gate 30337c478bd9Sstevel@tonic-gate if (hmep->hme_intrstats) 30347c478bd9Sstevel@tonic-gate KIOIP->intrs[KSTAT_INTR_HARD]++; 30357c478bd9Sstevel@tonic-gate hme_fatal_err(hmep, hmesbits); 30367c478bd9Sstevel@tonic-gate 30377c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_intrlock); 30387c478bd9Sstevel@tonic-gate (void) hmeinit(hmep); 30397c478bd9Sstevel@tonic-gate return (serviced); 30407c478bd9Sstevel@tonic-gate } 30417c478bd9Sstevel@tonic-gate hme_nonfatal_err(hmep, hmesbits); 30427c478bd9Sstevel@tonic-gate } 30437c478bd9Sstevel@tonic-gate 30447c478bd9Sstevel@tonic-gate if (hmesbits & (HMEG_STATUS_TX_ALL | HMEG_STATUS_TINT)) { 30457c478bd9Sstevel@tonic-gate mutex_enter(&hmep->hme_xmitlock); 30467c478bd9Sstevel@tonic-gate 30477c478bd9Sstevel@tonic-gate hmereclaim(hmep); 30487c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_xmitlock); 30497c478bd9Sstevel@tonic-gate } 30507c478bd9Sstevel@tonic-gate 30517c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_RINT) { 30527c478bd9Sstevel@tonic-gate 30537c478bd9Sstevel@tonic-gate /* 30547c478bd9Sstevel@tonic-gate * This dummy PIO is required to flush the SBus 30557c478bd9Sstevel@tonic-gate * Bridge buffers in QFE. 30567c478bd9Sstevel@tonic-gate */ 30570219346bSGarrett D'Amore (void) GET_GLOBREG(config); 30587c478bd9Sstevel@tonic-gate 30597c478bd9Sstevel@tonic-gate /* 30600219346bSGarrett D'Amore * Loop through each RMD no more than once. 30617c478bd9Sstevel@tonic-gate */ 30620219346bSGarrett D'Amore while (num_reads++ < HME_RMDMAX) { 30630219346bSGarrett D'Amore hmebuf_t *rbuf; 30640219346bSGarrett D'Amore int rxptr; 30650219346bSGarrett D'Amore 30660219346bSGarrett D'Amore rxptr = hmep->hme_rxindex % HME_RMDMAX; 30670219346bSGarrett D'Amore HMESYNCRMD(rxptr, DDI_DMA_SYNC_FORKERNEL); 30680219346bSGarrett D'Amore 30690219346bSGarrett D'Amore rflags = GET_RMD_FLAGS(rxptr); 30700219346bSGarrett D'Amore if (rflags & HMERMD_OWN) { 30710219346bSGarrett D'Amore /* 30720219346bSGarrett D'Amore * Chip still owns it. We're done. 30730219346bSGarrett D'Amore */ 30740219346bSGarrett D'Amore break; 30750219346bSGarrett D'Amore } 307685025c03Sgd 30770219346bSGarrett D'Amore /* 30780219346bSGarrett D'Amore * Retrieve the packet. 30790219346bSGarrett D'Amore */ 30800219346bSGarrett D'Amore rbuf = &hmep->hme_rbuf[rxptr]; 30810219346bSGarrett D'Amore mp = hmeread(hmep, rbuf, rflags); 308285025c03Sgd 30837c478bd9Sstevel@tonic-gate /* 30840219346bSGarrett D'Amore * Return ownership of the RMD. 30857c478bd9Sstevel@tonic-gate */ 30860219346bSGarrett D'Amore PUT_RMD(rxptr, rbuf->paddr); 30870219346bSGarrett D'Amore HMESYNCRMD(rxptr, DDI_DMA_SYNC_FORDEV); 30887c478bd9Sstevel@tonic-gate 308985025c03Sgd if (mp != NULL) { 309085025c03Sgd *tail = mp; 309185025c03Sgd tail = &mp->b_next; 309285025c03Sgd } 309385025c03Sgd 30947c478bd9Sstevel@tonic-gate /* 30950219346bSGarrett D'Amore * Advance to the next RMD. 30967c478bd9Sstevel@tonic-gate */ 30970219346bSGarrett D'Amore hmep->hme_rxindex++; 30987c478bd9Sstevel@tonic-gate } 30997c478bd9Sstevel@tonic-gate } 31007c478bd9Sstevel@tonic-gate 31017c478bd9Sstevel@tonic-gate if (hmep->hme_intrstats) 31027c478bd9Sstevel@tonic-gate KIOIP->intrs[KSTAT_INTR_HARD]++; 31037c478bd9Sstevel@tonic-gate 31047c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_intrlock); 310585025c03Sgd 310685025c03Sgd if (head != NULL) 310785025c03Sgd mac_rx(hmep->hme_mh, NULL, head); 310885025c03Sgd 31097c478bd9Sstevel@tonic-gate return (serviced); 31107c478bd9Sstevel@tonic-gate } 31117c478bd9Sstevel@tonic-gate 31127c478bd9Sstevel@tonic-gate /* 31137c478bd9Sstevel@tonic-gate * Transmit completion reclaiming. 31147c478bd9Sstevel@tonic-gate */ 31157c478bd9Sstevel@tonic-gate static void 31167c478bd9Sstevel@tonic-gate hmereclaim(struct hme *hmep) 31177c478bd9Sstevel@tonic-gate { 31180219346bSGarrett D'Amore boolean_t reclaimed = B_FALSE; 31197c478bd9Sstevel@tonic-gate 31207c478bd9Sstevel@tonic-gate /* 31217c478bd9Sstevel@tonic-gate * Loop through each TMD. 31227c478bd9Sstevel@tonic-gate */ 31230219346bSGarrett D'Amore while (hmep->hme_txindex > hmep->hme_txreclaim) { 31240219346bSGarrett D'Amore 31250219346bSGarrett D'Amore int reclaim; 31260219346bSGarrett D'Amore uint32_t flags; 31270219346bSGarrett D'Amore 31280219346bSGarrett D'Amore reclaim = hmep->hme_txreclaim % HME_TMDMAX; 31290219346bSGarrett D'Amore HMESYNCTMD(reclaim, DDI_DMA_SYNC_FORKERNEL); 31300219346bSGarrett D'Amore 31310219346bSGarrett D'Amore flags = GET_TMD_FLAGS(reclaim); 31320219346bSGarrett D'Amore if (flags & HMETMD_OWN) { 31330219346bSGarrett D'Amore /* 31340219346bSGarrett D'Amore * Chip still owns it. We're done. 31350219346bSGarrett D'Amore */ 31360219346bSGarrett D'Amore break; 31370219346bSGarrett D'Amore } 31387c478bd9Sstevel@tonic-gate 31397c478bd9Sstevel@tonic-gate /* 31400219346bSGarrett D'Amore * Count a chained packet only once. 31417c478bd9Sstevel@tonic-gate */ 31420219346bSGarrett D'Amore if (flags & HMETMD_SOP) { 31437c478bd9Sstevel@tonic-gate hmep->hme_opackets++; 31447c478bd9Sstevel@tonic-gate } 31457c478bd9Sstevel@tonic-gate 31467c478bd9Sstevel@tonic-gate /* 31477c478bd9Sstevel@tonic-gate * MIB II 31487c478bd9Sstevel@tonic-gate */ 31490219346bSGarrett D'Amore hmep->hme_obytes += flags & HMETMD_BUFSIZE; 31507c478bd9Sstevel@tonic-gate 31510219346bSGarrett D'Amore reclaimed = B_TRUE; 31520219346bSGarrett D'Amore hmep->hme_txreclaim++; 31537c478bd9Sstevel@tonic-gate } 31547c478bd9Sstevel@tonic-gate 31550219346bSGarrett D'Amore if (reclaimed) { 31567c478bd9Sstevel@tonic-gate /* 31577c478bd9Sstevel@tonic-gate * we could reclaim some TMDs so turn off interrupts 31587c478bd9Sstevel@tonic-gate */ 31597c478bd9Sstevel@tonic-gate if (hmep->hme_wantw) { 31607c478bd9Sstevel@tonic-gate PUT_GLOBREG(intmask, 316185025c03Sgd HMEG_MASK_INTR | HMEG_MASK_TINT | 316285025c03Sgd HMEG_MASK_TX_ALL); 316385025c03Sgd hmep->hme_wantw = B_FALSE; 316485025c03Sgd mac_tx_update(hmep->hme_mh); 31657c478bd9Sstevel@tonic-gate } 31667c478bd9Sstevel@tonic-gate } else { 31677c478bd9Sstevel@tonic-gate /* 31687c478bd9Sstevel@tonic-gate * enable TINTS: so that even if there is no further activity 31697c478bd9Sstevel@tonic-gate * hmereclaim will get called 31707c478bd9Sstevel@tonic-gate */ 31717c478bd9Sstevel@tonic-gate if (hmep->hme_wantw) 317285025c03Sgd PUT_GLOBREG(intmask, 317385025c03Sgd GET_GLOBREG(intmask) & ~HMEG_MASK_TX_ALL); 31747c478bd9Sstevel@tonic-gate } 31757c478bd9Sstevel@tonic-gate CHECK_GLOBREG(); 31767c478bd9Sstevel@tonic-gate } 31777c478bd9Sstevel@tonic-gate 31787c478bd9Sstevel@tonic-gate /* 31797c478bd9Sstevel@tonic-gate * Handle interrupts for fatal errors 31807c478bd9Sstevel@tonic-gate * Need reinitialization of the ENET channel. 31817c478bd9Sstevel@tonic-gate */ 31827c478bd9Sstevel@tonic-gate static void 31837c478bd9Sstevel@tonic-gate hme_fatal_err(struct hme *hmep, uint_t hmesbits) 31847c478bd9Sstevel@tonic-gate { 31857c478bd9Sstevel@tonic-gate 31867c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_SLV_PAR_ERR) { 31877c478bd9Sstevel@tonic-gate hmep->hme_slvparerr++; 31887c478bd9Sstevel@tonic-gate } 31897c478bd9Sstevel@tonic-gate 31907c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_SLV_ERR_ACK) { 31917c478bd9Sstevel@tonic-gate hmep->hme_slverrack++; 31927c478bd9Sstevel@tonic-gate } 31937c478bd9Sstevel@tonic-gate 31947c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_TX_TAG_ERR) { 31957c478bd9Sstevel@tonic-gate hmep->hme_txtagerr++; 31967c478bd9Sstevel@tonic-gate hmep->hme_oerrors++; 31977c478bd9Sstevel@tonic-gate } 31987c478bd9Sstevel@tonic-gate 31997c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_TX_PAR_ERR) { 32007c478bd9Sstevel@tonic-gate hmep->hme_txparerr++; 32017c478bd9Sstevel@tonic-gate hmep->hme_oerrors++; 32027c478bd9Sstevel@tonic-gate } 32037c478bd9Sstevel@tonic-gate 32047c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_TX_LATE_ERR) { 32057c478bd9Sstevel@tonic-gate hmep->hme_txlaterr++; 32067c478bd9Sstevel@tonic-gate hmep->hme_oerrors++; 32077c478bd9Sstevel@tonic-gate } 32087c478bd9Sstevel@tonic-gate 32097c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_TX_ERR_ACK) { 32107c478bd9Sstevel@tonic-gate hmep->hme_txerrack++; 32117c478bd9Sstevel@tonic-gate hmep->hme_oerrors++; 32127c478bd9Sstevel@tonic-gate } 32137c478bd9Sstevel@tonic-gate 32147c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_EOP_ERR) { 32157c478bd9Sstevel@tonic-gate hmep->hme_eoperr++; 32167c478bd9Sstevel@tonic-gate } 32177c478bd9Sstevel@tonic-gate 32187c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_RX_TAG_ERR) { 32197c478bd9Sstevel@tonic-gate hmep->hme_rxtagerr++; 32207c478bd9Sstevel@tonic-gate hmep->hme_ierrors++; 32217c478bd9Sstevel@tonic-gate } 32227c478bd9Sstevel@tonic-gate 32237c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_RX_PAR_ERR) { 32247c478bd9Sstevel@tonic-gate hmep->hme_rxparerr++; 32257c478bd9Sstevel@tonic-gate hmep->hme_ierrors++; 32267c478bd9Sstevel@tonic-gate } 32277c478bd9Sstevel@tonic-gate 32287c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_RX_LATE_ERR) { 32297c478bd9Sstevel@tonic-gate hmep->hme_rxlaterr++; 32307c478bd9Sstevel@tonic-gate hmep->hme_ierrors++; 32317c478bd9Sstevel@tonic-gate } 32327c478bd9Sstevel@tonic-gate 32337c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_RX_ERR_ACK) { 32347c478bd9Sstevel@tonic-gate hmep->hme_rxerrack++; 32357c478bd9Sstevel@tonic-gate hmep->hme_ierrors++; 32367c478bd9Sstevel@tonic-gate } 32377c478bd9Sstevel@tonic-gate } 32387c478bd9Sstevel@tonic-gate 32397c478bd9Sstevel@tonic-gate /* 32407c478bd9Sstevel@tonic-gate * Handle interrupts regarding non-fatal errors. 32417c478bd9Sstevel@tonic-gate */ 32427c478bd9Sstevel@tonic-gate static void 32437c478bd9Sstevel@tonic-gate hme_nonfatal_err(struct hme *hmep, uint_t hmesbits) 32447c478bd9Sstevel@tonic-gate { 32457c478bd9Sstevel@tonic-gate 32467c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_RX_DROP) { 32477c478bd9Sstevel@tonic-gate hmep->hme_missed++; 32487c478bd9Sstevel@tonic-gate hmep->hme_ierrors++; 32497c478bd9Sstevel@tonic-gate } 32507c478bd9Sstevel@tonic-gate 32517c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_DEFTIMR_EXP) { 32527c478bd9Sstevel@tonic-gate hmep->hme_defer_xmts++; 32537c478bd9Sstevel@tonic-gate } 32547c478bd9Sstevel@tonic-gate 32557c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_FSTCOLC_EXP) { 32567c478bd9Sstevel@tonic-gate hmep->hme_fstcol += 256; 32577c478bd9Sstevel@tonic-gate } 32587c478bd9Sstevel@tonic-gate 32597c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_LATCOLC_EXP) { 32607c478bd9Sstevel@tonic-gate hmep->hme_tlcol += 256; 32617c478bd9Sstevel@tonic-gate hmep->hme_oerrors += 256; 32627c478bd9Sstevel@tonic-gate } 32637c478bd9Sstevel@tonic-gate 32647c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_EXCOLC_EXP) { 326585025c03Sgd hmep->hme_excol += 256; 32667c478bd9Sstevel@tonic-gate hmep->hme_oerrors += 256; 32677c478bd9Sstevel@tonic-gate } 32687c478bd9Sstevel@tonic-gate 32697c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_NRMCOLC_EXP) { 32707c478bd9Sstevel@tonic-gate hmep->hme_coll += 256; 32717c478bd9Sstevel@tonic-gate } 32727c478bd9Sstevel@tonic-gate 32737c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_MXPKTSZ_ERR) { 32747c478bd9Sstevel@tonic-gate hmep->hme_babl++; 32757c478bd9Sstevel@tonic-gate hmep->hme_oerrors++; 32767c478bd9Sstevel@tonic-gate } 32777c478bd9Sstevel@tonic-gate 32787c478bd9Sstevel@tonic-gate /* 32797c478bd9Sstevel@tonic-gate * This error is fatal and the board needs to 32807c478bd9Sstevel@tonic-gate * be reinitialized. Comments? 32817c478bd9Sstevel@tonic-gate */ 32827c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_TXFIFO_UNDR) { 32837c478bd9Sstevel@tonic-gate hmep->hme_uflo++; 32847c478bd9Sstevel@tonic-gate hmep->hme_oerrors++; 32857c478bd9Sstevel@tonic-gate } 32867c478bd9Sstevel@tonic-gate 32877c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_SQE_TST_ERR) { 32887c478bd9Sstevel@tonic-gate hmep->hme_sqe_errors++; 32897c478bd9Sstevel@tonic-gate } 32907c478bd9Sstevel@tonic-gate 32917c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_RCV_CNT_EXP) { 32927c478bd9Sstevel@tonic-gate if (hmep->hme_rxcv_enable) { 32937c478bd9Sstevel@tonic-gate hmep->hme_cvc += 256; 32947c478bd9Sstevel@tonic-gate } 32957c478bd9Sstevel@tonic-gate } 32967c478bd9Sstevel@tonic-gate 32977c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_RXFIFO_OVFL) { 32987c478bd9Sstevel@tonic-gate hmep->hme_oflo++; 32997c478bd9Sstevel@tonic-gate hmep->hme_ierrors++; 33007c478bd9Sstevel@tonic-gate } 33017c478bd9Sstevel@tonic-gate 33027c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_LEN_CNT_EXP) { 33037c478bd9Sstevel@tonic-gate hmep->hme_lenerr += 256; 33047c478bd9Sstevel@tonic-gate hmep->hme_ierrors += 256; 33057c478bd9Sstevel@tonic-gate } 33067c478bd9Sstevel@tonic-gate 33077c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_ALN_CNT_EXP) { 33087c478bd9Sstevel@tonic-gate hmep->hme_align_errors += 256; 33097c478bd9Sstevel@tonic-gate hmep->hme_ierrors += 256; 33107c478bd9Sstevel@tonic-gate } 33117c478bd9Sstevel@tonic-gate 33127c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_CRC_CNT_EXP) { 33137c478bd9Sstevel@tonic-gate hmep->hme_fcs_errors += 256; 33147c478bd9Sstevel@tonic-gate hmep->hme_ierrors += 256; 33157c478bd9Sstevel@tonic-gate } 33167c478bd9Sstevel@tonic-gate } 33177c478bd9Sstevel@tonic-gate 331885025c03Sgd static mblk_t * 33190219346bSGarrett D'Amore hmeread(struct hme *hmep, hmebuf_t *rbuf, uint32_t rflags) 33207c478bd9Sstevel@tonic-gate { 33210219346bSGarrett D'Amore mblk_t *bp; 33220219346bSGarrett D'Amore uint32_t len; 33230219346bSGarrett D'Amore t_uscalar_t type; 33240219346bSGarrett D'Amore 332585025c03Sgd len = (rflags & HMERMD_BUFSIZE) >> HMERMD_BUFSIZE_SHIFT; 33267c478bd9Sstevel@tonic-gate 33277c478bd9Sstevel@tonic-gate /* 33287c478bd9Sstevel@tonic-gate * Check for short packet 33297c478bd9Sstevel@tonic-gate * and check for overflow packet also. The processing is the 33307c478bd9Sstevel@tonic-gate * same for both the cases - reuse the buffer. Update the Buffer 33317c478bd9Sstevel@tonic-gate * overflow counter. 33327c478bd9Sstevel@tonic-gate */ 333385025c03Sgd if ((len < ETHERMIN) || (rflags & HMERMD_OVFLOW) || 333485025c03Sgd (len > (ETHERMAX + 4))) { 33357c478bd9Sstevel@tonic-gate if (len < ETHERMIN) 33367c478bd9Sstevel@tonic-gate hmep->hme_runt++; 33377c478bd9Sstevel@tonic-gate 33387c478bd9Sstevel@tonic-gate else { 33397c478bd9Sstevel@tonic-gate hmep->hme_buff++; 33407c478bd9Sstevel@tonic-gate hmep->hme_toolong_errors++; 33417c478bd9Sstevel@tonic-gate } 33427c478bd9Sstevel@tonic-gate hmep->hme_ierrors++; 334385025c03Sgd return (NULL); 33447c478bd9Sstevel@tonic-gate } 33457c478bd9Sstevel@tonic-gate 33467c478bd9Sstevel@tonic-gate /* 33477c478bd9Sstevel@tonic-gate * Sync the received buffer before looking at it. 33487c478bd9Sstevel@tonic-gate */ 33497c478bd9Sstevel@tonic-gate 33500219346bSGarrett D'Amore (void) ddi_dma_sync(rbuf->dmah, 0, 0, DDI_DMA_SYNC_FORKERNEL); 33517c478bd9Sstevel@tonic-gate 33527c478bd9Sstevel@tonic-gate /* 33537c478bd9Sstevel@tonic-gate * copy the packet data and then recycle the descriptor. 33547c478bd9Sstevel@tonic-gate */ 33557c478bd9Sstevel@tonic-gate 33560219346bSGarrett D'Amore if ((bp = allocb(len + HME_FSTBYTE_OFFSET, BPRI_HI)) == NULL) { 33577c478bd9Sstevel@tonic-gate 33587c478bd9Sstevel@tonic-gate hmep->hme_allocbfail++; 33597c478bd9Sstevel@tonic-gate hmep->hme_norcvbuf++; 336085025c03Sgd 336185025c03Sgd return (NULL); 33627c478bd9Sstevel@tonic-gate } 33637c478bd9Sstevel@tonic-gate 33640219346bSGarrett D'Amore bcopy(rbuf->kaddr, bp->b_rptr, len + HME_FSTBYTE_OFFSET); 33657c478bd9Sstevel@tonic-gate 33660219346bSGarrett D'Amore hmep->hme_ipackets++; 33677c478bd9Sstevel@tonic-gate 33680219346bSGarrett D'Amore /* Add the First Byte offset to the b_rptr and copy */ 33690219346bSGarrett D'Amore bp->b_rptr += HME_FSTBYTE_OFFSET; 33700219346bSGarrett D'Amore bp->b_wptr = bp->b_rptr + len; 33717c478bd9Sstevel@tonic-gate 33727c478bd9Sstevel@tonic-gate /* 33730219346bSGarrett D'Amore * update MIB II statistics 33747c478bd9Sstevel@tonic-gate */ 33750219346bSGarrett D'Amore BUMP_InNUcast(hmep, bp->b_rptr); 33760219346bSGarrett D'Amore hmep->hme_rbytes += len; 33777c478bd9Sstevel@tonic-gate 33780219346bSGarrett D'Amore type = get_ether_type(bp->b_rptr); 33797c478bd9Sstevel@tonic-gate 33807c478bd9Sstevel@tonic-gate /* 33810219346bSGarrett D'Amore * TCP partial checksum in hardware 33827c478bd9Sstevel@tonic-gate */ 33830219346bSGarrett D'Amore if (type == ETHERTYPE_IP || type == ETHERTYPE_IPV6) { 33840219346bSGarrett D'Amore uint16_t cksum = ~rflags & HMERMD_CKSUM; 33850219346bSGarrett D'Amore uint_t end = len - sizeof (struct ether_header); 33860219346bSGarrett D'Amore (void) hcksum_assoc(bp, NULL, NULL, 0, 33870219346bSGarrett D'Amore 0, end, htons(cksum), HCK_PARTIALCKSUM, 0); 33887c478bd9Sstevel@tonic-gate } 33897c478bd9Sstevel@tonic-gate 339085025c03Sgd return (bp); 33917c478bd9Sstevel@tonic-gate } 33927c478bd9Sstevel@tonic-gate 33937c478bd9Sstevel@tonic-gate /*VARARGS*/ 33947c478bd9Sstevel@tonic-gate static void 33950219346bSGarrett D'Amore hme_fault_msg(struct hme *hmep, uint_t severity, msg_t type, char *fmt, ...) 33967c478bd9Sstevel@tonic-gate { 33977c478bd9Sstevel@tonic-gate char msg_buffer[255]; 33987c478bd9Sstevel@tonic-gate va_list ap; 33997c478bd9Sstevel@tonic-gate 34007c478bd9Sstevel@tonic-gate va_start(ap, fmt); 3401228fdff0Sgd (void) vsnprintf(msg_buffer, sizeof (msg_buffer), fmt, ap); 34027c478bd9Sstevel@tonic-gate 340385025c03Sgd if (hmep == NULL) { 34047c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "hme : %s", msg_buffer); 34057c478bd9Sstevel@tonic-gate 340685025c03Sgd } else if (type == DISPLAY_MSG) { 340785025c03Sgd cmn_err(CE_CONT, "?%s%d : %s\n", ddi_driver_name(hmep->dip), 340885025c03Sgd hmep->instance, msg_buffer); 340985025c03Sgd } else if (severity == SEVERITY_HIGH) { 341085025c03Sgd cmn_err(CE_WARN, "%s%d : %s, SEVERITY_HIGH, %s\n", 341185025c03Sgd ddi_driver_name(hmep->dip), hmep->instance, 341285025c03Sgd msg_buffer, msg_string[type]); 341385025c03Sgd } else { 341485025c03Sgd cmn_err(CE_CONT, "%s%d : %s\n", ddi_driver_name(hmep->dip), 341585025c03Sgd hmep->instance, msg_buffer); 341685025c03Sgd } 34177c478bd9Sstevel@tonic-gate va_end(ap); 34187c478bd9Sstevel@tonic-gate } 34197c478bd9Sstevel@tonic-gate 34207c478bd9Sstevel@tonic-gate /* 34217c478bd9Sstevel@tonic-gate * if this is the first init do not bother to save the 34227c478bd9Sstevel@tonic-gate * counters. They should be 0, but do not count on it. 34237c478bd9Sstevel@tonic-gate */ 34247c478bd9Sstevel@tonic-gate static void 34257c478bd9Sstevel@tonic-gate hmesavecntrs(struct hme *hmep) 34267c478bd9Sstevel@tonic-gate { 34277c478bd9Sstevel@tonic-gate uint32_t fecnt, aecnt, lecnt, rxcv; 34287c478bd9Sstevel@tonic-gate uint32_t ltcnt, excnt; 34297c478bd9Sstevel@tonic-gate 34307c478bd9Sstevel@tonic-gate /* XXX What all gets added in ierrors and oerrors? */ 34317c478bd9Sstevel@tonic-gate fecnt = GET_MACREG(fecnt); 34327c478bd9Sstevel@tonic-gate PUT_MACREG(fecnt, 0); 34337c478bd9Sstevel@tonic-gate 34347c478bd9Sstevel@tonic-gate aecnt = GET_MACREG(aecnt); 34357c478bd9Sstevel@tonic-gate hmep->hme_align_errors += aecnt; 34367c478bd9Sstevel@tonic-gate PUT_MACREG(aecnt, 0); 34377c478bd9Sstevel@tonic-gate 34387c478bd9Sstevel@tonic-gate lecnt = GET_MACREG(lecnt); 34397c478bd9Sstevel@tonic-gate hmep->hme_lenerr += lecnt; 34407c478bd9Sstevel@tonic-gate PUT_MACREG(lecnt, 0); 34417c478bd9Sstevel@tonic-gate 34427c478bd9Sstevel@tonic-gate rxcv = GET_MACREG(rxcv); 34437c478bd9Sstevel@tonic-gate #ifdef HME_CODEVIOL_BUG 34447c478bd9Sstevel@tonic-gate /* 34457c478bd9Sstevel@tonic-gate * Ignore rxcv errors for Sbus/FEPS 2.1 or earlier 34467c478bd9Sstevel@tonic-gate */ 34477c478bd9Sstevel@tonic-gate if (!hmep->hme_rxcv_enable) { 34487c478bd9Sstevel@tonic-gate rxcv = 0; 34497c478bd9Sstevel@tonic-gate } 34507c478bd9Sstevel@tonic-gate #endif 34517c478bd9Sstevel@tonic-gate hmep->hme_cvc += rxcv; 34527c478bd9Sstevel@tonic-gate PUT_MACREG(rxcv, 0); 34537c478bd9Sstevel@tonic-gate 34547c478bd9Sstevel@tonic-gate ltcnt = GET_MACREG(ltcnt); 34557c478bd9Sstevel@tonic-gate hmep->hme_tlcol += ltcnt; 34567c478bd9Sstevel@tonic-gate PUT_MACREG(ltcnt, 0); 34577c478bd9Sstevel@tonic-gate 34587c478bd9Sstevel@tonic-gate excnt = GET_MACREG(excnt); 345985025c03Sgd hmep->hme_excol += excnt; 34607c478bd9Sstevel@tonic-gate PUT_MACREG(excnt, 0); 34617c478bd9Sstevel@tonic-gate 34627c478bd9Sstevel@tonic-gate hmep->hme_fcs_errors += fecnt; 34637c478bd9Sstevel@tonic-gate hmep->hme_ierrors += (fecnt + aecnt + lecnt); 34647c478bd9Sstevel@tonic-gate hmep->hme_oerrors += (ltcnt + excnt); 34657c478bd9Sstevel@tonic-gate hmep->hme_coll += (GET_MACREG(nccnt) + ltcnt); 34667c478bd9Sstevel@tonic-gate 34677c478bd9Sstevel@tonic-gate PUT_MACREG(nccnt, 0); 34687c478bd9Sstevel@tonic-gate CHECK_MACREG(); 34697c478bd9Sstevel@tonic-gate } 34707c478bd9Sstevel@tonic-gate 34717c478bd9Sstevel@tonic-gate /* 34727c478bd9Sstevel@tonic-gate * To set up the mac address for the network interface: 34737c478bd9Sstevel@tonic-gate * The adapter card may support a local mac address which is published 34747c478bd9Sstevel@tonic-gate * in a device node property "local-mac-address". This mac address is 34757c478bd9Sstevel@tonic-gate * treated as the factory-installed mac address for DLPI interface. 34767c478bd9Sstevel@tonic-gate * If the adapter firmware has used the device for diskless boot 34777c478bd9Sstevel@tonic-gate * operation it publishes a property called "mac-address" for use by 34787c478bd9Sstevel@tonic-gate * inetboot and the device driver. 34797c478bd9Sstevel@tonic-gate * If "mac-address" is not found, the system options property 34807c478bd9Sstevel@tonic-gate * "local-mac-address" is used to select the mac-address. If this option 34817c478bd9Sstevel@tonic-gate * is set to "true", and "local-mac-address" has been found, then 34827c478bd9Sstevel@tonic-gate * local-mac-address is used; otherwise the system mac address is used 34837c478bd9Sstevel@tonic-gate * by calling the "localetheraddr()" function. 34847c478bd9Sstevel@tonic-gate */ 34857c478bd9Sstevel@tonic-gate static void 34867c478bd9Sstevel@tonic-gate hme_setup_mac_address(struct hme *hmep, dev_info_t *dip) 34877c478bd9Sstevel@tonic-gate { 34887c478bd9Sstevel@tonic-gate char *prop; 34897c478bd9Sstevel@tonic-gate int prop_len = sizeof (int); 34907c478bd9Sstevel@tonic-gate 34917c478bd9Sstevel@tonic-gate hmep->hme_addrflags = 0; 34927c478bd9Sstevel@tonic-gate 34937c478bd9Sstevel@tonic-gate /* 34947c478bd9Sstevel@tonic-gate * Check if it is an adapter with its own local mac address 34957c478bd9Sstevel@tonic-gate * If it is present, save it as the "factory-address" 34967c478bd9Sstevel@tonic-gate * for this adapter. 34977c478bd9Sstevel@tonic-gate */ 349885025c03Sgd if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 349985025c03Sgd "local-mac-address", 350085025c03Sgd (caddr_t)&prop, &prop_len) == DDI_PROP_SUCCESS) { 35017c478bd9Sstevel@tonic-gate if (prop_len == ETHERADDRL) { 35027c478bd9Sstevel@tonic-gate hmep->hme_addrflags = HME_FACTADDR_PRESENT; 35037c478bd9Sstevel@tonic-gate ether_bcopy(prop, &hmep->hme_factaddr); 35047c478bd9Sstevel@tonic-gate HME_FAULT_MSG2(hmep, SEVERITY_NONE, DISPLAY_MSG, 35050219346bSGarrett D'Amore "Local Ethernet address = %s", 350685025c03Sgd ether_sprintf(&hmep->hme_factaddr)); 35077c478bd9Sstevel@tonic-gate } 35087c478bd9Sstevel@tonic-gate kmem_free(prop, prop_len); 35097c478bd9Sstevel@tonic-gate } 35107c478bd9Sstevel@tonic-gate 35117c478bd9Sstevel@tonic-gate /* 35127c478bd9Sstevel@tonic-gate * Check if the adapter has published "mac-address" property. 35137c478bd9Sstevel@tonic-gate * If it is present, use it as the mac address for this device. 35147c478bd9Sstevel@tonic-gate */ 351585025c03Sgd if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 351685025c03Sgd "mac-address", (caddr_t)&prop, &prop_len) == DDI_PROP_SUCCESS) { 35177c478bd9Sstevel@tonic-gate if (prop_len >= ETHERADDRL) { 35187c478bd9Sstevel@tonic-gate ether_bcopy(prop, &hmep->hme_ouraddr); 35197c478bd9Sstevel@tonic-gate kmem_free(prop, prop_len); 35207c478bd9Sstevel@tonic-gate return; 35217c478bd9Sstevel@tonic-gate } 35227c478bd9Sstevel@tonic-gate kmem_free(prop, prop_len); 35237c478bd9Sstevel@tonic-gate } 35247c478bd9Sstevel@tonic-gate 35250219346bSGarrett D'Amore #ifdef __sparc 35260219346bSGarrett D'Amore /* 35270219346bSGarrett D'Amore * On sparc, we might be able to use the mac address from the 35280219346bSGarrett D'Amore * system. However, on all other systems, we need to use the 35290219346bSGarrett D'Amore * address from the PROM. 35300219346bSGarrett D'Amore */ 35317c478bd9Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 0, "local-mac-address?", 353285025c03Sgd (caddr_t)&prop, &prop_len) == DDI_PROP_SUCCESS) { 35337c478bd9Sstevel@tonic-gate if ((strncmp("true", prop, prop_len) == 0) && 353485025c03Sgd (hmep->hme_addrflags & HME_FACTADDR_PRESENT)) { 35357c478bd9Sstevel@tonic-gate hmep->hme_addrflags |= HME_FACTADDR_USE; 35367c478bd9Sstevel@tonic-gate ether_bcopy(&hmep->hme_factaddr, &hmep->hme_ouraddr); 35377c478bd9Sstevel@tonic-gate kmem_free(prop, prop_len); 35387c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_NONE, DISPLAY_MSG, 35390219346bSGarrett D'Amore "Using local MAC address"); 35407c478bd9Sstevel@tonic-gate return; 35417c478bd9Sstevel@tonic-gate } 35427c478bd9Sstevel@tonic-gate kmem_free(prop, prop_len); 35437c478bd9Sstevel@tonic-gate } 35447c478bd9Sstevel@tonic-gate 35457c478bd9Sstevel@tonic-gate /* 35467c478bd9Sstevel@tonic-gate * Get the system ethernet address. 35477c478bd9Sstevel@tonic-gate */ 35487c478bd9Sstevel@tonic-gate (void) localetheraddr((struct ether_addr *)NULL, &hmep->hme_ouraddr); 35490219346bSGarrett D'Amore #else 35500219346bSGarrett D'Amore ether_bcopy(&hmep->hme_factaddr, &hmep->hme_ouraddr); 35510219346bSGarrett D'Amore #endif 35527c478bd9Sstevel@tonic-gate } 35537c478bd9Sstevel@tonic-gate 35547c478bd9Sstevel@tonic-gate /* ARGSUSED */ 35557c478bd9Sstevel@tonic-gate static void 35567c478bd9Sstevel@tonic-gate hme_check_acc_handle(char *file, uint_t line, struct hme *hmep, 35577c478bd9Sstevel@tonic-gate ddi_acc_handle_t handle) 35587c478bd9Sstevel@tonic-gate { 35597c478bd9Sstevel@tonic-gate } 3560