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