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 /* 22*7a92e70fSZeeshanul Huq - Sun Microsystems - Beijing China * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. 237c478bd9Sstevel@tonic-gate */ 247c478bd9Sstevel@tonic-gate 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* 277c478bd9Sstevel@tonic-gate * SunOS MT STREAMS FEPS(SBus)/Cheerio(PCI) 10/100Mb Ethernet Device Driver 287c478bd9Sstevel@tonic-gate */ 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate #include <sys/types.h> 317c478bd9Sstevel@tonic-gate #include <sys/debug.h> 327c478bd9Sstevel@tonic-gate #include <sys/stream.h> 337c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 347c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 357c478bd9Sstevel@tonic-gate #include <sys/crc32.h> 3685025c03Sgd #include <sys/modctl.h> 3785025c03Sgd #include <sys/conf.h> 387c478bd9Sstevel@tonic-gate #include <sys/strsun.h> 397c478bd9Sstevel@tonic-gate #include <sys/kstat.h> 4085025c03Sgd #include <sys/pattr.h> 417c478bd9Sstevel@tonic-gate #include <sys/dlpi.h> 4285025c03Sgd #include <sys/strsubr.h> 43da14cebeSEric Cheng #include <sys/mac_provider.h> 4485025c03Sgd #include <sys/mac_ether.h> 4506673d9bSGarrett D'Amore #include <sys/mii.h> 467c478bd9Sstevel@tonic-gate #include <sys/ethernet.h> 47d62bc4baSyz #include <sys/vlan.h> 4885025c03Sgd #include <sys/pci.h> 4985025c03Sgd #include <sys/policy.h> 5085025c03Sgd #include <sys/ddi.h> 5185025c03Sgd #include <sys/sunddi.h> 520dc2366fSVenugopal Iyer #include <sys/byteorder.h> 530219346bSGarrett D'Amore #include "hme_phy.h" 540219346bSGarrett D'Amore #include "hme_mac.h" 550219346bSGarrett D'Amore #include "hme.h" 567c478bd9Sstevel@tonic-gate 577c478bd9Sstevel@tonic-gate typedef void (*fptrv_t)(); 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate typedef enum { 607c478bd9Sstevel@tonic-gate NO_MSG = 0, 6106673d9bSGarrett D'Amore AUTOCONFIG_MSG, 6206673d9bSGarrett D'Amore DISPLAY_MSG, 6306673d9bSGarrett D'Amore INIT_MSG, 6406673d9bSGarrett D'Amore UNINIT_MSG, 6506673d9bSGarrett D'Amore CONFIG_MSG, 6606673d9bSGarrett D'Amore MII_MSG, 6706673d9bSGarrett D'Amore FATAL_ERR_MSG, 6806673d9bSGarrett D'Amore NFATAL_ERR_MSG, 6906673d9bSGarrett D'Amore XCVR_MSG, 7006673d9bSGarrett D'Amore NOXCVR_MSG, 7106673d9bSGarrett D'Amore ERX_MSG, 7206673d9bSGarrett D'Amore DDI_MSG, 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 ", 8006673d9bSGarrett D'Amore "DISPLAY " 817c478bd9Sstevel@tonic-gate "INIT ", 827c478bd9Sstevel@tonic-gate "UNINIT ", 837c478bd9Sstevel@tonic-gate "CONFIG ", 8406673d9bSGarrett 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 */ 11406673d9bSGarrett D'Amore static int hme_ngu_enable = 0; /* Never Give Up mode */ 1157c478bd9Sstevel@tonic-gate 1160dc2366fSVenugopal Iyer char *hme_priv_prop[] = { 1170dc2366fSVenugopal Iyer "_ipg0", 1180dc2366fSVenugopal Iyer "_ipg1", 1190dc2366fSVenugopal Iyer "_ipg2", 1200dc2366fSVenugopal Iyer "_lance_mode", 1210dc2366fSVenugopal Iyer NULL 12206673d9bSGarrett D'Amore }; 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate static int hme_lance_mode = 1; /* to enable lance mode */ 1257c478bd9Sstevel@tonic-gate static int hme_ipg0 = 16; 1267c478bd9Sstevel@tonic-gate static int hme_ipg1 = 8; 1277c478bd9Sstevel@tonic-gate static int hme_ipg2 = 4; 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate /* 1307c478bd9Sstevel@tonic-gate * The following parameters may be configured by the user. If they are not 1317c478bd9Sstevel@tonic-gate * configured by the user, the values will be based on the capabilities of 1327c478bd9Sstevel@tonic-gate * the transceiver. 1337c478bd9Sstevel@tonic-gate * The value "HME_NOTUSR" is ORed with the parameter value to indicate values 1347c478bd9Sstevel@tonic-gate * which are NOT configured by the user. 1357c478bd9Sstevel@tonic-gate */ 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate #define HME_NOTUSR 0x0f000000 1387c478bd9Sstevel@tonic-gate #define HME_MASK_1BIT 0x1 1397c478bd9Sstevel@tonic-gate #define HME_MASK_5BIT 0x1f 1407c478bd9Sstevel@tonic-gate #define HME_MASK_8BIT 0xff 1417c478bd9Sstevel@tonic-gate 1427c478bd9Sstevel@tonic-gate /* 1437c478bd9Sstevel@tonic-gate * All strings used by hme messaging functions 1447c478bd9Sstevel@tonic-gate */ 1457c478bd9Sstevel@tonic-gate 1467c478bd9Sstevel@tonic-gate static char *no_xcvr_msg = 1477c478bd9Sstevel@tonic-gate "No transceiver found."; 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate static char *burst_size_msg = 1507c478bd9Sstevel@tonic-gate "Could not identify the burst size"; 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate static char *unk_rx_ringsz_msg = 1537c478bd9Sstevel@tonic-gate "Unknown receive RINGSZ"; 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate static char *add_intr_fail_msg = 1567c478bd9Sstevel@tonic-gate "ddi_add_intr(9F) failed"; 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate static char *mregs_4global_reg_fail_msg = 1597c478bd9Sstevel@tonic-gate "ddi_regs_map_setup(9F) for global reg failed"; 1607c478bd9Sstevel@tonic-gate 1617c478bd9Sstevel@tonic-gate static char *mregs_4etx_reg_fail_msg = 1627c478bd9Sstevel@tonic-gate "ddi_map_regs for etx reg failed"; 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate static char *mregs_4erx_reg_fail_msg = 1657c478bd9Sstevel@tonic-gate "ddi_map_regs for erx reg failed"; 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate static char *mregs_4bmac_reg_fail_msg = 1687c478bd9Sstevel@tonic-gate "ddi_map_regs for bmac reg failed"; 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate static char *mregs_4mif_reg_fail_msg = 1717c478bd9Sstevel@tonic-gate "ddi_map_regs for mif reg failed"; 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate static char *init_fail_gen_msg = 1747c478bd9Sstevel@tonic-gate "Failed to initialize hardware/driver"; 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate static char *ddi_nregs_fail_msg = 1777c478bd9Sstevel@tonic-gate "ddi_dev_nregs failed(9F), returned %d"; 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate static char *bad_num_regs_msg = 1807c478bd9Sstevel@tonic-gate "Invalid number of registers."; 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate 1837c478bd9Sstevel@tonic-gate /* FATAL ERR msgs */ 1847c478bd9Sstevel@tonic-gate /* 1857c478bd9Sstevel@tonic-gate * Function prototypes. 1867c478bd9Sstevel@tonic-gate */ 187f2cd0f02Sgd /* these two are global so that qfe can use them */ 188f2cd0f02Sgd int hmeattach(dev_info_t *, ddi_attach_cmd_t); 189f2cd0f02Sgd int hmedetach(dev_info_t *, ddi_detach_cmd_t); 1900219346bSGarrett D'Amore int hmequiesce(dev_info_t *); 19185025c03Sgd static boolean_t hmeinit_xfer_params(struct hme *); 1927c478bd9Sstevel@tonic-gate static uint_t hmestop(struct hme *); 1937c478bd9Sstevel@tonic-gate static void hmestatinit(struct hme *); 1947c478bd9Sstevel@tonic-gate static int hmeallocthings(struct hme *); 1950219346bSGarrett D'Amore static void hmefreethings(struct hme *); 1960219346bSGarrett D'Amore static int hmeallocbuf(struct hme *, hmebuf_t *, int); 1970219346bSGarrett D'Amore static int hmeallocbufs(struct hme *); 1987c478bd9Sstevel@tonic-gate static void hmefreebufs(struct hme *); 1997c478bd9Sstevel@tonic-gate static void hmeget_hm_rev_property(struct hme *); 20085025c03Sgd static boolean_t hmestart(struct hme *, mblk_t *); 20185025c03Sgd static uint_t hmeintr(caddr_t); 2027c478bd9Sstevel@tonic-gate static void hmereclaim(struct hme *); 2037c478bd9Sstevel@tonic-gate static int hmeinit(struct hme *); 2047c478bd9Sstevel@tonic-gate static void hmeuninit(struct hme *hmep); 2050219346bSGarrett D'Amore static mblk_t *hmeread(struct hme *, hmebuf_t *, uint32_t); 2067c478bd9Sstevel@tonic-gate static void hmesavecntrs(struct hme *); 2077c478bd9Sstevel@tonic-gate static void hme_fatal_err(struct hme *, uint_t); 2087c478bd9Sstevel@tonic-gate static void hme_nonfatal_err(struct hme *, uint_t); 2097c478bd9Sstevel@tonic-gate static int hmeburstsizes(struct hme *); 21006673d9bSGarrett D'Amore static void send_bit(struct hme *, uint16_t); 21106673d9bSGarrett D'Amore static uint16_t get_bit_std(uint8_t, struct hme *); 21206673d9bSGarrett D'Amore static uint16_t hme_bb_mii_read(struct hme *, uint8_t, uint8_t); 21306673d9bSGarrett D'Amore static void hme_bb_mii_write(struct hme *, uint8_t, uint8_t, uint16_t); 2147c478bd9Sstevel@tonic-gate static void hme_bb_force_idle(struct hme *); 21506673d9bSGarrett D'Amore static uint16_t hme_mii_read(void *, uint8_t, uint8_t); 21606673d9bSGarrett D'Amore static void hme_mii_write(void *, uint8_t, uint8_t, uint16_t); 2177c478bd9Sstevel@tonic-gate static void hme_setup_mac_address(struct hme *, dev_info_t *); 21806673d9bSGarrett D'Amore static void hme_mii_notify(void *, link_state_t); 2197c478bd9Sstevel@tonic-gate 2200219346bSGarrett D'Amore static void hme_fault_msg(struct hme *, uint_t, msg_t, char *, ...); 2217c478bd9Sstevel@tonic-gate 2227c478bd9Sstevel@tonic-gate static void hme_check_acc_handle(char *, uint_t, struct hme *, 22385025c03Sgd ddi_acc_handle_t); 2247c478bd9Sstevel@tonic-gate 22585025c03Sgd /* 22685025c03Sgd * Nemo (GLDv3) Functions. 22785025c03Sgd */ 22885025c03Sgd static int hme_m_stat(void *, uint_t, uint64_t *); 22985025c03Sgd static int hme_m_start(void *); 23085025c03Sgd static void hme_m_stop(void *); 23185025c03Sgd static int hme_m_promisc(void *, boolean_t); 23285025c03Sgd static int hme_m_multicst(void *, boolean_t, const uint8_t *); 23385025c03Sgd static int hme_m_unicst(void *, const uint8_t *); 23485025c03Sgd static mblk_t *hme_m_tx(void *, mblk_t *); 23585025c03Sgd static boolean_t hme_m_getcapab(void *, mac_capab_t, void *); 2360dc2366fSVenugopal Iyer static int hme_m_getprop(void *, const char *, mac_prop_id_t, uint_t, void *); 2370dc2366fSVenugopal Iyer static void hme_m_propinfo(void *, const char *, mac_prop_id_t, 2380dc2366fSVenugopal Iyer mac_prop_info_handle_t); 23906673d9bSGarrett D'Amore static int hme_m_setprop(void *, const char *, mac_prop_id_t, uint_t, 24006673d9bSGarrett D'Amore const void *); 24106673d9bSGarrett D'Amore 24206673d9bSGarrett D'Amore static mii_ops_t hme_mii_ops = { 24306673d9bSGarrett D'Amore MII_OPS_VERSION, 24406673d9bSGarrett D'Amore hme_mii_read, 24506673d9bSGarrett D'Amore hme_mii_write, 24606673d9bSGarrett D'Amore hme_mii_notify, 24706673d9bSGarrett D'Amore NULL 24806673d9bSGarrett D'Amore }; 24985025c03Sgd 25085025c03Sgd static mac_callbacks_t hme_m_callbacks = { 2510dc2366fSVenugopal Iyer MC_GETCAPAB | MC_SETPROP | MC_GETPROP | MC_PROPINFO, 25285025c03Sgd hme_m_stat, 25385025c03Sgd hme_m_start, 25485025c03Sgd hme_m_stop, 25585025c03Sgd hme_m_promisc, 25685025c03Sgd hme_m_multicst, 25785025c03Sgd hme_m_unicst, 25885025c03Sgd hme_m_tx, 25906673d9bSGarrett D'Amore NULL, 2600dc2366fSVenugopal Iyer NULL, 26185025c03Sgd hme_m_getcapab, 26206673d9bSGarrett D'Amore NULL, 26306673d9bSGarrett D'Amore NULL, 26406673d9bSGarrett D'Amore hme_m_setprop, 26506673d9bSGarrett D'Amore hme_m_getprop, 2660dc2366fSVenugopal Iyer hme_m_propinfo 26785025c03Sgd }; 26885025c03Sgd 26985025c03Sgd DDI_DEFINE_STREAM_OPS(hme_dev_ops, nulldev, nulldev, hmeattach, hmedetach, 2700219346bSGarrett D'Amore nodev, NULL, D_MP, NULL, hmequiesce); 2717c478bd9Sstevel@tonic-gate 2727c478bd9Sstevel@tonic-gate #define HME_FAULT_MSG1(p, s, t, f) \ 2730219346bSGarrett D'Amore hme_fault_msg((p), (s), (t), (f)); 2747c478bd9Sstevel@tonic-gate 2757c478bd9Sstevel@tonic-gate #define HME_FAULT_MSG2(p, s, t, f, a) \ 2760219346bSGarrett D'Amore hme_fault_msg((p), (s), (t), (f), (a)); 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate #define HME_FAULT_MSG3(p, s, t, f, a, b) \ 2790219346bSGarrett D'Amore hme_fault_msg((p), (s), (t), (f), (a), (b)); 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate #define HME_FAULT_MSG4(p, s, t, f, a, b, c) \ 2820219346bSGarrett D'Amore hme_fault_msg((p), (s), (t), (f), (a), (b), (c)); 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate #define CHECK_MIFREG() \ 2857c478bd9Sstevel@tonic-gate hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_mifregh) 2867c478bd9Sstevel@tonic-gate #define CHECK_ETXREG() \ 2877c478bd9Sstevel@tonic-gate hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_etxregh) 2887c478bd9Sstevel@tonic-gate #define CHECK_ERXREG() \ 2897c478bd9Sstevel@tonic-gate hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_erxregh) 2907c478bd9Sstevel@tonic-gate #define CHECK_MACREG() \ 2917c478bd9Sstevel@tonic-gate hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_bmacregh) 2927c478bd9Sstevel@tonic-gate #define CHECK_GLOBREG() \ 2937c478bd9Sstevel@tonic-gate hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_globregh) 2947c478bd9Sstevel@tonic-gate 2957c478bd9Sstevel@tonic-gate /* 2967c478bd9Sstevel@tonic-gate * Claim the device is ultra-capable of burst in the beginning. Use 2977c478bd9Sstevel@tonic-gate * the value returned by ddi_dma_burstsizes() to actually set the HME 2987c478bd9Sstevel@tonic-gate * global configuration register later. 2997c478bd9Sstevel@tonic-gate * 3007c478bd9Sstevel@tonic-gate * Sbus/FEPS supports burst sizes of 16, 32 and 64 bytes. Also, it supports 3017c478bd9Sstevel@tonic-gate * 32-bit and 64-bit Sbus transfers. Hence the dlim_burstsizes field contains 3027c478bd9Sstevel@tonic-gate * the the burstsizes in both the lo and hi words. 3037c478bd9Sstevel@tonic-gate */ 3047c478bd9Sstevel@tonic-gate #define HMELIMADDRLO ((uint64_t)0x00000000) 3057c478bd9Sstevel@tonic-gate #define HMELIMADDRHI ((uint64_t)0xffffffff) 3067c478bd9Sstevel@tonic-gate 3070219346bSGarrett D'Amore /* 3080219346bSGarrett D'Amore * Note that rx and tx data buffers can be arbitrarily aligned, but 3090219346bSGarrett D'Amore * that the descriptor rings need to be aligned on 2K boundaries, per 3100219346bSGarrett D'Amore * the spec. 3110219346bSGarrett D'Amore */ 3127c478bd9Sstevel@tonic-gate static ddi_dma_attr_t hme_dma_attr = { 3137c478bd9Sstevel@tonic-gate DMA_ATTR_V0, /* version number. */ 3147c478bd9Sstevel@tonic-gate (uint64_t)HMELIMADDRLO, /* low address */ 3157c478bd9Sstevel@tonic-gate (uint64_t)HMELIMADDRHI, /* high address */ 3167c478bd9Sstevel@tonic-gate (uint64_t)0x00ffffff, /* address counter max */ 3170219346bSGarrett D'Amore (uint64_t)HME_HMDALIGN, /* alignment */ 3187c478bd9Sstevel@tonic-gate (uint_t)0x00700070, /* dlim_burstsizes for 32 and 64 bit xfers */ 3197c478bd9Sstevel@tonic-gate (uint32_t)0x1, /* minimum transfer size */ 3207c478bd9Sstevel@tonic-gate (uint64_t)0x7fffffff, /* maximum transfer size */ 3217c478bd9Sstevel@tonic-gate (uint64_t)0x00ffffff, /* maximum segment size */ 3227c478bd9Sstevel@tonic-gate 1, /* scatter/gather list length */ 3237c478bd9Sstevel@tonic-gate 512, /* granularity */ 3247c478bd9Sstevel@tonic-gate 0 /* attribute flags */ 3257c478bd9Sstevel@tonic-gate }; 3267c478bd9Sstevel@tonic-gate 3270219346bSGarrett D'Amore static ddi_device_acc_attr_t hme_buf_attr = { 3280219346bSGarrett D'Amore DDI_DEVICE_ATTR_V0, 3290219346bSGarrett D'Amore DDI_NEVERSWAP_ACC, 3300219346bSGarrett D'Amore DDI_STRICTORDER_ACC, /* probably could allow merging & caching */ 3310219346bSGarrett D'Amore DDI_DEFAULT_ACC, 3327c478bd9Sstevel@tonic-gate }; 3337c478bd9Sstevel@tonic-gate 3347c478bd9Sstevel@tonic-gate static uchar_t pci_latency_timer = 0; 3357c478bd9Sstevel@tonic-gate 3367c478bd9Sstevel@tonic-gate /* 3377c478bd9Sstevel@tonic-gate * Module linkage information for the kernel. 3387c478bd9Sstevel@tonic-gate */ 3397c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 3407c478bd9Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a driver */ 34185025c03Sgd "Sun HME 10/100 Mb Ethernet", 34285025c03Sgd &hme_dev_ops, /* driver ops */ 3437c478bd9Sstevel@tonic-gate }; 3447c478bd9Sstevel@tonic-gate 3457c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 3467c478bd9Sstevel@tonic-gate MODREV_1, &modldrv, NULL 3477c478bd9Sstevel@tonic-gate }; 3487c478bd9Sstevel@tonic-gate 3497c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<<<<<<<<<<< Register operations >>>>>>>>>>>>>>>>>>>>> */ 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate #define GET_MIFREG(reg) \ 3527c478bd9Sstevel@tonic-gate ddi_get32(hmep->hme_mifregh, (uint32_t *)&hmep->hme_mifregp->reg) 3537c478bd9Sstevel@tonic-gate #define PUT_MIFREG(reg, value) \ 3547c478bd9Sstevel@tonic-gate ddi_put32(hmep->hme_mifregh, (uint32_t *)&hmep->hme_mifregp->reg, value) 3557c478bd9Sstevel@tonic-gate 3567c478bd9Sstevel@tonic-gate #define GET_ETXREG(reg) \ 3577c478bd9Sstevel@tonic-gate ddi_get32(hmep->hme_etxregh, (uint32_t *)&hmep->hme_etxregp->reg) 3587c478bd9Sstevel@tonic-gate #define PUT_ETXREG(reg, value) \ 3597c478bd9Sstevel@tonic-gate ddi_put32(hmep->hme_etxregh, (uint32_t *)&hmep->hme_etxregp->reg, value) 3607c478bd9Sstevel@tonic-gate #define GET_ERXREG(reg) \ 3617c478bd9Sstevel@tonic-gate ddi_get32(hmep->hme_erxregh, (uint32_t *)&hmep->hme_erxregp->reg) 3627c478bd9Sstevel@tonic-gate #define PUT_ERXREG(reg, value) \ 3637c478bd9Sstevel@tonic-gate ddi_put32(hmep->hme_erxregh, (uint32_t *)&hmep->hme_erxregp->reg, value) 3647c478bd9Sstevel@tonic-gate #define GET_MACREG(reg) \ 3657c478bd9Sstevel@tonic-gate ddi_get32(hmep->hme_bmacregh, (uint32_t *)&hmep->hme_bmacregp->reg) 3667c478bd9Sstevel@tonic-gate #define PUT_MACREG(reg, value) \ 3677c478bd9Sstevel@tonic-gate ddi_put32(hmep->hme_bmacregh, \ 3687c478bd9Sstevel@tonic-gate (uint32_t *)&hmep->hme_bmacregp->reg, value) 3697c478bd9Sstevel@tonic-gate #define GET_GLOBREG(reg) \ 3707c478bd9Sstevel@tonic-gate ddi_get32(hmep->hme_globregh, (uint32_t *)&hmep->hme_globregp->reg) 3717c478bd9Sstevel@tonic-gate #define PUT_GLOBREG(reg, value) \ 3727c478bd9Sstevel@tonic-gate ddi_put32(hmep->hme_globregh, \ 3737c478bd9Sstevel@tonic-gate (uint32_t *)&hmep->hme_globregp->reg, value) 3740219346bSGarrett D'Amore #define PUT_TMD(ptr, paddr, len, flags) \ 3750219346bSGarrett D'Amore ddi_put32(hmep->hme_tmd_acch, &hmep->hme_tmdp[ptr].tmd_addr, paddr); \ 3760219346bSGarrett D'Amore ddi_put32(hmep->hme_tmd_acch, &hmep->hme_tmdp[ptr].tmd_flags, \ 3770219346bSGarrett D'Amore len | flags) 3780219346bSGarrett D'Amore #define GET_TMD_FLAGS(ptr) \ 3790219346bSGarrett D'Amore ddi_get32(hmep->hme_tmd_acch, &hmep->hme_tmdp[ptr].tmd_flags) 3800219346bSGarrett D'Amore #define PUT_RMD(ptr, paddr) \ 3810219346bSGarrett D'Amore ddi_put32(hmep->hme_rmd_acch, &hmep->hme_rmdp[ptr].rmd_addr, paddr); \ 3820219346bSGarrett D'Amore ddi_put32(hmep->hme_rmd_acch, &hmep->hme_rmdp[ptr].rmd_flags, \ 3830219346bSGarrett D'Amore (uint32_t)(HMEBUFSIZE << HMERMD_BUFSIZE_SHIFT) | HMERMD_OWN) 3840219346bSGarrett D'Amore #define GET_RMD_FLAGS(ptr) \ 3850219346bSGarrett D'Amore ddi_get32(hmep->hme_rmd_acch, &hmep->hme_rmdp[ptr].rmd_flags) 3860219346bSGarrett D'Amore 3877c478bd9Sstevel@tonic-gate #define GET_ROM8(offset) \ 3887c478bd9Sstevel@tonic-gate ddi_get8((hmep->hme_romh), (offset)) 3897c478bd9Sstevel@tonic-gate 3907c478bd9Sstevel@tonic-gate /* 3917c478bd9Sstevel@tonic-gate * Ether_copy is not endian-correct. Define an endian-correct version. 3927c478bd9Sstevel@tonic-gate */ 3937c478bd9Sstevel@tonic-gate #define ether_bcopy(a, b) (bcopy(a, b, 6)) 3947c478bd9Sstevel@tonic-gate 3957c478bd9Sstevel@tonic-gate /* 3967c478bd9Sstevel@tonic-gate * Ether-type is specifically big-endian, but data region is unknown endian 3977c478bd9Sstevel@tonic-gate */ 39885025c03Sgd #define get_ether_type(ptr) \ 39985025c03Sgd (((((uint8_t *)ptr)[12] << 8) | (((uint8_t *)ptr)[13]))) 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<<<<<<<<<<< Configuration Parameters >>>>>>>>>>>>>>>>>>>>> */ 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate #define BMAC_DEFAULT_JAMSIZE (0x04) /* jamsize equals 4 */ 4047c478bd9Sstevel@tonic-gate #define BMAC_LONG_JAMSIZE (0x10) /* jamsize equals 0x10 */ 4057c478bd9Sstevel@tonic-gate static int jamsize = BMAC_DEFAULT_JAMSIZE; 4067c478bd9Sstevel@tonic-gate 4077c478bd9Sstevel@tonic-gate 4087c478bd9Sstevel@tonic-gate /* 4097c478bd9Sstevel@tonic-gate * Calculate the bit in the multicast address filter that selects the given 4107c478bd9Sstevel@tonic-gate * address. 4117c478bd9Sstevel@tonic-gate */ 4127c478bd9Sstevel@tonic-gate 4137c478bd9Sstevel@tonic-gate static uint32_t 41485025c03Sgd hmeladrf_bit(const uint8_t *addr) 4157c478bd9Sstevel@tonic-gate { 4167c478bd9Sstevel@tonic-gate uint32_t crc; 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate CRC32(crc, addr, ETHERADDRL, -1U, crc32_table); 4197c478bd9Sstevel@tonic-gate 4207c478bd9Sstevel@tonic-gate /* 4217c478bd9Sstevel@tonic-gate * Just want the 6 most significant bits. 4227c478bd9Sstevel@tonic-gate */ 4237c478bd9Sstevel@tonic-gate return (crc >> 26); 4247c478bd9Sstevel@tonic-gate } 4257c478bd9Sstevel@tonic-gate 4267c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<<<<<<<<<<<<< Bit Bang Operations >>>>>>>>>>>>>>>>>>>>>>>> */ 4277c478bd9Sstevel@tonic-gate 4287c478bd9Sstevel@tonic-gate static void 42906673d9bSGarrett D'Amore send_bit(struct hme *hmep, uint16_t x) 4307c478bd9Sstevel@tonic-gate { 4317c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbdata, x); 4327c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbclk, HME_BBCLK_LOW); 4337c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbclk, HME_BBCLK_HIGH); 4347c478bd9Sstevel@tonic-gate } 4357c478bd9Sstevel@tonic-gate 4367c478bd9Sstevel@tonic-gate 4377c478bd9Sstevel@tonic-gate /* 4387c478bd9Sstevel@tonic-gate * To read the MII register bits according to the IEEE Standard 4397c478bd9Sstevel@tonic-gate */ 44006673d9bSGarrett D'Amore static uint16_t 44106673d9bSGarrett D'Amore get_bit_std(uint8_t phyad, struct hme *hmep) 4427c478bd9Sstevel@tonic-gate { 44306673d9bSGarrett D'Amore uint16_t x; 4447c478bd9Sstevel@tonic-gate 4457c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbclk, HME_BBCLK_LOW); 4467c478bd9Sstevel@tonic-gate drv_usecwait(1); /* wait for >330 ns for stable data */ 44706673d9bSGarrett D'Amore if (phyad == HME_INTERNAL_PHYAD) 4487c478bd9Sstevel@tonic-gate x = (GET_MIFREG(mif_cfg) & HME_MIF_CFGM0) ? 1 : 0; 4497c478bd9Sstevel@tonic-gate else 4507c478bd9Sstevel@tonic-gate x = (GET_MIFREG(mif_cfg) & HME_MIF_CFGM1) ? 1 : 0; 4517c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbclk, HME_BBCLK_HIGH); 4527c478bd9Sstevel@tonic-gate return (x); 4537c478bd9Sstevel@tonic-gate } 4547c478bd9Sstevel@tonic-gate 4557c478bd9Sstevel@tonic-gate #define SEND_BIT(x) send_bit(hmep, x) 45606673d9bSGarrett D'Amore #define GET_BIT_STD(phyad, x) x = get_bit_std(phyad, hmep) 4577c478bd9Sstevel@tonic-gate 4587c478bd9Sstevel@tonic-gate 4597c478bd9Sstevel@tonic-gate static void 46006673d9bSGarrett D'Amore hme_bb_mii_write(struct hme *hmep, uint8_t phyad, uint8_t regad, uint16_t data) 4617c478bd9Sstevel@tonic-gate { 4627c478bd9Sstevel@tonic-gate int i; 4637c478bd9Sstevel@tonic-gate 4647c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbopenb, 1); /* Enable the MII driver */ 4657c478bd9Sstevel@tonic-gate (void) hme_bb_force_idle(hmep); 4667c478bd9Sstevel@tonic-gate SEND_BIT(0); SEND_BIT(1); /* <ST> */ 4677c478bd9Sstevel@tonic-gate SEND_BIT(0); SEND_BIT(1); /* <OP> */ 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate for (i = 4; i >= 0; i--) { /* <AAAAA> */ 4707c478bd9Sstevel@tonic-gate SEND_BIT((phyad >> i) & 1); 4717c478bd9Sstevel@tonic-gate } 4727c478bd9Sstevel@tonic-gate 4737c478bd9Sstevel@tonic-gate for (i = 4; i >= 0; i--) { /* <RRRRR> */ 4747c478bd9Sstevel@tonic-gate SEND_BIT((regad >> i) & 1); 4757c478bd9Sstevel@tonic-gate } 4767c478bd9Sstevel@tonic-gate 4777c478bd9Sstevel@tonic-gate SEND_BIT(1); SEND_BIT(0); /* <TA> */ 4787c478bd9Sstevel@tonic-gate 4797c478bd9Sstevel@tonic-gate for (i = 0xf; i >= 0; i--) { /* <DDDDDDDDDDDDDDDD> */ 4807c478bd9Sstevel@tonic-gate SEND_BIT((data >> i) & 1); 4817c478bd9Sstevel@tonic-gate } 4827c478bd9Sstevel@tonic-gate 4837c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbopenb, 0); /* Disable the MII driver */ 4847c478bd9Sstevel@tonic-gate CHECK_MIFREG(); 4857c478bd9Sstevel@tonic-gate } 4867c478bd9Sstevel@tonic-gate 4877c478bd9Sstevel@tonic-gate /* Return 0 if OK, 1 if error (Transceiver does not talk management) */ 48806673d9bSGarrett D'Amore static uint16_t 48906673d9bSGarrett D'Amore hme_bb_mii_read(struct hme *hmep, uint8_t phyad, uint8_t regad) 4907c478bd9Sstevel@tonic-gate { 4917c478bd9Sstevel@tonic-gate int i; 4927c478bd9Sstevel@tonic-gate uint32_t x; 49306673d9bSGarrett D'Amore uint16_t data = 0; 4947c478bd9Sstevel@tonic-gate 4957c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbopenb, 1); /* Enable the MII driver */ 4967c478bd9Sstevel@tonic-gate (void) hme_bb_force_idle(hmep); 4977c478bd9Sstevel@tonic-gate SEND_BIT(0); SEND_BIT(1); /* <ST> */ 4987c478bd9Sstevel@tonic-gate SEND_BIT(1); SEND_BIT(0); /* <OP> */ 4997c478bd9Sstevel@tonic-gate for (i = 4; i >= 0; i--) { /* <AAAAA> */ 5007c478bd9Sstevel@tonic-gate SEND_BIT((phyad >> i) & 1); 5017c478bd9Sstevel@tonic-gate } 5027c478bd9Sstevel@tonic-gate for (i = 4; i >= 0; i--) { /* <RRRRR> */ 5037c478bd9Sstevel@tonic-gate SEND_BIT((regad >> i) & 1); 5047c478bd9Sstevel@tonic-gate } 5057c478bd9Sstevel@tonic-gate 5067c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbopenb, 0); /* Disable the MII driver */ 5077c478bd9Sstevel@tonic-gate 50806673d9bSGarrett D'Amore GET_BIT_STD(phyad, x); 50906673d9bSGarrett D'Amore GET_BIT_STD(phyad, x); /* <TA> */ 51006673d9bSGarrett D'Amore for (i = 0xf; i >= 0; i--) { /* <DDDDDDDDDDDDDDDD> */ 51106673d9bSGarrett D'Amore GET_BIT_STD(phyad, x); 51206673d9bSGarrett D'Amore data += (x << i); 5137c478bd9Sstevel@tonic-gate } 51406673d9bSGarrett D'Amore /* 51506673d9bSGarrett D'Amore * Kludge to get the Transceiver out of hung mode 51606673d9bSGarrett D'Amore */ 51706673d9bSGarrett D'Amore GET_BIT_STD(phyad, x); 51806673d9bSGarrett D'Amore GET_BIT_STD(phyad, x); 51906673d9bSGarrett D'Amore GET_BIT_STD(phyad, x); 5207c478bd9Sstevel@tonic-gate CHECK_MIFREG(); 52106673d9bSGarrett D'Amore return (data); 5227c478bd9Sstevel@tonic-gate } 5237c478bd9Sstevel@tonic-gate 5247c478bd9Sstevel@tonic-gate 5257c478bd9Sstevel@tonic-gate static void 5267c478bd9Sstevel@tonic-gate hme_bb_force_idle(struct hme *hmep) 5277c478bd9Sstevel@tonic-gate { 5287c478bd9Sstevel@tonic-gate int i; 5297c478bd9Sstevel@tonic-gate 5307c478bd9Sstevel@tonic-gate for (i = 0; i < 33; i++) { 5317c478bd9Sstevel@tonic-gate SEND_BIT(1); 5327c478bd9Sstevel@tonic-gate } 5337c478bd9Sstevel@tonic-gate } 5347c478bd9Sstevel@tonic-gate 5357c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<<<<<<<<<End of Bit Bang Operations >>>>>>>>>>>>>>>>>>>>>>>> */ 5367c478bd9Sstevel@tonic-gate 5377c478bd9Sstevel@tonic-gate 5387c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<< Frame Register used for MII operations >>>>>>>>>>>>>>>>>>>> */ 5397c478bd9Sstevel@tonic-gate 5407c478bd9Sstevel@tonic-gate /* Return 0 if OK, 1 if error (Transceiver does not talk management) */ 54106673d9bSGarrett D'Amore static uint16_t 54206673d9bSGarrett D'Amore hme_mii_read(void *arg, uint8_t phyad, uint8_t regad) 5437c478bd9Sstevel@tonic-gate { 54406673d9bSGarrett D'Amore struct hme *hmep = arg; 5457c478bd9Sstevel@tonic-gate uint32_t frame; 546e8717ca2SGarrett D'Amore uint32_t tmp_mif; 547e8717ca2SGarrett D'Amore uint32_t tmp_xif; 5487c478bd9Sstevel@tonic-gate 549e8717ca2SGarrett D'Amore tmp_mif = GET_MIFREG(mif_cfg); 550e8717ca2SGarrett D'Amore tmp_xif = GET_MACREG(xifc); 551e8717ca2SGarrett D'Amore 552e8717ca2SGarrett D'Amore switch (phyad) { 553e8717ca2SGarrett D'Amore case HME_EXTERNAL_PHYAD: 554e8717ca2SGarrett D'Amore PUT_MIFREG(mif_cfg, tmp_mif | HME_MIF_CFGPS); 555e8717ca2SGarrett D'Amore PUT_MACREG(xifc, tmp_xif | BMAC_XIFC_MIIBUFDIS); 556e8717ca2SGarrett D'Amore break; 557e8717ca2SGarrett D'Amore case HME_INTERNAL_PHYAD: 558e8717ca2SGarrett D'Amore PUT_MIFREG(mif_cfg, tmp_mif & ~(HME_MIF_CFGPS)); 559e8717ca2SGarrett D'Amore PUT_MACREG(xifc, tmp_xif & ~(BMAC_XIFC_MIIBUFDIS)); 560e8717ca2SGarrett D'Amore break; 561e8717ca2SGarrett D'Amore default: 562e8717ca2SGarrett D'Amore return (0xffff); 563e8717ca2SGarrett D'Amore } 564e8717ca2SGarrett D'Amore 565e8717ca2SGarrett D'Amore if (!hmep->hme_frame_enable) { 566e8717ca2SGarrett D'Amore frame = (hme_bb_mii_read(hmep, phyad, regad)); 567e8717ca2SGarrett D'Amore PUT_MACREG(xifc, tmp_xif); 568e8717ca2SGarrett D'Amore PUT_MIFREG(mif_cfg, tmp_mif); 569e8717ca2SGarrett D'Amore return (frame & 0xffff); 570e8717ca2SGarrett D'Amore } 5717c478bd9Sstevel@tonic-gate 5720219346bSGarrett D'Amore PUT_MIFREG(mif_frame, 5730219346bSGarrett D'Amore HME_MIF_FRREAD | (phyad << HME_MIF_FRPHYAD_SHIFT) | 5740219346bSGarrett D'Amore (regad << HME_MIF_FRREGAD_SHIFT)); 5757c478bd9Sstevel@tonic-gate /* 5767c478bd9Sstevel@tonic-gate * HMEDELAY((*framerp & HME_MIF_FRTA0), HMEMAXRSTDELAY); 5777c478bd9Sstevel@tonic-gate */ 5780219346bSGarrett D'Amore HMEDELAY((GET_MIFREG(mif_frame) & HME_MIF_FRTA0), 300); 5790219346bSGarrett D'Amore frame = GET_MIFREG(mif_frame); 5807c478bd9Sstevel@tonic-gate CHECK_MIFREG(); 581e8717ca2SGarrett D'Amore 582e8717ca2SGarrett D'Amore PUT_MACREG(xifc, tmp_xif); 583e8717ca2SGarrett D'Amore PUT_MIFREG(mif_cfg, tmp_mif); 584e8717ca2SGarrett D'Amore 5857c478bd9Sstevel@tonic-gate if ((frame & HME_MIF_FRTA0) == 0) { 5867c478bd9Sstevel@tonic-gate 5877c478bd9Sstevel@tonic-gate 58806673d9bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, MII_MSG, 5890219346bSGarrett D'Amore "MIF Read failure"); 59006673d9bSGarrett D'Amore return (0xffff); 5917c478bd9Sstevel@tonic-gate } 59206673d9bSGarrett D'Amore return ((uint16_t)(frame & HME_MIF_FRDATA)); 5937c478bd9Sstevel@tonic-gate } 5947c478bd9Sstevel@tonic-gate 5957c478bd9Sstevel@tonic-gate static void 59606673d9bSGarrett D'Amore hme_mii_write(void *arg, uint8_t phyad, uint8_t regad, uint16_t data) 5977c478bd9Sstevel@tonic-gate { 59806673d9bSGarrett D'Amore struct hme *hmep = arg; 5997c478bd9Sstevel@tonic-gate uint32_t frame; 600e8717ca2SGarrett D'Amore uint32_t tmp_mif; 601e8717ca2SGarrett D'Amore uint32_t tmp_xif; 602e8717ca2SGarrett D'Amore 603e8717ca2SGarrett D'Amore tmp_mif = GET_MIFREG(mif_cfg); 604e8717ca2SGarrett D'Amore tmp_xif = GET_MACREG(xifc); 605e8717ca2SGarrett D'Amore 606e8717ca2SGarrett D'Amore switch (phyad) { 607e8717ca2SGarrett D'Amore case HME_EXTERNAL_PHYAD: 608e8717ca2SGarrett D'Amore PUT_MIFREG(mif_cfg, tmp_mif | HME_MIF_CFGPS); 609e8717ca2SGarrett D'Amore PUT_MACREG(xifc, tmp_xif | BMAC_XIFC_MIIBUFDIS); 610e8717ca2SGarrett D'Amore break; 611e8717ca2SGarrett D'Amore case HME_INTERNAL_PHYAD: 612e8717ca2SGarrett D'Amore PUT_MIFREG(mif_cfg, tmp_mif & ~(HME_MIF_CFGPS)); 613e8717ca2SGarrett D'Amore PUT_MACREG(xifc, tmp_xif & ~(BMAC_XIFC_MIIBUFDIS)); 614e8717ca2SGarrett D'Amore break; 615e8717ca2SGarrett D'Amore default: 616e8717ca2SGarrett D'Amore return; 617e8717ca2SGarrett D'Amore } 6187c478bd9Sstevel@tonic-gate 6197c478bd9Sstevel@tonic-gate if (!hmep->hme_frame_enable) { 62006673d9bSGarrett D'Amore hme_bb_mii_write(hmep, phyad, regad, data); 621e8717ca2SGarrett D'Amore PUT_MACREG(xifc, tmp_xif); 622e8717ca2SGarrett D'Amore PUT_MIFREG(mif_cfg, tmp_mif); 6237c478bd9Sstevel@tonic-gate return; 6247c478bd9Sstevel@tonic-gate } 6257c478bd9Sstevel@tonic-gate 6260219346bSGarrett D'Amore PUT_MIFREG(mif_frame, 6270219346bSGarrett D'Amore HME_MIF_FRWRITE | (phyad << HME_MIF_FRPHYAD_SHIFT) | 6280219346bSGarrett D'Amore (regad << HME_MIF_FRREGAD_SHIFT) | data); 6297c478bd9Sstevel@tonic-gate /* 6307c478bd9Sstevel@tonic-gate * HMEDELAY((*framerp & HME_MIF_FRTA0), HMEMAXRSTDELAY); 6317c478bd9Sstevel@tonic-gate */ 6320219346bSGarrett D'Amore HMEDELAY((GET_MIFREG(mif_frame) & HME_MIF_FRTA0), 300); 6330219346bSGarrett D'Amore frame = GET_MIFREG(mif_frame); 634e8717ca2SGarrett D'Amore PUT_MACREG(xifc, tmp_xif); 635e8717ca2SGarrett D'Amore PUT_MIFREG(mif_cfg, tmp_mif); 6367c478bd9Sstevel@tonic-gate CHECK_MIFREG(); 6377c478bd9Sstevel@tonic-gate if ((frame & HME_MIF_FRTA0) == 0) { 63806673d9bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_MID, MII_MSG, 6390219346bSGarrett D'Amore "MIF Write failure"); 6407c478bd9Sstevel@tonic-gate } 6417c478bd9Sstevel@tonic-gate } 6427c478bd9Sstevel@tonic-gate 6437c478bd9Sstevel@tonic-gate static void 64406673d9bSGarrett D'Amore hme_mii_notify(void *arg, link_state_t link) 6457c478bd9Sstevel@tonic-gate { 6467c478bd9Sstevel@tonic-gate struct hme *hmep = arg; 6477c478bd9Sstevel@tonic-gate 64806673d9bSGarrett D'Amore if (link == LINK_STATE_UP) { 64906673d9bSGarrett D'Amore (void) hmeinit(hmep); 6507c478bd9Sstevel@tonic-gate } 65106673d9bSGarrett D'Amore mac_link_update(hmep->hme_mh, link); 6527c478bd9Sstevel@tonic-gate } 6537c478bd9Sstevel@tonic-gate 6547c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<<<<<<<<<<<<<<<< LOADABLE ENTRIES >>>>>>>>>>>>>>>>>>>>>>> */ 6557c478bd9Sstevel@tonic-gate 6567c478bd9Sstevel@tonic-gate int 6577c478bd9Sstevel@tonic-gate _init(void) 6587c478bd9Sstevel@tonic-gate { 6597c478bd9Sstevel@tonic-gate int status; 6607c478bd9Sstevel@tonic-gate 66185025c03Sgd mac_init_ops(&hme_dev_ops, "hme"); 66285025c03Sgd if ((status = mod_install(&modlinkage)) != 0) { 66385025c03Sgd mac_fini_ops(&hme_dev_ops); 6647c478bd9Sstevel@tonic-gate } 6657c478bd9Sstevel@tonic-gate return (status); 6667c478bd9Sstevel@tonic-gate } 6677c478bd9Sstevel@tonic-gate 6687c478bd9Sstevel@tonic-gate int 6697c478bd9Sstevel@tonic-gate _fini(void) 6707c478bd9Sstevel@tonic-gate { 6717c478bd9Sstevel@tonic-gate int status; 6727c478bd9Sstevel@tonic-gate 67385025c03Sgd if ((status = mod_remove(&modlinkage)) == 0) { 67485025c03Sgd mac_fini_ops(&hme_dev_ops); 6757c478bd9Sstevel@tonic-gate } 6767c478bd9Sstevel@tonic-gate return (status); 6777c478bd9Sstevel@tonic-gate } 6787c478bd9Sstevel@tonic-gate 6797c478bd9Sstevel@tonic-gate int 6807c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 6817c478bd9Sstevel@tonic-gate { 6827c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 6837c478bd9Sstevel@tonic-gate } 6847c478bd9Sstevel@tonic-gate 6857c478bd9Sstevel@tonic-gate /* 6867c478bd9Sstevel@tonic-gate * ddi_dma_sync() a TMD or RMD descriptor. 6877c478bd9Sstevel@tonic-gate */ 6880219346bSGarrett D'Amore #define HMESYNCRMD(num, who) \ 6890219346bSGarrett D'Amore (void) ddi_dma_sync(hmep->hme_rmd_dmah, \ 6900219346bSGarrett D'Amore (num * sizeof (struct hme_rmd)), \ 6910219346bSGarrett D'Amore sizeof (struct hme_rmd), \ 6920219346bSGarrett D'Amore who) 6930219346bSGarrett D'Amore 6940219346bSGarrett D'Amore #define HMESYNCTMD(num, who) \ 6950219346bSGarrett D'Amore (void) ddi_dma_sync(hmep->hme_tmd_dmah, \ 6960219346bSGarrett D'Amore (num * sizeof (struct hme_tmd)), \ 6970219346bSGarrett D'Amore sizeof (struct hme_tmd), \ 6980219346bSGarrett D'Amore who) 6997c478bd9Sstevel@tonic-gate 7007c478bd9Sstevel@tonic-gate /* 7017c478bd9Sstevel@tonic-gate * Ethernet broadcast address definition. 7027c478bd9Sstevel@tonic-gate */ 7037c478bd9Sstevel@tonic-gate static struct ether_addr etherbroadcastaddr = { 7047c478bd9Sstevel@tonic-gate 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 7057c478bd9Sstevel@tonic-gate }; 7067c478bd9Sstevel@tonic-gate 7077c478bd9Sstevel@tonic-gate /* 7087c478bd9Sstevel@tonic-gate * MIB II broadcast/multicast packets 7097c478bd9Sstevel@tonic-gate */ 71085025c03Sgd #define IS_BROADCAST(pkt) (bcmp(pkt, ðerbroadcastaddr, ETHERADDRL) == 0) 71185025c03Sgd #define IS_MULTICAST(pkt) ((pkt[0] & 01) == 1) 71285025c03Sgd #define BUMP_InNUcast(hmep, pkt) \ 7130219346bSGarrett D'Amore if (IS_MULTICAST(pkt)) { \ 7140219346bSGarrett D'Amore if (IS_BROADCAST(pkt)) { \ 7150219346bSGarrett D'Amore hmep->hme_brdcstrcv++; \ 7160219346bSGarrett D'Amore } else { \ 7170219346bSGarrett D'Amore hmep->hme_multircv++; \ 7180219346bSGarrett D'Amore } \ 7190219346bSGarrett D'Amore } 72085025c03Sgd #define BUMP_OutNUcast(hmep, pkt) \ 7210219346bSGarrett D'Amore if (IS_MULTICAST(pkt)) { \ 7220219346bSGarrett D'Amore if (IS_BROADCAST(pkt)) { \ 7230219346bSGarrett D'Amore hmep->hme_brdcstxmt++; \ 7240219346bSGarrett D'Amore } else { \ 7250219346bSGarrett D'Amore hmep->hme_multixmt++; \ 7260219346bSGarrett D'Amore } \ 7270219346bSGarrett D'Amore } 7287c478bd9Sstevel@tonic-gate 7297c478bd9Sstevel@tonic-gate static int 7307c478bd9Sstevel@tonic-gate hme_create_prop_from_kw(dev_info_t *dip, char *vpdname, char *vpdstr) 7317c478bd9Sstevel@tonic-gate { 7327c478bd9Sstevel@tonic-gate char propstr[80]; 7337c478bd9Sstevel@tonic-gate int i, needprop = 0; 7347c478bd9Sstevel@tonic-gate struct ether_addr local_mac; 7357c478bd9Sstevel@tonic-gate 7367c478bd9Sstevel@tonic-gate if (strcmp(vpdname, "NA") == 0) { 7377c478bd9Sstevel@tonic-gate (void) strcpy(propstr, "local-mac-address"); 7387c478bd9Sstevel@tonic-gate needprop = 1; 7397c478bd9Sstevel@tonic-gate } else if (strcmp(vpdname, "Z0") == 0) { 7407c478bd9Sstevel@tonic-gate (void) strcpy(propstr, "model"); 7417c478bd9Sstevel@tonic-gate needprop = 1; 7427c478bd9Sstevel@tonic-gate } else if (strcmp(vpdname, "Z1") == 0) { 7437c478bd9Sstevel@tonic-gate (void) strcpy(propstr, "board-model"); 7447c478bd9Sstevel@tonic-gate needprop = 1; 7457c478bd9Sstevel@tonic-gate } 7467c478bd9Sstevel@tonic-gate 7477c478bd9Sstevel@tonic-gate if (needprop == 1) { 7480219346bSGarrett D'Amore 7497c478bd9Sstevel@tonic-gate if (strcmp(propstr, "local-mac-address") == 0) { 7507c478bd9Sstevel@tonic-gate for (i = 0; i < ETHERADDRL; i++) 7517c478bd9Sstevel@tonic-gate local_mac.ether_addr_octet[i] = 75285025c03Sgd (uchar_t)vpdstr[i]; 7537c478bd9Sstevel@tonic-gate if (ddi_prop_create(DDI_DEV_T_NONE, dip, 75485025c03Sgd DDI_PROP_CANSLEEP, propstr, 75585025c03Sgd (char *)local_mac.ether_addr_octet, ETHERADDRL) 75685025c03Sgd != DDI_SUCCESS) { 7577c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7587c478bd9Sstevel@tonic-gate } 7597c478bd9Sstevel@tonic-gate } else { 7607c478bd9Sstevel@tonic-gate if (ddi_prop_create(DDI_DEV_T_NONE, dip, 76185025c03Sgd DDI_PROP_CANSLEEP, propstr, vpdstr, 76285025c03Sgd strlen(vpdstr)+1) != DDI_SUCCESS) { 7637c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7647c478bd9Sstevel@tonic-gate } 7657c478bd9Sstevel@tonic-gate } 7667c478bd9Sstevel@tonic-gate } 7677c478bd9Sstevel@tonic-gate return (0); 7687c478bd9Sstevel@tonic-gate } 7697c478bd9Sstevel@tonic-gate 7707c478bd9Sstevel@tonic-gate /* 7717c478bd9Sstevel@tonic-gate * Get properties from old VPD 7727c478bd9Sstevel@tonic-gate * for PCI cards 7737c478bd9Sstevel@tonic-gate */ 7747c478bd9Sstevel@tonic-gate static int 7757c478bd9Sstevel@tonic-gate hme_get_oldvpd_props(dev_info_t *dip, int vpd_base) 7767c478bd9Sstevel@tonic-gate { 7777c478bd9Sstevel@tonic-gate struct hme *hmep; 7787c478bd9Sstevel@tonic-gate int vpd_start, vpd_len, kw_start, kw_len, kw_ptr; 7797c478bd9Sstevel@tonic-gate char kw_namestr[3]; 7807c478bd9Sstevel@tonic-gate char kw_fieldstr[256]; 7817c478bd9Sstevel@tonic-gate int i; 7827c478bd9Sstevel@tonic-gate 7837c478bd9Sstevel@tonic-gate hmep = ddi_get_driver_private(dip); 7847c478bd9Sstevel@tonic-gate 7857c478bd9Sstevel@tonic-gate vpd_start = vpd_base; 7867c478bd9Sstevel@tonic-gate 7877c478bd9Sstevel@tonic-gate if ((GET_ROM8(&hmep->hme_romp[vpd_start]) & 0xff) != 0x90) { 7887c478bd9Sstevel@tonic-gate return (1); /* error */ 7897c478bd9Sstevel@tonic-gate } else { 7907c478bd9Sstevel@tonic-gate vpd_len = 9; 7917c478bd9Sstevel@tonic-gate } 7927c478bd9Sstevel@tonic-gate 7937c478bd9Sstevel@tonic-gate /* Get local-mac-address */ 7947c478bd9Sstevel@tonic-gate kw_start = vpd_start + 3; /* Location of 1st keyword */ 7957c478bd9Sstevel@tonic-gate kw_ptr = kw_start; 7967c478bd9Sstevel@tonic-gate while ((kw_ptr - kw_start) < vpd_len) { /* Get all keywords */ 7977c478bd9Sstevel@tonic-gate kw_namestr[0] = GET_ROM8(&hmep->hme_romp[kw_ptr]); 7987c478bd9Sstevel@tonic-gate kw_namestr[1] = GET_ROM8(&hmep->hme_romp[kw_ptr+1]); 7997c478bd9Sstevel@tonic-gate kw_namestr[2] = '\0'; 8007c478bd9Sstevel@tonic-gate kw_len = (int)(GET_ROM8(&hmep->hme_romp[kw_ptr+2]) & 0xff); 8017c478bd9Sstevel@tonic-gate for (i = 0, kw_ptr += 3; i < kw_len; i++) 8027c478bd9Sstevel@tonic-gate kw_fieldstr[i] = GET_ROM8(&hmep->hme_romp[kw_ptr+i]); 8037c478bd9Sstevel@tonic-gate kw_fieldstr[i] = '\0'; 8047c478bd9Sstevel@tonic-gate if (hme_create_prop_from_kw(dip, kw_namestr, kw_fieldstr)) { 8057c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 8067c478bd9Sstevel@tonic-gate } 8077c478bd9Sstevel@tonic-gate kw_ptr += kw_len; 8087c478bd9Sstevel@tonic-gate } /* next keyword */ 8097c478bd9Sstevel@tonic-gate 81085025c03Sgd if (ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, "model", 81185025c03Sgd "SUNW,cheerio", strlen("SUNW,cheerio")+1) != DDI_SUCCESS) { 8127c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 8137c478bd9Sstevel@tonic-gate } 8147c478bd9Sstevel@tonic-gate return (0); 8157c478bd9Sstevel@tonic-gate } 8167c478bd9Sstevel@tonic-gate 8177c478bd9Sstevel@tonic-gate 8187c478bd9Sstevel@tonic-gate /* 8197c478bd9Sstevel@tonic-gate * Get properties from new VPD 8207c478bd9Sstevel@tonic-gate * for CompactPCI cards 8217c478bd9Sstevel@tonic-gate */ 8227c478bd9Sstevel@tonic-gate static int 8237c478bd9Sstevel@tonic-gate hme_get_newvpd_props(dev_info_t *dip, int vpd_base) 8247c478bd9Sstevel@tonic-gate { 8257c478bd9Sstevel@tonic-gate struct hme *hmep; 8267c478bd9Sstevel@tonic-gate int vpd_start, vpd_len, kw_start, kw_len, kw_ptr; 8277c478bd9Sstevel@tonic-gate char kw_namestr[3]; 8287c478bd9Sstevel@tonic-gate char kw_fieldstr[256]; 8297c478bd9Sstevel@tonic-gate int maxvpdsize, i; 8307c478bd9Sstevel@tonic-gate 8317c478bd9Sstevel@tonic-gate hmep = ddi_get_driver_private(dip); 8327c478bd9Sstevel@tonic-gate 8337c478bd9Sstevel@tonic-gate maxvpdsize = 1024; /* Real size not known until after it is read */ 8347c478bd9Sstevel@tonic-gate 8357c478bd9Sstevel@tonic-gate vpd_start = (int)((GET_ROM8(&(hmep->hme_romp[vpd_base+1])) & 0xff) | 83685025c03Sgd ((GET_ROM8(&hmep->hme_romp[vpd_base+2]) & 0xff) << 8)) +3; 8377c478bd9Sstevel@tonic-gate vpd_start = vpd_base + vpd_start; 8387c478bd9Sstevel@tonic-gate while (vpd_start < (vpd_base + maxvpdsize)) { /* Get all VPDs */ 8397c478bd9Sstevel@tonic-gate if ((GET_ROM8(&hmep->hme_romp[vpd_start]) & 0xff) != 0x90) { 8407c478bd9Sstevel@tonic-gate break; /* no VPD found */ 8417c478bd9Sstevel@tonic-gate } else { 8427c478bd9Sstevel@tonic-gate vpd_len = (int)((GET_ROM8(&hmep->hme_romp[vpd_start 84385025c03Sgd + 1]) & 0xff) | (GET_ROM8(&hmep->hme_romp[vpd_start 84485025c03Sgd + 2]) & 0xff) << 8); 8457c478bd9Sstevel@tonic-gate } 8467c478bd9Sstevel@tonic-gate /* Get all keywords in this VPD */ 8477c478bd9Sstevel@tonic-gate kw_start = vpd_start + 3; /* Location of 1st keyword */ 8487c478bd9Sstevel@tonic-gate kw_ptr = kw_start; 8497c478bd9Sstevel@tonic-gate while ((kw_ptr - kw_start) < vpd_len) { /* Get all keywords */ 8507c478bd9Sstevel@tonic-gate kw_namestr[0] = GET_ROM8(&hmep->hme_romp[kw_ptr]); 8517c478bd9Sstevel@tonic-gate kw_namestr[1] = GET_ROM8(&hmep->hme_romp[kw_ptr+1]); 8527c478bd9Sstevel@tonic-gate kw_namestr[2] = '\0'; 85385025c03Sgd kw_len = 85485025c03Sgd (int)(GET_ROM8(&hmep->hme_romp[kw_ptr+2]) & 0xff); 8557c478bd9Sstevel@tonic-gate for (i = 0, kw_ptr += 3; i < kw_len; i++) 85685025c03Sgd kw_fieldstr[i] = 85785025c03Sgd GET_ROM8(&hmep->hme_romp[kw_ptr+i]); 8587c478bd9Sstevel@tonic-gate kw_fieldstr[i] = '\0'; 8597c478bd9Sstevel@tonic-gate if (hme_create_prop_from_kw(dip, kw_namestr, 86085025c03Sgd kw_fieldstr)) { 8617c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 8627c478bd9Sstevel@tonic-gate } 8637c478bd9Sstevel@tonic-gate kw_ptr += kw_len; 8647c478bd9Sstevel@tonic-gate } /* next keyword */ 8657c478bd9Sstevel@tonic-gate vpd_start += (vpd_len + 3); 8667c478bd9Sstevel@tonic-gate } /* next VPD */ 8677c478bd9Sstevel@tonic-gate return (0); 8687c478bd9Sstevel@tonic-gate } 8697c478bd9Sstevel@tonic-gate 8707c478bd9Sstevel@tonic-gate 8717c478bd9Sstevel@tonic-gate /* 8727c478bd9Sstevel@tonic-gate * Get properties from VPD 8737c478bd9Sstevel@tonic-gate */ 8747c478bd9Sstevel@tonic-gate static int 8757c478bd9Sstevel@tonic-gate hme_get_vpd_props(dev_info_t *dip) 8767c478bd9Sstevel@tonic-gate { 8777c478bd9Sstevel@tonic-gate struct hme *hmep; 8787c478bd9Sstevel@tonic-gate int v0, v1, vpd_base; 8797c478bd9Sstevel@tonic-gate int i, epromsrchlimit; 8807c478bd9Sstevel@tonic-gate 8817c478bd9Sstevel@tonic-gate 8827c478bd9Sstevel@tonic-gate hmep = ddi_get_driver_private(dip); 8837c478bd9Sstevel@tonic-gate 8847c478bd9Sstevel@tonic-gate v0 = (int)(GET_ROM8(&(hmep->hme_romp[0]))); 8857c478bd9Sstevel@tonic-gate v1 = (int)(GET_ROM8(&(hmep->hme_romp[1]))); 8867c478bd9Sstevel@tonic-gate v0 = ((v0 & 0xff) << 8 | v1); 8877c478bd9Sstevel@tonic-gate 8887c478bd9Sstevel@tonic-gate if ((v0 & 0xffff) != 0x55aa) { 8897c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, " Valid pci prom not found \n"); 8907c478bd9Sstevel@tonic-gate return (1); 8917c478bd9Sstevel@tonic-gate } 8927c478bd9Sstevel@tonic-gate 8937c478bd9Sstevel@tonic-gate epromsrchlimit = 4096; 8947c478bd9Sstevel@tonic-gate for (i = 2; i < epromsrchlimit; i++) { 89585025c03Sgd /* "PCIR" */ 89685025c03Sgd if (((GET_ROM8(&(hmep->hme_romp[i])) & 0xff) == 'P') && 89785025c03Sgd ((GET_ROM8(&(hmep->hme_romp[i+1])) & 0xff) == 'C') && 89885025c03Sgd ((GET_ROM8(&(hmep->hme_romp[i+2])) & 0xff) == 'I') && 89985025c03Sgd ((GET_ROM8(&(hmep->hme_romp[i+3])) & 0xff) == 'R')) { 90085025c03Sgd vpd_base = 90185025c03Sgd (int)((GET_ROM8(&(hmep->hme_romp[i+8])) & 0xff) | 90285025c03Sgd (GET_ROM8(&(hmep->hme_romp[i+9])) & 0xff) << 8); 9037c478bd9Sstevel@tonic-gate break; /* VPD pointer found */ 9047c478bd9Sstevel@tonic-gate } 9057c478bd9Sstevel@tonic-gate } 9067c478bd9Sstevel@tonic-gate 9077c478bd9Sstevel@tonic-gate /* No VPD found */ 9087c478bd9Sstevel@tonic-gate if (vpd_base == 0) { 9097c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, " Vital Product Data pointer not found \n"); 9107c478bd9Sstevel@tonic-gate return (1); 9117c478bd9Sstevel@tonic-gate } 9127c478bd9Sstevel@tonic-gate 9137c478bd9Sstevel@tonic-gate v0 = (int)(GET_ROM8(&(hmep->hme_romp[vpd_base]))); 9147c478bd9Sstevel@tonic-gate if (v0 == 0x82) { 9157c478bd9Sstevel@tonic-gate if (hme_get_newvpd_props(dip, vpd_base)) 9167c478bd9Sstevel@tonic-gate return (1); 9177c478bd9Sstevel@tonic-gate return (0); 9187c478bd9Sstevel@tonic-gate } else if (v0 == 0x90) { 9190219346bSGarrett D'Amore /* If we are are SUNW,qfe card, look for the Nth "NA" descr */ 9200219346bSGarrett D'Amore if ((GET_ROM8(&hmep->hme_romp[vpd_base + 12]) != 0x79) && 9210219346bSGarrett D'Amore GET_ROM8(&hmep->hme_romp[vpd_base + 4 * 12]) == 0x79) { 9220219346bSGarrett D'Amore vpd_base += hmep->hme_devno * 12; 9230219346bSGarrett D'Amore } 9247c478bd9Sstevel@tonic-gate if (hme_get_oldvpd_props(dip, vpd_base)) 9257c478bd9Sstevel@tonic-gate return (1); 9267c478bd9Sstevel@tonic-gate return (0); 9277c478bd9Sstevel@tonic-gate } else 9287c478bd9Sstevel@tonic-gate return (1); /* unknown start byte in VPD */ 9297c478bd9Sstevel@tonic-gate } 9307c478bd9Sstevel@tonic-gate 9310219346bSGarrett D'Amore /* 9320219346bSGarrett D'Amore * For x86, the BIOS doesn't map the PCI Rom register for the qfe 9330219346bSGarrett D'Amore * cards, so we have to extract it from the ebus bridge that is 9340219346bSGarrett D'Amore * function zero of the same device. This is a bit of an ugly hack. 9350219346bSGarrett D'Amore * (The ebus bridge leaves the entire ROM mapped at base address 9360219346bSGarrett D'Amore * register 0x10.) 9370219346bSGarrett D'Amore */ 9380219346bSGarrett D'Amore 9390219346bSGarrett D'Amore typedef struct { 9400219346bSGarrett D'Amore struct hme *hmep; 9410219346bSGarrett D'Amore dev_info_t *parent; 9420219346bSGarrett D'Amore uint8_t bus, dev; 9430219346bSGarrett D'Amore ddi_acc_handle_t acch; 9440219346bSGarrett D'Amore caddr_t romp; 9450219346bSGarrett D'Amore } ebus_rom_t; 9460219346bSGarrett D'Amore 9470219346bSGarrett D'Amore static int 9480219346bSGarrett D'Amore hme_mapebusrom(dev_info_t *dip, void *arg) 9490219346bSGarrett D'Amore { 9500219346bSGarrett D'Amore int *regs; 9510219346bSGarrett D'Amore unsigned nregs; 9520219346bSGarrett D'Amore int reg; 9530219346bSGarrett D'Amore ebus_rom_t *rom = arg; 9540219346bSGarrett D'Amore struct hme *hmep = rom->hmep; 9550219346bSGarrett D'Amore 9560219346bSGarrett D'Amore /* 9570219346bSGarrett D'Amore * We only want to look at our peers. Skip our parent. 9580219346bSGarrett D'Amore */ 9590219346bSGarrett D'Amore if (dip == rom->parent) { 9600219346bSGarrett D'Amore return (DDI_WALK_PRUNESIB); 9610219346bSGarrett D'Amore } 9620219346bSGarrett D'Amore 96306673d9bSGarrett D'Amore if (ddi_get_parent(dip) != rom->parent) 96406673d9bSGarrett D'Amore return (DDI_WALK_CONTINUE); 96506673d9bSGarrett D'Amore 9660219346bSGarrett D'Amore if ((ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 0, 9670219346bSGarrett D'Amore "reg", ®s, &nregs)) != DDI_PROP_SUCCESS) { 9680219346bSGarrett D'Amore return (DDI_WALK_PRUNECHILD); 9690219346bSGarrett D'Amore } 9700219346bSGarrett D'Amore 9710219346bSGarrett D'Amore if (nregs < 1) { 9720219346bSGarrett D'Amore ddi_prop_free(regs); 9730219346bSGarrett D'Amore return (DDI_WALK_PRUNECHILD); 9740219346bSGarrett D'Amore } 9750219346bSGarrett D'Amore reg = regs[0]; 9760219346bSGarrett D'Amore ddi_prop_free(regs); 9770219346bSGarrett D'Amore 9780219346bSGarrett D'Amore /* 9790219346bSGarrett D'Amore * Look for function 0 on our bus and device. If the device doesn't 9800219346bSGarrett D'Amore * match, it might be an alternate peer, in which case we don't want 9810219346bSGarrett D'Amore * to examine any of its children. 9820219346bSGarrett D'Amore */ 9830219346bSGarrett D'Amore if ((PCI_REG_BUS_G(reg) != rom->bus) || 9840219346bSGarrett D'Amore (PCI_REG_DEV_G(reg) != rom->dev) || 9850219346bSGarrett D'Amore (PCI_REG_FUNC_G(reg) != 0)) { 9860219346bSGarrett D'Amore return (DDI_WALK_PRUNECHILD); 9870219346bSGarrett D'Amore } 9880219346bSGarrett D'Amore 9890219346bSGarrett D'Amore (void) ddi_regs_map_setup(dip, 1, &rom->romp, 0, 0, &hmep->hme_dev_attr, 9900219346bSGarrett D'Amore &rom->acch); 9910219346bSGarrett D'Amore /* 9920219346bSGarrett D'Amore * If we can't map the registers, the caller will notice that 9930219346bSGarrett D'Amore * the acch is NULL. 9940219346bSGarrett D'Amore */ 9950219346bSGarrett D'Amore return (DDI_WALK_TERMINATE); 9960219346bSGarrett D'Amore } 9970219346bSGarrett D'Amore 9980219346bSGarrett D'Amore static int 9990219346bSGarrett D'Amore hmeget_promebus(dev_info_t *dip) 10000219346bSGarrett D'Amore { 10010219346bSGarrett D'Amore ebus_rom_t rom; 10020219346bSGarrett D'Amore int *regs; 10030219346bSGarrett D'Amore unsigned nregs; 10040219346bSGarrett D'Amore struct hme *hmep; 10050219346bSGarrett D'Amore 10060219346bSGarrett D'Amore hmep = ddi_get_driver_private(dip); 10070219346bSGarrett D'Amore 10080219346bSGarrett D'Amore bzero(&rom, sizeof (rom)); 10090219346bSGarrett D'Amore 10100219346bSGarrett D'Amore /* 10110219346bSGarrett D'Amore * For x86, the BIOS doesn't map the PCI Rom register for the qfe 10120219346bSGarrett D'Amore * cards, so we have to extract it from the eBus bridge that is 10130219346bSGarrett D'Amore * function zero. This is a bit of an ugly hack. 10140219346bSGarrett D'Amore */ 10150219346bSGarrett D'Amore if ((ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 0, 10160219346bSGarrett D'Amore "reg", ®s, &nregs)) != DDI_PROP_SUCCESS) { 10170219346bSGarrett D'Amore return (DDI_FAILURE); 10180219346bSGarrett D'Amore } 10190219346bSGarrett D'Amore 10200219346bSGarrett D'Amore if (nregs < 5) { 10210219346bSGarrett D'Amore ddi_prop_free(regs); 10220219346bSGarrett D'Amore return (DDI_FAILURE); 10230219346bSGarrett D'Amore } 10240219346bSGarrett D'Amore rom.hmep = hmep; 10250219346bSGarrett D'Amore rom.bus = PCI_REG_BUS_G(regs[0]); 10260219346bSGarrett D'Amore rom.dev = PCI_REG_DEV_G(regs[0]); 10270219346bSGarrett D'Amore hmep->hme_devno = rom.dev; 10280219346bSGarrett D'Amore rom.parent = ddi_get_parent(dip); 10290219346bSGarrett D'Amore 10300219346bSGarrett D'Amore /* 10310219346bSGarrett D'Amore * The implementation of ddi_walk_devs says that we must not 103206673d9bSGarrett D'Amore * be called during autoconfiguration. However, it turns out 103306673d9bSGarrett D'Amore * that it is safe to call this during our attach routine, 103406673d9bSGarrett D'Amore * because we are not a nexus device. 10350219346bSGarrett D'Amore * 103606673d9bSGarrett D'Amore * Previously we rooted our search at our immediate parent, 103706673d9bSGarrett D'Amore * but this triggered an assertion panic in debug kernels. 10380219346bSGarrett D'Amore */ 103906673d9bSGarrett D'Amore ddi_walk_devs(ddi_root_node(), hme_mapebusrom, &rom); 10400219346bSGarrett D'Amore 10410219346bSGarrett D'Amore if (rom.acch) { 10420219346bSGarrett D'Amore hmep->hme_romh = rom.acch; 10430219346bSGarrett D'Amore hmep->hme_romp = (unsigned char *)rom.romp; 10440219346bSGarrett D'Amore return (DDI_SUCCESS); 10450219346bSGarrett D'Amore } 10460219346bSGarrett D'Amore return (DDI_FAILURE); 10470219346bSGarrett D'Amore } 10480219346bSGarrett D'Amore 10497c478bd9Sstevel@tonic-gate static int 10507c478bd9Sstevel@tonic-gate hmeget_promprops(dev_info_t *dip) 10517c478bd9Sstevel@tonic-gate { 10527c478bd9Sstevel@tonic-gate struct hme *hmep; 10537c478bd9Sstevel@tonic-gate int rom_bar; 10547c478bd9Sstevel@tonic-gate ddi_acc_handle_t cfg_handle; 10557c478bd9Sstevel@tonic-gate struct { 10567c478bd9Sstevel@tonic-gate uint16_t vendorid; 10577c478bd9Sstevel@tonic-gate uint16_t devid; 10587c478bd9Sstevel@tonic-gate uint16_t command; 10597c478bd9Sstevel@tonic-gate uint16_t status; 10607c478bd9Sstevel@tonic-gate uint32_t junk1; 10617c478bd9Sstevel@tonic-gate uint8_t cache_line; 10627c478bd9Sstevel@tonic-gate uint8_t latency; 10637c478bd9Sstevel@tonic-gate uint8_t header; 10647c478bd9Sstevel@tonic-gate uint8_t bist; 10657c478bd9Sstevel@tonic-gate uint32_t base; 10667c478bd9Sstevel@tonic-gate uint32_t base14; 10677c478bd9Sstevel@tonic-gate uint32_t base18; 10687c478bd9Sstevel@tonic-gate uint32_t base1c; 10697c478bd9Sstevel@tonic-gate uint32_t base20; 10707c478bd9Sstevel@tonic-gate uint32_t base24; 10717c478bd9Sstevel@tonic-gate uint32_t base28; 10727c478bd9Sstevel@tonic-gate uint32_t base2c; 10737c478bd9Sstevel@tonic-gate uint32_t base30; 10747c478bd9Sstevel@tonic-gate } *cfg_ptr; 10757c478bd9Sstevel@tonic-gate 10767c478bd9Sstevel@tonic-gate hmep = ddi_get_driver_private(dip); 10777c478bd9Sstevel@tonic-gate 10787c478bd9Sstevel@tonic-gate 10797c478bd9Sstevel@tonic-gate /* 10807c478bd9Sstevel@tonic-gate * map configuration space 10817c478bd9Sstevel@tonic-gate */ 10827c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(hmep->dip, 0, (caddr_t *)&cfg_ptr, 108385025c03Sgd 0, 0, &hmep->hme_dev_attr, &cfg_handle)) { 10847c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 10857c478bd9Sstevel@tonic-gate } 10867c478bd9Sstevel@tonic-gate 10877c478bd9Sstevel@tonic-gate /* 10887c478bd9Sstevel@tonic-gate * Enable bus-master and memory accesses 10897c478bd9Sstevel@tonic-gate */ 10907c478bd9Sstevel@tonic-gate ddi_put16(cfg_handle, &cfg_ptr->command, 109185025c03Sgd PCI_COMM_SERR_ENABLE | PCI_COMM_PARITY_DETECT | 109285025c03Sgd PCI_COMM_MAE | PCI_COMM_ME); 10937c478bd9Sstevel@tonic-gate 10947c478bd9Sstevel@tonic-gate /* 10957c478bd9Sstevel@tonic-gate * Enable rom accesses 10967c478bd9Sstevel@tonic-gate */ 10977c478bd9Sstevel@tonic-gate rom_bar = ddi_get32(cfg_handle, &cfg_ptr->base30); 10987c478bd9Sstevel@tonic-gate ddi_put32(cfg_handle, &cfg_ptr->base30, rom_bar | 1); 10997c478bd9Sstevel@tonic-gate 11007c478bd9Sstevel@tonic-gate 11010219346bSGarrett D'Amore if ((ddi_regs_map_setup(dip, 2, (caddr_t *)&(hmep->hme_romp), 0, 0, 11020219346bSGarrett D'Amore &hmep->hme_dev_attr, &hmep->hme_romh) != DDI_SUCCESS) && 11030219346bSGarrett D'Amore (hmeget_promebus(dip) != DDI_SUCCESS)) { 11040219346bSGarrett D'Amore 11057c478bd9Sstevel@tonic-gate if (cfg_ptr) 11067c478bd9Sstevel@tonic-gate ddi_regs_map_free(&cfg_handle); 11077c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 11087c478bd9Sstevel@tonic-gate } else { 11097c478bd9Sstevel@tonic-gate if (hme_get_vpd_props(dip)) 11100219346bSGarrett D'Amore return (DDI_FAILURE); 11117c478bd9Sstevel@tonic-gate } 11127c478bd9Sstevel@tonic-gate if (hmep->hme_romp) 11137c478bd9Sstevel@tonic-gate ddi_regs_map_free(&hmep->hme_romh); 11147c478bd9Sstevel@tonic-gate if (cfg_ptr) 11157c478bd9Sstevel@tonic-gate ddi_regs_map_free(&cfg_handle); 11160219346bSGarrett D'Amore return (DDI_SUCCESS); 11177c478bd9Sstevel@tonic-gate 11187c478bd9Sstevel@tonic-gate } 11197c478bd9Sstevel@tonic-gate 11207c478bd9Sstevel@tonic-gate static void 11217c478bd9Sstevel@tonic-gate hmeget_hm_rev_property(struct hme *hmep) 11227c478bd9Sstevel@tonic-gate { 11237c478bd9Sstevel@tonic-gate int hm_rev; 11247c478bd9Sstevel@tonic-gate 11257c478bd9Sstevel@tonic-gate 11267c478bd9Sstevel@tonic-gate hm_rev = hmep->asic_rev; 11277c478bd9Sstevel@tonic-gate switch (hm_rev) { 11287c478bd9Sstevel@tonic-gate case HME_2P1_REVID: 11297c478bd9Sstevel@tonic-gate case HME_2P1_REVID_OBP: 11307c478bd9Sstevel@tonic-gate HME_FAULT_MSG2(hmep, SEVERITY_NONE, DISPLAY_MSG, 113185025c03Sgd "SBus 2.1 Found (Rev Id = %x)", hm_rev); 11327c478bd9Sstevel@tonic-gate hmep->hme_frame_enable = 1; 11337c478bd9Sstevel@tonic-gate break; 11347c478bd9Sstevel@tonic-gate 11357c478bd9Sstevel@tonic-gate case HME_2P0_REVID: 11367c478bd9Sstevel@tonic-gate HME_FAULT_MSG2(hmep, SEVERITY_NONE, DISPLAY_MSG, 113785025c03Sgd "SBus 2.0 Found (Rev Id = %x)", hm_rev); 11387c478bd9Sstevel@tonic-gate break; 11397c478bd9Sstevel@tonic-gate 11407c478bd9Sstevel@tonic-gate case HME_1C0_REVID: 11417c478bd9Sstevel@tonic-gate HME_FAULT_MSG2(hmep, SEVERITY_NONE, DISPLAY_MSG, 114285025c03Sgd "PCI IO 1.0 Found (Rev Id = %x)", hm_rev); 11437c478bd9Sstevel@tonic-gate break; 11447c478bd9Sstevel@tonic-gate 11457c478bd9Sstevel@tonic-gate default: 114606673d9bSGarrett D'Amore HME_FAULT_MSG3(hmep, SEVERITY_NONE, DISPLAY_MSG, 114785025c03Sgd "%s (Rev Id = %x) Found", 114885025c03Sgd (hm_rev == HME_2C0_REVID) ? "PCI IO 2.0" : "Sbus", hm_rev); 11497c478bd9Sstevel@tonic-gate hmep->hme_frame_enable = 1; 11507c478bd9Sstevel@tonic-gate hmep->hme_lance_mode_enable = 1; 11517c478bd9Sstevel@tonic-gate hmep->hme_rxcv_enable = 1; 11527c478bd9Sstevel@tonic-gate break; 11537c478bd9Sstevel@tonic-gate } 11547c478bd9Sstevel@tonic-gate } 11557c478bd9Sstevel@tonic-gate 11567c478bd9Sstevel@tonic-gate /* 11577c478bd9Sstevel@tonic-gate * Interface exists: make available by filling in network interface 11587c478bd9Sstevel@tonic-gate * record. System will initialize the interface when it is ready 11597c478bd9Sstevel@tonic-gate * to accept packets. 11607c478bd9Sstevel@tonic-gate */ 1161f2cd0f02Sgd int 11627c478bd9Sstevel@tonic-gate hmeattach(dev_info_t *dip, ddi_attach_cmd_t cmd) 11637c478bd9Sstevel@tonic-gate { 11647c478bd9Sstevel@tonic-gate struct hme *hmep; 116585025c03Sgd mac_register_t *macp = NULL; 11667c478bd9Sstevel@tonic-gate int regno; 11677c478bd9Sstevel@tonic-gate int hm_rev = 0; 11687c478bd9Sstevel@tonic-gate int prop_len = sizeof (int); 11697c478bd9Sstevel@tonic-gate ddi_acc_handle_t cfg_handle; 11707c478bd9Sstevel@tonic-gate struct { 11717c478bd9Sstevel@tonic-gate uint16_t vendorid; 11727c478bd9Sstevel@tonic-gate uint16_t devid; 11737c478bd9Sstevel@tonic-gate uint16_t command; 11747c478bd9Sstevel@tonic-gate uint16_t status; 11757c478bd9Sstevel@tonic-gate uint8_t revid; 11767c478bd9Sstevel@tonic-gate uint8_t j1; 11777c478bd9Sstevel@tonic-gate uint16_t j2; 11787c478bd9Sstevel@tonic-gate } *cfg_ptr; 11797c478bd9Sstevel@tonic-gate 11807c478bd9Sstevel@tonic-gate switch (cmd) { 11817c478bd9Sstevel@tonic-gate case DDI_ATTACH: 11827c478bd9Sstevel@tonic-gate break; 11837c478bd9Sstevel@tonic-gate 11847c478bd9Sstevel@tonic-gate case DDI_RESUME: 11857c478bd9Sstevel@tonic-gate if ((hmep = ddi_get_driver_private(dip)) == NULL) 118685025c03Sgd return (DDI_FAILURE); 11877c478bd9Sstevel@tonic-gate 11887c478bd9Sstevel@tonic-gate hmep->hme_flags &= ~HMESUSPENDED; 118906673d9bSGarrett D'Amore 119006673d9bSGarrett D'Amore mii_resume(hmep->hme_mii); 119185025c03Sgd 1192228fdff0Sgd if (hmep->hme_started) 119385025c03Sgd (void) hmeinit(hmep); 11947c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 11957c478bd9Sstevel@tonic-gate 11967c478bd9Sstevel@tonic-gate default: 11977c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 11987c478bd9Sstevel@tonic-gate } 11997c478bd9Sstevel@tonic-gate 12007c478bd9Sstevel@tonic-gate /* 12017c478bd9Sstevel@tonic-gate * Allocate soft device data structure 12027c478bd9Sstevel@tonic-gate */ 12030219346bSGarrett D'Amore hmep = kmem_zalloc(sizeof (*hmep), KM_SLEEP); 12047c478bd9Sstevel@tonic-gate 12057c478bd9Sstevel@tonic-gate /* 12067c478bd9Sstevel@tonic-gate * Might as well set up elements of data structure 12077c478bd9Sstevel@tonic-gate */ 12087c478bd9Sstevel@tonic-gate hmep->dip = dip; 12097c478bd9Sstevel@tonic-gate hmep->instance = ddi_get_instance(dip); 12107c478bd9Sstevel@tonic-gate hmep->pagesize = ddi_ptob(dip, (ulong_t)1); /* IOMMU PSize */ 12117c478bd9Sstevel@tonic-gate 12127c478bd9Sstevel@tonic-gate /* 12137c478bd9Sstevel@tonic-gate * Might as well setup the driver private 12147c478bd9Sstevel@tonic-gate * structure as part of the dip. 12157c478bd9Sstevel@tonic-gate */ 12167c478bd9Sstevel@tonic-gate ddi_set_driver_private(dip, hmep); 12177c478bd9Sstevel@tonic-gate 12187c478bd9Sstevel@tonic-gate /* 12197c478bd9Sstevel@tonic-gate * Reject this device if it's in a slave-only slot. 12207c478bd9Sstevel@tonic-gate */ 12217c478bd9Sstevel@tonic-gate if (ddi_slaveonly(dip) == DDI_SUCCESS) { 12227c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG, 12230219346bSGarrett D'Amore "Dev not used - dev in slave only slot"); 12247c478bd9Sstevel@tonic-gate goto error_state; 12257c478bd9Sstevel@tonic-gate } 12267c478bd9Sstevel@tonic-gate 12277c478bd9Sstevel@tonic-gate /* 12287c478bd9Sstevel@tonic-gate * Map in the device registers. 12297c478bd9Sstevel@tonic-gate * 12307c478bd9Sstevel@tonic-gate * Reg # 0 is the Global register set 12317c478bd9Sstevel@tonic-gate * Reg # 1 is the ETX register set 12327c478bd9Sstevel@tonic-gate * Reg # 2 is the ERX register set 12337c478bd9Sstevel@tonic-gate * Reg # 3 is the BigMAC register set. 12347c478bd9Sstevel@tonic-gate * Reg # 4 is the MIF register set 12357c478bd9Sstevel@tonic-gate */ 12367c478bd9Sstevel@tonic-gate if (ddi_dev_nregs(dip, ®no) != (DDI_SUCCESS)) { 12377c478bd9Sstevel@tonic-gate HME_FAULT_MSG2(hmep, SEVERITY_HIGH, INIT_MSG, 123885025c03Sgd ddi_nregs_fail_msg, regno); 12397c478bd9Sstevel@tonic-gate goto error_state; 12407c478bd9Sstevel@tonic-gate } 12417c478bd9Sstevel@tonic-gate 12427c478bd9Sstevel@tonic-gate switch (regno) { 12437c478bd9Sstevel@tonic-gate case 5: 12447c478bd9Sstevel@tonic-gate hmep->hme_cheerio_mode = 0; 12457c478bd9Sstevel@tonic-gate break; 12467c478bd9Sstevel@tonic-gate case 2: 12477c478bd9Sstevel@tonic-gate case 3: /* for hot swap/plug, there will be 3 entries in "reg" prop */ 12487c478bd9Sstevel@tonic-gate hmep->hme_cheerio_mode = 1; 12497c478bd9Sstevel@tonic-gate break; 12507c478bd9Sstevel@tonic-gate default: 125185025c03Sgd HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 125285025c03Sgd bad_num_regs_msg); 12537c478bd9Sstevel@tonic-gate goto error_state; 12547c478bd9Sstevel@tonic-gate } 12557c478bd9Sstevel@tonic-gate 12567c478bd9Sstevel@tonic-gate /* Initialize device attributes structure */ 12577c478bd9Sstevel@tonic-gate hmep->hme_dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 12587c478bd9Sstevel@tonic-gate 12597c478bd9Sstevel@tonic-gate if (hmep->hme_cheerio_mode) 126085025c03Sgd hmep->hme_dev_attr.devacc_attr_endian_flags = 126185025c03Sgd DDI_STRUCTURE_LE_ACC; 12627c478bd9Sstevel@tonic-gate else 126385025c03Sgd hmep->hme_dev_attr.devacc_attr_endian_flags = 126485025c03Sgd DDI_STRUCTURE_BE_ACC; 12657c478bd9Sstevel@tonic-gate 12667c478bd9Sstevel@tonic-gate hmep->hme_dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 12677c478bd9Sstevel@tonic-gate 12687c478bd9Sstevel@tonic-gate if (hmep->hme_cheerio_mode) { 12697c478bd9Sstevel@tonic-gate uint8_t oldLT; 12707c478bd9Sstevel@tonic-gate uint8_t newLT = 0; 12717c478bd9Sstevel@tonic-gate dev_info_t *pdip; 12727c478bd9Sstevel@tonic-gate const char *pdrvname; 12737c478bd9Sstevel@tonic-gate 12747c478bd9Sstevel@tonic-gate /* 12757c478bd9Sstevel@tonic-gate * Map the PCI config space 12767c478bd9Sstevel@tonic-gate */ 12777c478bd9Sstevel@tonic-gate if (pci_config_setup(dip, &hmep->pci_config_handle) != 127885025c03Sgd DDI_SUCCESS) { 12797c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG, 128085025c03Sgd "pci_config_setup() failed.."); 12817c478bd9Sstevel@tonic-gate goto error_state; 12827c478bd9Sstevel@tonic-gate } 12837c478bd9Sstevel@tonic-gate 12847c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(dip, 1, 128585025c03Sgd (caddr_t *)&(hmep->hme_globregp), 0, 0, 128685025c03Sgd &hmep->hme_dev_attr, &hmep->hme_globregh)) { 12877c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG, 128885025c03Sgd mregs_4global_reg_fail_msg); 12897c478bd9Sstevel@tonic-gate goto error_unmap; 12907c478bd9Sstevel@tonic-gate } 12917c478bd9Sstevel@tonic-gate hmep->hme_etxregh = hmep->hme_erxregh = hmep->hme_bmacregh = 12927c478bd9Sstevel@tonic-gate hmep->hme_mifregh = hmep->hme_globregh; 12937c478bd9Sstevel@tonic-gate 129485025c03Sgd hmep->hme_etxregp = 129585025c03Sgd (void *)(((caddr_t)hmep->hme_globregp) + 0x2000); 129685025c03Sgd hmep->hme_erxregp = 129785025c03Sgd (void *)(((caddr_t)hmep->hme_globregp) + 0x4000); 129885025c03Sgd hmep->hme_bmacregp = 129985025c03Sgd (void *)(((caddr_t)hmep->hme_globregp) + 0x6000); 130085025c03Sgd hmep->hme_mifregp = 130185025c03Sgd (void *)(((caddr_t)hmep->hme_globregp) + 0x7000); 13027c478bd9Sstevel@tonic-gate 13037c478bd9Sstevel@tonic-gate /* 13047c478bd9Sstevel@tonic-gate * Get parent pci bridge info. 13057c478bd9Sstevel@tonic-gate */ 13067c478bd9Sstevel@tonic-gate pdip = ddi_get_parent(dip); 13077c478bd9Sstevel@tonic-gate pdrvname = ddi_driver_name(pdip); 13087c478bd9Sstevel@tonic-gate 13097c478bd9Sstevel@tonic-gate oldLT = pci_config_get8(hmep->pci_config_handle, 131085025c03Sgd PCI_CONF_LATENCY_TIMER); 13117c478bd9Sstevel@tonic-gate /* 13127c478bd9Sstevel@tonic-gate * Honor value set in /etc/system 13137c478bd9Sstevel@tonic-gate * "set hme:pci_latency_timer=0xYY" 13147c478bd9Sstevel@tonic-gate */ 13157c478bd9Sstevel@tonic-gate if (pci_latency_timer) 13167c478bd9Sstevel@tonic-gate newLT = pci_latency_timer; 13177c478bd9Sstevel@tonic-gate /* 13187c478bd9Sstevel@tonic-gate * Modify LT for simba 13197c478bd9Sstevel@tonic-gate */ 13207c478bd9Sstevel@tonic-gate else if (strcmp("simba", pdrvname) == 0) 13217c478bd9Sstevel@tonic-gate newLT = 0xf0; 13227c478bd9Sstevel@tonic-gate /* 13237c478bd9Sstevel@tonic-gate * Ensure minimum cheerio latency timer of 0x50 13247c478bd9Sstevel@tonic-gate * Usually OBP or pci bridge should set this value 13257c478bd9Sstevel@tonic-gate * based on cheerio 13267c478bd9Sstevel@tonic-gate * min_grant * 8(33MHz) = 0x50 = 0xa * 0x8 13277c478bd9Sstevel@tonic-gate * Some system set cheerio LT at 0x40 13287c478bd9Sstevel@tonic-gate */ 13297c478bd9Sstevel@tonic-gate else if (oldLT < 0x40) 13307c478bd9Sstevel@tonic-gate newLT = 0x50; 13317c478bd9Sstevel@tonic-gate 13327c478bd9Sstevel@tonic-gate /* 13337c478bd9Sstevel@tonic-gate * Now program cheerio's pci latency timer with newLT 13347c478bd9Sstevel@tonic-gate */ 13357c478bd9Sstevel@tonic-gate if (newLT) 13367c478bd9Sstevel@tonic-gate pci_config_put8(hmep->pci_config_handle, 133785025c03Sgd PCI_CONF_LATENCY_TIMER, (uchar_t)newLT); 13387c478bd9Sstevel@tonic-gate } else { /* Map register sets */ 13397c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(dip, 0, 134085025c03Sgd (caddr_t *)&(hmep->hme_globregp), 0, 0, 134185025c03Sgd &hmep->hme_dev_attr, &hmep->hme_globregh)) { 13427c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG, 134385025c03Sgd mregs_4global_reg_fail_msg); 13447c478bd9Sstevel@tonic-gate goto error_state; 13457c478bd9Sstevel@tonic-gate } 13467c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(dip, 1, 134785025c03Sgd (caddr_t *)&(hmep->hme_etxregp), 0, 0, 134885025c03Sgd &hmep->hme_dev_attr, &hmep->hme_etxregh)) { 13497c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG, 135085025c03Sgd mregs_4etx_reg_fail_msg); 13517c478bd9Sstevel@tonic-gate goto error_unmap; 13527c478bd9Sstevel@tonic-gate } 13537c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(dip, 2, 135485025c03Sgd (caddr_t *)&(hmep->hme_erxregp), 0, 0, 135585025c03Sgd &hmep->hme_dev_attr, &hmep->hme_erxregh)) { 13567c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG, 135785025c03Sgd mregs_4erx_reg_fail_msg); 13587c478bd9Sstevel@tonic-gate goto error_unmap; 13597c478bd9Sstevel@tonic-gate } 13607c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(dip, 3, 136185025c03Sgd (caddr_t *)&(hmep->hme_bmacregp), 0, 0, 136285025c03Sgd &hmep->hme_dev_attr, &hmep->hme_bmacregh)) { 13637c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG, 136485025c03Sgd mregs_4bmac_reg_fail_msg); 13657c478bd9Sstevel@tonic-gate goto error_unmap; 13667c478bd9Sstevel@tonic-gate } 13677c478bd9Sstevel@tonic-gate 13687c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(dip, 4, 136985025c03Sgd (caddr_t *)&(hmep->hme_mifregp), 0, 0, 137085025c03Sgd &hmep->hme_dev_attr, &hmep->hme_mifregh)) { 13717c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG, 137285025c03Sgd mregs_4mif_reg_fail_msg); 13737c478bd9Sstevel@tonic-gate goto error_unmap; 13747c478bd9Sstevel@tonic-gate } 13757c478bd9Sstevel@tonic-gate } /* Endif cheerio_mode */ 13767c478bd9Sstevel@tonic-gate 13777c478bd9Sstevel@tonic-gate /* 13787c478bd9Sstevel@tonic-gate * Based on the hm-rev, set some capabilities 13797c478bd9Sstevel@tonic-gate * Set up default capabilities for HM 2.0 13807c478bd9Sstevel@tonic-gate */ 13817c478bd9Sstevel@tonic-gate hmep->hme_frame_enable = 0; 13827c478bd9Sstevel@tonic-gate hmep->hme_lance_mode_enable = 0; 13837c478bd9Sstevel@tonic-gate hmep->hme_rxcv_enable = 0; 13847c478bd9Sstevel@tonic-gate 13857c478bd9Sstevel@tonic-gate /* NEW routine to get the properties */ 13867c478bd9Sstevel@tonic-gate 13877c478bd9Sstevel@tonic-gate if (ddi_getlongprop_buf(DDI_DEV_T_ANY, hmep->dip, 0, "hm-rev", 138885025c03Sgd (caddr_t)&hm_rev, &prop_len) == DDI_PROP_SUCCESS) { 13897c478bd9Sstevel@tonic-gate 13907c478bd9Sstevel@tonic-gate hmep->asic_rev = hm_rev; 13917c478bd9Sstevel@tonic-gate hmeget_hm_rev_property(hmep); 13927c478bd9Sstevel@tonic-gate } else { 13937c478bd9Sstevel@tonic-gate /* 13947c478bd9Sstevel@tonic-gate * hm_rev property not found so, this is 13957c478bd9Sstevel@tonic-gate * case of hot insertion of card without interpreting fcode. 13967c478bd9Sstevel@tonic-gate * Get it from revid in config space after mapping it. 13977c478bd9Sstevel@tonic-gate */ 13987c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(hmep->dip, 0, (caddr_t *)&cfg_ptr, 139985025c03Sgd 0, 0, &hmep->hme_dev_attr, &cfg_handle)) { 14007c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 14017c478bd9Sstevel@tonic-gate } 14027c478bd9Sstevel@tonic-gate /* 14037c478bd9Sstevel@tonic-gate * Since this is cheerio-based PCI card, we write 0xC in the 14047c478bd9Sstevel@tonic-gate * top 4 bits(4-7) of hm-rev and retain the bottom(0-3) bits 14057c478bd9Sstevel@tonic-gate * for Cheerio version(1.0 or 2.0 = 0xC0 or 0xC1) 14067c478bd9Sstevel@tonic-gate */ 14077c478bd9Sstevel@tonic-gate hm_rev = ddi_get8(cfg_handle, &cfg_ptr->revid); 14087c478bd9Sstevel@tonic-gate hm_rev = HME_1C0_REVID | (hm_rev & HME_REV_VERS_MASK); 14097c478bd9Sstevel@tonic-gate hmep->asic_rev = hm_rev; 14107c478bd9Sstevel@tonic-gate if (ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, 141185025c03Sgd "hm-rev", (caddr_t)&hm_rev, sizeof (hm_rev)) != 141285025c03Sgd DDI_SUCCESS) { 14137c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, AUTOCONFIG_MSG, 141406673d9bSGarrett D'Amore "ddi_prop_create error for hm_rev"); 14157c478bd9Sstevel@tonic-gate } 14167c478bd9Sstevel@tonic-gate ddi_regs_map_free(&cfg_handle); 14177c478bd9Sstevel@tonic-gate 14187c478bd9Sstevel@tonic-gate hmeget_hm_rev_property(hmep); 14197c478bd9Sstevel@tonic-gate 14207c478bd9Sstevel@tonic-gate /* get info via VPD */ 14210219346bSGarrett D'Amore if (hmeget_promprops(dip) != DDI_SUCCESS) { 14227c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, AUTOCONFIG_MSG, 142306673d9bSGarrett D'Amore "no promprops"); 14247c478bd9Sstevel@tonic-gate } 14257c478bd9Sstevel@tonic-gate } 14267c478bd9Sstevel@tonic-gate 14277c478bd9Sstevel@tonic-gate if (ddi_intr_hilevel(dip, 0)) { 14287c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_HIGH, NFATAL_ERR_MSG, 142985025c03Sgd " high-level interrupts are not supported"); 14307c478bd9Sstevel@tonic-gate goto error_unmap; 14317c478bd9Sstevel@tonic-gate } 14327c478bd9Sstevel@tonic-gate 14337c478bd9Sstevel@tonic-gate /* 14347c478bd9Sstevel@tonic-gate * Get intr. block cookie so that mutex locks can be initialized. 14357c478bd9Sstevel@tonic-gate */ 14367c478bd9Sstevel@tonic-gate if (ddi_get_iblock_cookie(dip, 0, &hmep->hme_cookie) != DDI_SUCCESS) 14377c478bd9Sstevel@tonic-gate goto error_unmap; 14387c478bd9Sstevel@tonic-gate 14397c478bd9Sstevel@tonic-gate /* 14407c478bd9Sstevel@tonic-gate * Initialize mutex's for this device. 14417c478bd9Sstevel@tonic-gate */ 144285025c03Sgd mutex_init(&hmep->hme_xmitlock, NULL, MUTEX_DRIVER, hmep->hme_cookie); 144385025c03Sgd mutex_init(&hmep->hme_intrlock, NULL, MUTEX_DRIVER, hmep->hme_cookie); 14447c478bd9Sstevel@tonic-gate 14457c478bd9Sstevel@tonic-gate /* 14467c478bd9Sstevel@tonic-gate * Quiesce the hardware. 14477c478bd9Sstevel@tonic-gate */ 14487c478bd9Sstevel@tonic-gate (void) hmestop(hmep); 14497c478bd9Sstevel@tonic-gate 14507c478bd9Sstevel@tonic-gate /* 14517c478bd9Sstevel@tonic-gate * Add interrupt to system 14527c478bd9Sstevel@tonic-gate */ 14537c478bd9Sstevel@tonic-gate if (ddi_add_intr(dip, 0, (ddi_iblock_cookie_t *)NULL, 14547c478bd9Sstevel@tonic-gate (ddi_idevice_cookie_t *)NULL, hmeintr, (caddr_t)hmep)) { 14557c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG, 145685025c03Sgd add_intr_fail_msg); 14577c478bd9Sstevel@tonic-gate goto error_mutex; 14587c478bd9Sstevel@tonic-gate } 14597c478bd9Sstevel@tonic-gate 14607c478bd9Sstevel@tonic-gate /* 14617c478bd9Sstevel@tonic-gate * Set up the ethernet mac address. 14627c478bd9Sstevel@tonic-gate */ 14637c478bd9Sstevel@tonic-gate hme_setup_mac_address(hmep, dip); 14647c478bd9Sstevel@tonic-gate 14657c478bd9Sstevel@tonic-gate if (!hmeinit_xfer_params(hmep)) 146685025c03Sgd goto error_intr; 14677c478bd9Sstevel@tonic-gate 14687c478bd9Sstevel@tonic-gate if (hmeburstsizes(hmep) == DDI_FAILURE) { 14697c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, burst_size_msg); 147085025c03Sgd goto error_intr; 14717c478bd9Sstevel@tonic-gate } 14727c478bd9Sstevel@tonic-gate 14730219346bSGarrett D'Amore if (hmeallocthings(hmep) != DDI_SUCCESS) { 14740219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, CONFIG_MSG, 14750219346bSGarrett D'Amore "resource allocation failed"); 14760219346bSGarrett D'Amore goto error_intr; 14770219346bSGarrett D'Amore } 14780219346bSGarrett D'Amore 14790219346bSGarrett D'Amore if (hmeallocbufs(hmep) != DDI_SUCCESS) { 14800219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, CONFIG_MSG, 14810219346bSGarrett D'Amore "buffer allocation failed"); 14820219346bSGarrett D'Amore goto error_intr; 14830219346bSGarrett D'Amore } 14847c478bd9Sstevel@tonic-gate 14857c478bd9Sstevel@tonic-gate hmestatinit(hmep); 148685025c03Sgd 1487e8717ca2SGarrett D'Amore /* our external (preferred) PHY is at address 0 */ 1488e8717ca2SGarrett D'Amore (void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, "first-phy", 0); 1489e8717ca2SGarrett D'Amore 149006673d9bSGarrett D'Amore hmep->hme_mii = mii_alloc(hmep, dip, &hme_mii_ops); 149106673d9bSGarrett D'Amore if (hmep->hme_mii == NULL) { 149206673d9bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, CONFIG_MSG, 149306673d9bSGarrett D'Amore "mii_alloc failed"); 149406673d9bSGarrett D'Amore goto error_intr; 149506673d9bSGarrett D'Amore } 149606673d9bSGarrett D'Amore /* force a probe for the PHY */ 149706673d9bSGarrett D'Amore mii_probe(hmep->hme_mii); 149806673d9bSGarrett D'Amore 149985025c03Sgd if ((macp = mac_alloc(MAC_VERSION)) == NULL) { 150085025c03Sgd HME_FAULT_MSG1(hmep, SEVERITY_HIGH, CONFIG_MSG, 150185025c03Sgd "mac_alloc failed"); 150285025c03Sgd goto error_intr; 150385025c03Sgd } 150485025c03Sgd macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 150585025c03Sgd macp->m_driver = hmep; 150685025c03Sgd macp->m_dip = dip; 150785025c03Sgd macp->m_src_addr = hmep->hme_ouraddr.ether_addr_octet; 150885025c03Sgd macp->m_callbacks = &hme_m_callbacks; 150985025c03Sgd macp->m_min_sdu = 0; 151085025c03Sgd macp->m_max_sdu = ETHERMTU; 1511d62bc4baSyz macp->m_margin = VLAN_TAGSZ; 151206673d9bSGarrett D'Amore macp->m_priv_props = hme_priv_prop; 151385025c03Sgd if (mac_register(macp, &hmep->hme_mh) != 0) { 151485025c03Sgd mac_free(macp); 151585025c03Sgd goto error_intr; 151685025c03Sgd } 151785025c03Sgd 151885025c03Sgd mac_free(macp); 151985025c03Sgd 15207c478bd9Sstevel@tonic-gate ddi_report_dev(dip); 15217c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 15227c478bd9Sstevel@tonic-gate 15237c478bd9Sstevel@tonic-gate /* 15247c478bd9Sstevel@tonic-gate * Failure Exit 15257c478bd9Sstevel@tonic-gate */ 15267c478bd9Sstevel@tonic-gate 15277c478bd9Sstevel@tonic-gate error_intr: 15287c478bd9Sstevel@tonic-gate if (hmep->hme_cookie) 15297c478bd9Sstevel@tonic-gate ddi_remove_intr(dip, 0, (ddi_iblock_cookie_t)0); 15307c478bd9Sstevel@tonic-gate 153106673d9bSGarrett D'Amore if (hmep->hme_mii) 153206673d9bSGarrett D'Amore mii_free(hmep->hme_mii); 153306673d9bSGarrett D'Amore 15347c478bd9Sstevel@tonic-gate error_mutex: 15357c478bd9Sstevel@tonic-gate mutex_destroy(&hmep->hme_xmitlock); 15367c478bd9Sstevel@tonic-gate mutex_destroy(&hmep->hme_intrlock); 15377c478bd9Sstevel@tonic-gate 15387c478bd9Sstevel@tonic-gate error_unmap: 15397c478bd9Sstevel@tonic-gate if (hmep->hme_globregh) 154085025c03Sgd ddi_regs_map_free(&hmep->hme_globregh); 15417c478bd9Sstevel@tonic-gate if (hmep->hme_cheerio_mode == 0) { 15427c478bd9Sstevel@tonic-gate if (hmep->hme_etxregh) 154385025c03Sgd ddi_regs_map_free(&hmep->hme_etxregh); 15447c478bd9Sstevel@tonic-gate if (hmep->hme_erxregh) 154585025c03Sgd ddi_regs_map_free(&hmep->hme_erxregh); 15467c478bd9Sstevel@tonic-gate if (hmep->hme_bmacregh) 154785025c03Sgd ddi_regs_map_free(&hmep->hme_bmacregh); 15487c478bd9Sstevel@tonic-gate if (hmep->hme_mifregh) 154985025c03Sgd ddi_regs_map_free(&hmep->hme_mifregh); 15507c478bd9Sstevel@tonic-gate } else { 15517c478bd9Sstevel@tonic-gate if (hmep->pci_config_handle) 15527c478bd9Sstevel@tonic-gate (void) pci_config_teardown(&hmep->pci_config_handle); 15537c478bd9Sstevel@tonic-gate hmep->hme_etxregh = hmep->hme_erxregh = hmep->hme_bmacregh = 15547c478bd9Sstevel@tonic-gate hmep->hme_mifregh = hmep->hme_globregh = NULL; 15557c478bd9Sstevel@tonic-gate } 15567c478bd9Sstevel@tonic-gate 15577c478bd9Sstevel@tonic-gate error_state: 15580219346bSGarrett D'Amore hmefreethings(hmep); 15590219346bSGarrett D'Amore hmefreebufs(hmep); 15600219346bSGarrett D'Amore 15617c478bd9Sstevel@tonic-gate if (hmep) { 15627c478bd9Sstevel@tonic-gate kmem_free((caddr_t)hmep, sizeof (*hmep)); 15637c478bd9Sstevel@tonic-gate ddi_set_driver_private(dip, NULL); 15647c478bd9Sstevel@tonic-gate } 15657c478bd9Sstevel@tonic-gate 15667c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 15677c478bd9Sstevel@tonic-gate } 15687c478bd9Sstevel@tonic-gate 1569f2cd0f02Sgd int 15707c478bd9Sstevel@tonic-gate hmedetach(dev_info_t *dip, ddi_detach_cmd_t cmd) 15717c478bd9Sstevel@tonic-gate { 157285025c03Sgd struct hme *hmep; 15737c478bd9Sstevel@tonic-gate 15747c478bd9Sstevel@tonic-gate if ((hmep = ddi_get_driver_private(dip)) == NULL) 15757c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 15767c478bd9Sstevel@tonic-gate 15777c478bd9Sstevel@tonic-gate switch (cmd) { 15787c478bd9Sstevel@tonic-gate case DDI_DETACH: 15797c478bd9Sstevel@tonic-gate break; 15807c478bd9Sstevel@tonic-gate 15817c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 158206673d9bSGarrett D'Amore mii_suspend(hmep->hme_mii); 15837c478bd9Sstevel@tonic-gate hmep->hme_flags |= HMESUSPENDED; 15847c478bd9Sstevel@tonic-gate hmeuninit(hmep); 15857c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 15867c478bd9Sstevel@tonic-gate 15877c478bd9Sstevel@tonic-gate default: 158885025c03Sgd return (DDI_FAILURE); 158985025c03Sgd } 159085025c03Sgd 159185025c03Sgd 159285025c03Sgd if (mac_unregister(hmep->hme_mh) != 0) { 15937c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 15947c478bd9Sstevel@tonic-gate } 15957c478bd9Sstevel@tonic-gate 15967c478bd9Sstevel@tonic-gate /* 15977c478bd9Sstevel@tonic-gate * Make driver quiescent, we don't want to prevent the 15984dd87b61Sgd * detach on failure. Note that this should be redundant, 15994dd87b61Sgd * since mac_stop should already have called hmeuninit(). 16007c478bd9Sstevel@tonic-gate */ 16014dd87b61Sgd if (!(hmep->hme_flags & HMESUSPENDED)) { 16024dd87b61Sgd (void) hmestop(hmep); 16034dd87b61Sgd } 16047c478bd9Sstevel@tonic-gate 160506673d9bSGarrett D'Amore if (hmep->hme_mii) 160606673d9bSGarrett D'Amore mii_free(hmep->hme_mii); 160706673d9bSGarrett D'Amore 16087c478bd9Sstevel@tonic-gate /* 16097c478bd9Sstevel@tonic-gate * Remove instance of the intr 16107c478bd9Sstevel@tonic-gate */ 16117c478bd9Sstevel@tonic-gate ddi_remove_intr(dip, 0, (ddi_iblock_cookie_t)0); 16127c478bd9Sstevel@tonic-gate 161385025c03Sgd /* 161485025c03Sgd * Unregister kstats. 161585025c03Sgd */ 161685025c03Sgd if (hmep->hme_ksp != NULL) 161785025c03Sgd kstat_delete(hmep->hme_ksp); 161885025c03Sgd if (hmep->hme_intrstats != NULL) 161985025c03Sgd kstat_delete(hmep->hme_intrstats); 162085025c03Sgd 162106673d9bSGarrett D'Amore hmep->hme_ksp = NULL; 162206673d9bSGarrett D'Amore hmep->hme_intrstats = NULL; 162385025c03Sgd 16247c478bd9Sstevel@tonic-gate /* 16257c478bd9Sstevel@tonic-gate * Destroy all mutexes and data structures allocated during 16267c478bd9Sstevel@tonic-gate * attach time. 162785025c03Sgd * 162885025c03Sgd * Note: at this time we should be the only thread accessing 162985025c03Sgd * the structures for this instance. 16307c478bd9Sstevel@tonic-gate */ 16317c478bd9Sstevel@tonic-gate 16327c478bd9Sstevel@tonic-gate if (hmep->hme_globregh) 16337c478bd9Sstevel@tonic-gate ddi_regs_map_free(&hmep->hme_globregh); 16347c478bd9Sstevel@tonic-gate if (hmep->hme_cheerio_mode == 0) { 16357c478bd9Sstevel@tonic-gate if (hmep->hme_etxregh) 163685025c03Sgd ddi_regs_map_free(&hmep->hme_etxregh); 16377c478bd9Sstevel@tonic-gate if (hmep->hme_erxregh) 163885025c03Sgd ddi_regs_map_free(&hmep->hme_erxregh); 16397c478bd9Sstevel@tonic-gate if (hmep->hme_bmacregh) 164085025c03Sgd ddi_regs_map_free(&hmep->hme_bmacregh); 16417c478bd9Sstevel@tonic-gate if (hmep->hme_mifregh) 164285025c03Sgd ddi_regs_map_free(&hmep->hme_mifregh); 16437c478bd9Sstevel@tonic-gate } else { 16447c478bd9Sstevel@tonic-gate if (hmep->pci_config_handle) 16457c478bd9Sstevel@tonic-gate (void) pci_config_teardown(&hmep->pci_config_handle); 16467c478bd9Sstevel@tonic-gate hmep->hme_etxregh = hmep->hme_erxregh = hmep->hme_bmacregh = 16477c478bd9Sstevel@tonic-gate hmep->hme_mifregh = hmep->hme_globregh = NULL; 16487c478bd9Sstevel@tonic-gate } 16497c478bd9Sstevel@tonic-gate 165085025c03Sgd mutex_destroy(&hmep->hme_xmitlock); 165185025c03Sgd mutex_destroy(&hmep->hme_intrlock); 16527c478bd9Sstevel@tonic-gate 16530219346bSGarrett D'Amore hmefreethings(hmep); 165485025c03Sgd hmefreebufs(hmep); 16557c478bd9Sstevel@tonic-gate 165685025c03Sgd ddi_set_driver_private(dip, NULL); 165785025c03Sgd kmem_free(hmep, sizeof (struct hme)); 16587c478bd9Sstevel@tonic-gate 16597c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 16607c478bd9Sstevel@tonic-gate } 16617c478bd9Sstevel@tonic-gate 16620219346bSGarrett D'Amore int 16630219346bSGarrett D'Amore hmequiesce(dev_info_t *dip) 16640219346bSGarrett D'Amore { 16650219346bSGarrett D'Amore struct hme *hmep; 16660219346bSGarrett D'Amore 16670219346bSGarrett D'Amore if ((hmep = ddi_get_driver_private(dip)) == NULL) 16680219346bSGarrett D'Amore return (DDI_FAILURE); 16690219346bSGarrett D'Amore 16700219346bSGarrett D'Amore (void) hmestop(hmep); 16710219346bSGarrett D'Amore return (DDI_SUCCESS); 16720219346bSGarrett D'Amore } 16730219346bSGarrett D'Amore 167485025c03Sgd static boolean_t 16757c478bd9Sstevel@tonic-gate hmeinit_xfer_params(struct hme *hmep) 16767c478bd9Sstevel@tonic-gate { 16777c478bd9Sstevel@tonic-gate int hme_ipg1_conf, hme_ipg2_conf; 16787c478bd9Sstevel@tonic-gate int hme_ipg0_conf, hme_lance_mode_conf; 16797c478bd9Sstevel@tonic-gate int prop_len = sizeof (int); 16807c478bd9Sstevel@tonic-gate dev_info_t *dip; 16817c478bd9Sstevel@tonic-gate 16827c478bd9Sstevel@tonic-gate dip = hmep->dip; 16837c478bd9Sstevel@tonic-gate 16847c478bd9Sstevel@tonic-gate /* 16857c478bd9Sstevel@tonic-gate * Set up the start-up values for user-configurable parameters 16867c478bd9Sstevel@tonic-gate * Get the values from the global variables first. 16877c478bd9Sstevel@tonic-gate * Use the MASK to limit the value to allowed maximum. 16887c478bd9Sstevel@tonic-gate */ 168906673d9bSGarrett D'Amore hmep->hme_ipg1 = hme_ipg1 & HME_MASK_8BIT; 169006673d9bSGarrett D'Amore hmep->hme_ipg2 = hme_ipg2 & HME_MASK_8BIT; 169106673d9bSGarrett D'Amore hmep->hme_ipg0 = hme_ipg0 & HME_MASK_5BIT; 16927c478bd9Sstevel@tonic-gate 16937c478bd9Sstevel@tonic-gate /* 16947c478bd9Sstevel@tonic-gate * Get the parameter values configured in .conf file. 16957c478bd9Sstevel@tonic-gate */ 16967c478bd9Sstevel@tonic-gate if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "ipg1", 169785025c03Sgd (caddr_t)&hme_ipg1_conf, &prop_len) == DDI_PROP_SUCCESS) { 169806673d9bSGarrett D'Amore hmep->hme_ipg1 = hme_ipg1_conf & HME_MASK_8BIT; 16997c478bd9Sstevel@tonic-gate } 17007c478bd9Sstevel@tonic-gate 17017c478bd9Sstevel@tonic-gate if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "ipg2", 170285025c03Sgd (caddr_t)&hme_ipg2_conf, &prop_len) == DDI_PROP_SUCCESS) { 170306673d9bSGarrett D'Amore hmep->hme_ipg2 = hme_ipg2_conf & HME_MASK_8BIT; 17047c478bd9Sstevel@tonic-gate } 17057c478bd9Sstevel@tonic-gate 17067c478bd9Sstevel@tonic-gate if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "ipg0", 170785025c03Sgd (caddr_t)&hme_ipg0_conf, &prop_len) == DDI_PROP_SUCCESS) { 170806673d9bSGarrett D'Amore hmep->hme_ipg0 = hme_ipg0_conf & HME_MASK_5BIT; 17097c478bd9Sstevel@tonic-gate } 17107c478bd9Sstevel@tonic-gate 17117c478bd9Sstevel@tonic-gate if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "lance_mode", 171285025c03Sgd (caddr_t)&hme_lance_mode_conf, &prop_len) == DDI_PROP_SUCCESS) { 171306673d9bSGarrett D'Amore hmep->hme_lance_mode = hme_lance_mode_conf & HME_MASK_1BIT; 17147c478bd9Sstevel@tonic-gate } 17157c478bd9Sstevel@tonic-gate 17167c478bd9Sstevel@tonic-gate return (B_TRUE); 17177c478bd9Sstevel@tonic-gate } 17187c478bd9Sstevel@tonic-gate 17197c478bd9Sstevel@tonic-gate /* 17207c478bd9Sstevel@tonic-gate * Return 0 upon success, 1 on failure. 17217c478bd9Sstevel@tonic-gate */ 17227c478bd9Sstevel@tonic-gate static uint_t 17237c478bd9Sstevel@tonic-gate hmestop(struct hme *hmep) 17247c478bd9Sstevel@tonic-gate { 17257c478bd9Sstevel@tonic-gate /* 17267c478bd9Sstevel@tonic-gate * Disable the Tx dma engine. 17277c478bd9Sstevel@tonic-gate */ 17287c478bd9Sstevel@tonic-gate PUT_ETXREG(config, (GET_ETXREG(config) & ~HMET_CONFIG_TXDMA_EN)); 17297c478bd9Sstevel@tonic-gate HMEDELAY(((GET_ETXREG(state_mach) & 0x1f) == 0x1), HMEMAXRSTDELAY); 17307c478bd9Sstevel@tonic-gate 17317c478bd9Sstevel@tonic-gate /* 17327c478bd9Sstevel@tonic-gate * Disable the Rx dma engine. 17337c478bd9Sstevel@tonic-gate */ 17347c478bd9Sstevel@tonic-gate PUT_ERXREG(config, (GET_ERXREG(config) & ~HMER_CONFIG_RXDMA_EN)); 17357c478bd9Sstevel@tonic-gate HMEDELAY(((GET_ERXREG(state_mach) & 0x3f) == 0), HMEMAXRSTDELAY); 17367c478bd9Sstevel@tonic-gate 17377c478bd9Sstevel@tonic-gate /* 17387c478bd9Sstevel@tonic-gate * By this time all things should be quiet, so hit the 17397c478bd9Sstevel@tonic-gate * chip with a reset. 17407c478bd9Sstevel@tonic-gate */ 17417c478bd9Sstevel@tonic-gate PUT_GLOBREG(reset, HMEG_RESET_GLOBAL); 17427c478bd9Sstevel@tonic-gate 17437c478bd9Sstevel@tonic-gate HMEDELAY((GET_GLOBREG(reset) == 0), HMEMAXRSTDELAY); 17447c478bd9Sstevel@tonic-gate if (GET_GLOBREG(reset)) { 17457c478bd9Sstevel@tonic-gate return (1); 17467c478bd9Sstevel@tonic-gate } 17477c478bd9Sstevel@tonic-gate 17487c478bd9Sstevel@tonic-gate CHECK_GLOBREG(); 17497c478bd9Sstevel@tonic-gate return (0); 17507c478bd9Sstevel@tonic-gate } 17517c478bd9Sstevel@tonic-gate 17527c478bd9Sstevel@tonic-gate static int 17537c478bd9Sstevel@tonic-gate hmestat_kstat_update(kstat_t *ksp, int rw) 17547c478bd9Sstevel@tonic-gate { 17557c478bd9Sstevel@tonic-gate struct hme *hmep; 17567c478bd9Sstevel@tonic-gate struct hmekstat *hkp; 17577c478bd9Sstevel@tonic-gate 17587c478bd9Sstevel@tonic-gate hmep = (struct hme *)ksp->ks_private; 17597c478bd9Sstevel@tonic-gate hkp = (struct hmekstat *)ksp->ks_data; 17607c478bd9Sstevel@tonic-gate 176185025c03Sgd if (rw != KSTAT_READ) 176285025c03Sgd return (EACCES); 176385025c03Sgd 17647c478bd9Sstevel@tonic-gate /* 17657c478bd9Sstevel@tonic-gate * Update all the stats by reading all the counter registers. 17667c478bd9Sstevel@tonic-gate * Counter register stats are not updated till they overflow 17677c478bd9Sstevel@tonic-gate * and interrupt. 17687c478bd9Sstevel@tonic-gate */ 17697c478bd9Sstevel@tonic-gate 17707c478bd9Sstevel@tonic-gate mutex_enter(&hmep->hme_xmitlock); 17714dd87b61Sgd if (hmep->hme_flags & HMERUNNING) { 17727c478bd9Sstevel@tonic-gate hmereclaim(hmep); 17734dd87b61Sgd hmesavecntrs(hmep); 17744dd87b61Sgd } 17757c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_xmitlock); 17767c478bd9Sstevel@tonic-gate 177785025c03Sgd hkp->hk_cvc.value.ul = hmep->hme_cvc; 177885025c03Sgd hkp->hk_lenerr.value.ul = hmep->hme_lenerr; 177985025c03Sgd hkp->hk_buff.value.ul = hmep->hme_buff; 178085025c03Sgd hkp->hk_missed.value.ul = hmep->hme_missed; 178185025c03Sgd hkp->hk_allocbfail.value.ul = hmep->hme_allocbfail; 178285025c03Sgd hkp->hk_babl.value.ul = hmep->hme_babl; 178385025c03Sgd hkp->hk_tmder.value.ul = hmep->hme_tmder; 178485025c03Sgd hkp->hk_txlaterr.value.ul = hmep->hme_txlaterr; 178585025c03Sgd hkp->hk_rxlaterr.value.ul = hmep->hme_rxlaterr; 178685025c03Sgd hkp->hk_slvparerr.value.ul = hmep->hme_slvparerr; 178785025c03Sgd hkp->hk_txparerr.value.ul = hmep->hme_txparerr; 178885025c03Sgd hkp->hk_rxparerr.value.ul = hmep->hme_rxparerr; 178985025c03Sgd hkp->hk_slverrack.value.ul = hmep->hme_slverrack; 179085025c03Sgd hkp->hk_txerrack.value.ul = hmep->hme_txerrack; 179185025c03Sgd hkp->hk_rxerrack.value.ul = hmep->hme_rxerrack; 179285025c03Sgd hkp->hk_txtagerr.value.ul = hmep->hme_txtagerr; 179385025c03Sgd hkp->hk_rxtagerr.value.ul = hmep->hme_rxtagerr; 179485025c03Sgd hkp->hk_eoperr.value.ul = hmep->hme_eoperr; 179585025c03Sgd hkp->hk_notmds.value.ul = hmep->hme_notmds; 179685025c03Sgd hkp->hk_notbufs.value.ul = hmep->hme_notbufs; 179785025c03Sgd hkp->hk_norbufs.value.ul = hmep->hme_norbufs; 17987c478bd9Sstevel@tonic-gate 179985025c03Sgd /* 180085025c03Sgd * Debug kstats 180185025c03Sgd */ 180285025c03Sgd hkp->hk_inits.value.ul = hmep->inits; 180385025c03Sgd hkp->hk_phyfail.value.ul = hmep->phyfail; 18047c478bd9Sstevel@tonic-gate 180585025c03Sgd /* 180685025c03Sgd * xcvr kstats 180785025c03Sgd */ 180885025c03Sgd hkp->hk_asic_rev.value.ul = hmep->asic_rev; 18097c478bd9Sstevel@tonic-gate 18107c478bd9Sstevel@tonic-gate return (0); 18117c478bd9Sstevel@tonic-gate } 18127c478bd9Sstevel@tonic-gate 18137c478bd9Sstevel@tonic-gate static void 18147c478bd9Sstevel@tonic-gate hmestatinit(struct hme *hmep) 18157c478bd9Sstevel@tonic-gate { 18167c478bd9Sstevel@tonic-gate struct kstat *ksp; 18177c478bd9Sstevel@tonic-gate struct hmekstat *hkp; 1818f2cd0f02Sgd const char *driver; 18197c478bd9Sstevel@tonic-gate int instance; 18207c478bd9Sstevel@tonic-gate char buf[16]; 18217c478bd9Sstevel@tonic-gate 18227c478bd9Sstevel@tonic-gate instance = hmep->instance; 1823f2cd0f02Sgd driver = ddi_driver_name(hmep->dip); 18247c478bd9Sstevel@tonic-gate 1825f2cd0f02Sgd if ((ksp = kstat_create(driver, instance, 182685025c03Sgd "driver_info", "net", KSTAT_TYPE_NAMED, 18277c478bd9Sstevel@tonic-gate sizeof (struct hmekstat) / sizeof (kstat_named_t), 0)) == NULL) { 18287c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, INIT_MSG, 18290219346bSGarrett D'Amore "kstat_create failed"); 18307c478bd9Sstevel@tonic-gate return; 18317c478bd9Sstevel@tonic-gate } 18327c478bd9Sstevel@tonic-gate 1833f2cd0f02Sgd (void) snprintf(buf, sizeof (buf), "%sc%d", driver, instance); 1834f2cd0f02Sgd hmep->hme_intrstats = kstat_create(driver, instance, buf, "controller", 183585025c03Sgd KSTAT_TYPE_INTR, 1, KSTAT_FLAG_PERSISTENT); 18367c478bd9Sstevel@tonic-gate if (hmep->hme_intrstats) 18377c478bd9Sstevel@tonic-gate kstat_install(hmep->hme_intrstats); 18387c478bd9Sstevel@tonic-gate 18397c478bd9Sstevel@tonic-gate hmep->hme_ksp = ksp; 18407c478bd9Sstevel@tonic-gate hkp = (struct hmekstat *)ksp->ks_data; 18417c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_cvc, "code_violations", 184285025c03Sgd KSTAT_DATA_ULONG); 18437c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_lenerr, "len_errors", 184485025c03Sgd KSTAT_DATA_ULONG); 18457c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_buff, "buff", 184685025c03Sgd KSTAT_DATA_ULONG); 18477c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_missed, "missed", 184885025c03Sgd KSTAT_DATA_ULONG); 18497c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_nocanput, "nocanput", 185085025c03Sgd KSTAT_DATA_ULONG); 18517c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_allocbfail, "allocbfail", 185285025c03Sgd KSTAT_DATA_ULONG); 18537c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_babl, "babble", 185485025c03Sgd KSTAT_DATA_ULONG); 18557c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_tmder, "tmd_error", 185685025c03Sgd KSTAT_DATA_ULONG); 18577c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_txlaterr, "tx_late_error", 185885025c03Sgd KSTAT_DATA_ULONG); 18597c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_rxlaterr, "rx_late_error", 186085025c03Sgd KSTAT_DATA_ULONG); 18617c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_slvparerr, "slv_parity_error", 186285025c03Sgd KSTAT_DATA_ULONG); 18637c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_txparerr, "tx_parity_error", 186485025c03Sgd KSTAT_DATA_ULONG); 18657c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_rxparerr, "rx_parity_error", 186685025c03Sgd KSTAT_DATA_ULONG); 18677c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_slverrack, "slv_error_ack", 186885025c03Sgd KSTAT_DATA_ULONG); 18697c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_txerrack, "tx_error_ack", 187085025c03Sgd KSTAT_DATA_ULONG); 18717c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_rxerrack, "rx_error_ack", 187285025c03Sgd KSTAT_DATA_ULONG); 18737c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_txtagerr, "tx_tag_error", 187485025c03Sgd KSTAT_DATA_ULONG); 18757c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_rxtagerr, "rx_tag_error", 187685025c03Sgd KSTAT_DATA_ULONG); 18777c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_eoperr, "eop_error", 187885025c03Sgd KSTAT_DATA_ULONG); 18797c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_notmds, "no_tmds", 188085025c03Sgd KSTAT_DATA_ULONG); 18817c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_notbufs, "no_tbufs", 188285025c03Sgd KSTAT_DATA_ULONG); 18837c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_norbufs, "no_rbufs", 188485025c03Sgd KSTAT_DATA_ULONG); 18857c478bd9Sstevel@tonic-gate 18867c478bd9Sstevel@tonic-gate /* 18877c478bd9Sstevel@tonic-gate * Debugging kstats 18887c478bd9Sstevel@tonic-gate */ 18897c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_inits, "inits", 189085025c03Sgd KSTAT_DATA_ULONG); 18917c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_phyfail, "phy_failures", 189285025c03Sgd KSTAT_DATA_ULONG); 18937c478bd9Sstevel@tonic-gate 18947c478bd9Sstevel@tonic-gate /* 18957c478bd9Sstevel@tonic-gate * xcvr kstats 18967c478bd9Sstevel@tonic-gate */ 18977c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_asic_rev, "asic_rev", 189885025c03Sgd KSTAT_DATA_ULONG); 18997c478bd9Sstevel@tonic-gate 19007c478bd9Sstevel@tonic-gate ksp->ks_update = hmestat_kstat_update; 19017c478bd9Sstevel@tonic-gate ksp->ks_private = (void *) hmep; 19027c478bd9Sstevel@tonic-gate kstat_install(ksp); 19037c478bd9Sstevel@tonic-gate } 19047c478bd9Sstevel@tonic-gate 190506673d9bSGarrett D'Amore int 19060dc2366fSVenugopal Iyer hme_m_getprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz, 19070dc2366fSVenugopal Iyer void *val) 19087c478bd9Sstevel@tonic-gate { 190906673d9bSGarrett D'Amore struct hme *hmep = arg; 191006673d9bSGarrett D'Amore int value; 191106673d9bSGarrett D'Amore int rv; 191206673d9bSGarrett D'Amore 19130dc2366fSVenugopal Iyer rv = mii_m_getprop(hmep->hme_mii, name, num, sz, val); 191406673d9bSGarrett D'Amore if (rv != ENOTSUP) 191506673d9bSGarrett D'Amore return (rv); 191606673d9bSGarrett D'Amore 191706673d9bSGarrett D'Amore switch (num) { 191806673d9bSGarrett D'Amore case MAC_PROP_PRIVATE: 191906673d9bSGarrett D'Amore break; 192006673d9bSGarrett D'Amore default: 192106673d9bSGarrett D'Amore return (ENOTSUP); 192206673d9bSGarrett D'Amore } 192306673d9bSGarrett D'Amore 192406673d9bSGarrett D'Amore if (strcmp(name, "_ipg0") == 0) { 19250dc2366fSVenugopal Iyer value = hmep->hme_ipg0; 192606673d9bSGarrett D'Amore } else if (strcmp(name, "_ipg1") == 0) { 19270dc2366fSVenugopal Iyer value = hmep->hme_ipg1; 192806673d9bSGarrett D'Amore } else if (strcmp(name, "_ipg2") == 0) { 19290dc2366fSVenugopal Iyer value = hmep->hme_ipg2; 193006673d9bSGarrett D'Amore } else if (strcmp(name, "_lance_mode") == 0) { 19310dc2366fSVenugopal Iyer value = hmep->hme_lance_mode; 193206673d9bSGarrett D'Amore } else { 193306673d9bSGarrett D'Amore return (ENOTSUP); 193406673d9bSGarrett D'Amore } 193506673d9bSGarrett D'Amore (void) snprintf(val, sz, "%d", value); 193606673d9bSGarrett D'Amore return (0); 193706673d9bSGarrett D'Amore } 193806673d9bSGarrett D'Amore 19390dc2366fSVenugopal Iyer static void 19400dc2366fSVenugopal Iyer hme_m_propinfo(void *arg, const char *name, mac_prop_id_t num, 19410dc2366fSVenugopal Iyer mac_prop_info_handle_t mph) 19420dc2366fSVenugopal Iyer { 19430dc2366fSVenugopal Iyer struct hme *hmep = arg; 19440dc2366fSVenugopal Iyer 19450dc2366fSVenugopal Iyer mii_m_propinfo(hmep->hme_mii, name, num, mph); 19460dc2366fSVenugopal Iyer 19470dc2366fSVenugopal Iyer switch (num) { 19480dc2366fSVenugopal Iyer case MAC_PROP_PRIVATE: { 19490dc2366fSVenugopal Iyer char valstr[64]; 19500dc2366fSVenugopal Iyer int default_val; 19510dc2366fSVenugopal Iyer 19520dc2366fSVenugopal Iyer if (strcmp(name, "_ipg0") == 0) { 19530dc2366fSVenugopal Iyer default_val = hme_ipg0; 19540dc2366fSVenugopal Iyer } else if (strcmp(name, "_ipg1") == 0) { 19550dc2366fSVenugopal Iyer default_val = hme_ipg1; 19560dc2366fSVenugopal Iyer } else if (strcmp(name, "_ipg2") == 0) { 19570dc2366fSVenugopal Iyer default_val = hme_ipg2; 19580dc2366fSVenugopal Iyer } if (strcmp(name, "_lance_mode") == 0) { 19590dc2366fSVenugopal Iyer default_val = hme_lance_mode; 19600dc2366fSVenugopal Iyer } else { 19610dc2366fSVenugopal Iyer return; 19620dc2366fSVenugopal Iyer } 19630dc2366fSVenugopal Iyer 19640dc2366fSVenugopal Iyer (void) snprintf(valstr, sizeof (valstr), "%d", default_val); 19650dc2366fSVenugopal Iyer mac_prop_info_set_default_str(mph, valstr); 19660dc2366fSVenugopal Iyer break; 19670dc2366fSVenugopal Iyer } 19680dc2366fSVenugopal Iyer } 19690dc2366fSVenugopal Iyer } 19700dc2366fSVenugopal Iyer 197106673d9bSGarrett D'Amore int 197206673d9bSGarrett D'Amore hme_m_setprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz, 197306673d9bSGarrett D'Amore const void *val) 197406673d9bSGarrett D'Amore { 197506673d9bSGarrett D'Amore struct hme *hmep = arg; 197606673d9bSGarrett D'Amore int rv; 197706673d9bSGarrett D'Amore long lval; 197806673d9bSGarrett D'Amore boolean_t init = B_FALSE; 197906673d9bSGarrett D'Amore 198006673d9bSGarrett D'Amore rv = mii_m_setprop(hmep->hme_mii, name, num, sz, val); 198106673d9bSGarrett D'Amore if (rv != ENOTSUP) 198206673d9bSGarrett D'Amore return (rv); 198306673d9bSGarrett D'Amore rv = 0; 198406673d9bSGarrett D'Amore 198506673d9bSGarrett D'Amore switch (num) { 198606673d9bSGarrett D'Amore case MAC_PROP_PRIVATE: 198785025c03Sgd break; 198806673d9bSGarrett D'Amore default: 198906673d9bSGarrett D'Amore return (ENOTSUP); 199006673d9bSGarrett D'Amore } 19917c478bd9Sstevel@tonic-gate 199206673d9bSGarrett D'Amore (void) ddi_strtol(val, NULL, 0, &lval); 199306673d9bSGarrett D'Amore 199406673d9bSGarrett D'Amore if (strcmp(name, "_ipg1") == 0) { 199506673d9bSGarrett D'Amore if ((lval >= 0) && (lval <= 255)) { 199606673d9bSGarrett D'Amore hmep->hme_ipg1 = lval & 0xff; 199706673d9bSGarrett D'Amore init = B_TRUE; 199806673d9bSGarrett D'Amore } else { 199906673d9bSGarrett D'Amore return (EINVAL); 200085025c03Sgd } 20017c478bd9Sstevel@tonic-gate 200206673d9bSGarrett D'Amore } else if (strcmp(name, "_ipg2") == 0) { 200306673d9bSGarrett D'Amore if ((lval >= 0) && (lval <= 255)) { 200406673d9bSGarrett D'Amore hmep->hme_ipg2 = lval & 0xff; 200506673d9bSGarrett D'Amore init = B_TRUE; 200606673d9bSGarrett D'Amore } else { 200706673d9bSGarrett D'Amore return (EINVAL); 200806673d9bSGarrett D'Amore } 20097c478bd9Sstevel@tonic-gate 201006673d9bSGarrett D'Amore } else if (strcmp(name, "_ipg0") == 0) { 201106673d9bSGarrett D'Amore if ((lval >= 0) && (lval <= 31)) { 201206673d9bSGarrett D'Amore hmep->hme_ipg0 = lval & 0xff; 201306673d9bSGarrett D'Amore init = B_TRUE; 201485025c03Sgd } else { 201506673d9bSGarrett D'Amore return (EINVAL); 201606673d9bSGarrett D'Amore } 201706673d9bSGarrett D'Amore } else if (strcmp(name, "_lance_mode") == 0) { 201806673d9bSGarrett D'Amore if ((lval >= 0) && (lval <= 1)) { 201906673d9bSGarrett D'Amore hmep->hme_lance_mode = lval & 0xff; 202006673d9bSGarrett D'Amore init = B_TRUE; 202106673d9bSGarrett D'Amore } else { 202206673d9bSGarrett D'Amore return (EINVAL); 20237c478bd9Sstevel@tonic-gate } 20247c478bd9Sstevel@tonic-gate 202506673d9bSGarrett D'Amore } else { 202606673d9bSGarrett D'Amore rv = ENOTSUP; 202706673d9bSGarrett D'Amore } 202806673d9bSGarrett D'Amore 202906673d9bSGarrett D'Amore if (init) { 203006673d9bSGarrett D'Amore (void) hmeinit(hmep); 20317c478bd9Sstevel@tonic-gate } 203206673d9bSGarrett D'Amore return (rv); 20337c478bd9Sstevel@tonic-gate } 20347c478bd9Sstevel@tonic-gate 203506673d9bSGarrett D'Amore 203685025c03Sgd /*ARGSUSED*/ 203785025c03Sgd static boolean_t 203885025c03Sgd hme_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) 20397c478bd9Sstevel@tonic-gate { 204085025c03Sgd switch (cap) { 204185025c03Sgd case MAC_CAPAB_HCKSUM: 204285025c03Sgd *(uint32_t *)cap_data = HCKSUM_INET_PARTIAL; 204385025c03Sgd return (B_TRUE); 204485025c03Sgd default: 204585025c03Sgd return (B_FALSE); 20467c478bd9Sstevel@tonic-gate } 204785025c03Sgd } 20487c478bd9Sstevel@tonic-gate 204985025c03Sgd static int 205085025c03Sgd hme_m_promisc(void *arg, boolean_t on) 205185025c03Sgd { 205285025c03Sgd struct hme *hmep = arg; 20537c478bd9Sstevel@tonic-gate 205485025c03Sgd hmep->hme_promisc = on; 205585025c03Sgd (void) hmeinit(hmep); 205685025c03Sgd return (0); 205785025c03Sgd } 20587c478bd9Sstevel@tonic-gate 205985025c03Sgd static int 206085025c03Sgd hme_m_unicst(void *arg, const uint8_t *macaddr) 206185025c03Sgd { 206285025c03Sgd struct hme *hmep = arg; 20637c478bd9Sstevel@tonic-gate 20647c478bd9Sstevel@tonic-gate /* 20657c478bd9Sstevel@tonic-gate * Set new interface local address and re-init device. 20667c478bd9Sstevel@tonic-gate * This is destructive to any other streams attached 20677c478bd9Sstevel@tonic-gate * to this device. 20687c478bd9Sstevel@tonic-gate */ 206985025c03Sgd mutex_enter(&hmep->hme_intrlock); 207085025c03Sgd bcopy(macaddr, &hmep->hme_ouraddr, ETHERADDRL); 207185025c03Sgd mutex_exit(&hmep->hme_intrlock); 207285025c03Sgd (void) hmeinit(hmep); 207385025c03Sgd return (0); 20747c478bd9Sstevel@tonic-gate } 20757c478bd9Sstevel@tonic-gate 207685025c03Sgd static int 207785025c03Sgd hme_m_multicst(void *arg, boolean_t add, const uint8_t *macaddr) 20787c478bd9Sstevel@tonic-gate { 207985025c03Sgd struct hme *hmep = arg; 208085025c03Sgd uint32_t ladrf_bit; 208185025c03Sgd boolean_t doinit = B_FALSE; 20827c478bd9Sstevel@tonic-gate 20837c478bd9Sstevel@tonic-gate /* 208485025c03Sgd * If this address's bit was not already set in the local address 208585025c03Sgd * filter, add it and re-initialize the Hardware. 20867c478bd9Sstevel@tonic-gate */ 208785025c03Sgd ladrf_bit = hmeladrf_bit(macaddr); 20887c478bd9Sstevel@tonic-gate 208985025c03Sgd mutex_enter(&hmep->hme_intrlock); 209085025c03Sgd if (add) { 209185025c03Sgd hmep->hme_ladrf_refcnt[ladrf_bit]++; 209285025c03Sgd if (hmep->hme_ladrf_refcnt[ladrf_bit] == 1) { 209385025c03Sgd hmep->hme_ladrf[ladrf_bit >> 4] |= 209485025c03Sgd 1 << (ladrf_bit & 0xf); 209585025c03Sgd hmep->hme_multi++; 209685025c03Sgd doinit = B_TRUE; 209785025c03Sgd } 20987c478bd9Sstevel@tonic-gate } else { 209985025c03Sgd hmep->hme_ladrf_refcnt[ladrf_bit]--; 210085025c03Sgd if (hmep->hme_ladrf_refcnt[ladrf_bit] == 0) { 210185025c03Sgd hmep->hme_ladrf[ladrf_bit >> 4] &= 210285025c03Sgd ~(1 << (ladrf_bit & 0xf)); 210385025c03Sgd doinit = B_TRUE; 21047c478bd9Sstevel@tonic-gate } 21057c478bd9Sstevel@tonic-gate } 210685025c03Sgd mutex_exit(&hmep->hme_intrlock); 21077c478bd9Sstevel@tonic-gate 21080219346bSGarrett D'Amore if (doinit) { 210985025c03Sgd (void) hmeinit(hmep); 21100219346bSGarrett D'Amore } 21117c478bd9Sstevel@tonic-gate 211285025c03Sgd return (0); 21137c478bd9Sstevel@tonic-gate } 21147c478bd9Sstevel@tonic-gate 211585025c03Sgd static int 211685025c03Sgd hme_m_start(void *arg) 21177c478bd9Sstevel@tonic-gate { 211885025c03Sgd struct hme *hmep = arg; 21197c478bd9Sstevel@tonic-gate 2120228fdff0Sgd if (hmeinit(hmep) != 0) { 2121228fdff0Sgd /* initialization failed -- really want DL_INITFAILED */ 2122228fdff0Sgd return (EIO); 2123228fdff0Sgd } else { 2124228fdff0Sgd hmep->hme_started = B_TRUE; 212506673d9bSGarrett D'Amore mii_start(hmep->hme_mii); 2126228fdff0Sgd return (0); 2127228fdff0Sgd } 212885025c03Sgd } 21297c478bd9Sstevel@tonic-gate 213085025c03Sgd static void 213185025c03Sgd hme_m_stop(void *arg) 213285025c03Sgd { 213385025c03Sgd struct hme *hmep = arg; 21347c478bd9Sstevel@tonic-gate 213506673d9bSGarrett D'Amore mii_stop(hmep->hme_mii); 2136228fdff0Sgd hmep->hme_started = B_FALSE; 213785025c03Sgd hmeuninit(hmep); 213885025c03Sgd } 21397c478bd9Sstevel@tonic-gate 214085025c03Sgd static int 214185025c03Sgd hme_m_stat(void *arg, uint_t stat, uint64_t *val) 214285025c03Sgd { 214385025c03Sgd struct hme *hmep = arg; 21447c478bd9Sstevel@tonic-gate 214585025c03Sgd mutex_enter(&hmep->hme_xmitlock); 21464dd87b61Sgd if (hmep->hme_flags & HMERUNNING) { 214785025c03Sgd hmereclaim(hmep); 21484dd87b61Sgd hmesavecntrs(hmep); 21494dd87b61Sgd } 215085025c03Sgd mutex_exit(&hmep->hme_xmitlock); 21517c478bd9Sstevel@tonic-gate 21527c478bd9Sstevel@tonic-gate 215306673d9bSGarrett D'Amore if (mii_m_getstat(hmep->hme_mii, stat, val) == 0) { 215406673d9bSGarrett D'Amore return (0); 215506673d9bSGarrett D'Amore } 215685025c03Sgd switch (stat) { 215785025c03Sgd case MAC_STAT_IPACKETS: 215885025c03Sgd *val = hmep->hme_ipackets; 215985025c03Sgd break; 216085025c03Sgd case MAC_STAT_RBYTES: 216185025c03Sgd *val = hmep->hme_rbytes; 216285025c03Sgd break; 216385025c03Sgd case MAC_STAT_IERRORS: 216485025c03Sgd *val = hmep->hme_ierrors; 216585025c03Sgd break; 216685025c03Sgd case MAC_STAT_OPACKETS: 216785025c03Sgd *val = hmep->hme_opackets; 216885025c03Sgd break; 216985025c03Sgd case MAC_STAT_OBYTES: 217085025c03Sgd *val = hmep->hme_obytes; 217185025c03Sgd break; 217285025c03Sgd case MAC_STAT_OERRORS: 217385025c03Sgd *val = hmep->hme_oerrors; 217485025c03Sgd break; 217585025c03Sgd case MAC_STAT_MULTIRCV: 217685025c03Sgd *val = hmep->hme_multircv; 217785025c03Sgd break; 217885025c03Sgd case MAC_STAT_MULTIXMT: 217985025c03Sgd *val = hmep->hme_multixmt; 218085025c03Sgd break; 218185025c03Sgd case MAC_STAT_BRDCSTRCV: 218285025c03Sgd *val = hmep->hme_brdcstrcv; 218385025c03Sgd break; 218485025c03Sgd case MAC_STAT_BRDCSTXMT: 218585025c03Sgd *val = hmep->hme_brdcstxmt; 218685025c03Sgd break; 218785025c03Sgd case MAC_STAT_UNDERFLOWS: 218885025c03Sgd *val = hmep->hme_uflo; 218985025c03Sgd break; 219085025c03Sgd case MAC_STAT_OVERFLOWS: 219185025c03Sgd *val = hmep->hme_oflo; 219285025c03Sgd break; 219385025c03Sgd case MAC_STAT_COLLISIONS: 219485025c03Sgd *val = hmep->hme_coll; 219585025c03Sgd break; 219685025c03Sgd case MAC_STAT_NORCVBUF: 219785025c03Sgd *val = hmep->hme_norcvbuf; 219885025c03Sgd break; 219985025c03Sgd case MAC_STAT_NOXMTBUF: 220085025c03Sgd *val = hmep->hme_noxmtbuf; 220185025c03Sgd break; 220285025c03Sgd case ETHER_STAT_LINK_DUPLEX: 220385025c03Sgd *val = hmep->hme_duplex; 220485025c03Sgd break; 220585025c03Sgd case ETHER_STAT_ALIGN_ERRORS: 220685025c03Sgd *val = hmep->hme_align_errors; 220785025c03Sgd break; 220885025c03Sgd case ETHER_STAT_FCS_ERRORS: 220985025c03Sgd *val = hmep->hme_fcs_errors; 221085025c03Sgd break; 221185025c03Sgd case ETHER_STAT_EX_COLLISIONS: 221285025c03Sgd *val = hmep->hme_excol; 221385025c03Sgd break; 221485025c03Sgd case ETHER_STAT_DEFER_XMTS: 221585025c03Sgd *val = hmep->hme_defer_xmts; 221685025c03Sgd break; 221785025c03Sgd case ETHER_STAT_SQE_ERRORS: 221885025c03Sgd *val = hmep->hme_sqe_errors; 221985025c03Sgd break; 222085025c03Sgd case ETHER_STAT_FIRST_COLLISIONS: 222185025c03Sgd *val = hmep->hme_fstcol; 222285025c03Sgd break; 222385025c03Sgd case ETHER_STAT_TX_LATE_COLLISIONS: 222485025c03Sgd *val = hmep->hme_tlcol; 222585025c03Sgd break; 222685025c03Sgd case ETHER_STAT_TOOLONG_ERRORS: 222785025c03Sgd *val = hmep->hme_toolong_errors; 222885025c03Sgd break; 222985025c03Sgd case ETHER_STAT_TOOSHORT_ERRORS: 223085025c03Sgd *val = hmep->hme_runt; 223185025c03Sgd break; 22324dd87b61Sgd case ETHER_STAT_CARRIER_ERRORS: 22334dd87b61Sgd *val = hmep->hme_carrier_errors; 22344dd87b61Sgd break; 223585025c03Sgd default: 223685025c03Sgd return (EINVAL); 22377c478bd9Sstevel@tonic-gate } 223885025c03Sgd return (0); 22397c478bd9Sstevel@tonic-gate } 22407c478bd9Sstevel@tonic-gate 224185025c03Sgd static mblk_t * 224285025c03Sgd hme_m_tx(void *arg, mblk_t *mp) 22437c478bd9Sstevel@tonic-gate { 224485025c03Sgd struct hme *hmep = arg; 224585025c03Sgd mblk_t *next; 22467c478bd9Sstevel@tonic-gate 224785025c03Sgd while (mp != NULL) { 224885025c03Sgd next = mp->b_next; 224985025c03Sgd mp->b_next = NULL; 225085025c03Sgd if (!hmestart(hmep, mp)) { 225185025c03Sgd mp->b_next = next; 225285025c03Sgd break; 22537c478bd9Sstevel@tonic-gate } 225485025c03Sgd mp = next; 22557c478bd9Sstevel@tonic-gate } 225685025c03Sgd return (mp); 22577c478bd9Sstevel@tonic-gate } 22587c478bd9Sstevel@tonic-gate 2259eb7b3d20Sgd /* 2260eb7b3d20Sgd * Software IP checksum, for the edge cases that the 2261eb7b3d20Sgd * hardware can't handle. See hmestart for more info. 2262eb7b3d20Sgd */ 2263eb7b3d20Sgd static uint16_t 2264eb7b3d20Sgd hme_cksum(void *data, int len) 2265eb7b3d20Sgd { 2266eb7b3d20Sgd uint16_t *words = data; 2267eb7b3d20Sgd int i, nwords = len / 2; 2268eb7b3d20Sgd uint32_t sum = 0; 2269eb7b3d20Sgd 2270eb7b3d20Sgd /* just add up the words */ 2271eb7b3d20Sgd for (i = 0; i < nwords; i++) { 2272eb7b3d20Sgd sum += *words++; 2273eb7b3d20Sgd } 2274eb7b3d20Sgd 2275eb7b3d20Sgd /* pick up residual byte ... assume even half-word allocations */ 2276eb7b3d20Sgd if (len % 2) { 22770219346bSGarrett D'Amore sum += (*words & htons(0xff00)); 2278eb7b3d20Sgd } 2279eb7b3d20Sgd 2280eb7b3d20Sgd sum = (sum >> 16) + (sum & 0xffff); 2281eb7b3d20Sgd sum = (sum >> 16) + (sum & 0xffff); 2282eb7b3d20Sgd 2283eb7b3d20Sgd return (~(sum & 0xffff)); 2284eb7b3d20Sgd } 2285eb7b3d20Sgd 228685025c03Sgd static boolean_t 22870219346bSGarrett D'Amore hmestart(struct hme *hmep, mblk_t *mp) 22887c478bd9Sstevel@tonic-gate { 22890219346bSGarrett D'Amore uint32_t len; 22900219346bSGarrett D'Amore boolean_t retval = B_TRUE; 22910219346bSGarrett D'Amore hmebuf_t *tbuf; 22920219346bSGarrett D'Amore uint32_t txptr; 22937c478bd9Sstevel@tonic-gate 229485025c03Sgd uint32_t csflags = 0; 229585025c03Sgd uint32_t flags; 229685025c03Sgd uint32_t start_offset; 229785025c03Sgd uint32_t stuff_offset; 22987c478bd9Sstevel@tonic-gate 22990dc2366fSVenugopal Iyer mac_hcksum_get(mp, &start_offset, &stuff_offset, NULL, NULL, &flags); 23007c478bd9Sstevel@tonic-gate 230185025c03Sgd if (flags & HCK_PARTIALCKSUM) { 230285025c03Sgd if (get_ether_type(mp->b_rptr) == ETHERTYPE_VLAN) { 230385025c03Sgd start_offset += sizeof (struct ether_header) + 4; 230485025c03Sgd stuff_offset += sizeof (struct ether_header) + 4; 230585025c03Sgd } else { 230685025c03Sgd start_offset += sizeof (struct ether_header); 230785025c03Sgd stuff_offset += sizeof (struct ether_header); 23087c478bd9Sstevel@tonic-gate } 230985025c03Sgd csflags = HMETMD_CSENABL | 231085025c03Sgd (start_offset << HMETMD_CSSTART_SHIFT) | 231185025c03Sgd (stuff_offset << HMETMD_CSSTUFF_SHIFT); 231285025c03Sgd } 23137c478bd9Sstevel@tonic-gate 23147c478bd9Sstevel@tonic-gate mutex_enter(&hmep->hme_xmitlock); 23157c478bd9Sstevel@tonic-gate 23164dd87b61Sgd if (hmep->hme_flags & HMESUSPENDED) { 23174dd87b61Sgd hmep->hme_carrier_errors++; 23184dd87b61Sgd hmep->hme_oerrors++; 23194dd87b61Sgd goto bad; 23204dd87b61Sgd } 23214dd87b61Sgd 23220219346bSGarrett D'Amore if (hmep->hme_txindex != hmep->hme_txreclaim) { 23230219346bSGarrett D'Amore hmereclaim(hmep); 23247c478bd9Sstevel@tonic-gate } 23250219346bSGarrett D'Amore if ((hmep->hme_txindex - HME_TMDMAX) == hmep->hme_txreclaim) 23267c478bd9Sstevel@tonic-gate goto notmds; 23270219346bSGarrett D'Amore txptr = hmep->hme_txindex % HME_TMDMAX; 23280219346bSGarrett D'Amore tbuf = &hmep->hme_tbuf[txptr]; 23297c478bd9Sstevel@tonic-gate 2330eb7b3d20Sgd /* 2331eb7b3d20Sgd * Note that for checksum offload, the hardware cannot 2332eb7b3d20Sgd * generate correct checksums if the packet is smaller than 2333eb7b3d20Sgd * 64-bytes. In such a case, we bcopy the packet and use 2334eb7b3d20Sgd * a software checksum. 2335eb7b3d20Sgd */ 2336eb7b3d20Sgd 23370219346bSGarrett D'Amore len = msgsize(mp); 23380219346bSGarrett D'Amore if (len < 64) { 23390219346bSGarrett D'Amore /* zero fill the padding */ 23400219346bSGarrett D'Amore bzero(tbuf->kaddr, 64); 23417c478bd9Sstevel@tonic-gate } 23420219346bSGarrett D'Amore mcopymsg(mp, tbuf->kaddr); 23437c478bd9Sstevel@tonic-gate 2344*7a92e70fSZeeshanul Huq - Sun Microsystems - Beijing China if ((csflags != 0) && ((len < 64) || 2345*7a92e70fSZeeshanul Huq - Sun Microsystems - Beijing China (start_offset > HMETMD_CSSTART_MAX) || 2346*7a92e70fSZeeshanul Huq - Sun Microsystems - Beijing China (stuff_offset > HMETMD_CSSTUFF_MAX))) { 23470219346bSGarrett D'Amore uint16_t sum; 23480219346bSGarrett D'Amore sum = hme_cksum(tbuf->kaddr + start_offset, 23490219346bSGarrett D'Amore len - start_offset); 23500219346bSGarrett D'Amore bcopy(&sum, tbuf->kaddr + stuff_offset, sizeof (sum)); 23510219346bSGarrett D'Amore csflags = 0; 23527c478bd9Sstevel@tonic-gate } 23537c478bd9Sstevel@tonic-gate 23540219346bSGarrett D'Amore if (ddi_dma_sync(tbuf->dmah, 0, len, DDI_DMA_SYNC_FORDEV) == 23550219346bSGarrett D'Amore DDI_FAILURE) { 23567c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_HIGH, DDI_MSG, 235785025c03Sgd "ddi_dma_sync failed"); 23587c478bd9Sstevel@tonic-gate } 23597c478bd9Sstevel@tonic-gate 23600219346bSGarrett D'Amore /* 23610219346bSGarrett D'Amore * update MIB II statistics 23620219346bSGarrett D'Amore */ 23630219346bSGarrett D'Amore BUMP_OutNUcast(hmep, tbuf->kaddr); 23640219346bSGarrett D'Amore 23650219346bSGarrett D'Amore PUT_TMD(txptr, tbuf->paddr, len, 23660219346bSGarrett D'Amore HMETMD_OWN | HMETMD_SOP | HMETMD_EOP | csflags); 23677c478bd9Sstevel@tonic-gate 23680219346bSGarrett D'Amore HMESYNCTMD(txptr, DDI_DMA_SYNC_FORDEV); 23690219346bSGarrett D'Amore hmep->hme_txindex++; 23707c478bd9Sstevel@tonic-gate 23717c478bd9Sstevel@tonic-gate PUT_ETXREG(txpend, HMET_TXPEND_TDMD); 23727c478bd9Sstevel@tonic-gate CHECK_ETXREG(); 23737c478bd9Sstevel@tonic-gate 23747c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_xmitlock); 23757c478bd9Sstevel@tonic-gate 23767c478bd9Sstevel@tonic-gate hmep->hme_starts++; 237785025c03Sgd return (B_TRUE); 23787c478bd9Sstevel@tonic-gate 23797c478bd9Sstevel@tonic-gate bad: 23807c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_xmitlock); 23817c478bd9Sstevel@tonic-gate freemsg(mp); 238285025c03Sgd return (B_TRUE); 23837c478bd9Sstevel@tonic-gate 23847c478bd9Sstevel@tonic-gate notmds: 23857c478bd9Sstevel@tonic-gate hmep->hme_notmds++; 238685025c03Sgd hmep->hme_wantw = B_TRUE; 23877c478bd9Sstevel@tonic-gate hmereclaim(hmep); 238885025c03Sgd retval = B_FALSE; 23897c478bd9Sstevel@tonic-gate done: 23907c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_xmitlock); 23917c478bd9Sstevel@tonic-gate 239285025c03Sgd return (retval); 23937c478bd9Sstevel@tonic-gate } 23947c478bd9Sstevel@tonic-gate 23957c478bd9Sstevel@tonic-gate /* 23967c478bd9Sstevel@tonic-gate * Initialize channel. 23977c478bd9Sstevel@tonic-gate * Return 0 on success, nonzero on error. 23987c478bd9Sstevel@tonic-gate * 23997c478bd9Sstevel@tonic-gate * The recommended sequence for initialization is: 24007c478bd9Sstevel@tonic-gate * 1. Issue a Global Reset command to the Ethernet Channel. 24017c478bd9Sstevel@tonic-gate * 2. Poll the Global_Reset bits until the execution of the reset has been 24027c478bd9Sstevel@tonic-gate * completed. 24037c478bd9Sstevel@tonic-gate * 2(a). Use the MIF Frame/Output register to reset the transceiver. 24047c478bd9Sstevel@tonic-gate * Poll Register 0 to till the Resetbit is 0. 24057c478bd9Sstevel@tonic-gate * 2(b). Use the MIF Frame/Output register to set the PHY in in Normal-Op, 24067c478bd9Sstevel@tonic-gate * 100Mbps and Non-Isolated mode. The main point here is to bring the 24077c478bd9Sstevel@tonic-gate * PHY out of Isolate mode so that it can generate the rx_clk and tx_clk 24087c478bd9Sstevel@tonic-gate * to the MII interface so that the Bigmac core can correctly reset 24097c478bd9Sstevel@tonic-gate * upon a software reset. 24107c478bd9Sstevel@tonic-gate * 2(c). Issue another Global Reset command to the Ethernet Channel and poll 24117c478bd9Sstevel@tonic-gate * the Global_Reset bits till completion. 24127c478bd9Sstevel@tonic-gate * 3. Set up all the data structures in the host memory. 24137c478bd9Sstevel@tonic-gate * 4. Program the TX_MAC registers/counters (excluding the TX_MAC Configuration 24147c478bd9Sstevel@tonic-gate * Register). 24157c478bd9Sstevel@tonic-gate * 5. Program the RX_MAC registers/counters (excluding the RX_MAC Configuration 24167c478bd9Sstevel@tonic-gate * Register). 24177c478bd9Sstevel@tonic-gate * 6. Program the Transmit Descriptor Ring Base Address in the ETX. 24187c478bd9Sstevel@tonic-gate * 7. Program the Receive Descriptor Ring Base Address in the ERX. 24197c478bd9Sstevel@tonic-gate * 8. Program the Global Configuration and the Global Interrupt Mask Registers. 24207c478bd9Sstevel@tonic-gate * 9. Program the ETX Configuration register (enable the Transmit DMA channel). 24217c478bd9Sstevel@tonic-gate * 10. Program the ERX Configuration register (enable the Receive DMA channel). 24227c478bd9Sstevel@tonic-gate * 11. Program the XIF Configuration Register (enable the XIF). 24237c478bd9Sstevel@tonic-gate * 12. Program the RX_MAC Configuration Register (Enable the RX_MAC). 24247c478bd9Sstevel@tonic-gate * 13. Program the TX_MAC Configuration Register (Enable the TX_MAC). 24257c478bd9Sstevel@tonic-gate */ 24267c478bd9Sstevel@tonic-gate 24277c478bd9Sstevel@tonic-gate 24287c478bd9Sstevel@tonic-gate #ifdef FEPS_URUN_BUG 24297c478bd9Sstevel@tonic-gate static int hme_palen = 32; 24307c478bd9Sstevel@tonic-gate #endif 24317c478bd9Sstevel@tonic-gate 24327c478bd9Sstevel@tonic-gate static int 24337c478bd9Sstevel@tonic-gate hmeinit(struct hme *hmep) 24347c478bd9Sstevel@tonic-gate { 24350219346bSGarrett D'Amore uint32_t i; 24360219346bSGarrett D'Amore int ret; 243706673d9bSGarrett D'Amore boolean_t fdx; 243806673d9bSGarrett D'Amore int phyad; 24397c478bd9Sstevel@tonic-gate 244085025c03Sgd /* 244185025c03Sgd * Lock sequence: 244285025c03Sgd * hme_intrlock, hme_xmitlock. 244385025c03Sgd */ 244485025c03Sgd mutex_enter(&hmep->hme_intrlock); 24457c478bd9Sstevel@tonic-gate 24467c478bd9Sstevel@tonic-gate /* 244785025c03Sgd * Don't touch the hardware if we are suspended. But don't 244885025c03Sgd * fail either. Some time later we may be resumed, and then 244985025c03Sgd * we'll be back here to program the device using the settings 245085025c03Sgd * in the soft state. 24517c478bd9Sstevel@tonic-gate */ 245285025c03Sgd if (hmep->hme_flags & HMESUSPENDED) { 245385025c03Sgd mutex_exit(&hmep->hme_intrlock); 245485025c03Sgd return (0); 245585025c03Sgd } 24567c478bd9Sstevel@tonic-gate 24577c478bd9Sstevel@tonic-gate /* 245885025c03Sgd * This should prevent us from clearing any interrupts that 245985025c03Sgd * may occur by temporarily stopping interrupts from occurring 246085025c03Sgd * for a short time. We need to update the interrupt mask 246185025c03Sgd * later in this function. 24627c478bd9Sstevel@tonic-gate */ 246385025c03Sgd PUT_GLOBREG(intmask, ~HMEG_MASK_MIF_INTR); 24647c478bd9Sstevel@tonic-gate 24657c478bd9Sstevel@tonic-gate 24667c478bd9Sstevel@tonic-gate /* 24677c478bd9Sstevel@tonic-gate * Rearranged the mutex acquisition order to solve the deadlock 24687c478bd9Sstevel@tonic-gate * situation as described in bug ID 4065896. 24697c478bd9Sstevel@tonic-gate */ 24707c478bd9Sstevel@tonic-gate 24717c478bd9Sstevel@tonic-gate mutex_enter(&hmep->hme_xmitlock); 24727c478bd9Sstevel@tonic-gate 24737c478bd9Sstevel@tonic-gate hmep->hme_flags = 0; 247485025c03Sgd hmep->hme_wantw = B_FALSE; 24757c478bd9Sstevel@tonic-gate 24767c478bd9Sstevel@tonic-gate if (hmep->inits) 24777c478bd9Sstevel@tonic-gate hmesavecntrs(hmep); 24787c478bd9Sstevel@tonic-gate 24797c478bd9Sstevel@tonic-gate /* 24807c478bd9Sstevel@tonic-gate * Perform Global reset of the Sbus/FEPS ENET channel. 24817c478bd9Sstevel@tonic-gate */ 24827c478bd9Sstevel@tonic-gate (void) hmestop(hmep); 24837c478bd9Sstevel@tonic-gate 24847c478bd9Sstevel@tonic-gate /* 24857c478bd9Sstevel@tonic-gate * Clear all descriptors. 24867c478bd9Sstevel@tonic-gate */ 24877c478bd9Sstevel@tonic-gate bzero(hmep->hme_rmdp, HME_RMDMAX * sizeof (struct hme_rmd)); 24887c478bd9Sstevel@tonic-gate bzero(hmep->hme_tmdp, HME_TMDMAX * sizeof (struct hme_tmd)); 24897c478bd9Sstevel@tonic-gate 24907c478bd9Sstevel@tonic-gate /* 24917c478bd9Sstevel@tonic-gate * Hang out receive buffers. 24927c478bd9Sstevel@tonic-gate */ 24930219346bSGarrett D'Amore for (i = 0; i < HME_RMDMAX; i++) { 24940219346bSGarrett D'Amore PUT_RMD(i, hmep->hme_rbuf[i].paddr); 24957c478bd9Sstevel@tonic-gate } 24967c478bd9Sstevel@tonic-gate 24977c478bd9Sstevel@tonic-gate /* 24987c478bd9Sstevel@tonic-gate * DMA sync descriptors. 24997c478bd9Sstevel@tonic-gate */ 25000219346bSGarrett D'Amore (void) ddi_dma_sync(hmep->hme_rmd_dmah, 0, 0, DDI_DMA_SYNC_FORDEV); 25010219346bSGarrett D'Amore (void) ddi_dma_sync(hmep->hme_tmd_dmah, 0, 0, DDI_DMA_SYNC_FORDEV); 25027c478bd9Sstevel@tonic-gate 25037c478bd9Sstevel@tonic-gate /* 25047c478bd9Sstevel@tonic-gate * Reset RMD and TMD 'walking' pointers. 25057c478bd9Sstevel@tonic-gate */ 25060219346bSGarrett D'Amore hmep->hme_rxindex = 0; 25070219346bSGarrett D'Amore hmep->hme_txindex = hmep->hme_txreclaim = 0; 25087c478bd9Sstevel@tonic-gate 25097c478bd9Sstevel@tonic-gate /* 25107c478bd9Sstevel@tonic-gate * This is the right place to initialize MIF !!! 25117c478bd9Sstevel@tonic-gate */ 25127c478bd9Sstevel@tonic-gate 25137c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_imask, HME_MIF_INTMASK); /* mask all interrupts */ 25147c478bd9Sstevel@tonic-gate 25157c478bd9Sstevel@tonic-gate if (!hmep->hme_frame_enable) 25167c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_cfg, GET_MIFREG(mif_cfg) | HME_MIF_CFGBB); 25177c478bd9Sstevel@tonic-gate else 25187c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_cfg, GET_MIFREG(mif_cfg) & ~HME_MIF_CFGBB); 25197c478bd9Sstevel@tonic-gate /* enable frame mode */ 25207c478bd9Sstevel@tonic-gate 25217c478bd9Sstevel@tonic-gate /* 25227c478bd9Sstevel@tonic-gate * Depending on the transceiver detected, select the source 25237c478bd9Sstevel@tonic-gate * of the clocks for the MAC. Without the clocks, TX_MAC does 25247c478bd9Sstevel@tonic-gate * not reset. When the Global Reset is issued to the Sbus/FEPS 25257c478bd9Sstevel@tonic-gate * ASIC, it selects Internal by default. 25267c478bd9Sstevel@tonic-gate */ 25277c478bd9Sstevel@tonic-gate 252806673d9bSGarrett D'Amore switch ((phyad = mii_get_addr(hmep->hme_mii))) { 252906673d9bSGarrett D'Amore case -1: 25307c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_HIGH, XCVR_MSG, no_xcvr_msg); 25317c478bd9Sstevel@tonic-gate goto init_fail; /* abort initialization */ 25327c478bd9Sstevel@tonic-gate 253306673d9bSGarrett D'Amore case HME_INTERNAL_PHYAD: 25347c478bd9Sstevel@tonic-gate PUT_MACREG(xifc, 0); 253506673d9bSGarrett D'Amore break; 253606673d9bSGarrett D'Amore case HME_EXTERNAL_PHYAD: 253706673d9bSGarrett D'Amore /* Isolate the Int. xcvr */ 25387c478bd9Sstevel@tonic-gate PUT_MACREG(xifc, BMAC_XIFC_MIIBUFDIS); 253906673d9bSGarrett D'Amore break; 25407c478bd9Sstevel@tonic-gate } 254106673d9bSGarrett D'Amore 25427c478bd9Sstevel@tonic-gate hmep->inits++; 25437c478bd9Sstevel@tonic-gate 25447c478bd9Sstevel@tonic-gate /* 25457c478bd9Sstevel@tonic-gate * Initialize BigMAC registers. 25467c478bd9Sstevel@tonic-gate * First set the tx enable bit in tx config reg to 0 and poll on 25477c478bd9Sstevel@tonic-gate * it till it turns to 0. Same for rx config, hash and address 25487c478bd9Sstevel@tonic-gate * filter reg. 25497c478bd9Sstevel@tonic-gate * Here is the sequence per the spec. 25507c478bd9Sstevel@tonic-gate * MADD2 - MAC Address 2 25517c478bd9Sstevel@tonic-gate * MADD1 - MAC Address 1 25527c478bd9Sstevel@tonic-gate * MADD0 - MAC Address 0 25537c478bd9Sstevel@tonic-gate * HASH3, HASH2, HASH1, HASH0 for group address 25547c478bd9Sstevel@tonic-gate * AFR2, AFR1, AFR0 and AFMR for address filter mask 25557c478bd9Sstevel@tonic-gate * Program RXMIN and RXMAX for packet length if not 802.3 25567c478bd9Sstevel@tonic-gate * RXCFG - Rx config for not stripping CRC 25577c478bd9Sstevel@tonic-gate * XXX Anything else to hme configured in RXCFG 25587c478bd9Sstevel@tonic-gate * IPG1, IPG2, ALIMIT, SLOT, PALEN, PAPAT, TXSFD, JAM, TXMAX, TXMIN 25597c478bd9Sstevel@tonic-gate * if not 802.3 compliant 25607c478bd9Sstevel@tonic-gate * XIF register for speed selection 25617c478bd9Sstevel@tonic-gate * MASK - Interrupt mask 25627c478bd9Sstevel@tonic-gate * Set bit 0 of TXCFG 25637c478bd9Sstevel@tonic-gate * Set bit 0 of RXCFG 25647c478bd9Sstevel@tonic-gate */ 25657c478bd9Sstevel@tonic-gate 25667c478bd9Sstevel@tonic-gate /* 25677c478bd9Sstevel@tonic-gate * Initialize the TX_MAC registers 25687c478bd9Sstevel@tonic-gate * Initialization of jamsize to work around rx crc bug 25697c478bd9Sstevel@tonic-gate */ 25707c478bd9Sstevel@tonic-gate PUT_MACREG(jam, jamsize); 25717c478bd9Sstevel@tonic-gate 25727c478bd9Sstevel@tonic-gate #ifdef FEPS_URUN_BUG 25737c478bd9Sstevel@tonic-gate if (hme_urun_fix) 25747c478bd9Sstevel@tonic-gate PUT_MACREG(palen, hme_palen); 25757c478bd9Sstevel@tonic-gate #endif 25767c478bd9Sstevel@tonic-gate 257706673d9bSGarrett D'Amore PUT_MACREG(ipg1, hmep->hme_ipg1); 257806673d9bSGarrett D'Amore PUT_MACREG(ipg2, hmep->hme_ipg2); 25797c478bd9Sstevel@tonic-gate 25807c478bd9Sstevel@tonic-gate PUT_MACREG(rseed, 258185025c03Sgd ((hmep->hme_ouraddr.ether_addr_octet[0] << 8) & 0x3) | 258285025c03Sgd hmep->hme_ouraddr.ether_addr_octet[1]); 25837c478bd9Sstevel@tonic-gate 25847c478bd9Sstevel@tonic-gate /* Initialize the RX_MAC registers */ 25857c478bd9Sstevel@tonic-gate 25867c478bd9Sstevel@tonic-gate /* 25877c478bd9Sstevel@tonic-gate * Program BigMAC with local individual ethernet address. 25887c478bd9Sstevel@tonic-gate */ 25897c478bd9Sstevel@tonic-gate PUT_MACREG(madd2, (hmep->hme_ouraddr.ether_addr_octet[4] << 8) | 259085025c03Sgd hmep->hme_ouraddr.ether_addr_octet[5]); 25917c478bd9Sstevel@tonic-gate PUT_MACREG(madd1, (hmep->hme_ouraddr.ether_addr_octet[2] << 8) | 259285025c03Sgd hmep->hme_ouraddr.ether_addr_octet[3]); 25937c478bd9Sstevel@tonic-gate PUT_MACREG(madd0, (hmep->hme_ouraddr.ether_addr_octet[0] << 8) | 259485025c03Sgd hmep->hme_ouraddr.ether_addr_octet[1]); 25957c478bd9Sstevel@tonic-gate 25967c478bd9Sstevel@tonic-gate /* 25977c478bd9Sstevel@tonic-gate * Set up multicast address filter by passing all multicast 25987c478bd9Sstevel@tonic-gate * addresses through a crc generator, and then using the 25997c478bd9Sstevel@tonic-gate * low order 6 bits as a index into the 64 bit logical 26007c478bd9Sstevel@tonic-gate * address filter. The high order three bits select the word, 26017c478bd9Sstevel@tonic-gate * while the rest of the bits select the bit within the word. 26027c478bd9Sstevel@tonic-gate */ 260385025c03Sgd PUT_MACREG(hash0, hmep->hme_ladrf[0]); 260485025c03Sgd PUT_MACREG(hash1, hmep->hme_ladrf[1]); 260585025c03Sgd PUT_MACREG(hash2, hmep->hme_ladrf[2]); 260685025c03Sgd PUT_MACREG(hash3, hmep->hme_ladrf[3]); 26077c478bd9Sstevel@tonic-gate 26087c478bd9Sstevel@tonic-gate /* 260985025c03Sgd * Configure parameters to support VLAN. (VLAN encapsulation adds 261085025c03Sgd * four bytes.) 26117c478bd9Sstevel@tonic-gate */ 261285025c03Sgd PUT_MACREG(txmax, ETHERMAX + ETHERFCSL + 4); 261385025c03Sgd PUT_MACREG(rxmax, ETHERMAX + ETHERFCSL + 4); 26147c478bd9Sstevel@tonic-gate 26157c478bd9Sstevel@tonic-gate /* 26167c478bd9Sstevel@tonic-gate * Initialize HME Global registers, ETX registers and ERX registers. 26177c478bd9Sstevel@tonic-gate */ 26187c478bd9Sstevel@tonic-gate 26190219346bSGarrett D'Amore PUT_ETXREG(txring, hmep->hme_tmd_paddr); 26200219346bSGarrett D'Amore PUT_ERXREG(rxring, hmep->hme_rmd_paddr); 26217c478bd9Sstevel@tonic-gate 26227c478bd9Sstevel@tonic-gate /* 26237c478bd9Sstevel@tonic-gate * ERX registers can be written only if they have even no. of bits set. 26247c478bd9Sstevel@tonic-gate * So, if the value written is not read back, set the lsb and write 26257c478bd9Sstevel@tonic-gate * again. 26267c478bd9Sstevel@tonic-gate * static int hme_erx_fix = 1; : Use the fix for erx bug 26277c478bd9Sstevel@tonic-gate */ 26287c478bd9Sstevel@tonic-gate { 26297c478bd9Sstevel@tonic-gate uint32_t temp; 26300219346bSGarrett D'Amore temp = hmep->hme_rmd_paddr; 26317c478bd9Sstevel@tonic-gate 26327c478bd9Sstevel@tonic-gate if (GET_ERXREG(rxring) != temp) 26337c478bd9Sstevel@tonic-gate PUT_ERXREG(rxring, (temp | 4)); 26347c478bd9Sstevel@tonic-gate } 26357c478bd9Sstevel@tonic-gate 263685025c03Sgd PUT_GLOBREG(config, (hmep->hme_config | 263785025c03Sgd (hmep->hme_64bit_xfer << HMEG_CONFIG_64BIT_SHIFT))); 26387c478bd9Sstevel@tonic-gate 26397c478bd9Sstevel@tonic-gate /* 26407c478bd9Sstevel@tonic-gate * Significant performance improvements can be achieved by 26417c478bd9Sstevel@tonic-gate * disabling transmit interrupt. Thus TMD's are reclaimed only 26427c478bd9Sstevel@tonic-gate * when we run out of them in hmestart(). 26437c478bd9Sstevel@tonic-gate */ 26447c478bd9Sstevel@tonic-gate PUT_GLOBREG(intmask, 264585025c03Sgd HMEG_MASK_INTR | HMEG_MASK_TINT | HMEG_MASK_TX_ALL); 26467c478bd9Sstevel@tonic-gate 26477c478bd9Sstevel@tonic-gate PUT_ETXREG(txring_size, ((HME_TMDMAX -1)>> HMET_RINGSZ_SHIFT)); 26487c478bd9Sstevel@tonic-gate PUT_ETXREG(config, (GET_ETXREG(config) | HMET_CONFIG_TXDMA_EN 264985025c03Sgd | HMET_CONFIG_TXFIFOTH)); 26507c478bd9Sstevel@tonic-gate /* get the rxring size bits */ 26517c478bd9Sstevel@tonic-gate switch (HME_RMDMAX) { 26527c478bd9Sstevel@tonic-gate case 32: 26537c478bd9Sstevel@tonic-gate i = HMER_CONFIG_RXRINGSZ32; 26547c478bd9Sstevel@tonic-gate break; 26557c478bd9Sstevel@tonic-gate case 64: 26567c478bd9Sstevel@tonic-gate i = HMER_CONFIG_RXRINGSZ64; 26577c478bd9Sstevel@tonic-gate break; 26587c478bd9Sstevel@tonic-gate case 128: 26597c478bd9Sstevel@tonic-gate i = HMER_CONFIG_RXRINGSZ128; 26607c478bd9Sstevel@tonic-gate break; 26617c478bd9Sstevel@tonic-gate case 256: 26627c478bd9Sstevel@tonic-gate i = HMER_CONFIG_RXRINGSZ256; 26637c478bd9Sstevel@tonic-gate break; 26647c478bd9Sstevel@tonic-gate default: 26657c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 266685025c03Sgd unk_rx_ringsz_msg); 26677c478bd9Sstevel@tonic-gate goto init_fail; 26687c478bd9Sstevel@tonic-gate } 26697c478bd9Sstevel@tonic-gate i |= (HME_FSTBYTE_OFFSET << HMER_CONFIG_FBO_SHIFT) 267085025c03Sgd | HMER_CONFIG_RXDMA_EN; 267185025c03Sgd 267285025c03Sgd /* h/w checks start offset in half words */ 267385025c03Sgd i |= ((sizeof (struct ether_header) / 2) << HMER_RX_CSSTART_SHIFT); 267485025c03Sgd 26757c478bd9Sstevel@tonic-gate PUT_ERXREG(config, i); 26767c478bd9Sstevel@tonic-gate 26777c478bd9Sstevel@tonic-gate /* 26787c478bd9Sstevel@tonic-gate * Bug related to the parity handling in ERX. When erxp-config is 26797c478bd9Sstevel@tonic-gate * read back. 26807c478bd9Sstevel@tonic-gate * Sbus/FEPS drives the parity bit. This value is used while 26817c478bd9Sstevel@tonic-gate * writing again. 26827c478bd9Sstevel@tonic-gate * This fixes the RECV problem in SS5. 26837c478bd9Sstevel@tonic-gate * static int hme_erx_fix = 1; : Use the fix for erx bug 26847c478bd9Sstevel@tonic-gate */ 26857c478bd9Sstevel@tonic-gate { 26867c478bd9Sstevel@tonic-gate uint32_t temp; 26877c478bd9Sstevel@tonic-gate temp = GET_ERXREG(config); 26887c478bd9Sstevel@tonic-gate PUT_ERXREG(config, i); 26897c478bd9Sstevel@tonic-gate 26907c478bd9Sstevel@tonic-gate if (GET_ERXREG(config) != i) 26917c478bd9Sstevel@tonic-gate HME_FAULT_MSG4(hmep, SEVERITY_UNKNOWN, ERX_MSG, 269285025c03Sgd "error:temp = %x erxp->config = %x, should be %x", 269385025c03Sgd temp, GET_ERXREG(config), i); 26947c478bd9Sstevel@tonic-gate } 26957c478bd9Sstevel@tonic-gate 26967c478bd9Sstevel@tonic-gate /* 26977c478bd9Sstevel@tonic-gate * Set up the rxconfig, txconfig and seed register without enabling 26987c478bd9Sstevel@tonic-gate * them the former two at this time 26997c478bd9Sstevel@tonic-gate * 27007c478bd9Sstevel@tonic-gate * BigMAC strips the CRC bytes by default. Since this is 27017c478bd9Sstevel@tonic-gate * contrary to other pieces of hardware, this bit needs to 27027c478bd9Sstevel@tonic-gate * enabled to tell BigMAC not to strip the CRC bytes. 27037c478bd9Sstevel@tonic-gate * Do not filter this node's own packets. 27047c478bd9Sstevel@tonic-gate */ 27057c478bd9Sstevel@tonic-gate 27067c478bd9Sstevel@tonic-gate if (hme_reject_own) { 27077c478bd9Sstevel@tonic-gate PUT_MACREG(rxcfg, 2708228fdff0Sgd ((hmep->hme_promisc ? BMAC_RXCFG_PROMIS : 0) | 270985025c03Sgd BMAC_RXCFG_MYOWN | BMAC_RXCFG_HASH)); 27107c478bd9Sstevel@tonic-gate } else { 27117c478bd9Sstevel@tonic-gate PUT_MACREG(rxcfg, 2712228fdff0Sgd ((hmep->hme_promisc ? BMAC_RXCFG_PROMIS : 0) | 271385025c03Sgd BMAC_RXCFG_HASH)); 27147c478bd9Sstevel@tonic-gate } 27157c478bd9Sstevel@tonic-gate 27167c478bd9Sstevel@tonic-gate drv_usecwait(10); /* wait after setting Hash Enable bit */ 27177c478bd9Sstevel@tonic-gate 271806673d9bSGarrett D'Amore fdx = (mii_get_duplex(hmep->hme_mii) == LINK_DUPLEX_FULL); 271906673d9bSGarrett D'Amore 27207c478bd9Sstevel@tonic-gate if (hme_ngu_enable) 272106673d9bSGarrett D'Amore PUT_MACREG(txcfg, (fdx ? BMAC_TXCFG_FDX : 0) | 272285025c03Sgd BMAC_TXCFG_NGU); 27237c478bd9Sstevel@tonic-gate else 272406673d9bSGarrett D'Amore PUT_MACREG(txcfg, (fdx ? BMAC_TXCFG_FDX: 0)); 27257c478bd9Sstevel@tonic-gate 27267c478bd9Sstevel@tonic-gate i = 0; 272706673d9bSGarrett D'Amore if ((hmep->hme_lance_mode) && (hmep->hme_lance_mode_enable)) 272806673d9bSGarrett D'Amore i = ((hmep->hme_ipg0 & HME_MASK_5BIT) << BMAC_XIFC_IPG0_SHIFT) 272985025c03Sgd | BMAC_XIFC_LANCE_ENAB; 273006673d9bSGarrett D'Amore if (phyad == HME_INTERNAL_PHYAD) 27317c478bd9Sstevel@tonic-gate PUT_MACREG(xifc, i | (BMAC_XIFC_ENAB)); 27327c478bd9Sstevel@tonic-gate else 27337c478bd9Sstevel@tonic-gate PUT_MACREG(xifc, i | (BMAC_XIFC_ENAB | BMAC_XIFC_MIIBUFDIS)); 27347c478bd9Sstevel@tonic-gate 27357c478bd9Sstevel@tonic-gate PUT_MACREG(rxcfg, GET_MACREG(rxcfg) | BMAC_RXCFG_ENAB); 27367c478bd9Sstevel@tonic-gate PUT_MACREG(txcfg, GET_MACREG(txcfg) | BMAC_TXCFG_ENAB); 27377c478bd9Sstevel@tonic-gate 27387c478bd9Sstevel@tonic-gate hmep->hme_flags |= (HMERUNNING | HMEINITIALIZED); 27397c478bd9Sstevel@tonic-gate /* 27407c478bd9Sstevel@tonic-gate * Update the interrupt mask : this will re-allow interrupts to occur 27417c478bd9Sstevel@tonic-gate */ 274285025c03Sgd PUT_GLOBREG(intmask, HMEG_MASK_INTR); 274385025c03Sgd mac_tx_update(hmep->hme_mh); 27447c478bd9Sstevel@tonic-gate 27457c478bd9Sstevel@tonic-gate init_fail: 27467c478bd9Sstevel@tonic-gate /* 27477c478bd9Sstevel@tonic-gate * Release the locks in reverse order 27487c478bd9Sstevel@tonic-gate */ 27497c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_xmitlock); 27507c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_intrlock); 27517c478bd9Sstevel@tonic-gate 27527c478bd9Sstevel@tonic-gate ret = !(hmep->hme_flags & HMERUNNING); 27537c478bd9Sstevel@tonic-gate if (ret) { 27547c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 275585025c03Sgd init_fail_gen_msg); 27567c478bd9Sstevel@tonic-gate } 27577c478bd9Sstevel@tonic-gate 27587c478bd9Sstevel@tonic-gate /* 27597c478bd9Sstevel@tonic-gate * Hardware checks. 27607c478bd9Sstevel@tonic-gate */ 27617c478bd9Sstevel@tonic-gate CHECK_GLOBREG(); 27627c478bd9Sstevel@tonic-gate CHECK_MIFREG(); 27637c478bd9Sstevel@tonic-gate CHECK_MACREG(); 27647c478bd9Sstevel@tonic-gate CHECK_ERXREG(); 27657c478bd9Sstevel@tonic-gate CHECK_ETXREG(); 27667c478bd9Sstevel@tonic-gate 27677c478bd9Sstevel@tonic-gate init_exit: 27687c478bd9Sstevel@tonic-gate return (ret); 27697c478bd9Sstevel@tonic-gate } 27707c478bd9Sstevel@tonic-gate 27717c478bd9Sstevel@tonic-gate /* 27727c478bd9Sstevel@tonic-gate * Calculate the dvma burstsize by setting up a dvma temporarily. Return 27737c478bd9Sstevel@tonic-gate * 0 as burstsize upon failure as it signifies no burst size. 27747c478bd9Sstevel@tonic-gate * Requests for 64-bit transfer setup, if the platform supports it. 27757c478bd9Sstevel@tonic-gate * NOTE: Do not use ddi_dma_alloc_handle(9f) then ddi_dma_burstsize(9f), 27767c478bd9Sstevel@tonic-gate * sun4u Ultra-2 incorrectly returns a 32bit transfer. 27777c478bd9Sstevel@tonic-gate */ 27787c478bd9Sstevel@tonic-gate static int 27797c478bd9Sstevel@tonic-gate hmeburstsizes(struct hme *hmep) 27807c478bd9Sstevel@tonic-gate { 27817c478bd9Sstevel@tonic-gate int burstsizes; 27827c478bd9Sstevel@tonic-gate ddi_dma_handle_t handle; 27837c478bd9Sstevel@tonic-gate 27847c478bd9Sstevel@tonic-gate if (ddi_dma_alloc_handle(hmep->dip, &hme_dma_attr, 27857c478bd9Sstevel@tonic-gate DDI_DMA_DONTWAIT, NULL, &handle)) { 27867c478bd9Sstevel@tonic-gate return (0); 27877c478bd9Sstevel@tonic-gate } 27887c478bd9Sstevel@tonic-gate 27897c478bd9Sstevel@tonic-gate hmep->hme_burstsizes = burstsizes = ddi_dma_burstsizes(handle); 27907c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&handle); 27917c478bd9Sstevel@tonic-gate 27927c478bd9Sstevel@tonic-gate /* 27937c478bd9Sstevel@tonic-gate * Use user-configurable parameter for enabling 64-bit transfers 27947c478bd9Sstevel@tonic-gate */ 27957c478bd9Sstevel@tonic-gate burstsizes = (hmep->hme_burstsizes >> 16); 27967c478bd9Sstevel@tonic-gate if (burstsizes) 27977c478bd9Sstevel@tonic-gate hmep->hme_64bit_xfer = hme_64bit_enable; /* user config value */ 27987c478bd9Sstevel@tonic-gate else 27997c478bd9Sstevel@tonic-gate burstsizes = hmep->hme_burstsizes; 28007c478bd9Sstevel@tonic-gate 28017c478bd9Sstevel@tonic-gate if (hmep->hme_cheerio_mode) 28027c478bd9Sstevel@tonic-gate hmep->hme_64bit_xfer = 0; /* Disable for cheerio */ 28037c478bd9Sstevel@tonic-gate 28047c478bd9Sstevel@tonic-gate if (burstsizes & 0x40) 28057c478bd9Sstevel@tonic-gate hmep->hme_config = HMEG_CONFIG_BURST64; 28067c478bd9Sstevel@tonic-gate else if (burstsizes & 0x20) 28077c478bd9Sstevel@tonic-gate hmep->hme_config = HMEG_CONFIG_BURST32; 28087c478bd9Sstevel@tonic-gate else 28097c478bd9Sstevel@tonic-gate hmep->hme_config = HMEG_CONFIG_BURST16; 28107c478bd9Sstevel@tonic-gate 28110219346bSGarrett D'Amore return (DDI_SUCCESS); 28120219346bSGarrett D'Amore } 28130219346bSGarrett D'Amore 28140219346bSGarrett D'Amore static int 28150219346bSGarrett D'Amore hmeallocbuf(struct hme *hmep, hmebuf_t *buf, int dir) 28160219346bSGarrett D'Amore { 28170219346bSGarrett D'Amore ddi_dma_cookie_t dmac; 28180219346bSGarrett D'Amore size_t len; 28190219346bSGarrett D'Amore unsigned ccnt; 28200219346bSGarrett D'Amore 28210219346bSGarrett D'Amore if (ddi_dma_alloc_handle(hmep->dip, &hme_dma_attr, 28220219346bSGarrett D'Amore DDI_DMA_DONTWAIT, NULL, &buf->dmah) != DDI_SUCCESS) { 28230219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 28240219346bSGarrett D'Amore "cannot allocate buf dma handle - failed"); 28250219346bSGarrett D'Amore return (DDI_FAILURE); 28260219346bSGarrett D'Amore } 28270219346bSGarrett D'Amore 28280219346bSGarrett D'Amore if (ddi_dma_mem_alloc(buf->dmah, ROUNDUP(HMEBUFSIZE, 512), 28290219346bSGarrett D'Amore &hme_buf_attr, DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, NULL, 28300219346bSGarrett D'Amore &buf->kaddr, &len, &buf->acch) != DDI_SUCCESS) { 28310219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 28320219346bSGarrett D'Amore "cannot allocate buf memory - failed"); 28330219346bSGarrett D'Amore return (DDI_FAILURE); 28340219346bSGarrett D'Amore } 28350219346bSGarrett D'Amore 28360219346bSGarrett D'Amore if (ddi_dma_addr_bind_handle(buf->dmah, NULL, buf->kaddr, 28370219346bSGarrett D'Amore len, dir | DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL, 28380219346bSGarrett D'Amore &dmac, &ccnt) != DDI_DMA_MAPPED) { 28390219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 28400219346bSGarrett D'Amore "cannot map buf for dma - failed"); 28410219346bSGarrett D'Amore return (DDI_FAILURE); 28420219346bSGarrett D'Amore } 28430219346bSGarrett D'Amore buf->paddr = dmac.dmac_address; 28440219346bSGarrett D'Amore 28450219346bSGarrett D'Amore /* apparently they don't handle multiple cookies */ 28460219346bSGarrett D'Amore if (ccnt > 1) { 28470219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 28480219346bSGarrett D'Amore "too many buf dma cookies"); 28490219346bSGarrett D'Amore return (DDI_FAILURE); 28500219346bSGarrett D'Amore } 28510219346bSGarrett D'Amore return (DDI_SUCCESS); 28520219346bSGarrett D'Amore } 28530219346bSGarrett D'Amore 28540219346bSGarrett D'Amore static int 28550219346bSGarrett D'Amore hmeallocbufs(struct hme *hmep) 28560219346bSGarrett D'Amore { 28570219346bSGarrett D'Amore hmep->hme_tbuf = kmem_zalloc(HME_TMDMAX * sizeof (hmebuf_t), KM_SLEEP); 28580219346bSGarrett D'Amore hmep->hme_rbuf = kmem_zalloc(HME_RMDMAX * sizeof (hmebuf_t), KM_SLEEP); 28590219346bSGarrett D'Amore 28600219346bSGarrett D'Amore /* Alloc RX buffers. */ 28610219346bSGarrett D'Amore for (int i = 0; i < HME_RMDMAX; i++) { 28620219346bSGarrett D'Amore if (hmeallocbuf(hmep, &hmep->hme_rbuf[i], DDI_DMA_READ) != 28630219346bSGarrett D'Amore DDI_SUCCESS) { 28640219346bSGarrett D'Amore return (DDI_FAILURE); 28650219346bSGarrett D'Amore } 28660219346bSGarrett D'Amore } 28670219346bSGarrett D'Amore 28680219346bSGarrett D'Amore /* Alloc TX buffers. */ 28690219346bSGarrett D'Amore for (int i = 0; i < HME_TMDMAX; i++) { 28700219346bSGarrett D'Amore if (hmeallocbuf(hmep, &hmep->hme_tbuf[i], DDI_DMA_WRITE) != 28710219346bSGarrett D'Amore DDI_SUCCESS) { 28720219346bSGarrett D'Amore return (DDI_FAILURE); 28730219346bSGarrett D'Amore } 28740219346bSGarrett D'Amore } 28757c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 28767c478bd9Sstevel@tonic-gate } 28777c478bd9Sstevel@tonic-gate 28787c478bd9Sstevel@tonic-gate static void 28797c478bd9Sstevel@tonic-gate hmefreebufs(struct hme *hmep) 28807c478bd9Sstevel@tonic-gate { 28817c478bd9Sstevel@tonic-gate int i; 28820219346bSGarrett D'Amore 28830219346bSGarrett D'Amore if (hmep->hme_rbuf == NULL) 28840219346bSGarrett D'Amore return; 28857c478bd9Sstevel@tonic-gate 28867c478bd9Sstevel@tonic-gate /* 28870219346bSGarrett D'Amore * Free and unload pending xmit and recv buffers. 28887c478bd9Sstevel@tonic-gate * Maintaining the 1-to-1 ordered sequence of 28890219346bSGarrett D'Amore * We have written the routine to be idempotent. 28907c478bd9Sstevel@tonic-gate */ 28917c478bd9Sstevel@tonic-gate 28927c478bd9Sstevel@tonic-gate for (i = 0; i < HME_TMDMAX; i++) { 28930219346bSGarrett D'Amore hmebuf_t *tbuf = &hmep->hme_tbuf[i]; 28940219346bSGarrett D'Amore if (tbuf->paddr) { 28950219346bSGarrett D'Amore (void) ddi_dma_unbind_handle(tbuf->dmah); 28960219346bSGarrett D'Amore } 28970219346bSGarrett D'Amore if (tbuf->kaddr) { 28980219346bSGarrett D'Amore ddi_dma_mem_free(&tbuf->acch); 28990219346bSGarrett D'Amore } 29000219346bSGarrett D'Amore if (tbuf->dmah) { 29010219346bSGarrett D'Amore ddi_dma_free_handle(&tbuf->dmah); 29027c478bd9Sstevel@tonic-gate } 29037c478bd9Sstevel@tonic-gate } 29047c478bd9Sstevel@tonic-gate for (i = 0; i < HME_RMDMAX; i++) { 29050219346bSGarrett D'Amore hmebuf_t *rbuf = &hmep->hme_rbuf[i]; 29060219346bSGarrett D'Amore if (rbuf->paddr) { 29070219346bSGarrett D'Amore (void) ddi_dma_unbind_handle(rbuf->dmah); 29080219346bSGarrett D'Amore } 29090219346bSGarrett D'Amore if (rbuf->kaddr) { 29100219346bSGarrett D'Amore ddi_dma_mem_free(&rbuf->acch); 29110219346bSGarrett D'Amore } 29120219346bSGarrett D'Amore if (rbuf->dmah) { 29130219346bSGarrett D'Amore ddi_dma_free_handle(&rbuf->dmah); 29147c478bd9Sstevel@tonic-gate } 29157c478bd9Sstevel@tonic-gate } 29160219346bSGarrett D'Amore kmem_free(hmep->hme_rbuf, HME_RMDMAX * sizeof (hmebuf_t)); 29170219346bSGarrett D'Amore kmem_free(hmep->hme_tbuf, HME_TMDMAX * sizeof (hmebuf_t)); 29187c478bd9Sstevel@tonic-gate } 29197c478bd9Sstevel@tonic-gate 29207c478bd9Sstevel@tonic-gate /* 29217c478bd9Sstevel@tonic-gate * Un-initialize (STOP) HME channel. 29227c478bd9Sstevel@tonic-gate */ 29237c478bd9Sstevel@tonic-gate static void 29247c478bd9Sstevel@tonic-gate hmeuninit(struct hme *hmep) 29257c478bd9Sstevel@tonic-gate { 29267c478bd9Sstevel@tonic-gate /* 29277c478bd9Sstevel@tonic-gate * Allow up to 'HMEDRAINTIME' for pending xmit's to complete. 29287c478bd9Sstevel@tonic-gate */ 29290219346bSGarrett D'Amore HMEDELAY((hmep->hme_txindex == hmep->hme_txreclaim), HMEDRAINTIME); 29307c478bd9Sstevel@tonic-gate 29317c478bd9Sstevel@tonic-gate mutex_enter(&hmep->hme_intrlock); 29327c478bd9Sstevel@tonic-gate mutex_enter(&hmep->hme_xmitlock); 29337c478bd9Sstevel@tonic-gate 29347c478bd9Sstevel@tonic-gate hmep->hme_flags &= ~HMERUNNING; 29357c478bd9Sstevel@tonic-gate 29367c478bd9Sstevel@tonic-gate (void) hmestop(hmep); 29377c478bd9Sstevel@tonic-gate 29387c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_xmitlock); 29397c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_intrlock); 29407c478bd9Sstevel@tonic-gate } 29417c478bd9Sstevel@tonic-gate 29427c478bd9Sstevel@tonic-gate /* 29437c478bd9Sstevel@tonic-gate * Allocate CONSISTENT memory for rmds and tmds with appropriate alignment and 29447c478bd9Sstevel@tonic-gate * map it in IO space. Allocate space for transmit and receive ddi_dma_handle 29457c478bd9Sstevel@tonic-gate * structures to use the DMA interface. 29467c478bd9Sstevel@tonic-gate */ 29477c478bd9Sstevel@tonic-gate static int 29487c478bd9Sstevel@tonic-gate hmeallocthings(struct hme *hmep) 29497c478bd9Sstevel@tonic-gate { 29500219346bSGarrett D'Amore int size; 29510219346bSGarrett D'Amore int rval; 29520219346bSGarrett D'Amore size_t real_len; 29530219346bSGarrett D'Amore uint_t cookiec; 29540219346bSGarrett D'Amore ddi_dma_cookie_t dmac; 29550219346bSGarrett D'Amore dev_info_t *dip = hmep->dip; 29567c478bd9Sstevel@tonic-gate 29577c478bd9Sstevel@tonic-gate /* 29587c478bd9Sstevel@tonic-gate * Allocate the TMD and RMD descriptors and extra for page alignment. 29597c478bd9Sstevel@tonic-gate */ 29607c478bd9Sstevel@tonic-gate 29610219346bSGarrett D'Amore rval = ddi_dma_alloc_handle(dip, &hme_dma_attr, DDI_DMA_DONTWAIT, NULL, 29620219346bSGarrett D'Amore &hmep->hme_rmd_dmah); 29637c478bd9Sstevel@tonic-gate if (rval != DDI_SUCCESS) { 296485025c03Sgd HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 296585025c03Sgd "cannot allocate rmd handle - failed"); 29660219346bSGarrett D'Amore return (DDI_FAILURE); 29677c478bd9Sstevel@tonic-gate } 29680219346bSGarrett D'Amore size = HME_RMDMAX * sizeof (struct hme_rmd); 29690219346bSGarrett D'Amore rval = ddi_dma_mem_alloc(hmep->hme_rmd_dmah, size, 29700219346bSGarrett D'Amore &hmep->hme_dev_attr, DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL, 29710219346bSGarrett D'Amore &hmep->hme_rmd_kaddr, &real_len, &hmep->hme_rmd_acch); 29727c478bd9Sstevel@tonic-gate if (rval != DDI_SUCCESS) { 297385025c03Sgd HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 29740219346bSGarrett D'Amore "cannot allocate rmd dma mem - failed"); 29750219346bSGarrett D'Amore return (DDI_FAILURE); 29767c478bd9Sstevel@tonic-gate } 29770219346bSGarrett D'Amore hmep->hme_rmdp = (void *)(hmep->hme_rmd_kaddr); 29780219346bSGarrett D'Amore rval = ddi_dma_addr_bind_handle(hmep->hme_rmd_dmah, NULL, 29790219346bSGarrett D'Amore hmep->hme_rmd_kaddr, size, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 29800219346bSGarrett D'Amore DDI_DMA_DONTWAIT, NULL, &dmac, &cookiec); 29817c478bd9Sstevel@tonic-gate if (rval != DDI_DMA_MAPPED) { 298285025c03Sgd HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 29830219346bSGarrett D'Amore "cannot allocate rmd dma - failed"); 29840219346bSGarrett D'Amore return (DDI_FAILURE); 29857c478bd9Sstevel@tonic-gate } 29860219346bSGarrett D'Amore hmep->hme_rmd_paddr = dmac.dmac_address; 29877c478bd9Sstevel@tonic-gate if (cookiec != 1) { 298885025c03Sgd HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 29890219346bSGarrett D'Amore "too many rmd cookies - failed"); 29900219346bSGarrett D'Amore return (DDI_FAILURE); 29917c478bd9Sstevel@tonic-gate } 29927c478bd9Sstevel@tonic-gate 29930219346bSGarrett D'Amore rval = ddi_dma_alloc_handle(dip, &hme_dma_attr, DDI_DMA_DONTWAIT, NULL, 29940219346bSGarrett D'Amore &hmep->hme_tmd_dmah); 29950219346bSGarrett D'Amore if (rval != DDI_SUCCESS) { 29960219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 29970219346bSGarrett D'Amore "cannot allocate tmd handle - failed"); 29980219346bSGarrett D'Amore return (DDI_FAILURE); 29990219346bSGarrett D'Amore } 30000219346bSGarrett D'Amore size = HME_TMDMAX * sizeof (struct hme_rmd); 30010219346bSGarrett D'Amore rval = ddi_dma_mem_alloc(hmep->hme_tmd_dmah, size, 30020219346bSGarrett D'Amore &hmep->hme_dev_attr, DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL, 30030219346bSGarrett D'Amore &hmep->hme_tmd_kaddr, &real_len, &hmep->hme_tmd_acch); 30040219346bSGarrett D'Amore if (rval != DDI_SUCCESS) { 30050219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 30060219346bSGarrett D'Amore "cannot allocate tmd dma mem - failed"); 30070219346bSGarrett D'Amore return (DDI_FAILURE); 30080219346bSGarrett D'Amore } 30090219346bSGarrett D'Amore hmep->hme_tmdp = (void *)(hmep->hme_tmd_kaddr); 30100219346bSGarrett D'Amore rval = ddi_dma_addr_bind_handle(hmep->hme_tmd_dmah, NULL, 30110219346bSGarrett D'Amore hmep->hme_tmd_kaddr, size, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 30120219346bSGarrett D'Amore DDI_DMA_DONTWAIT, NULL, &dmac, &cookiec); 30130219346bSGarrett D'Amore if (rval != DDI_DMA_MAPPED) { 30140219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 30150219346bSGarrett D'Amore "cannot allocate tmd dma - failed"); 30160219346bSGarrett D'Amore return (DDI_FAILURE); 30170219346bSGarrett D'Amore } 30180219346bSGarrett D'Amore hmep->hme_tmd_paddr = dmac.dmac_address; 30190219346bSGarrett D'Amore if (cookiec != 1) { 30200219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 30210219346bSGarrett D'Amore "too many tmd cookies - failed"); 30220219346bSGarrett D'Amore return (DDI_FAILURE); 30237c478bd9Sstevel@tonic-gate } 30247c478bd9Sstevel@tonic-gate 30250219346bSGarrett D'Amore return (DDI_SUCCESS); 30267c478bd9Sstevel@tonic-gate } 30277c478bd9Sstevel@tonic-gate 30280219346bSGarrett D'Amore static void 30290219346bSGarrett D'Amore hmefreethings(struct hme *hmep) 30300219346bSGarrett D'Amore { 30310219346bSGarrett D'Amore if (hmep->hme_rmd_paddr) { 30320219346bSGarrett D'Amore (void) ddi_dma_unbind_handle(hmep->hme_rmd_dmah); 30330219346bSGarrett D'Amore hmep->hme_rmd_paddr = 0; 30340219346bSGarrett D'Amore } 30350219346bSGarrett D'Amore if (hmep->hme_rmd_acch) 30360219346bSGarrett D'Amore ddi_dma_mem_free(&hmep->hme_rmd_acch); 30370219346bSGarrett D'Amore if (hmep->hme_rmd_dmah) 30380219346bSGarrett D'Amore ddi_dma_free_handle(&hmep->hme_rmd_dmah); 30390219346bSGarrett D'Amore 30400219346bSGarrett D'Amore if (hmep->hme_tmd_paddr) { 30410219346bSGarrett D'Amore (void) ddi_dma_unbind_handle(hmep->hme_tmd_dmah); 30420219346bSGarrett D'Amore hmep->hme_tmd_paddr = 0; 30430219346bSGarrett D'Amore } 30440219346bSGarrett D'Amore if (hmep->hme_tmd_acch) 30450219346bSGarrett D'Amore ddi_dma_mem_free(&hmep->hme_tmd_acch); 30460219346bSGarrett D'Amore if (hmep->hme_tmd_dmah) 30470219346bSGarrett D'Amore ddi_dma_free_handle(&hmep->hme_tmd_dmah); 30480219346bSGarrett D'Amore } 30497c478bd9Sstevel@tonic-gate 30507c478bd9Sstevel@tonic-gate /* 30517c478bd9Sstevel@tonic-gate * First check to see if it our device interrupting. 30527c478bd9Sstevel@tonic-gate */ 30537c478bd9Sstevel@tonic-gate static uint_t 305485025c03Sgd hmeintr(caddr_t arg) 30557c478bd9Sstevel@tonic-gate { 305685025c03Sgd struct hme *hmep = (void *)arg; 30577c478bd9Sstevel@tonic-gate uint32_t hmesbits; 30587c478bd9Sstevel@tonic-gate uint32_t serviced = DDI_INTR_UNCLAIMED; 30597c478bd9Sstevel@tonic-gate uint32_t num_reads = 0; 306085025c03Sgd uint32_t rflags; 306185025c03Sgd mblk_t *mp, *head, **tail; 30627c478bd9Sstevel@tonic-gate 30637c478bd9Sstevel@tonic-gate 306485025c03Sgd head = NULL; 306585025c03Sgd tail = &head; 30667c478bd9Sstevel@tonic-gate 30677c478bd9Sstevel@tonic-gate mutex_enter(&hmep->hme_intrlock); 30687c478bd9Sstevel@tonic-gate 30697c478bd9Sstevel@tonic-gate /* 30707c478bd9Sstevel@tonic-gate * The status register auto-clears on read except for 30717c478bd9Sstevel@tonic-gate * MIF Interrupt bit 30727c478bd9Sstevel@tonic-gate */ 30737c478bd9Sstevel@tonic-gate hmesbits = GET_GLOBREG(status); 30747c478bd9Sstevel@tonic-gate CHECK_GLOBREG(); 30757c478bd9Sstevel@tonic-gate 30767c478bd9Sstevel@tonic-gate /* 30777c478bd9Sstevel@tonic-gate * Note: TINT is sometimes enabled in thr hmereclaim() 30787c478bd9Sstevel@tonic-gate */ 30797c478bd9Sstevel@tonic-gate 30807c478bd9Sstevel@tonic-gate /* 30817c478bd9Sstevel@tonic-gate * Bugid 1227832 - to handle spurious interrupts on fusion systems. 30827c478bd9Sstevel@tonic-gate * Claim the first interrupt after initialization 30837c478bd9Sstevel@tonic-gate */ 30847c478bd9Sstevel@tonic-gate if (hmep->hme_flags & HMEINITIALIZED) { 30857c478bd9Sstevel@tonic-gate hmep->hme_flags &= ~HMEINITIALIZED; 30867c478bd9Sstevel@tonic-gate serviced = DDI_INTR_CLAIMED; 30877c478bd9Sstevel@tonic-gate } 30887c478bd9Sstevel@tonic-gate 30897c478bd9Sstevel@tonic-gate if ((hmesbits & (HMEG_STATUS_INTR | HMEG_STATUS_TINT)) == 0) { 30907c478bd9Sstevel@tonic-gate /* No interesting interrupt */ 30917c478bd9Sstevel@tonic-gate if (hmep->hme_intrstats) { 30927c478bd9Sstevel@tonic-gate if (serviced == DDI_INTR_UNCLAIMED) 30937c478bd9Sstevel@tonic-gate KIOIP->intrs[KSTAT_INTR_SPURIOUS]++; 30947c478bd9Sstevel@tonic-gate else 30957c478bd9Sstevel@tonic-gate KIOIP->intrs[KSTAT_INTR_HARD]++; 30967c478bd9Sstevel@tonic-gate } 30977c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_intrlock); 30987c478bd9Sstevel@tonic-gate return (serviced); 30997c478bd9Sstevel@tonic-gate } 31007c478bd9Sstevel@tonic-gate 31017c478bd9Sstevel@tonic-gate serviced = DDI_INTR_CLAIMED; 31027c478bd9Sstevel@tonic-gate 31037c478bd9Sstevel@tonic-gate if (!(hmep->hme_flags & HMERUNNING)) { 31047c478bd9Sstevel@tonic-gate if (hmep->hme_intrstats) 31057c478bd9Sstevel@tonic-gate KIOIP->intrs[KSTAT_INTR_HARD]++; 31067c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_intrlock); 31077c478bd9Sstevel@tonic-gate hmeuninit(hmep); 31087c478bd9Sstevel@tonic-gate return (serviced); 31097c478bd9Sstevel@tonic-gate } 31107c478bd9Sstevel@tonic-gate 31117c478bd9Sstevel@tonic-gate if (hmesbits & (HMEG_STATUS_FATAL_ERR | HMEG_STATUS_NONFATAL_ERR)) { 31127c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_FATAL_ERR) { 31137c478bd9Sstevel@tonic-gate 31147c478bd9Sstevel@tonic-gate if (hmep->hme_intrstats) 31157c478bd9Sstevel@tonic-gate KIOIP->intrs[KSTAT_INTR_HARD]++; 31167c478bd9Sstevel@tonic-gate hme_fatal_err(hmep, hmesbits); 31177c478bd9Sstevel@tonic-gate 31187c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_intrlock); 31197c478bd9Sstevel@tonic-gate (void) hmeinit(hmep); 31207c478bd9Sstevel@tonic-gate return (serviced); 31217c478bd9Sstevel@tonic-gate } 31227c478bd9Sstevel@tonic-gate hme_nonfatal_err(hmep, hmesbits); 31237c478bd9Sstevel@tonic-gate } 31247c478bd9Sstevel@tonic-gate 31257c478bd9Sstevel@tonic-gate if (hmesbits & (HMEG_STATUS_TX_ALL | HMEG_STATUS_TINT)) { 31267c478bd9Sstevel@tonic-gate mutex_enter(&hmep->hme_xmitlock); 31277c478bd9Sstevel@tonic-gate 31287c478bd9Sstevel@tonic-gate hmereclaim(hmep); 31297c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_xmitlock); 31307c478bd9Sstevel@tonic-gate } 31317c478bd9Sstevel@tonic-gate 31327c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_RINT) { 31337c478bd9Sstevel@tonic-gate 31347c478bd9Sstevel@tonic-gate /* 31357c478bd9Sstevel@tonic-gate * This dummy PIO is required to flush the SBus 31367c478bd9Sstevel@tonic-gate * Bridge buffers in QFE. 31377c478bd9Sstevel@tonic-gate */ 31380219346bSGarrett D'Amore (void) GET_GLOBREG(config); 31397c478bd9Sstevel@tonic-gate 31407c478bd9Sstevel@tonic-gate /* 31410219346bSGarrett D'Amore * Loop through each RMD no more than once. 31427c478bd9Sstevel@tonic-gate */ 31430219346bSGarrett D'Amore while (num_reads++ < HME_RMDMAX) { 31440219346bSGarrett D'Amore hmebuf_t *rbuf; 31450219346bSGarrett D'Amore int rxptr; 31460219346bSGarrett D'Amore 31470219346bSGarrett D'Amore rxptr = hmep->hme_rxindex % HME_RMDMAX; 31480219346bSGarrett D'Amore HMESYNCRMD(rxptr, DDI_DMA_SYNC_FORKERNEL); 31490219346bSGarrett D'Amore 31500219346bSGarrett D'Amore rflags = GET_RMD_FLAGS(rxptr); 31510219346bSGarrett D'Amore if (rflags & HMERMD_OWN) { 31520219346bSGarrett D'Amore /* 31530219346bSGarrett D'Amore * Chip still owns it. We're done. 31540219346bSGarrett D'Amore */ 31550219346bSGarrett D'Amore break; 31560219346bSGarrett D'Amore } 315785025c03Sgd 31580219346bSGarrett D'Amore /* 31590219346bSGarrett D'Amore * Retrieve the packet. 31600219346bSGarrett D'Amore */ 31610219346bSGarrett D'Amore rbuf = &hmep->hme_rbuf[rxptr]; 31620219346bSGarrett D'Amore mp = hmeread(hmep, rbuf, rflags); 316385025c03Sgd 31647c478bd9Sstevel@tonic-gate /* 31650219346bSGarrett D'Amore * Return ownership of the RMD. 31667c478bd9Sstevel@tonic-gate */ 31670219346bSGarrett D'Amore PUT_RMD(rxptr, rbuf->paddr); 31680219346bSGarrett D'Amore HMESYNCRMD(rxptr, DDI_DMA_SYNC_FORDEV); 31697c478bd9Sstevel@tonic-gate 317085025c03Sgd if (mp != NULL) { 317185025c03Sgd *tail = mp; 317285025c03Sgd tail = &mp->b_next; 317385025c03Sgd } 317485025c03Sgd 31757c478bd9Sstevel@tonic-gate /* 31760219346bSGarrett D'Amore * Advance to the next RMD. 31777c478bd9Sstevel@tonic-gate */ 31780219346bSGarrett D'Amore hmep->hme_rxindex++; 31797c478bd9Sstevel@tonic-gate } 31807c478bd9Sstevel@tonic-gate } 31817c478bd9Sstevel@tonic-gate 31827c478bd9Sstevel@tonic-gate if (hmep->hme_intrstats) 31837c478bd9Sstevel@tonic-gate KIOIP->intrs[KSTAT_INTR_HARD]++; 31847c478bd9Sstevel@tonic-gate 31857c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_intrlock); 318685025c03Sgd 318785025c03Sgd if (head != NULL) 318885025c03Sgd mac_rx(hmep->hme_mh, NULL, head); 318985025c03Sgd 31907c478bd9Sstevel@tonic-gate return (serviced); 31917c478bd9Sstevel@tonic-gate } 31927c478bd9Sstevel@tonic-gate 31937c478bd9Sstevel@tonic-gate /* 31947c478bd9Sstevel@tonic-gate * Transmit completion reclaiming. 31957c478bd9Sstevel@tonic-gate */ 31967c478bd9Sstevel@tonic-gate static void 31977c478bd9Sstevel@tonic-gate hmereclaim(struct hme *hmep) 31987c478bd9Sstevel@tonic-gate { 31990219346bSGarrett D'Amore boolean_t reclaimed = B_FALSE; 32007c478bd9Sstevel@tonic-gate 32017c478bd9Sstevel@tonic-gate /* 32027c478bd9Sstevel@tonic-gate * Loop through each TMD. 32037c478bd9Sstevel@tonic-gate */ 32040219346bSGarrett D'Amore while (hmep->hme_txindex > hmep->hme_txreclaim) { 32050219346bSGarrett D'Amore 32060219346bSGarrett D'Amore int reclaim; 32070219346bSGarrett D'Amore uint32_t flags; 32080219346bSGarrett D'Amore 32090219346bSGarrett D'Amore reclaim = hmep->hme_txreclaim % HME_TMDMAX; 32100219346bSGarrett D'Amore HMESYNCTMD(reclaim, DDI_DMA_SYNC_FORKERNEL); 32110219346bSGarrett D'Amore 32120219346bSGarrett D'Amore flags = GET_TMD_FLAGS(reclaim); 32130219346bSGarrett D'Amore if (flags & HMETMD_OWN) { 32140219346bSGarrett D'Amore /* 32150219346bSGarrett D'Amore * Chip still owns it. We're done. 32160219346bSGarrett D'Amore */ 32170219346bSGarrett D'Amore break; 32180219346bSGarrett D'Amore } 32197c478bd9Sstevel@tonic-gate 32207c478bd9Sstevel@tonic-gate /* 32210219346bSGarrett D'Amore * Count a chained packet only once. 32227c478bd9Sstevel@tonic-gate */ 32230219346bSGarrett D'Amore if (flags & HMETMD_SOP) { 32247c478bd9Sstevel@tonic-gate hmep->hme_opackets++; 32257c478bd9Sstevel@tonic-gate } 32267c478bd9Sstevel@tonic-gate 32277c478bd9Sstevel@tonic-gate /* 32287c478bd9Sstevel@tonic-gate * MIB II 32297c478bd9Sstevel@tonic-gate */ 32300219346bSGarrett D'Amore hmep->hme_obytes += flags & HMETMD_BUFSIZE; 32317c478bd9Sstevel@tonic-gate 32320219346bSGarrett D'Amore reclaimed = B_TRUE; 32330219346bSGarrett D'Amore hmep->hme_txreclaim++; 32347c478bd9Sstevel@tonic-gate } 32357c478bd9Sstevel@tonic-gate 32360219346bSGarrett D'Amore if (reclaimed) { 32377c478bd9Sstevel@tonic-gate /* 32387c478bd9Sstevel@tonic-gate * we could reclaim some TMDs so turn off interrupts 32397c478bd9Sstevel@tonic-gate */ 32407c478bd9Sstevel@tonic-gate if (hmep->hme_wantw) { 32417c478bd9Sstevel@tonic-gate PUT_GLOBREG(intmask, 324285025c03Sgd HMEG_MASK_INTR | HMEG_MASK_TINT | 324385025c03Sgd HMEG_MASK_TX_ALL); 324485025c03Sgd hmep->hme_wantw = B_FALSE; 324585025c03Sgd mac_tx_update(hmep->hme_mh); 32467c478bd9Sstevel@tonic-gate } 32477c478bd9Sstevel@tonic-gate } else { 32487c478bd9Sstevel@tonic-gate /* 32497c478bd9Sstevel@tonic-gate * enable TINTS: so that even if there is no further activity 32507c478bd9Sstevel@tonic-gate * hmereclaim will get called 32517c478bd9Sstevel@tonic-gate */ 32527c478bd9Sstevel@tonic-gate if (hmep->hme_wantw) 325385025c03Sgd PUT_GLOBREG(intmask, 325485025c03Sgd GET_GLOBREG(intmask) & ~HMEG_MASK_TX_ALL); 32557c478bd9Sstevel@tonic-gate } 32567c478bd9Sstevel@tonic-gate CHECK_GLOBREG(); 32577c478bd9Sstevel@tonic-gate } 32587c478bd9Sstevel@tonic-gate 32597c478bd9Sstevel@tonic-gate /* 32607c478bd9Sstevel@tonic-gate * Handle interrupts for fatal errors 32617c478bd9Sstevel@tonic-gate * Need reinitialization of the ENET channel. 32627c478bd9Sstevel@tonic-gate */ 32637c478bd9Sstevel@tonic-gate static void 32647c478bd9Sstevel@tonic-gate hme_fatal_err(struct hme *hmep, uint_t hmesbits) 32657c478bd9Sstevel@tonic-gate { 32667c478bd9Sstevel@tonic-gate 32677c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_SLV_PAR_ERR) { 32687c478bd9Sstevel@tonic-gate hmep->hme_slvparerr++; 32697c478bd9Sstevel@tonic-gate } 32707c478bd9Sstevel@tonic-gate 32717c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_SLV_ERR_ACK) { 32727c478bd9Sstevel@tonic-gate hmep->hme_slverrack++; 32737c478bd9Sstevel@tonic-gate } 32747c478bd9Sstevel@tonic-gate 32757c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_TX_TAG_ERR) { 32767c478bd9Sstevel@tonic-gate hmep->hme_txtagerr++; 32777c478bd9Sstevel@tonic-gate hmep->hme_oerrors++; 32787c478bd9Sstevel@tonic-gate } 32797c478bd9Sstevel@tonic-gate 32807c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_TX_PAR_ERR) { 32817c478bd9Sstevel@tonic-gate hmep->hme_txparerr++; 32827c478bd9Sstevel@tonic-gate hmep->hme_oerrors++; 32837c478bd9Sstevel@tonic-gate } 32847c478bd9Sstevel@tonic-gate 32857c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_TX_LATE_ERR) { 32867c478bd9Sstevel@tonic-gate hmep->hme_txlaterr++; 32877c478bd9Sstevel@tonic-gate hmep->hme_oerrors++; 32887c478bd9Sstevel@tonic-gate } 32897c478bd9Sstevel@tonic-gate 32907c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_TX_ERR_ACK) { 32917c478bd9Sstevel@tonic-gate hmep->hme_txerrack++; 32927c478bd9Sstevel@tonic-gate hmep->hme_oerrors++; 32937c478bd9Sstevel@tonic-gate } 32947c478bd9Sstevel@tonic-gate 32957c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_EOP_ERR) { 32967c478bd9Sstevel@tonic-gate hmep->hme_eoperr++; 32977c478bd9Sstevel@tonic-gate } 32987c478bd9Sstevel@tonic-gate 32997c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_RX_TAG_ERR) { 33007c478bd9Sstevel@tonic-gate hmep->hme_rxtagerr++; 33017c478bd9Sstevel@tonic-gate hmep->hme_ierrors++; 33027c478bd9Sstevel@tonic-gate } 33037c478bd9Sstevel@tonic-gate 33047c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_RX_PAR_ERR) { 33057c478bd9Sstevel@tonic-gate hmep->hme_rxparerr++; 33067c478bd9Sstevel@tonic-gate hmep->hme_ierrors++; 33077c478bd9Sstevel@tonic-gate } 33087c478bd9Sstevel@tonic-gate 33097c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_RX_LATE_ERR) { 33107c478bd9Sstevel@tonic-gate hmep->hme_rxlaterr++; 33117c478bd9Sstevel@tonic-gate hmep->hme_ierrors++; 33127c478bd9Sstevel@tonic-gate } 33137c478bd9Sstevel@tonic-gate 33147c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_RX_ERR_ACK) { 33157c478bd9Sstevel@tonic-gate hmep->hme_rxerrack++; 33167c478bd9Sstevel@tonic-gate hmep->hme_ierrors++; 33177c478bd9Sstevel@tonic-gate } 33187c478bd9Sstevel@tonic-gate } 33197c478bd9Sstevel@tonic-gate 33207c478bd9Sstevel@tonic-gate /* 33217c478bd9Sstevel@tonic-gate * Handle interrupts regarding non-fatal errors. 33227c478bd9Sstevel@tonic-gate */ 33237c478bd9Sstevel@tonic-gate static void 33247c478bd9Sstevel@tonic-gate hme_nonfatal_err(struct hme *hmep, uint_t hmesbits) 33257c478bd9Sstevel@tonic-gate { 33267c478bd9Sstevel@tonic-gate 33277c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_RX_DROP) { 33287c478bd9Sstevel@tonic-gate hmep->hme_missed++; 33297c478bd9Sstevel@tonic-gate hmep->hme_ierrors++; 33307c478bd9Sstevel@tonic-gate } 33317c478bd9Sstevel@tonic-gate 33327c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_DEFTIMR_EXP) { 33337c478bd9Sstevel@tonic-gate hmep->hme_defer_xmts++; 33347c478bd9Sstevel@tonic-gate } 33357c478bd9Sstevel@tonic-gate 33367c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_FSTCOLC_EXP) { 33377c478bd9Sstevel@tonic-gate hmep->hme_fstcol += 256; 33387c478bd9Sstevel@tonic-gate } 33397c478bd9Sstevel@tonic-gate 33407c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_LATCOLC_EXP) { 33417c478bd9Sstevel@tonic-gate hmep->hme_tlcol += 256; 33427c478bd9Sstevel@tonic-gate hmep->hme_oerrors += 256; 33437c478bd9Sstevel@tonic-gate } 33447c478bd9Sstevel@tonic-gate 33457c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_EXCOLC_EXP) { 334685025c03Sgd hmep->hme_excol += 256; 33477c478bd9Sstevel@tonic-gate hmep->hme_oerrors += 256; 33487c478bd9Sstevel@tonic-gate } 33497c478bd9Sstevel@tonic-gate 33507c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_NRMCOLC_EXP) { 33517c478bd9Sstevel@tonic-gate hmep->hme_coll += 256; 33527c478bd9Sstevel@tonic-gate } 33537c478bd9Sstevel@tonic-gate 33547c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_MXPKTSZ_ERR) { 33557c478bd9Sstevel@tonic-gate hmep->hme_babl++; 33567c478bd9Sstevel@tonic-gate hmep->hme_oerrors++; 33577c478bd9Sstevel@tonic-gate } 33587c478bd9Sstevel@tonic-gate 33597c478bd9Sstevel@tonic-gate /* 33607c478bd9Sstevel@tonic-gate * This error is fatal and the board needs to 33617c478bd9Sstevel@tonic-gate * be reinitialized. Comments? 33627c478bd9Sstevel@tonic-gate */ 33637c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_TXFIFO_UNDR) { 33647c478bd9Sstevel@tonic-gate hmep->hme_uflo++; 33657c478bd9Sstevel@tonic-gate hmep->hme_oerrors++; 33667c478bd9Sstevel@tonic-gate } 33677c478bd9Sstevel@tonic-gate 33687c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_SQE_TST_ERR) { 33697c478bd9Sstevel@tonic-gate hmep->hme_sqe_errors++; 33707c478bd9Sstevel@tonic-gate } 33717c478bd9Sstevel@tonic-gate 33727c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_RCV_CNT_EXP) { 33737c478bd9Sstevel@tonic-gate if (hmep->hme_rxcv_enable) { 33747c478bd9Sstevel@tonic-gate hmep->hme_cvc += 256; 33757c478bd9Sstevel@tonic-gate } 33767c478bd9Sstevel@tonic-gate } 33777c478bd9Sstevel@tonic-gate 33787c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_RXFIFO_OVFL) { 33797c478bd9Sstevel@tonic-gate hmep->hme_oflo++; 33807c478bd9Sstevel@tonic-gate hmep->hme_ierrors++; 33817c478bd9Sstevel@tonic-gate } 33827c478bd9Sstevel@tonic-gate 33837c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_LEN_CNT_EXP) { 33847c478bd9Sstevel@tonic-gate hmep->hme_lenerr += 256; 33857c478bd9Sstevel@tonic-gate hmep->hme_ierrors += 256; 33867c478bd9Sstevel@tonic-gate } 33877c478bd9Sstevel@tonic-gate 33887c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_ALN_CNT_EXP) { 33897c478bd9Sstevel@tonic-gate hmep->hme_align_errors += 256; 33907c478bd9Sstevel@tonic-gate hmep->hme_ierrors += 256; 33917c478bd9Sstevel@tonic-gate } 33927c478bd9Sstevel@tonic-gate 33937c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_CRC_CNT_EXP) { 33947c478bd9Sstevel@tonic-gate hmep->hme_fcs_errors += 256; 33957c478bd9Sstevel@tonic-gate hmep->hme_ierrors += 256; 33967c478bd9Sstevel@tonic-gate } 33977c478bd9Sstevel@tonic-gate } 33987c478bd9Sstevel@tonic-gate 339985025c03Sgd static mblk_t * 34000219346bSGarrett D'Amore hmeread(struct hme *hmep, hmebuf_t *rbuf, uint32_t rflags) 34017c478bd9Sstevel@tonic-gate { 34020219346bSGarrett D'Amore mblk_t *bp; 34030219346bSGarrett D'Amore uint32_t len; 34040219346bSGarrett D'Amore t_uscalar_t type; 34050219346bSGarrett D'Amore 340685025c03Sgd len = (rflags & HMERMD_BUFSIZE) >> HMERMD_BUFSIZE_SHIFT; 34077c478bd9Sstevel@tonic-gate 34087c478bd9Sstevel@tonic-gate /* 34097c478bd9Sstevel@tonic-gate * Check for short packet 34107c478bd9Sstevel@tonic-gate * and check for overflow packet also. The processing is the 34117c478bd9Sstevel@tonic-gate * same for both the cases - reuse the buffer. Update the Buffer 34127c478bd9Sstevel@tonic-gate * overflow counter. 34137c478bd9Sstevel@tonic-gate */ 341485025c03Sgd if ((len < ETHERMIN) || (rflags & HMERMD_OVFLOW) || 341585025c03Sgd (len > (ETHERMAX + 4))) { 34167c478bd9Sstevel@tonic-gate if (len < ETHERMIN) 34177c478bd9Sstevel@tonic-gate hmep->hme_runt++; 34187c478bd9Sstevel@tonic-gate 34197c478bd9Sstevel@tonic-gate else { 34207c478bd9Sstevel@tonic-gate hmep->hme_buff++; 34217c478bd9Sstevel@tonic-gate hmep->hme_toolong_errors++; 34227c478bd9Sstevel@tonic-gate } 34237c478bd9Sstevel@tonic-gate hmep->hme_ierrors++; 342485025c03Sgd return (NULL); 34257c478bd9Sstevel@tonic-gate } 34267c478bd9Sstevel@tonic-gate 34277c478bd9Sstevel@tonic-gate /* 34287c478bd9Sstevel@tonic-gate * Sync the received buffer before looking at it. 34297c478bd9Sstevel@tonic-gate */ 34307c478bd9Sstevel@tonic-gate 34310219346bSGarrett D'Amore (void) ddi_dma_sync(rbuf->dmah, 0, 0, DDI_DMA_SYNC_FORKERNEL); 34327c478bd9Sstevel@tonic-gate 34337c478bd9Sstevel@tonic-gate /* 34347c478bd9Sstevel@tonic-gate * copy the packet data and then recycle the descriptor. 34357c478bd9Sstevel@tonic-gate */ 34367c478bd9Sstevel@tonic-gate 34370219346bSGarrett D'Amore if ((bp = allocb(len + HME_FSTBYTE_OFFSET, BPRI_HI)) == NULL) { 34387c478bd9Sstevel@tonic-gate 34397c478bd9Sstevel@tonic-gate hmep->hme_allocbfail++; 34407c478bd9Sstevel@tonic-gate hmep->hme_norcvbuf++; 344185025c03Sgd 344285025c03Sgd return (NULL); 34437c478bd9Sstevel@tonic-gate } 34447c478bd9Sstevel@tonic-gate 34450219346bSGarrett D'Amore bcopy(rbuf->kaddr, bp->b_rptr, len + HME_FSTBYTE_OFFSET); 34467c478bd9Sstevel@tonic-gate 34470219346bSGarrett D'Amore hmep->hme_ipackets++; 34487c478bd9Sstevel@tonic-gate 34490219346bSGarrett D'Amore /* Add the First Byte offset to the b_rptr and copy */ 34500219346bSGarrett D'Amore bp->b_rptr += HME_FSTBYTE_OFFSET; 34510219346bSGarrett D'Amore bp->b_wptr = bp->b_rptr + len; 34527c478bd9Sstevel@tonic-gate 34537c478bd9Sstevel@tonic-gate /* 34540219346bSGarrett D'Amore * update MIB II statistics 34557c478bd9Sstevel@tonic-gate */ 34560219346bSGarrett D'Amore BUMP_InNUcast(hmep, bp->b_rptr); 34570219346bSGarrett D'Amore hmep->hme_rbytes += len; 34587c478bd9Sstevel@tonic-gate 34590219346bSGarrett D'Amore type = get_ether_type(bp->b_rptr); 34607c478bd9Sstevel@tonic-gate 34617c478bd9Sstevel@tonic-gate /* 34620219346bSGarrett D'Amore * TCP partial checksum in hardware 34637c478bd9Sstevel@tonic-gate */ 34640219346bSGarrett D'Amore if (type == ETHERTYPE_IP || type == ETHERTYPE_IPV6) { 34650219346bSGarrett D'Amore uint16_t cksum = ~rflags & HMERMD_CKSUM; 34660219346bSGarrett D'Amore uint_t end = len - sizeof (struct ether_header); 34670dc2366fSVenugopal Iyer mac_hcksum_set(bp, 0, 0, end, htons(cksum), HCK_PARTIALCKSUM); 34687c478bd9Sstevel@tonic-gate } 34697c478bd9Sstevel@tonic-gate 347085025c03Sgd return (bp); 34717c478bd9Sstevel@tonic-gate } 34727c478bd9Sstevel@tonic-gate 34737c478bd9Sstevel@tonic-gate /*VARARGS*/ 34747c478bd9Sstevel@tonic-gate static void 34750219346bSGarrett D'Amore hme_fault_msg(struct hme *hmep, uint_t severity, msg_t type, char *fmt, ...) 34767c478bd9Sstevel@tonic-gate { 34777c478bd9Sstevel@tonic-gate char msg_buffer[255]; 34787c478bd9Sstevel@tonic-gate va_list ap; 34797c478bd9Sstevel@tonic-gate 34807c478bd9Sstevel@tonic-gate va_start(ap, fmt); 3481228fdff0Sgd (void) vsnprintf(msg_buffer, sizeof (msg_buffer), fmt, ap); 34827c478bd9Sstevel@tonic-gate 348385025c03Sgd if (hmep == NULL) { 34847c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "hme : %s", msg_buffer); 34857c478bd9Sstevel@tonic-gate 348685025c03Sgd } else if (type == DISPLAY_MSG) { 348785025c03Sgd cmn_err(CE_CONT, "?%s%d : %s\n", ddi_driver_name(hmep->dip), 348885025c03Sgd hmep->instance, msg_buffer); 348985025c03Sgd } else if (severity == SEVERITY_HIGH) { 349085025c03Sgd cmn_err(CE_WARN, "%s%d : %s, SEVERITY_HIGH, %s\n", 349185025c03Sgd ddi_driver_name(hmep->dip), hmep->instance, 349285025c03Sgd msg_buffer, msg_string[type]); 349385025c03Sgd } else { 349485025c03Sgd cmn_err(CE_CONT, "%s%d : %s\n", ddi_driver_name(hmep->dip), 349585025c03Sgd hmep->instance, msg_buffer); 349685025c03Sgd } 34977c478bd9Sstevel@tonic-gate va_end(ap); 34987c478bd9Sstevel@tonic-gate } 34997c478bd9Sstevel@tonic-gate 35007c478bd9Sstevel@tonic-gate /* 35017c478bd9Sstevel@tonic-gate * if this is the first init do not bother to save the 35027c478bd9Sstevel@tonic-gate * counters. They should be 0, but do not count on it. 35037c478bd9Sstevel@tonic-gate */ 35047c478bd9Sstevel@tonic-gate static void 35057c478bd9Sstevel@tonic-gate hmesavecntrs(struct hme *hmep) 35067c478bd9Sstevel@tonic-gate { 35077c478bd9Sstevel@tonic-gate uint32_t fecnt, aecnt, lecnt, rxcv; 35087c478bd9Sstevel@tonic-gate uint32_t ltcnt, excnt; 35097c478bd9Sstevel@tonic-gate 35107c478bd9Sstevel@tonic-gate /* XXX What all gets added in ierrors and oerrors? */ 35117c478bd9Sstevel@tonic-gate fecnt = GET_MACREG(fecnt); 35127c478bd9Sstevel@tonic-gate PUT_MACREG(fecnt, 0); 35137c478bd9Sstevel@tonic-gate 35147c478bd9Sstevel@tonic-gate aecnt = GET_MACREG(aecnt); 35157c478bd9Sstevel@tonic-gate hmep->hme_align_errors += aecnt; 35167c478bd9Sstevel@tonic-gate PUT_MACREG(aecnt, 0); 35177c478bd9Sstevel@tonic-gate 35187c478bd9Sstevel@tonic-gate lecnt = GET_MACREG(lecnt); 35197c478bd9Sstevel@tonic-gate hmep->hme_lenerr += lecnt; 35207c478bd9Sstevel@tonic-gate PUT_MACREG(lecnt, 0); 35217c478bd9Sstevel@tonic-gate 35227c478bd9Sstevel@tonic-gate rxcv = GET_MACREG(rxcv); 35237c478bd9Sstevel@tonic-gate #ifdef HME_CODEVIOL_BUG 35247c478bd9Sstevel@tonic-gate /* 35257c478bd9Sstevel@tonic-gate * Ignore rxcv errors for Sbus/FEPS 2.1 or earlier 35267c478bd9Sstevel@tonic-gate */ 35277c478bd9Sstevel@tonic-gate if (!hmep->hme_rxcv_enable) { 35287c478bd9Sstevel@tonic-gate rxcv = 0; 35297c478bd9Sstevel@tonic-gate } 35307c478bd9Sstevel@tonic-gate #endif 35317c478bd9Sstevel@tonic-gate hmep->hme_cvc += rxcv; 35327c478bd9Sstevel@tonic-gate PUT_MACREG(rxcv, 0); 35337c478bd9Sstevel@tonic-gate 35347c478bd9Sstevel@tonic-gate ltcnt = GET_MACREG(ltcnt); 35357c478bd9Sstevel@tonic-gate hmep->hme_tlcol += ltcnt; 35367c478bd9Sstevel@tonic-gate PUT_MACREG(ltcnt, 0); 35377c478bd9Sstevel@tonic-gate 35387c478bd9Sstevel@tonic-gate excnt = GET_MACREG(excnt); 353985025c03Sgd hmep->hme_excol += excnt; 35407c478bd9Sstevel@tonic-gate PUT_MACREG(excnt, 0); 35417c478bd9Sstevel@tonic-gate 35427c478bd9Sstevel@tonic-gate hmep->hme_fcs_errors += fecnt; 35437c478bd9Sstevel@tonic-gate hmep->hme_ierrors += (fecnt + aecnt + lecnt); 35447c478bd9Sstevel@tonic-gate hmep->hme_oerrors += (ltcnt + excnt); 35457c478bd9Sstevel@tonic-gate hmep->hme_coll += (GET_MACREG(nccnt) + ltcnt); 35467c478bd9Sstevel@tonic-gate 35477c478bd9Sstevel@tonic-gate PUT_MACREG(nccnt, 0); 35487c478bd9Sstevel@tonic-gate CHECK_MACREG(); 35497c478bd9Sstevel@tonic-gate } 35507c478bd9Sstevel@tonic-gate 35517c478bd9Sstevel@tonic-gate /* 35527c478bd9Sstevel@tonic-gate * To set up the mac address for the network interface: 35537c478bd9Sstevel@tonic-gate * The adapter card may support a local mac address which is published 35547c478bd9Sstevel@tonic-gate * in a device node property "local-mac-address". This mac address is 35557c478bd9Sstevel@tonic-gate * treated as the factory-installed mac address for DLPI interface. 35567c478bd9Sstevel@tonic-gate * If the adapter firmware has used the device for diskless boot 35577c478bd9Sstevel@tonic-gate * operation it publishes a property called "mac-address" for use by 35587c478bd9Sstevel@tonic-gate * inetboot and the device driver. 35597c478bd9Sstevel@tonic-gate * If "mac-address" is not found, the system options property 35607c478bd9Sstevel@tonic-gate * "local-mac-address" is used to select the mac-address. If this option 35617c478bd9Sstevel@tonic-gate * is set to "true", and "local-mac-address" has been found, then 35627c478bd9Sstevel@tonic-gate * local-mac-address is used; otherwise the system mac address is used 35637c478bd9Sstevel@tonic-gate * by calling the "localetheraddr()" function. 35647c478bd9Sstevel@tonic-gate */ 35657c478bd9Sstevel@tonic-gate static void 35667c478bd9Sstevel@tonic-gate hme_setup_mac_address(struct hme *hmep, dev_info_t *dip) 35677c478bd9Sstevel@tonic-gate { 35687c478bd9Sstevel@tonic-gate char *prop; 35697c478bd9Sstevel@tonic-gate int prop_len = sizeof (int); 35707c478bd9Sstevel@tonic-gate 35717c478bd9Sstevel@tonic-gate hmep->hme_addrflags = 0; 35727c478bd9Sstevel@tonic-gate 35737c478bd9Sstevel@tonic-gate /* 35747c478bd9Sstevel@tonic-gate * Check if it is an adapter with its own local mac address 35757c478bd9Sstevel@tonic-gate * If it is present, save it as the "factory-address" 35767c478bd9Sstevel@tonic-gate * for this adapter. 35777c478bd9Sstevel@tonic-gate */ 357885025c03Sgd if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 357985025c03Sgd "local-mac-address", 358085025c03Sgd (caddr_t)&prop, &prop_len) == DDI_PROP_SUCCESS) { 35817c478bd9Sstevel@tonic-gate if (prop_len == ETHERADDRL) { 35827c478bd9Sstevel@tonic-gate hmep->hme_addrflags = HME_FACTADDR_PRESENT; 35837c478bd9Sstevel@tonic-gate ether_bcopy(prop, &hmep->hme_factaddr); 35847c478bd9Sstevel@tonic-gate HME_FAULT_MSG2(hmep, SEVERITY_NONE, DISPLAY_MSG, 35850219346bSGarrett D'Amore "Local Ethernet address = %s", 358685025c03Sgd ether_sprintf(&hmep->hme_factaddr)); 35877c478bd9Sstevel@tonic-gate } 35887c478bd9Sstevel@tonic-gate kmem_free(prop, prop_len); 35897c478bd9Sstevel@tonic-gate } 35907c478bd9Sstevel@tonic-gate 35917c478bd9Sstevel@tonic-gate /* 35927c478bd9Sstevel@tonic-gate * Check if the adapter has published "mac-address" property. 35937c478bd9Sstevel@tonic-gate * If it is present, use it as the mac address for this device. 35947c478bd9Sstevel@tonic-gate */ 359585025c03Sgd if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 359685025c03Sgd "mac-address", (caddr_t)&prop, &prop_len) == DDI_PROP_SUCCESS) { 35977c478bd9Sstevel@tonic-gate if (prop_len >= ETHERADDRL) { 35987c478bd9Sstevel@tonic-gate ether_bcopy(prop, &hmep->hme_ouraddr); 35997c478bd9Sstevel@tonic-gate kmem_free(prop, prop_len); 36007c478bd9Sstevel@tonic-gate return; 36017c478bd9Sstevel@tonic-gate } 36027c478bd9Sstevel@tonic-gate kmem_free(prop, prop_len); 36037c478bd9Sstevel@tonic-gate } 36047c478bd9Sstevel@tonic-gate 36050219346bSGarrett D'Amore #ifdef __sparc 36060219346bSGarrett D'Amore /* 36070219346bSGarrett D'Amore * On sparc, we might be able to use the mac address from the 36080219346bSGarrett D'Amore * system. However, on all other systems, we need to use the 36090219346bSGarrett D'Amore * address from the PROM. 36100219346bSGarrett D'Amore */ 36117c478bd9Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 0, "local-mac-address?", 361285025c03Sgd (caddr_t)&prop, &prop_len) == DDI_PROP_SUCCESS) { 36137c478bd9Sstevel@tonic-gate if ((strncmp("true", prop, prop_len) == 0) && 361485025c03Sgd (hmep->hme_addrflags & HME_FACTADDR_PRESENT)) { 36157c478bd9Sstevel@tonic-gate hmep->hme_addrflags |= HME_FACTADDR_USE; 36167c478bd9Sstevel@tonic-gate ether_bcopy(&hmep->hme_factaddr, &hmep->hme_ouraddr); 36177c478bd9Sstevel@tonic-gate kmem_free(prop, prop_len); 36187c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_NONE, DISPLAY_MSG, 36190219346bSGarrett D'Amore "Using local MAC address"); 36207c478bd9Sstevel@tonic-gate return; 36217c478bd9Sstevel@tonic-gate } 36227c478bd9Sstevel@tonic-gate kmem_free(prop, prop_len); 36237c478bd9Sstevel@tonic-gate } 36247c478bd9Sstevel@tonic-gate 36257c478bd9Sstevel@tonic-gate /* 36267c478bd9Sstevel@tonic-gate * Get the system ethernet address. 36277c478bd9Sstevel@tonic-gate */ 36287c478bd9Sstevel@tonic-gate (void) localetheraddr((struct ether_addr *)NULL, &hmep->hme_ouraddr); 36290219346bSGarrett D'Amore #else 36300219346bSGarrett D'Amore ether_bcopy(&hmep->hme_factaddr, &hmep->hme_ouraddr); 36310219346bSGarrett D'Amore #endif 36327c478bd9Sstevel@tonic-gate } 36337c478bd9Sstevel@tonic-gate 36347c478bd9Sstevel@tonic-gate /* ARGSUSED */ 36357c478bd9Sstevel@tonic-gate static void 36367c478bd9Sstevel@tonic-gate hme_check_acc_handle(char *file, uint_t line, struct hme *hmep, 36377c478bd9Sstevel@tonic-gate ddi_acc_handle_t handle) 36387c478bd9Sstevel@tonic-gate { 36397c478bd9Sstevel@tonic-gate } 3640