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*e8717ca2SGarrett D'Amore * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate /* 287c478bd9Sstevel@tonic-gate * SunOS MT STREAMS FEPS(SBus)/Cheerio(PCI) 10/100Mb Ethernet Device Driver 297c478bd9Sstevel@tonic-gate */ 307c478bd9Sstevel@tonic-gate 317c478bd9Sstevel@tonic-gate #include <sys/types.h> 327c478bd9Sstevel@tonic-gate #include <sys/debug.h> 337c478bd9Sstevel@tonic-gate #include <sys/stream.h> 347c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 357c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 367c478bd9Sstevel@tonic-gate #include <sys/crc32.h> 3785025c03Sgd #include <sys/modctl.h> 3885025c03Sgd #include <sys/conf.h> 397c478bd9Sstevel@tonic-gate #include <sys/strsun.h> 407c478bd9Sstevel@tonic-gate #include <sys/kstat.h> 4185025c03Sgd #include <sys/pattr.h> 427c478bd9Sstevel@tonic-gate #include <sys/dlpi.h> 4385025c03Sgd #include <sys/strsubr.h> 44da14cebeSEric Cheng #include <sys/mac_provider.h> 4585025c03Sgd #include <sys/mac_ether.h> 4606673d9bSGarrett D'Amore #include <sys/mii.h> 477c478bd9Sstevel@tonic-gate #include <sys/ethernet.h> 48d62bc4baSyz #include <sys/vlan.h> 4985025c03Sgd #include <sys/pci.h> 5085025c03Sgd #include <sys/policy.h> 5185025c03Sgd #include <sys/ddi.h> 5285025c03Sgd #include <sys/sunddi.h> 530219346bSGarrett D'Amore #include "hme_phy.h" 540219346bSGarrett D'Amore #include "hme_mac.h" 550219346bSGarrett D'Amore #include "hme.h" 567c478bd9Sstevel@tonic-gate 577c478bd9Sstevel@tonic-gate typedef void (*fptrv_t)(); 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate typedef enum { 607c478bd9Sstevel@tonic-gate NO_MSG = 0, 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 11606673d9bSGarrett D'Amore mac_priv_prop_t hme_priv_prop[] = { 11706673d9bSGarrett D'Amore { "_ipg0", MAC_PROP_PERM_RW }, 11806673d9bSGarrett D'Amore { "_ipg1", MAC_PROP_PERM_RW }, 11906673d9bSGarrett D'Amore { "_ipg2", MAC_PROP_PERM_RW }, 12006673d9bSGarrett D'Amore { "_lance_mode", MAC_PROP_PERM_RW }, 12106673d9bSGarrett D'Amore }; 1227c478bd9Sstevel@tonic-gate 1237c478bd9Sstevel@tonic-gate static int hme_lance_mode = 1; /* to enable lance mode */ 1247c478bd9Sstevel@tonic-gate static int hme_ipg0 = 16; 1257c478bd9Sstevel@tonic-gate static int hme_ipg1 = 8; 1267c478bd9Sstevel@tonic-gate static int hme_ipg2 = 4; 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate /* 1297c478bd9Sstevel@tonic-gate * The following parameters may be configured by the user. If they are not 1307c478bd9Sstevel@tonic-gate * configured by the user, the values will be based on the capabilities of 1317c478bd9Sstevel@tonic-gate * the transceiver. 1327c478bd9Sstevel@tonic-gate * The value "HME_NOTUSR" is ORed with the parameter value to indicate values 1337c478bd9Sstevel@tonic-gate * which are NOT configured by the user. 1347c478bd9Sstevel@tonic-gate */ 1357c478bd9Sstevel@tonic-gate 1367c478bd9Sstevel@tonic-gate #define HME_NOTUSR 0x0f000000 1377c478bd9Sstevel@tonic-gate #define HME_MASK_1BIT 0x1 1387c478bd9Sstevel@tonic-gate #define HME_MASK_5BIT 0x1f 1397c478bd9Sstevel@tonic-gate #define HME_MASK_8BIT 0xff 1407c478bd9Sstevel@tonic-gate 1417c478bd9Sstevel@tonic-gate /* 1427c478bd9Sstevel@tonic-gate * All strings used by hme messaging functions 1437c478bd9Sstevel@tonic-gate */ 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate static char *no_xcvr_msg = 1467c478bd9Sstevel@tonic-gate "No transceiver found."; 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate static char *burst_size_msg = 1497c478bd9Sstevel@tonic-gate "Could not identify the burst size"; 1507c478bd9Sstevel@tonic-gate 1517c478bd9Sstevel@tonic-gate static char *unk_rx_ringsz_msg = 1527c478bd9Sstevel@tonic-gate "Unknown receive RINGSZ"; 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate static char *add_intr_fail_msg = 1557c478bd9Sstevel@tonic-gate "ddi_add_intr(9F) failed"; 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate static char *mregs_4global_reg_fail_msg = 1587c478bd9Sstevel@tonic-gate "ddi_regs_map_setup(9F) for global reg failed"; 1597c478bd9Sstevel@tonic-gate 1607c478bd9Sstevel@tonic-gate static char *mregs_4etx_reg_fail_msg = 1617c478bd9Sstevel@tonic-gate "ddi_map_regs for etx reg failed"; 1627c478bd9Sstevel@tonic-gate 1637c478bd9Sstevel@tonic-gate static char *mregs_4erx_reg_fail_msg = 1647c478bd9Sstevel@tonic-gate "ddi_map_regs for erx reg failed"; 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate static char *mregs_4bmac_reg_fail_msg = 1677c478bd9Sstevel@tonic-gate "ddi_map_regs for bmac reg failed"; 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate static char *mregs_4mif_reg_fail_msg = 1707c478bd9Sstevel@tonic-gate "ddi_map_regs for mif reg failed"; 1717c478bd9Sstevel@tonic-gate 1727c478bd9Sstevel@tonic-gate static char *init_fail_gen_msg = 1737c478bd9Sstevel@tonic-gate "Failed to initialize hardware/driver"; 1747c478bd9Sstevel@tonic-gate 1757c478bd9Sstevel@tonic-gate static char *ddi_nregs_fail_msg = 1767c478bd9Sstevel@tonic-gate "ddi_dev_nregs failed(9F), returned %d"; 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate static char *bad_num_regs_msg = 1797c478bd9Sstevel@tonic-gate "Invalid number of registers."; 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate /* FATAL ERR msgs */ 1837c478bd9Sstevel@tonic-gate /* 1847c478bd9Sstevel@tonic-gate * Function prototypes. 1857c478bd9Sstevel@tonic-gate */ 186f2cd0f02Sgd /* these two are global so that qfe can use them */ 187f2cd0f02Sgd int hmeattach(dev_info_t *, ddi_attach_cmd_t); 188f2cd0f02Sgd int hmedetach(dev_info_t *, ddi_detach_cmd_t); 1890219346bSGarrett D'Amore int hmequiesce(dev_info_t *); 19085025c03Sgd static boolean_t hmeinit_xfer_params(struct hme *); 1917c478bd9Sstevel@tonic-gate static uint_t hmestop(struct hme *); 1927c478bd9Sstevel@tonic-gate static void hmestatinit(struct hme *); 1937c478bd9Sstevel@tonic-gate static int hmeallocthings(struct hme *); 1940219346bSGarrett D'Amore static void hmefreethings(struct hme *); 1950219346bSGarrett D'Amore static int hmeallocbuf(struct hme *, hmebuf_t *, int); 1960219346bSGarrett D'Amore static int hmeallocbufs(struct hme *); 1977c478bd9Sstevel@tonic-gate static void hmefreebufs(struct hme *); 1987c478bd9Sstevel@tonic-gate static void hmeget_hm_rev_property(struct hme *); 19985025c03Sgd static boolean_t hmestart(struct hme *, mblk_t *); 20085025c03Sgd static uint_t hmeintr(caddr_t); 2017c478bd9Sstevel@tonic-gate static void hmereclaim(struct hme *); 2027c478bd9Sstevel@tonic-gate static int hmeinit(struct hme *); 2037c478bd9Sstevel@tonic-gate static void hmeuninit(struct hme *hmep); 2040219346bSGarrett D'Amore static mblk_t *hmeread(struct hme *, hmebuf_t *, uint32_t); 2057c478bd9Sstevel@tonic-gate static void hmesavecntrs(struct hme *); 2067c478bd9Sstevel@tonic-gate static void hme_fatal_err(struct hme *, uint_t); 2077c478bd9Sstevel@tonic-gate static void hme_nonfatal_err(struct hme *, uint_t); 2087c478bd9Sstevel@tonic-gate static int hmeburstsizes(struct hme *); 20906673d9bSGarrett D'Amore static void send_bit(struct hme *, uint16_t); 21006673d9bSGarrett D'Amore static uint16_t get_bit_std(uint8_t, struct hme *); 21106673d9bSGarrett D'Amore static uint16_t hme_bb_mii_read(struct hme *, uint8_t, uint8_t); 21206673d9bSGarrett D'Amore static void hme_bb_mii_write(struct hme *, uint8_t, uint8_t, uint16_t); 2137c478bd9Sstevel@tonic-gate static void hme_bb_force_idle(struct hme *); 21406673d9bSGarrett D'Amore static uint16_t hme_mii_read(void *, uint8_t, uint8_t); 21506673d9bSGarrett D'Amore static void hme_mii_write(void *, uint8_t, uint8_t, uint16_t); 2167c478bd9Sstevel@tonic-gate static void hme_setup_mac_address(struct hme *, dev_info_t *); 21706673d9bSGarrett D'Amore static void hme_mii_notify(void *, link_state_t); 2187c478bd9Sstevel@tonic-gate 2190219346bSGarrett D'Amore static void hme_fault_msg(struct hme *, uint_t, msg_t, char *, ...); 2207c478bd9Sstevel@tonic-gate 2217c478bd9Sstevel@tonic-gate static void hme_check_acc_handle(char *, uint_t, struct hme *, 22285025c03Sgd ddi_acc_handle_t); 2237c478bd9Sstevel@tonic-gate 22485025c03Sgd /* 22585025c03Sgd * Nemo (GLDv3) Functions. 22685025c03Sgd */ 22785025c03Sgd static int hme_m_stat(void *, uint_t, uint64_t *); 22885025c03Sgd static int hme_m_start(void *); 22985025c03Sgd static void hme_m_stop(void *); 23085025c03Sgd static int hme_m_promisc(void *, boolean_t); 23185025c03Sgd static int hme_m_multicst(void *, boolean_t, const uint8_t *); 23285025c03Sgd static int hme_m_unicst(void *, const uint8_t *); 23385025c03Sgd static mblk_t *hme_m_tx(void *, mblk_t *); 23485025c03Sgd static boolean_t hme_m_getcapab(void *, mac_capab_t, void *); 23506673d9bSGarrett D'Amore static int hme_m_getprop(void *, const char *, mac_prop_id_t, uint_t, 23606673d9bSGarrett D'Amore uint_t, void *, uint_t *); 23706673d9bSGarrett D'Amore static int hme_m_setprop(void *, const char *, mac_prop_id_t, uint_t, 23806673d9bSGarrett D'Amore const void *); 23906673d9bSGarrett D'Amore 24006673d9bSGarrett D'Amore static mii_ops_t hme_mii_ops = { 24106673d9bSGarrett D'Amore MII_OPS_VERSION, 24206673d9bSGarrett D'Amore hme_mii_read, 24306673d9bSGarrett D'Amore hme_mii_write, 24406673d9bSGarrett D'Amore hme_mii_notify, 24506673d9bSGarrett D'Amore NULL 24606673d9bSGarrett D'Amore }; 24785025c03Sgd 24885025c03Sgd static mac_callbacks_t hme_m_callbacks = { 24906673d9bSGarrett D'Amore MC_GETCAPAB | MC_SETPROP | MC_GETPROP, 25085025c03Sgd hme_m_stat, 25185025c03Sgd hme_m_start, 25285025c03Sgd hme_m_stop, 25385025c03Sgd hme_m_promisc, 25485025c03Sgd hme_m_multicst, 25585025c03Sgd hme_m_unicst, 25685025c03Sgd hme_m_tx, 25706673d9bSGarrett D'Amore NULL, 25885025c03Sgd hme_m_getcapab, 25906673d9bSGarrett D'Amore NULL, 26006673d9bSGarrett D'Amore NULL, 26106673d9bSGarrett D'Amore hme_m_setprop, 26206673d9bSGarrett D'Amore hme_m_getprop, 26385025c03Sgd }; 26485025c03Sgd 26585025c03Sgd DDI_DEFINE_STREAM_OPS(hme_dev_ops, nulldev, nulldev, hmeattach, hmedetach, 2660219346bSGarrett D'Amore nodev, NULL, D_MP, NULL, hmequiesce); 2677c478bd9Sstevel@tonic-gate 2687c478bd9Sstevel@tonic-gate #define HME_FAULT_MSG1(p, s, t, f) \ 2690219346bSGarrett D'Amore hme_fault_msg((p), (s), (t), (f)); 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate #define HME_FAULT_MSG2(p, s, t, f, a) \ 2720219346bSGarrett D'Amore hme_fault_msg((p), (s), (t), (f), (a)); 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate #define HME_FAULT_MSG3(p, s, t, f, a, b) \ 2750219346bSGarrett D'Amore hme_fault_msg((p), (s), (t), (f), (a), (b)); 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate #define HME_FAULT_MSG4(p, s, t, f, a, b, c) \ 2780219346bSGarrett D'Amore hme_fault_msg((p), (s), (t), (f), (a), (b), (c)); 2797c478bd9Sstevel@tonic-gate 2807c478bd9Sstevel@tonic-gate #define CHECK_MIFREG() \ 2817c478bd9Sstevel@tonic-gate hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_mifregh) 2827c478bd9Sstevel@tonic-gate #define CHECK_ETXREG() \ 2837c478bd9Sstevel@tonic-gate hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_etxregh) 2847c478bd9Sstevel@tonic-gate #define CHECK_ERXREG() \ 2857c478bd9Sstevel@tonic-gate hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_erxregh) 2867c478bd9Sstevel@tonic-gate #define CHECK_MACREG() \ 2877c478bd9Sstevel@tonic-gate hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_bmacregh) 2887c478bd9Sstevel@tonic-gate #define CHECK_GLOBREG() \ 2897c478bd9Sstevel@tonic-gate hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_globregh) 2907c478bd9Sstevel@tonic-gate 2917c478bd9Sstevel@tonic-gate /* 2927c478bd9Sstevel@tonic-gate * Claim the device is ultra-capable of burst in the beginning. Use 2937c478bd9Sstevel@tonic-gate * the value returned by ddi_dma_burstsizes() to actually set the HME 2947c478bd9Sstevel@tonic-gate * global configuration register later. 2957c478bd9Sstevel@tonic-gate * 2967c478bd9Sstevel@tonic-gate * Sbus/FEPS supports burst sizes of 16, 32 and 64 bytes. Also, it supports 2977c478bd9Sstevel@tonic-gate * 32-bit and 64-bit Sbus transfers. Hence the dlim_burstsizes field contains 2987c478bd9Sstevel@tonic-gate * the the burstsizes in both the lo and hi words. 2997c478bd9Sstevel@tonic-gate */ 3007c478bd9Sstevel@tonic-gate #define HMELIMADDRLO ((uint64_t)0x00000000) 3017c478bd9Sstevel@tonic-gate #define HMELIMADDRHI ((uint64_t)0xffffffff) 3027c478bd9Sstevel@tonic-gate 3030219346bSGarrett D'Amore /* 3040219346bSGarrett D'Amore * Note that rx and tx data buffers can be arbitrarily aligned, but 3050219346bSGarrett D'Amore * that the descriptor rings need to be aligned on 2K boundaries, per 3060219346bSGarrett D'Amore * the spec. 3070219346bSGarrett D'Amore */ 3087c478bd9Sstevel@tonic-gate static ddi_dma_attr_t hme_dma_attr = { 3097c478bd9Sstevel@tonic-gate DMA_ATTR_V0, /* version number. */ 3107c478bd9Sstevel@tonic-gate (uint64_t)HMELIMADDRLO, /* low address */ 3117c478bd9Sstevel@tonic-gate (uint64_t)HMELIMADDRHI, /* high address */ 3127c478bd9Sstevel@tonic-gate (uint64_t)0x00ffffff, /* address counter max */ 3130219346bSGarrett D'Amore (uint64_t)HME_HMDALIGN, /* alignment */ 3147c478bd9Sstevel@tonic-gate (uint_t)0x00700070, /* dlim_burstsizes for 32 and 64 bit xfers */ 3157c478bd9Sstevel@tonic-gate (uint32_t)0x1, /* minimum transfer size */ 3167c478bd9Sstevel@tonic-gate (uint64_t)0x7fffffff, /* maximum transfer size */ 3177c478bd9Sstevel@tonic-gate (uint64_t)0x00ffffff, /* maximum segment size */ 3187c478bd9Sstevel@tonic-gate 1, /* scatter/gather list length */ 3197c478bd9Sstevel@tonic-gate 512, /* granularity */ 3207c478bd9Sstevel@tonic-gate 0 /* attribute flags */ 3217c478bd9Sstevel@tonic-gate }; 3227c478bd9Sstevel@tonic-gate 3230219346bSGarrett D'Amore static ddi_device_acc_attr_t hme_buf_attr = { 3240219346bSGarrett D'Amore DDI_DEVICE_ATTR_V0, 3250219346bSGarrett D'Amore DDI_NEVERSWAP_ACC, 3260219346bSGarrett D'Amore DDI_STRICTORDER_ACC, /* probably could allow merging & caching */ 3270219346bSGarrett D'Amore DDI_DEFAULT_ACC, 3287c478bd9Sstevel@tonic-gate }; 3297c478bd9Sstevel@tonic-gate 3307c478bd9Sstevel@tonic-gate static uchar_t pci_latency_timer = 0; 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate /* 3337c478bd9Sstevel@tonic-gate * Module linkage information for the kernel. 3347c478bd9Sstevel@tonic-gate */ 3357c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 3367c478bd9Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a driver */ 33785025c03Sgd "Sun HME 10/100 Mb Ethernet", 33885025c03Sgd &hme_dev_ops, /* driver ops */ 3397c478bd9Sstevel@tonic-gate }; 3407c478bd9Sstevel@tonic-gate 3417c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 3427c478bd9Sstevel@tonic-gate MODREV_1, &modldrv, NULL 3437c478bd9Sstevel@tonic-gate }; 3447c478bd9Sstevel@tonic-gate 3457c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<<<<<<<<<<< Register operations >>>>>>>>>>>>>>>>>>>>> */ 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate #define GET_MIFREG(reg) \ 3487c478bd9Sstevel@tonic-gate ddi_get32(hmep->hme_mifregh, (uint32_t *)&hmep->hme_mifregp->reg) 3497c478bd9Sstevel@tonic-gate #define PUT_MIFREG(reg, value) \ 3507c478bd9Sstevel@tonic-gate ddi_put32(hmep->hme_mifregh, (uint32_t *)&hmep->hme_mifregp->reg, value) 3517c478bd9Sstevel@tonic-gate 3527c478bd9Sstevel@tonic-gate #define GET_ETXREG(reg) \ 3537c478bd9Sstevel@tonic-gate ddi_get32(hmep->hme_etxregh, (uint32_t *)&hmep->hme_etxregp->reg) 3547c478bd9Sstevel@tonic-gate #define PUT_ETXREG(reg, value) \ 3557c478bd9Sstevel@tonic-gate ddi_put32(hmep->hme_etxregh, (uint32_t *)&hmep->hme_etxregp->reg, value) 3567c478bd9Sstevel@tonic-gate #define GET_ERXREG(reg) \ 3577c478bd9Sstevel@tonic-gate ddi_get32(hmep->hme_erxregh, (uint32_t *)&hmep->hme_erxregp->reg) 3587c478bd9Sstevel@tonic-gate #define PUT_ERXREG(reg, value) \ 3597c478bd9Sstevel@tonic-gate ddi_put32(hmep->hme_erxregh, (uint32_t *)&hmep->hme_erxregp->reg, value) 3607c478bd9Sstevel@tonic-gate #define GET_MACREG(reg) \ 3617c478bd9Sstevel@tonic-gate ddi_get32(hmep->hme_bmacregh, (uint32_t *)&hmep->hme_bmacregp->reg) 3627c478bd9Sstevel@tonic-gate #define PUT_MACREG(reg, value) \ 3637c478bd9Sstevel@tonic-gate ddi_put32(hmep->hme_bmacregh, \ 3647c478bd9Sstevel@tonic-gate (uint32_t *)&hmep->hme_bmacregp->reg, value) 3657c478bd9Sstevel@tonic-gate #define GET_GLOBREG(reg) \ 3667c478bd9Sstevel@tonic-gate ddi_get32(hmep->hme_globregh, (uint32_t *)&hmep->hme_globregp->reg) 3677c478bd9Sstevel@tonic-gate #define PUT_GLOBREG(reg, value) \ 3687c478bd9Sstevel@tonic-gate ddi_put32(hmep->hme_globregh, \ 3697c478bd9Sstevel@tonic-gate (uint32_t *)&hmep->hme_globregp->reg, value) 3700219346bSGarrett D'Amore #define PUT_TMD(ptr, paddr, len, flags) \ 3710219346bSGarrett D'Amore ddi_put32(hmep->hme_tmd_acch, &hmep->hme_tmdp[ptr].tmd_addr, paddr); \ 3720219346bSGarrett D'Amore ddi_put32(hmep->hme_tmd_acch, &hmep->hme_tmdp[ptr].tmd_flags, \ 3730219346bSGarrett D'Amore len | flags) 3740219346bSGarrett D'Amore #define GET_TMD_FLAGS(ptr) \ 3750219346bSGarrett D'Amore ddi_get32(hmep->hme_tmd_acch, &hmep->hme_tmdp[ptr].tmd_flags) 3760219346bSGarrett D'Amore #define PUT_RMD(ptr, paddr) \ 3770219346bSGarrett D'Amore ddi_put32(hmep->hme_rmd_acch, &hmep->hme_rmdp[ptr].rmd_addr, paddr); \ 3780219346bSGarrett D'Amore ddi_put32(hmep->hme_rmd_acch, &hmep->hme_rmdp[ptr].rmd_flags, \ 3790219346bSGarrett D'Amore (uint32_t)(HMEBUFSIZE << HMERMD_BUFSIZE_SHIFT) | HMERMD_OWN) 3800219346bSGarrett D'Amore #define GET_RMD_FLAGS(ptr) \ 3810219346bSGarrett D'Amore ddi_get32(hmep->hme_rmd_acch, &hmep->hme_rmdp[ptr].rmd_flags) 3820219346bSGarrett D'Amore 3837c478bd9Sstevel@tonic-gate #define GET_ROM8(offset) \ 3847c478bd9Sstevel@tonic-gate ddi_get8((hmep->hme_romh), (offset)) 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate /* 3877c478bd9Sstevel@tonic-gate * Ether_copy is not endian-correct. Define an endian-correct version. 3887c478bd9Sstevel@tonic-gate */ 3897c478bd9Sstevel@tonic-gate #define ether_bcopy(a, b) (bcopy(a, b, 6)) 3907c478bd9Sstevel@tonic-gate 3917c478bd9Sstevel@tonic-gate /* 3927c478bd9Sstevel@tonic-gate * Ether-type is specifically big-endian, but data region is unknown endian 3937c478bd9Sstevel@tonic-gate */ 39485025c03Sgd #define get_ether_type(ptr) \ 39585025c03Sgd (((((uint8_t *)ptr)[12] << 8) | (((uint8_t *)ptr)[13]))) 3967c478bd9Sstevel@tonic-gate 3977c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<<<<<<<<<<< Configuration Parameters >>>>>>>>>>>>>>>>>>>>> */ 3987c478bd9Sstevel@tonic-gate 3997c478bd9Sstevel@tonic-gate #define BMAC_DEFAULT_JAMSIZE (0x04) /* jamsize equals 4 */ 4007c478bd9Sstevel@tonic-gate #define BMAC_LONG_JAMSIZE (0x10) /* jamsize equals 0x10 */ 4017c478bd9Sstevel@tonic-gate static int jamsize = BMAC_DEFAULT_JAMSIZE; 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate 4047c478bd9Sstevel@tonic-gate /* 4057c478bd9Sstevel@tonic-gate * Calculate the bit in the multicast address filter that selects the given 4067c478bd9Sstevel@tonic-gate * address. 4077c478bd9Sstevel@tonic-gate */ 4087c478bd9Sstevel@tonic-gate 4097c478bd9Sstevel@tonic-gate static uint32_t 41085025c03Sgd hmeladrf_bit(const uint8_t *addr) 4117c478bd9Sstevel@tonic-gate { 4127c478bd9Sstevel@tonic-gate uint32_t crc; 4137c478bd9Sstevel@tonic-gate 4147c478bd9Sstevel@tonic-gate CRC32(crc, addr, ETHERADDRL, -1U, crc32_table); 4157c478bd9Sstevel@tonic-gate 4167c478bd9Sstevel@tonic-gate /* 4177c478bd9Sstevel@tonic-gate * Just want the 6 most significant bits. 4187c478bd9Sstevel@tonic-gate */ 4197c478bd9Sstevel@tonic-gate return (crc >> 26); 4207c478bd9Sstevel@tonic-gate } 4217c478bd9Sstevel@tonic-gate 4227c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<<<<<<<<<<<<< Bit Bang Operations >>>>>>>>>>>>>>>>>>>>>>>> */ 4237c478bd9Sstevel@tonic-gate 4247c478bd9Sstevel@tonic-gate static void 42506673d9bSGarrett D'Amore send_bit(struct hme *hmep, uint16_t x) 4267c478bd9Sstevel@tonic-gate { 4277c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbdata, x); 4287c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbclk, HME_BBCLK_LOW); 4297c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbclk, HME_BBCLK_HIGH); 4307c478bd9Sstevel@tonic-gate } 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate 4337c478bd9Sstevel@tonic-gate /* 4347c478bd9Sstevel@tonic-gate * To read the MII register bits according to the IEEE Standard 4357c478bd9Sstevel@tonic-gate */ 43606673d9bSGarrett D'Amore static uint16_t 43706673d9bSGarrett D'Amore get_bit_std(uint8_t phyad, struct hme *hmep) 4387c478bd9Sstevel@tonic-gate { 43906673d9bSGarrett D'Amore uint16_t x; 4407c478bd9Sstevel@tonic-gate 4417c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbclk, HME_BBCLK_LOW); 4427c478bd9Sstevel@tonic-gate drv_usecwait(1); /* wait for >330 ns for stable data */ 44306673d9bSGarrett D'Amore if (phyad == HME_INTERNAL_PHYAD) 4447c478bd9Sstevel@tonic-gate x = (GET_MIFREG(mif_cfg) & HME_MIF_CFGM0) ? 1 : 0; 4457c478bd9Sstevel@tonic-gate else 4467c478bd9Sstevel@tonic-gate x = (GET_MIFREG(mif_cfg) & HME_MIF_CFGM1) ? 1 : 0; 4477c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbclk, HME_BBCLK_HIGH); 4487c478bd9Sstevel@tonic-gate return (x); 4497c478bd9Sstevel@tonic-gate } 4507c478bd9Sstevel@tonic-gate 4517c478bd9Sstevel@tonic-gate #define SEND_BIT(x) send_bit(hmep, x) 45206673d9bSGarrett D'Amore #define GET_BIT_STD(phyad, x) x = get_bit_std(phyad, hmep) 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate 4557c478bd9Sstevel@tonic-gate static void 45606673d9bSGarrett D'Amore hme_bb_mii_write(struct hme *hmep, uint8_t phyad, uint8_t regad, uint16_t data) 4577c478bd9Sstevel@tonic-gate { 4587c478bd9Sstevel@tonic-gate int i; 4597c478bd9Sstevel@tonic-gate 4607c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbopenb, 1); /* Enable the MII driver */ 4617c478bd9Sstevel@tonic-gate (void) hme_bb_force_idle(hmep); 4627c478bd9Sstevel@tonic-gate SEND_BIT(0); SEND_BIT(1); /* <ST> */ 4637c478bd9Sstevel@tonic-gate SEND_BIT(0); SEND_BIT(1); /* <OP> */ 4647c478bd9Sstevel@tonic-gate 4657c478bd9Sstevel@tonic-gate for (i = 4; i >= 0; i--) { /* <AAAAA> */ 4667c478bd9Sstevel@tonic-gate SEND_BIT((phyad >> i) & 1); 4677c478bd9Sstevel@tonic-gate } 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate for (i = 4; i >= 0; i--) { /* <RRRRR> */ 4707c478bd9Sstevel@tonic-gate SEND_BIT((regad >> i) & 1); 4717c478bd9Sstevel@tonic-gate } 4727c478bd9Sstevel@tonic-gate 4737c478bd9Sstevel@tonic-gate SEND_BIT(1); SEND_BIT(0); /* <TA> */ 4747c478bd9Sstevel@tonic-gate 4757c478bd9Sstevel@tonic-gate for (i = 0xf; i >= 0; i--) { /* <DDDDDDDDDDDDDDDD> */ 4767c478bd9Sstevel@tonic-gate SEND_BIT((data >> i) & 1); 4777c478bd9Sstevel@tonic-gate } 4787c478bd9Sstevel@tonic-gate 4797c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbopenb, 0); /* Disable the MII driver */ 4807c478bd9Sstevel@tonic-gate CHECK_MIFREG(); 4817c478bd9Sstevel@tonic-gate } 4827c478bd9Sstevel@tonic-gate 4837c478bd9Sstevel@tonic-gate /* Return 0 if OK, 1 if error (Transceiver does not talk management) */ 48406673d9bSGarrett D'Amore static uint16_t 48506673d9bSGarrett D'Amore hme_bb_mii_read(struct hme *hmep, uint8_t phyad, uint8_t regad) 4867c478bd9Sstevel@tonic-gate { 4877c478bd9Sstevel@tonic-gate int i; 4887c478bd9Sstevel@tonic-gate uint32_t x; 48906673d9bSGarrett D'Amore uint16_t data = 0; 4907c478bd9Sstevel@tonic-gate 4917c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbopenb, 1); /* Enable the MII driver */ 4927c478bd9Sstevel@tonic-gate (void) hme_bb_force_idle(hmep); 4937c478bd9Sstevel@tonic-gate SEND_BIT(0); SEND_BIT(1); /* <ST> */ 4947c478bd9Sstevel@tonic-gate SEND_BIT(1); SEND_BIT(0); /* <OP> */ 4957c478bd9Sstevel@tonic-gate for (i = 4; i >= 0; i--) { /* <AAAAA> */ 4967c478bd9Sstevel@tonic-gate SEND_BIT((phyad >> i) & 1); 4977c478bd9Sstevel@tonic-gate } 4987c478bd9Sstevel@tonic-gate for (i = 4; i >= 0; i--) { /* <RRRRR> */ 4997c478bd9Sstevel@tonic-gate SEND_BIT((regad >> i) & 1); 5007c478bd9Sstevel@tonic-gate } 5017c478bd9Sstevel@tonic-gate 5027c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbopenb, 0); /* Disable the MII driver */ 5037c478bd9Sstevel@tonic-gate 50406673d9bSGarrett D'Amore GET_BIT_STD(phyad, x); 50506673d9bSGarrett D'Amore GET_BIT_STD(phyad, x); /* <TA> */ 50606673d9bSGarrett D'Amore for (i = 0xf; i >= 0; i--) { /* <DDDDDDDDDDDDDDDD> */ 50706673d9bSGarrett D'Amore GET_BIT_STD(phyad, x); 50806673d9bSGarrett D'Amore data += (x << i); 5097c478bd9Sstevel@tonic-gate } 51006673d9bSGarrett D'Amore /* 51106673d9bSGarrett D'Amore * Kludge to get the Transceiver out of hung mode 51206673d9bSGarrett D'Amore */ 51306673d9bSGarrett D'Amore GET_BIT_STD(phyad, x); 51406673d9bSGarrett D'Amore GET_BIT_STD(phyad, x); 51506673d9bSGarrett D'Amore GET_BIT_STD(phyad, x); 5167c478bd9Sstevel@tonic-gate CHECK_MIFREG(); 51706673d9bSGarrett D'Amore return (data); 5187c478bd9Sstevel@tonic-gate } 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate 5217c478bd9Sstevel@tonic-gate static void 5227c478bd9Sstevel@tonic-gate hme_bb_force_idle(struct hme *hmep) 5237c478bd9Sstevel@tonic-gate { 5247c478bd9Sstevel@tonic-gate int i; 5257c478bd9Sstevel@tonic-gate 5267c478bd9Sstevel@tonic-gate for (i = 0; i < 33; i++) { 5277c478bd9Sstevel@tonic-gate SEND_BIT(1); 5287c478bd9Sstevel@tonic-gate } 5297c478bd9Sstevel@tonic-gate } 5307c478bd9Sstevel@tonic-gate 5317c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<<<<<<<<<End of Bit Bang Operations >>>>>>>>>>>>>>>>>>>>>>>> */ 5327c478bd9Sstevel@tonic-gate 5337c478bd9Sstevel@tonic-gate 5347c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<< Frame Register used for MII operations >>>>>>>>>>>>>>>>>>>> */ 5357c478bd9Sstevel@tonic-gate 5367c478bd9Sstevel@tonic-gate /* Return 0 if OK, 1 if error (Transceiver does not talk management) */ 53706673d9bSGarrett D'Amore static uint16_t 53806673d9bSGarrett D'Amore hme_mii_read(void *arg, uint8_t phyad, uint8_t regad) 5397c478bd9Sstevel@tonic-gate { 54006673d9bSGarrett D'Amore struct hme *hmep = arg; 5417c478bd9Sstevel@tonic-gate uint32_t frame; 542*e8717ca2SGarrett D'Amore uint32_t tmp_mif; 543*e8717ca2SGarrett D'Amore uint32_t tmp_xif; 5447c478bd9Sstevel@tonic-gate 545*e8717ca2SGarrett D'Amore tmp_mif = GET_MIFREG(mif_cfg); 546*e8717ca2SGarrett D'Amore tmp_xif = GET_MACREG(xifc); 547*e8717ca2SGarrett D'Amore 548*e8717ca2SGarrett D'Amore switch (phyad) { 549*e8717ca2SGarrett D'Amore case HME_EXTERNAL_PHYAD: 550*e8717ca2SGarrett D'Amore PUT_MIFREG(mif_cfg, tmp_mif | HME_MIF_CFGPS); 551*e8717ca2SGarrett D'Amore PUT_MACREG(xifc, tmp_xif | BMAC_XIFC_MIIBUFDIS); 552*e8717ca2SGarrett D'Amore break; 553*e8717ca2SGarrett D'Amore case HME_INTERNAL_PHYAD: 554*e8717ca2SGarrett D'Amore PUT_MIFREG(mif_cfg, tmp_mif & ~(HME_MIF_CFGPS)); 555*e8717ca2SGarrett D'Amore PUT_MACREG(xifc, tmp_xif & ~(BMAC_XIFC_MIIBUFDIS)); 556*e8717ca2SGarrett D'Amore break; 557*e8717ca2SGarrett D'Amore default: 558*e8717ca2SGarrett D'Amore return (0xffff); 559*e8717ca2SGarrett D'Amore } 560*e8717ca2SGarrett D'Amore 561*e8717ca2SGarrett D'Amore if (!hmep->hme_frame_enable) { 562*e8717ca2SGarrett D'Amore frame = (hme_bb_mii_read(hmep, phyad, regad)); 563*e8717ca2SGarrett D'Amore PUT_MACREG(xifc, tmp_xif); 564*e8717ca2SGarrett D'Amore PUT_MIFREG(mif_cfg, tmp_mif); 565*e8717ca2SGarrett D'Amore return (frame & 0xffff); 566*e8717ca2SGarrett D'Amore } 5677c478bd9Sstevel@tonic-gate 5680219346bSGarrett D'Amore PUT_MIFREG(mif_frame, 5690219346bSGarrett D'Amore HME_MIF_FRREAD | (phyad << HME_MIF_FRPHYAD_SHIFT) | 5700219346bSGarrett D'Amore (regad << HME_MIF_FRREGAD_SHIFT)); 5717c478bd9Sstevel@tonic-gate /* 5727c478bd9Sstevel@tonic-gate * HMEDELAY((*framerp & HME_MIF_FRTA0), HMEMAXRSTDELAY); 5737c478bd9Sstevel@tonic-gate */ 5740219346bSGarrett D'Amore HMEDELAY((GET_MIFREG(mif_frame) & HME_MIF_FRTA0), 300); 5750219346bSGarrett D'Amore frame = GET_MIFREG(mif_frame); 5767c478bd9Sstevel@tonic-gate CHECK_MIFREG(); 577*e8717ca2SGarrett D'Amore 578*e8717ca2SGarrett D'Amore PUT_MACREG(xifc, tmp_xif); 579*e8717ca2SGarrett D'Amore PUT_MIFREG(mif_cfg, tmp_mif); 580*e8717ca2SGarrett D'Amore 5817c478bd9Sstevel@tonic-gate if ((frame & HME_MIF_FRTA0) == 0) { 5827c478bd9Sstevel@tonic-gate 5837c478bd9Sstevel@tonic-gate 58406673d9bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, MII_MSG, 5850219346bSGarrett D'Amore "MIF Read failure"); 58606673d9bSGarrett D'Amore return (0xffff); 5877c478bd9Sstevel@tonic-gate } 58806673d9bSGarrett D'Amore return ((uint16_t)(frame & HME_MIF_FRDATA)); 5897c478bd9Sstevel@tonic-gate } 5907c478bd9Sstevel@tonic-gate 5917c478bd9Sstevel@tonic-gate static void 59206673d9bSGarrett D'Amore hme_mii_write(void *arg, uint8_t phyad, uint8_t regad, uint16_t data) 5937c478bd9Sstevel@tonic-gate { 59406673d9bSGarrett D'Amore struct hme *hmep = arg; 5957c478bd9Sstevel@tonic-gate uint32_t frame; 596*e8717ca2SGarrett D'Amore uint32_t tmp_mif; 597*e8717ca2SGarrett D'Amore uint32_t tmp_xif; 598*e8717ca2SGarrett D'Amore 599*e8717ca2SGarrett D'Amore tmp_mif = GET_MIFREG(mif_cfg); 600*e8717ca2SGarrett D'Amore tmp_xif = GET_MACREG(xifc); 601*e8717ca2SGarrett D'Amore 602*e8717ca2SGarrett D'Amore switch (phyad) { 603*e8717ca2SGarrett D'Amore case HME_EXTERNAL_PHYAD: 604*e8717ca2SGarrett D'Amore PUT_MIFREG(mif_cfg, tmp_mif | HME_MIF_CFGPS); 605*e8717ca2SGarrett D'Amore PUT_MACREG(xifc, tmp_xif | BMAC_XIFC_MIIBUFDIS); 606*e8717ca2SGarrett D'Amore break; 607*e8717ca2SGarrett D'Amore case HME_INTERNAL_PHYAD: 608*e8717ca2SGarrett D'Amore PUT_MIFREG(mif_cfg, tmp_mif & ~(HME_MIF_CFGPS)); 609*e8717ca2SGarrett D'Amore PUT_MACREG(xifc, tmp_xif & ~(BMAC_XIFC_MIIBUFDIS)); 610*e8717ca2SGarrett D'Amore break; 611*e8717ca2SGarrett D'Amore default: 612*e8717ca2SGarrett D'Amore return; 613*e8717ca2SGarrett D'Amore } 6147c478bd9Sstevel@tonic-gate 6157c478bd9Sstevel@tonic-gate if (!hmep->hme_frame_enable) { 61606673d9bSGarrett D'Amore hme_bb_mii_write(hmep, phyad, regad, data); 617*e8717ca2SGarrett D'Amore PUT_MACREG(xifc, tmp_xif); 618*e8717ca2SGarrett D'Amore PUT_MIFREG(mif_cfg, tmp_mif); 6197c478bd9Sstevel@tonic-gate return; 6207c478bd9Sstevel@tonic-gate } 6217c478bd9Sstevel@tonic-gate 6220219346bSGarrett D'Amore PUT_MIFREG(mif_frame, 6230219346bSGarrett D'Amore HME_MIF_FRWRITE | (phyad << HME_MIF_FRPHYAD_SHIFT) | 6240219346bSGarrett D'Amore (regad << HME_MIF_FRREGAD_SHIFT) | data); 6257c478bd9Sstevel@tonic-gate /* 6267c478bd9Sstevel@tonic-gate * HMEDELAY((*framerp & HME_MIF_FRTA0), HMEMAXRSTDELAY); 6277c478bd9Sstevel@tonic-gate */ 6280219346bSGarrett D'Amore HMEDELAY((GET_MIFREG(mif_frame) & HME_MIF_FRTA0), 300); 6290219346bSGarrett D'Amore frame = GET_MIFREG(mif_frame); 630*e8717ca2SGarrett D'Amore PUT_MACREG(xifc, tmp_xif); 631*e8717ca2SGarrett D'Amore PUT_MIFREG(mif_cfg, tmp_mif); 6327c478bd9Sstevel@tonic-gate CHECK_MIFREG(); 6337c478bd9Sstevel@tonic-gate if ((frame & HME_MIF_FRTA0) == 0) { 63406673d9bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_MID, MII_MSG, 6350219346bSGarrett D'Amore "MIF Write failure"); 6367c478bd9Sstevel@tonic-gate } 6377c478bd9Sstevel@tonic-gate } 6387c478bd9Sstevel@tonic-gate 6397c478bd9Sstevel@tonic-gate static void 64006673d9bSGarrett D'Amore hme_mii_notify(void *arg, link_state_t link) 6417c478bd9Sstevel@tonic-gate { 6427c478bd9Sstevel@tonic-gate struct hme *hmep = arg; 6437c478bd9Sstevel@tonic-gate 64406673d9bSGarrett D'Amore if (link == LINK_STATE_UP) { 64506673d9bSGarrett D'Amore (void) hmeinit(hmep); 6467c478bd9Sstevel@tonic-gate } 64706673d9bSGarrett D'Amore mac_link_update(hmep->hme_mh, link); 6487c478bd9Sstevel@tonic-gate } 6497c478bd9Sstevel@tonic-gate 6507c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<<<<<<<<<<<<<<<< LOADABLE ENTRIES >>>>>>>>>>>>>>>>>>>>>>> */ 6517c478bd9Sstevel@tonic-gate 6527c478bd9Sstevel@tonic-gate int 6537c478bd9Sstevel@tonic-gate _init(void) 6547c478bd9Sstevel@tonic-gate { 6557c478bd9Sstevel@tonic-gate int status; 6567c478bd9Sstevel@tonic-gate 65785025c03Sgd mac_init_ops(&hme_dev_ops, "hme"); 65885025c03Sgd if ((status = mod_install(&modlinkage)) != 0) { 65985025c03Sgd mac_fini_ops(&hme_dev_ops); 6607c478bd9Sstevel@tonic-gate } 6617c478bd9Sstevel@tonic-gate return (status); 6627c478bd9Sstevel@tonic-gate } 6637c478bd9Sstevel@tonic-gate 6647c478bd9Sstevel@tonic-gate int 6657c478bd9Sstevel@tonic-gate _fini(void) 6667c478bd9Sstevel@tonic-gate { 6677c478bd9Sstevel@tonic-gate int status; 6687c478bd9Sstevel@tonic-gate 66985025c03Sgd if ((status = mod_remove(&modlinkage)) == 0) { 67085025c03Sgd mac_fini_ops(&hme_dev_ops); 6717c478bd9Sstevel@tonic-gate } 6727c478bd9Sstevel@tonic-gate return (status); 6737c478bd9Sstevel@tonic-gate } 6747c478bd9Sstevel@tonic-gate 6757c478bd9Sstevel@tonic-gate int 6767c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 6777c478bd9Sstevel@tonic-gate { 6787c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 6797c478bd9Sstevel@tonic-gate } 6807c478bd9Sstevel@tonic-gate 6817c478bd9Sstevel@tonic-gate /* 6827c478bd9Sstevel@tonic-gate * ddi_dma_sync() a TMD or RMD descriptor. 6837c478bd9Sstevel@tonic-gate */ 6840219346bSGarrett D'Amore #define HMESYNCRMD(num, who) \ 6850219346bSGarrett D'Amore (void) ddi_dma_sync(hmep->hme_rmd_dmah, \ 6860219346bSGarrett D'Amore (num * sizeof (struct hme_rmd)), \ 6870219346bSGarrett D'Amore sizeof (struct hme_rmd), \ 6880219346bSGarrett D'Amore who) 6890219346bSGarrett D'Amore 6900219346bSGarrett D'Amore #define HMESYNCTMD(num, who) \ 6910219346bSGarrett D'Amore (void) ddi_dma_sync(hmep->hme_tmd_dmah, \ 6920219346bSGarrett D'Amore (num * sizeof (struct hme_tmd)), \ 6930219346bSGarrett D'Amore sizeof (struct hme_tmd), \ 6940219346bSGarrett D'Amore who) 6957c478bd9Sstevel@tonic-gate 6967c478bd9Sstevel@tonic-gate /* 6977c478bd9Sstevel@tonic-gate * Ethernet broadcast address definition. 6987c478bd9Sstevel@tonic-gate */ 6997c478bd9Sstevel@tonic-gate static struct ether_addr etherbroadcastaddr = { 7007c478bd9Sstevel@tonic-gate 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 7017c478bd9Sstevel@tonic-gate }; 7027c478bd9Sstevel@tonic-gate 7037c478bd9Sstevel@tonic-gate /* 7047c478bd9Sstevel@tonic-gate * MIB II broadcast/multicast packets 7057c478bd9Sstevel@tonic-gate */ 70685025c03Sgd #define IS_BROADCAST(pkt) (bcmp(pkt, ðerbroadcastaddr, ETHERADDRL) == 0) 70785025c03Sgd #define IS_MULTICAST(pkt) ((pkt[0] & 01) == 1) 70885025c03Sgd #define BUMP_InNUcast(hmep, pkt) \ 7090219346bSGarrett D'Amore if (IS_MULTICAST(pkt)) { \ 7100219346bSGarrett D'Amore if (IS_BROADCAST(pkt)) { \ 7110219346bSGarrett D'Amore hmep->hme_brdcstrcv++; \ 7120219346bSGarrett D'Amore } else { \ 7130219346bSGarrett D'Amore hmep->hme_multircv++; \ 7140219346bSGarrett D'Amore } \ 7150219346bSGarrett D'Amore } 71685025c03Sgd #define BUMP_OutNUcast(hmep, pkt) \ 7170219346bSGarrett D'Amore if (IS_MULTICAST(pkt)) { \ 7180219346bSGarrett D'Amore if (IS_BROADCAST(pkt)) { \ 7190219346bSGarrett D'Amore hmep->hme_brdcstxmt++; \ 7200219346bSGarrett D'Amore } else { \ 7210219346bSGarrett D'Amore hmep->hme_multixmt++; \ 7220219346bSGarrett D'Amore } \ 7230219346bSGarrett D'Amore } 7247c478bd9Sstevel@tonic-gate 7257c478bd9Sstevel@tonic-gate static int 7267c478bd9Sstevel@tonic-gate hme_create_prop_from_kw(dev_info_t *dip, char *vpdname, char *vpdstr) 7277c478bd9Sstevel@tonic-gate { 7287c478bd9Sstevel@tonic-gate char propstr[80]; 7297c478bd9Sstevel@tonic-gate int i, needprop = 0; 7307c478bd9Sstevel@tonic-gate struct ether_addr local_mac; 7317c478bd9Sstevel@tonic-gate 7327c478bd9Sstevel@tonic-gate if (strcmp(vpdname, "NA") == 0) { 7337c478bd9Sstevel@tonic-gate (void) strcpy(propstr, "local-mac-address"); 7347c478bd9Sstevel@tonic-gate needprop = 1; 7357c478bd9Sstevel@tonic-gate } else if (strcmp(vpdname, "Z0") == 0) { 7367c478bd9Sstevel@tonic-gate (void) strcpy(propstr, "model"); 7377c478bd9Sstevel@tonic-gate needprop = 1; 7387c478bd9Sstevel@tonic-gate } else if (strcmp(vpdname, "Z1") == 0) { 7397c478bd9Sstevel@tonic-gate (void) strcpy(propstr, "board-model"); 7407c478bd9Sstevel@tonic-gate needprop = 1; 7417c478bd9Sstevel@tonic-gate } 7427c478bd9Sstevel@tonic-gate 7437c478bd9Sstevel@tonic-gate if (needprop == 1) { 7440219346bSGarrett D'Amore 7457c478bd9Sstevel@tonic-gate if (strcmp(propstr, "local-mac-address") == 0) { 7467c478bd9Sstevel@tonic-gate for (i = 0; i < ETHERADDRL; i++) 7477c478bd9Sstevel@tonic-gate local_mac.ether_addr_octet[i] = 74885025c03Sgd (uchar_t)vpdstr[i]; 7497c478bd9Sstevel@tonic-gate if (ddi_prop_create(DDI_DEV_T_NONE, dip, 75085025c03Sgd DDI_PROP_CANSLEEP, propstr, 75185025c03Sgd (char *)local_mac.ether_addr_octet, ETHERADDRL) 75285025c03Sgd != DDI_SUCCESS) { 7537c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7547c478bd9Sstevel@tonic-gate } 7557c478bd9Sstevel@tonic-gate } else { 7567c478bd9Sstevel@tonic-gate if (ddi_prop_create(DDI_DEV_T_NONE, dip, 75785025c03Sgd DDI_PROP_CANSLEEP, propstr, vpdstr, 75885025c03Sgd strlen(vpdstr)+1) != DDI_SUCCESS) { 7597c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7607c478bd9Sstevel@tonic-gate } 7617c478bd9Sstevel@tonic-gate } 7627c478bd9Sstevel@tonic-gate } 7637c478bd9Sstevel@tonic-gate return (0); 7647c478bd9Sstevel@tonic-gate } 7657c478bd9Sstevel@tonic-gate 7667c478bd9Sstevel@tonic-gate /* 7677c478bd9Sstevel@tonic-gate * Get properties from old VPD 7687c478bd9Sstevel@tonic-gate * for PCI cards 7697c478bd9Sstevel@tonic-gate */ 7707c478bd9Sstevel@tonic-gate static int 7717c478bd9Sstevel@tonic-gate hme_get_oldvpd_props(dev_info_t *dip, int vpd_base) 7727c478bd9Sstevel@tonic-gate { 7737c478bd9Sstevel@tonic-gate struct hme *hmep; 7747c478bd9Sstevel@tonic-gate int vpd_start, vpd_len, kw_start, kw_len, kw_ptr; 7757c478bd9Sstevel@tonic-gate char kw_namestr[3]; 7767c478bd9Sstevel@tonic-gate char kw_fieldstr[256]; 7777c478bd9Sstevel@tonic-gate int i; 7787c478bd9Sstevel@tonic-gate 7797c478bd9Sstevel@tonic-gate hmep = ddi_get_driver_private(dip); 7807c478bd9Sstevel@tonic-gate 7817c478bd9Sstevel@tonic-gate vpd_start = vpd_base; 7827c478bd9Sstevel@tonic-gate 7837c478bd9Sstevel@tonic-gate if ((GET_ROM8(&hmep->hme_romp[vpd_start]) & 0xff) != 0x90) { 7847c478bd9Sstevel@tonic-gate return (1); /* error */ 7857c478bd9Sstevel@tonic-gate } else { 7867c478bd9Sstevel@tonic-gate vpd_len = 9; 7877c478bd9Sstevel@tonic-gate } 7887c478bd9Sstevel@tonic-gate 7897c478bd9Sstevel@tonic-gate /* Get local-mac-address */ 7907c478bd9Sstevel@tonic-gate kw_start = vpd_start + 3; /* Location of 1st keyword */ 7917c478bd9Sstevel@tonic-gate kw_ptr = kw_start; 7927c478bd9Sstevel@tonic-gate while ((kw_ptr - kw_start) < vpd_len) { /* Get all keywords */ 7937c478bd9Sstevel@tonic-gate kw_namestr[0] = GET_ROM8(&hmep->hme_romp[kw_ptr]); 7947c478bd9Sstevel@tonic-gate kw_namestr[1] = GET_ROM8(&hmep->hme_romp[kw_ptr+1]); 7957c478bd9Sstevel@tonic-gate kw_namestr[2] = '\0'; 7967c478bd9Sstevel@tonic-gate kw_len = (int)(GET_ROM8(&hmep->hme_romp[kw_ptr+2]) & 0xff); 7977c478bd9Sstevel@tonic-gate for (i = 0, kw_ptr += 3; i < kw_len; i++) 7987c478bd9Sstevel@tonic-gate kw_fieldstr[i] = GET_ROM8(&hmep->hme_romp[kw_ptr+i]); 7997c478bd9Sstevel@tonic-gate kw_fieldstr[i] = '\0'; 8007c478bd9Sstevel@tonic-gate if (hme_create_prop_from_kw(dip, kw_namestr, kw_fieldstr)) { 8017c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 8027c478bd9Sstevel@tonic-gate } 8037c478bd9Sstevel@tonic-gate kw_ptr += kw_len; 8047c478bd9Sstevel@tonic-gate } /* next keyword */ 8057c478bd9Sstevel@tonic-gate 80685025c03Sgd if (ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, "model", 80785025c03Sgd "SUNW,cheerio", strlen("SUNW,cheerio")+1) != DDI_SUCCESS) { 8087c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 8097c478bd9Sstevel@tonic-gate } 8107c478bd9Sstevel@tonic-gate return (0); 8117c478bd9Sstevel@tonic-gate } 8127c478bd9Sstevel@tonic-gate 8137c478bd9Sstevel@tonic-gate 8147c478bd9Sstevel@tonic-gate /* 8157c478bd9Sstevel@tonic-gate * Get properties from new VPD 8167c478bd9Sstevel@tonic-gate * for CompactPCI cards 8177c478bd9Sstevel@tonic-gate */ 8187c478bd9Sstevel@tonic-gate static int 8197c478bd9Sstevel@tonic-gate hme_get_newvpd_props(dev_info_t *dip, int vpd_base) 8207c478bd9Sstevel@tonic-gate { 8217c478bd9Sstevel@tonic-gate struct hme *hmep; 8227c478bd9Sstevel@tonic-gate int vpd_start, vpd_len, kw_start, kw_len, kw_ptr; 8237c478bd9Sstevel@tonic-gate char kw_namestr[3]; 8247c478bd9Sstevel@tonic-gate char kw_fieldstr[256]; 8257c478bd9Sstevel@tonic-gate int maxvpdsize, i; 8267c478bd9Sstevel@tonic-gate 8277c478bd9Sstevel@tonic-gate hmep = ddi_get_driver_private(dip); 8287c478bd9Sstevel@tonic-gate 8297c478bd9Sstevel@tonic-gate maxvpdsize = 1024; /* Real size not known until after it is read */ 8307c478bd9Sstevel@tonic-gate 8317c478bd9Sstevel@tonic-gate vpd_start = (int)((GET_ROM8(&(hmep->hme_romp[vpd_base+1])) & 0xff) | 83285025c03Sgd ((GET_ROM8(&hmep->hme_romp[vpd_base+2]) & 0xff) << 8)) +3; 8337c478bd9Sstevel@tonic-gate vpd_start = vpd_base + vpd_start; 8347c478bd9Sstevel@tonic-gate while (vpd_start < (vpd_base + maxvpdsize)) { /* Get all VPDs */ 8357c478bd9Sstevel@tonic-gate if ((GET_ROM8(&hmep->hme_romp[vpd_start]) & 0xff) != 0x90) { 8367c478bd9Sstevel@tonic-gate break; /* no VPD found */ 8377c478bd9Sstevel@tonic-gate } else { 8387c478bd9Sstevel@tonic-gate vpd_len = (int)((GET_ROM8(&hmep->hme_romp[vpd_start 83985025c03Sgd + 1]) & 0xff) | (GET_ROM8(&hmep->hme_romp[vpd_start 84085025c03Sgd + 2]) & 0xff) << 8); 8417c478bd9Sstevel@tonic-gate } 8427c478bd9Sstevel@tonic-gate /* Get all keywords in this VPD */ 8437c478bd9Sstevel@tonic-gate kw_start = vpd_start + 3; /* Location of 1st keyword */ 8447c478bd9Sstevel@tonic-gate kw_ptr = kw_start; 8457c478bd9Sstevel@tonic-gate while ((kw_ptr - kw_start) < vpd_len) { /* Get all keywords */ 8467c478bd9Sstevel@tonic-gate kw_namestr[0] = GET_ROM8(&hmep->hme_romp[kw_ptr]); 8477c478bd9Sstevel@tonic-gate kw_namestr[1] = GET_ROM8(&hmep->hme_romp[kw_ptr+1]); 8487c478bd9Sstevel@tonic-gate kw_namestr[2] = '\0'; 84985025c03Sgd kw_len = 85085025c03Sgd (int)(GET_ROM8(&hmep->hme_romp[kw_ptr+2]) & 0xff); 8517c478bd9Sstevel@tonic-gate for (i = 0, kw_ptr += 3; i < kw_len; i++) 85285025c03Sgd kw_fieldstr[i] = 85385025c03Sgd GET_ROM8(&hmep->hme_romp[kw_ptr+i]); 8547c478bd9Sstevel@tonic-gate kw_fieldstr[i] = '\0'; 8557c478bd9Sstevel@tonic-gate if (hme_create_prop_from_kw(dip, kw_namestr, 85685025c03Sgd kw_fieldstr)) { 8577c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 8587c478bd9Sstevel@tonic-gate } 8597c478bd9Sstevel@tonic-gate kw_ptr += kw_len; 8607c478bd9Sstevel@tonic-gate } /* next keyword */ 8617c478bd9Sstevel@tonic-gate vpd_start += (vpd_len + 3); 8627c478bd9Sstevel@tonic-gate } /* next VPD */ 8637c478bd9Sstevel@tonic-gate return (0); 8647c478bd9Sstevel@tonic-gate } 8657c478bd9Sstevel@tonic-gate 8667c478bd9Sstevel@tonic-gate 8677c478bd9Sstevel@tonic-gate /* 8687c478bd9Sstevel@tonic-gate * Get properties from VPD 8697c478bd9Sstevel@tonic-gate */ 8707c478bd9Sstevel@tonic-gate static int 8717c478bd9Sstevel@tonic-gate hme_get_vpd_props(dev_info_t *dip) 8727c478bd9Sstevel@tonic-gate { 8737c478bd9Sstevel@tonic-gate struct hme *hmep; 8747c478bd9Sstevel@tonic-gate int v0, v1, vpd_base; 8757c478bd9Sstevel@tonic-gate int i, epromsrchlimit; 8767c478bd9Sstevel@tonic-gate 8777c478bd9Sstevel@tonic-gate 8787c478bd9Sstevel@tonic-gate hmep = ddi_get_driver_private(dip); 8797c478bd9Sstevel@tonic-gate 8807c478bd9Sstevel@tonic-gate v0 = (int)(GET_ROM8(&(hmep->hme_romp[0]))); 8817c478bd9Sstevel@tonic-gate v1 = (int)(GET_ROM8(&(hmep->hme_romp[1]))); 8827c478bd9Sstevel@tonic-gate v0 = ((v0 & 0xff) << 8 | v1); 8837c478bd9Sstevel@tonic-gate 8847c478bd9Sstevel@tonic-gate if ((v0 & 0xffff) != 0x55aa) { 8857c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, " Valid pci prom not found \n"); 8867c478bd9Sstevel@tonic-gate return (1); 8877c478bd9Sstevel@tonic-gate } 8887c478bd9Sstevel@tonic-gate 8897c478bd9Sstevel@tonic-gate epromsrchlimit = 4096; 8907c478bd9Sstevel@tonic-gate for (i = 2; i < epromsrchlimit; i++) { 89185025c03Sgd /* "PCIR" */ 89285025c03Sgd if (((GET_ROM8(&(hmep->hme_romp[i])) & 0xff) == 'P') && 89385025c03Sgd ((GET_ROM8(&(hmep->hme_romp[i+1])) & 0xff) == 'C') && 89485025c03Sgd ((GET_ROM8(&(hmep->hme_romp[i+2])) & 0xff) == 'I') && 89585025c03Sgd ((GET_ROM8(&(hmep->hme_romp[i+3])) & 0xff) == 'R')) { 89685025c03Sgd vpd_base = 89785025c03Sgd (int)((GET_ROM8(&(hmep->hme_romp[i+8])) & 0xff) | 89885025c03Sgd (GET_ROM8(&(hmep->hme_romp[i+9])) & 0xff) << 8); 8997c478bd9Sstevel@tonic-gate break; /* VPD pointer found */ 9007c478bd9Sstevel@tonic-gate } 9017c478bd9Sstevel@tonic-gate } 9027c478bd9Sstevel@tonic-gate 9037c478bd9Sstevel@tonic-gate /* No VPD found */ 9047c478bd9Sstevel@tonic-gate if (vpd_base == 0) { 9057c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, " Vital Product Data pointer not found \n"); 9067c478bd9Sstevel@tonic-gate return (1); 9077c478bd9Sstevel@tonic-gate } 9087c478bd9Sstevel@tonic-gate 9097c478bd9Sstevel@tonic-gate v0 = (int)(GET_ROM8(&(hmep->hme_romp[vpd_base]))); 9107c478bd9Sstevel@tonic-gate if (v0 == 0x82) { 9117c478bd9Sstevel@tonic-gate if (hme_get_newvpd_props(dip, vpd_base)) 9127c478bd9Sstevel@tonic-gate return (1); 9137c478bd9Sstevel@tonic-gate return (0); 9147c478bd9Sstevel@tonic-gate } else if (v0 == 0x90) { 9150219346bSGarrett D'Amore /* If we are are SUNW,qfe card, look for the Nth "NA" descr */ 9160219346bSGarrett D'Amore if ((GET_ROM8(&hmep->hme_romp[vpd_base + 12]) != 0x79) && 9170219346bSGarrett D'Amore GET_ROM8(&hmep->hme_romp[vpd_base + 4 * 12]) == 0x79) { 9180219346bSGarrett D'Amore vpd_base += hmep->hme_devno * 12; 9190219346bSGarrett D'Amore } 9207c478bd9Sstevel@tonic-gate if (hme_get_oldvpd_props(dip, vpd_base)) 9217c478bd9Sstevel@tonic-gate return (1); 9227c478bd9Sstevel@tonic-gate return (0); 9237c478bd9Sstevel@tonic-gate } else 9247c478bd9Sstevel@tonic-gate return (1); /* unknown start byte in VPD */ 9257c478bd9Sstevel@tonic-gate } 9267c478bd9Sstevel@tonic-gate 9270219346bSGarrett D'Amore /* 9280219346bSGarrett D'Amore * For x86, the BIOS doesn't map the PCI Rom register for the qfe 9290219346bSGarrett D'Amore * cards, so we have to extract it from the ebus bridge that is 9300219346bSGarrett D'Amore * function zero of the same device. This is a bit of an ugly hack. 9310219346bSGarrett D'Amore * (The ebus bridge leaves the entire ROM mapped at base address 9320219346bSGarrett D'Amore * register 0x10.) 9330219346bSGarrett D'Amore */ 9340219346bSGarrett D'Amore 9350219346bSGarrett D'Amore typedef struct { 9360219346bSGarrett D'Amore struct hme *hmep; 9370219346bSGarrett D'Amore dev_info_t *parent; 9380219346bSGarrett D'Amore uint8_t bus, dev; 9390219346bSGarrett D'Amore ddi_acc_handle_t acch; 9400219346bSGarrett D'Amore caddr_t romp; 9410219346bSGarrett D'Amore } ebus_rom_t; 9420219346bSGarrett D'Amore 9430219346bSGarrett D'Amore static int 9440219346bSGarrett D'Amore hme_mapebusrom(dev_info_t *dip, void *arg) 9450219346bSGarrett D'Amore { 9460219346bSGarrett D'Amore int *regs; 9470219346bSGarrett D'Amore unsigned nregs; 9480219346bSGarrett D'Amore int reg; 9490219346bSGarrett D'Amore ebus_rom_t *rom = arg; 9500219346bSGarrett D'Amore struct hme *hmep = rom->hmep; 9510219346bSGarrett D'Amore 9520219346bSGarrett D'Amore /* 9530219346bSGarrett D'Amore * We only want to look at our peers. Skip our parent. 9540219346bSGarrett D'Amore */ 9550219346bSGarrett D'Amore if (dip == rom->parent) { 9560219346bSGarrett D'Amore return (DDI_WALK_PRUNESIB); 9570219346bSGarrett D'Amore } 9580219346bSGarrett D'Amore 95906673d9bSGarrett D'Amore if (ddi_get_parent(dip) != rom->parent) 96006673d9bSGarrett D'Amore return (DDI_WALK_CONTINUE); 96106673d9bSGarrett D'Amore 9620219346bSGarrett D'Amore if ((ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 0, 9630219346bSGarrett D'Amore "reg", ®s, &nregs)) != DDI_PROP_SUCCESS) { 9640219346bSGarrett D'Amore return (DDI_WALK_PRUNECHILD); 9650219346bSGarrett D'Amore } 9660219346bSGarrett D'Amore 9670219346bSGarrett D'Amore if (nregs < 1) { 9680219346bSGarrett D'Amore ddi_prop_free(regs); 9690219346bSGarrett D'Amore return (DDI_WALK_PRUNECHILD); 9700219346bSGarrett D'Amore } 9710219346bSGarrett D'Amore reg = regs[0]; 9720219346bSGarrett D'Amore ddi_prop_free(regs); 9730219346bSGarrett D'Amore 9740219346bSGarrett D'Amore /* 9750219346bSGarrett D'Amore * Look for function 0 on our bus and device. If the device doesn't 9760219346bSGarrett D'Amore * match, it might be an alternate peer, in which case we don't want 9770219346bSGarrett D'Amore * to examine any of its children. 9780219346bSGarrett D'Amore */ 9790219346bSGarrett D'Amore if ((PCI_REG_BUS_G(reg) != rom->bus) || 9800219346bSGarrett D'Amore (PCI_REG_DEV_G(reg) != rom->dev) || 9810219346bSGarrett D'Amore (PCI_REG_FUNC_G(reg) != 0)) { 9820219346bSGarrett D'Amore return (DDI_WALK_PRUNECHILD); 9830219346bSGarrett D'Amore } 9840219346bSGarrett D'Amore 9850219346bSGarrett D'Amore (void) ddi_regs_map_setup(dip, 1, &rom->romp, 0, 0, &hmep->hme_dev_attr, 9860219346bSGarrett D'Amore &rom->acch); 9870219346bSGarrett D'Amore /* 9880219346bSGarrett D'Amore * If we can't map the registers, the caller will notice that 9890219346bSGarrett D'Amore * the acch is NULL. 9900219346bSGarrett D'Amore */ 9910219346bSGarrett D'Amore return (DDI_WALK_TERMINATE); 9920219346bSGarrett D'Amore } 9930219346bSGarrett D'Amore 9940219346bSGarrett D'Amore static int 9950219346bSGarrett D'Amore hmeget_promebus(dev_info_t *dip) 9960219346bSGarrett D'Amore { 9970219346bSGarrett D'Amore ebus_rom_t rom; 9980219346bSGarrett D'Amore int *regs; 9990219346bSGarrett D'Amore unsigned nregs; 10000219346bSGarrett D'Amore struct hme *hmep; 10010219346bSGarrett D'Amore 10020219346bSGarrett D'Amore hmep = ddi_get_driver_private(dip); 10030219346bSGarrett D'Amore 10040219346bSGarrett D'Amore bzero(&rom, sizeof (rom)); 10050219346bSGarrett D'Amore 10060219346bSGarrett D'Amore /* 10070219346bSGarrett D'Amore * For x86, the BIOS doesn't map the PCI Rom register for the qfe 10080219346bSGarrett D'Amore * cards, so we have to extract it from the eBus bridge that is 10090219346bSGarrett D'Amore * function zero. This is a bit of an ugly hack. 10100219346bSGarrett D'Amore */ 10110219346bSGarrett D'Amore if ((ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 0, 10120219346bSGarrett D'Amore "reg", ®s, &nregs)) != DDI_PROP_SUCCESS) { 10130219346bSGarrett D'Amore return (DDI_FAILURE); 10140219346bSGarrett D'Amore } 10150219346bSGarrett D'Amore 10160219346bSGarrett D'Amore if (nregs < 5) { 10170219346bSGarrett D'Amore ddi_prop_free(regs); 10180219346bSGarrett D'Amore return (DDI_FAILURE); 10190219346bSGarrett D'Amore } 10200219346bSGarrett D'Amore rom.hmep = hmep; 10210219346bSGarrett D'Amore rom.bus = PCI_REG_BUS_G(regs[0]); 10220219346bSGarrett D'Amore rom.dev = PCI_REG_DEV_G(regs[0]); 10230219346bSGarrett D'Amore hmep->hme_devno = rom.dev; 10240219346bSGarrett D'Amore rom.parent = ddi_get_parent(dip); 10250219346bSGarrett D'Amore 10260219346bSGarrett D'Amore /* 10270219346bSGarrett D'Amore * The implementation of ddi_walk_devs says that we must not 102806673d9bSGarrett D'Amore * be called during autoconfiguration. However, it turns out 102906673d9bSGarrett D'Amore * that it is safe to call this during our attach routine, 103006673d9bSGarrett D'Amore * because we are not a nexus device. 10310219346bSGarrett D'Amore * 103206673d9bSGarrett D'Amore * Previously we rooted our search at our immediate parent, 103306673d9bSGarrett D'Amore * but this triggered an assertion panic in debug kernels. 10340219346bSGarrett D'Amore */ 103506673d9bSGarrett D'Amore ddi_walk_devs(ddi_root_node(), hme_mapebusrom, &rom); 10360219346bSGarrett D'Amore 10370219346bSGarrett D'Amore if (rom.acch) { 10380219346bSGarrett D'Amore hmep->hme_romh = rom.acch; 10390219346bSGarrett D'Amore hmep->hme_romp = (unsigned char *)rom.romp; 10400219346bSGarrett D'Amore return (DDI_SUCCESS); 10410219346bSGarrett D'Amore } 10420219346bSGarrett D'Amore return (DDI_FAILURE); 10430219346bSGarrett D'Amore } 10440219346bSGarrett D'Amore 10457c478bd9Sstevel@tonic-gate static int 10467c478bd9Sstevel@tonic-gate hmeget_promprops(dev_info_t *dip) 10477c478bd9Sstevel@tonic-gate { 10487c478bd9Sstevel@tonic-gate struct hme *hmep; 10497c478bd9Sstevel@tonic-gate int rom_bar; 10507c478bd9Sstevel@tonic-gate ddi_acc_handle_t cfg_handle; 10517c478bd9Sstevel@tonic-gate struct { 10527c478bd9Sstevel@tonic-gate uint16_t vendorid; 10537c478bd9Sstevel@tonic-gate uint16_t devid; 10547c478bd9Sstevel@tonic-gate uint16_t command; 10557c478bd9Sstevel@tonic-gate uint16_t status; 10567c478bd9Sstevel@tonic-gate uint32_t junk1; 10577c478bd9Sstevel@tonic-gate uint8_t cache_line; 10587c478bd9Sstevel@tonic-gate uint8_t latency; 10597c478bd9Sstevel@tonic-gate uint8_t header; 10607c478bd9Sstevel@tonic-gate uint8_t bist; 10617c478bd9Sstevel@tonic-gate uint32_t base; 10627c478bd9Sstevel@tonic-gate uint32_t base14; 10637c478bd9Sstevel@tonic-gate uint32_t base18; 10647c478bd9Sstevel@tonic-gate uint32_t base1c; 10657c478bd9Sstevel@tonic-gate uint32_t base20; 10667c478bd9Sstevel@tonic-gate uint32_t base24; 10677c478bd9Sstevel@tonic-gate uint32_t base28; 10687c478bd9Sstevel@tonic-gate uint32_t base2c; 10697c478bd9Sstevel@tonic-gate uint32_t base30; 10707c478bd9Sstevel@tonic-gate } *cfg_ptr; 10717c478bd9Sstevel@tonic-gate 10727c478bd9Sstevel@tonic-gate hmep = ddi_get_driver_private(dip); 10737c478bd9Sstevel@tonic-gate 10747c478bd9Sstevel@tonic-gate 10757c478bd9Sstevel@tonic-gate /* 10767c478bd9Sstevel@tonic-gate * map configuration space 10777c478bd9Sstevel@tonic-gate */ 10787c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(hmep->dip, 0, (caddr_t *)&cfg_ptr, 107985025c03Sgd 0, 0, &hmep->hme_dev_attr, &cfg_handle)) { 10807c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 10817c478bd9Sstevel@tonic-gate } 10827c478bd9Sstevel@tonic-gate 10837c478bd9Sstevel@tonic-gate /* 10847c478bd9Sstevel@tonic-gate * Enable bus-master and memory accesses 10857c478bd9Sstevel@tonic-gate */ 10867c478bd9Sstevel@tonic-gate ddi_put16(cfg_handle, &cfg_ptr->command, 108785025c03Sgd PCI_COMM_SERR_ENABLE | PCI_COMM_PARITY_DETECT | 108885025c03Sgd PCI_COMM_MAE | PCI_COMM_ME); 10897c478bd9Sstevel@tonic-gate 10907c478bd9Sstevel@tonic-gate /* 10917c478bd9Sstevel@tonic-gate * Enable rom accesses 10927c478bd9Sstevel@tonic-gate */ 10937c478bd9Sstevel@tonic-gate rom_bar = ddi_get32(cfg_handle, &cfg_ptr->base30); 10947c478bd9Sstevel@tonic-gate ddi_put32(cfg_handle, &cfg_ptr->base30, rom_bar | 1); 10957c478bd9Sstevel@tonic-gate 10967c478bd9Sstevel@tonic-gate 10970219346bSGarrett D'Amore if ((ddi_regs_map_setup(dip, 2, (caddr_t *)&(hmep->hme_romp), 0, 0, 10980219346bSGarrett D'Amore &hmep->hme_dev_attr, &hmep->hme_romh) != DDI_SUCCESS) && 10990219346bSGarrett D'Amore (hmeget_promebus(dip) != DDI_SUCCESS)) { 11000219346bSGarrett D'Amore 11017c478bd9Sstevel@tonic-gate if (cfg_ptr) 11027c478bd9Sstevel@tonic-gate ddi_regs_map_free(&cfg_handle); 11037c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 11047c478bd9Sstevel@tonic-gate } else { 11057c478bd9Sstevel@tonic-gate if (hme_get_vpd_props(dip)) 11060219346bSGarrett D'Amore return (DDI_FAILURE); 11077c478bd9Sstevel@tonic-gate } 11087c478bd9Sstevel@tonic-gate if (hmep->hme_romp) 11097c478bd9Sstevel@tonic-gate ddi_regs_map_free(&hmep->hme_romh); 11107c478bd9Sstevel@tonic-gate if (cfg_ptr) 11117c478bd9Sstevel@tonic-gate ddi_regs_map_free(&cfg_handle); 11120219346bSGarrett D'Amore return (DDI_SUCCESS); 11137c478bd9Sstevel@tonic-gate 11147c478bd9Sstevel@tonic-gate } 11157c478bd9Sstevel@tonic-gate 11167c478bd9Sstevel@tonic-gate static void 11177c478bd9Sstevel@tonic-gate hmeget_hm_rev_property(struct hme *hmep) 11187c478bd9Sstevel@tonic-gate { 11197c478bd9Sstevel@tonic-gate int hm_rev; 11207c478bd9Sstevel@tonic-gate 11217c478bd9Sstevel@tonic-gate 11227c478bd9Sstevel@tonic-gate hm_rev = hmep->asic_rev; 11237c478bd9Sstevel@tonic-gate switch (hm_rev) { 11247c478bd9Sstevel@tonic-gate case HME_2P1_REVID: 11257c478bd9Sstevel@tonic-gate case HME_2P1_REVID_OBP: 11267c478bd9Sstevel@tonic-gate HME_FAULT_MSG2(hmep, SEVERITY_NONE, DISPLAY_MSG, 112785025c03Sgd "SBus 2.1 Found (Rev Id = %x)", hm_rev); 11287c478bd9Sstevel@tonic-gate hmep->hme_frame_enable = 1; 11297c478bd9Sstevel@tonic-gate break; 11307c478bd9Sstevel@tonic-gate 11317c478bd9Sstevel@tonic-gate case HME_2P0_REVID: 11327c478bd9Sstevel@tonic-gate HME_FAULT_MSG2(hmep, SEVERITY_NONE, DISPLAY_MSG, 113385025c03Sgd "SBus 2.0 Found (Rev Id = %x)", hm_rev); 11347c478bd9Sstevel@tonic-gate break; 11357c478bd9Sstevel@tonic-gate 11367c478bd9Sstevel@tonic-gate case HME_1C0_REVID: 11377c478bd9Sstevel@tonic-gate HME_FAULT_MSG2(hmep, SEVERITY_NONE, DISPLAY_MSG, 113885025c03Sgd "PCI IO 1.0 Found (Rev Id = %x)", hm_rev); 11397c478bd9Sstevel@tonic-gate break; 11407c478bd9Sstevel@tonic-gate 11417c478bd9Sstevel@tonic-gate default: 114206673d9bSGarrett D'Amore HME_FAULT_MSG3(hmep, SEVERITY_NONE, DISPLAY_MSG, 114385025c03Sgd "%s (Rev Id = %x) Found", 114485025c03Sgd (hm_rev == HME_2C0_REVID) ? "PCI IO 2.0" : "Sbus", hm_rev); 11457c478bd9Sstevel@tonic-gate hmep->hme_frame_enable = 1; 11467c478bd9Sstevel@tonic-gate hmep->hme_lance_mode_enable = 1; 11477c478bd9Sstevel@tonic-gate hmep->hme_rxcv_enable = 1; 11487c478bd9Sstevel@tonic-gate break; 11497c478bd9Sstevel@tonic-gate } 11507c478bd9Sstevel@tonic-gate } 11517c478bd9Sstevel@tonic-gate 11527c478bd9Sstevel@tonic-gate /* 11537c478bd9Sstevel@tonic-gate * Interface exists: make available by filling in network interface 11547c478bd9Sstevel@tonic-gate * record. System will initialize the interface when it is ready 11557c478bd9Sstevel@tonic-gate * to accept packets. 11567c478bd9Sstevel@tonic-gate */ 1157f2cd0f02Sgd int 11587c478bd9Sstevel@tonic-gate hmeattach(dev_info_t *dip, ddi_attach_cmd_t cmd) 11597c478bd9Sstevel@tonic-gate { 11607c478bd9Sstevel@tonic-gate struct hme *hmep; 116185025c03Sgd mac_register_t *macp = NULL; 11627c478bd9Sstevel@tonic-gate int regno; 11637c478bd9Sstevel@tonic-gate int hm_rev = 0; 11647c478bd9Sstevel@tonic-gate int prop_len = sizeof (int); 11657c478bd9Sstevel@tonic-gate ddi_acc_handle_t cfg_handle; 11667c478bd9Sstevel@tonic-gate struct { 11677c478bd9Sstevel@tonic-gate uint16_t vendorid; 11687c478bd9Sstevel@tonic-gate uint16_t devid; 11697c478bd9Sstevel@tonic-gate uint16_t command; 11707c478bd9Sstevel@tonic-gate uint16_t status; 11717c478bd9Sstevel@tonic-gate uint8_t revid; 11727c478bd9Sstevel@tonic-gate uint8_t j1; 11737c478bd9Sstevel@tonic-gate uint16_t j2; 11747c478bd9Sstevel@tonic-gate } *cfg_ptr; 11757c478bd9Sstevel@tonic-gate 11767c478bd9Sstevel@tonic-gate switch (cmd) { 11777c478bd9Sstevel@tonic-gate case DDI_ATTACH: 11787c478bd9Sstevel@tonic-gate break; 11797c478bd9Sstevel@tonic-gate 11807c478bd9Sstevel@tonic-gate case DDI_RESUME: 11817c478bd9Sstevel@tonic-gate if ((hmep = ddi_get_driver_private(dip)) == NULL) 118285025c03Sgd return (DDI_FAILURE); 11837c478bd9Sstevel@tonic-gate 11847c478bd9Sstevel@tonic-gate hmep->hme_flags &= ~HMESUSPENDED; 118506673d9bSGarrett D'Amore 118606673d9bSGarrett D'Amore mii_resume(hmep->hme_mii); 118785025c03Sgd 1188228fdff0Sgd if (hmep->hme_started) 118985025c03Sgd (void) hmeinit(hmep); 11907c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 11917c478bd9Sstevel@tonic-gate 11927c478bd9Sstevel@tonic-gate default: 11937c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 11947c478bd9Sstevel@tonic-gate } 11957c478bd9Sstevel@tonic-gate 11967c478bd9Sstevel@tonic-gate /* 11977c478bd9Sstevel@tonic-gate * Allocate soft device data structure 11987c478bd9Sstevel@tonic-gate */ 11990219346bSGarrett D'Amore hmep = kmem_zalloc(sizeof (*hmep), KM_SLEEP); 12007c478bd9Sstevel@tonic-gate 12017c478bd9Sstevel@tonic-gate /* 12027c478bd9Sstevel@tonic-gate * Might as well set up elements of data structure 12037c478bd9Sstevel@tonic-gate */ 12047c478bd9Sstevel@tonic-gate hmep->dip = dip; 12057c478bd9Sstevel@tonic-gate hmep->instance = ddi_get_instance(dip); 12067c478bd9Sstevel@tonic-gate hmep->pagesize = ddi_ptob(dip, (ulong_t)1); /* IOMMU PSize */ 12077c478bd9Sstevel@tonic-gate 12087c478bd9Sstevel@tonic-gate /* 12097c478bd9Sstevel@tonic-gate * Might as well setup the driver private 12107c478bd9Sstevel@tonic-gate * structure as part of the dip. 12117c478bd9Sstevel@tonic-gate */ 12127c478bd9Sstevel@tonic-gate ddi_set_driver_private(dip, hmep); 12137c478bd9Sstevel@tonic-gate 12147c478bd9Sstevel@tonic-gate /* 12157c478bd9Sstevel@tonic-gate * Reject this device if it's in a slave-only slot. 12167c478bd9Sstevel@tonic-gate */ 12177c478bd9Sstevel@tonic-gate if (ddi_slaveonly(dip) == DDI_SUCCESS) { 12187c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG, 12190219346bSGarrett D'Amore "Dev not used - dev in slave only slot"); 12207c478bd9Sstevel@tonic-gate goto error_state; 12217c478bd9Sstevel@tonic-gate } 12227c478bd9Sstevel@tonic-gate 12237c478bd9Sstevel@tonic-gate /* 12247c478bd9Sstevel@tonic-gate * Map in the device registers. 12257c478bd9Sstevel@tonic-gate * 12267c478bd9Sstevel@tonic-gate * Reg # 0 is the Global register set 12277c478bd9Sstevel@tonic-gate * Reg # 1 is the ETX register set 12287c478bd9Sstevel@tonic-gate * Reg # 2 is the ERX register set 12297c478bd9Sstevel@tonic-gate * Reg # 3 is the BigMAC register set. 12307c478bd9Sstevel@tonic-gate * Reg # 4 is the MIF register set 12317c478bd9Sstevel@tonic-gate */ 12327c478bd9Sstevel@tonic-gate if (ddi_dev_nregs(dip, ®no) != (DDI_SUCCESS)) { 12337c478bd9Sstevel@tonic-gate HME_FAULT_MSG2(hmep, SEVERITY_HIGH, INIT_MSG, 123485025c03Sgd ddi_nregs_fail_msg, regno); 12357c478bd9Sstevel@tonic-gate goto error_state; 12367c478bd9Sstevel@tonic-gate } 12377c478bd9Sstevel@tonic-gate 12387c478bd9Sstevel@tonic-gate switch (regno) { 12397c478bd9Sstevel@tonic-gate case 5: 12407c478bd9Sstevel@tonic-gate hmep->hme_cheerio_mode = 0; 12417c478bd9Sstevel@tonic-gate break; 12427c478bd9Sstevel@tonic-gate case 2: 12437c478bd9Sstevel@tonic-gate case 3: /* for hot swap/plug, there will be 3 entries in "reg" prop */ 12447c478bd9Sstevel@tonic-gate hmep->hme_cheerio_mode = 1; 12457c478bd9Sstevel@tonic-gate break; 12467c478bd9Sstevel@tonic-gate default: 124785025c03Sgd HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 124885025c03Sgd bad_num_regs_msg); 12497c478bd9Sstevel@tonic-gate goto error_state; 12507c478bd9Sstevel@tonic-gate } 12517c478bd9Sstevel@tonic-gate 12527c478bd9Sstevel@tonic-gate /* Initialize device attributes structure */ 12537c478bd9Sstevel@tonic-gate hmep->hme_dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 12547c478bd9Sstevel@tonic-gate 12557c478bd9Sstevel@tonic-gate if (hmep->hme_cheerio_mode) 125685025c03Sgd hmep->hme_dev_attr.devacc_attr_endian_flags = 125785025c03Sgd DDI_STRUCTURE_LE_ACC; 12587c478bd9Sstevel@tonic-gate else 125985025c03Sgd hmep->hme_dev_attr.devacc_attr_endian_flags = 126085025c03Sgd DDI_STRUCTURE_BE_ACC; 12617c478bd9Sstevel@tonic-gate 12627c478bd9Sstevel@tonic-gate hmep->hme_dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 12637c478bd9Sstevel@tonic-gate 12647c478bd9Sstevel@tonic-gate if (hmep->hme_cheerio_mode) { 12657c478bd9Sstevel@tonic-gate uint8_t oldLT; 12667c478bd9Sstevel@tonic-gate uint8_t newLT = 0; 12677c478bd9Sstevel@tonic-gate dev_info_t *pdip; 12687c478bd9Sstevel@tonic-gate const char *pdrvname; 12697c478bd9Sstevel@tonic-gate 12707c478bd9Sstevel@tonic-gate /* 12717c478bd9Sstevel@tonic-gate * Map the PCI config space 12727c478bd9Sstevel@tonic-gate */ 12737c478bd9Sstevel@tonic-gate if (pci_config_setup(dip, &hmep->pci_config_handle) != 127485025c03Sgd DDI_SUCCESS) { 12757c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG, 127685025c03Sgd "pci_config_setup() failed.."); 12777c478bd9Sstevel@tonic-gate goto error_state; 12787c478bd9Sstevel@tonic-gate } 12797c478bd9Sstevel@tonic-gate 12807c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(dip, 1, 128185025c03Sgd (caddr_t *)&(hmep->hme_globregp), 0, 0, 128285025c03Sgd &hmep->hme_dev_attr, &hmep->hme_globregh)) { 12837c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG, 128485025c03Sgd mregs_4global_reg_fail_msg); 12857c478bd9Sstevel@tonic-gate goto error_unmap; 12867c478bd9Sstevel@tonic-gate } 12877c478bd9Sstevel@tonic-gate hmep->hme_etxregh = hmep->hme_erxregh = hmep->hme_bmacregh = 12887c478bd9Sstevel@tonic-gate hmep->hme_mifregh = hmep->hme_globregh; 12897c478bd9Sstevel@tonic-gate 129085025c03Sgd hmep->hme_etxregp = 129185025c03Sgd (void *)(((caddr_t)hmep->hme_globregp) + 0x2000); 129285025c03Sgd hmep->hme_erxregp = 129385025c03Sgd (void *)(((caddr_t)hmep->hme_globregp) + 0x4000); 129485025c03Sgd hmep->hme_bmacregp = 129585025c03Sgd (void *)(((caddr_t)hmep->hme_globregp) + 0x6000); 129685025c03Sgd hmep->hme_mifregp = 129785025c03Sgd (void *)(((caddr_t)hmep->hme_globregp) + 0x7000); 12987c478bd9Sstevel@tonic-gate 12997c478bd9Sstevel@tonic-gate /* 13007c478bd9Sstevel@tonic-gate * Get parent pci bridge info. 13017c478bd9Sstevel@tonic-gate */ 13027c478bd9Sstevel@tonic-gate pdip = ddi_get_parent(dip); 13037c478bd9Sstevel@tonic-gate pdrvname = ddi_driver_name(pdip); 13047c478bd9Sstevel@tonic-gate 13057c478bd9Sstevel@tonic-gate oldLT = pci_config_get8(hmep->pci_config_handle, 130685025c03Sgd PCI_CONF_LATENCY_TIMER); 13077c478bd9Sstevel@tonic-gate /* 13087c478bd9Sstevel@tonic-gate * Honor value set in /etc/system 13097c478bd9Sstevel@tonic-gate * "set hme:pci_latency_timer=0xYY" 13107c478bd9Sstevel@tonic-gate */ 13117c478bd9Sstevel@tonic-gate if (pci_latency_timer) 13127c478bd9Sstevel@tonic-gate newLT = pci_latency_timer; 13137c478bd9Sstevel@tonic-gate /* 13147c478bd9Sstevel@tonic-gate * Modify LT for simba 13157c478bd9Sstevel@tonic-gate */ 13167c478bd9Sstevel@tonic-gate else if (strcmp("simba", pdrvname) == 0) 13177c478bd9Sstevel@tonic-gate newLT = 0xf0; 13187c478bd9Sstevel@tonic-gate /* 13197c478bd9Sstevel@tonic-gate * Ensure minimum cheerio latency timer of 0x50 13207c478bd9Sstevel@tonic-gate * Usually OBP or pci bridge should set this value 13217c478bd9Sstevel@tonic-gate * based on cheerio 13227c478bd9Sstevel@tonic-gate * min_grant * 8(33MHz) = 0x50 = 0xa * 0x8 13237c478bd9Sstevel@tonic-gate * Some system set cheerio LT at 0x40 13247c478bd9Sstevel@tonic-gate */ 13257c478bd9Sstevel@tonic-gate else if (oldLT < 0x40) 13267c478bd9Sstevel@tonic-gate newLT = 0x50; 13277c478bd9Sstevel@tonic-gate 13287c478bd9Sstevel@tonic-gate /* 13297c478bd9Sstevel@tonic-gate * Now program cheerio's pci latency timer with newLT 13307c478bd9Sstevel@tonic-gate */ 13317c478bd9Sstevel@tonic-gate if (newLT) 13327c478bd9Sstevel@tonic-gate pci_config_put8(hmep->pci_config_handle, 133385025c03Sgd PCI_CONF_LATENCY_TIMER, (uchar_t)newLT); 13347c478bd9Sstevel@tonic-gate } else { /* Map register sets */ 13357c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(dip, 0, 133685025c03Sgd (caddr_t *)&(hmep->hme_globregp), 0, 0, 133785025c03Sgd &hmep->hme_dev_attr, &hmep->hme_globregh)) { 13387c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG, 133985025c03Sgd mregs_4global_reg_fail_msg); 13407c478bd9Sstevel@tonic-gate goto error_state; 13417c478bd9Sstevel@tonic-gate } 13427c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(dip, 1, 134385025c03Sgd (caddr_t *)&(hmep->hme_etxregp), 0, 0, 134485025c03Sgd &hmep->hme_dev_attr, &hmep->hme_etxregh)) { 13457c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG, 134685025c03Sgd mregs_4etx_reg_fail_msg); 13477c478bd9Sstevel@tonic-gate goto error_unmap; 13487c478bd9Sstevel@tonic-gate } 13497c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(dip, 2, 135085025c03Sgd (caddr_t *)&(hmep->hme_erxregp), 0, 0, 135185025c03Sgd &hmep->hme_dev_attr, &hmep->hme_erxregh)) { 13527c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG, 135385025c03Sgd mregs_4erx_reg_fail_msg); 13547c478bd9Sstevel@tonic-gate goto error_unmap; 13557c478bd9Sstevel@tonic-gate } 13567c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(dip, 3, 135785025c03Sgd (caddr_t *)&(hmep->hme_bmacregp), 0, 0, 135885025c03Sgd &hmep->hme_dev_attr, &hmep->hme_bmacregh)) { 13597c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG, 136085025c03Sgd mregs_4bmac_reg_fail_msg); 13617c478bd9Sstevel@tonic-gate goto error_unmap; 13627c478bd9Sstevel@tonic-gate } 13637c478bd9Sstevel@tonic-gate 13647c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(dip, 4, 136585025c03Sgd (caddr_t *)&(hmep->hme_mifregp), 0, 0, 136685025c03Sgd &hmep->hme_dev_attr, &hmep->hme_mifregh)) { 13677c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG, 136885025c03Sgd mregs_4mif_reg_fail_msg); 13697c478bd9Sstevel@tonic-gate goto error_unmap; 13707c478bd9Sstevel@tonic-gate } 13717c478bd9Sstevel@tonic-gate } /* Endif cheerio_mode */ 13727c478bd9Sstevel@tonic-gate 13737c478bd9Sstevel@tonic-gate /* 13747c478bd9Sstevel@tonic-gate * Based on the hm-rev, set some capabilities 13757c478bd9Sstevel@tonic-gate * Set up default capabilities for HM 2.0 13767c478bd9Sstevel@tonic-gate */ 13777c478bd9Sstevel@tonic-gate hmep->hme_frame_enable = 0; 13787c478bd9Sstevel@tonic-gate hmep->hme_lance_mode_enable = 0; 13797c478bd9Sstevel@tonic-gate hmep->hme_rxcv_enable = 0; 13807c478bd9Sstevel@tonic-gate 13817c478bd9Sstevel@tonic-gate /* NEW routine to get the properties */ 13827c478bd9Sstevel@tonic-gate 13837c478bd9Sstevel@tonic-gate if (ddi_getlongprop_buf(DDI_DEV_T_ANY, hmep->dip, 0, "hm-rev", 138485025c03Sgd (caddr_t)&hm_rev, &prop_len) == DDI_PROP_SUCCESS) { 13857c478bd9Sstevel@tonic-gate 13867c478bd9Sstevel@tonic-gate hmep->asic_rev = hm_rev; 13877c478bd9Sstevel@tonic-gate hmeget_hm_rev_property(hmep); 13887c478bd9Sstevel@tonic-gate } else { 13897c478bd9Sstevel@tonic-gate /* 13907c478bd9Sstevel@tonic-gate * hm_rev property not found so, this is 13917c478bd9Sstevel@tonic-gate * case of hot insertion of card without interpreting fcode. 13927c478bd9Sstevel@tonic-gate * Get it from revid in config space after mapping it. 13937c478bd9Sstevel@tonic-gate */ 13947c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(hmep->dip, 0, (caddr_t *)&cfg_ptr, 139585025c03Sgd 0, 0, &hmep->hme_dev_attr, &cfg_handle)) { 13967c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 13977c478bd9Sstevel@tonic-gate } 13987c478bd9Sstevel@tonic-gate /* 13997c478bd9Sstevel@tonic-gate * Since this is cheerio-based PCI card, we write 0xC in the 14007c478bd9Sstevel@tonic-gate * top 4 bits(4-7) of hm-rev and retain the bottom(0-3) bits 14017c478bd9Sstevel@tonic-gate * for Cheerio version(1.0 or 2.0 = 0xC0 or 0xC1) 14027c478bd9Sstevel@tonic-gate */ 14037c478bd9Sstevel@tonic-gate hm_rev = ddi_get8(cfg_handle, &cfg_ptr->revid); 14047c478bd9Sstevel@tonic-gate hm_rev = HME_1C0_REVID | (hm_rev & HME_REV_VERS_MASK); 14057c478bd9Sstevel@tonic-gate hmep->asic_rev = hm_rev; 14067c478bd9Sstevel@tonic-gate if (ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, 140785025c03Sgd "hm-rev", (caddr_t)&hm_rev, sizeof (hm_rev)) != 140885025c03Sgd DDI_SUCCESS) { 14097c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, AUTOCONFIG_MSG, 141006673d9bSGarrett D'Amore "ddi_prop_create error for hm_rev"); 14117c478bd9Sstevel@tonic-gate } 14127c478bd9Sstevel@tonic-gate ddi_regs_map_free(&cfg_handle); 14137c478bd9Sstevel@tonic-gate 14147c478bd9Sstevel@tonic-gate hmeget_hm_rev_property(hmep); 14157c478bd9Sstevel@tonic-gate 14167c478bd9Sstevel@tonic-gate /* get info via VPD */ 14170219346bSGarrett D'Amore if (hmeget_promprops(dip) != DDI_SUCCESS) { 14187c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, AUTOCONFIG_MSG, 141906673d9bSGarrett D'Amore "no promprops"); 14207c478bd9Sstevel@tonic-gate } 14217c478bd9Sstevel@tonic-gate } 14227c478bd9Sstevel@tonic-gate 14237c478bd9Sstevel@tonic-gate if (ddi_intr_hilevel(dip, 0)) { 14247c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_HIGH, NFATAL_ERR_MSG, 142585025c03Sgd " high-level interrupts are not supported"); 14267c478bd9Sstevel@tonic-gate goto error_unmap; 14277c478bd9Sstevel@tonic-gate } 14287c478bd9Sstevel@tonic-gate 14297c478bd9Sstevel@tonic-gate /* 14307c478bd9Sstevel@tonic-gate * Get intr. block cookie so that mutex locks can be initialized. 14317c478bd9Sstevel@tonic-gate */ 14327c478bd9Sstevel@tonic-gate if (ddi_get_iblock_cookie(dip, 0, &hmep->hme_cookie) != DDI_SUCCESS) 14337c478bd9Sstevel@tonic-gate goto error_unmap; 14347c478bd9Sstevel@tonic-gate 14357c478bd9Sstevel@tonic-gate /* 14367c478bd9Sstevel@tonic-gate * Initialize mutex's for this device. 14377c478bd9Sstevel@tonic-gate */ 143885025c03Sgd mutex_init(&hmep->hme_xmitlock, NULL, MUTEX_DRIVER, hmep->hme_cookie); 143985025c03Sgd mutex_init(&hmep->hme_intrlock, NULL, MUTEX_DRIVER, hmep->hme_cookie); 14407c478bd9Sstevel@tonic-gate 14417c478bd9Sstevel@tonic-gate /* 14427c478bd9Sstevel@tonic-gate * Quiesce the hardware. 14437c478bd9Sstevel@tonic-gate */ 14447c478bd9Sstevel@tonic-gate (void) hmestop(hmep); 14457c478bd9Sstevel@tonic-gate 14467c478bd9Sstevel@tonic-gate /* 14477c478bd9Sstevel@tonic-gate * Add interrupt to system 14487c478bd9Sstevel@tonic-gate */ 14497c478bd9Sstevel@tonic-gate if (ddi_add_intr(dip, 0, (ddi_iblock_cookie_t *)NULL, 14507c478bd9Sstevel@tonic-gate (ddi_idevice_cookie_t *)NULL, hmeintr, (caddr_t)hmep)) { 14517c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG, 145285025c03Sgd add_intr_fail_msg); 14537c478bd9Sstevel@tonic-gate goto error_mutex; 14547c478bd9Sstevel@tonic-gate } 14557c478bd9Sstevel@tonic-gate 14567c478bd9Sstevel@tonic-gate /* 14577c478bd9Sstevel@tonic-gate * Set up the ethernet mac address. 14587c478bd9Sstevel@tonic-gate */ 14597c478bd9Sstevel@tonic-gate hme_setup_mac_address(hmep, dip); 14607c478bd9Sstevel@tonic-gate 14617c478bd9Sstevel@tonic-gate if (!hmeinit_xfer_params(hmep)) 146285025c03Sgd goto error_intr; 14637c478bd9Sstevel@tonic-gate 14647c478bd9Sstevel@tonic-gate if (hmeburstsizes(hmep) == DDI_FAILURE) { 14657c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, burst_size_msg); 146685025c03Sgd goto error_intr; 14677c478bd9Sstevel@tonic-gate } 14687c478bd9Sstevel@tonic-gate 14690219346bSGarrett D'Amore if (hmeallocthings(hmep) != DDI_SUCCESS) { 14700219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, CONFIG_MSG, 14710219346bSGarrett D'Amore "resource allocation failed"); 14720219346bSGarrett D'Amore goto error_intr; 14730219346bSGarrett D'Amore } 14740219346bSGarrett D'Amore 14750219346bSGarrett D'Amore if (hmeallocbufs(hmep) != DDI_SUCCESS) { 14760219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, CONFIG_MSG, 14770219346bSGarrett D'Amore "buffer allocation failed"); 14780219346bSGarrett D'Amore goto error_intr; 14790219346bSGarrett D'Amore } 14807c478bd9Sstevel@tonic-gate 14817c478bd9Sstevel@tonic-gate hmestatinit(hmep); 148285025c03Sgd 1483*e8717ca2SGarrett D'Amore /* our external (preferred) PHY is at address 0 */ 1484*e8717ca2SGarrett D'Amore (void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, "first-phy", 0); 1485*e8717ca2SGarrett D'Amore 148606673d9bSGarrett D'Amore hmep->hme_mii = mii_alloc(hmep, dip, &hme_mii_ops); 148706673d9bSGarrett D'Amore if (hmep->hme_mii == NULL) { 148806673d9bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, CONFIG_MSG, 148906673d9bSGarrett D'Amore "mii_alloc failed"); 149006673d9bSGarrett D'Amore goto error_intr; 149106673d9bSGarrett D'Amore } 149206673d9bSGarrett D'Amore /* force a probe for the PHY */ 149306673d9bSGarrett D'Amore mii_probe(hmep->hme_mii); 149406673d9bSGarrett D'Amore 149585025c03Sgd if ((macp = mac_alloc(MAC_VERSION)) == NULL) { 149685025c03Sgd HME_FAULT_MSG1(hmep, SEVERITY_HIGH, CONFIG_MSG, 149785025c03Sgd "mac_alloc failed"); 149885025c03Sgd goto error_intr; 149985025c03Sgd } 150085025c03Sgd macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 150185025c03Sgd macp->m_driver = hmep; 150285025c03Sgd macp->m_dip = dip; 150385025c03Sgd macp->m_src_addr = hmep->hme_ouraddr.ether_addr_octet; 150485025c03Sgd macp->m_callbacks = &hme_m_callbacks; 150585025c03Sgd macp->m_min_sdu = 0; 150685025c03Sgd macp->m_max_sdu = ETHERMTU; 1507d62bc4baSyz macp->m_margin = VLAN_TAGSZ; 150806673d9bSGarrett D'Amore macp->m_priv_props = hme_priv_prop; 150906673d9bSGarrett D'Amore macp->m_priv_prop_count = 151006673d9bSGarrett D'Amore sizeof (hme_priv_prop) / sizeof (hme_priv_prop[0]); 151185025c03Sgd if (mac_register(macp, &hmep->hme_mh) != 0) { 151285025c03Sgd mac_free(macp); 151385025c03Sgd goto error_intr; 151485025c03Sgd } 151585025c03Sgd 151685025c03Sgd mac_free(macp); 151785025c03Sgd 15187c478bd9Sstevel@tonic-gate ddi_report_dev(dip); 15197c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 15207c478bd9Sstevel@tonic-gate 15217c478bd9Sstevel@tonic-gate /* 15227c478bd9Sstevel@tonic-gate * Failure Exit 15237c478bd9Sstevel@tonic-gate */ 15247c478bd9Sstevel@tonic-gate 15257c478bd9Sstevel@tonic-gate error_intr: 15267c478bd9Sstevel@tonic-gate if (hmep->hme_cookie) 15277c478bd9Sstevel@tonic-gate ddi_remove_intr(dip, 0, (ddi_iblock_cookie_t)0); 15287c478bd9Sstevel@tonic-gate 152906673d9bSGarrett D'Amore if (hmep->hme_mii) 153006673d9bSGarrett D'Amore mii_free(hmep->hme_mii); 153106673d9bSGarrett D'Amore 15327c478bd9Sstevel@tonic-gate error_mutex: 15337c478bd9Sstevel@tonic-gate mutex_destroy(&hmep->hme_xmitlock); 15347c478bd9Sstevel@tonic-gate mutex_destroy(&hmep->hme_intrlock); 15357c478bd9Sstevel@tonic-gate 15367c478bd9Sstevel@tonic-gate error_unmap: 15377c478bd9Sstevel@tonic-gate if (hmep->hme_globregh) 153885025c03Sgd ddi_regs_map_free(&hmep->hme_globregh); 15397c478bd9Sstevel@tonic-gate if (hmep->hme_cheerio_mode == 0) { 15407c478bd9Sstevel@tonic-gate if (hmep->hme_etxregh) 154185025c03Sgd ddi_regs_map_free(&hmep->hme_etxregh); 15427c478bd9Sstevel@tonic-gate if (hmep->hme_erxregh) 154385025c03Sgd ddi_regs_map_free(&hmep->hme_erxregh); 15447c478bd9Sstevel@tonic-gate if (hmep->hme_bmacregh) 154585025c03Sgd ddi_regs_map_free(&hmep->hme_bmacregh); 15467c478bd9Sstevel@tonic-gate if (hmep->hme_mifregh) 154785025c03Sgd ddi_regs_map_free(&hmep->hme_mifregh); 15487c478bd9Sstevel@tonic-gate } else { 15497c478bd9Sstevel@tonic-gate if (hmep->pci_config_handle) 15507c478bd9Sstevel@tonic-gate (void) pci_config_teardown(&hmep->pci_config_handle); 15517c478bd9Sstevel@tonic-gate hmep->hme_etxregh = hmep->hme_erxregh = hmep->hme_bmacregh = 15527c478bd9Sstevel@tonic-gate hmep->hme_mifregh = hmep->hme_globregh = NULL; 15537c478bd9Sstevel@tonic-gate } 15547c478bd9Sstevel@tonic-gate 15557c478bd9Sstevel@tonic-gate error_state: 15560219346bSGarrett D'Amore hmefreethings(hmep); 15570219346bSGarrett D'Amore hmefreebufs(hmep); 15580219346bSGarrett D'Amore 15597c478bd9Sstevel@tonic-gate if (hmep) { 15607c478bd9Sstevel@tonic-gate kmem_free((caddr_t)hmep, sizeof (*hmep)); 15617c478bd9Sstevel@tonic-gate ddi_set_driver_private(dip, NULL); 15627c478bd9Sstevel@tonic-gate } 15637c478bd9Sstevel@tonic-gate 15647c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 15657c478bd9Sstevel@tonic-gate } 15667c478bd9Sstevel@tonic-gate 1567f2cd0f02Sgd int 15687c478bd9Sstevel@tonic-gate hmedetach(dev_info_t *dip, ddi_detach_cmd_t cmd) 15697c478bd9Sstevel@tonic-gate { 157085025c03Sgd struct hme *hmep; 15717c478bd9Sstevel@tonic-gate 15727c478bd9Sstevel@tonic-gate if ((hmep = ddi_get_driver_private(dip)) == NULL) 15737c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 15747c478bd9Sstevel@tonic-gate 15757c478bd9Sstevel@tonic-gate switch (cmd) { 15767c478bd9Sstevel@tonic-gate case DDI_DETACH: 15777c478bd9Sstevel@tonic-gate break; 15787c478bd9Sstevel@tonic-gate 15797c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 158006673d9bSGarrett D'Amore mii_suspend(hmep->hme_mii); 15817c478bd9Sstevel@tonic-gate hmep->hme_flags |= HMESUSPENDED; 15827c478bd9Sstevel@tonic-gate hmeuninit(hmep); 15837c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 15847c478bd9Sstevel@tonic-gate 15857c478bd9Sstevel@tonic-gate default: 158685025c03Sgd return (DDI_FAILURE); 158785025c03Sgd } 158885025c03Sgd 158985025c03Sgd 159085025c03Sgd if (mac_unregister(hmep->hme_mh) != 0) { 15917c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 15927c478bd9Sstevel@tonic-gate } 15937c478bd9Sstevel@tonic-gate 15947c478bd9Sstevel@tonic-gate /* 15957c478bd9Sstevel@tonic-gate * Make driver quiescent, we don't want to prevent the 15964dd87b61Sgd * detach on failure. Note that this should be redundant, 15974dd87b61Sgd * since mac_stop should already have called hmeuninit(). 15987c478bd9Sstevel@tonic-gate */ 15994dd87b61Sgd if (!(hmep->hme_flags & HMESUSPENDED)) { 16004dd87b61Sgd (void) hmestop(hmep); 16014dd87b61Sgd } 16027c478bd9Sstevel@tonic-gate 160306673d9bSGarrett D'Amore if (hmep->hme_mii) 160406673d9bSGarrett D'Amore mii_free(hmep->hme_mii); 160506673d9bSGarrett D'Amore 16067c478bd9Sstevel@tonic-gate /* 16077c478bd9Sstevel@tonic-gate * Remove instance of the intr 16087c478bd9Sstevel@tonic-gate */ 16097c478bd9Sstevel@tonic-gate ddi_remove_intr(dip, 0, (ddi_iblock_cookie_t)0); 16107c478bd9Sstevel@tonic-gate 161185025c03Sgd /* 161285025c03Sgd * Unregister kstats. 161385025c03Sgd */ 161485025c03Sgd if (hmep->hme_ksp != NULL) 161585025c03Sgd kstat_delete(hmep->hme_ksp); 161685025c03Sgd if (hmep->hme_intrstats != NULL) 161785025c03Sgd kstat_delete(hmep->hme_intrstats); 161885025c03Sgd 161906673d9bSGarrett D'Amore hmep->hme_ksp = NULL; 162006673d9bSGarrett D'Amore hmep->hme_intrstats = NULL; 162185025c03Sgd 16227c478bd9Sstevel@tonic-gate /* 16237c478bd9Sstevel@tonic-gate * Destroy all mutexes and data structures allocated during 16247c478bd9Sstevel@tonic-gate * attach time. 162585025c03Sgd * 162685025c03Sgd * Note: at this time we should be the only thread accessing 162785025c03Sgd * the structures for this instance. 16287c478bd9Sstevel@tonic-gate */ 16297c478bd9Sstevel@tonic-gate 16307c478bd9Sstevel@tonic-gate if (hmep->hme_globregh) 16317c478bd9Sstevel@tonic-gate ddi_regs_map_free(&hmep->hme_globregh); 16327c478bd9Sstevel@tonic-gate if (hmep->hme_cheerio_mode == 0) { 16337c478bd9Sstevel@tonic-gate if (hmep->hme_etxregh) 163485025c03Sgd ddi_regs_map_free(&hmep->hme_etxregh); 16357c478bd9Sstevel@tonic-gate if (hmep->hme_erxregh) 163685025c03Sgd ddi_regs_map_free(&hmep->hme_erxregh); 16377c478bd9Sstevel@tonic-gate if (hmep->hme_bmacregh) 163885025c03Sgd ddi_regs_map_free(&hmep->hme_bmacregh); 16397c478bd9Sstevel@tonic-gate if (hmep->hme_mifregh) 164085025c03Sgd ddi_regs_map_free(&hmep->hme_mifregh); 16417c478bd9Sstevel@tonic-gate } else { 16427c478bd9Sstevel@tonic-gate if (hmep->pci_config_handle) 16437c478bd9Sstevel@tonic-gate (void) pci_config_teardown(&hmep->pci_config_handle); 16447c478bd9Sstevel@tonic-gate hmep->hme_etxregh = hmep->hme_erxregh = hmep->hme_bmacregh = 16457c478bd9Sstevel@tonic-gate hmep->hme_mifregh = hmep->hme_globregh = NULL; 16467c478bd9Sstevel@tonic-gate } 16477c478bd9Sstevel@tonic-gate 164885025c03Sgd mutex_destroy(&hmep->hme_xmitlock); 164985025c03Sgd mutex_destroy(&hmep->hme_intrlock); 16507c478bd9Sstevel@tonic-gate 16510219346bSGarrett D'Amore hmefreethings(hmep); 165285025c03Sgd hmefreebufs(hmep); 16537c478bd9Sstevel@tonic-gate 165485025c03Sgd ddi_set_driver_private(dip, NULL); 165585025c03Sgd kmem_free(hmep, sizeof (struct hme)); 16567c478bd9Sstevel@tonic-gate 16577c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 16587c478bd9Sstevel@tonic-gate } 16597c478bd9Sstevel@tonic-gate 16600219346bSGarrett D'Amore int 16610219346bSGarrett D'Amore hmequiesce(dev_info_t *dip) 16620219346bSGarrett D'Amore { 16630219346bSGarrett D'Amore struct hme *hmep; 16640219346bSGarrett D'Amore 16650219346bSGarrett D'Amore if ((hmep = ddi_get_driver_private(dip)) == NULL) 16660219346bSGarrett D'Amore return (DDI_FAILURE); 16670219346bSGarrett D'Amore 16680219346bSGarrett D'Amore (void) hmestop(hmep); 16690219346bSGarrett D'Amore return (DDI_SUCCESS); 16700219346bSGarrett D'Amore } 16710219346bSGarrett D'Amore 167285025c03Sgd static boolean_t 16737c478bd9Sstevel@tonic-gate hmeinit_xfer_params(struct hme *hmep) 16747c478bd9Sstevel@tonic-gate { 16757c478bd9Sstevel@tonic-gate int hme_ipg1_conf, hme_ipg2_conf; 16767c478bd9Sstevel@tonic-gate int hme_ipg0_conf, hme_lance_mode_conf; 16777c478bd9Sstevel@tonic-gate int prop_len = sizeof (int); 16787c478bd9Sstevel@tonic-gate dev_info_t *dip; 16797c478bd9Sstevel@tonic-gate 16807c478bd9Sstevel@tonic-gate dip = hmep->dip; 16817c478bd9Sstevel@tonic-gate 16827c478bd9Sstevel@tonic-gate /* 16837c478bd9Sstevel@tonic-gate * Set up the start-up values for user-configurable parameters 16847c478bd9Sstevel@tonic-gate * Get the values from the global variables first. 16857c478bd9Sstevel@tonic-gate * Use the MASK to limit the value to allowed maximum. 16867c478bd9Sstevel@tonic-gate */ 168706673d9bSGarrett D'Amore hmep->hme_ipg1 = hme_ipg1 & HME_MASK_8BIT; 168806673d9bSGarrett D'Amore hmep->hme_ipg2 = hme_ipg2 & HME_MASK_8BIT; 168906673d9bSGarrett D'Amore hmep->hme_ipg0 = hme_ipg0 & HME_MASK_5BIT; 16907c478bd9Sstevel@tonic-gate 16917c478bd9Sstevel@tonic-gate /* 16927c478bd9Sstevel@tonic-gate * Get the parameter values configured in .conf file. 16937c478bd9Sstevel@tonic-gate */ 16947c478bd9Sstevel@tonic-gate if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "ipg1", 169585025c03Sgd (caddr_t)&hme_ipg1_conf, &prop_len) == DDI_PROP_SUCCESS) { 169606673d9bSGarrett D'Amore hmep->hme_ipg1 = hme_ipg1_conf & HME_MASK_8BIT; 16977c478bd9Sstevel@tonic-gate } 16987c478bd9Sstevel@tonic-gate 16997c478bd9Sstevel@tonic-gate if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "ipg2", 170085025c03Sgd (caddr_t)&hme_ipg2_conf, &prop_len) == DDI_PROP_SUCCESS) { 170106673d9bSGarrett D'Amore hmep->hme_ipg2 = hme_ipg2_conf & HME_MASK_8BIT; 17027c478bd9Sstevel@tonic-gate } 17037c478bd9Sstevel@tonic-gate 17047c478bd9Sstevel@tonic-gate if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "ipg0", 170585025c03Sgd (caddr_t)&hme_ipg0_conf, &prop_len) == DDI_PROP_SUCCESS) { 170606673d9bSGarrett D'Amore hmep->hme_ipg0 = hme_ipg0_conf & HME_MASK_5BIT; 17077c478bd9Sstevel@tonic-gate } 17087c478bd9Sstevel@tonic-gate 17097c478bd9Sstevel@tonic-gate if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "lance_mode", 171085025c03Sgd (caddr_t)&hme_lance_mode_conf, &prop_len) == DDI_PROP_SUCCESS) { 171106673d9bSGarrett D'Amore hmep->hme_lance_mode = hme_lance_mode_conf & HME_MASK_1BIT; 17127c478bd9Sstevel@tonic-gate } 17137c478bd9Sstevel@tonic-gate 17147c478bd9Sstevel@tonic-gate return (B_TRUE); 17157c478bd9Sstevel@tonic-gate } 17167c478bd9Sstevel@tonic-gate 17177c478bd9Sstevel@tonic-gate /* 17187c478bd9Sstevel@tonic-gate * Return 0 upon success, 1 on failure. 17197c478bd9Sstevel@tonic-gate */ 17207c478bd9Sstevel@tonic-gate static uint_t 17217c478bd9Sstevel@tonic-gate hmestop(struct hme *hmep) 17227c478bd9Sstevel@tonic-gate { 17237c478bd9Sstevel@tonic-gate /* 17247c478bd9Sstevel@tonic-gate * Disable the Tx dma engine. 17257c478bd9Sstevel@tonic-gate */ 17267c478bd9Sstevel@tonic-gate PUT_ETXREG(config, (GET_ETXREG(config) & ~HMET_CONFIG_TXDMA_EN)); 17277c478bd9Sstevel@tonic-gate HMEDELAY(((GET_ETXREG(state_mach) & 0x1f) == 0x1), HMEMAXRSTDELAY); 17287c478bd9Sstevel@tonic-gate 17297c478bd9Sstevel@tonic-gate /* 17307c478bd9Sstevel@tonic-gate * Disable the Rx dma engine. 17317c478bd9Sstevel@tonic-gate */ 17327c478bd9Sstevel@tonic-gate PUT_ERXREG(config, (GET_ERXREG(config) & ~HMER_CONFIG_RXDMA_EN)); 17337c478bd9Sstevel@tonic-gate HMEDELAY(((GET_ERXREG(state_mach) & 0x3f) == 0), HMEMAXRSTDELAY); 17347c478bd9Sstevel@tonic-gate 17357c478bd9Sstevel@tonic-gate /* 17367c478bd9Sstevel@tonic-gate * By this time all things should be quiet, so hit the 17377c478bd9Sstevel@tonic-gate * chip with a reset. 17387c478bd9Sstevel@tonic-gate */ 17397c478bd9Sstevel@tonic-gate PUT_GLOBREG(reset, HMEG_RESET_GLOBAL); 17407c478bd9Sstevel@tonic-gate 17417c478bd9Sstevel@tonic-gate HMEDELAY((GET_GLOBREG(reset) == 0), HMEMAXRSTDELAY); 17427c478bd9Sstevel@tonic-gate if (GET_GLOBREG(reset)) { 17437c478bd9Sstevel@tonic-gate return (1); 17447c478bd9Sstevel@tonic-gate } 17457c478bd9Sstevel@tonic-gate 17467c478bd9Sstevel@tonic-gate CHECK_GLOBREG(); 17477c478bd9Sstevel@tonic-gate return (0); 17487c478bd9Sstevel@tonic-gate } 17497c478bd9Sstevel@tonic-gate 17507c478bd9Sstevel@tonic-gate static int 17517c478bd9Sstevel@tonic-gate hmestat_kstat_update(kstat_t *ksp, int rw) 17527c478bd9Sstevel@tonic-gate { 17537c478bd9Sstevel@tonic-gate struct hme *hmep; 17547c478bd9Sstevel@tonic-gate struct hmekstat *hkp; 17557c478bd9Sstevel@tonic-gate 17567c478bd9Sstevel@tonic-gate hmep = (struct hme *)ksp->ks_private; 17577c478bd9Sstevel@tonic-gate hkp = (struct hmekstat *)ksp->ks_data; 17587c478bd9Sstevel@tonic-gate 175985025c03Sgd if (rw != KSTAT_READ) 176085025c03Sgd return (EACCES); 176185025c03Sgd 17627c478bd9Sstevel@tonic-gate /* 17637c478bd9Sstevel@tonic-gate * Update all the stats by reading all the counter registers. 17647c478bd9Sstevel@tonic-gate * Counter register stats are not updated till they overflow 17657c478bd9Sstevel@tonic-gate * and interrupt. 17667c478bd9Sstevel@tonic-gate */ 17677c478bd9Sstevel@tonic-gate 17687c478bd9Sstevel@tonic-gate mutex_enter(&hmep->hme_xmitlock); 17694dd87b61Sgd if (hmep->hme_flags & HMERUNNING) { 17707c478bd9Sstevel@tonic-gate hmereclaim(hmep); 17714dd87b61Sgd hmesavecntrs(hmep); 17724dd87b61Sgd } 17737c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_xmitlock); 17747c478bd9Sstevel@tonic-gate 177585025c03Sgd hkp->hk_cvc.value.ul = hmep->hme_cvc; 177685025c03Sgd hkp->hk_lenerr.value.ul = hmep->hme_lenerr; 177785025c03Sgd hkp->hk_buff.value.ul = hmep->hme_buff; 177885025c03Sgd hkp->hk_missed.value.ul = hmep->hme_missed; 177985025c03Sgd hkp->hk_allocbfail.value.ul = hmep->hme_allocbfail; 178085025c03Sgd hkp->hk_babl.value.ul = hmep->hme_babl; 178185025c03Sgd hkp->hk_tmder.value.ul = hmep->hme_tmder; 178285025c03Sgd hkp->hk_txlaterr.value.ul = hmep->hme_txlaterr; 178385025c03Sgd hkp->hk_rxlaterr.value.ul = hmep->hme_rxlaterr; 178485025c03Sgd hkp->hk_slvparerr.value.ul = hmep->hme_slvparerr; 178585025c03Sgd hkp->hk_txparerr.value.ul = hmep->hme_txparerr; 178685025c03Sgd hkp->hk_rxparerr.value.ul = hmep->hme_rxparerr; 178785025c03Sgd hkp->hk_slverrack.value.ul = hmep->hme_slverrack; 178885025c03Sgd hkp->hk_txerrack.value.ul = hmep->hme_txerrack; 178985025c03Sgd hkp->hk_rxerrack.value.ul = hmep->hme_rxerrack; 179085025c03Sgd hkp->hk_txtagerr.value.ul = hmep->hme_txtagerr; 179185025c03Sgd hkp->hk_rxtagerr.value.ul = hmep->hme_rxtagerr; 179285025c03Sgd hkp->hk_eoperr.value.ul = hmep->hme_eoperr; 179385025c03Sgd hkp->hk_notmds.value.ul = hmep->hme_notmds; 179485025c03Sgd hkp->hk_notbufs.value.ul = hmep->hme_notbufs; 179585025c03Sgd hkp->hk_norbufs.value.ul = hmep->hme_norbufs; 17967c478bd9Sstevel@tonic-gate 179785025c03Sgd /* 179885025c03Sgd * Debug kstats 179985025c03Sgd */ 180085025c03Sgd hkp->hk_inits.value.ul = hmep->inits; 180185025c03Sgd hkp->hk_phyfail.value.ul = hmep->phyfail; 18027c478bd9Sstevel@tonic-gate 180385025c03Sgd /* 180485025c03Sgd * xcvr kstats 180585025c03Sgd */ 180685025c03Sgd hkp->hk_asic_rev.value.ul = hmep->asic_rev; 18077c478bd9Sstevel@tonic-gate 18087c478bd9Sstevel@tonic-gate return (0); 18097c478bd9Sstevel@tonic-gate } 18107c478bd9Sstevel@tonic-gate 18117c478bd9Sstevel@tonic-gate static void 18127c478bd9Sstevel@tonic-gate hmestatinit(struct hme *hmep) 18137c478bd9Sstevel@tonic-gate { 18147c478bd9Sstevel@tonic-gate struct kstat *ksp; 18157c478bd9Sstevel@tonic-gate struct hmekstat *hkp; 1816f2cd0f02Sgd const char *driver; 18177c478bd9Sstevel@tonic-gate int instance; 18187c478bd9Sstevel@tonic-gate char buf[16]; 18197c478bd9Sstevel@tonic-gate 18207c478bd9Sstevel@tonic-gate instance = hmep->instance; 1821f2cd0f02Sgd driver = ddi_driver_name(hmep->dip); 18227c478bd9Sstevel@tonic-gate 1823f2cd0f02Sgd if ((ksp = kstat_create(driver, instance, 182485025c03Sgd "driver_info", "net", KSTAT_TYPE_NAMED, 18257c478bd9Sstevel@tonic-gate sizeof (struct hmekstat) / sizeof (kstat_named_t), 0)) == NULL) { 18267c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, INIT_MSG, 18270219346bSGarrett D'Amore "kstat_create failed"); 18287c478bd9Sstevel@tonic-gate return; 18297c478bd9Sstevel@tonic-gate } 18307c478bd9Sstevel@tonic-gate 1831f2cd0f02Sgd (void) snprintf(buf, sizeof (buf), "%sc%d", driver, instance); 1832f2cd0f02Sgd hmep->hme_intrstats = kstat_create(driver, instance, buf, "controller", 183385025c03Sgd KSTAT_TYPE_INTR, 1, KSTAT_FLAG_PERSISTENT); 18347c478bd9Sstevel@tonic-gate if (hmep->hme_intrstats) 18357c478bd9Sstevel@tonic-gate kstat_install(hmep->hme_intrstats); 18367c478bd9Sstevel@tonic-gate 18377c478bd9Sstevel@tonic-gate hmep->hme_ksp = ksp; 18387c478bd9Sstevel@tonic-gate hkp = (struct hmekstat *)ksp->ks_data; 18397c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_cvc, "code_violations", 184085025c03Sgd KSTAT_DATA_ULONG); 18417c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_lenerr, "len_errors", 184285025c03Sgd KSTAT_DATA_ULONG); 18437c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_buff, "buff", 184485025c03Sgd KSTAT_DATA_ULONG); 18457c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_missed, "missed", 184685025c03Sgd KSTAT_DATA_ULONG); 18477c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_nocanput, "nocanput", 184885025c03Sgd KSTAT_DATA_ULONG); 18497c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_allocbfail, "allocbfail", 185085025c03Sgd KSTAT_DATA_ULONG); 18517c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_babl, "babble", 185285025c03Sgd KSTAT_DATA_ULONG); 18537c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_tmder, "tmd_error", 185485025c03Sgd KSTAT_DATA_ULONG); 18557c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_txlaterr, "tx_late_error", 185685025c03Sgd KSTAT_DATA_ULONG); 18577c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_rxlaterr, "rx_late_error", 185885025c03Sgd KSTAT_DATA_ULONG); 18597c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_slvparerr, "slv_parity_error", 186085025c03Sgd KSTAT_DATA_ULONG); 18617c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_txparerr, "tx_parity_error", 186285025c03Sgd KSTAT_DATA_ULONG); 18637c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_rxparerr, "rx_parity_error", 186485025c03Sgd KSTAT_DATA_ULONG); 18657c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_slverrack, "slv_error_ack", 186685025c03Sgd KSTAT_DATA_ULONG); 18677c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_txerrack, "tx_error_ack", 186885025c03Sgd KSTAT_DATA_ULONG); 18697c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_rxerrack, "rx_error_ack", 187085025c03Sgd KSTAT_DATA_ULONG); 18717c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_txtagerr, "tx_tag_error", 187285025c03Sgd KSTAT_DATA_ULONG); 18737c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_rxtagerr, "rx_tag_error", 187485025c03Sgd KSTAT_DATA_ULONG); 18757c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_eoperr, "eop_error", 187685025c03Sgd KSTAT_DATA_ULONG); 18777c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_notmds, "no_tmds", 187885025c03Sgd KSTAT_DATA_ULONG); 18797c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_notbufs, "no_tbufs", 188085025c03Sgd KSTAT_DATA_ULONG); 18817c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_norbufs, "no_rbufs", 188285025c03Sgd KSTAT_DATA_ULONG); 18837c478bd9Sstevel@tonic-gate 18847c478bd9Sstevel@tonic-gate /* 18857c478bd9Sstevel@tonic-gate * Debugging kstats 18867c478bd9Sstevel@tonic-gate */ 18877c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_inits, "inits", 188885025c03Sgd KSTAT_DATA_ULONG); 18897c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_phyfail, "phy_failures", 189085025c03Sgd KSTAT_DATA_ULONG); 18917c478bd9Sstevel@tonic-gate 18927c478bd9Sstevel@tonic-gate /* 18937c478bd9Sstevel@tonic-gate * xcvr kstats 18947c478bd9Sstevel@tonic-gate */ 18957c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_asic_rev, "asic_rev", 189685025c03Sgd KSTAT_DATA_ULONG); 18977c478bd9Sstevel@tonic-gate 18987c478bd9Sstevel@tonic-gate ksp->ks_update = hmestat_kstat_update; 18997c478bd9Sstevel@tonic-gate ksp->ks_private = (void *) hmep; 19007c478bd9Sstevel@tonic-gate kstat_install(ksp); 19017c478bd9Sstevel@tonic-gate } 19027c478bd9Sstevel@tonic-gate 190306673d9bSGarrett D'Amore int 190406673d9bSGarrett D'Amore hme_m_getprop(void *arg, const char *name, mac_prop_id_t num, uint_t flags, 190506673d9bSGarrett D'Amore uint_t sz, void *val, uint_t *perm) 19067c478bd9Sstevel@tonic-gate { 190706673d9bSGarrett D'Amore struct hme *hmep = arg; 190806673d9bSGarrett D'Amore int value; 190906673d9bSGarrett D'Amore boolean_t is_default; 191006673d9bSGarrett D'Amore int rv; 191106673d9bSGarrett D'Amore 191206673d9bSGarrett D'Amore rv = mii_m_getprop(hmep->hme_mii, name, num, flags, sz, val, perm); 191306673d9bSGarrett D'Amore if (rv != ENOTSUP) 191406673d9bSGarrett D'Amore return (rv); 191506673d9bSGarrett D'Amore 191606673d9bSGarrett D'Amore switch (num) { 191706673d9bSGarrett D'Amore case MAC_PROP_PRIVATE: 191806673d9bSGarrett D'Amore break; 191906673d9bSGarrett D'Amore default: 192006673d9bSGarrett D'Amore return (ENOTSUP); 192106673d9bSGarrett D'Amore } 192206673d9bSGarrett D'Amore 192306673d9bSGarrett D'Amore *perm = MAC_PROP_PERM_RW; 192406673d9bSGarrett D'Amore 192506673d9bSGarrett D'Amore is_default = (flags & MAC_PROP_DEFAULT) ? B_TRUE : B_FALSE; 192606673d9bSGarrett D'Amore if (strcmp(name, "_ipg0") == 0) { 192706673d9bSGarrett D'Amore value = is_default ? hme_ipg0 : hmep->hme_ipg0; 192806673d9bSGarrett D'Amore 192906673d9bSGarrett D'Amore } else if (strcmp(name, "_ipg1") == 0) { 193006673d9bSGarrett D'Amore value = is_default ? hme_ipg1 : hmep->hme_ipg1; 193106673d9bSGarrett D'Amore } else if (strcmp(name, "_ipg2") == 0) { 193206673d9bSGarrett D'Amore value = is_default ? hme_ipg2 : hmep->hme_ipg2; 193306673d9bSGarrett D'Amore } else if (strcmp(name, "_lance_mode") == 0) { 193406673d9bSGarrett D'Amore value = is_default ? hme_lance_mode : hmep->hme_lance_mode; 193506673d9bSGarrett D'Amore } else { 193606673d9bSGarrett D'Amore return (ENOTSUP); 193706673d9bSGarrett D'Amore } 193806673d9bSGarrett D'Amore (void) snprintf(val, sz, "%d", value); 193906673d9bSGarrett D'Amore return (0); 194006673d9bSGarrett D'Amore } 194106673d9bSGarrett D'Amore 194206673d9bSGarrett D'Amore int 194306673d9bSGarrett D'Amore hme_m_setprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz, 194406673d9bSGarrett D'Amore const void *val) 194506673d9bSGarrett D'Amore { 194606673d9bSGarrett D'Amore struct hme *hmep = arg; 194706673d9bSGarrett D'Amore int rv; 194806673d9bSGarrett D'Amore long lval; 194906673d9bSGarrett D'Amore boolean_t init = B_FALSE; 195006673d9bSGarrett D'Amore 195106673d9bSGarrett D'Amore rv = mii_m_setprop(hmep->hme_mii, name, num, sz, val); 195206673d9bSGarrett D'Amore if (rv != ENOTSUP) 195306673d9bSGarrett D'Amore return (rv); 195406673d9bSGarrett D'Amore rv = 0; 195506673d9bSGarrett D'Amore 195606673d9bSGarrett D'Amore switch (num) { 195706673d9bSGarrett D'Amore case MAC_PROP_PRIVATE: 195885025c03Sgd break; 195906673d9bSGarrett D'Amore default: 196006673d9bSGarrett D'Amore return (ENOTSUP); 196106673d9bSGarrett D'Amore } 19627c478bd9Sstevel@tonic-gate 196306673d9bSGarrett D'Amore (void) ddi_strtol(val, NULL, 0, &lval); 196406673d9bSGarrett D'Amore 196506673d9bSGarrett D'Amore if (strcmp(name, "_ipg1") == 0) { 196606673d9bSGarrett D'Amore if ((lval >= 0) && (lval <= 255)) { 196706673d9bSGarrett D'Amore hmep->hme_ipg1 = lval & 0xff; 196806673d9bSGarrett D'Amore init = B_TRUE; 196906673d9bSGarrett D'Amore } else { 197006673d9bSGarrett D'Amore return (EINVAL); 197185025c03Sgd } 19727c478bd9Sstevel@tonic-gate 197306673d9bSGarrett D'Amore } else if (strcmp(name, "_ipg2") == 0) { 197406673d9bSGarrett D'Amore if ((lval >= 0) && (lval <= 255)) { 197506673d9bSGarrett D'Amore hmep->hme_ipg2 = lval & 0xff; 197606673d9bSGarrett D'Amore init = B_TRUE; 197706673d9bSGarrett D'Amore } else { 197806673d9bSGarrett D'Amore return (EINVAL); 197906673d9bSGarrett D'Amore } 19807c478bd9Sstevel@tonic-gate 198106673d9bSGarrett D'Amore } else if (strcmp(name, "_ipg0") == 0) { 198206673d9bSGarrett D'Amore if ((lval >= 0) && (lval <= 31)) { 198306673d9bSGarrett D'Amore hmep->hme_ipg0 = lval & 0xff; 198406673d9bSGarrett D'Amore init = B_TRUE; 198585025c03Sgd } else { 198606673d9bSGarrett D'Amore return (EINVAL); 198706673d9bSGarrett D'Amore } 198806673d9bSGarrett D'Amore } else if (strcmp(name, "_lance_mode") == 0) { 198906673d9bSGarrett D'Amore if ((lval >= 0) && (lval <= 1)) { 199006673d9bSGarrett D'Amore hmep->hme_lance_mode = lval & 0xff; 199106673d9bSGarrett D'Amore init = B_TRUE; 199206673d9bSGarrett D'Amore } else { 199306673d9bSGarrett D'Amore return (EINVAL); 19947c478bd9Sstevel@tonic-gate } 19957c478bd9Sstevel@tonic-gate 199606673d9bSGarrett D'Amore } else { 199706673d9bSGarrett D'Amore rv = ENOTSUP; 199806673d9bSGarrett D'Amore } 199906673d9bSGarrett D'Amore 200006673d9bSGarrett D'Amore if (init) { 200106673d9bSGarrett D'Amore (void) hmeinit(hmep); 20027c478bd9Sstevel@tonic-gate } 200306673d9bSGarrett D'Amore return (rv); 20047c478bd9Sstevel@tonic-gate } 20057c478bd9Sstevel@tonic-gate 200606673d9bSGarrett D'Amore 200785025c03Sgd /*ARGSUSED*/ 200885025c03Sgd static boolean_t 200985025c03Sgd hme_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) 20107c478bd9Sstevel@tonic-gate { 201185025c03Sgd switch (cap) { 201285025c03Sgd case MAC_CAPAB_HCKSUM: 201385025c03Sgd *(uint32_t *)cap_data = HCKSUM_INET_PARTIAL; 201485025c03Sgd return (B_TRUE); 201585025c03Sgd default: 201685025c03Sgd return (B_FALSE); 20177c478bd9Sstevel@tonic-gate } 201885025c03Sgd } 20197c478bd9Sstevel@tonic-gate 202085025c03Sgd static int 202185025c03Sgd hme_m_promisc(void *arg, boolean_t on) 202285025c03Sgd { 202385025c03Sgd struct hme *hmep = arg; 20247c478bd9Sstevel@tonic-gate 202585025c03Sgd hmep->hme_promisc = on; 202685025c03Sgd (void) hmeinit(hmep); 202785025c03Sgd return (0); 202885025c03Sgd } 20297c478bd9Sstevel@tonic-gate 203085025c03Sgd static int 203185025c03Sgd hme_m_unicst(void *arg, const uint8_t *macaddr) 203285025c03Sgd { 203385025c03Sgd struct hme *hmep = arg; 20347c478bd9Sstevel@tonic-gate 20357c478bd9Sstevel@tonic-gate /* 20367c478bd9Sstevel@tonic-gate * Set new interface local address and re-init device. 20377c478bd9Sstevel@tonic-gate * This is destructive to any other streams attached 20387c478bd9Sstevel@tonic-gate * to this device. 20397c478bd9Sstevel@tonic-gate */ 204085025c03Sgd mutex_enter(&hmep->hme_intrlock); 204185025c03Sgd bcopy(macaddr, &hmep->hme_ouraddr, ETHERADDRL); 204285025c03Sgd mutex_exit(&hmep->hme_intrlock); 204385025c03Sgd (void) hmeinit(hmep); 204485025c03Sgd return (0); 20457c478bd9Sstevel@tonic-gate } 20467c478bd9Sstevel@tonic-gate 204785025c03Sgd static int 204885025c03Sgd hme_m_multicst(void *arg, boolean_t add, const uint8_t *macaddr) 20497c478bd9Sstevel@tonic-gate { 205085025c03Sgd struct hme *hmep = arg; 205185025c03Sgd uint32_t ladrf_bit; 205285025c03Sgd boolean_t doinit = B_FALSE; 20537c478bd9Sstevel@tonic-gate 20547c478bd9Sstevel@tonic-gate /* 205585025c03Sgd * If this address's bit was not already set in the local address 205685025c03Sgd * filter, add it and re-initialize the Hardware. 20577c478bd9Sstevel@tonic-gate */ 205885025c03Sgd ladrf_bit = hmeladrf_bit(macaddr); 20597c478bd9Sstevel@tonic-gate 206085025c03Sgd mutex_enter(&hmep->hme_intrlock); 206185025c03Sgd if (add) { 206285025c03Sgd hmep->hme_ladrf_refcnt[ladrf_bit]++; 206385025c03Sgd if (hmep->hme_ladrf_refcnt[ladrf_bit] == 1) { 206485025c03Sgd hmep->hme_ladrf[ladrf_bit >> 4] |= 206585025c03Sgd 1 << (ladrf_bit & 0xf); 206685025c03Sgd hmep->hme_multi++; 206785025c03Sgd doinit = B_TRUE; 206885025c03Sgd } 20697c478bd9Sstevel@tonic-gate } else { 207085025c03Sgd hmep->hme_ladrf_refcnt[ladrf_bit]--; 207185025c03Sgd if (hmep->hme_ladrf_refcnt[ladrf_bit] == 0) { 207285025c03Sgd hmep->hme_ladrf[ladrf_bit >> 4] &= 207385025c03Sgd ~(1 << (ladrf_bit & 0xf)); 207485025c03Sgd doinit = B_TRUE; 20757c478bd9Sstevel@tonic-gate } 20767c478bd9Sstevel@tonic-gate } 207785025c03Sgd mutex_exit(&hmep->hme_intrlock); 20787c478bd9Sstevel@tonic-gate 20790219346bSGarrett D'Amore if (doinit) { 208085025c03Sgd (void) hmeinit(hmep); 20810219346bSGarrett D'Amore } 20827c478bd9Sstevel@tonic-gate 208385025c03Sgd return (0); 20847c478bd9Sstevel@tonic-gate } 20857c478bd9Sstevel@tonic-gate 208685025c03Sgd static int 208785025c03Sgd hme_m_start(void *arg) 20887c478bd9Sstevel@tonic-gate { 208985025c03Sgd struct hme *hmep = arg; 20907c478bd9Sstevel@tonic-gate 2091228fdff0Sgd if (hmeinit(hmep) != 0) { 2092228fdff0Sgd /* initialization failed -- really want DL_INITFAILED */ 2093228fdff0Sgd return (EIO); 2094228fdff0Sgd } else { 2095228fdff0Sgd hmep->hme_started = B_TRUE; 209606673d9bSGarrett D'Amore mii_start(hmep->hme_mii); 2097228fdff0Sgd return (0); 2098228fdff0Sgd } 209985025c03Sgd } 21007c478bd9Sstevel@tonic-gate 210185025c03Sgd static void 210285025c03Sgd hme_m_stop(void *arg) 210385025c03Sgd { 210485025c03Sgd struct hme *hmep = arg; 21057c478bd9Sstevel@tonic-gate 210606673d9bSGarrett D'Amore mii_stop(hmep->hme_mii); 2107228fdff0Sgd hmep->hme_started = B_FALSE; 210885025c03Sgd hmeuninit(hmep); 210985025c03Sgd } 21107c478bd9Sstevel@tonic-gate 211185025c03Sgd static int 211285025c03Sgd hme_m_stat(void *arg, uint_t stat, uint64_t *val) 211385025c03Sgd { 211485025c03Sgd struct hme *hmep = arg; 21157c478bd9Sstevel@tonic-gate 211685025c03Sgd mutex_enter(&hmep->hme_xmitlock); 21174dd87b61Sgd if (hmep->hme_flags & HMERUNNING) { 211885025c03Sgd hmereclaim(hmep); 21194dd87b61Sgd hmesavecntrs(hmep); 21204dd87b61Sgd } 212185025c03Sgd mutex_exit(&hmep->hme_xmitlock); 21227c478bd9Sstevel@tonic-gate 21237c478bd9Sstevel@tonic-gate 212406673d9bSGarrett D'Amore if (mii_m_getstat(hmep->hme_mii, stat, val) == 0) { 212506673d9bSGarrett D'Amore return (0); 212606673d9bSGarrett D'Amore } 212785025c03Sgd switch (stat) { 212885025c03Sgd case MAC_STAT_IPACKETS: 212985025c03Sgd *val = hmep->hme_ipackets; 213085025c03Sgd break; 213185025c03Sgd case MAC_STAT_RBYTES: 213285025c03Sgd *val = hmep->hme_rbytes; 213385025c03Sgd break; 213485025c03Sgd case MAC_STAT_IERRORS: 213585025c03Sgd *val = hmep->hme_ierrors; 213685025c03Sgd break; 213785025c03Sgd case MAC_STAT_OPACKETS: 213885025c03Sgd *val = hmep->hme_opackets; 213985025c03Sgd break; 214085025c03Sgd case MAC_STAT_OBYTES: 214185025c03Sgd *val = hmep->hme_obytes; 214285025c03Sgd break; 214385025c03Sgd case MAC_STAT_OERRORS: 214485025c03Sgd *val = hmep->hme_oerrors; 214585025c03Sgd break; 214685025c03Sgd case MAC_STAT_MULTIRCV: 214785025c03Sgd *val = hmep->hme_multircv; 214885025c03Sgd break; 214985025c03Sgd case MAC_STAT_MULTIXMT: 215085025c03Sgd *val = hmep->hme_multixmt; 215185025c03Sgd break; 215285025c03Sgd case MAC_STAT_BRDCSTRCV: 215385025c03Sgd *val = hmep->hme_brdcstrcv; 215485025c03Sgd break; 215585025c03Sgd case MAC_STAT_BRDCSTXMT: 215685025c03Sgd *val = hmep->hme_brdcstxmt; 215785025c03Sgd break; 215885025c03Sgd case MAC_STAT_UNDERFLOWS: 215985025c03Sgd *val = hmep->hme_uflo; 216085025c03Sgd break; 216185025c03Sgd case MAC_STAT_OVERFLOWS: 216285025c03Sgd *val = hmep->hme_oflo; 216385025c03Sgd break; 216485025c03Sgd case MAC_STAT_COLLISIONS: 216585025c03Sgd *val = hmep->hme_coll; 216685025c03Sgd break; 216785025c03Sgd case MAC_STAT_NORCVBUF: 216885025c03Sgd *val = hmep->hme_norcvbuf; 216985025c03Sgd break; 217085025c03Sgd case MAC_STAT_NOXMTBUF: 217185025c03Sgd *val = hmep->hme_noxmtbuf; 217285025c03Sgd break; 217385025c03Sgd case ETHER_STAT_LINK_DUPLEX: 217485025c03Sgd *val = hmep->hme_duplex; 217585025c03Sgd break; 217685025c03Sgd case ETHER_STAT_ALIGN_ERRORS: 217785025c03Sgd *val = hmep->hme_align_errors; 217885025c03Sgd break; 217985025c03Sgd case ETHER_STAT_FCS_ERRORS: 218085025c03Sgd *val = hmep->hme_fcs_errors; 218185025c03Sgd break; 218285025c03Sgd case ETHER_STAT_EX_COLLISIONS: 218385025c03Sgd *val = hmep->hme_excol; 218485025c03Sgd break; 218585025c03Sgd case ETHER_STAT_DEFER_XMTS: 218685025c03Sgd *val = hmep->hme_defer_xmts; 218785025c03Sgd break; 218885025c03Sgd case ETHER_STAT_SQE_ERRORS: 218985025c03Sgd *val = hmep->hme_sqe_errors; 219085025c03Sgd break; 219185025c03Sgd case ETHER_STAT_FIRST_COLLISIONS: 219285025c03Sgd *val = hmep->hme_fstcol; 219385025c03Sgd break; 219485025c03Sgd case ETHER_STAT_TX_LATE_COLLISIONS: 219585025c03Sgd *val = hmep->hme_tlcol; 219685025c03Sgd break; 219785025c03Sgd case ETHER_STAT_TOOLONG_ERRORS: 219885025c03Sgd *val = hmep->hme_toolong_errors; 219985025c03Sgd break; 220085025c03Sgd case ETHER_STAT_TOOSHORT_ERRORS: 220185025c03Sgd *val = hmep->hme_runt; 220285025c03Sgd break; 22034dd87b61Sgd case ETHER_STAT_CARRIER_ERRORS: 22044dd87b61Sgd *val = hmep->hme_carrier_errors; 22054dd87b61Sgd break; 220685025c03Sgd default: 220785025c03Sgd return (EINVAL); 22087c478bd9Sstevel@tonic-gate } 220985025c03Sgd return (0); 22107c478bd9Sstevel@tonic-gate } 22117c478bd9Sstevel@tonic-gate 221285025c03Sgd static mblk_t * 221385025c03Sgd hme_m_tx(void *arg, mblk_t *mp) 22147c478bd9Sstevel@tonic-gate { 221585025c03Sgd struct hme *hmep = arg; 221685025c03Sgd mblk_t *next; 22177c478bd9Sstevel@tonic-gate 221885025c03Sgd while (mp != NULL) { 221985025c03Sgd next = mp->b_next; 222085025c03Sgd mp->b_next = NULL; 222185025c03Sgd if (!hmestart(hmep, mp)) { 222285025c03Sgd mp->b_next = next; 222385025c03Sgd break; 22247c478bd9Sstevel@tonic-gate } 222585025c03Sgd mp = next; 22267c478bd9Sstevel@tonic-gate } 222785025c03Sgd return (mp); 22287c478bd9Sstevel@tonic-gate } 22297c478bd9Sstevel@tonic-gate 2230eb7b3d20Sgd /* 2231eb7b3d20Sgd * Software IP checksum, for the edge cases that the 2232eb7b3d20Sgd * hardware can't handle. See hmestart for more info. 2233eb7b3d20Sgd */ 2234eb7b3d20Sgd static uint16_t 2235eb7b3d20Sgd hme_cksum(void *data, int len) 2236eb7b3d20Sgd { 2237eb7b3d20Sgd uint16_t *words = data; 2238eb7b3d20Sgd int i, nwords = len / 2; 2239eb7b3d20Sgd uint32_t sum = 0; 2240eb7b3d20Sgd 2241eb7b3d20Sgd /* just add up the words */ 2242eb7b3d20Sgd for (i = 0; i < nwords; i++) { 2243eb7b3d20Sgd sum += *words++; 2244eb7b3d20Sgd } 2245eb7b3d20Sgd 2246eb7b3d20Sgd /* pick up residual byte ... assume even half-word allocations */ 2247eb7b3d20Sgd if (len % 2) { 22480219346bSGarrett D'Amore sum += (*words & htons(0xff00)); 2249eb7b3d20Sgd } 2250eb7b3d20Sgd 2251eb7b3d20Sgd sum = (sum >> 16) + (sum & 0xffff); 2252eb7b3d20Sgd sum = (sum >> 16) + (sum & 0xffff); 2253eb7b3d20Sgd 2254eb7b3d20Sgd return (~(sum & 0xffff)); 2255eb7b3d20Sgd } 2256eb7b3d20Sgd 225785025c03Sgd static boolean_t 22580219346bSGarrett D'Amore hmestart(struct hme *hmep, mblk_t *mp) 22597c478bd9Sstevel@tonic-gate { 22600219346bSGarrett D'Amore uint32_t len; 22610219346bSGarrett D'Amore boolean_t retval = B_TRUE; 22620219346bSGarrett D'Amore hmebuf_t *tbuf; 22630219346bSGarrett D'Amore uint32_t txptr; 22647c478bd9Sstevel@tonic-gate 226585025c03Sgd uint32_t csflags = 0; 226685025c03Sgd uint32_t flags; 226785025c03Sgd uint32_t start_offset; 226885025c03Sgd uint32_t stuff_offset; 22697c478bd9Sstevel@tonic-gate 227085025c03Sgd hcksum_retrieve(mp, NULL, NULL, &start_offset, &stuff_offset, 227185025c03Sgd NULL, NULL, &flags); 22727c478bd9Sstevel@tonic-gate 227385025c03Sgd if (flags & HCK_PARTIALCKSUM) { 227485025c03Sgd if (get_ether_type(mp->b_rptr) == ETHERTYPE_VLAN) { 227585025c03Sgd start_offset += sizeof (struct ether_header) + 4; 227685025c03Sgd stuff_offset += sizeof (struct ether_header) + 4; 227785025c03Sgd } else { 227885025c03Sgd start_offset += sizeof (struct ether_header); 227985025c03Sgd stuff_offset += sizeof (struct ether_header); 22807c478bd9Sstevel@tonic-gate } 228185025c03Sgd csflags = HMETMD_CSENABL | 228285025c03Sgd (start_offset << HMETMD_CSSTART_SHIFT) | 228385025c03Sgd (stuff_offset << HMETMD_CSSTUFF_SHIFT); 228485025c03Sgd } 22857c478bd9Sstevel@tonic-gate 22867c478bd9Sstevel@tonic-gate mutex_enter(&hmep->hme_xmitlock); 22877c478bd9Sstevel@tonic-gate 22884dd87b61Sgd if (hmep->hme_flags & HMESUSPENDED) { 22894dd87b61Sgd hmep->hme_carrier_errors++; 22904dd87b61Sgd hmep->hme_oerrors++; 22914dd87b61Sgd goto bad; 22924dd87b61Sgd } 22934dd87b61Sgd 22940219346bSGarrett D'Amore if (hmep->hme_txindex != hmep->hme_txreclaim) { 22950219346bSGarrett D'Amore hmereclaim(hmep); 22967c478bd9Sstevel@tonic-gate } 22970219346bSGarrett D'Amore if ((hmep->hme_txindex - HME_TMDMAX) == hmep->hme_txreclaim) 22987c478bd9Sstevel@tonic-gate goto notmds; 22990219346bSGarrett D'Amore txptr = hmep->hme_txindex % HME_TMDMAX; 23000219346bSGarrett D'Amore tbuf = &hmep->hme_tbuf[txptr]; 23017c478bd9Sstevel@tonic-gate 2302eb7b3d20Sgd /* 2303eb7b3d20Sgd * Note that for checksum offload, the hardware cannot 2304eb7b3d20Sgd * generate correct checksums if the packet is smaller than 2305eb7b3d20Sgd * 64-bytes. In such a case, we bcopy the packet and use 2306eb7b3d20Sgd * a software checksum. 2307eb7b3d20Sgd */ 2308eb7b3d20Sgd 23090219346bSGarrett D'Amore len = msgsize(mp); 23100219346bSGarrett D'Amore if (len < 64) { 23110219346bSGarrett D'Amore /* zero fill the padding */ 23120219346bSGarrett D'Amore bzero(tbuf->kaddr, 64); 23137c478bd9Sstevel@tonic-gate } 23140219346bSGarrett D'Amore mcopymsg(mp, tbuf->kaddr); 23157c478bd9Sstevel@tonic-gate 23160219346bSGarrett D'Amore if ((csflags != 0) && (len < 64)) { 23170219346bSGarrett D'Amore uint16_t sum; 23180219346bSGarrett D'Amore sum = hme_cksum(tbuf->kaddr + start_offset, 23190219346bSGarrett D'Amore len - start_offset); 23200219346bSGarrett D'Amore bcopy(&sum, tbuf->kaddr + stuff_offset, sizeof (sum)); 23210219346bSGarrett D'Amore csflags = 0; 23227c478bd9Sstevel@tonic-gate } 23237c478bd9Sstevel@tonic-gate 23240219346bSGarrett D'Amore if (ddi_dma_sync(tbuf->dmah, 0, len, DDI_DMA_SYNC_FORDEV) == 23250219346bSGarrett D'Amore DDI_FAILURE) { 23267c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_HIGH, DDI_MSG, 232785025c03Sgd "ddi_dma_sync failed"); 23287c478bd9Sstevel@tonic-gate } 23297c478bd9Sstevel@tonic-gate 23300219346bSGarrett D'Amore /* 23310219346bSGarrett D'Amore * update MIB II statistics 23320219346bSGarrett D'Amore */ 23330219346bSGarrett D'Amore BUMP_OutNUcast(hmep, tbuf->kaddr); 23340219346bSGarrett D'Amore 23350219346bSGarrett D'Amore PUT_TMD(txptr, tbuf->paddr, len, 23360219346bSGarrett D'Amore HMETMD_OWN | HMETMD_SOP | HMETMD_EOP | csflags); 23377c478bd9Sstevel@tonic-gate 23380219346bSGarrett D'Amore HMESYNCTMD(txptr, DDI_DMA_SYNC_FORDEV); 23390219346bSGarrett D'Amore hmep->hme_txindex++; 23407c478bd9Sstevel@tonic-gate 23417c478bd9Sstevel@tonic-gate PUT_ETXREG(txpend, HMET_TXPEND_TDMD); 23427c478bd9Sstevel@tonic-gate CHECK_ETXREG(); 23437c478bd9Sstevel@tonic-gate 23447c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_xmitlock); 23457c478bd9Sstevel@tonic-gate 23467c478bd9Sstevel@tonic-gate hmep->hme_starts++; 234785025c03Sgd return (B_TRUE); 23487c478bd9Sstevel@tonic-gate 23497c478bd9Sstevel@tonic-gate bad: 23507c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_xmitlock); 23517c478bd9Sstevel@tonic-gate freemsg(mp); 235285025c03Sgd return (B_TRUE); 23537c478bd9Sstevel@tonic-gate 23547c478bd9Sstevel@tonic-gate notmds: 23557c478bd9Sstevel@tonic-gate hmep->hme_notmds++; 235685025c03Sgd hmep->hme_wantw = B_TRUE; 23577c478bd9Sstevel@tonic-gate hmereclaim(hmep); 235885025c03Sgd retval = B_FALSE; 23597c478bd9Sstevel@tonic-gate done: 23607c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_xmitlock); 23617c478bd9Sstevel@tonic-gate 236285025c03Sgd return (retval); 23637c478bd9Sstevel@tonic-gate } 23647c478bd9Sstevel@tonic-gate 23657c478bd9Sstevel@tonic-gate /* 23667c478bd9Sstevel@tonic-gate * Initialize channel. 23677c478bd9Sstevel@tonic-gate * Return 0 on success, nonzero on error. 23687c478bd9Sstevel@tonic-gate * 23697c478bd9Sstevel@tonic-gate * The recommended sequence for initialization is: 23707c478bd9Sstevel@tonic-gate * 1. Issue a Global Reset command to the Ethernet Channel. 23717c478bd9Sstevel@tonic-gate * 2. Poll the Global_Reset bits until the execution of the reset has been 23727c478bd9Sstevel@tonic-gate * completed. 23737c478bd9Sstevel@tonic-gate * 2(a). Use the MIF Frame/Output register to reset the transceiver. 23747c478bd9Sstevel@tonic-gate * Poll Register 0 to till the Resetbit is 0. 23757c478bd9Sstevel@tonic-gate * 2(b). Use the MIF Frame/Output register to set the PHY in in Normal-Op, 23767c478bd9Sstevel@tonic-gate * 100Mbps and Non-Isolated mode. The main point here is to bring the 23777c478bd9Sstevel@tonic-gate * PHY out of Isolate mode so that it can generate the rx_clk and tx_clk 23787c478bd9Sstevel@tonic-gate * to the MII interface so that the Bigmac core can correctly reset 23797c478bd9Sstevel@tonic-gate * upon a software reset. 23807c478bd9Sstevel@tonic-gate * 2(c). Issue another Global Reset command to the Ethernet Channel and poll 23817c478bd9Sstevel@tonic-gate * the Global_Reset bits till completion. 23827c478bd9Sstevel@tonic-gate * 3. Set up all the data structures in the host memory. 23837c478bd9Sstevel@tonic-gate * 4. Program the TX_MAC registers/counters (excluding the TX_MAC Configuration 23847c478bd9Sstevel@tonic-gate * Register). 23857c478bd9Sstevel@tonic-gate * 5. Program the RX_MAC registers/counters (excluding the RX_MAC Configuration 23867c478bd9Sstevel@tonic-gate * Register). 23877c478bd9Sstevel@tonic-gate * 6. Program the Transmit Descriptor Ring Base Address in the ETX. 23887c478bd9Sstevel@tonic-gate * 7. Program the Receive Descriptor Ring Base Address in the ERX. 23897c478bd9Sstevel@tonic-gate * 8. Program the Global Configuration and the Global Interrupt Mask Registers. 23907c478bd9Sstevel@tonic-gate * 9. Program the ETX Configuration register (enable the Transmit DMA channel). 23917c478bd9Sstevel@tonic-gate * 10. Program the ERX Configuration register (enable the Receive DMA channel). 23927c478bd9Sstevel@tonic-gate * 11. Program the XIF Configuration Register (enable the XIF). 23937c478bd9Sstevel@tonic-gate * 12. Program the RX_MAC Configuration Register (Enable the RX_MAC). 23947c478bd9Sstevel@tonic-gate * 13. Program the TX_MAC Configuration Register (Enable the TX_MAC). 23957c478bd9Sstevel@tonic-gate */ 23967c478bd9Sstevel@tonic-gate 23977c478bd9Sstevel@tonic-gate 23987c478bd9Sstevel@tonic-gate #ifdef FEPS_URUN_BUG 23997c478bd9Sstevel@tonic-gate static int hme_palen = 32; 24007c478bd9Sstevel@tonic-gate #endif 24017c478bd9Sstevel@tonic-gate 24027c478bd9Sstevel@tonic-gate static int 24037c478bd9Sstevel@tonic-gate hmeinit(struct hme *hmep) 24047c478bd9Sstevel@tonic-gate { 24050219346bSGarrett D'Amore uint32_t i; 24060219346bSGarrett D'Amore int ret; 240706673d9bSGarrett D'Amore boolean_t fdx; 240806673d9bSGarrett D'Amore int phyad; 24097c478bd9Sstevel@tonic-gate 241085025c03Sgd /* 241185025c03Sgd * Lock sequence: 241285025c03Sgd * hme_intrlock, hme_xmitlock. 241385025c03Sgd */ 241485025c03Sgd mutex_enter(&hmep->hme_intrlock); 24157c478bd9Sstevel@tonic-gate 24167c478bd9Sstevel@tonic-gate /* 241785025c03Sgd * Don't touch the hardware if we are suspended. But don't 241885025c03Sgd * fail either. Some time later we may be resumed, and then 241985025c03Sgd * we'll be back here to program the device using the settings 242085025c03Sgd * in the soft state. 24217c478bd9Sstevel@tonic-gate */ 242285025c03Sgd if (hmep->hme_flags & HMESUSPENDED) { 242385025c03Sgd mutex_exit(&hmep->hme_intrlock); 242485025c03Sgd return (0); 242585025c03Sgd } 24267c478bd9Sstevel@tonic-gate 24277c478bd9Sstevel@tonic-gate /* 242885025c03Sgd * This should prevent us from clearing any interrupts that 242985025c03Sgd * may occur by temporarily stopping interrupts from occurring 243085025c03Sgd * for a short time. We need to update the interrupt mask 243185025c03Sgd * later in this function. 24327c478bd9Sstevel@tonic-gate */ 243385025c03Sgd PUT_GLOBREG(intmask, ~HMEG_MASK_MIF_INTR); 24347c478bd9Sstevel@tonic-gate 24357c478bd9Sstevel@tonic-gate 24367c478bd9Sstevel@tonic-gate /* 24377c478bd9Sstevel@tonic-gate * Rearranged the mutex acquisition order to solve the deadlock 24387c478bd9Sstevel@tonic-gate * situation as described in bug ID 4065896. 24397c478bd9Sstevel@tonic-gate */ 24407c478bd9Sstevel@tonic-gate 24417c478bd9Sstevel@tonic-gate mutex_enter(&hmep->hme_xmitlock); 24427c478bd9Sstevel@tonic-gate 24437c478bd9Sstevel@tonic-gate hmep->hme_flags = 0; 244485025c03Sgd hmep->hme_wantw = B_FALSE; 24457c478bd9Sstevel@tonic-gate 24467c478bd9Sstevel@tonic-gate if (hmep->inits) 24477c478bd9Sstevel@tonic-gate hmesavecntrs(hmep); 24487c478bd9Sstevel@tonic-gate 24497c478bd9Sstevel@tonic-gate /* 24507c478bd9Sstevel@tonic-gate * Perform Global reset of the Sbus/FEPS ENET channel. 24517c478bd9Sstevel@tonic-gate */ 24527c478bd9Sstevel@tonic-gate (void) hmestop(hmep); 24537c478bd9Sstevel@tonic-gate 24547c478bd9Sstevel@tonic-gate /* 24557c478bd9Sstevel@tonic-gate * Clear all descriptors. 24567c478bd9Sstevel@tonic-gate */ 24577c478bd9Sstevel@tonic-gate bzero(hmep->hme_rmdp, HME_RMDMAX * sizeof (struct hme_rmd)); 24587c478bd9Sstevel@tonic-gate bzero(hmep->hme_tmdp, HME_TMDMAX * sizeof (struct hme_tmd)); 24597c478bd9Sstevel@tonic-gate 24607c478bd9Sstevel@tonic-gate /* 24617c478bd9Sstevel@tonic-gate * Hang out receive buffers. 24627c478bd9Sstevel@tonic-gate */ 24630219346bSGarrett D'Amore for (i = 0; i < HME_RMDMAX; i++) { 24640219346bSGarrett D'Amore PUT_RMD(i, hmep->hme_rbuf[i].paddr); 24657c478bd9Sstevel@tonic-gate } 24667c478bd9Sstevel@tonic-gate 24677c478bd9Sstevel@tonic-gate /* 24687c478bd9Sstevel@tonic-gate * DMA sync descriptors. 24697c478bd9Sstevel@tonic-gate */ 24700219346bSGarrett D'Amore (void) ddi_dma_sync(hmep->hme_rmd_dmah, 0, 0, DDI_DMA_SYNC_FORDEV); 24710219346bSGarrett D'Amore (void) ddi_dma_sync(hmep->hme_tmd_dmah, 0, 0, DDI_DMA_SYNC_FORDEV); 24727c478bd9Sstevel@tonic-gate 24737c478bd9Sstevel@tonic-gate /* 24747c478bd9Sstevel@tonic-gate * Reset RMD and TMD 'walking' pointers. 24757c478bd9Sstevel@tonic-gate */ 24760219346bSGarrett D'Amore hmep->hme_rxindex = 0; 24770219346bSGarrett D'Amore hmep->hme_txindex = hmep->hme_txreclaim = 0; 24787c478bd9Sstevel@tonic-gate 24797c478bd9Sstevel@tonic-gate /* 24807c478bd9Sstevel@tonic-gate * This is the right place to initialize MIF !!! 24817c478bd9Sstevel@tonic-gate */ 24827c478bd9Sstevel@tonic-gate 24837c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_imask, HME_MIF_INTMASK); /* mask all interrupts */ 24847c478bd9Sstevel@tonic-gate 24857c478bd9Sstevel@tonic-gate if (!hmep->hme_frame_enable) 24867c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_cfg, GET_MIFREG(mif_cfg) | HME_MIF_CFGBB); 24877c478bd9Sstevel@tonic-gate else 24887c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_cfg, GET_MIFREG(mif_cfg) & ~HME_MIF_CFGBB); 24897c478bd9Sstevel@tonic-gate /* enable frame mode */ 24907c478bd9Sstevel@tonic-gate 24917c478bd9Sstevel@tonic-gate /* 24927c478bd9Sstevel@tonic-gate * Depending on the transceiver detected, select the source 24937c478bd9Sstevel@tonic-gate * of the clocks for the MAC. Without the clocks, TX_MAC does 24947c478bd9Sstevel@tonic-gate * not reset. When the Global Reset is issued to the Sbus/FEPS 24957c478bd9Sstevel@tonic-gate * ASIC, it selects Internal by default. 24967c478bd9Sstevel@tonic-gate */ 24977c478bd9Sstevel@tonic-gate 249806673d9bSGarrett D'Amore switch ((phyad = mii_get_addr(hmep->hme_mii))) { 249906673d9bSGarrett D'Amore case -1: 25007c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_HIGH, XCVR_MSG, no_xcvr_msg); 25017c478bd9Sstevel@tonic-gate goto init_fail; /* abort initialization */ 25027c478bd9Sstevel@tonic-gate 250306673d9bSGarrett D'Amore case HME_INTERNAL_PHYAD: 25047c478bd9Sstevel@tonic-gate PUT_MACREG(xifc, 0); 250506673d9bSGarrett D'Amore break; 250606673d9bSGarrett D'Amore case HME_EXTERNAL_PHYAD: 250706673d9bSGarrett D'Amore /* Isolate the Int. xcvr */ 25087c478bd9Sstevel@tonic-gate PUT_MACREG(xifc, BMAC_XIFC_MIIBUFDIS); 250906673d9bSGarrett D'Amore break; 25107c478bd9Sstevel@tonic-gate } 251106673d9bSGarrett D'Amore 25127c478bd9Sstevel@tonic-gate hmep->inits++; 25137c478bd9Sstevel@tonic-gate 25147c478bd9Sstevel@tonic-gate /* 25157c478bd9Sstevel@tonic-gate * Initialize BigMAC registers. 25167c478bd9Sstevel@tonic-gate * First set the tx enable bit in tx config reg to 0 and poll on 25177c478bd9Sstevel@tonic-gate * it till it turns to 0. Same for rx config, hash and address 25187c478bd9Sstevel@tonic-gate * filter reg. 25197c478bd9Sstevel@tonic-gate * Here is the sequence per the spec. 25207c478bd9Sstevel@tonic-gate * MADD2 - MAC Address 2 25217c478bd9Sstevel@tonic-gate * MADD1 - MAC Address 1 25227c478bd9Sstevel@tonic-gate * MADD0 - MAC Address 0 25237c478bd9Sstevel@tonic-gate * HASH3, HASH2, HASH1, HASH0 for group address 25247c478bd9Sstevel@tonic-gate * AFR2, AFR1, AFR0 and AFMR for address filter mask 25257c478bd9Sstevel@tonic-gate * Program RXMIN and RXMAX for packet length if not 802.3 25267c478bd9Sstevel@tonic-gate * RXCFG - Rx config for not stripping CRC 25277c478bd9Sstevel@tonic-gate * XXX Anything else to hme configured in RXCFG 25287c478bd9Sstevel@tonic-gate * IPG1, IPG2, ALIMIT, SLOT, PALEN, PAPAT, TXSFD, JAM, TXMAX, TXMIN 25297c478bd9Sstevel@tonic-gate * if not 802.3 compliant 25307c478bd9Sstevel@tonic-gate * XIF register for speed selection 25317c478bd9Sstevel@tonic-gate * MASK - Interrupt mask 25327c478bd9Sstevel@tonic-gate * Set bit 0 of TXCFG 25337c478bd9Sstevel@tonic-gate * Set bit 0 of RXCFG 25347c478bd9Sstevel@tonic-gate */ 25357c478bd9Sstevel@tonic-gate 25367c478bd9Sstevel@tonic-gate /* 25377c478bd9Sstevel@tonic-gate * Initialize the TX_MAC registers 25387c478bd9Sstevel@tonic-gate * Initialization of jamsize to work around rx crc bug 25397c478bd9Sstevel@tonic-gate */ 25407c478bd9Sstevel@tonic-gate PUT_MACREG(jam, jamsize); 25417c478bd9Sstevel@tonic-gate 25427c478bd9Sstevel@tonic-gate #ifdef FEPS_URUN_BUG 25437c478bd9Sstevel@tonic-gate if (hme_urun_fix) 25447c478bd9Sstevel@tonic-gate PUT_MACREG(palen, hme_palen); 25457c478bd9Sstevel@tonic-gate #endif 25467c478bd9Sstevel@tonic-gate 254706673d9bSGarrett D'Amore PUT_MACREG(ipg1, hmep->hme_ipg1); 254806673d9bSGarrett D'Amore PUT_MACREG(ipg2, hmep->hme_ipg2); 25497c478bd9Sstevel@tonic-gate 25507c478bd9Sstevel@tonic-gate PUT_MACREG(rseed, 255185025c03Sgd ((hmep->hme_ouraddr.ether_addr_octet[0] << 8) & 0x3) | 255285025c03Sgd hmep->hme_ouraddr.ether_addr_octet[1]); 25537c478bd9Sstevel@tonic-gate 25547c478bd9Sstevel@tonic-gate /* Initialize the RX_MAC registers */ 25557c478bd9Sstevel@tonic-gate 25567c478bd9Sstevel@tonic-gate /* 25577c478bd9Sstevel@tonic-gate * Program BigMAC with local individual ethernet address. 25587c478bd9Sstevel@tonic-gate */ 25597c478bd9Sstevel@tonic-gate PUT_MACREG(madd2, (hmep->hme_ouraddr.ether_addr_octet[4] << 8) | 256085025c03Sgd hmep->hme_ouraddr.ether_addr_octet[5]); 25617c478bd9Sstevel@tonic-gate PUT_MACREG(madd1, (hmep->hme_ouraddr.ether_addr_octet[2] << 8) | 256285025c03Sgd hmep->hme_ouraddr.ether_addr_octet[3]); 25637c478bd9Sstevel@tonic-gate PUT_MACREG(madd0, (hmep->hme_ouraddr.ether_addr_octet[0] << 8) | 256485025c03Sgd hmep->hme_ouraddr.ether_addr_octet[1]); 25657c478bd9Sstevel@tonic-gate 25667c478bd9Sstevel@tonic-gate /* 25677c478bd9Sstevel@tonic-gate * Set up multicast address filter by passing all multicast 25687c478bd9Sstevel@tonic-gate * addresses through a crc generator, and then using the 25697c478bd9Sstevel@tonic-gate * low order 6 bits as a index into the 64 bit logical 25707c478bd9Sstevel@tonic-gate * address filter. The high order three bits select the word, 25717c478bd9Sstevel@tonic-gate * while the rest of the bits select the bit within the word. 25727c478bd9Sstevel@tonic-gate */ 257385025c03Sgd PUT_MACREG(hash0, hmep->hme_ladrf[0]); 257485025c03Sgd PUT_MACREG(hash1, hmep->hme_ladrf[1]); 257585025c03Sgd PUT_MACREG(hash2, hmep->hme_ladrf[2]); 257685025c03Sgd PUT_MACREG(hash3, hmep->hme_ladrf[3]); 25777c478bd9Sstevel@tonic-gate 25787c478bd9Sstevel@tonic-gate /* 257985025c03Sgd * Configure parameters to support VLAN. (VLAN encapsulation adds 258085025c03Sgd * four bytes.) 25817c478bd9Sstevel@tonic-gate */ 258285025c03Sgd PUT_MACREG(txmax, ETHERMAX + ETHERFCSL + 4); 258385025c03Sgd PUT_MACREG(rxmax, ETHERMAX + ETHERFCSL + 4); 25847c478bd9Sstevel@tonic-gate 25857c478bd9Sstevel@tonic-gate /* 25867c478bd9Sstevel@tonic-gate * Initialize HME Global registers, ETX registers and ERX registers. 25877c478bd9Sstevel@tonic-gate */ 25887c478bd9Sstevel@tonic-gate 25890219346bSGarrett D'Amore PUT_ETXREG(txring, hmep->hme_tmd_paddr); 25900219346bSGarrett D'Amore PUT_ERXREG(rxring, hmep->hme_rmd_paddr); 25917c478bd9Sstevel@tonic-gate 25927c478bd9Sstevel@tonic-gate /* 25937c478bd9Sstevel@tonic-gate * ERX registers can be written only if they have even no. of bits set. 25947c478bd9Sstevel@tonic-gate * So, if the value written is not read back, set the lsb and write 25957c478bd9Sstevel@tonic-gate * again. 25967c478bd9Sstevel@tonic-gate * static int hme_erx_fix = 1; : Use the fix for erx bug 25977c478bd9Sstevel@tonic-gate */ 25987c478bd9Sstevel@tonic-gate { 25997c478bd9Sstevel@tonic-gate uint32_t temp; 26000219346bSGarrett D'Amore temp = hmep->hme_rmd_paddr; 26017c478bd9Sstevel@tonic-gate 26027c478bd9Sstevel@tonic-gate if (GET_ERXREG(rxring) != temp) 26037c478bd9Sstevel@tonic-gate PUT_ERXREG(rxring, (temp | 4)); 26047c478bd9Sstevel@tonic-gate } 26057c478bd9Sstevel@tonic-gate 260685025c03Sgd PUT_GLOBREG(config, (hmep->hme_config | 260785025c03Sgd (hmep->hme_64bit_xfer << HMEG_CONFIG_64BIT_SHIFT))); 26087c478bd9Sstevel@tonic-gate 26097c478bd9Sstevel@tonic-gate /* 26107c478bd9Sstevel@tonic-gate * Significant performance improvements can be achieved by 26117c478bd9Sstevel@tonic-gate * disabling transmit interrupt. Thus TMD's are reclaimed only 26127c478bd9Sstevel@tonic-gate * when we run out of them in hmestart(). 26137c478bd9Sstevel@tonic-gate */ 26147c478bd9Sstevel@tonic-gate PUT_GLOBREG(intmask, 261585025c03Sgd HMEG_MASK_INTR | HMEG_MASK_TINT | HMEG_MASK_TX_ALL); 26167c478bd9Sstevel@tonic-gate 26177c478bd9Sstevel@tonic-gate PUT_ETXREG(txring_size, ((HME_TMDMAX -1)>> HMET_RINGSZ_SHIFT)); 26187c478bd9Sstevel@tonic-gate PUT_ETXREG(config, (GET_ETXREG(config) | HMET_CONFIG_TXDMA_EN 261985025c03Sgd | HMET_CONFIG_TXFIFOTH)); 26207c478bd9Sstevel@tonic-gate /* get the rxring size bits */ 26217c478bd9Sstevel@tonic-gate switch (HME_RMDMAX) { 26227c478bd9Sstevel@tonic-gate case 32: 26237c478bd9Sstevel@tonic-gate i = HMER_CONFIG_RXRINGSZ32; 26247c478bd9Sstevel@tonic-gate break; 26257c478bd9Sstevel@tonic-gate case 64: 26267c478bd9Sstevel@tonic-gate i = HMER_CONFIG_RXRINGSZ64; 26277c478bd9Sstevel@tonic-gate break; 26287c478bd9Sstevel@tonic-gate case 128: 26297c478bd9Sstevel@tonic-gate i = HMER_CONFIG_RXRINGSZ128; 26307c478bd9Sstevel@tonic-gate break; 26317c478bd9Sstevel@tonic-gate case 256: 26327c478bd9Sstevel@tonic-gate i = HMER_CONFIG_RXRINGSZ256; 26337c478bd9Sstevel@tonic-gate break; 26347c478bd9Sstevel@tonic-gate default: 26357c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 263685025c03Sgd unk_rx_ringsz_msg); 26377c478bd9Sstevel@tonic-gate goto init_fail; 26387c478bd9Sstevel@tonic-gate } 26397c478bd9Sstevel@tonic-gate i |= (HME_FSTBYTE_OFFSET << HMER_CONFIG_FBO_SHIFT) 264085025c03Sgd | HMER_CONFIG_RXDMA_EN; 264185025c03Sgd 264285025c03Sgd /* h/w checks start offset in half words */ 264385025c03Sgd i |= ((sizeof (struct ether_header) / 2) << HMER_RX_CSSTART_SHIFT); 264485025c03Sgd 26457c478bd9Sstevel@tonic-gate PUT_ERXREG(config, i); 26467c478bd9Sstevel@tonic-gate 26477c478bd9Sstevel@tonic-gate /* 26487c478bd9Sstevel@tonic-gate * Bug related to the parity handling in ERX. When erxp-config is 26497c478bd9Sstevel@tonic-gate * read back. 26507c478bd9Sstevel@tonic-gate * Sbus/FEPS drives the parity bit. This value is used while 26517c478bd9Sstevel@tonic-gate * writing again. 26527c478bd9Sstevel@tonic-gate * This fixes the RECV problem in SS5. 26537c478bd9Sstevel@tonic-gate * static int hme_erx_fix = 1; : Use the fix for erx bug 26547c478bd9Sstevel@tonic-gate */ 26557c478bd9Sstevel@tonic-gate { 26567c478bd9Sstevel@tonic-gate uint32_t temp; 26577c478bd9Sstevel@tonic-gate temp = GET_ERXREG(config); 26587c478bd9Sstevel@tonic-gate PUT_ERXREG(config, i); 26597c478bd9Sstevel@tonic-gate 26607c478bd9Sstevel@tonic-gate if (GET_ERXREG(config) != i) 26617c478bd9Sstevel@tonic-gate HME_FAULT_MSG4(hmep, SEVERITY_UNKNOWN, ERX_MSG, 266285025c03Sgd "error:temp = %x erxp->config = %x, should be %x", 266385025c03Sgd temp, GET_ERXREG(config), i); 26647c478bd9Sstevel@tonic-gate } 26657c478bd9Sstevel@tonic-gate 26667c478bd9Sstevel@tonic-gate /* 26677c478bd9Sstevel@tonic-gate * Set up the rxconfig, txconfig and seed register without enabling 26687c478bd9Sstevel@tonic-gate * them the former two at this time 26697c478bd9Sstevel@tonic-gate * 26707c478bd9Sstevel@tonic-gate * BigMAC strips the CRC bytes by default. Since this is 26717c478bd9Sstevel@tonic-gate * contrary to other pieces of hardware, this bit needs to 26727c478bd9Sstevel@tonic-gate * enabled to tell BigMAC not to strip the CRC bytes. 26737c478bd9Sstevel@tonic-gate * Do not filter this node's own packets. 26747c478bd9Sstevel@tonic-gate */ 26757c478bd9Sstevel@tonic-gate 26767c478bd9Sstevel@tonic-gate if (hme_reject_own) { 26777c478bd9Sstevel@tonic-gate PUT_MACREG(rxcfg, 2678228fdff0Sgd ((hmep->hme_promisc ? BMAC_RXCFG_PROMIS : 0) | 267985025c03Sgd BMAC_RXCFG_MYOWN | BMAC_RXCFG_HASH)); 26807c478bd9Sstevel@tonic-gate } else { 26817c478bd9Sstevel@tonic-gate PUT_MACREG(rxcfg, 2682228fdff0Sgd ((hmep->hme_promisc ? BMAC_RXCFG_PROMIS : 0) | 268385025c03Sgd BMAC_RXCFG_HASH)); 26847c478bd9Sstevel@tonic-gate } 26857c478bd9Sstevel@tonic-gate 26867c478bd9Sstevel@tonic-gate drv_usecwait(10); /* wait after setting Hash Enable bit */ 26877c478bd9Sstevel@tonic-gate 268806673d9bSGarrett D'Amore fdx = (mii_get_duplex(hmep->hme_mii) == LINK_DUPLEX_FULL); 268906673d9bSGarrett D'Amore 26907c478bd9Sstevel@tonic-gate if (hme_ngu_enable) 269106673d9bSGarrett D'Amore PUT_MACREG(txcfg, (fdx ? BMAC_TXCFG_FDX : 0) | 269285025c03Sgd BMAC_TXCFG_NGU); 26937c478bd9Sstevel@tonic-gate else 269406673d9bSGarrett D'Amore PUT_MACREG(txcfg, (fdx ? BMAC_TXCFG_FDX: 0)); 26957c478bd9Sstevel@tonic-gate 26967c478bd9Sstevel@tonic-gate i = 0; 269706673d9bSGarrett D'Amore if ((hmep->hme_lance_mode) && (hmep->hme_lance_mode_enable)) 269806673d9bSGarrett D'Amore i = ((hmep->hme_ipg0 & HME_MASK_5BIT) << BMAC_XIFC_IPG0_SHIFT) 269985025c03Sgd | BMAC_XIFC_LANCE_ENAB; 270006673d9bSGarrett D'Amore if (phyad == HME_INTERNAL_PHYAD) 27017c478bd9Sstevel@tonic-gate PUT_MACREG(xifc, i | (BMAC_XIFC_ENAB)); 27027c478bd9Sstevel@tonic-gate else 27037c478bd9Sstevel@tonic-gate PUT_MACREG(xifc, i | (BMAC_XIFC_ENAB | BMAC_XIFC_MIIBUFDIS)); 27047c478bd9Sstevel@tonic-gate 27057c478bd9Sstevel@tonic-gate PUT_MACREG(rxcfg, GET_MACREG(rxcfg) | BMAC_RXCFG_ENAB); 27067c478bd9Sstevel@tonic-gate PUT_MACREG(txcfg, GET_MACREG(txcfg) | BMAC_TXCFG_ENAB); 27077c478bd9Sstevel@tonic-gate 27087c478bd9Sstevel@tonic-gate hmep->hme_flags |= (HMERUNNING | HMEINITIALIZED); 27097c478bd9Sstevel@tonic-gate /* 27107c478bd9Sstevel@tonic-gate * Update the interrupt mask : this will re-allow interrupts to occur 27117c478bd9Sstevel@tonic-gate */ 271285025c03Sgd PUT_GLOBREG(intmask, HMEG_MASK_INTR); 271385025c03Sgd mac_tx_update(hmep->hme_mh); 27147c478bd9Sstevel@tonic-gate 27157c478bd9Sstevel@tonic-gate init_fail: 27167c478bd9Sstevel@tonic-gate /* 27177c478bd9Sstevel@tonic-gate * Release the locks in reverse order 27187c478bd9Sstevel@tonic-gate */ 27197c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_xmitlock); 27207c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_intrlock); 27217c478bd9Sstevel@tonic-gate 27227c478bd9Sstevel@tonic-gate ret = !(hmep->hme_flags & HMERUNNING); 27237c478bd9Sstevel@tonic-gate if (ret) { 27247c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 272585025c03Sgd init_fail_gen_msg); 27267c478bd9Sstevel@tonic-gate } 27277c478bd9Sstevel@tonic-gate 27287c478bd9Sstevel@tonic-gate /* 27297c478bd9Sstevel@tonic-gate * Hardware checks. 27307c478bd9Sstevel@tonic-gate */ 27317c478bd9Sstevel@tonic-gate CHECK_GLOBREG(); 27327c478bd9Sstevel@tonic-gate CHECK_MIFREG(); 27337c478bd9Sstevel@tonic-gate CHECK_MACREG(); 27347c478bd9Sstevel@tonic-gate CHECK_ERXREG(); 27357c478bd9Sstevel@tonic-gate CHECK_ETXREG(); 27367c478bd9Sstevel@tonic-gate 27377c478bd9Sstevel@tonic-gate init_exit: 27387c478bd9Sstevel@tonic-gate return (ret); 27397c478bd9Sstevel@tonic-gate } 27407c478bd9Sstevel@tonic-gate 27417c478bd9Sstevel@tonic-gate /* 27427c478bd9Sstevel@tonic-gate * Calculate the dvma burstsize by setting up a dvma temporarily. Return 27437c478bd9Sstevel@tonic-gate * 0 as burstsize upon failure as it signifies no burst size. 27447c478bd9Sstevel@tonic-gate * Requests for 64-bit transfer setup, if the platform supports it. 27457c478bd9Sstevel@tonic-gate * NOTE: Do not use ddi_dma_alloc_handle(9f) then ddi_dma_burstsize(9f), 27467c478bd9Sstevel@tonic-gate * sun4u Ultra-2 incorrectly returns a 32bit transfer. 27477c478bd9Sstevel@tonic-gate */ 27487c478bd9Sstevel@tonic-gate static int 27497c478bd9Sstevel@tonic-gate hmeburstsizes(struct hme *hmep) 27507c478bd9Sstevel@tonic-gate { 27517c478bd9Sstevel@tonic-gate int burstsizes; 27527c478bd9Sstevel@tonic-gate ddi_dma_handle_t handle; 27537c478bd9Sstevel@tonic-gate 27547c478bd9Sstevel@tonic-gate if (ddi_dma_alloc_handle(hmep->dip, &hme_dma_attr, 27557c478bd9Sstevel@tonic-gate DDI_DMA_DONTWAIT, NULL, &handle)) { 27567c478bd9Sstevel@tonic-gate return (0); 27577c478bd9Sstevel@tonic-gate } 27587c478bd9Sstevel@tonic-gate 27597c478bd9Sstevel@tonic-gate hmep->hme_burstsizes = burstsizes = ddi_dma_burstsizes(handle); 27607c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&handle); 27617c478bd9Sstevel@tonic-gate 27627c478bd9Sstevel@tonic-gate /* 27637c478bd9Sstevel@tonic-gate * Use user-configurable parameter for enabling 64-bit transfers 27647c478bd9Sstevel@tonic-gate */ 27657c478bd9Sstevel@tonic-gate burstsizes = (hmep->hme_burstsizes >> 16); 27667c478bd9Sstevel@tonic-gate if (burstsizes) 27677c478bd9Sstevel@tonic-gate hmep->hme_64bit_xfer = hme_64bit_enable; /* user config value */ 27687c478bd9Sstevel@tonic-gate else 27697c478bd9Sstevel@tonic-gate burstsizes = hmep->hme_burstsizes; 27707c478bd9Sstevel@tonic-gate 27717c478bd9Sstevel@tonic-gate if (hmep->hme_cheerio_mode) 27727c478bd9Sstevel@tonic-gate hmep->hme_64bit_xfer = 0; /* Disable for cheerio */ 27737c478bd9Sstevel@tonic-gate 27747c478bd9Sstevel@tonic-gate if (burstsizes & 0x40) 27757c478bd9Sstevel@tonic-gate hmep->hme_config = HMEG_CONFIG_BURST64; 27767c478bd9Sstevel@tonic-gate else if (burstsizes & 0x20) 27777c478bd9Sstevel@tonic-gate hmep->hme_config = HMEG_CONFIG_BURST32; 27787c478bd9Sstevel@tonic-gate else 27797c478bd9Sstevel@tonic-gate hmep->hme_config = HMEG_CONFIG_BURST16; 27807c478bd9Sstevel@tonic-gate 27810219346bSGarrett D'Amore return (DDI_SUCCESS); 27820219346bSGarrett D'Amore } 27830219346bSGarrett D'Amore 27840219346bSGarrett D'Amore static int 27850219346bSGarrett D'Amore hmeallocbuf(struct hme *hmep, hmebuf_t *buf, int dir) 27860219346bSGarrett D'Amore { 27870219346bSGarrett D'Amore ddi_dma_cookie_t dmac; 27880219346bSGarrett D'Amore size_t len; 27890219346bSGarrett D'Amore unsigned ccnt; 27900219346bSGarrett D'Amore 27910219346bSGarrett D'Amore if (ddi_dma_alloc_handle(hmep->dip, &hme_dma_attr, 27920219346bSGarrett D'Amore DDI_DMA_DONTWAIT, NULL, &buf->dmah) != DDI_SUCCESS) { 27930219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 27940219346bSGarrett D'Amore "cannot allocate buf dma handle - failed"); 27950219346bSGarrett D'Amore return (DDI_FAILURE); 27960219346bSGarrett D'Amore } 27970219346bSGarrett D'Amore 27980219346bSGarrett D'Amore if (ddi_dma_mem_alloc(buf->dmah, ROUNDUP(HMEBUFSIZE, 512), 27990219346bSGarrett D'Amore &hme_buf_attr, DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, NULL, 28000219346bSGarrett D'Amore &buf->kaddr, &len, &buf->acch) != DDI_SUCCESS) { 28010219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 28020219346bSGarrett D'Amore "cannot allocate buf memory - failed"); 28030219346bSGarrett D'Amore return (DDI_FAILURE); 28040219346bSGarrett D'Amore } 28050219346bSGarrett D'Amore 28060219346bSGarrett D'Amore if (ddi_dma_addr_bind_handle(buf->dmah, NULL, buf->kaddr, 28070219346bSGarrett D'Amore len, dir | DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL, 28080219346bSGarrett D'Amore &dmac, &ccnt) != DDI_DMA_MAPPED) { 28090219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 28100219346bSGarrett D'Amore "cannot map buf for dma - failed"); 28110219346bSGarrett D'Amore return (DDI_FAILURE); 28120219346bSGarrett D'Amore } 28130219346bSGarrett D'Amore buf->paddr = dmac.dmac_address; 28140219346bSGarrett D'Amore 28150219346bSGarrett D'Amore /* apparently they don't handle multiple cookies */ 28160219346bSGarrett D'Amore if (ccnt > 1) { 28170219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 28180219346bSGarrett D'Amore "too many buf dma cookies"); 28190219346bSGarrett D'Amore return (DDI_FAILURE); 28200219346bSGarrett D'Amore } 28210219346bSGarrett D'Amore return (DDI_SUCCESS); 28220219346bSGarrett D'Amore } 28230219346bSGarrett D'Amore 28240219346bSGarrett D'Amore static int 28250219346bSGarrett D'Amore hmeallocbufs(struct hme *hmep) 28260219346bSGarrett D'Amore { 28270219346bSGarrett D'Amore hmep->hme_tbuf = kmem_zalloc(HME_TMDMAX * sizeof (hmebuf_t), KM_SLEEP); 28280219346bSGarrett D'Amore hmep->hme_rbuf = kmem_zalloc(HME_RMDMAX * sizeof (hmebuf_t), KM_SLEEP); 28290219346bSGarrett D'Amore 28300219346bSGarrett D'Amore /* Alloc RX buffers. */ 28310219346bSGarrett D'Amore for (int i = 0; i < HME_RMDMAX; i++) { 28320219346bSGarrett D'Amore if (hmeallocbuf(hmep, &hmep->hme_rbuf[i], DDI_DMA_READ) != 28330219346bSGarrett D'Amore DDI_SUCCESS) { 28340219346bSGarrett D'Amore return (DDI_FAILURE); 28350219346bSGarrett D'Amore } 28360219346bSGarrett D'Amore } 28370219346bSGarrett D'Amore 28380219346bSGarrett D'Amore /* Alloc TX buffers. */ 28390219346bSGarrett D'Amore for (int i = 0; i < HME_TMDMAX; i++) { 28400219346bSGarrett D'Amore if (hmeallocbuf(hmep, &hmep->hme_tbuf[i], DDI_DMA_WRITE) != 28410219346bSGarrett D'Amore DDI_SUCCESS) { 28420219346bSGarrett D'Amore return (DDI_FAILURE); 28430219346bSGarrett D'Amore } 28440219346bSGarrett D'Amore } 28457c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 28467c478bd9Sstevel@tonic-gate } 28477c478bd9Sstevel@tonic-gate 28487c478bd9Sstevel@tonic-gate static void 28497c478bd9Sstevel@tonic-gate hmefreebufs(struct hme *hmep) 28507c478bd9Sstevel@tonic-gate { 28517c478bd9Sstevel@tonic-gate int i; 28520219346bSGarrett D'Amore 28530219346bSGarrett D'Amore if (hmep->hme_rbuf == NULL) 28540219346bSGarrett D'Amore return; 28557c478bd9Sstevel@tonic-gate 28567c478bd9Sstevel@tonic-gate /* 28570219346bSGarrett D'Amore * Free and unload pending xmit and recv buffers. 28587c478bd9Sstevel@tonic-gate * Maintaining the 1-to-1 ordered sequence of 28590219346bSGarrett D'Amore * We have written the routine to be idempotent. 28607c478bd9Sstevel@tonic-gate */ 28617c478bd9Sstevel@tonic-gate 28627c478bd9Sstevel@tonic-gate for (i = 0; i < HME_TMDMAX; i++) { 28630219346bSGarrett D'Amore hmebuf_t *tbuf = &hmep->hme_tbuf[i]; 28640219346bSGarrett D'Amore if (tbuf->paddr) { 28650219346bSGarrett D'Amore (void) ddi_dma_unbind_handle(tbuf->dmah); 28660219346bSGarrett D'Amore } 28670219346bSGarrett D'Amore if (tbuf->kaddr) { 28680219346bSGarrett D'Amore ddi_dma_mem_free(&tbuf->acch); 28690219346bSGarrett D'Amore } 28700219346bSGarrett D'Amore if (tbuf->dmah) { 28710219346bSGarrett D'Amore ddi_dma_free_handle(&tbuf->dmah); 28727c478bd9Sstevel@tonic-gate } 28737c478bd9Sstevel@tonic-gate } 28747c478bd9Sstevel@tonic-gate for (i = 0; i < HME_RMDMAX; i++) { 28750219346bSGarrett D'Amore hmebuf_t *rbuf = &hmep->hme_rbuf[i]; 28760219346bSGarrett D'Amore if (rbuf->paddr) { 28770219346bSGarrett D'Amore (void) ddi_dma_unbind_handle(rbuf->dmah); 28780219346bSGarrett D'Amore } 28790219346bSGarrett D'Amore if (rbuf->kaddr) { 28800219346bSGarrett D'Amore ddi_dma_mem_free(&rbuf->acch); 28810219346bSGarrett D'Amore } 28820219346bSGarrett D'Amore if (rbuf->dmah) { 28830219346bSGarrett D'Amore ddi_dma_free_handle(&rbuf->dmah); 28847c478bd9Sstevel@tonic-gate } 28857c478bd9Sstevel@tonic-gate } 28860219346bSGarrett D'Amore kmem_free(hmep->hme_rbuf, HME_RMDMAX * sizeof (hmebuf_t)); 28870219346bSGarrett D'Amore kmem_free(hmep->hme_tbuf, HME_TMDMAX * sizeof (hmebuf_t)); 28887c478bd9Sstevel@tonic-gate } 28897c478bd9Sstevel@tonic-gate 28907c478bd9Sstevel@tonic-gate /* 28917c478bd9Sstevel@tonic-gate * Un-initialize (STOP) HME channel. 28927c478bd9Sstevel@tonic-gate */ 28937c478bd9Sstevel@tonic-gate static void 28947c478bd9Sstevel@tonic-gate hmeuninit(struct hme *hmep) 28957c478bd9Sstevel@tonic-gate { 28967c478bd9Sstevel@tonic-gate /* 28977c478bd9Sstevel@tonic-gate * Allow up to 'HMEDRAINTIME' for pending xmit's to complete. 28987c478bd9Sstevel@tonic-gate */ 28990219346bSGarrett D'Amore HMEDELAY((hmep->hme_txindex == hmep->hme_txreclaim), HMEDRAINTIME); 29007c478bd9Sstevel@tonic-gate 29017c478bd9Sstevel@tonic-gate mutex_enter(&hmep->hme_intrlock); 29027c478bd9Sstevel@tonic-gate mutex_enter(&hmep->hme_xmitlock); 29037c478bd9Sstevel@tonic-gate 29047c478bd9Sstevel@tonic-gate hmep->hme_flags &= ~HMERUNNING; 29057c478bd9Sstevel@tonic-gate 29067c478bd9Sstevel@tonic-gate (void) hmestop(hmep); 29077c478bd9Sstevel@tonic-gate 29087c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_xmitlock); 29097c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_intrlock); 29107c478bd9Sstevel@tonic-gate } 29117c478bd9Sstevel@tonic-gate 29127c478bd9Sstevel@tonic-gate /* 29137c478bd9Sstevel@tonic-gate * Allocate CONSISTENT memory for rmds and tmds with appropriate alignment and 29147c478bd9Sstevel@tonic-gate * map it in IO space. Allocate space for transmit and receive ddi_dma_handle 29157c478bd9Sstevel@tonic-gate * structures to use the DMA interface. 29167c478bd9Sstevel@tonic-gate */ 29177c478bd9Sstevel@tonic-gate static int 29187c478bd9Sstevel@tonic-gate hmeallocthings(struct hme *hmep) 29197c478bd9Sstevel@tonic-gate { 29200219346bSGarrett D'Amore int size; 29210219346bSGarrett D'Amore int rval; 29220219346bSGarrett D'Amore size_t real_len; 29230219346bSGarrett D'Amore uint_t cookiec; 29240219346bSGarrett D'Amore ddi_dma_cookie_t dmac; 29250219346bSGarrett D'Amore dev_info_t *dip = hmep->dip; 29267c478bd9Sstevel@tonic-gate 29277c478bd9Sstevel@tonic-gate /* 29287c478bd9Sstevel@tonic-gate * Allocate the TMD and RMD descriptors and extra for page alignment. 29297c478bd9Sstevel@tonic-gate */ 29307c478bd9Sstevel@tonic-gate 29310219346bSGarrett D'Amore rval = ddi_dma_alloc_handle(dip, &hme_dma_attr, DDI_DMA_DONTWAIT, NULL, 29320219346bSGarrett D'Amore &hmep->hme_rmd_dmah); 29337c478bd9Sstevel@tonic-gate if (rval != DDI_SUCCESS) { 293485025c03Sgd HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 293585025c03Sgd "cannot allocate rmd handle - failed"); 29360219346bSGarrett D'Amore return (DDI_FAILURE); 29377c478bd9Sstevel@tonic-gate } 29380219346bSGarrett D'Amore size = HME_RMDMAX * sizeof (struct hme_rmd); 29390219346bSGarrett D'Amore rval = ddi_dma_mem_alloc(hmep->hme_rmd_dmah, size, 29400219346bSGarrett D'Amore &hmep->hme_dev_attr, DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL, 29410219346bSGarrett D'Amore &hmep->hme_rmd_kaddr, &real_len, &hmep->hme_rmd_acch); 29427c478bd9Sstevel@tonic-gate if (rval != DDI_SUCCESS) { 294385025c03Sgd HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 29440219346bSGarrett D'Amore "cannot allocate rmd dma mem - failed"); 29450219346bSGarrett D'Amore return (DDI_FAILURE); 29467c478bd9Sstevel@tonic-gate } 29470219346bSGarrett D'Amore hmep->hme_rmdp = (void *)(hmep->hme_rmd_kaddr); 29480219346bSGarrett D'Amore rval = ddi_dma_addr_bind_handle(hmep->hme_rmd_dmah, NULL, 29490219346bSGarrett D'Amore hmep->hme_rmd_kaddr, size, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 29500219346bSGarrett D'Amore DDI_DMA_DONTWAIT, NULL, &dmac, &cookiec); 29517c478bd9Sstevel@tonic-gate if (rval != DDI_DMA_MAPPED) { 295285025c03Sgd HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 29530219346bSGarrett D'Amore "cannot allocate rmd dma - failed"); 29540219346bSGarrett D'Amore return (DDI_FAILURE); 29557c478bd9Sstevel@tonic-gate } 29560219346bSGarrett D'Amore hmep->hme_rmd_paddr = dmac.dmac_address; 29577c478bd9Sstevel@tonic-gate if (cookiec != 1) { 295885025c03Sgd HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 29590219346bSGarrett D'Amore "too many rmd cookies - failed"); 29600219346bSGarrett D'Amore return (DDI_FAILURE); 29617c478bd9Sstevel@tonic-gate } 29627c478bd9Sstevel@tonic-gate 29630219346bSGarrett D'Amore rval = ddi_dma_alloc_handle(dip, &hme_dma_attr, DDI_DMA_DONTWAIT, NULL, 29640219346bSGarrett D'Amore &hmep->hme_tmd_dmah); 29650219346bSGarrett D'Amore if (rval != DDI_SUCCESS) { 29660219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 29670219346bSGarrett D'Amore "cannot allocate tmd handle - failed"); 29680219346bSGarrett D'Amore return (DDI_FAILURE); 29690219346bSGarrett D'Amore } 29700219346bSGarrett D'Amore size = HME_TMDMAX * sizeof (struct hme_rmd); 29710219346bSGarrett D'Amore rval = ddi_dma_mem_alloc(hmep->hme_tmd_dmah, size, 29720219346bSGarrett D'Amore &hmep->hme_dev_attr, DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL, 29730219346bSGarrett D'Amore &hmep->hme_tmd_kaddr, &real_len, &hmep->hme_tmd_acch); 29740219346bSGarrett D'Amore if (rval != DDI_SUCCESS) { 29750219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 29760219346bSGarrett D'Amore "cannot allocate tmd dma mem - failed"); 29770219346bSGarrett D'Amore return (DDI_FAILURE); 29780219346bSGarrett D'Amore } 29790219346bSGarrett D'Amore hmep->hme_tmdp = (void *)(hmep->hme_tmd_kaddr); 29800219346bSGarrett D'Amore rval = ddi_dma_addr_bind_handle(hmep->hme_tmd_dmah, NULL, 29810219346bSGarrett D'Amore hmep->hme_tmd_kaddr, size, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 29820219346bSGarrett D'Amore DDI_DMA_DONTWAIT, NULL, &dmac, &cookiec); 29830219346bSGarrett D'Amore if (rval != DDI_DMA_MAPPED) { 29840219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 29850219346bSGarrett D'Amore "cannot allocate tmd dma - failed"); 29860219346bSGarrett D'Amore return (DDI_FAILURE); 29870219346bSGarrett D'Amore } 29880219346bSGarrett D'Amore hmep->hme_tmd_paddr = dmac.dmac_address; 29890219346bSGarrett D'Amore if (cookiec != 1) { 29900219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 29910219346bSGarrett D'Amore "too many tmd cookies - failed"); 29920219346bSGarrett D'Amore return (DDI_FAILURE); 29937c478bd9Sstevel@tonic-gate } 29947c478bd9Sstevel@tonic-gate 29950219346bSGarrett D'Amore return (DDI_SUCCESS); 29967c478bd9Sstevel@tonic-gate } 29977c478bd9Sstevel@tonic-gate 29980219346bSGarrett D'Amore static void 29990219346bSGarrett D'Amore hmefreethings(struct hme *hmep) 30000219346bSGarrett D'Amore { 30010219346bSGarrett D'Amore if (hmep->hme_rmd_paddr) { 30020219346bSGarrett D'Amore (void) ddi_dma_unbind_handle(hmep->hme_rmd_dmah); 30030219346bSGarrett D'Amore hmep->hme_rmd_paddr = 0; 30040219346bSGarrett D'Amore } 30050219346bSGarrett D'Amore if (hmep->hme_rmd_acch) 30060219346bSGarrett D'Amore ddi_dma_mem_free(&hmep->hme_rmd_acch); 30070219346bSGarrett D'Amore if (hmep->hme_rmd_dmah) 30080219346bSGarrett D'Amore ddi_dma_free_handle(&hmep->hme_rmd_dmah); 30090219346bSGarrett D'Amore 30100219346bSGarrett D'Amore if (hmep->hme_tmd_paddr) { 30110219346bSGarrett D'Amore (void) ddi_dma_unbind_handle(hmep->hme_tmd_dmah); 30120219346bSGarrett D'Amore hmep->hme_tmd_paddr = 0; 30130219346bSGarrett D'Amore } 30140219346bSGarrett D'Amore if (hmep->hme_tmd_acch) 30150219346bSGarrett D'Amore ddi_dma_mem_free(&hmep->hme_tmd_acch); 30160219346bSGarrett D'Amore if (hmep->hme_tmd_dmah) 30170219346bSGarrett D'Amore ddi_dma_free_handle(&hmep->hme_tmd_dmah); 30180219346bSGarrett D'Amore } 30197c478bd9Sstevel@tonic-gate 30207c478bd9Sstevel@tonic-gate /* 30217c478bd9Sstevel@tonic-gate * First check to see if it our device interrupting. 30227c478bd9Sstevel@tonic-gate */ 30237c478bd9Sstevel@tonic-gate static uint_t 302485025c03Sgd hmeintr(caddr_t arg) 30257c478bd9Sstevel@tonic-gate { 302685025c03Sgd struct hme *hmep = (void *)arg; 30277c478bd9Sstevel@tonic-gate uint32_t hmesbits; 30287c478bd9Sstevel@tonic-gate uint32_t serviced = DDI_INTR_UNCLAIMED; 30297c478bd9Sstevel@tonic-gate uint32_t num_reads = 0; 303085025c03Sgd uint32_t rflags; 303185025c03Sgd mblk_t *mp, *head, **tail; 30327c478bd9Sstevel@tonic-gate 30337c478bd9Sstevel@tonic-gate 303485025c03Sgd head = NULL; 303585025c03Sgd tail = &head; 30367c478bd9Sstevel@tonic-gate 30377c478bd9Sstevel@tonic-gate mutex_enter(&hmep->hme_intrlock); 30387c478bd9Sstevel@tonic-gate 30397c478bd9Sstevel@tonic-gate /* 30407c478bd9Sstevel@tonic-gate * The status register auto-clears on read except for 30417c478bd9Sstevel@tonic-gate * MIF Interrupt bit 30427c478bd9Sstevel@tonic-gate */ 30437c478bd9Sstevel@tonic-gate hmesbits = GET_GLOBREG(status); 30447c478bd9Sstevel@tonic-gate CHECK_GLOBREG(); 30457c478bd9Sstevel@tonic-gate 30467c478bd9Sstevel@tonic-gate /* 30477c478bd9Sstevel@tonic-gate * Note: TINT is sometimes enabled in thr hmereclaim() 30487c478bd9Sstevel@tonic-gate */ 30497c478bd9Sstevel@tonic-gate 30507c478bd9Sstevel@tonic-gate /* 30517c478bd9Sstevel@tonic-gate * Bugid 1227832 - to handle spurious interrupts on fusion systems. 30527c478bd9Sstevel@tonic-gate * Claim the first interrupt after initialization 30537c478bd9Sstevel@tonic-gate */ 30547c478bd9Sstevel@tonic-gate if (hmep->hme_flags & HMEINITIALIZED) { 30557c478bd9Sstevel@tonic-gate hmep->hme_flags &= ~HMEINITIALIZED; 30567c478bd9Sstevel@tonic-gate serviced = DDI_INTR_CLAIMED; 30577c478bd9Sstevel@tonic-gate } 30587c478bd9Sstevel@tonic-gate 30597c478bd9Sstevel@tonic-gate if ((hmesbits & (HMEG_STATUS_INTR | HMEG_STATUS_TINT)) == 0) { 30607c478bd9Sstevel@tonic-gate /* No interesting interrupt */ 30617c478bd9Sstevel@tonic-gate if (hmep->hme_intrstats) { 30627c478bd9Sstevel@tonic-gate if (serviced == DDI_INTR_UNCLAIMED) 30637c478bd9Sstevel@tonic-gate KIOIP->intrs[KSTAT_INTR_SPURIOUS]++; 30647c478bd9Sstevel@tonic-gate else 30657c478bd9Sstevel@tonic-gate KIOIP->intrs[KSTAT_INTR_HARD]++; 30667c478bd9Sstevel@tonic-gate } 30677c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_intrlock); 30687c478bd9Sstevel@tonic-gate return (serviced); 30697c478bd9Sstevel@tonic-gate } 30707c478bd9Sstevel@tonic-gate 30717c478bd9Sstevel@tonic-gate serviced = DDI_INTR_CLAIMED; 30727c478bd9Sstevel@tonic-gate 30737c478bd9Sstevel@tonic-gate if (!(hmep->hme_flags & HMERUNNING)) { 30747c478bd9Sstevel@tonic-gate if (hmep->hme_intrstats) 30757c478bd9Sstevel@tonic-gate KIOIP->intrs[KSTAT_INTR_HARD]++; 30767c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_intrlock); 30777c478bd9Sstevel@tonic-gate hmeuninit(hmep); 30787c478bd9Sstevel@tonic-gate return (serviced); 30797c478bd9Sstevel@tonic-gate } 30807c478bd9Sstevel@tonic-gate 30817c478bd9Sstevel@tonic-gate if (hmesbits & (HMEG_STATUS_FATAL_ERR | HMEG_STATUS_NONFATAL_ERR)) { 30827c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_FATAL_ERR) { 30837c478bd9Sstevel@tonic-gate 30847c478bd9Sstevel@tonic-gate if (hmep->hme_intrstats) 30857c478bd9Sstevel@tonic-gate KIOIP->intrs[KSTAT_INTR_HARD]++; 30867c478bd9Sstevel@tonic-gate hme_fatal_err(hmep, hmesbits); 30877c478bd9Sstevel@tonic-gate 30887c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_intrlock); 30897c478bd9Sstevel@tonic-gate (void) hmeinit(hmep); 30907c478bd9Sstevel@tonic-gate return (serviced); 30917c478bd9Sstevel@tonic-gate } 30927c478bd9Sstevel@tonic-gate hme_nonfatal_err(hmep, hmesbits); 30937c478bd9Sstevel@tonic-gate } 30947c478bd9Sstevel@tonic-gate 30957c478bd9Sstevel@tonic-gate if (hmesbits & (HMEG_STATUS_TX_ALL | HMEG_STATUS_TINT)) { 30967c478bd9Sstevel@tonic-gate mutex_enter(&hmep->hme_xmitlock); 30977c478bd9Sstevel@tonic-gate 30987c478bd9Sstevel@tonic-gate hmereclaim(hmep); 30997c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_xmitlock); 31007c478bd9Sstevel@tonic-gate } 31017c478bd9Sstevel@tonic-gate 31027c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_RINT) { 31037c478bd9Sstevel@tonic-gate 31047c478bd9Sstevel@tonic-gate /* 31057c478bd9Sstevel@tonic-gate * This dummy PIO is required to flush the SBus 31067c478bd9Sstevel@tonic-gate * Bridge buffers in QFE. 31077c478bd9Sstevel@tonic-gate */ 31080219346bSGarrett D'Amore (void) GET_GLOBREG(config); 31097c478bd9Sstevel@tonic-gate 31107c478bd9Sstevel@tonic-gate /* 31110219346bSGarrett D'Amore * Loop through each RMD no more than once. 31127c478bd9Sstevel@tonic-gate */ 31130219346bSGarrett D'Amore while (num_reads++ < HME_RMDMAX) { 31140219346bSGarrett D'Amore hmebuf_t *rbuf; 31150219346bSGarrett D'Amore int rxptr; 31160219346bSGarrett D'Amore 31170219346bSGarrett D'Amore rxptr = hmep->hme_rxindex % HME_RMDMAX; 31180219346bSGarrett D'Amore HMESYNCRMD(rxptr, DDI_DMA_SYNC_FORKERNEL); 31190219346bSGarrett D'Amore 31200219346bSGarrett D'Amore rflags = GET_RMD_FLAGS(rxptr); 31210219346bSGarrett D'Amore if (rflags & HMERMD_OWN) { 31220219346bSGarrett D'Amore /* 31230219346bSGarrett D'Amore * Chip still owns it. We're done. 31240219346bSGarrett D'Amore */ 31250219346bSGarrett D'Amore break; 31260219346bSGarrett D'Amore } 312785025c03Sgd 31280219346bSGarrett D'Amore /* 31290219346bSGarrett D'Amore * Retrieve the packet. 31300219346bSGarrett D'Amore */ 31310219346bSGarrett D'Amore rbuf = &hmep->hme_rbuf[rxptr]; 31320219346bSGarrett D'Amore mp = hmeread(hmep, rbuf, rflags); 313385025c03Sgd 31347c478bd9Sstevel@tonic-gate /* 31350219346bSGarrett D'Amore * Return ownership of the RMD. 31367c478bd9Sstevel@tonic-gate */ 31370219346bSGarrett D'Amore PUT_RMD(rxptr, rbuf->paddr); 31380219346bSGarrett D'Amore HMESYNCRMD(rxptr, DDI_DMA_SYNC_FORDEV); 31397c478bd9Sstevel@tonic-gate 314085025c03Sgd if (mp != NULL) { 314185025c03Sgd *tail = mp; 314285025c03Sgd tail = &mp->b_next; 314385025c03Sgd } 314485025c03Sgd 31457c478bd9Sstevel@tonic-gate /* 31460219346bSGarrett D'Amore * Advance to the next RMD. 31477c478bd9Sstevel@tonic-gate */ 31480219346bSGarrett D'Amore hmep->hme_rxindex++; 31497c478bd9Sstevel@tonic-gate } 31507c478bd9Sstevel@tonic-gate } 31517c478bd9Sstevel@tonic-gate 31527c478bd9Sstevel@tonic-gate if (hmep->hme_intrstats) 31537c478bd9Sstevel@tonic-gate KIOIP->intrs[KSTAT_INTR_HARD]++; 31547c478bd9Sstevel@tonic-gate 31557c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_intrlock); 315685025c03Sgd 315785025c03Sgd if (head != NULL) 315885025c03Sgd mac_rx(hmep->hme_mh, NULL, head); 315985025c03Sgd 31607c478bd9Sstevel@tonic-gate return (serviced); 31617c478bd9Sstevel@tonic-gate } 31627c478bd9Sstevel@tonic-gate 31637c478bd9Sstevel@tonic-gate /* 31647c478bd9Sstevel@tonic-gate * Transmit completion reclaiming. 31657c478bd9Sstevel@tonic-gate */ 31667c478bd9Sstevel@tonic-gate static void 31677c478bd9Sstevel@tonic-gate hmereclaim(struct hme *hmep) 31687c478bd9Sstevel@tonic-gate { 31690219346bSGarrett D'Amore boolean_t reclaimed = B_FALSE; 31707c478bd9Sstevel@tonic-gate 31717c478bd9Sstevel@tonic-gate /* 31727c478bd9Sstevel@tonic-gate * Loop through each TMD. 31737c478bd9Sstevel@tonic-gate */ 31740219346bSGarrett D'Amore while (hmep->hme_txindex > hmep->hme_txreclaim) { 31750219346bSGarrett D'Amore 31760219346bSGarrett D'Amore int reclaim; 31770219346bSGarrett D'Amore uint32_t flags; 31780219346bSGarrett D'Amore 31790219346bSGarrett D'Amore reclaim = hmep->hme_txreclaim % HME_TMDMAX; 31800219346bSGarrett D'Amore HMESYNCTMD(reclaim, DDI_DMA_SYNC_FORKERNEL); 31810219346bSGarrett D'Amore 31820219346bSGarrett D'Amore flags = GET_TMD_FLAGS(reclaim); 31830219346bSGarrett D'Amore if (flags & HMETMD_OWN) { 31840219346bSGarrett D'Amore /* 31850219346bSGarrett D'Amore * Chip still owns it. We're done. 31860219346bSGarrett D'Amore */ 31870219346bSGarrett D'Amore break; 31880219346bSGarrett D'Amore } 31897c478bd9Sstevel@tonic-gate 31907c478bd9Sstevel@tonic-gate /* 31910219346bSGarrett D'Amore * Count a chained packet only once. 31927c478bd9Sstevel@tonic-gate */ 31930219346bSGarrett D'Amore if (flags & HMETMD_SOP) { 31947c478bd9Sstevel@tonic-gate hmep->hme_opackets++; 31957c478bd9Sstevel@tonic-gate } 31967c478bd9Sstevel@tonic-gate 31977c478bd9Sstevel@tonic-gate /* 31987c478bd9Sstevel@tonic-gate * MIB II 31997c478bd9Sstevel@tonic-gate */ 32000219346bSGarrett D'Amore hmep->hme_obytes += flags & HMETMD_BUFSIZE; 32017c478bd9Sstevel@tonic-gate 32020219346bSGarrett D'Amore reclaimed = B_TRUE; 32030219346bSGarrett D'Amore hmep->hme_txreclaim++; 32047c478bd9Sstevel@tonic-gate } 32057c478bd9Sstevel@tonic-gate 32060219346bSGarrett D'Amore if (reclaimed) { 32077c478bd9Sstevel@tonic-gate /* 32087c478bd9Sstevel@tonic-gate * we could reclaim some TMDs so turn off interrupts 32097c478bd9Sstevel@tonic-gate */ 32107c478bd9Sstevel@tonic-gate if (hmep->hme_wantw) { 32117c478bd9Sstevel@tonic-gate PUT_GLOBREG(intmask, 321285025c03Sgd HMEG_MASK_INTR | HMEG_MASK_TINT | 321385025c03Sgd HMEG_MASK_TX_ALL); 321485025c03Sgd hmep->hme_wantw = B_FALSE; 321585025c03Sgd mac_tx_update(hmep->hme_mh); 32167c478bd9Sstevel@tonic-gate } 32177c478bd9Sstevel@tonic-gate } else { 32187c478bd9Sstevel@tonic-gate /* 32197c478bd9Sstevel@tonic-gate * enable TINTS: so that even if there is no further activity 32207c478bd9Sstevel@tonic-gate * hmereclaim will get called 32217c478bd9Sstevel@tonic-gate */ 32227c478bd9Sstevel@tonic-gate if (hmep->hme_wantw) 322385025c03Sgd PUT_GLOBREG(intmask, 322485025c03Sgd GET_GLOBREG(intmask) & ~HMEG_MASK_TX_ALL); 32257c478bd9Sstevel@tonic-gate } 32267c478bd9Sstevel@tonic-gate CHECK_GLOBREG(); 32277c478bd9Sstevel@tonic-gate } 32287c478bd9Sstevel@tonic-gate 32297c478bd9Sstevel@tonic-gate /* 32307c478bd9Sstevel@tonic-gate * Handle interrupts for fatal errors 32317c478bd9Sstevel@tonic-gate * Need reinitialization of the ENET channel. 32327c478bd9Sstevel@tonic-gate */ 32337c478bd9Sstevel@tonic-gate static void 32347c478bd9Sstevel@tonic-gate hme_fatal_err(struct hme *hmep, uint_t hmesbits) 32357c478bd9Sstevel@tonic-gate { 32367c478bd9Sstevel@tonic-gate 32377c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_SLV_PAR_ERR) { 32387c478bd9Sstevel@tonic-gate hmep->hme_slvparerr++; 32397c478bd9Sstevel@tonic-gate } 32407c478bd9Sstevel@tonic-gate 32417c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_SLV_ERR_ACK) { 32427c478bd9Sstevel@tonic-gate hmep->hme_slverrack++; 32437c478bd9Sstevel@tonic-gate } 32447c478bd9Sstevel@tonic-gate 32457c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_TX_TAG_ERR) { 32467c478bd9Sstevel@tonic-gate hmep->hme_txtagerr++; 32477c478bd9Sstevel@tonic-gate hmep->hme_oerrors++; 32487c478bd9Sstevel@tonic-gate } 32497c478bd9Sstevel@tonic-gate 32507c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_TX_PAR_ERR) { 32517c478bd9Sstevel@tonic-gate hmep->hme_txparerr++; 32527c478bd9Sstevel@tonic-gate hmep->hme_oerrors++; 32537c478bd9Sstevel@tonic-gate } 32547c478bd9Sstevel@tonic-gate 32557c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_TX_LATE_ERR) { 32567c478bd9Sstevel@tonic-gate hmep->hme_txlaterr++; 32577c478bd9Sstevel@tonic-gate hmep->hme_oerrors++; 32587c478bd9Sstevel@tonic-gate } 32597c478bd9Sstevel@tonic-gate 32607c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_TX_ERR_ACK) { 32617c478bd9Sstevel@tonic-gate hmep->hme_txerrack++; 32627c478bd9Sstevel@tonic-gate hmep->hme_oerrors++; 32637c478bd9Sstevel@tonic-gate } 32647c478bd9Sstevel@tonic-gate 32657c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_EOP_ERR) { 32667c478bd9Sstevel@tonic-gate hmep->hme_eoperr++; 32677c478bd9Sstevel@tonic-gate } 32687c478bd9Sstevel@tonic-gate 32697c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_RX_TAG_ERR) { 32707c478bd9Sstevel@tonic-gate hmep->hme_rxtagerr++; 32717c478bd9Sstevel@tonic-gate hmep->hme_ierrors++; 32727c478bd9Sstevel@tonic-gate } 32737c478bd9Sstevel@tonic-gate 32747c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_RX_PAR_ERR) { 32757c478bd9Sstevel@tonic-gate hmep->hme_rxparerr++; 32767c478bd9Sstevel@tonic-gate hmep->hme_ierrors++; 32777c478bd9Sstevel@tonic-gate } 32787c478bd9Sstevel@tonic-gate 32797c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_RX_LATE_ERR) { 32807c478bd9Sstevel@tonic-gate hmep->hme_rxlaterr++; 32817c478bd9Sstevel@tonic-gate hmep->hme_ierrors++; 32827c478bd9Sstevel@tonic-gate } 32837c478bd9Sstevel@tonic-gate 32847c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_RX_ERR_ACK) { 32857c478bd9Sstevel@tonic-gate hmep->hme_rxerrack++; 32867c478bd9Sstevel@tonic-gate hmep->hme_ierrors++; 32877c478bd9Sstevel@tonic-gate } 32887c478bd9Sstevel@tonic-gate } 32897c478bd9Sstevel@tonic-gate 32907c478bd9Sstevel@tonic-gate /* 32917c478bd9Sstevel@tonic-gate * Handle interrupts regarding non-fatal errors. 32927c478bd9Sstevel@tonic-gate */ 32937c478bd9Sstevel@tonic-gate static void 32947c478bd9Sstevel@tonic-gate hme_nonfatal_err(struct hme *hmep, uint_t hmesbits) 32957c478bd9Sstevel@tonic-gate { 32967c478bd9Sstevel@tonic-gate 32977c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_RX_DROP) { 32987c478bd9Sstevel@tonic-gate hmep->hme_missed++; 32997c478bd9Sstevel@tonic-gate hmep->hme_ierrors++; 33007c478bd9Sstevel@tonic-gate } 33017c478bd9Sstevel@tonic-gate 33027c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_DEFTIMR_EXP) { 33037c478bd9Sstevel@tonic-gate hmep->hme_defer_xmts++; 33047c478bd9Sstevel@tonic-gate } 33057c478bd9Sstevel@tonic-gate 33067c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_FSTCOLC_EXP) { 33077c478bd9Sstevel@tonic-gate hmep->hme_fstcol += 256; 33087c478bd9Sstevel@tonic-gate } 33097c478bd9Sstevel@tonic-gate 33107c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_LATCOLC_EXP) { 33117c478bd9Sstevel@tonic-gate hmep->hme_tlcol += 256; 33127c478bd9Sstevel@tonic-gate hmep->hme_oerrors += 256; 33137c478bd9Sstevel@tonic-gate } 33147c478bd9Sstevel@tonic-gate 33157c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_EXCOLC_EXP) { 331685025c03Sgd hmep->hme_excol += 256; 33177c478bd9Sstevel@tonic-gate hmep->hme_oerrors += 256; 33187c478bd9Sstevel@tonic-gate } 33197c478bd9Sstevel@tonic-gate 33207c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_NRMCOLC_EXP) { 33217c478bd9Sstevel@tonic-gate hmep->hme_coll += 256; 33227c478bd9Sstevel@tonic-gate } 33237c478bd9Sstevel@tonic-gate 33247c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_MXPKTSZ_ERR) { 33257c478bd9Sstevel@tonic-gate hmep->hme_babl++; 33267c478bd9Sstevel@tonic-gate hmep->hme_oerrors++; 33277c478bd9Sstevel@tonic-gate } 33287c478bd9Sstevel@tonic-gate 33297c478bd9Sstevel@tonic-gate /* 33307c478bd9Sstevel@tonic-gate * This error is fatal and the board needs to 33317c478bd9Sstevel@tonic-gate * be reinitialized. Comments? 33327c478bd9Sstevel@tonic-gate */ 33337c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_TXFIFO_UNDR) { 33347c478bd9Sstevel@tonic-gate hmep->hme_uflo++; 33357c478bd9Sstevel@tonic-gate hmep->hme_oerrors++; 33367c478bd9Sstevel@tonic-gate } 33377c478bd9Sstevel@tonic-gate 33387c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_SQE_TST_ERR) { 33397c478bd9Sstevel@tonic-gate hmep->hme_sqe_errors++; 33407c478bd9Sstevel@tonic-gate } 33417c478bd9Sstevel@tonic-gate 33427c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_RCV_CNT_EXP) { 33437c478bd9Sstevel@tonic-gate if (hmep->hme_rxcv_enable) { 33447c478bd9Sstevel@tonic-gate hmep->hme_cvc += 256; 33457c478bd9Sstevel@tonic-gate } 33467c478bd9Sstevel@tonic-gate } 33477c478bd9Sstevel@tonic-gate 33487c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_RXFIFO_OVFL) { 33497c478bd9Sstevel@tonic-gate hmep->hme_oflo++; 33507c478bd9Sstevel@tonic-gate hmep->hme_ierrors++; 33517c478bd9Sstevel@tonic-gate } 33527c478bd9Sstevel@tonic-gate 33537c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_LEN_CNT_EXP) { 33547c478bd9Sstevel@tonic-gate hmep->hme_lenerr += 256; 33557c478bd9Sstevel@tonic-gate hmep->hme_ierrors += 256; 33567c478bd9Sstevel@tonic-gate } 33577c478bd9Sstevel@tonic-gate 33587c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_ALN_CNT_EXP) { 33597c478bd9Sstevel@tonic-gate hmep->hme_align_errors += 256; 33607c478bd9Sstevel@tonic-gate hmep->hme_ierrors += 256; 33617c478bd9Sstevel@tonic-gate } 33627c478bd9Sstevel@tonic-gate 33637c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_CRC_CNT_EXP) { 33647c478bd9Sstevel@tonic-gate hmep->hme_fcs_errors += 256; 33657c478bd9Sstevel@tonic-gate hmep->hme_ierrors += 256; 33667c478bd9Sstevel@tonic-gate } 33677c478bd9Sstevel@tonic-gate } 33687c478bd9Sstevel@tonic-gate 336985025c03Sgd static mblk_t * 33700219346bSGarrett D'Amore hmeread(struct hme *hmep, hmebuf_t *rbuf, uint32_t rflags) 33717c478bd9Sstevel@tonic-gate { 33720219346bSGarrett D'Amore mblk_t *bp; 33730219346bSGarrett D'Amore uint32_t len; 33740219346bSGarrett D'Amore t_uscalar_t type; 33750219346bSGarrett D'Amore 337685025c03Sgd len = (rflags & HMERMD_BUFSIZE) >> HMERMD_BUFSIZE_SHIFT; 33777c478bd9Sstevel@tonic-gate 33787c478bd9Sstevel@tonic-gate /* 33797c478bd9Sstevel@tonic-gate * Check for short packet 33807c478bd9Sstevel@tonic-gate * and check for overflow packet also. The processing is the 33817c478bd9Sstevel@tonic-gate * same for both the cases - reuse the buffer. Update the Buffer 33827c478bd9Sstevel@tonic-gate * overflow counter. 33837c478bd9Sstevel@tonic-gate */ 338485025c03Sgd if ((len < ETHERMIN) || (rflags & HMERMD_OVFLOW) || 338585025c03Sgd (len > (ETHERMAX + 4))) { 33867c478bd9Sstevel@tonic-gate if (len < ETHERMIN) 33877c478bd9Sstevel@tonic-gate hmep->hme_runt++; 33887c478bd9Sstevel@tonic-gate 33897c478bd9Sstevel@tonic-gate else { 33907c478bd9Sstevel@tonic-gate hmep->hme_buff++; 33917c478bd9Sstevel@tonic-gate hmep->hme_toolong_errors++; 33927c478bd9Sstevel@tonic-gate } 33937c478bd9Sstevel@tonic-gate hmep->hme_ierrors++; 339485025c03Sgd return (NULL); 33957c478bd9Sstevel@tonic-gate } 33967c478bd9Sstevel@tonic-gate 33977c478bd9Sstevel@tonic-gate /* 33987c478bd9Sstevel@tonic-gate * Sync the received buffer before looking at it. 33997c478bd9Sstevel@tonic-gate */ 34007c478bd9Sstevel@tonic-gate 34010219346bSGarrett D'Amore (void) ddi_dma_sync(rbuf->dmah, 0, 0, DDI_DMA_SYNC_FORKERNEL); 34027c478bd9Sstevel@tonic-gate 34037c478bd9Sstevel@tonic-gate /* 34047c478bd9Sstevel@tonic-gate * copy the packet data and then recycle the descriptor. 34057c478bd9Sstevel@tonic-gate */ 34067c478bd9Sstevel@tonic-gate 34070219346bSGarrett D'Amore if ((bp = allocb(len + HME_FSTBYTE_OFFSET, BPRI_HI)) == NULL) { 34087c478bd9Sstevel@tonic-gate 34097c478bd9Sstevel@tonic-gate hmep->hme_allocbfail++; 34107c478bd9Sstevel@tonic-gate hmep->hme_norcvbuf++; 341185025c03Sgd 341285025c03Sgd return (NULL); 34137c478bd9Sstevel@tonic-gate } 34147c478bd9Sstevel@tonic-gate 34150219346bSGarrett D'Amore bcopy(rbuf->kaddr, bp->b_rptr, len + HME_FSTBYTE_OFFSET); 34167c478bd9Sstevel@tonic-gate 34170219346bSGarrett D'Amore hmep->hme_ipackets++; 34187c478bd9Sstevel@tonic-gate 34190219346bSGarrett D'Amore /* Add the First Byte offset to the b_rptr and copy */ 34200219346bSGarrett D'Amore bp->b_rptr += HME_FSTBYTE_OFFSET; 34210219346bSGarrett D'Amore bp->b_wptr = bp->b_rptr + len; 34227c478bd9Sstevel@tonic-gate 34237c478bd9Sstevel@tonic-gate /* 34240219346bSGarrett D'Amore * update MIB II statistics 34257c478bd9Sstevel@tonic-gate */ 34260219346bSGarrett D'Amore BUMP_InNUcast(hmep, bp->b_rptr); 34270219346bSGarrett D'Amore hmep->hme_rbytes += len; 34287c478bd9Sstevel@tonic-gate 34290219346bSGarrett D'Amore type = get_ether_type(bp->b_rptr); 34307c478bd9Sstevel@tonic-gate 34317c478bd9Sstevel@tonic-gate /* 34320219346bSGarrett D'Amore * TCP partial checksum in hardware 34337c478bd9Sstevel@tonic-gate */ 34340219346bSGarrett D'Amore if (type == ETHERTYPE_IP || type == ETHERTYPE_IPV6) { 34350219346bSGarrett D'Amore uint16_t cksum = ~rflags & HMERMD_CKSUM; 34360219346bSGarrett D'Amore uint_t end = len - sizeof (struct ether_header); 34370219346bSGarrett D'Amore (void) hcksum_assoc(bp, NULL, NULL, 0, 34380219346bSGarrett D'Amore 0, end, htons(cksum), HCK_PARTIALCKSUM, 0); 34397c478bd9Sstevel@tonic-gate } 34407c478bd9Sstevel@tonic-gate 344185025c03Sgd return (bp); 34427c478bd9Sstevel@tonic-gate } 34437c478bd9Sstevel@tonic-gate 34447c478bd9Sstevel@tonic-gate /*VARARGS*/ 34457c478bd9Sstevel@tonic-gate static void 34460219346bSGarrett D'Amore hme_fault_msg(struct hme *hmep, uint_t severity, msg_t type, char *fmt, ...) 34477c478bd9Sstevel@tonic-gate { 34487c478bd9Sstevel@tonic-gate char msg_buffer[255]; 34497c478bd9Sstevel@tonic-gate va_list ap; 34507c478bd9Sstevel@tonic-gate 34517c478bd9Sstevel@tonic-gate va_start(ap, fmt); 3452228fdff0Sgd (void) vsnprintf(msg_buffer, sizeof (msg_buffer), fmt, ap); 34537c478bd9Sstevel@tonic-gate 345485025c03Sgd if (hmep == NULL) { 34557c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "hme : %s", msg_buffer); 34567c478bd9Sstevel@tonic-gate 345785025c03Sgd } else if (type == DISPLAY_MSG) { 345885025c03Sgd cmn_err(CE_CONT, "?%s%d : %s\n", ddi_driver_name(hmep->dip), 345985025c03Sgd hmep->instance, msg_buffer); 346085025c03Sgd } else if (severity == SEVERITY_HIGH) { 346185025c03Sgd cmn_err(CE_WARN, "%s%d : %s, SEVERITY_HIGH, %s\n", 346285025c03Sgd ddi_driver_name(hmep->dip), hmep->instance, 346385025c03Sgd msg_buffer, msg_string[type]); 346485025c03Sgd } else { 346585025c03Sgd cmn_err(CE_CONT, "%s%d : %s\n", ddi_driver_name(hmep->dip), 346685025c03Sgd hmep->instance, msg_buffer); 346785025c03Sgd } 34687c478bd9Sstevel@tonic-gate va_end(ap); 34697c478bd9Sstevel@tonic-gate } 34707c478bd9Sstevel@tonic-gate 34717c478bd9Sstevel@tonic-gate /* 34727c478bd9Sstevel@tonic-gate * if this is the first init do not bother to save the 34737c478bd9Sstevel@tonic-gate * counters. They should be 0, but do not count on it. 34747c478bd9Sstevel@tonic-gate */ 34757c478bd9Sstevel@tonic-gate static void 34767c478bd9Sstevel@tonic-gate hmesavecntrs(struct hme *hmep) 34777c478bd9Sstevel@tonic-gate { 34787c478bd9Sstevel@tonic-gate uint32_t fecnt, aecnt, lecnt, rxcv; 34797c478bd9Sstevel@tonic-gate uint32_t ltcnt, excnt; 34807c478bd9Sstevel@tonic-gate 34817c478bd9Sstevel@tonic-gate /* XXX What all gets added in ierrors and oerrors? */ 34827c478bd9Sstevel@tonic-gate fecnt = GET_MACREG(fecnt); 34837c478bd9Sstevel@tonic-gate PUT_MACREG(fecnt, 0); 34847c478bd9Sstevel@tonic-gate 34857c478bd9Sstevel@tonic-gate aecnt = GET_MACREG(aecnt); 34867c478bd9Sstevel@tonic-gate hmep->hme_align_errors += aecnt; 34877c478bd9Sstevel@tonic-gate PUT_MACREG(aecnt, 0); 34887c478bd9Sstevel@tonic-gate 34897c478bd9Sstevel@tonic-gate lecnt = GET_MACREG(lecnt); 34907c478bd9Sstevel@tonic-gate hmep->hme_lenerr += lecnt; 34917c478bd9Sstevel@tonic-gate PUT_MACREG(lecnt, 0); 34927c478bd9Sstevel@tonic-gate 34937c478bd9Sstevel@tonic-gate rxcv = GET_MACREG(rxcv); 34947c478bd9Sstevel@tonic-gate #ifdef HME_CODEVIOL_BUG 34957c478bd9Sstevel@tonic-gate /* 34967c478bd9Sstevel@tonic-gate * Ignore rxcv errors for Sbus/FEPS 2.1 or earlier 34977c478bd9Sstevel@tonic-gate */ 34987c478bd9Sstevel@tonic-gate if (!hmep->hme_rxcv_enable) { 34997c478bd9Sstevel@tonic-gate rxcv = 0; 35007c478bd9Sstevel@tonic-gate } 35017c478bd9Sstevel@tonic-gate #endif 35027c478bd9Sstevel@tonic-gate hmep->hme_cvc += rxcv; 35037c478bd9Sstevel@tonic-gate PUT_MACREG(rxcv, 0); 35047c478bd9Sstevel@tonic-gate 35057c478bd9Sstevel@tonic-gate ltcnt = GET_MACREG(ltcnt); 35067c478bd9Sstevel@tonic-gate hmep->hme_tlcol += ltcnt; 35077c478bd9Sstevel@tonic-gate PUT_MACREG(ltcnt, 0); 35087c478bd9Sstevel@tonic-gate 35097c478bd9Sstevel@tonic-gate excnt = GET_MACREG(excnt); 351085025c03Sgd hmep->hme_excol += excnt; 35117c478bd9Sstevel@tonic-gate PUT_MACREG(excnt, 0); 35127c478bd9Sstevel@tonic-gate 35137c478bd9Sstevel@tonic-gate hmep->hme_fcs_errors += fecnt; 35147c478bd9Sstevel@tonic-gate hmep->hme_ierrors += (fecnt + aecnt + lecnt); 35157c478bd9Sstevel@tonic-gate hmep->hme_oerrors += (ltcnt + excnt); 35167c478bd9Sstevel@tonic-gate hmep->hme_coll += (GET_MACREG(nccnt) + ltcnt); 35177c478bd9Sstevel@tonic-gate 35187c478bd9Sstevel@tonic-gate PUT_MACREG(nccnt, 0); 35197c478bd9Sstevel@tonic-gate CHECK_MACREG(); 35207c478bd9Sstevel@tonic-gate } 35217c478bd9Sstevel@tonic-gate 35227c478bd9Sstevel@tonic-gate /* 35237c478bd9Sstevel@tonic-gate * To set up the mac address for the network interface: 35247c478bd9Sstevel@tonic-gate * The adapter card may support a local mac address which is published 35257c478bd9Sstevel@tonic-gate * in a device node property "local-mac-address". This mac address is 35267c478bd9Sstevel@tonic-gate * treated as the factory-installed mac address for DLPI interface. 35277c478bd9Sstevel@tonic-gate * If the adapter firmware has used the device for diskless boot 35287c478bd9Sstevel@tonic-gate * operation it publishes a property called "mac-address" for use by 35297c478bd9Sstevel@tonic-gate * inetboot and the device driver. 35307c478bd9Sstevel@tonic-gate * If "mac-address" is not found, the system options property 35317c478bd9Sstevel@tonic-gate * "local-mac-address" is used to select the mac-address. If this option 35327c478bd9Sstevel@tonic-gate * is set to "true", and "local-mac-address" has been found, then 35337c478bd9Sstevel@tonic-gate * local-mac-address is used; otherwise the system mac address is used 35347c478bd9Sstevel@tonic-gate * by calling the "localetheraddr()" function. 35357c478bd9Sstevel@tonic-gate */ 35367c478bd9Sstevel@tonic-gate static void 35377c478bd9Sstevel@tonic-gate hme_setup_mac_address(struct hme *hmep, dev_info_t *dip) 35387c478bd9Sstevel@tonic-gate { 35397c478bd9Sstevel@tonic-gate char *prop; 35407c478bd9Sstevel@tonic-gate int prop_len = sizeof (int); 35417c478bd9Sstevel@tonic-gate 35427c478bd9Sstevel@tonic-gate hmep->hme_addrflags = 0; 35437c478bd9Sstevel@tonic-gate 35447c478bd9Sstevel@tonic-gate /* 35457c478bd9Sstevel@tonic-gate * Check if it is an adapter with its own local mac address 35467c478bd9Sstevel@tonic-gate * If it is present, save it as the "factory-address" 35477c478bd9Sstevel@tonic-gate * for this adapter. 35487c478bd9Sstevel@tonic-gate */ 354985025c03Sgd if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 355085025c03Sgd "local-mac-address", 355185025c03Sgd (caddr_t)&prop, &prop_len) == DDI_PROP_SUCCESS) { 35527c478bd9Sstevel@tonic-gate if (prop_len == ETHERADDRL) { 35537c478bd9Sstevel@tonic-gate hmep->hme_addrflags = HME_FACTADDR_PRESENT; 35547c478bd9Sstevel@tonic-gate ether_bcopy(prop, &hmep->hme_factaddr); 35557c478bd9Sstevel@tonic-gate HME_FAULT_MSG2(hmep, SEVERITY_NONE, DISPLAY_MSG, 35560219346bSGarrett D'Amore "Local Ethernet address = %s", 355785025c03Sgd ether_sprintf(&hmep->hme_factaddr)); 35587c478bd9Sstevel@tonic-gate } 35597c478bd9Sstevel@tonic-gate kmem_free(prop, prop_len); 35607c478bd9Sstevel@tonic-gate } 35617c478bd9Sstevel@tonic-gate 35627c478bd9Sstevel@tonic-gate /* 35637c478bd9Sstevel@tonic-gate * Check if the adapter has published "mac-address" property. 35647c478bd9Sstevel@tonic-gate * If it is present, use it as the mac address for this device. 35657c478bd9Sstevel@tonic-gate */ 356685025c03Sgd if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 356785025c03Sgd "mac-address", (caddr_t)&prop, &prop_len) == DDI_PROP_SUCCESS) { 35687c478bd9Sstevel@tonic-gate if (prop_len >= ETHERADDRL) { 35697c478bd9Sstevel@tonic-gate ether_bcopy(prop, &hmep->hme_ouraddr); 35707c478bd9Sstevel@tonic-gate kmem_free(prop, prop_len); 35717c478bd9Sstevel@tonic-gate return; 35727c478bd9Sstevel@tonic-gate } 35737c478bd9Sstevel@tonic-gate kmem_free(prop, prop_len); 35747c478bd9Sstevel@tonic-gate } 35757c478bd9Sstevel@tonic-gate 35760219346bSGarrett D'Amore #ifdef __sparc 35770219346bSGarrett D'Amore /* 35780219346bSGarrett D'Amore * On sparc, we might be able to use the mac address from the 35790219346bSGarrett D'Amore * system. However, on all other systems, we need to use the 35800219346bSGarrett D'Amore * address from the PROM. 35810219346bSGarrett D'Amore */ 35827c478bd9Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 0, "local-mac-address?", 358385025c03Sgd (caddr_t)&prop, &prop_len) == DDI_PROP_SUCCESS) { 35847c478bd9Sstevel@tonic-gate if ((strncmp("true", prop, prop_len) == 0) && 358585025c03Sgd (hmep->hme_addrflags & HME_FACTADDR_PRESENT)) { 35867c478bd9Sstevel@tonic-gate hmep->hme_addrflags |= HME_FACTADDR_USE; 35877c478bd9Sstevel@tonic-gate ether_bcopy(&hmep->hme_factaddr, &hmep->hme_ouraddr); 35887c478bd9Sstevel@tonic-gate kmem_free(prop, prop_len); 35897c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_NONE, DISPLAY_MSG, 35900219346bSGarrett D'Amore "Using local MAC address"); 35917c478bd9Sstevel@tonic-gate return; 35927c478bd9Sstevel@tonic-gate } 35937c478bd9Sstevel@tonic-gate kmem_free(prop, prop_len); 35947c478bd9Sstevel@tonic-gate } 35957c478bd9Sstevel@tonic-gate 35967c478bd9Sstevel@tonic-gate /* 35977c478bd9Sstevel@tonic-gate * Get the system ethernet address. 35987c478bd9Sstevel@tonic-gate */ 35997c478bd9Sstevel@tonic-gate (void) localetheraddr((struct ether_addr *)NULL, &hmep->hme_ouraddr); 36000219346bSGarrett D'Amore #else 36010219346bSGarrett D'Amore ether_bcopy(&hmep->hme_factaddr, &hmep->hme_ouraddr); 36020219346bSGarrett D'Amore #endif 36037c478bd9Sstevel@tonic-gate } 36047c478bd9Sstevel@tonic-gate 36057c478bd9Sstevel@tonic-gate /* ARGSUSED */ 36067c478bd9Sstevel@tonic-gate static void 36077c478bd9Sstevel@tonic-gate hme_check_acc_handle(char *file, uint_t line, struct hme *hmep, 36087c478bd9Sstevel@tonic-gate ddi_acc_handle_t handle) 36097c478bd9Sstevel@tonic-gate { 36107c478bd9Sstevel@tonic-gate } 3611