17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5447e4a63Spetede * Common Development and Distribution License (the "License"). 6447e4a63Spetede * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*0219346bSGarrett D'Amore * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate /* 287c478bd9Sstevel@tonic-gate * SunOS MT STREAMS FEPS(SBus)/Cheerio(PCI) 10/100Mb Ethernet Device Driver 297c478bd9Sstevel@tonic-gate */ 307c478bd9Sstevel@tonic-gate 317c478bd9Sstevel@tonic-gate #include <sys/types.h> 327c478bd9Sstevel@tonic-gate #include <sys/debug.h> 337c478bd9Sstevel@tonic-gate #include <sys/stream.h> 347c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 357c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 367c478bd9Sstevel@tonic-gate #include <sys/crc32.h> 3785025c03Sgd #include <sys/modctl.h> 3885025c03Sgd #include <sys/conf.h> 397c478bd9Sstevel@tonic-gate #include <sys/strsun.h> 407c478bd9Sstevel@tonic-gate #include <sys/kstat.h> 417c478bd9Sstevel@tonic-gate #include <inet/common.h> 427c478bd9Sstevel@tonic-gate #include <inet/mi.h> 437c478bd9Sstevel@tonic-gate #include <inet/nd.h> 4485025c03Sgd #include <sys/pattr.h> 457c478bd9Sstevel@tonic-gate #include <sys/dlpi.h> 4685025c03Sgd #include <sys/strsubr.h> 47da14cebeSEric Cheng #include <sys/mac_provider.h> 4885025c03Sgd #include <sys/mac_ether.h> 497c478bd9Sstevel@tonic-gate #include <sys/ethernet.h> 50d62bc4baSyz #include <sys/vlan.h> 5185025c03Sgd #include <sys/pci.h> 5285025c03Sgd #include <sys/policy.h> 5385025c03Sgd #include <sys/ddi.h> 5485025c03Sgd #include <sys/sunddi.h> 55*0219346bSGarrett D'Amore #include "hme_phy.h" 56*0219346bSGarrett D'Amore #include "hme_mac.h" 57*0219346bSGarrett D'Amore #include "hme.h" 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate typedef void (*fptrv_t)(); 607c478bd9Sstevel@tonic-gate 617c478bd9Sstevel@tonic-gate typedef enum { 627c478bd9Sstevel@tonic-gate NO_MSG = 0, 637c478bd9Sstevel@tonic-gate AUTOCONFIG_MSG = 1, 647c478bd9Sstevel@tonic-gate STREAMS_MSG = 2, 657c478bd9Sstevel@tonic-gate IOCTL_MSG = 3, 667c478bd9Sstevel@tonic-gate PROTO_MSG = 4, 677c478bd9Sstevel@tonic-gate INIT_MSG = 5, 687c478bd9Sstevel@tonic-gate TX_MSG = 6, 697c478bd9Sstevel@tonic-gate RX_MSG = 7, 707c478bd9Sstevel@tonic-gate INTR_MSG = 8, 717c478bd9Sstevel@tonic-gate UNINIT_MSG = 9, 727c478bd9Sstevel@tonic-gate CONFIG_MSG = 10, 737c478bd9Sstevel@tonic-gate PROP_MSG = 11, 747c478bd9Sstevel@tonic-gate ENTER_MSG = 12, 757c478bd9Sstevel@tonic-gate RESUME_MSG = 13, 767c478bd9Sstevel@tonic-gate AUTONEG_MSG = 14, 777c478bd9Sstevel@tonic-gate NAUTONEG_MSG = 15, 787c478bd9Sstevel@tonic-gate FATAL_ERR_MSG = 16, 797c478bd9Sstevel@tonic-gate NFATAL_ERR_MSG = 17, 807c478bd9Sstevel@tonic-gate NDD_MSG = 18, 817c478bd9Sstevel@tonic-gate PHY_MSG = 19, 827c478bd9Sstevel@tonic-gate XCVR_MSG = 20, 837c478bd9Sstevel@tonic-gate NOXCVR_MSG = 21, 847c478bd9Sstevel@tonic-gate NSUPPORT_MSG = 22, 857c478bd9Sstevel@tonic-gate ERX_MSG = 23, 867c478bd9Sstevel@tonic-gate FREE_MSG = 24, 877c478bd9Sstevel@tonic-gate IPG_MSG = 25, 887c478bd9Sstevel@tonic-gate DDI_MSG = 26, 897c478bd9Sstevel@tonic-gate DEFAULT_MSG = 27, 907c478bd9Sstevel@tonic-gate DISPLAY_MSG = 28, 917c478bd9Sstevel@tonic-gate LATECOLL_MSG = 29, 927c478bd9Sstevel@tonic-gate MIFPOLL_MSG = 30, 9385025c03Sgd LINKPULSE_MSG = 31 947c478bd9Sstevel@tonic-gate } msg_t; 957c478bd9Sstevel@tonic-gate 967c478bd9Sstevel@tonic-gate msg_t hme_debug_level = NO_MSG; 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate static char *msg_string[] = { 997c478bd9Sstevel@tonic-gate "NONE ", 1007c478bd9Sstevel@tonic-gate "AUTOCONFIG ", 1017c478bd9Sstevel@tonic-gate "STREAMS ", 1027c478bd9Sstevel@tonic-gate "IOCTL ", 1037c478bd9Sstevel@tonic-gate "PROTO ", 1047c478bd9Sstevel@tonic-gate "INIT ", 1057c478bd9Sstevel@tonic-gate "TX ", 1067c478bd9Sstevel@tonic-gate "RX ", 1077c478bd9Sstevel@tonic-gate "INTR ", 1087c478bd9Sstevel@tonic-gate "UNINIT ", 1097c478bd9Sstevel@tonic-gate "CONFIG ", 1107c478bd9Sstevel@tonic-gate "PROP ", 1117c478bd9Sstevel@tonic-gate "ENTER ", 1127c478bd9Sstevel@tonic-gate "RESUME ", 1137c478bd9Sstevel@tonic-gate "AUTONEG ", 1147c478bd9Sstevel@tonic-gate "NAUTONEG ", 1157c478bd9Sstevel@tonic-gate "FATAL_ERR ", 1167c478bd9Sstevel@tonic-gate "NFATAL_ERR ", 1177c478bd9Sstevel@tonic-gate "NDD ", 1187c478bd9Sstevel@tonic-gate "PHY ", 1197c478bd9Sstevel@tonic-gate "XCVR ", 1207c478bd9Sstevel@tonic-gate "NOXCVR ", 1217c478bd9Sstevel@tonic-gate "NSUPPOR ", 1227c478bd9Sstevel@tonic-gate "ERX ", 1237c478bd9Sstevel@tonic-gate "FREE ", 1247c478bd9Sstevel@tonic-gate "IPG ", 1257c478bd9Sstevel@tonic-gate "DDI ", 1267c478bd9Sstevel@tonic-gate "DEFAULT ", 1277c478bd9Sstevel@tonic-gate "DISPLAY " 1287c478bd9Sstevel@tonic-gate "LATECOLL_MSG ", 1297c478bd9Sstevel@tonic-gate "MIFPOLL_MSG ", 13085025c03Sgd "LINKPULSE_MSG " 1317c478bd9Sstevel@tonic-gate }; 1327c478bd9Sstevel@tonic-gate 1337c478bd9Sstevel@tonic-gate #define SEVERITY_NONE 0 1347c478bd9Sstevel@tonic-gate #define SEVERITY_LOW 0 1357c478bd9Sstevel@tonic-gate #define SEVERITY_MID 1 1367c478bd9Sstevel@tonic-gate #define SEVERITY_HIGH 2 1377c478bd9Sstevel@tonic-gate #define SEVERITY_UNKNOWN 99 1387c478bd9Sstevel@tonic-gate 1397c478bd9Sstevel@tonic-gate #define FEPS_URUN_BUG 1407c478bd9Sstevel@tonic-gate #define HME_CODEVIOL_BUG 1417c478bd9Sstevel@tonic-gate 1427c478bd9Sstevel@tonic-gate #define KIOIP KSTAT_INTR_PTR(hmep->hme_intrstats) 1437c478bd9Sstevel@tonic-gate 1447c478bd9Sstevel@tonic-gate /* 1457c478bd9Sstevel@tonic-gate * The following variables are used for checking fixes in Sbus/FEPS 2.0 1467c478bd9Sstevel@tonic-gate */ 1477c478bd9Sstevel@tonic-gate static int hme_urun_fix = 0; /* Bug fixed in Sbus/FEPS 2.0 */ 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate /* 1507c478bd9Sstevel@tonic-gate * The following variables are used for configuring various features 1517c478bd9Sstevel@tonic-gate */ 1527c478bd9Sstevel@tonic-gate static int hme_64bit_enable = 1; /* Use 64-bit sbus transfers */ 1537c478bd9Sstevel@tonic-gate static int hme_reject_own = 1; /* Reject packets with own SA */ 1547c478bd9Sstevel@tonic-gate static int hme_autoneg_enable = 1; /* Enable auto-negotiation */ 1557c478bd9Sstevel@tonic-gate 1567c478bd9Sstevel@tonic-gate static int hme_ngu_enable = 1; /* to enable Never Give Up mode */ 1577c478bd9Sstevel@tonic-gate static int hme_mifpoll_enable = 1; /* to enable mif poll */ 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate /* 1607c478bd9Sstevel@tonic-gate * The following variables are used for configuring link-operation. 1617c478bd9Sstevel@tonic-gate * Later these parameters may be changed per interface using "ndd" command 1627c478bd9Sstevel@tonic-gate * These parameters may also be specified as properties using the .conf 1637c478bd9Sstevel@tonic-gate * file mechanism for each interface. 1647c478bd9Sstevel@tonic-gate */ 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate static int hme_lance_mode = 1; /* to enable lance mode */ 1677c478bd9Sstevel@tonic-gate static int hme_ipg0 = 16; 1687c478bd9Sstevel@tonic-gate static int hme_ipg1 = 8; 1697c478bd9Sstevel@tonic-gate static int hme_ipg2 = 4; 1707c478bd9Sstevel@tonic-gate static int hme_use_int_xcvr = 0; 1717c478bd9Sstevel@tonic-gate static int hme_pace_size = 0; /* Do not use pacing */ 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate /* 1747c478bd9Sstevel@tonic-gate * The following variable value will be overridden by "link-pulse-disabled" 1757c478bd9Sstevel@tonic-gate * property which may be created by OBP or hme.conf file. 1767c478bd9Sstevel@tonic-gate */ 1777c478bd9Sstevel@tonic-gate static int hme_link_pulse_disabled = 0; /* link pulse disabled */ 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate /* 1807c478bd9Sstevel@tonic-gate * The following parameters may be configured by the user. If they are not 1817c478bd9Sstevel@tonic-gate * configured by the user, the values will be based on the capabilities of 1827c478bd9Sstevel@tonic-gate * the transceiver. 1837c478bd9Sstevel@tonic-gate * The value "HME_NOTUSR" is ORed with the parameter value to indicate values 1847c478bd9Sstevel@tonic-gate * which are NOT configured by the user. 1857c478bd9Sstevel@tonic-gate */ 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate #define HME_NOTUSR 0x0f000000 1887c478bd9Sstevel@tonic-gate #define HME_MASK_1BIT 0x1 1897c478bd9Sstevel@tonic-gate #define HME_MASK_5BIT 0x1f 1907c478bd9Sstevel@tonic-gate #define HME_MASK_8BIT 0xff 1917c478bd9Sstevel@tonic-gate 1927c478bd9Sstevel@tonic-gate static int hme_adv_autoneg_cap = HME_NOTUSR | 0; 1937c478bd9Sstevel@tonic-gate static int hme_adv_100T4_cap = HME_NOTUSR | 0; 1947c478bd9Sstevel@tonic-gate static int hme_adv_100fdx_cap = HME_NOTUSR | 0; 1957c478bd9Sstevel@tonic-gate static int hme_adv_100hdx_cap = HME_NOTUSR | 0; 1967c478bd9Sstevel@tonic-gate static int hme_adv_10fdx_cap = HME_NOTUSR | 0; 1977c478bd9Sstevel@tonic-gate static int hme_adv_10hdx_cap = HME_NOTUSR | 0; 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate /* 2007c478bd9Sstevel@tonic-gate * PHY_IDR1 and PHY_IDR2 values to identify National Semiconductor's DP83840 2017c478bd9Sstevel@tonic-gate * Rev C chip which needs some work-arounds. 2027c478bd9Sstevel@tonic-gate */ 2037c478bd9Sstevel@tonic-gate #define HME_NSIDR1 0x2000 2047c478bd9Sstevel@tonic-gate #define HME_NSIDR2 0x5c00 /* IDR2 register for with revision no. 0 */ 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate /* 2077c478bd9Sstevel@tonic-gate * PHY_IDR1 and PHY_IDR2 values to identify Quality Semiconductor's QS6612 2087c478bd9Sstevel@tonic-gate * chip which needs some work-arounds. 2097c478bd9Sstevel@tonic-gate * Addition Interface Technologies Group (NPG) 8/28/1997. 2107c478bd9Sstevel@tonic-gate */ 2117c478bd9Sstevel@tonic-gate #define HME_QSIDR1 0x0181 2127c478bd9Sstevel@tonic-gate #define HME_QSIDR2 0x4400 /* IDR2 register for with revision no. 0 */ 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate /* 2157c478bd9Sstevel@tonic-gate * The least significant 4 bits of HME_NSIDR2 represent the revision 2167c478bd9Sstevel@tonic-gate * no. of the DP83840 chip. For Rev-C of DP83840, the rev. no. is 0. 2177c478bd9Sstevel@tonic-gate * The next revision of the chip is called DP83840A and the value of 2187c478bd9Sstevel@tonic-gate * HME_NSIDR2 is 0x5c01 for this new chip. All the workarounds specific 2197c478bd9Sstevel@tonic-gate * to DP83840 chip are valid for both the revisions of the chip. 2207c478bd9Sstevel@tonic-gate * Assuming that these workarounds are valid for the future revisions 2217c478bd9Sstevel@tonic-gate * also, we will apply these workarounds independent of the revision no. 2227c478bd9Sstevel@tonic-gate * Hence we mask out the last 4 bits of the IDR2 register and compare 2237c478bd9Sstevel@tonic-gate * with 0x5c00 value. 2247c478bd9Sstevel@tonic-gate */ 2257c478bd9Sstevel@tonic-gate 2267c478bd9Sstevel@tonic-gate #define HME_DP83840 ((hmep->hme_idr1 == HME_NSIDR1) && \ 2277c478bd9Sstevel@tonic-gate ((hmep->hme_idr2 & 0xfff0) == HME_NSIDR2)) 2287c478bd9Sstevel@tonic-gate /* 2297c478bd9Sstevel@tonic-gate * Likewise for the QSI 6612 Fast ethernet phy. 2307c478bd9Sstevel@tonic-gate * Addition Interface Technologies Group (NPG) 8/28/1997. 2317c478bd9Sstevel@tonic-gate */ 2327c478bd9Sstevel@tonic-gate #define HME_QS6612 ((hmep->hme_idr1 == HME_QSIDR1) && \ 2337c478bd9Sstevel@tonic-gate ((hmep->hme_idr2 & 0xfff0) == HME_QSIDR2)) 2347c478bd9Sstevel@tonic-gate /* 2357c478bd9Sstevel@tonic-gate * All strings used by hme messaging functions 2367c478bd9Sstevel@tonic-gate */ 2377c478bd9Sstevel@tonic-gate 2387c478bd9Sstevel@tonic-gate static char *par_detect_msg = 2397c478bd9Sstevel@tonic-gate "Parallel detection fault."; 2407c478bd9Sstevel@tonic-gate 2417c478bd9Sstevel@tonic-gate static char *xcvr_no_mii_msg = 2427c478bd9Sstevel@tonic-gate "Transceiver does not talk MII."; 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate static char *xcvr_isolate_msg = 2457c478bd9Sstevel@tonic-gate "Transceiver isolate failed."; 2467c478bd9Sstevel@tonic-gate 2477c478bd9Sstevel@tonic-gate static char *int_xcvr_msg = 2487c478bd9Sstevel@tonic-gate "Internal Transceiver Selected."; 2497c478bd9Sstevel@tonic-gate 2507c478bd9Sstevel@tonic-gate static char *ext_xcvr_msg = 2517c478bd9Sstevel@tonic-gate "External Transceiver Selected."; 2527c478bd9Sstevel@tonic-gate 2537c478bd9Sstevel@tonic-gate static char *no_xcvr_msg = 2547c478bd9Sstevel@tonic-gate "No transceiver found."; 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate static char *burst_size_msg = 2577c478bd9Sstevel@tonic-gate "Could not identify the burst size"; 2587c478bd9Sstevel@tonic-gate 2597c478bd9Sstevel@tonic-gate static char *unk_rx_ringsz_msg = 2607c478bd9Sstevel@tonic-gate "Unknown receive RINGSZ"; 2617c478bd9Sstevel@tonic-gate 2627c478bd9Sstevel@tonic-gate static char *add_intr_fail_msg = 2637c478bd9Sstevel@tonic-gate "ddi_add_intr(9F) failed"; 2647c478bd9Sstevel@tonic-gate 2657c478bd9Sstevel@tonic-gate static char *mregs_4global_reg_fail_msg = 2667c478bd9Sstevel@tonic-gate "ddi_regs_map_setup(9F) for global reg failed"; 2677c478bd9Sstevel@tonic-gate 2687c478bd9Sstevel@tonic-gate static char *mregs_4etx_reg_fail_msg = 2697c478bd9Sstevel@tonic-gate "ddi_map_regs for etx reg failed"; 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate static char *mregs_4erx_reg_fail_msg = 2727c478bd9Sstevel@tonic-gate "ddi_map_regs for erx reg failed"; 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate static char *mregs_4bmac_reg_fail_msg = 2757c478bd9Sstevel@tonic-gate "ddi_map_regs for bmac reg failed"; 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate static char *mregs_4mif_reg_fail_msg = 2787c478bd9Sstevel@tonic-gate "ddi_map_regs for mif reg failed"; 2797c478bd9Sstevel@tonic-gate 2807c478bd9Sstevel@tonic-gate static char *param_reg_fail_msg = 2817c478bd9Sstevel@tonic-gate "parameter register error"; 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate static char *init_fail_gen_msg = 2847c478bd9Sstevel@tonic-gate "Failed to initialize hardware/driver"; 2857c478bd9Sstevel@tonic-gate 2867c478bd9Sstevel@tonic-gate static char *ddi_nregs_fail_msg = 2877c478bd9Sstevel@tonic-gate "ddi_dev_nregs failed(9F), returned %d"; 2887c478bd9Sstevel@tonic-gate 2897c478bd9Sstevel@tonic-gate static char *bad_num_regs_msg = 2907c478bd9Sstevel@tonic-gate "Invalid number of registers."; 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate static char *anar_not_set_msg = 2937c478bd9Sstevel@tonic-gate "External Transceiver: anar not set with speed selection"; 2947c478bd9Sstevel@tonic-gate 2957c478bd9Sstevel@tonic-gate static char *par_detect_anar_not_set_msg = 2967c478bd9Sstevel@tonic-gate "External Transceiver: anar not set with speed selection"; 2977c478bd9Sstevel@tonic-gate 2987c478bd9Sstevel@tonic-gate 2997c478bd9Sstevel@tonic-gate /* FATAL ERR msgs */ 3007c478bd9Sstevel@tonic-gate /* 3017c478bd9Sstevel@tonic-gate * Function prototypes. 3027c478bd9Sstevel@tonic-gate */ 303f2cd0f02Sgd /* these two are global so that qfe can use them */ 304f2cd0f02Sgd int hmeattach(dev_info_t *, ddi_attach_cmd_t); 305f2cd0f02Sgd int hmedetach(dev_info_t *, ddi_detach_cmd_t); 306*0219346bSGarrett D'Amore int hmequiesce(dev_info_t *); 30785025c03Sgd static boolean_t hmeinit_xfer_params(struct hme *); 3087c478bd9Sstevel@tonic-gate static uint_t hmestop(struct hme *); 3097c478bd9Sstevel@tonic-gate static void hmestatinit(struct hme *); 3107c478bd9Sstevel@tonic-gate static int hmeallocthings(struct hme *); 311*0219346bSGarrett D'Amore static void hmefreethings(struct hme *); 312*0219346bSGarrett D'Amore static int hmeallocbuf(struct hme *, hmebuf_t *, int); 313*0219346bSGarrett D'Amore static int hmeallocbufs(struct hme *); 3147c478bd9Sstevel@tonic-gate static void hmefreebufs(struct hme *); 3157c478bd9Sstevel@tonic-gate static void hmeget_hm_rev_property(struct hme *); 31685025c03Sgd static boolean_t hmestart(struct hme *, mblk_t *); 31785025c03Sgd static uint_t hmeintr(caddr_t); 3187c478bd9Sstevel@tonic-gate static void hmereclaim(struct hme *); 3197c478bd9Sstevel@tonic-gate static int hmeinit(struct hme *); 3207c478bd9Sstevel@tonic-gate static void hmeuninit(struct hme *hmep); 321*0219346bSGarrett D'Amore static mblk_t *hmeread(struct hme *, hmebuf_t *, uint32_t); 3227c478bd9Sstevel@tonic-gate static void hmesavecntrs(struct hme *); 3237c478bd9Sstevel@tonic-gate static void hme_fatal_err(struct hme *, uint_t); 3247c478bd9Sstevel@tonic-gate static void hme_nonfatal_err(struct hme *, uint_t); 3257c478bd9Sstevel@tonic-gate static int hmeburstsizes(struct hme *); 3267c478bd9Sstevel@tonic-gate static void hme_start_mifpoll(struct hme *); 3277c478bd9Sstevel@tonic-gate static void hme_stop_mifpoll(struct hme *); 3287c478bd9Sstevel@tonic-gate static void hme_param_cleanup(struct hme *); 3297c478bd9Sstevel@tonic-gate static int hme_param_get(queue_t *q, mblk_t *mp, caddr_t cp); 3307c478bd9Sstevel@tonic-gate static int hme_param_register(struct hme *, hmeparam_t *, int); 3317c478bd9Sstevel@tonic-gate static int hme_param_set(queue_t *, mblk_t *, char *, caddr_t); 3327c478bd9Sstevel@tonic-gate static void send_bit(struct hme *, uint_t); 3337c478bd9Sstevel@tonic-gate static uint_t get_bit(struct hme *); 3347c478bd9Sstevel@tonic-gate static uint_t get_bit_std(struct hme *); 3357c478bd9Sstevel@tonic-gate static uint_t hme_bb_mii_read(struct hme *, uchar_t, uint16_t *); 3367c478bd9Sstevel@tonic-gate static void hme_bb_mii_write(struct hme *, uchar_t, uint16_t); 3377c478bd9Sstevel@tonic-gate static void hme_bb_force_idle(struct hme *); 3387c478bd9Sstevel@tonic-gate static uint_t hme_mii_read(struct hme *, uchar_t, uint16_t *); 3397c478bd9Sstevel@tonic-gate static void hme_mii_write(struct hme *, uchar_t, uint16_t); 3407c478bd9Sstevel@tonic-gate static void hme_stop_timer(struct hme *); 3417c478bd9Sstevel@tonic-gate static void hme_start_timer(struct hme *, fptrv_t, int); 3427c478bd9Sstevel@tonic-gate static int hme_select_speed(struct hme *, int); 3437c478bd9Sstevel@tonic-gate static void hme_reset_transceiver(struct hme *); 3447c478bd9Sstevel@tonic-gate static void hme_check_transceiver(struct hme *); 3457c478bd9Sstevel@tonic-gate static void hme_setup_link_default(struct hme *); 3467c478bd9Sstevel@tonic-gate static void hme_setup_link_status(struct hme *); 3477c478bd9Sstevel@tonic-gate static void hme_setup_link_control(struct hme *); 3487c478bd9Sstevel@tonic-gate static int hme_check_txhung(struct hme *hmep); 3497c478bd9Sstevel@tonic-gate static void hme_check_link(void *); 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate static void hme_init_xcvr_info(struct hme *); 3527c478bd9Sstevel@tonic-gate static void hme_disable_link_pulse(struct hme *); 3537c478bd9Sstevel@tonic-gate static void hme_force_speed(void *); 3547c478bd9Sstevel@tonic-gate static void hme_get_autoinfo(struct hme *); 3557c478bd9Sstevel@tonic-gate static int hme_try_auto_negotiation(struct hme *); 3567c478bd9Sstevel@tonic-gate static void hme_try_speed(void *); 3577c478bd9Sstevel@tonic-gate static void hme_link_now_up(struct hme *); 3587c478bd9Sstevel@tonic-gate static void hme_setup_mac_address(struct hme *, dev_info_t *); 3597c478bd9Sstevel@tonic-gate 3607c478bd9Sstevel@tonic-gate static void hme_nd_free(caddr_t *nd_pparam); 3617c478bd9Sstevel@tonic-gate static int hme_nd_getset(queue_t *q, caddr_t nd_param, MBLKP mp); 3627c478bd9Sstevel@tonic-gate static boolean_t hme_nd_load(caddr_t *nd_pparam, char *name, 36385025c03Sgd pfi_t get_pfi, pfi_t set_pfi, caddr_t data); 3647c478bd9Sstevel@tonic-gate 365*0219346bSGarrett D'Amore static void hme_fault_msg(struct hme *, uint_t, msg_t, char *, ...); 3667c478bd9Sstevel@tonic-gate 3677c478bd9Sstevel@tonic-gate static void hme_check_acc_handle(char *, uint_t, struct hme *, 36885025c03Sgd ddi_acc_handle_t); 3697c478bd9Sstevel@tonic-gate 37085025c03Sgd /* 37185025c03Sgd * Nemo (GLDv3) Functions. 37285025c03Sgd */ 37385025c03Sgd static int hme_m_stat(void *, uint_t, uint64_t *); 37485025c03Sgd static int hme_m_start(void *); 37585025c03Sgd static void hme_m_stop(void *); 37685025c03Sgd static int hme_m_promisc(void *, boolean_t); 37785025c03Sgd static int hme_m_multicst(void *, boolean_t, const uint8_t *); 37885025c03Sgd static int hme_m_unicst(void *, const uint8_t *); 37985025c03Sgd static mblk_t *hme_m_tx(void *, mblk_t *); 38085025c03Sgd static void hme_m_ioctl(void *, queue_t *, mblk_t *); 38185025c03Sgd static boolean_t hme_m_getcapab(void *, mac_capab_t, void *); 38285025c03Sgd 38385025c03Sgd static mac_callbacks_t hme_m_callbacks = { 38485025c03Sgd MC_IOCTL | MC_GETCAPAB, 38585025c03Sgd hme_m_stat, 38685025c03Sgd hme_m_start, 38785025c03Sgd hme_m_stop, 38885025c03Sgd hme_m_promisc, 38985025c03Sgd hme_m_multicst, 39085025c03Sgd hme_m_unicst, 39185025c03Sgd hme_m_tx, 39285025c03Sgd hme_m_ioctl, 39385025c03Sgd hme_m_getcapab, 39485025c03Sgd }; 39585025c03Sgd 39685025c03Sgd DDI_DEFINE_STREAM_OPS(hme_dev_ops, nulldev, nulldev, hmeattach, hmedetach, 397*0219346bSGarrett D'Amore nodev, NULL, D_MP, NULL, hmequiesce); 3987c478bd9Sstevel@tonic-gate 3997c478bd9Sstevel@tonic-gate #define HME_FAULT_MSG1(p, s, t, f) \ 400*0219346bSGarrett D'Amore hme_fault_msg((p), (s), (t), (f)); 4017c478bd9Sstevel@tonic-gate 4027c478bd9Sstevel@tonic-gate #define HME_FAULT_MSG2(p, s, t, f, a) \ 403*0219346bSGarrett D'Amore hme_fault_msg((p), (s), (t), (f), (a)); 4047c478bd9Sstevel@tonic-gate 4057c478bd9Sstevel@tonic-gate #define HME_FAULT_MSG3(p, s, t, f, a, b) \ 406*0219346bSGarrett D'Amore hme_fault_msg((p), (s), (t), (f), (a), (b)); 4077c478bd9Sstevel@tonic-gate 4087c478bd9Sstevel@tonic-gate #define HME_FAULT_MSG4(p, s, t, f, a, b, c) \ 409*0219346bSGarrett D'Amore hme_fault_msg((p), (s), (t), (f), (a), (b), (c)); 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate #define CHECK_MIFREG() \ 4127c478bd9Sstevel@tonic-gate hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_mifregh) 4137c478bd9Sstevel@tonic-gate #define CHECK_ETXREG() \ 4147c478bd9Sstevel@tonic-gate hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_etxregh) 4157c478bd9Sstevel@tonic-gate #define CHECK_ERXREG() \ 4167c478bd9Sstevel@tonic-gate hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_erxregh) 4177c478bd9Sstevel@tonic-gate #define CHECK_MACREG() \ 4187c478bd9Sstevel@tonic-gate hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_bmacregh) 4197c478bd9Sstevel@tonic-gate #define CHECK_GLOBREG() \ 4207c478bd9Sstevel@tonic-gate hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_globregh) 4217c478bd9Sstevel@tonic-gate 4227c478bd9Sstevel@tonic-gate /* 4237c478bd9Sstevel@tonic-gate * Claim the device is ultra-capable of burst in the beginning. Use 4247c478bd9Sstevel@tonic-gate * the value returned by ddi_dma_burstsizes() to actually set the HME 4257c478bd9Sstevel@tonic-gate * global configuration register later. 4267c478bd9Sstevel@tonic-gate * 4277c478bd9Sstevel@tonic-gate * Sbus/FEPS supports burst sizes of 16, 32 and 64 bytes. Also, it supports 4287c478bd9Sstevel@tonic-gate * 32-bit and 64-bit Sbus transfers. Hence the dlim_burstsizes field contains 4297c478bd9Sstevel@tonic-gate * the the burstsizes in both the lo and hi words. 4307c478bd9Sstevel@tonic-gate */ 4317c478bd9Sstevel@tonic-gate #define HMELIMADDRLO ((uint64_t)0x00000000) 4327c478bd9Sstevel@tonic-gate #define HMELIMADDRHI ((uint64_t)0xffffffff) 4337c478bd9Sstevel@tonic-gate 434*0219346bSGarrett D'Amore /* 435*0219346bSGarrett D'Amore * Note that rx and tx data buffers can be arbitrarily aligned, but 436*0219346bSGarrett D'Amore * that the descriptor rings need to be aligned on 2K boundaries, per 437*0219346bSGarrett D'Amore * the spec. 438*0219346bSGarrett D'Amore */ 4397c478bd9Sstevel@tonic-gate static ddi_dma_attr_t hme_dma_attr = { 4407c478bd9Sstevel@tonic-gate DMA_ATTR_V0, /* version number. */ 4417c478bd9Sstevel@tonic-gate (uint64_t)HMELIMADDRLO, /* low address */ 4427c478bd9Sstevel@tonic-gate (uint64_t)HMELIMADDRHI, /* high address */ 4437c478bd9Sstevel@tonic-gate (uint64_t)0x00ffffff, /* address counter max */ 444*0219346bSGarrett D'Amore (uint64_t)HME_HMDALIGN, /* alignment */ 4457c478bd9Sstevel@tonic-gate (uint_t)0x00700070, /* dlim_burstsizes for 32 and 64 bit xfers */ 4467c478bd9Sstevel@tonic-gate (uint32_t)0x1, /* minimum transfer size */ 4477c478bd9Sstevel@tonic-gate (uint64_t)0x7fffffff, /* maximum transfer size */ 4487c478bd9Sstevel@tonic-gate (uint64_t)0x00ffffff, /* maximum segment size */ 4497c478bd9Sstevel@tonic-gate 1, /* scatter/gather list length */ 4507c478bd9Sstevel@tonic-gate 512, /* granularity */ 4517c478bd9Sstevel@tonic-gate 0 /* attribute flags */ 4527c478bd9Sstevel@tonic-gate }; 4537c478bd9Sstevel@tonic-gate 454*0219346bSGarrett D'Amore static ddi_device_acc_attr_t hme_buf_attr = { 455*0219346bSGarrett D'Amore DDI_DEVICE_ATTR_V0, 456*0219346bSGarrett D'Amore DDI_NEVERSWAP_ACC, 457*0219346bSGarrett D'Amore DDI_STRICTORDER_ACC, /* probably could allow merging & caching */ 458*0219346bSGarrett D'Amore DDI_DEFAULT_ACC, 4597c478bd9Sstevel@tonic-gate }; 4607c478bd9Sstevel@tonic-gate 4617c478bd9Sstevel@tonic-gate static uchar_t pci_latency_timer = 0; 4627c478bd9Sstevel@tonic-gate 4637c478bd9Sstevel@tonic-gate /* 4647c478bd9Sstevel@tonic-gate * Module linkage information for the kernel. 4657c478bd9Sstevel@tonic-gate */ 4667c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 4677c478bd9Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a driver */ 46885025c03Sgd "Sun HME 10/100 Mb Ethernet", 46985025c03Sgd &hme_dev_ops, /* driver ops */ 4707c478bd9Sstevel@tonic-gate }; 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 4737c478bd9Sstevel@tonic-gate MODREV_1, &modldrv, NULL 4747c478bd9Sstevel@tonic-gate }; 4757c478bd9Sstevel@tonic-gate 4767c478bd9Sstevel@tonic-gate /* 4777c478bd9Sstevel@tonic-gate * Internal PHY Id: 4787c478bd9Sstevel@tonic-gate */ 4797c478bd9Sstevel@tonic-gate 4807c478bd9Sstevel@tonic-gate #define HME_BB1 0x15 /* Babybac1, Rev 1.5 */ 4817c478bd9Sstevel@tonic-gate #define HME_BB2 0x20 /* Babybac2, Rev 0 */ 4827c478bd9Sstevel@tonic-gate 4837c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<<<<<<<<<<< Register operations >>>>>>>>>>>>>>>>>>>>> */ 4847c478bd9Sstevel@tonic-gate 4857c478bd9Sstevel@tonic-gate #define GET_MIFREG(reg) \ 4867c478bd9Sstevel@tonic-gate ddi_get32(hmep->hme_mifregh, (uint32_t *)&hmep->hme_mifregp->reg) 4877c478bd9Sstevel@tonic-gate #define PUT_MIFREG(reg, value) \ 4887c478bd9Sstevel@tonic-gate ddi_put32(hmep->hme_mifregh, (uint32_t *)&hmep->hme_mifregp->reg, value) 4897c478bd9Sstevel@tonic-gate 4907c478bd9Sstevel@tonic-gate #define GET_ETXREG(reg) \ 4917c478bd9Sstevel@tonic-gate ddi_get32(hmep->hme_etxregh, (uint32_t *)&hmep->hme_etxregp->reg) 4927c478bd9Sstevel@tonic-gate #define PUT_ETXREG(reg, value) \ 4937c478bd9Sstevel@tonic-gate ddi_put32(hmep->hme_etxregh, (uint32_t *)&hmep->hme_etxregp->reg, value) 4947c478bd9Sstevel@tonic-gate #define GET_ERXREG(reg) \ 4957c478bd9Sstevel@tonic-gate ddi_get32(hmep->hme_erxregh, (uint32_t *)&hmep->hme_erxregp->reg) 4967c478bd9Sstevel@tonic-gate #define PUT_ERXREG(reg, value) \ 4977c478bd9Sstevel@tonic-gate ddi_put32(hmep->hme_erxregh, (uint32_t *)&hmep->hme_erxregp->reg, value) 4987c478bd9Sstevel@tonic-gate #define GET_MACREG(reg) \ 4997c478bd9Sstevel@tonic-gate ddi_get32(hmep->hme_bmacregh, (uint32_t *)&hmep->hme_bmacregp->reg) 5007c478bd9Sstevel@tonic-gate #define PUT_MACREG(reg, value) \ 5017c478bd9Sstevel@tonic-gate ddi_put32(hmep->hme_bmacregh, \ 5027c478bd9Sstevel@tonic-gate (uint32_t *)&hmep->hme_bmacregp->reg, value) 5037c478bd9Sstevel@tonic-gate #define GET_GLOBREG(reg) \ 5047c478bd9Sstevel@tonic-gate ddi_get32(hmep->hme_globregh, (uint32_t *)&hmep->hme_globregp->reg) 5057c478bd9Sstevel@tonic-gate #define PUT_GLOBREG(reg, value) \ 5067c478bd9Sstevel@tonic-gate ddi_put32(hmep->hme_globregh, \ 5077c478bd9Sstevel@tonic-gate (uint32_t *)&hmep->hme_globregp->reg, value) 508*0219346bSGarrett D'Amore #define PUT_TMD(ptr, paddr, len, flags) \ 509*0219346bSGarrett D'Amore ddi_put32(hmep->hme_tmd_acch, &hmep->hme_tmdp[ptr].tmd_addr, paddr); \ 510*0219346bSGarrett D'Amore ddi_put32(hmep->hme_tmd_acch, &hmep->hme_tmdp[ptr].tmd_flags, \ 511*0219346bSGarrett D'Amore len | flags) 512*0219346bSGarrett D'Amore #define GET_TMD_FLAGS(ptr) \ 513*0219346bSGarrett D'Amore ddi_get32(hmep->hme_tmd_acch, &hmep->hme_tmdp[ptr].tmd_flags) 514*0219346bSGarrett D'Amore #define PUT_RMD(ptr, paddr) \ 515*0219346bSGarrett D'Amore ddi_put32(hmep->hme_rmd_acch, &hmep->hme_rmdp[ptr].rmd_addr, paddr); \ 516*0219346bSGarrett D'Amore ddi_put32(hmep->hme_rmd_acch, &hmep->hme_rmdp[ptr].rmd_flags, \ 517*0219346bSGarrett D'Amore (uint32_t)(HMEBUFSIZE << HMERMD_BUFSIZE_SHIFT) | HMERMD_OWN) 518*0219346bSGarrett D'Amore #define GET_RMD_FLAGS(ptr) \ 519*0219346bSGarrett D'Amore ddi_get32(hmep->hme_rmd_acch, &hmep->hme_rmdp[ptr].rmd_flags) 520*0219346bSGarrett D'Amore 5217c478bd9Sstevel@tonic-gate #define GET_ROM8(offset) \ 5227c478bd9Sstevel@tonic-gate ddi_get8((hmep->hme_romh), (offset)) 5237c478bd9Sstevel@tonic-gate 5247c478bd9Sstevel@tonic-gate /* 5257c478bd9Sstevel@tonic-gate * Ether_copy is not endian-correct. Define an endian-correct version. 5267c478bd9Sstevel@tonic-gate */ 5277c478bd9Sstevel@tonic-gate #define ether_bcopy(a, b) (bcopy(a, b, 6)) 5287c478bd9Sstevel@tonic-gate 5297c478bd9Sstevel@tonic-gate /* 5307c478bd9Sstevel@tonic-gate * Ether-type is specifically big-endian, but data region is unknown endian 5317c478bd9Sstevel@tonic-gate */ 53285025c03Sgd #define get_ether_type(ptr) \ 53385025c03Sgd (((((uint8_t *)ptr)[12] << 8) | (((uint8_t *)ptr)[13]))) 5347c478bd9Sstevel@tonic-gate 5357c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<<<<<<<<<<< Configuration Parameters >>>>>>>>>>>>>>>>>>>>> */ 5367c478bd9Sstevel@tonic-gate 5377c478bd9Sstevel@tonic-gate #define BMAC_DEFAULT_JAMSIZE (0x04) /* jamsize equals 4 */ 5387c478bd9Sstevel@tonic-gate #define BMAC_LONG_JAMSIZE (0x10) /* jamsize equals 0x10 */ 5397c478bd9Sstevel@tonic-gate static int jamsize = BMAC_DEFAULT_JAMSIZE; 5407c478bd9Sstevel@tonic-gate 5417c478bd9Sstevel@tonic-gate 5427c478bd9Sstevel@tonic-gate /* 5437c478bd9Sstevel@tonic-gate * Calculate the bit in the multicast address filter that selects the given 5447c478bd9Sstevel@tonic-gate * address. 5457c478bd9Sstevel@tonic-gate */ 5467c478bd9Sstevel@tonic-gate 5477c478bd9Sstevel@tonic-gate static uint32_t 54885025c03Sgd hmeladrf_bit(const uint8_t *addr) 5497c478bd9Sstevel@tonic-gate { 5507c478bd9Sstevel@tonic-gate uint32_t crc; 5517c478bd9Sstevel@tonic-gate 5527c478bd9Sstevel@tonic-gate CRC32(crc, addr, ETHERADDRL, -1U, crc32_table); 5537c478bd9Sstevel@tonic-gate 5547c478bd9Sstevel@tonic-gate /* 5557c478bd9Sstevel@tonic-gate * Just want the 6 most significant bits. 5567c478bd9Sstevel@tonic-gate */ 5577c478bd9Sstevel@tonic-gate return (crc >> 26); 5587c478bd9Sstevel@tonic-gate } 5597c478bd9Sstevel@tonic-gate 5607c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<<<<<<<<<<<<< Bit Bang Operations >>>>>>>>>>>>>>>>>>>>>>>> */ 5617c478bd9Sstevel@tonic-gate 5627c478bd9Sstevel@tonic-gate static int hme_internal_phy_id = HME_BB2; /* Internal PHY is Babybac2 */ 5637c478bd9Sstevel@tonic-gate 5647c478bd9Sstevel@tonic-gate 5657c478bd9Sstevel@tonic-gate static void 5667c478bd9Sstevel@tonic-gate send_bit(struct hme *hmep, uint32_t x) 5677c478bd9Sstevel@tonic-gate { 5687c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbdata, x); 5697c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbclk, HME_BBCLK_LOW); 5707c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbclk, HME_BBCLK_HIGH); 5717c478bd9Sstevel@tonic-gate } 5727c478bd9Sstevel@tonic-gate 5737c478bd9Sstevel@tonic-gate /* 5747c478bd9Sstevel@tonic-gate * To read the MII register bits from the Babybac1 transceiver 5757c478bd9Sstevel@tonic-gate */ 5767c478bd9Sstevel@tonic-gate static uint32_t 5777c478bd9Sstevel@tonic-gate get_bit(struct hme *hmep) 5787c478bd9Sstevel@tonic-gate { 5797c478bd9Sstevel@tonic-gate uint32_t x; 5807c478bd9Sstevel@tonic-gate 5817c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbclk, HME_BBCLK_LOW); 5827c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbclk, HME_BBCLK_HIGH); 5837c478bd9Sstevel@tonic-gate if (hmep->hme_transceiver == HME_INTERNAL_TRANSCEIVER) 5847c478bd9Sstevel@tonic-gate x = (GET_MIFREG(mif_cfg) & HME_MIF_CFGM0) ? 1 : 0; 5857c478bd9Sstevel@tonic-gate else 5867c478bd9Sstevel@tonic-gate x = (GET_MIFREG(mif_cfg) & HME_MIF_CFGM1) ? 1 : 0; 5877c478bd9Sstevel@tonic-gate return (x); 5887c478bd9Sstevel@tonic-gate } 5897c478bd9Sstevel@tonic-gate 5907c478bd9Sstevel@tonic-gate 5917c478bd9Sstevel@tonic-gate /* 5927c478bd9Sstevel@tonic-gate * To read the MII register bits according to the IEEE Standard 5937c478bd9Sstevel@tonic-gate */ 5947c478bd9Sstevel@tonic-gate static uint32_t 5957c478bd9Sstevel@tonic-gate get_bit_std(struct hme *hmep) 5967c478bd9Sstevel@tonic-gate { 5977c478bd9Sstevel@tonic-gate uint32_t x; 5987c478bd9Sstevel@tonic-gate 5997c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbclk, HME_BBCLK_LOW); 6007c478bd9Sstevel@tonic-gate drv_usecwait(1); /* wait for >330 ns for stable data */ 6017c478bd9Sstevel@tonic-gate if (hmep->hme_transceiver == HME_INTERNAL_TRANSCEIVER) 6027c478bd9Sstevel@tonic-gate x = (GET_MIFREG(mif_cfg) & HME_MIF_CFGM0) ? 1 : 0; 6037c478bd9Sstevel@tonic-gate else 6047c478bd9Sstevel@tonic-gate x = (GET_MIFREG(mif_cfg) & HME_MIF_CFGM1) ? 1 : 0; 6057c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbclk, HME_BBCLK_HIGH); 6067c478bd9Sstevel@tonic-gate return (x); 6077c478bd9Sstevel@tonic-gate } 6087c478bd9Sstevel@tonic-gate 6097c478bd9Sstevel@tonic-gate #define SEND_BIT(x) send_bit(hmep, x) 6107c478bd9Sstevel@tonic-gate #define GET_BIT(x) x = get_bit(hmep) 6117c478bd9Sstevel@tonic-gate #define GET_BIT_STD(x) x = get_bit_std(hmep) 6127c478bd9Sstevel@tonic-gate 6137c478bd9Sstevel@tonic-gate 6147c478bd9Sstevel@tonic-gate static void 6157c478bd9Sstevel@tonic-gate hme_bb_mii_write(struct hme *hmep, uint8_t regad, uint16_t data) 6167c478bd9Sstevel@tonic-gate { 6177c478bd9Sstevel@tonic-gate uint8_t phyad; 6187c478bd9Sstevel@tonic-gate int i; 6197c478bd9Sstevel@tonic-gate 6207c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbopenb, 1); /* Enable the MII driver */ 6217c478bd9Sstevel@tonic-gate phyad = hmep->hme_phyad; 6227c478bd9Sstevel@tonic-gate (void) hme_bb_force_idle(hmep); 6237c478bd9Sstevel@tonic-gate SEND_BIT(0); SEND_BIT(1); /* <ST> */ 6247c478bd9Sstevel@tonic-gate SEND_BIT(0); SEND_BIT(1); /* <OP> */ 6257c478bd9Sstevel@tonic-gate 6267c478bd9Sstevel@tonic-gate for (i = 4; i >= 0; i--) { /* <AAAAA> */ 6277c478bd9Sstevel@tonic-gate SEND_BIT((phyad >> i) & 1); 6287c478bd9Sstevel@tonic-gate } 6297c478bd9Sstevel@tonic-gate 6307c478bd9Sstevel@tonic-gate for (i = 4; i >= 0; i--) { /* <RRRRR> */ 6317c478bd9Sstevel@tonic-gate SEND_BIT((regad >> i) & 1); 6327c478bd9Sstevel@tonic-gate } 6337c478bd9Sstevel@tonic-gate 6347c478bd9Sstevel@tonic-gate SEND_BIT(1); SEND_BIT(0); /* <TA> */ 6357c478bd9Sstevel@tonic-gate 6367c478bd9Sstevel@tonic-gate for (i = 0xf; i >= 0; i--) { /* <DDDDDDDDDDDDDDDD> */ 6377c478bd9Sstevel@tonic-gate SEND_BIT((data >> i) & 1); 6387c478bd9Sstevel@tonic-gate } 6397c478bd9Sstevel@tonic-gate 6407c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbopenb, 0); /* Disable the MII driver */ 6417c478bd9Sstevel@tonic-gate CHECK_MIFREG(); 6427c478bd9Sstevel@tonic-gate } 6437c478bd9Sstevel@tonic-gate 6447c478bd9Sstevel@tonic-gate /* Return 0 if OK, 1 if error (Transceiver does not talk management) */ 6457c478bd9Sstevel@tonic-gate static uint_t 6467c478bd9Sstevel@tonic-gate hme_bb_mii_read(struct hme *hmep, uint8_t regad, uint16_t *datap) 6477c478bd9Sstevel@tonic-gate { 6487c478bd9Sstevel@tonic-gate uint8_t phyad; 6497c478bd9Sstevel@tonic-gate int i; 6507c478bd9Sstevel@tonic-gate uint32_t x; 6517c478bd9Sstevel@tonic-gate uint32_t y; 6527c478bd9Sstevel@tonic-gate 6537c478bd9Sstevel@tonic-gate *datap = 0; 6547c478bd9Sstevel@tonic-gate 6557c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbopenb, 1); /* Enable the MII driver */ 6567c478bd9Sstevel@tonic-gate phyad = hmep->hme_phyad; 6577c478bd9Sstevel@tonic-gate (void) hme_bb_force_idle(hmep); 6587c478bd9Sstevel@tonic-gate SEND_BIT(0); SEND_BIT(1); /* <ST> */ 6597c478bd9Sstevel@tonic-gate SEND_BIT(1); SEND_BIT(0); /* <OP> */ 6607c478bd9Sstevel@tonic-gate for (i = 4; i >= 0; i--) { /* <AAAAA> */ 6617c478bd9Sstevel@tonic-gate SEND_BIT((phyad >> i) & 1); 6627c478bd9Sstevel@tonic-gate } 6637c478bd9Sstevel@tonic-gate for (i = 4; i >= 0; i--) { /* <RRRRR> */ 6647c478bd9Sstevel@tonic-gate SEND_BIT((regad >> i) & 1); 6657c478bd9Sstevel@tonic-gate } 6667c478bd9Sstevel@tonic-gate 6677c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_bbopenb, 0); /* Disable the MII driver */ 6687c478bd9Sstevel@tonic-gate 6697c478bd9Sstevel@tonic-gate if ((hme_internal_phy_id == HME_BB2) || 67085025c03Sgd (hmep->hme_transceiver == HME_EXTERNAL_TRANSCEIVER)) { 6717c478bd9Sstevel@tonic-gate GET_BIT_STD(x); 6727c478bd9Sstevel@tonic-gate GET_BIT_STD(y); /* <TA> */ 6737c478bd9Sstevel@tonic-gate for (i = 0xf; i >= 0; i--) { /* <DDDDDDDDDDDDDDDD> */ 6747c478bd9Sstevel@tonic-gate GET_BIT_STD(x); 6757c478bd9Sstevel@tonic-gate *datap += (x << i); 6767c478bd9Sstevel@tonic-gate } 6777c478bd9Sstevel@tonic-gate /* 6787c478bd9Sstevel@tonic-gate * Kludge to get the Transceiver out of hung mode 6797c478bd9Sstevel@tonic-gate */ 6807c478bd9Sstevel@tonic-gate GET_BIT_STD(x); 6817c478bd9Sstevel@tonic-gate GET_BIT_STD(x); 6827c478bd9Sstevel@tonic-gate GET_BIT_STD(x); 6837c478bd9Sstevel@tonic-gate } else { 6847c478bd9Sstevel@tonic-gate GET_BIT(x); 6857c478bd9Sstevel@tonic-gate GET_BIT(y); /* <TA> */ 6867c478bd9Sstevel@tonic-gate for (i = 0xf; i >= 0; i--) { /* <DDDDDDDDDDDDDDDD> */ 6877c478bd9Sstevel@tonic-gate GET_BIT(x); 6887c478bd9Sstevel@tonic-gate *datap += (x << i); 6897c478bd9Sstevel@tonic-gate } 6907c478bd9Sstevel@tonic-gate /* 6917c478bd9Sstevel@tonic-gate * Kludge to get the Transceiver out of hung mode 6927c478bd9Sstevel@tonic-gate */ 6937c478bd9Sstevel@tonic-gate GET_BIT(x); 6947c478bd9Sstevel@tonic-gate GET_BIT(x); 6957c478bd9Sstevel@tonic-gate GET_BIT(x); 6967c478bd9Sstevel@tonic-gate } 6977c478bd9Sstevel@tonic-gate CHECK_MIFREG(); 6987c478bd9Sstevel@tonic-gate return (y); 6997c478bd9Sstevel@tonic-gate } 7007c478bd9Sstevel@tonic-gate 7017c478bd9Sstevel@tonic-gate 7027c478bd9Sstevel@tonic-gate static void 7037c478bd9Sstevel@tonic-gate hme_bb_force_idle(struct hme *hmep) 7047c478bd9Sstevel@tonic-gate { 7057c478bd9Sstevel@tonic-gate int i; 7067c478bd9Sstevel@tonic-gate 7077c478bd9Sstevel@tonic-gate for (i = 0; i < 33; i++) { 7087c478bd9Sstevel@tonic-gate SEND_BIT(1); 7097c478bd9Sstevel@tonic-gate } 7107c478bd9Sstevel@tonic-gate } 7117c478bd9Sstevel@tonic-gate 7127c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<<<<<<<<<End of Bit Bang Operations >>>>>>>>>>>>>>>>>>>>>>>> */ 7137c478bd9Sstevel@tonic-gate 7147c478bd9Sstevel@tonic-gate 7157c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<< Frame Register used for MII operations >>>>>>>>>>>>>>>>>>>> */ 7167c478bd9Sstevel@tonic-gate 7177c478bd9Sstevel@tonic-gate /* Return 0 if OK, 1 if error (Transceiver does not talk management) */ 7187c478bd9Sstevel@tonic-gate static uint_t 7197c478bd9Sstevel@tonic-gate hme_mii_read(struct hme *hmep, uchar_t regad, uint16_t *datap) 7207c478bd9Sstevel@tonic-gate { 7217c478bd9Sstevel@tonic-gate uint32_t frame; 7227c478bd9Sstevel@tonic-gate uint8_t phyad; 7237c478bd9Sstevel@tonic-gate 7247c478bd9Sstevel@tonic-gate if (hmep->hme_transceiver == HME_NO_TRANSCEIVER) 7257c478bd9Sstevel@tonic-gate return (1); /* No transceiver present */ 7267c478bd9Sstevel@tonic-gate 7277c478bd9Sstevel@tonic-gate if (!hmep->hme_frame_enable) 7287c478bd9Sstevel@tonic-gate return (hme_bb_mii_read(hmep, regad, datap)); 7297c478bd9Sstevel@tonic-gate 7307c478bd9Sstevel@tonic-gate phyad = hmep->hme_phyad; 7317c478bd9Sstevel@tonic-gate 732*0219346bSGarrett D'Amore PUT_MIFREG(mif_frame, 733*0219346bSGarrett D'Amore HME_MIF_FRREAD | (phyad << HME_MIF_FRPHYAD_SHIFT) | 734*0219346bSGarrett D'Amore (regad << HME_MIF_FRREGAD_SHIFT)); 7357c478bd9Sstevel@tonic-gate /* 7367c478bd9Sstevel@tonic-gate * HMEDELAY((*framerp & HME_MIF_FRTA0), HMEMAXRSTDELAY); 7377c478bd9Sstevel@tonic-gate */ 738*0219346bSGarrett D'Amore HMEDELAY((GET_MIFREG(mif_frame) & HME_MIF_FRTA0), 300); 739*0219346bSGarrett D'Amore frame = GET_MIFREG(mif_frame); 7407c478bd9Sstevel@tonic-gate CHECK_MIFREG(); 7417c478bd9Sstevel@tonic-gate if ((frame & HME_MIF_FRTA0) == 0) { 7427c478bd9Sstevel@tonic-gate 7437c478bd9Sstevel@tonic-gate 7447c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, NAUTONEG_MSG, 745*0219346bSGarrett D'Amore "MIF Read failure"); 7467c478bd9Sstevel@tonic-gate return (1); 7477c478bd9Sstevel@tonic-gate } else { 7487c478bd9Sstevel@tonic-gate *datap = (uint16_t)(frame & HME_MIF_FRDATA); 7497c478bd9Sstevel@tonic-gate return (0); 7507c478bd9Sstevel@tonic-gate } 7517c478bd9Sstevel@tonic-gate 7527c478bd9Sstevel@tonic-gate } 7537c478bd9Sstevel@tonic-gate 7547c478bd9Sstevel@tonic-gate static void 7557c478bd9Sstevel@tonic-gate hme_mii_write(struct hme *hmep, uint8_t regad, uint16_t data) 7567c478bd9Sstevel@tonic-gate { 7577c478bd9Sstevel@tonic-gate uint32_t frame; 7587c478bd9Sstevel@tonic-gate uint8_t phyad; 7597c478bd9Sstevel@tonic-gate 7607c478bd9Sstevel@tonic-gate if (!hmep->hme_frame_enable) { 7617c478bd9Sstevel@tonic-gate hme_bb_mii_write(hmep, regad, data); 7627c478bd9Sstevel@tonic-gate return; 7637c478bd9Sstevel@tonic-gate } 7647c478bd9Sstevel@tonic-gate 7657c478bd9Sstevel@tonic-gate phyad = hmep->hme_phyad; 7667c478bd9Sstevel@tonic-gate 767*0219346bSGarrett D'Amore PUT_MIFREG(mif_frame, 768*0219346bSGarrett D'Amore HME_MIF_FRWRITE | (phyad << HME_MIF_FRPHYAD_SHIFT) | 769*0219346bSGarrett D'Amore (regad << HME_MIF_FRREGAD_SHIFT) | data); 7707c478bd9Sstevel@tonic-gate /* 7717c478bd9Sstevel@tonic-gate * HMEDELAY((*framerp & HME_MIF_FRTA0), HMEMAXRSTDELAY); 7727c478bd9Sstevel@tonic-gate */ 773*0219346bSGarrett D'Amore HMEDELAY((GET_MIFREG(mif_frame) & HME_MIF_FRTA0), 300); 774*0219346bSGarrett D'Amore frame = GET_MIFREG(mif_frame); 7757c478bd9Sstevel@tonic-gate CHECK_MIFREG(); 7767c478bd9Sstevel@tonic-gate if ((frame & HME_MIF_FRTA0) == 0) { 7777c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_MID, NAUTONEG_MSG, 778*0219346bSGarrett D'Amore "MIF Write failure"); 7797c478bd9Sstevel@tonic-gate } 7807c478bd9Sstevel@tonic-gate } 7817c478bd9Sstevel@tonic-gate 7827c478bd9Sstevel@tonic-gate /* 7837c478bd9Sstevel@tonic-gate * hme_stop_timer function is used by a function before doing link-related 7847c478bd9Sstevel@tonic-gate * processing. It locks the "hme_linklock" to protect the link-related data 7857c478bd9Sstevel@tonic-gate * structures. This lock will be subsequently released in hme_start_timer(). 7867c478bd9Sstevel@tonic-gate */ 7877c478bd9Sstevel@tonic-gate static void 7887c478bd9Sstevel@tonic-gate hme_stop_timer(struct hme *hmep) 7897c478bd9Sstevel@tonic-gate { 7907c478bd9Sstevel@tonic-gate timeout_id_t tid; 7917c478bd9Sstevel@tonic-gate 7927c478bd9Sstevel@tonic-gate mutex_enter(&hmep->hme_linklock); 7937c478bd9Sstevel@tonic-gate 7947c478bd9Sstevel@tonic-gate if (hmep->hme_timerid) { 7957c478bd9Sstevel@tonic-gate tid = hmep->hme_timerid; 7967c478bd9Sstevel@tonic-gate hmep->hme_timerid = 0; 7977c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_linklock); 7987c478bd9Sstevel@tonic-gate (void) untimeout(tid); 7997c478bd9Sstevel@tonic-gate mutex_enter(&hmep->hme_linklock); 8007c478bd9Sstevel@tonic-gate } 8017c478bd9Sstevel@tonic-gate } 8027c478bd9Sstevel@tonic-gate 8037c478bd9Sstevel@tonic-gate static void 8047c478bd9Sstevel@tonic-gate hme_start_timer(struct hme *hmep, fptrv_t func, int msec) 8057c478bd9Sstevel@tonic-gate { 806228fdff0Sgd hmep->hme_timerid = timeout(func, hmep, drv_usectohz(1000 * msec)); 8077c478bd9Sstevel@tonic-gate 8087c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_linklock); 8097c478bd9Sstevel@tonic-gate } 8107c478bd9Sstevel@tonic-gate 8117c478bd9Sstevel@tonic-gate /* 8127c478bd9Sstevel@tonic-gate * hme_select_speed is required only when auto-negotiation is not supported. 8137c478bd9Sstevel@tonic-gate * It should be used only for the Internal Transceiver and not the External 8147c478bd9Sstevel@tonic-gate * transceiver because we wouldn't know how to generate Link Down state on 8157c478bd9Sstevel@tonic-gate * the wire. 8167c478bd9Sstevel@tonic-gate * Currently it is required to support Electron 1.1 Build machines. When all 8177c478bd9Sstevel@tonic-gate * these machines are upgraded to 1.2 or better, remove this function. 8187c478bd9Sstevel@tonic-gate * 8197c478bd9Sstevel@tonic-gate * Returns 1 if the link is up, 0 otherwise. 8207c478bd9Sstevel@tonic-gate */ 8217c478bd9Sstevel@tonic-gate 8227c478bd9Sstevel@tonic-gate static int 8237c478bd9Sstevel@tonic-gate hme_select_speed(struct hme *hmep, int speed) 8247c478bd9Sstevel@tonic-gate { 8257c478bd9Sstevel@tonic-gate uint16_t stat; 8267c478bd9Sstevel@tonic-gate uint16_t fdx; 8277c478bd9Sstevel@tonic-gate 8287c478bd9Sstevel@tonic-gate if (hmep->hme_linkup_cnt) /* not first time */ 8297c478bd9Sstevel@tonic-gate goto read_status; 8307c478bd9Sstevel@tonic-gate 8317c478bd9Sstevel@tonic-gate if (hmep->hme_fdx) 8327c478bd9Sstevel@tonic-gate fdx = PHY_BMCR_FDX; 8337c478bd9Sstevel@tonic-gate else 8347c478bd9Sstevel@tonic-gate fdx = 0; 8357c478bd9Sstevel@tonic-gate 8367c478bd9Sstevel@tonic-gate switch (speed) { 8377c478bd9Sstevel@tonic-gate case HME_SPEED_100: 8387c478bd9Sstevel@tonic-gate 8397c478bd9Sstevel@tonic-gate switch (hmep->hme_transceiver) { 8407c478bd9Sstevel@tonic-gate case HME_INTERNAL_TRANSCEIVER: 8417c478bd9Sstevel@tonic-gate hme_mii_write(hmep, HME_PHY_BMCR, fdx | PHY_BMCR_100M); 8427c478bd9Sstevel@tonic-gate break; 8437c478bd9Sstevel@tonic-gate case HME_EXTERNAL_TRANSCEIVER: 8447c478bd9Sstevel@tonic-gate if (hmep->hme_delay == 0) { 8457c478bd9Sstevel@tonic-gate hme_mii_write(hmep, HME_PHY_BMCR, 84685025c03Sgd fdx | PHY_BMCR_100M); 8477c478bd9Sstevel@tonic-gate } 8487c478bd9Sstevel@tonic-gate break; 8497c478bd9Sstevel@tonic-gate default: 8507c478bd9Sstevel@tonic-gate break; 8517c478bd9Sstevel@tonic-gate } 8527c478bd9Sstevel@tonic-gate break; 8537c478bd9Sstevel@tonic-gate case HME_SPEED_10: 8547c478bd9Sstevel@tonic-gate switch (hmep->hme_transceiver) { 8557c478bd9Sstevel@tonic-gate case HME_INTERNAL_TRANSCEIVER: 8567c478bd9Sstevel@tonic-gate hme_mii_write(hmep, HME_PHY_BMCR, fdx); 8577c478bd9Sstevel@tonic-gate break; 8587c478bd9Sstevel@tonic-gate case HME_EXTERNAL_TRANSCEIVER: 8597c478bd9Sstevel@tonic-gate if (hmep->hme_delay == 0) { 8607c478bd9Sstevel@tonic-gate hme_mii_write(hmep, HME_PHY_BMCR, fdx); 8617c478bd9Sstevel@tonic-gate } 8627c478bd9Sstevel@tonic-gate break; 8637c478bd9Sstevel@tonic-gate default: 8647c478bd9Sstevel@tonic-gate break; 8657c478bd9Sstevel@tonic-gate } 8667c478bd9Sstevel@tonic-gate break; 8677c478bd9Sstevel@tonic-gate default: 8687c478bd9Sstevel@tonic-gate return (0); 8697c478bd9Sstevel@tonic-gate } 8707c478bd9Sstevel@tonic-gate 8717c478bd9Sstevel@tonic-gate if (!hmep->hme_linkup_cnt) { /* first time; select speed */ 8727c478bd9Sstevel@tonic-gate (void) hme_mii_read(hmep, HME_PHY_BMSR, &stat); 8737c478bd9Sstevel@tonic-gate hmep->hme_linkup_cnt++; 8747c478bd9Sstevel@tonic-gate return (0); 8757c478bd9Sstevel@tonic-gate } 8767c478bd9Sstevel@tonic-gate 8777c478bd9Sstevel@tonic-gate read_status: 8787c478bd9Sstevel@tonic-gate hmep->hme_linkup_cnt++; 8797c478bd9Sstevel@tonic-gate (void) hme_mii_read(hmep, HME_PHY_BMSR, &stat); 8807c478bd9Sstevel@tonic-gate if (stat & PHY_BMSR_LNKSTS) 8817c478bd9Sstevel@tonic-gate return (1); 8827c478bd9Sstevel@tonic-gate else 8837c478bd9Sstevel@tonic-gate return (0); 8847c478bd9Sstevel@tonic-gate } 8857c478bd9Sstevel@tonic-gate 8867c478bd9Sstevel@tonic-gate 8877c478bd9Sstevel@tonic-gate #define HME_PHYRST_PERIOD 600 /* 600 milliseconds, instead of 500 */ 8887c478bd9Sstevel@tonic-gate #define HME_PDOWN_PERIOD 256 /* 256 milliseconds power down period to */ 8897c478bd9Sstevel@tonic-gate /* insure a good reset of the QSI PHY */ 8907c478bd9Sstevel@tonic-gate 8917c478bd9Sstevel@tonic-gate static void 8927c478bd9Sstevel@tonic-gate hme_reset_transceiver(struct hme *hmep) 8937c478bd9Sstevel@tonic-gate { 8947c478bd9Sstevel@tonic-gate uint32_t cfg; 8957c478bd9Sstevel@tonic-gate uint16_t stat; 8967c478bd9Sstevel@tonic-gate uint16_t anar; 8977c478bd9Sstevel@tonic-gate uint16_t control; 8987c478bd9Sstevel@tonic-gate uint16_t csc; 8997c478bd9Sstevel@tonic-gate int n; 9007c478bd9Sstevel@tonic-gate 9017c478bd9Sstevel@tonic-gate cfg = GET_MIFREG(mif_cfg); 9027c478bd9Sstevel@tonic-gate 9037c478bd9Sstevel@tonic-gate if (hmep->hme_transceiver == HME_EXTERNAL_TRANSCEIVER) { 9047c478bd9Sstevel@tonic-gate /* Isolate the Internal Transceiver */ 9057c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_cfg, (cfg & ~HME_MIF_CFGPS)); 9067c478bd9Sstevel@tonic-gate hmep->hme_phyad = HME_INTERNAL_PHYAD; 9077c478bd9Sstevel@tonic-gate hmep->hme_transceiver = HME_INTERNAL_TRANSCEIVER; 9087c478bd9Sstevel@tonic-gate hme_mii_write(hmep, HME_PHY_BMCR, (PHY_BMCR_ISOLATE | 90985025c03Sgd PHY_BMCR_PWRDN | PHY_BMCR_LPBK)); 9107c478bd9Sstevel@tonic-gate if (hme_mii_read(hmep, HME_PHY_BMCR, &control) == 1) 9117c478bd9Sstevel@tonic-gate goto start_again; 9127c478bd9Sstevel@tonic-gate 9137c478bd9Sstevel@tonic-gate /* select the External transceiver */ 9147c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_cfg, (cfg | HME_MIF_CFGPS)); 9157c478bd9Sstevel@tonic-gate hmep->hme_transceiver = HME_EXTERNAL_TRANSCEIVER; 9167c478bd9Sstevel@tonic-gate hmep->hme_phyad = HME_EXTERNAL_PHYAD; 9177c478bd9Sstevel@tonic-gate 9187c478bd9Sstevel@tonic-gate } else if (cfg & HME_MIF_CFGM1) { 9197c478bd9Sstevel@tonic-gate /* Isolate the External transceiver, if present */ 9207c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_cfg, (cfg | HME_MIF_CFGPS)); 9217c478bd9Sstevel@tonic-gate hmep->hme_phyad = HME_EXTERNAL_PHYAD; 9227c478bd9Sstevel@tonic-gate hmep->hme_transceiver = HME_EXTERNAL_TRANSCEIVER; 9237c478bd9Sstevel@tonic-gate hme_mii_write(hmep, HME_PHY_BMCR, (PHY_BMCR_ISOLATE | 92485025c03Sgd PHY_BMCR_PWRDN | PHY_BMCR_LPBK)); 9257c478bd9Sstevel@tonic-gate if (hme_mii_read(hmep, HME_PHY_BMCR, &control) == 1) 9267c478bd9Sstevel@tonic-gate goto start_again; 9277c478bd9Sstevel@tonic-gate 9287c478bd9Sstevel@tonic-gate /* select the Internal transceiver */ 9297c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_cfg, (cfg & ~HME_MIF_CFGPS)); 9307c478bd9Sstevel@tonic-gate hmep->hme_transceiver = HME_INTERNAL_TRANSCEIVER; 9317c478bd9Sstevel@tonic-gate hmep->hme_phyad = HME_INTERNAL_PHYAD; 9327c478bd9Sstevel@tonic-gate } 9337c478bd9Sstevel@tonic-gate 9347c478bd9Sstevel@tonic-gate hme_mii_write(hmep, HME_PHY_BMCR, PHY_BMCR_PWRDN); 9357c478bd9Sstevel@tonic-gate drv_usecwait((clock_t)HME_PDOWN_PERIOD); 9367c478bd9Sstevel@tonic-gate 9377c478bd9Sstevel@tonic-gate /* 9387c478bd9Sstevel@tonic-gate * Now reset the transceiver. 9397c478bd9Sstevel@tonic-gate */ 9407c478bd9Sstevel@tonic-gate hme_mii_write(hmep, HME_PHY_BMCR, PHY_BMCR_RESET); 9417c478bd9Sstevel@tonic-gate 9427c478bd9Sstevel@tonic-gate /* 9437c478bd9Sstevel@tonic-gate * Check for transceiver reset completion. 9447c478bd9Sstevel@tonic-gate */ 9457c478bd9Sstevel@tonic-gate n = HME_PHYRST_PERIOD / HMEWAITPERIOD; 9467c478bd9Sstevel@tonic-gate 9477c478bd9Sstevel@tonic-gate while (--n > 0) { 9487c478bd9Sstevel@tonic-gate if (hme_mii_read(hmep, HME_PHY_BMCR, &control) == 1) { 9497c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, XCVR_MSG, 95085025c03Sgd xcvr_no_mii_msg); 9517c478bd9Sstevel@tonic-gate goto start_again; 9527c478bd9Sstevel@tonic-gate } 9537c478bd9Sstevel@tonic-gate if ((control & PHY_BMCR_RESET) == 0) 9547c478bd9Sstevel@tonic-gate goto reset_issued; 9557c478bd9Sstevel@tonic-gate if (hmep->hme_transceiver == HME_INTERNAL_TRANSCEIVER) 9567c478bd9Sstevel@tonic-gate drv_usecwait((clock_t)HMEWAITPERIOD); 9577c478bd9Sstevel@tonic-gate else 9587c478bd9Sstevel@tonic-gate drv_usecwait((clock_t)(500 * HMEWAITPERIOD)); 9597c478bd9Sstevel@tonic-gate } 9607c478bd9Sstevel@tonic-gate /* 9617c478bd9Sstevel@tonic-gate * phy reset failure 9627c478bd9Sstevel@tonic-gate */ 9637c478bd9Sstevel@tonic-gate hmep->phyfail++; 9647c478bd9Sstevel@tonic-gate goto start_again; 9657c478bd9Sstevel@tonic-gate 9667c478bd9Sstevel@tonic-gate reset_issued: 9677c478bd9Sstevel@tonic-gate 9687c478bd9Sstevel@tonic-gate /* 9697c478bd9Sstevel@tonic-gate * Get the PHY id registers. We need this to implement work-arounds 9707c478bd9Sstevel@tonic-gate * for bugs in transceivers which use the National DP83840 PHY chip. 9717c478bd9Sstevel@tonic-gate * National should fix this in the next release. 9727c478bd9Sstevel@tonic-gate */ 9737c478bd9Sstevel@tonic-gate 9747c478bd9Sstevel@tonic-gate (void) hme_mii_read(hmep, HME_PHY_BMSR, &stat); 9757c478bd9Sstevel@tonic-gate (void) hme_mii_read(hmep, HME_PHY_IDR1, &hmep->hme_idr1); 9767c478bd9Sstevel@tonic-gate (void) hme_mii_read(hmep, HME_PHY_IDR2, &hmep->hme_idr2); 9777c478bd9Sstevel@tonic-gate (void) hme_mii_read(hmep, HME_PHY_ANAR, &anar); 9787c478bd9Sstevel@tonic-gate 9797c478bd9Sstevel@tonic-gate hme_init_xcvr_info(hmep); 9807c478bd9Sstevel@tonic-gate 9817c478bd9Sstevel@tonic-gate hmep->hme_bmcr = control; 9827c478bd9Sstevel@tonic-gate hmep->hme_anar = anar; 9837c478bd9Sstevel@tonic-gate hmep->hme_bmsr = stat; 9847c478bd9Sstevel@tonic-gate 9857c478bd9Sstevel@tonic-gate /* 9867c478bd9Sstevel@tonic-gate * The strapping of AN0 and AN1 pins on DP83840 cannot select 9877c478bd9Sstevel@tonic-gate * 10FDX, 100FDX and Auto-negotiation. So select it here for the 9887c478bd9Sstevel@tonic-gate * Internal Transceiver. 9897c478bd9Sstevel@tonic-gate */ 9907c478bd9Sstevel@tonic-gate if (hmep->hme_transceiver == HME_INTERNAL_TRANSCEIVER) { 9917c478bd9Sstevel@tonic-gate anar = (PHY_ANAR_TXFDX | PHY_ANAR_10FDX | 99285025c03Sgd PHY_ANAR_TX | PHY_ANAR_10 | PHY_SELECTOR); 9937c478bd9Sstevel@tonic-gate } 9947c478bd9Sstevel@tonic-gate /* 9957c478bd9Sstevel@tonic-gate * Modify control and bmsr based on anar for Rev-C of DP83840. 9967c478bd9Sstevel@tonic-gate */ 9977c478bd9Sstevel@tonic-gate if (HME_DP83840) { 9987c478bd9Sstevel@tonic-gate n = 0; 9997c478bd9Sstevel@tonic-gate if (anar & PHY_ANAR_TXFDX) { 10007c478bd9Sstevel@tonic-gate stat |= PHY_BMSR_100FDX; 10017c478bd9Sstevel@tonic-gate n++; 10027c478bd9Sstevel@tonic-gate } else 10037c478bd9Sstevel@tonic-gate stat &= ~PHY_BMSR_100FDX; 10047c478bd9Sstevel@tonic-gate 10057c478bd9Sstevel@tonic-gate if (anar & PHY_ANAR_TX) { 10067c478bd9Sstevel@tonic-gate stat |= PHY_BMSR_100HDX; 10077c478bd9Sstevel@tonic-gate n++; 10087c478bd9Sstevel@tonic-gate } else 10097c478bd9Sstevel@tonic-gate stat &= ~PHY_BMSR_100HDX; 10107c478bd9Sstevel@tonic-gate 10117c478bd9Sstevel@tonic-gate if (anar & PHY_ANAR_10FDX) { 10127c478bd9Sstevel@tonic-gate stat |= PHY_BMSR_10FDX; 10137c478bd9Sstevel@tonic-gate n++; 10147c478bd9Sstevel@tonic-gate } else 10157c478bd9Sstevel@tonic-gate stat &= ~PHY_BMSR_10FDX; 10167c478bd9Sstevel@tonic-gate 10177c478bd9Sstevel@tonic-gate if (anar & PHY_ANAR_10) { 10187c478bd9Sstevel@tonic-gate stat |= PHY_BMSR_10HDX; 10197c478bd9Sstevel@tonic-gate n++; 10207c478bd9Sstevel@tonic-gate } else 10217c478bd9Sstevel@tonic-gate stat &= ~PHY_BMSR_10HDX; 10227c478bd9Sstevel@tonic-gate 10237c478bd9Sstevel@tonic-gate if (n == 1) { /* only one mode. disable auto-negotiation */ 10247c478bd9Sstevel@tonic-gate stat &= ~PHY_BMSR_ACFG; 10257c478bd9Sstevel@tonic-gate control &= ~PHY_BMCR_ANE; 10267c478bd9Sstevel@tonic-gate } 10277c478bd9Sstevel@tonic-gate if (n) { 10287c478bd9Sstevel@tonic-gate hmep->hme_bmsr = stat; 10297c478bd9Sstevel@tonic-gate hmep->hme_bmcr = control; 10307c478bd9Sstevel@tonic-gate } 10317c478bd9Sstevel@tonic-gate } 10327c478bd9Sstevel@tonic-gate hme_setup_link_default(hmep); 10337c478bd9Sstevel@tonic-gate hme_setup_link_status(hmep); 10347c478bd9Sstevel@tonic-gate 10357c478bd9Sstevel@tonic-gate 10367c478bd9Sstevel@tonic-gate /* 10377c478bd9Sstevel@tonic-gate * Place the Transceiver in normal operation mode 10387c478bd9Sstevel@tonic-gate */ 10397c478bd9Sstevel@tonic-gate hme_mii_write(hmep, HME_PHY_BMCR, (control & ~PHY_BMCR_ISOLATE)); 10407c478bd9Sstevel@tonic-gate 10417c478bd9Sstevel@tonic-gate /* 10427c478bd9Sstevel@tonic-gate * check if the transceiver is not in Isolate mode 10437c478bd9Sstevel@tonic-gate */ 10447c478bd9Sstevel@tonic-gate n = HME_PHYRST_PERIOD / HMEWAITPERIOD; 10457c478bd9Sstevel@tonic-gate 10467c478bd9Sstevel@tonic-gate while (--n > 0) { 10477c478bd9Sstevel@tonic-gate if (hme_mii_read(hmep, HME_PHY_BMCR, &control) == 1) { 10487c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, XCVR_MSG, 104985025c03Sgd xcvr_no_mii_msg); 10507c478bd9Sstevel@tonic-gate goto start_again; /* Transceiver does not talk MII */ 10517c478bd9Sstevel@tonic-gate } 10527c478bd9Sstevel@tonic-gate if ((control & PHY_BMCR_ISOLATE) == 0) 10537c478bd9Sstevel@tonic-gate goto setconn; 10547c478bd9Sstevel@tonic-gate drv_usecwait(HMEWAITPERIOD); 10557c478bd9Sstevel@tonic-gate } 10567c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, XCVR_MSG, 105785025c03Sgd xcvr_isolate_msg); 10587c478bd9Sstevel@tonic-gate goto start_again; /* transceiver reset failure */ 10597c478bd9Sstevel@tonic-gate 10607c478bd9Sstevel@tonic-gate setconn: 10617c478bd9Sstevel@tonic-gate 10627c478bd9Sstevel@tonic-gate /* 10637c478bd9Sstevel@tonic-gate * Work-around for the late-collision problem with 100m cables. 10647c478bd9Sstevel@tonic-gate * National should fix this in the next release ! 10657c478bd9Sstevel@tonic-gate */ 10667c478bd9Sstevel@tonic-gate if (HME_DP83840) { 10677c478bd9Sstevel@tonic-gate (void) hme_mii_read(hmep, HME_PHY_CSC, &csc); 10687c478bd9Sstevel@tonic-gate 10697c478bd9Sstevel@tonic-gate hme_mii_write(hmep, HME_PHY_CSC, (csc | PHY_CSCR_FCONN)); 10707c478bd9Sstevel@tonic-gate } 10717c478bd9Sstevel@tonic-gate 10727c478bd9Sstevel@tonic-gate hmep->hme_linkcheck = 0; 10737c478bd9Sstevel@tonic-gate hmep->hme_linkup = 0; 10747c478bd9Sstevel@tonic-gate hme_setup_link_status(hmep); 10757c478bd9Sstevel@tonic-gate hmep->hme_autoneg = HME_HWAN_TRY; 10767c478bd9Sstevel@tonic-gate hmep->hme_force_linkdown = HME_FORCE_LINKDOWN; 10777c478bd9Sstevel@tonic-gate hmep->hme_linkup_cnt = 0; 10787c478bd9Sstevel@tonic-gate hmep->hme_delay = 0; 10797c478bd9Sstevel@tonic-gate hme_setup_link_control(hmep); 10807c478bd9Sstevel@tonic-gate hme_start_timer(hmep, hme_check_link, HME_LINKCHECK_TIMER); 10817c478bd9Sstevel@tonic-gate 10827c478bd9Sstevel@tonic-gate if (hmep->hme_mode == HME_FORCE_SPEED) 10837c478bd9Sstevel@tonic-gate hme_force_speed(hmep); 10847c478bd9Sstevel@tonic-gate else { 10857c478bd9Sstevel@tonic-gate hmep->hme_linkup_10 = 0; 10867c478bd9Sstevel@tonic-gate hmep->hme_tryspeed = HME_SPEED_100; 10877c478bd9Sstevel@tonic-gate hmep->hme_ntries = HME_NTRIES_LOW; 10887c478bd9Sstevel@tonic-gate hmep->hme_nlasttries = HME_NTRIES_LOW; 10897c478bd9Sstevel@tonic-gate hme_try_speed(hmep); 10907c478bd9Sstevel@tonic-gate } 10917c478bd9Sstevel@tonic-gate return; 10927c478bd9Sstevel@tonic-gate 10937c478bd9Sstevel@tonic-gate start_again: 10947c478bd9Sstevel@tonic-gate hme_start_timer(hmep, hme_check_link, HME_TICKS); 10957c478bd9Sstevel@tonic-gate } 10967c478bd9Sstevel@tonic-gate 10977c478bd9Sstevel@tonic-gate static void 10987c478bd9Sstevel@tonic-gate hme_check_transceiver(struct hme *hmep) 10997c478bd9Sstevel@tonic-gate { 11007c478bd9Sstevel@tonic-gate uint32_t cfgsav; 11017c478bd9Sstevel@tonic-gate uint32_t cfg; 11027c478bd9Sstevel@tonic-gate uint32_t stat; 11037c478bd9Sstevel@tonic-gate 11047c478bd9Sstevel@tonic-gate /* 11057c478bd9Sstevel@tonic-gate * If the MIF Polling is ON, and Internal transceiver is in use, just 11067c478bd9Sstevel@tonic-gate * check for the presence of the External Transceiver. 11077c478bd9Sstevel@tonic-gate * Otherwise: 11087c478bd9Sstevel@tonic-gate * First check to see what transceivers are out there. 11097c478bd9Sstevel@tonic-gate * If an external transceiver is present 11107c478bd9Sstevel@tonic-gate * then use it, regardless of whether there is a Internal transceiver. 11117c478bd9Sstevel@tonic-gate * If Internal transceiver is present and no external transceiver 11127c478bd9Sstevel@tonic-gate * then use the Internal transceiver. 11137c478bd9Sstevel@tonic-gate * If there is no external transceiver and no Internal transceiver, 11147c478bd9Sstevel@tonic-gate * then something is wrong so print an error message. 11157c478bd9Sstevel@tonic-gate */ 11167c478bd9Sstevel@tonic-gate 11177c478bd9Sstevel@tonic-gate cfgsav = GET_MIFREG(mif_cfg); 11187c478bd9Sstevel@tonic-gate 11197c478bd9Sstevel@tonic-gate if (hmep->hme_polling_on) { 11207c478bd9Sstevel@tonic-gate 11217c478bd9Sstevel@tonic-gate if (hmep->hme_transceiver == HME_INTERNAL_TRANSCEIVER) { 11227c478bd9Sstevel@tonic-gate if ((cfgsav & HME_MIF_CFGM1) && !hme_param_use_intphy) { 11237c478bd9Sstevel@tonic-gate hme_stop_mifpoll(hmep); 11247c478bd9Sstevel@tonic-gate hmep->hme_phyad = HME_EXTERNAL_PHYAD; 11257c478bd9Sstevel@tonic-gate hmep->hme_transceiver = 112685025c03Sgd HME_EXTERNAL_TRANSCEIVER; 11277c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_cfg, ((cfgsav & ~HME_MIF_CFGPE) 112885025c03Sgd | HME_MIF_CFGPS)); 11297c478bd9Sstevel@tonic-gate } 11307c478bd9Sstevel@tonic-gate } else if (hmep->hme_transceiver == HME_EXTERNAL_TRANSCEIVER) { 11317c478bd9Sstevel@tonic-gate stat = (GET_MIFREG(mif_bsts) >> 16); 11327c478bd9Sstevel@tonic-gate if ((stat == 0x00) || (hme_param_use_intphy)) { 11337c478bd9Sstevel@tonic-gate 11347c478bd9Sstevel@tonic-gate hme_stop_mifpoll(hmep); 11357c478bd9Sstevel@tonic-gate hmep->hme_phyad = HME_INTERNAL_PHYAD; 11367c478bd9Sstevel@tonic-gate hmep->hme_transceiver = 113785025c03Sgd HME_INTERNAL_TRANSCEIVER; 113885025c03Sgd PUT_MIFREG(mif_cfg, 113985025c03Sgd (GET_MIFREG(mif_cfg) & ~HME_MIF_CFGPS)); 11407c478bd9Sstevel@tonic-gate } 11417c478bd9Sstevel@tonic-gate } 11427c478bd9Sstevel@tonic-gate CHECK_MIFREG(); 11437c478bd9Sstevel@tonic-gate return; 11447c478bd9Sstevel@tonic-gate } 11457c478bd9Sstevel@tonic-gate 11467c478bd9Sstevel@tonic-gate cfg = GET_MIFREG(mif_cfg); 11477c478bd9Sstevel@tonic-gate if ((cfg & HME_MIF_CFGM1) && !hme_param_use_intphy) { 11487c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_cfg, (cfgsav | HME_MIF_CFGPS)); 11497c478bd9Sstevel@tonic-gate hmep->hme_phyad = HME_EXTERNAL_PHYAD; 11507c478bd9Sstevel@tonic-gate hmep->hme_transceiver = HME_EXTERNAL_TRANSCEIVER; 11517c478bd9Sstevel@tonic-gate 11527c478bd9Sstevel@tonic-gate } else if (cfg & HME_MIF_CFGM0) { /* Internal Transceiver OK */ 11537c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_cfg, (cfgsav & ~HME_MIF_CFGPS)); 11547c478bd9Sstevel@tonic-gate hmep->hme_phyad = HME_INTERNAL_PHYAD; 11557c478bd9Sstevel@tonic-gate hmep->hme_transceiver = HME_INTERNAL_TRANSCEIVER; 11567c478bd9Sstevel@tonic-gate 11577c478bd9Sstevel@tonic-gate } else { 11587c478bd9Sstevel@tonic-gate hmep->hme_transceiver = HME_NO_TRANSCEIVER; 11597c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_HIGH, XCVR_MSG, no_xcvr_msg); 11607c478bd9Sstevel@tonic-gate } 11617c478bd9Sstevel@tonic-gate CHECK_MIFREG(); 11627c478bd9Sstevel@tonic-gate } 11637c478bd9Sstevel@tonic-gate 11647c478bd9Sstevel@tonic-gate static void 11657c478bd9Sstevel@tonic-gate hme_setup_link_default(struct hme *hmep) 11667c478bd9Sstevel@tonic-gate { 11677c478bd9Sstevel@tonic-gate uint16_t bmsr; 11687c478bd9Sstevel@tonic-gate 11697c478bd9Sstevel@tonic-gate bmsr = hmep->hme_bmsr; 11707c478bd9Sstevel@tonic-gate if (hme_param_autoneg & HME_NOTUSR) 11717c478bd9Sstevel@tonic-gate hme_param_autoneg = HME_NOTUSR | 117285025c03Sgd ((bmsr & PHY_BMSR_ACFG) ? 1 : 0); 11737c478bd9Sstevel@tonic-gate if (hme_param_anar_100T4 & HME_NOTUSR) 11747c478bd9Sstevel@tonic-gate hme_param_anar_100T4 = HME_NOTUSR | 117585025c03Sgd ((bmsr & PHY_BMSR_100T4) ? 1 : 0); 11767c478bd9Sstevel@tonic-gate if (hme_param_anar_100fdx & HME_NOTUSR) 11777c478bd9Sstevel@tonic-gate hme_param_anar_100fdx = HME_NOTUSR | 117885025c03Sgd ((bmsr & PHY_BMSR_100FDX) ? 1 : 0); 11797c478bd9Sstevel@tonic-gate if (hme_param_anar_100hdx & HME_NOTUSR) 11807c478bd9Sstevel@tonic-gate hme_param_anar_100hdx = HME_NOTUSR | 118185025c03Sgd ((bmsr & PHY_BMSR_100HDX) ? 1 : 0); 11827c478bd9Sstevel@tonic-gate if (hme_param_anar_10fdx & HME_NOTUSR) 11837c478bd9Sstevel@tonic-gate hme_param_anar_10fdx = HME_NOTUSR | 118485025c03Sgd ((bmsr & PHY_BMSR_10FDX) ? 1 : 0); 11857c478bd9Sstevel@tonic-gate if (hme_param_anar_10hdx & HME_NOTUSR) 11867c478bd9Sstevel@tonic-gate hme_param_anar_10hdx = HME_NOTUSR | 118785025c03Sgd ((bmsr & PHY_BMSR_10HDX) ? 1 : 0); 11887c478bd9Sstevel@tonic-gate } 11897c478bd9Sstevel@tonic-gate 11907c478bd9Sstevel@tonic-gate static void 11917c478bd9Sstevel@tonic-gate hme_setup_link_status(struct hme *hmep) 11927c478bd9Sstevel@tonic-gate { 11937c478bd9Sstevel@tonic-gate uint16_t tmp; 11947c478bd9Sstevel@tonic-gate 11957c478bd9Sstevel@tonic-gate if (hmep->hme_transceiver == HME_EXTERNAL_TRANSCEIVER) 11967c478bd9Sstevel@tonic-gate hme_param_transceiver = 1; 11977c478bd9Sstevel@tonic-gate else 11987c478bd9Sstevel@tonic-gate hme_param_transceiver = 0; 11997c478bd9Sstevel@tonic-gate 12007c478bd9Sstevel@tonic-gate tmp = hmep->hme_bmsr; 12017c478bd9Sstevel@tonic-gate if (tmp & PHY_BMSR_ACFG) 12027c478bd9Sstevel@tonic-gate hme_param_bmsr_ancap = 1; 12037c478bd9Sstevel@tonic-gate else 12047c478bd9Sstevel@tonic-gate hme_param_bmsr_ancap = 0; 12057c478bd9Sstevel@tonic-gate if (tmp & PHY_BMSR_100T4) 12067c478bd9Sstevel@tonic-gate hme_param_bmsr_100T4 = 1; 12077c478bd9Sstevel@tonic-gate else 12087c478bd9Sstevel@tonic-gate hme_param_bmsr_100T4 = 0; 12097c478bd9Sstevel@tonic-gate if (tmp & PHY_BMSR_100FDX) 12107c478bd9Sstevel@tonic-gate hme_param_bmsr_100fdx = 1; 12117c478bd9Sstevel@tonic-gate else 12127c478bd9Sstevel@tonic-gate hme_param_bmsr_100fdx = 0; 12137c478bd9Sstevel@tonic-gate if (tmp & PHY_BMSR_100HDX) 12147c478bd9Sstevel@tonic-gate hme_param_bmsr_100hdx = 1; 12157c478bd9Sstevel@tonic-gate else 12167c478bd9Sstevel@tonic-gate hme_param_bmsr_100hdx = 0; 12177c478bd9Sstevel@tonic-gate if (tmp & PHY_BMSR_10FDX) 12187c478bd9Sstevel@tonic-gate hme_param_bmsr_10fdx = 1; 12197c478bd9Sstevel@tonic-gate else 12207c478bd9Sstevel@tonic-gate hme_param_bmsr_10fdx = 0; 12217c478bd9Sstevel@tonic-gate if (tmp & PHY_BMSR_10HDX) 12227c478bd9Sstevel@tonic-gate hme_param_bmsr_10hdx = 1; 12237c478bd9Sstevel@tonic-gate else 12247c478bd9Sstevel@tonic-gate hme_param_bmsr_10hdx = 0; 12257c478bd9Sstevel@tonic-gate 12267c478bd9Sstevel@tonic-gate if (hmep->hme_link_pulse_disabled) { 12277c478bd9Sstevel@tonic-gate hme_param_linkup = 1; 12287c478bd9Sstevel@tonic-gate hme_param_speed = 0; 12297c478bd9Sstevel@tonic-gate hme_param_mode = 0; 123085025c03Sgd hmep->hme_duplex = LINK_DUPLEX_HALF; 123185025c03Sgd mac_link_update(hmep->hme_mh, LINK_STATE_UP); 12327c478bd9Sstevel@tonic-gate return; 12337c478bd9Sstevel@tonic-gate } 12347c478bd9Sstevel@tonic-gate 12357c478bd9Sstevel@tonic-gate if (!hmep->hme_linkup) { 12367c478bd9Sstevel@tonic-gate hme_param_linkup = 0; 123785025c03Sgd hmep->hme_duplex = LINK_DUPLEX_UNKNOWN; 123885025c03Sgd mac_link_update(hmep->hme_mh, LINK_STATE_DOWN); 12397c478bd9Sstevel@tonic-gate return; 12407c478bd9Sstevel@tonic-gate } 12417c478bd9Sstevel@tonic-gate 12427c478bd9Sstevel@tonic-gate hme_param_linkup = 1; 12437c478bd9Sstevel@tonic-gate 12447c478bd9Sstevel@tonic-gate if (hmep->hme_fdx == HME_FULL_DUPLEX) { 12457c478bd9Sstevel@tonic-gate hme_param_mode = 1; 124685025c03Sgd hmep->hme_duplex = LINK_DUPLEX_FULL; 12477c478bd9Sstevel@tonic-gate } else { 12487c478bd9Sstevel@tonic-gate hme_param_mode = 0; 124985025c03Sgd hmep->hme_duplex = LINK_DUPLEX_HALF; 12507c478bd9Sstevel@tonic-gate } 12517c478bd9Sstevel@tonic-gate 125285025c03Sgd mac_link_update(hmep->hme_mh, LINK_STATE_UP); 125385025c03Sgd 12547c478bd9Sstevel@tonic-gate if (hmep->hme_mode == HME_FORCE_SPEED) { 12557c478bd9Sstevel@tonic-gate if (hmep->hme_forcespeed == HME_SPEED_100) 12567c478bd9Sstevel@tonic-gate hme_param_speed = 1; 12577c478bd9Sstevel@tonic-gate else 12587c478bd9Sstevel@tonic-gate hme_param_speed = 0; 12597c478bd9Sstevel@tonic-gate return; 12607c478bd9Sstevel@tonic-gate } 12617c478bd9Sstevel@tonic-gate if (hmep->hme_tryspeed == HME_SPEED_100) 12627c478bd9Sstevel@tonic-gate hme_param_speed = 1; 12637c478bd9Sstevel@tonic-gate else 12647c478bd9Sstevel@tonic-gate hme_param_speed = 0; 12657c478bd9Sstevel@tonic-gate 12667c478bd9Sstevel@tonic-gate 12677c478bd9Sstevel@tonic-gate if (!(hmep->hme_aner & PHY_ANER_LPNW)) { 12687c478bd9Sstevel@tonic-gate hme_param_aner_lpancap = 0; 12697c478bd9Sstevel@tonic-gate hme_param_anlpar_100T4 = 0; 12707c478bd9Sstevel@tonic-gate hme_param_anlpar_100fdx = 0; 12717c478bd9Sstevel@tonic-gate hme_param_anlpar_100hdx = 0; 12727c478bd9Sstevel@tonic-gate hme_param_anlpar_10fdx = 0; 12737c478bd9Sstevel@tonic-gate hme_param_anlpar_10hdx = 0; 12747c478bd9Sstevel@tonic-gate return; 12757c478bd9Sstevel@tonic-gate } 12767c478bd9Sstevel@tonic-gate hme_param_aner_lpancap = 1; 12777c478bd9Sstevel@tonic-gate tmp = hmep->hme_anlpar; 12787c478bd9Sstevel@tonic-gate if (tmp & PHY_ANLPAR_T4) 12797c478bd9Sstevel@tonic-gate hme_param_anlpar_100T4 = 1; 12807c478bd9Sstevel@tonic-gate else 12817c478bd9Sstevel@tonic-gate hme_param_anlpar_100T4 = 0; 12827c478bd9Sstevel@tonic-gate if (tmp & PHY_ANLPAR_TXFDX) 12837c478bd9Sstevel@tonic-gate hme_param_anlpar_100fdx = 1; 12847c478bd9Sstevel@tonic-gate else 12857c478bd9Sstevel@tonic-gate hme_param_anlpar_100fdx = 0; 12867c478bd9Sstevel@tonic-gate if (tmp & PHY_ANLPAR_TX) 12877c478bd9Sstevel@tonic-gate hme_param_anlpar_100hdx = 1; 12887c478bd9Sstevel@tonic-gate else 12897c478bd9Sstevel@tonic-gate hme_param_anlpar_100hdx = 0; 12907c478bd9Sstevel@tonic-gate if (tmp & PHY_ANLPAR_10FDX) 12917c478bd9Sstevel@tonic-gate hme_param_anlpar_10fdx = 1; 12927c478bd9Sstevel@tonic-gate else 12937c478bd9Sstevel@tonic-gate hme_param_anlpar_10fdx = 0; 12947c478bd9Sstevel@tonic-gate if (tmp & PHY_ANLPAR_10) 12957c478bd9Sstevel@tonic-gate hme_param_anlpar_10hdx = 1; 12967c478bd9Sstevel@tonic-gate else 12977c478bd9Sstevel@tonic-gate hme_param_anlpar_10hdx = 0; 12987c478bd9Sstevel@tonic-gate } 12997c478bd9Sstevel@tonic-gate 13007c478bd9Sstevel@tonic-gate static void 13017c478bd9Sstevel@tonic-gate hme_setup_link_control(struct hme *hmep) 13027c478bd9Sstevel@tonic-gate { 1303*0219346bSGarrett D'Amore uint16_t anar = PHY_SELECTOR; 13047c478bd9Sstevel@tonic-gate uint32_t autoneg = ~HME_NOTUSR & hme_param_autoneg; 13057c478bd9Sstevel@tonic-gate uint32_t anar_100T4 = ~HME_NOTUSR & hme_param_anar_100T4; 13067c478bd9Sstevel@tonic-gate uint32_t anar_100fdx = ~HME_NOTUSR & hme_param_anar_100fdx; 13077c478bd9Sstevel@tonic-gate uint32_t anar_100hdx = ~HME_NOTUSR & hme_param_anar_100hdx; 13087c478bd9Sstevel@tonic-gate uint32_t anar_10fdx = ~HME_NOTUSR & hme_param_anar_10fdx; 13097c478bd9Sstevel@tonic-gate uint32_t anar_10hdx = ~HME_NOTUSR & hme_param_anar_10hdx; 13107c478bd9Sstevel@tonic-gate 13117c478bd9Sstevel@tonic-gate if (autoneg) { 13127c478bd9Sstevel@tonic-gate hmep->hme_mode = HME_AUTO_SPEED; 13137c478bd9Sstevel@tonic-gate hmep->hme_tryspeed = HME_SPEED_100; 13147c478bd9Sstevel@tonic-gate if (anar_100T4) 13157c478bd9Sstevel@tonic-gate anar |= PHY_ANAR_T4; 13167c478bd9Sstevel@tonic-gate if (anar_100fdx) 13177c478bd9Sstevel@tonic-gate anar |= PHY_ANAR_TXFDX; 13187c478bd9Sstevel@tonic-gate if (anar_100hdx) 13197c478bd9Sstevel@tonic-gate anar |= PHY_ANAR_TX; 13207c478bd9Sstevel@tonic-gate if (anar_10fdx) 13217c478bd9Sstevel@tonic-gate anar |= PHY_ANAR_10FDX; 13227c478bd9Sstevel@tonic-gate if (anar_10hdx) 13237c478bd9Sstevel@tonic-gate anar |= PHY_ANAR_10; 13247c478bd9Sstevel@tonic-gate hmep->hme_anar = anar; 13257c478bd9Sstevel@tonic-gate } else { 13267c478bd9Sstevel@tonic-gate hmep->hme_mode = HME_FORCE_SPEED; 13277c478bd9Sstevel@tonic-gate if (anar_100T4) { 13287c478bd9Sstevel@tonic-gate hmep->hme_forcespeed = HME_SPEED_100; 13297c478bd9Sstevel@tonic-gate hmep->hme_fdx = HME_HALF_DUPLEX; 13307c478bd9Sstevel@tonic-gate 13317c478bd9Sstevel@tonic-gate } else if (anar_100fdx) { 13327c478bd9Sstevel@tonic-gate /* 100fdx needs to be checked first for 100BaseFX */ 13337c478bd9Sstevel@tonic-gate hmep->hme_forcespeed = HME_SPEED_100; 13347c478bd9Sstevel@tonic-gate hmep->hme_fdx = HME_FULL_DUPLEX; 13357c478bd9Sstevel@tonic-gate 13367c478bd9Sstevel@tonic-gate } else if (anar_100hdx) { 13377c478bd9Sstevel@tonic-gate hmep->hme_forcespeed = HME_SPEED_100; 13387c478bd9Sstevel@tonic-gate hmep->hme_fdx = HME_HALF_DUPLEX; 13397c478bd9Sstevel@tonic-gate } else if (anar_10hdx) { 13407c478bd9Sstevel@tonic-gate /* 10hdx needs to be checked first for MII-AUI */ 13417c478bd9Sstevel@tonic-gate /* MII-AUI BugIds 1252776,4032280,4035106,4028558 */ 13427c478bd9Sstevel@tonic-gate hmep->hme_forcespeed = HME_SPEED_10; 13437c478bd9Sstevel@tonic-gate hmep->hme_fdx = HME_HALF_DUPLEX; 13447c478bd9Sstevel@tonic-gate 13457c478bd9Sstevel@tonic-gate } else if (anar_10fdx) { 13467c478bd9Sstevel@tonic-gate hmep->hme_forcespeed = HME_SPEED_10; 13477c478bd9Sstevel@tonic-gate hmep->hme_fdx = HME_FULL_DUPLEX; 13487c478bd9Sstevel@tonic-gate 13497c478bd9Sstevel@tonic-gate } else { 13507c478bd9Sstevel@tonic-gate hmep->hme_forcespeed = HME_SPEED_10; 13517c478bd9Sstevel@tonic-gate hmep->hme_fdx = HME_HALF_DUPLEX; 13527c478bd9Sstevel@tonic-gate } 13537c478bd9Sstevel@tonic-gate } 13547c478bd9Sstevel@tonic-gate } 13557c478bd9Sstevel@tonic-gate 13567c478bd9Sstevel@tonic-gate /* Decide if transmitter went dead and reinitialize everything */ 13577c478bd9Sstevel@tonic-gate static int hme_txhung_limit = 3; 13587c478bd9Sstevel@tonic-gate static int 13597c478bd9Sstevel@tonic-gate hme_check_txhung(struct hme *hmep) 13607c478bd9Sstevel@tonic-gate { 13617c478bd9Sstevel@tonic-gate boolean_t status; 13627c478bd9Sstevel@tonic-gate 13637c478bd9Sstevel@tonic-gate mutex_enter(&hmep->hme_xmitlock); 13647c478bd9Sstevel@tonic-gate if (hmep->hme_flags & HMERUNNING) 13657c478bd9Sstevel@tonic-gate hmereclaim(hmep); 13667c478bd9Sstevel@tonic-gate 13677c478bd9Sstevel@tonic-gate /* Something needs to be sent out but it is not going out */ 1368*0219346bSGarrett D'Amore if ((hmep->hme_txindex != hmep->hme_txreclaim) && 13697c478bd9Sstevel@tonic-gate (hmep->hme_opackets == hmep->hmesave.hme_opackets)) 13707c478bd9Sstevel@tonic-gate hmep->hme_txhung++; 13717c478bd9Sstevel@tonic-gate else 13727c478bd9Sstevel@tonic-gate hmep->hme_txhung = 0; 13737c478bd9Sstevel@tonic-gate 13747c478bd9Sstevel@tonic-gate hmep->hmesave.hme_opackets = hmep->hme_opackets; 13757c478bd9Sstevel@tonic-gate 13767c478bd9Sstevel@tonic-gate status = hmep->hme_txhung >= hme_txhung_limit; 13777c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_xmitlock); 13787c478bd9Sstevel@tonic-gate 13797c478bd9Sstevel@tonic-gate return (status); 13807c478bd9Sstevel@tonic-gate } 13817c478bd9Sstevel@tonic-gate 13827c478bd9Sstevel@tonic-gate /* 13837c478bd9Sstevel@tonic-gate * hme_check_link () 13847c478bd9Sstevel@tonic-gate * Called as a result of HME_LINKCHECK_TIMER timeout, to poll for Transceiver 13857c478bd9Sstevel@tonic-gate * change or when a transceiver change has been detected by the hme_try_speed 13867c478bd9Sstevel@tonic-gate * function. 13877c478bd9Sstevel@tonic-gate * This function will also be called from the interrupt handler when polled mode 13887c478bd9Sstevel@tonic-gate * is used. Before calling this function the interrupt lock should be freed 13897c478bd9Sstevel@tonic-gate * so that the hmeinit() may be called. 13907c478bd9Sstevel@tonic-gate * Note that the hmeinit() function calls hme_select_speed() to set the link 13917c478bd9Sstevel@tonic-gate * speed and check for link status. 13927c478bd9Sstevel@tonic-gate */ 13937c478bd9Sstevel@tonic-gate 13947c478bd9Sstevel@tonic-gate static void 13957c478bd9Sstevel@tonic-gate hme_check_link(void *arg) 13967c478bd9Sstevel@tonic-gate { 13977c478bd9Sstevel@tonic-gate struct hme *hmep = arg; 13987c478bd9Sstevel@tonic-gate uint16_t stat; 13997c478bd9Sstevel@tonic-gate uint_t temp; 14007c478bd9Sstevel@tonic-gate 14017c478bd9Sstevel@tonic-gate hme_stop_timer(hmep); /* acquire hme_linklock */ 14027c478bd9Sstevel@tonic-gate 14037c478bd9Sstevel@tonic-gate /* 14047c478bd9Sstevel@tonic-gate * This condition was added to work around for 14057c478bd9Sstevel@tonic-gate * a problem with the Synoptics/Bay 28115 switch. 14067c478bd9Sstevel@tonic-gate * Basically if the link is up but no packets 14077c478bd9Sstevel@tonic-gate * are being received. This can be checked using 14087c478bd9Sstevel@tonic-gate * ipackets, which in case of reception will 14097c478bd9Sstevel@tonic-gate * continue to increment after 'hmep->hme_iipackets' 14107c478bd9Sstevel@tonic-gate * has been made equal to it and the 'hme_check_link' 14117c478bd9Sstevel@tonic-gate * timer has expired. Note this could also be done 14127c478bd9Sstevel@tonic-gate * if there's no traffic on the net. 14137c478bd9Sstevel@tonic-gate * 'hmep->hme_ipackets' is incremented in hme_read 14147c478bd9Sstevel@tonic-gate * for successfully received packets. 14157c478bd9Sstevel@tonic-gate */ 14167c478bd9Sstevel@tonic-gate if ((hmep->hme_flags & HMERUNNING) && (hmep->hme_linkup)) { 14177c478bd9Sstevel@tonic-gate if (hmep->hme_ipackets != hmep->hme_iipackets) 14187c478bd9Sstevel@tonic-gate /* 14197c478bd9Sstevel@tonic-gate * Receptions are occurring set 'hmep->hme_iipackets' 14207c478bd9Sstevel@tonic-gate * to 'hmep->hme_ipackets' to monitor if receptions 14217c478bd9Sstevel@tonic-gate * occur during the next timeout interval. 14227c478bd9Sstevel@tonic-gate */ 14237c478bd9Sstevel@tonic-gate hmep->hme_iipackets = hmep->hme_ipackets; 14247c478bd9Sstevel@tonic-gate else 14257c478bd9Sstevel@tonic-gate /* 14267c478bd9Sstevel@tonic-gate * Receptions not occurring could be due to 14277c478bd9Sstevel@tonic-gate * Synoptics problem, try switchin of data 14287c478bd9Sstevel@tonic-gate * scrabbling. That should bring up the link. 14297c478bd9Sstevel@tonic-gate */ 14307c478bd9Sstevel@tonic-gate hme_link_now_up(hmep); 14317c478bd9Sstevel@tonic-gate } 14327c478bd9Sstevel@tonic-gate 14337c478bd9Sstevel@tonic-gate if ((hmep->hme_flags & HMERUNNING) && 14347c478bd9Sstevel@tonic-gate (hmep->hme_linkup) && (hme_check_txhung(hmep))) { 14357c478bd9Sstevel@tonic-gate 14367c478bd9Sstevel@tonic-gate hme_start_timer(hmep, hme_check_link, HME_LINKCHECK_TIMER); 14377c478bd9Sstevel@tonic-gate (void) hmeinit(hmep); /* To reset the transceiver and */ 14387c478bd9Sstevel@tonic-gate /* to init the interface */ 14397c478bd9Sstevel@tonic-gate return; 14407c478bd9Sstevel@tonic-gate } 14417c478bd9Sstevel@tonic-gate 14427c478bd9Sstevel@tonic-gate /* 14437c478bd9Sstevel@tonic-gate * check if the transceiver is the same. 14447c478bd9Sstevel@tonic-gate * init to be done if the external transceiver is 14457c478bd9Sstevel@tonic-gate * connected/disconnected 14467c478bd9Sstevel@tonic-gate */ 14477c478bd9Sstevel@tonic-gate temp = hmep->hme_transceiver; /* save the transceiver type */ 14487c478bd9Sstevel@tonic-gate hme_check_transceiver(hmep); 14497c478bd9Sstevel@tonic-gate if ((temp != hmep->hme_transceiver) || (hmep->hme_linkup == 0)) { 14507c478bd9Sstevel@tonic-gate if (temp != hmep->hme_transceiver) { 14517c478bd9Sstevel@tonic-gate if (hmep->hme_transceiver == HME_EXTERNAL_TRANSCEIVER) { 14527c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, 145385025c03Sgd XCVR_MSG, ext_xcvr_msg); 14547c478bd9Sstevel@tonic-gate } else { 14557c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, 145685025c03Sgd XCVR_MSG, int_xcvr_msg); 14577c478bd9Sstevel@tonic-gate } 14587c478bd9Sstevel@tonic-gate } 14597c478bd9Sstevel@tonic-gate hmep->hme_linkcheck = 0; 14607c478bd9Sstevel@tonic-gate hme_start_timer(hmep, hme_check_link, HME_LINKCHECK_TIMER); 146185025c03Sgd (void) hmeinit(hmep); /* To reset xcvr and init interface */ 14627c478bd9Sstevel@tonic-gate return; 14637c478bd9Sstevel@tonic-gate } 14647c478bd9Sstevel@tonic-gate 14657c478bd9Sstevel@tonic-gate 14667c478bd9Sstevel@tonic-gate if (hmep->hme_mifpoll_enable) { 14677c478bd9Sstevel@tonic-gate stat = (GET_MIFREG(mif_bsts) >> 16); 14687c478bd9Sstevel@tonic-gate 14697c478bd9Sstevel@tonic-gate CHECK_MIFREG(); /* Verify */ 14707c478bd9Sstevel@tonic-gate 14717c478bd9Sstevel@tonic-gate if (!hmep->hme_mifpoll_flag) { 14727c478bd9Sstevel@tonic-gate if (stat & PHY_BMSR_LNKSTS) { 14737c478bd9Sstevel@tonic-gate hme_start_timer(hmep, hme_check_link, 147485025c03Sgd HME_LINKCHECK_TIMER); 14757c478bd9Sstevel@tonic-gate return; 14767c478bd9Sstevel@tonic-gate } 14777c478bd9Sstevel@tonic-gate hme_stop_mifpoll(hmep); 14787c478bd9Sstevel@tonic-gate 14797c478bd9Sstevel@tonic-gate temp = (GET_MIFREG(mif_bsts) >> 16); 14807c478bd9Sstevel@tonic-gate } else { 14817c478bd9Sstevel@tonic-gate hmep->hme_mifpoll_flag = 0; 14827c478bd9Sstevel@tonic-gate } 14837c478bd9Sstevel@tonic-gate } else { 14847c478bd9Sstevel@tonic-gate if (hme_mii_read(hmep, HME_PHY_BMSR, &stat) == 1) { 14857c478bd9Sstevel@tonic-gate /* Transceiver does not talk mii */ 14867c478bd9Sstevel@tonic-gate hme_start_timer(hmep, hme_check_link, 148785025c03Sgd HME_LINKCHECK_TIMER); 14887c478bd9Sstevel@tonic-gate return; 14897c478bd9Sstevel@tonic-gate } 14907c478bd9Sstevel@tonic-gate 14917c478bd9Sstevel@tonic-gate if (stat & PHY_BMSR_LNKSTS) { 14927c478bd9Sstevel@tonic-gate hme_start_timer(hmep, hme_check_link, 149385025c03Sgd HME_LINKCHECK_TIMER); 14947c478bd9Sstevel@tonic-gate return; 14957c478bd9Sstevel@tonic-gate } 14967c478bd9Sstevel@tonic-gate } 14977c478bd9Sstevel@tonic-gate 14987c478bd9Sstevel@tonic-gate (void) hme_mii_read(hmep, HME_PHY_BMSR, &stat); 149985025c03Sgd 15007c478bd9Sstevel@tonic-gate /* 15017c478bd9Sstevel@tonic-gate * The PHY may have automatically renegotiated link speed and mode. 15027c478bd9Sstevel@tonic-gate * Get the new link speed and mode. 15037c478bd9Sstevel@tonic-gate */ 15047c478bd9Sstevel@tonic-gate if ((stat & PHY_BMSR_LNKSTS) && hme_autoneg_enable) { 15057c478bd9Sstevel@tonic-gate if (hmep->hme_mode == HME_AUTO_SPEED) { 15067c478bd9Sstevel@tonic-gate (void) hme_get_autoinfo(hmep); 15077c478bd9Sstevel@tonic-gate hme_setup_link_status(hmep); 15087c478bd9Sstevel@tonic-gate hme_start_mifpoll(hmep); 15097c478bd9Sstevel@tonic-gate if (hmep->hme_fdx != hmep->hme_macfdx) { 15107c478bd9Sstevel@tonic-gate hme_start_timer(hmep, hme_check_link, 151185025c03Sgd HME_LINKCHECK_TIMER); 15127c478bd9Sstevel@tonic-gate (void) hmeinit(hmep); 15137c478bd9Sstevel@tonic-gate return; 15147c478bd9Sstevel@tonic-gate } 15157c478bd9Sstevel@tonic-gate } 15167c478bd9Sstevel@tonic-gate hme_start_mifpoll(hmep); 15177c478bd9Sstevel@tonic-gate hme_start_timer(hmep, hme_check_link, HME_LINKCHECK_TIMER); 15187c478bd9Sstevel@tonic-gate return; 15197c478bd9Sstevel@tonic-gate } 15207c478bd9Sstevel@tonic-gate /* Reset the PHY and bring up the link */ 15217c478bd9Sstevel@tonic-gate hme_reset_transceiver(hmep); 15227c478bd9Sstevel@tonic-gate } 15237c478bd9Sstevel@tonic-gate 15247c478bd9Sstevel@tonic-gate static void 15257c478bd9Sstevel@tonic-gate hme_init_xcvr_info(struct hme *hmep) 15267c478bd9Sstevel@tonic-gate { 15277c478bd9Sstevel@tonic-gate uint16_t phy_id1, phy_id2; 15287c478bd9Sstevel@tonic-gate 15297c478bd9Sstevel@tonic-gate (void) hme_mii_read(hmep, HME_PHY_IDR1, &phy_id1); 15307c478bd9Sstevel@tonic-gate (void) hme_mii_read(hmep, HME_PHY_IDR2, &phy_id2); 15317c478bd9Sstevel@tonic-gate } 15327c478bd9Sstevel@tonic-gate 15337c478bd9Sstevel@tonic-gate /* 15347c478bd9Sstevel@tonic-gate * Disable link pulses for the Internal Transceiver 15357c478bd9Sstevel@tonic-gate */ 15367c478bd9Sstevel@tonic-gate 15377c478bd9Sstevel@tonic-gate static void 15387c478bd9Sstevel@tonic-gate hme_disable_link_pulse(struct hme *hmep) 15397c478bd9Sstevel@tonic-gate { 15407c478bd9Sstevel@tonic-gate uint16_t nicr; 15417c478bd9Sstevel@tonic-gate 15427c478bd9Sstevel@tonic-gate hme_mii_write(hmep, HME_PHY_BMCR, 0); /* force 10 Mbps */ 15437c478bd9Sstevel@tonic-gate (void) hme_mii_read(hmep, HME_PHY_NICR, &nicr); 15447c478bd9Sstevel@tonic-gate 15457c478bd9Sstevel@tonic-gate hme_mii_write(hmep, HME_PHY_NICR, (nicr & ~PHY_NICR_LD)); 15467c478bd9Sstevel@tonic-gate 15477c478bd9Sstevel@tonic-gate hmep->hme_linkup = 1; 15487c478bd9Sstevel@tonic-gate hmep->hme_linkcheck = 1; 15497c478bd9Sstevel@tonic-gate hme_setup_link_status(hmep); 15507c478bd9Sstevel@tonic-gate hme_start_mifpoll(hmep); 15517c478bd9Sstevel@tonic-gate hme_start_timer(hmep, hme_check_link, HME_LINKCHECK_TIMER); 15527c478bd9Sstevel@tonic-gate } 15537c478bd9Sstevel@tonic-gate 15547c478bd9Sstevel@tonic-gate static void 15557c478bd9Sstevel@tonic-gate hme_force_speed(void *arg) 15567c478bd9Sstevel@tonic-gate { 15577c478bd9Sstevel@tonic-gate struct hme *hmep = arg; 15587c478bd9Sstevel@tonic-gate int linkup; 15597c478bd9Sstevel@tonic-gate uint_t temp; 15607c478bd9Sstevel@tonic-gate uint16_t csc; 15617c478bd9Sstevel@tonic-gate 15627c478bd9Sstevel@tonic-gate hme_stop_timer(hmep); 15637c478bd9Sstevel@tonic-gate if (hmep->hme_fdx != hmep->hme_macfdx) { 15647c478bd9Sstevel@tonic-gate hme_start_timer(hmep, hme_check_link, HME_TICKS*5); 15657c478bd9Sstevel@tonic-gate return; 15667c478bd9Sstevel@tonic-gate } 15677c478bd9Sstevel@tonic-gate temp = hmep->hme_transceiver; /* save the transceiver type */ 15687c478bd9Sstevel@tonic-gate hme_check_transceiver(hmep); 15697c478bd9Sstevel@tonic-gate if (temp != hmep->hme_transceiver) { 15707c478bd9Sstevel@tonic-gate if (hmep->hme_transceiver == HME_EXTERNAL_TRANSCEIVER) { 15717c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, XCVR_MSG, 157285025c03Sgd ext_xcvr_msg); 15737c478bd9Sstevel@tonic-gate } else { 15747c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, XCVR_MSG, 157585025c03Sgd int_xcvr_msg); 15767c478bd9Sstevel@tonic-gate } 15777c478bd9Sstevel@tonic-gate hme_start_timer(hmep, hme_check_link, HME_TICKS * 10); 15787c478bd9Sstevel@tonic-gate return; 15797c478bd9Sstevel@tonic-gate } 15807c478bd9Sstevel@tonic-gate 15817c478bd9Sstevel@tonic-gate if ((hmep->hme_transceiver == HME_INTERNAL_TRANSCEIVER) && 158285025c03Sgd (hmep->hme_link_pulse_disabled)) { 15837c478bd9Sstevel@tonic-gate hmep->hme_forcespeed = HME_SPEED_10; 15847c478bd9Sstevel@tonic-gate hme_disable_link_pulse(hmep); 15857c478bd9Sstevel@tonic-gate return; 15867c478bd9Sstevel@tonic-gate } 15877c478bd9Sstevel@tonic-gate 15887c478bd9Sstevel@tonic-gate /* 15897c478bd9Sstevel@tonic-gate * To interoperate with auto-negotiable capable systems 15907c478bd9Sstevel@tonic-gate * the link should be brought down for 1 second. 15917c478bd9Sstevel@tonic-gate * How to do this using only standard registers ? 15927c478bd9Sstevel@tonic-gate */ 15937c478bd9Sstevel@tonic-gate if (HME_DP83840) { 15947c478bd9Sstevel@tonic-gate if (hmep->hme_force_linkdown == HME_FORCE_LINKDOWN) { 15957c478bd9Sstevel@tonic-gate hmep->hme_force_linkdown = HME_LINKDOWN_STARTED; 15967c478bd9Sstevel@tonic-gate hme_mii_write(hmep, HME_PHY_BMCR, PHY_BMCR_100M); 15977c478bd9Sstevel@tonic-gate (void) hme_mii_read(hmep, HME_PHY_CSC, &csc); 15987c478bd9Sstevel@tonic-gate hme_mii_write(hmep, HME_PHY_CSC, 159985025c03Sgd (csc | PHY_CSCR_TXOFF)); 16007c478bd9Sstevel@tonic-gate hme_start_timer(hmep, hme_force_speed, 10 * HME_TICKS); 16017c478bd9Sstevel@tonic-gate return; 16027c478bd9Sstevel@tonic-gate } else if (hmep->hme_force_linkdown == HME_LINKDOWN_STARTED) { 16037c478bd9Sstevel@tonic-gate (void) hme_mii_read(hmep, HME_PHY_CSC, &csc); 16047c478bd9Sstevel@tonic-gate hme_mii_write(hmep, HME_PHY_CSC, 160585025c03Sgd (csc & ~PHY_CSCR_TXOFF)); 16067c478bd9Sstevel@tonic-gate hmep->hme_force_linkdown = HME_LINKDOWN_DONE; 16077c478bd9Sstevel@tonic-gate } 16087c478bd9Sstevel@tonic-gate } else { 16097c478bd9Sstevel@tonic-gate if (hmep->hme_force_linkdown == HME_FORCE_LINKDOWN) { 16107c478bd9Sstevel@tonic-gate hmep->hme_force_linkdown = HME_LINKDOWN_STARTED; 16117c478bd9Sstevel@tonic-gate hme_mii_write(hmep, HME_PHY_BMCR, PHY_BMCR_LPBK); 16127c478bd9Sstevel@tonic-gate hme_start_timer(hmep, hme_force_speed, 10 * HME_TICKS); 16137c478bd9Sstevel@tonic-gate return; 16147c478bd9Sstevel@tonic-gate } else if (hmep->hme_force_linkdown == HME_LINKDOWN_STARTED) { 16157c478bd9Sstevel@tonic-gate hmep->hme_force_linkdown = HME_LINKDOWN_DONE; 16167c478bd9Sstevel@tonic-gate } 16177c478bd9Sstevel@tonic-gate } 16187c478bd9Sstevel@tonic-gate 16197c478bd9Sstevel@tonic-gate 16207c478bd9Sstevel@tonic-gate linkup = hme_select_speed(hmep, hmep->hme_forcespeed); 16217c478bd9Sstevel@tonic-gate if (hmep->hme_linkup_cnt == 1) { 16227c478bd9Sstevel@tonic-gate hme_start_timer(hmep, hme_force_speed, SECOND(4)); 16237c478bd9Sstevel@tonic-gate return; 16247c478bd9Sstevel@tonic-gate } 16257c478bd9Sstevel@tonic-gate if (linkup) { 16267c478bd9Sstevel@tonic-gate 16277c478bd9Sstevel@tonic-gate hmep->hme_linkup = 1; 16287c478bd9Sstevel@tonic-gate hmep->hme_linkcheck = 1; 16297c478bd9Sstevel@tonic-gate hmep->hme_ifspeed = hmep->hme_forcespeed; 16307c478bd9Sstevel@tonic-gate hme_link_now_up(hmep); 16317c478bd9Sstevel@tonic-gate hme_setup_link_status(hmep); 16327c478bd9Sstevel@tonic-gate hme_start_mifpoll(hmep); 16337c478bd9Sstevel@tonic-gate hme_start_timer(hmep, hme_check_link, HME_LINKCHECK_TIMER); 16347c478bd9Sstevel@tonic-gate } else { 16357c478bd9Sstevel@tonic-gate hme_start_timer(hmep, hme_force_speed, HME_TICKS); 16367c478bd9Sstevel@tonic-gate } 16377c478bd9Sstevel@tonic-gate } 16387c478bd9Sstevel@tonic-gate 16397c478bd9Sstevel@tonic-gate static void 16407c478bd9Sstevel@tonic-gate hme_get_autoinfo(struct hme *hmep) 16417c478bd9Sstevel@tonic-gate { 16427c478bd9Sstevel@tonic-gate uint16_t anar; 16437c478bd9Sstevel@tonic-gate uint16_t aner; 16447c478bd9Sstevel@tonic-gate uint16_t anlpar; 16457c478bd9Sstevel@tonic-gate uint16_t tmp; 16467c478bd9Sstevel@tonic-gate uint16_t ar; 16477c478bd9Sstevel@tonic-gate 16487c478bd9Sstevel@tonic-gate (void) hme_mii_read(hmep, HME_PHY_ANER, &aner); 16497c478bd9Sstevel@tonic-gate (void) hme_mii_read(hmep, HME_PHY_ANLPAR, &anlpar); 16507c478bd9Sstevel@tonic-gate (void) hme_mii_read(hmep, HME_PHY_ANAR, &anar); 16517c478bd9Sstevel@tonic-gate 16527c478bd9Sstevel@tonic-gate hmep->hme_anlpar = anlpar; 16537c478bd9Sstevel@tonic-gate hmep->hme_aner = aner; 16547c478bd9Sstevel@tonic-gate 16557c478bd9Sstevel@tonic-gate if (aner & PHY_ANER_LPNW) { 16567c478bd9Sstevel@tonic-gate 16577c478bd9Sstevel@tonic-gate tmp = anar & anlpar; 16587c478bd9Sstevel@tonic-gate if (tmp & PHY_ANAR_TXFDX) { 16597c478bd9Sstevel@tonic-gate hmep->hme_tryspeed = HME_SPEED_100; 16607c478bd9Sstevel@tonic-gate hmep->hme_fdx = HME_FULL_DUPLEX; 16617c478bd9Sstevel@tonic-gate } else if (tmp & PHY_ANAR_TX) { 16627c478bd9Sstevel@tonic-gate hmep->hme_tryspeed = HME_SPEED_100; 16637c478bd9Sstevel@tonic-gate hmep->hme_fdx = HME_HALF_DUPLEX; 16647c478bd9Sstevel@tonic-gate } else if (tmp & PHY_ANLPAR_10FDX) { 16657c478bd9Sstevel@tonic-gate hmep->hme_tryspeed = HME_SPEED_10; 16667c478bd9Sstevel@tonic-gate hmep->hme_fdx = HME_FULL_DUPLEX; 16677c478bd9Sstevel@tonic-gate } else if (tmp & PHY_ANLPAR_10) { 16687c478bd9Sstevel@tonic-gate hmep->hme_tryspeed = HME_SPEED_10; 16697c478bd9Sstevel@tonic-gate hmep->hme_fdx = HME_HALF_DUPLEX; 16707c478bd9Sstevel@tonic-gate } else { 16717c478bd9Sstevel@tonic-gate if (HME_DP83840) { 16727c478bd9Sstevel@tonic-gate 16737c478bd9Sstevel@tonic-gate hmep->hme_fdx = HME_HALF_DUPLEX; 16747c478bd9Sstevel@tonic-gate (void) hme_mii_read(hmep, HME_PHY_AR, &ar); 16757c478bd9Sstevel@tonic-gate 16767c478bd9Sstevel@tonic-gate if (ar & PHY_AR_SPEED10) 16777c478bd9Sstevel@tonic-gate hmep->hme_tryspeed = HME_SPEED_10; 16787c478bd9Sstevel@tonic-gate else 16797c478bd9Sstevel@tonic-gate hmep->hme_tryspeed = HME_SPEED_100; 16807c478bd9Sstevel@tonic-gate } else 16817c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, 168285025c03Sgd AUTONEG_MSG, anar_not_set_msg); 16837c478bd9Sstevel@tonic-gate } 16847c478bd9Sstevel@tonic-gate } else { 16857c478bd9Sstevel@tonic-gate hmep->hme_fdx = HME_HALF_DUPLEX; 16867c478bd9Sstevel@tonic-gate if (anlpar & PHY_ANLPAR_TX) 16877c478bd9Sstevel@tonic-gate hmep->hme_tryspeed = HME_SPEED_100; 16887c478bd9Sstevel@tonic-gate else if (anlpar & PHY_ANLPAR_10) 16897c478bd9Sstevel@tonic-gate hmep->hme_tryspeed = HME_SPEED_10; 16907c478bd9Sstevel@tonic-gate else { 16917c478bd9Sstevel@tonic-gate if (HME_DP83840) { 16927c478bd9Sstevel@tonic-gate 16937c478bd9Sstevel@tonic-gate (void) hme_mii_read(hmep, HME_PHY_AR, &ar); 16947c478bd9Sstevel@tonic-gate 16957c478bd9Sstevel@tonic-gate if (ar & PHY_AR_SPEED10) 16967c478bd9Sstevel@tonic-gate hmep->hme_tryspeed = HME_SPEED_10; 16977c478bd9Sstevel@tonic-gate else 16987c478bd9Sstevel@tonic-gate hmep->hme_tryspeed = HME_SPEED_100; 16997c478bd9Sstevel@tonic-gate } else 17007c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, 170185025c03Sgd AUTONEG_MSG, par_detect_anar_not_set_msg); 17027c478bd9Sstevel@tonic-gate } 17037c478bd9Sstevel@tonic-gate } 17047c478bd9Sstevel@tonic-gate 17057c478bd9Sstevel@tonic-gate hmep->hme_linkup = 1; 17067c478bd9Sstevel@tonic-gate hmep->hme_linkcheck = 1; 17077c478bd9Sstevel@tonic-gate hmep->hme_ifspeed = hmep->hme_tryspeed; 17087c478bd9Sstevel@tonic-gate hme_link_now_up(hmep); 17097c478bd9Sstevel@tonic-gate } 17107c478bd9Sstevel@tonic-gate 17117c478bd9Sstevel@tonic-gate /* 17127c478bd9Sstevel@tonic-gate * Return 1 if the link is up or auto-negotiation being tried, 0 otherwise. 17137c478bd9Sstevel@tonic-gate */ 17147c478bd9Sstevel@tonic-gate 17157c478bd9Sstevel@tonic-gate static int 17167c478bd9Sstevel@tonic-gate hme_try_auto_negotiation(struct hme *hmep) 17177c478bd9Sstevel@tonic-gate { 17187c478bd9Sstevel@tonic-gate uint16_t stat; 17197c478bd9Sstevel@tonic-gate uint16_t aner; 17207c478bd9Sstevel@tonic-gate 17217c478bd9Sstevel@tonic-gate if (hmep->hme_autoneg == HME_HWAN_TRY) { 17227c478bd9Sstevel@tonic-gate /* auto negotiation not initiated */ 17237c478bd9Sstevel@tonic-gate (void) hme_mii_read(hmep, HME_PHY_BMSR, &stat); 17247c478bd9Sstevel@tonic-gate if (hme_mii_read(hmep, HME_PHY_BMSR, &stat) == 1) { 17257c478bd9Sstevel@tonic-gate /* 17267c478bd9Sstevel@tonic-gate * Transceiver does not talk mii 17277c478bd9Sstevel@tonic-gate */ 17287c478bd9Sstevel@tonic-gate goto hme_anfail; 17297c478bd9Sstevel@tonic-gate } 17307c478bd9Sstevel@tonic-gate if ((stat & PHY_BMSR_ACFG) == 0) { /* auto neg. not supported */ 17317c478bd9Sstevel@tonic-gate 17327c478bd9Sstevel@tonic-gate return (hmep->hme_autoneg = HME_HWAN_FAILED); 17337c478bd9Sstevel@tonic-gate } 17347c478bd9Sstevel@tonic-gate 17357c478bd9Sstevel@tonic-gate /* 17367c478bd9Sstevel@tonic-gate * Read ANER to clear status from previous operations. 17377c478bd9Sstevel@tonic-gate */ 17387c478bd9Sstevel@tonic-gate if (hme_mii_read(hmep, HME_PHY_ANER, &aner) == 1) { 17397c478bd9Sstevel@tonic-gate /* 17407c478bd9Sstevel@tonic-gate * Transceiver does not talk mii 17417c478bd9Sstevel@tonic-gate */ 17427c478bd9Sstevel@tonic-gate goto hme_anfail; 17437c478bd9Sstevel@tonic-gate } 17447c478bd9Sstevel@tonic-gate 17457c478bd9Sstevel@tonic-gate hme_mii_write(hmep, HME_PHY_ANAR, hmep->hme_anar); 17467c478bd9Sstevel@tonic-gate hme_mii_write(hmep, HME_PHY_BMCR, PHY_BMCR_ANE | PHY_BMCR_RAN); 17477c478bd9Sstevel@tonic-gate /* 17487c478bd9Sstevel@tonic-gate * auto-negotiation initiated 17497c478bd9Sstevel@tonic-gate */ 17507c478bd9Sstevel@tonic-gate hmep->hme_delay = 0; 17517c478bd9Sstevel@tonic-gate hme_start_timer(hmep, hme_try_speed, HME_TICKS); 17527c478bd9Sstevel@tonic-gate return (hmep->hme_autoneg = HME_HWAN_INPROGRESS); 17537c478bd9Sstevel@tonic-gate /* 17547c478bd9Sstevel@tonic-gate * auto-negotiation in progress 17557c478bd9Sstevel@tonic-gate */ 17567c478bd9Sstevel@tonic-gate } 17577c478bd9Sstevel@tonic-gate 17587c478bd9Sstevel@tonic-gate /* 17597c478bd9Sstevel@tonic-gate * Auto-negotiation has been in progress. Wait for at least 17607c478bd9Sstevel@tonic-gate * least 3000 ms. 17617c478bd9Sstevel@tonic-gate * Changed 8/28/97 to fix bug ID 4070989. 17627c478bd9Sstevel@tonic-gate */ 17637c478bd9Sstevel@tonic-gate if (hmep->hme_delay < 30) { 17647c478bd9Sstevel@tonic-gate hmep->hme_delay++; 17657c478bd9Sstevel@tonic-gate hme_start_timer(hmep, hme_try_speed, HME_TICKS); 17667c478bd9Sstevel@tonic-gate return (hmep->hme_autoneg = HME_HWAN_INPROGRESS); 17677c478bd9Sstevel@tonic-gate } 17687c478bd9Sstevel@tonic-gate 17697c478bd9Sstevel@tonic-gate (void) hme_mii_read(hmep, HME_PHY_BMSR, &stat); 17707c478bd9Sstevel@tonic-gate if (hme_mii_read(hmep, HME_PHY_BMSR, &stat) == 1) { 17717c478bd9Sstevel@tonic-gate /* 17727c478bd9Sstevel@tonic-gate * Transceiver does not talk mii 17737c478bd9Sstevel@tonic-gate */ 17747c478bd9Sstevel@tonic-gate goto hme_anfail; 17757c478bd9Sstevel@tonic-gate } 17767c478bd9Sstevel@tonic-gate 17777c478bd9Sstevel@tonic-gate if ((stat & PHY_BMSR_ANC) == 0) { 17787c478bd9Sstevel@tonic-gate /* 17797c478bd9Sstevel@tonic-gate * wait for a maximum of 5 seconds 17807c478bd9Sstevel@tonic-gate */ 17817c478bd9Sstevel@tonic-gate if (hmep->hme_delay < 50) { 17827c478bd9Sstevel@tonic-gate hmep->hme_delay++; 17837c478bd9Sstevel@tonic-gate hme_start_timer(hmep, hme_try_speed, HME_TICKS); 17847c478bd9Sstevel@tonic-gate return (hmep->hme_autoneg = HME_HWAN_INPROGRESS); 17857c478bd9Sstevel@tonic-gate } 17867c478bd9Sstevel@tonic-gate if (HME_DP83840) { 17877c478bd9Sstevel@tonic-gate (void) hme_mii_read(hmep, HME_PHY_ANER, &aner); 17887c478bd9Sstevel@tonic-gate if (aner & PHY_ANER_MLF) { 17897c478bd9Sstevel@tonic-gate 17907c478bd9Sstevel@tonic-gate return (hmep->hme_autoneg = HME_HWAN_FAILED); 17917c478bd9Sstevel@tonic-gate } 17927c478bd9Sstevel@tonic-gate } 17937c478bd9Sstevel@tonic-gate 17947c478bd9Sstevel@tonic-gate goto hme_anfail; 17957c478bd9Sstevel@tonic-gate } 17967c478bd9Sstevel@tonic-gate 17977c478bd9Sstevel@tonic-gate (void) hme_mii_read(hmep, HME_PHY_ANER, &aner); 17987c478bd9Sstevel@tonic-gate if (aner & PHY_ANER_MLF) { 17997c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, AUTONEG_MSG, 180085025c03Sgd par_detect_msg); 18017c478bd9Sstevel@tonic-gate goto hme_anfail; 18027c478bd9Sstevel@tonic-gate } 18037c478bd9Sstevel@tonic-gate 18047c478bd9Sstevel@tonic-gate if (!(stat & PHY_BMSR_LNKSTS)) { 18057c478bd9Sstevel@tonic-gate /* 18067c478bd9Sstevel@tonic-gate * wait for a maximum of 10 seconds 18077c478bd9Sstevel@tonic-gate */ 18087c478bd9Sstevel@tonic-gate if (hmep->hme_delay < 100) { 18097c478bd9Sstevel@tonic-gate hmep->hme_delay++; 18107c478bd9Sstevel@tonic-gate hme_start_timer(hmep, hme_try_speed, HME_TICKS); 18117c478bd9Sstevel@tonic-gate return (hmep->hme_autoneg = HME_HWAN_INPROGRESS); 18127c478bd9Sstevel@tonic-gate } 18137c478bd9Sstevel@tonic-gate goto hme_anfail; 18147c478bd9Sstevel@tonic-gate } else { 18157c478bd9Sstevel@tonic-gate hmep->hme_bmsr |= (PHY_BMSR_LNKSTS); 18167c478bd9Sstevel@tonic-gate hme_get_autoinfo(hmep); 18177c478bd9Sstevel@tonic-gate hmep->hme_force_linkdown = HME_LINKDOWN_DONE; 18187c478bd9Sstevel@tonic-gate hme_setup_link_status(hmep); 18197c478bd9Sstevel@tonic-gate hme_start_mifpoll(hmep); 18207c478bd9Sstevel@tonic-gate hme_start_timer(hmep, hme_check_link, HME_LINKCHECK_TIMER); 1821*0219346bSGarrett D'Amore if (hmep->hme_fdx != hmep->hme_macfdx) { 18227c478bd9Sstevel@tonic-gate (void) hmeinit(hmep); 1823*0219346bSGarrett D'Amore } 18247c478bd9Sstevel@tonic-gate return (hmep->hme_autoneg = HME_HWAN_SUCCESFUL); 18257c478bd9Sstevel@tonic-gate } 18267c478bd9Sstevel@tonic-gate 18277c478bd9Sstevel@tonic-gate hme_anfail: 18287c478bd9Sstevel@tonic-gate hme_start_timer(hmep, hme_try_speed, HME_TICKS); 18297c478bd9Sstevel@tonic-gate return (hmep->hme_autoneg = HME_HWAN_TRY); 18307c478bd9Sstevel@tonic-gate } 18317c478bd9Sstevel@tonic-gate 18327c478bd9Sstevel@tonic-gate /* 18337c478bd9Sstevel@tonic-gate * This function is used to perform automatic speed detection. 18347c478bd9Sstevel@tonic-gate * The Internal Transceiver which is based on the National PHY chip 18357c478bd9Sstevel@tonic-gate * 83840 supports auto-negotiation functionality. 18367c478bd9Sstevel@tonic-gate * Some External transceivers may not support auto-negotiation. 18377c478bd9Sstevel@tonic-gate * In that case, the software performs the speed detection. 18387c478bd9Sstevel@tonic-gate * The software tries to bring down the link for about 2 seconds to 18397c478bd9Sstevel@tonic-gate * force the Link Partner to notice speed change. 18407c478bd9Sstevel@tonic-gate * The software speed detection favors the 100 Mbps speed. 18417c478bd9Sstevel@tonic-gate * It does this by setting the 100 Mbps for longer duration ( 5 seconds ) 18427c478bd9Sstevel@tonic-gate * than the 10 Mbps ( 2 seconds ). Also, even after the link is up 18437c478bd9Sstevel@tonic-gate * in 10 Mbps once, the 100 Mbps is also tried. Only if the link 18447c478bd9Sstevel@tonic-gate * is not up in 100 Mbps, the 10 Mbps speed is tried again. 18457c478bd9Sstevel@tonic-gate */ 18467c478bd9Sstevel@tonic-gate static void 18477c478bd9Sstevel@tonic-gate hme_try_speed(void *arg) 18487c478bd9Sstevel@tonic-gate { 18497c478bd9Sstevel@tonic-gate struct hme *hmep = arg; 18507c478bd9Sstevel@tonic-gate int linkup; 18517c478bd9Sstevel@tonic-gate uint_t temp; 18527c478bd9Sstevel@tonic-gate 18537c478bd9Sstevel@tonic-gate hme_stop_timer(hmep); 18547c478bd9Sstevel@tonic-gate temp = hmep->hme_transceiver; /* save the transceiver type */ 18557c478bd9Sstevel@tonic-gate hme_check_transceiver(hmep); 18567c478bd9Sstevel@tonic-gate if (temp != hmep->hme_transceiver) { 18577c478bd9Sstevel@tonic-gate if (hmep->hme_transceiver == HME_EXTERNAL_TRANSCEIVER) { 18587c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, XCVR_MSG, 185985025c03Sgd ext_xcvr_msg); 18607c478bd9Sstevel@tonic-gate } else { 18617c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, XCVR_MSG, 186285025c03Sgd int_xcvr_msg); 18637c478bd9Sstevel@tonic-gate } 18647c478bd9Sstevel@tonic-gate hme_start_timer(hmep, hme_check_link, 10 * HME_TICKS); 18657c478bd9Sstevel@tonic-gate return; 18667c478bd9Sstevel@tonic-gate } 18677c478bd9Sstevel@tonic-gate 18687c478bd9Sstevel@tonic-gate if ((hmep->hme_transceiver == HME_INTERNAL_TRANSCEIVER) && 186985025c03Sgd (hmep->hme_link_pulse_disabled)) { 18707c478bd9Sstevel@tonic-gate hmep->hme_tryspeed = HME_SPEED_10; 18717c478bd9Sstevel@tonic-gate hme_disable_link_pulse(hmep); 18727c478bd9Sstevel@tonic-gate return; 18737c478bd9Sstevel@tonic-gate } 18747c478bd9Sstevel@tonic-gate 18757c478bd9Sstevel@tonic-gate if (hme_autoneg_enable && (hmep->hme_autoneg != HME_HWAN_FAILED)) { 18767c478bd9Sstevel@tonic-gate if (hme_try_auto_negotiation(hmep) != HME_HWAN_FAILED) 18777c478bd9Sstevel@tonic-gate return; /* auto negotiation successful or being tried */ 18787c478bd9Sstevel@tonic-gate } 18797c478bd9Sstevel@tonic-gate 18807c478bd9Sstevel@tonic-gate linkup = hme_select_speed(hmep, hmep->hme_tryspeed); 18817c478bd9Sstevel@tonic-gate if (hmep->hme_linkup_cnt == 1) { 18827c478bd9Sstevel@tonic-gate hme_start_timer(hmep, hme_try_speed, SECOND(1)); 18837c478bd9Sstevel@tonic-gate return; 18847c478bd9Sstevel@tonic-gate } 18857c478bd9Sstevel@tonic-gate if (linkup) { 18867c478bd9Sstevel@tonic-gate switch (hmep->hme_tryspeed) { 18877c478bd9Sstevel@tonic-gate case HME_SPEED_100: 18887c478bd9Sstevel@tonic-gate if (hmep->hme_linkup_cnt == 4) { 18897c478bd9Sstevel@tonic-gate hmep->hme_ntries = HME_NTRIES_LOW; 18907c478bd9Sstevel@tonic-gate hmep->hme_nlasttries = HME_NTRIES_LOW; 18917c478bd9Sstevel@tonic-gate hmep->hme_linkup = 1; 18927c478bd9Sstevel@tonic-gate hmep->hme_linkcheck = 1; 18937c478bd9Sstevel@tonic-gate hme_link_now_up(hmep); 18947c478bd9Sstevel@tonic-gate hme_setup_link_status(hmep); 18957c478bd9Sstevel@tonic-gate hme_start_mifpoll(hmep); 18967c478bd9Sstevel@tonic-gate hme_start_timer(hmep, hme_check_link, 189785025c03Sgd HME_LINKCHECK_TIMER); 1898*0219346bSGarrett D'Amore if (hmep->hme_fdx != hmep->hme_macfdx) { 18997c478bd9Sstevel@tonic-gate (void) hmeinit(hmep); 1900*0219346bSGarrett D'Amore } 19017c478bd9Sstevel@tonic-gate } else 19027c478bd9Sstevel@tonic-gate hme_start_timer(hmep, hme_try_speed, HME_TICKS); 19037c478bd9Sstevel@tonic-gate break; 19047c478bd9Sstevel@tonic-gate case HME_SPEED_10: 19057c478bd9Sstevel@tonic-gate if (hmep->hme_linkup_cnt == 4) { 19067c478bd9Sstevel@tonic-gate if (hmep->hme_linkup_10) { 19077c478bd9Sstevel@tonic-gate hmep->hme_linkup_10 = 0; 19087c478bd9Sstevel@tonic-gate hmep->hme_ntries = HME_NTRIES_LOW; 19097c478bd9Sstevel@tonic-gate hmep->hme_nlasttries = HME_NTRIES_LOW; 19107c478bd9Sstevel@tonic-gate hmep->hme_linkup = 1; 19117c478bd9Sstevel@tonic-gate hmep->hme_linkcheck = 1; 19127c478bd9Sstevel@tonic-gate hmep->hme_ifspeed = HME_SPEED_10; 19137c478bd9Sstevel@tonic-gate hme_setup_link_status(hmep); 19147c478bd9Sstevel@tonic-gate hme_start_mifpoll(hmep); 19157c478bd9Sstevel@tonic-gate hme_start_timer(hmep, hme_check_link, 191685025c03Sgd HME_LINKCHECK_TIMER); 1917*0219346bSGarrett D'Amore if (hmep->hme_fdx != hmep->hme_macfdx) { 19187c478bd9Sstevel@tonic-gate (void) hmeinit(hmep); 1919*0219346bSGarrett D'Amore } 19207c478bd9Sstevel@tonic-gate } else { 19217c478bd9Sstevel@tonic-gate hmep->hme_linkup_10 = 1; 19227c478bd9Sstevel@tonic-gate hmep->hme_tryspeed = HME_SPEED_100; 19237c478bd9Sstevel@tonic-gate hmep->hme_force_linkdown = 192485025c03Sgd HME_FORCE_LINKDOWN; 19257c478bd9Sstevel@tonic-gate hmep->hme_linkup_cnt = 0; 19267c478bd9Sstevel@tonic-gate hmep->hme_ntries = HME_NTRIES_LOW; 19277c478bd9Sstevel@tonic-gate hmep->hme_nlasttries = HME_NTRIES_LOW; 19287c478bd9Sstevel@tonic-gate hme_start_timer(hmep, 192985025c03Sgd hme_try_speed, HME_TICKS); 19307c478bd9Sstevel@tonic-gate } 19317c478bd9Sstevel@tonic-gate 19327c478bd9Sstevel@tonic-gate } else 19337c478bd9Sstevel@tonic-gate hme_start_timer(hmep, hme_try_speed, HME_TICKS); 19347c478bd9Sstevel@tonic-gate break; 19357c478bd9Sstevel@tonic-gate default: 19367c478bd9Sstevel@tonic-gate break; 19377c478bd9Sstevel@tonic-gate } 19387c478bd9Sstevel@tonic-gate return; 19397c478bd9Sstevel@tonic-gate } 19407c478bd9Sstevel@tonic-gate 19417c478bd9Sstevel@tonic-gate hmep->hme_ntries--; 19427c478bd9Sstevel@tonic-gate hmep->hme_linkup_cnt = 0; 19437c478bd9Sstevel@tonic-gate if (hmep->hme_ntries == 0) { 19447c478bd9Sstevel@tonic-gate hmep->hme_force_linkdown = HME_FORCE_LINKDOWN; 19457c478bd9Sstevel@tonic-gate switch (hmep->hme_tryspeed) { 19467c478bd9Sstevel@tonic-gate case HME_SPEED_100: 19477c478bd9Sstevel@tonic-gate hmep->hme_tryspeed = HME_SPEED_10; 19487c478bd9Sstevel@tonic-gate hmep->hme_ntries = HME_NTRIES_LOW_10; 19497c478bd9Sstevel@tonic-gate break; 19507c478bd9Sstevel@tonic-gate case HME_SPEED_10: 19517c478bd9Sstevel@tonic-gate hmep->hme_ntries = HME_NTRIES_LOW; 19527c478bd9Sstevel@tonic-gate hmep->hme_tryspeed = HME_SPEED_100; 19537c478bd9Sstevel@tonic-gate break; 19547c478bd9Sstevel@tonic-gate default: 19557c478bd9Sstevel@tonic-gate break; 19567c478bd9Sstevel@tonic-gate } 19577c478bd9Sstevel@tonic-gate } 19587c478bd9Sstevel@tonic-gate hme_start_timer(hmep, hme_try_speed, HME_TICKS); 19597c478bd9Sstevel@tonic-gate } 19607c478bd9Sstevel@tonic-gate 19617c478bd9Sstevel@tonic-gate static void 19627c478bd9Sstevel@tonic-gate hme_link_now_up(struct hme *hmep) 19637c478bd9Sstevel@tonic-gate { 19647c478bd9Sstevel@tonic-gate uint16_t btxpc; 19657c478bd9Sstevel@tonic-gate /* 19667c478bd9Sstevel@tonic-gate * Work-around for the scramble problem with QSI 19677c478bd9Sstevel@tonic-gate * chip and Synoptics 28115 switch. 19687c478bd9Sstevel@tonic-gate * Addition Interface Technologies Group (NPG) 8/28/1997. 19697c478bd9Sstevel@tonic-gate */ 197085025c03Sgd if ((HME_QS6612) && ((hmep->hme_tryspeed == HME_SPEED_100) || 197185025c03Sgd (hmep->hme_forcespeed == HME_SPEED_100))) { 19727c478bd9Sstevel@tonic-gate /* 19737c478bd9Sstevel@tonic-gate * Addition of a check for 'hmep->hme_forcespeed' 19747c478bd9Sstevel@tonic-gate * This is necessary when the autonegotiation is 19757c478bd9Sstevel@tonic-gate * disabled by the 'hme.conf' file. In this case 19767c478bd9Sstevel@tonic-gate * hmep->hme_tryspeed is not initialized. Resulting 19777c478bd9Sstevel@tonic-gate * in the workaround not being applied. 19787c478bd9Sstevel@tonic-gate */ 19797c478bd9Sstevel@tonic-gate if (hme_mii_read(hmep, HME_PHY_BTXPC, &btxpc) == 0) { 19807c478bd9Sstevel@tonic-gate hme_mii_write(hmep, HME_PHY_BTXPC, 198185025c03Sgd (btxpc | PHY_BTXPC_DSCRAM)); 19827c478bd9Sstevel@tonic-gate drv_usecwait(20); 19837c478bd9Sstevel@tonic-gate hme_mii_write(hmep, HME_PHY_BTXPC, btxpc); 19847c478bd9Sstevel@tonic-gate } 19857c478bd9Sstevel@tonic-gate } 19867c478bd9Sstevel@tonic-gate } 19877c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<<<<<<<<<<<<<<<< LOADABLE ENTRIES >>>>>>>>>>>>>>>>>>>>>>> */ 19887c478bd9Sstevel@tonic-gate 19897c478bd9Sstevel@tonic-gate int 19907c478bd9Sstevel@tonic-gate _init(void) 19917c478bd9Sstevel@tonic-gate { 19927c478bd9Sstevel@tonic-gate int status; 19937c478bd9Sstevel@tonic-gate 199485025c03Sgd mac_init_ops(&hme_dev_ops, "hme"); 199585025c03Sgd if ((status = mod_install(&modlinkage)) != 0) { 199685025c03Sgd mac_fini_ops(&hme_dev_ops); 19977c478bd9Sstevel@tonic-gate } 19987c478bd9Sstevel@tonic-gate return (status); 19997c478bd9Sstevel@tonic-gate } 20007c478bd9Sstevel@tonic-gate 20017c478bd9Sstevel@tonic-gate int 20027c478bd9Sstevel@tonic-gate _fini(void) 20037c478bd9Sstevel@tonic-gate { 20047c478bd9Sstevel@tonic-gate int status; 20057c478bd9Sstevel@tonic-gate 200685025c03Sgd if ((status = mod_remove(&modlinkage)) == 0) { 200785025c03Sgd mac_fini_ops(&hme_dev_ops); 20087c478bd9Sstevel@tonic-gate } 20097c478bd9Sstevel@tonic-gate return (status); 20107c478bd9Sstevel@tonic-gate } 20117c478bd9Sstevel@tonic-gate 20127c478bd9Sstevel@tonic-gate int 20137c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 20147c478bd9Sstevel@tonic-gate { 20157c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 20167c478bd9Sstevel@tonic-gate } 20177c478bd9Sstevel@tonic-gate 20187c478bd9Sstevel@tonic-gate /* 20197c478bd9Sstevel@tonic-gate * ddi_dma_sync() a TMD or RMD descriptor. 20207c478bd9Sstevel@tonic-gate */ 2021*0219346bSGarrett D'Amore #define HMESYNCRMD(num, who) \ 2022*0219346bSGarrett D'Amore (void) ddi_dma_sync(hmep->hme_rmd_dmah, \ 2023*0219346bSGarrett D'Amore (num * sizeof (struct hme_rmd)), \ 2024*0219346bSGarrett D'Amore sizeof (struct hme_rmd), \ 2025*0219346bSGarrett D'Amore who) 2026*0219346bSGarrett D'Amore 2027*0219346bSGarrett D'Amore #define HMESYNCTMD(num, who) \ 2028*0219346bSGarrett D'Amore (void) ddi_dma_sync(hmep->hme_tmd_dmah, \ 2029*0219346bSGarrett D'Amore (num * sizeof (struct hme_tmd)), \ 2030*0219346bSGarrett D'Amore sizeof (struct hme_tmd), \ 2031*0219346bSGarrett D'Amore who) 20327c478bd9Sstevel@tonic-gate 20337c478bd9Sstevel@tonic-gate /* 20347c478bd9Sstevel@tonic-gate * Ethernet broadcast address definition. 20357c478bd9Sstevel@tonic-gate */ 20367c478bd9Sstevel@tonic-gate static struct ether_addr etherbroadcastaddr = { 20377c478bd9Sstevel@tonic-gate 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 20387c478bd9Sstevel@tonic-gate }; 20397c478bd9Sstevel@tonic-gate 20407c478bd9Sstevel@tonic-gate /* 20417c478bd9Sstevel@tonic-gate * MIB II broadcast/multicast packets 20427c478bd9Sstevel@tonic-gate */ 204385025c03Sgd #define IS_BROADCAST(pkt) (bcmp(pkt, ðerbroadcastaddr, ETHERADDRL) == 0) 204485025c03Sgd #define IS_MULTICAST(pkt) ((pkt[0] & 01) == 1) 204585025c03Sgd #define BUMP_InNUcast(hmep, pkt) \ 2046*0219346bSGarrett D'Amore if (IS_MULTICAST(pkt)) { \ 2047*0219346bSGarrett D'Amore if (IS_BROADCAST(pkt)) { \ 2048*0219346bSGarrett D'Amore hmep->hme_brdcstrcv++; \ 2049*0219346bSGarrett D'Amore } else { \ 2050*0219346bSGarrett D'Amore hmep->hme_multircv++; \ 2051*0219346bSGarrett D'Amore } \ 2052*0219346bSGarrett D'Amore } 205385025c03Sgd #define BUMP_OutNUcast(hmep, pkt) \ 2054*0219346bSGarrett D'Amore if (IS_MULTICAST(pkt)) { \ 2055*0219346bSGarrett D'Amore if (IS_BROADCAST(pkt)) { \ 2056*0219346bSGarrett D'Amore hmep->hme_brdcstxmt++; \ 2057*0219346bSGarrett D'Amore } else { \ 2058*0219346bSGarrett D'Amore hmep->hme_multixmt++; \ 2059*0219346bSGarrett D'Amore } \ 2060*0219346bSGarrett D'Amore } 20617c478bd9Sstevel@tonic-gate 20627c478bd9Sstevel@tonic-gate static int 20637c478bd9Sstevel@tonic-gate hme_create_prop_from_kw(dev_info_t *dip, char *vpdname, char *vpdstr) 20647c478bd9Sstevel@tonic-gate { 20657c478bd9Sstevel@tonic-gate char propstr[80]; 20667c478bd9Sstevel@tonic-gate int i, needprop = 0; 20677c478bd9Sstevel@tonic-gate struct ether_addr local_mac; 20687c478bd9Sstevel@tonic-gate 20697c478bd9Sstevel@tonic-gate if (strcmp(vpdname, "NA") == 0) { 20707c478bd9Sstevel@tonic-gate (void) strcpy(propstr, "local-mac-address"); 20717c478bd9Sstevel@tonic-gate needprop = 1; 20727c478bd9Sstevel@tonic-gate } else if (strcmp(vpdname, "Z0") == 0) { 20737c478bd9Sstevel@tonic-gate (void) strcpy(propstr, "model"); 20747c478bd9Sstevel@tonic-gate needprop = 1; 20757c478bd9Sstevel@tonic-gate } else if (strcmp(vpdname, "Z1") == 0) { 20767c478bd9Sstevel@tonic-gate (void) strcpy(propstr, "board-model"); 20777c478bd9Sstevel@tonic-gate needprop = 1; 20787c478bd9Sstevel@tonic-gate } 20797c478bd9Sstevel@tonic-gate 20807c478bd9Sstevel@tonic-gate if (needprop == 1) { 2081*0219346bSGarrett D'Amore 20827c478bd9Sstevel@tonic-gate if (strcmp(propstr, "local-mac-address") == 0) { 20837c478bd9Sstevel@tonic-gate for (i = 0; i < ETHERADDRL; i++) 20847c478bd9Sstevel@tonic-gate local_mac.ether_addr_octet[i] = 208585025c03Sgd (uchar_t)vpdstr[i]; 20867c478bd9Sstevel@tonic-gate if (ddi_prop_create(DDI_DEV_T_NONE, dip, 208785025c03Sgd DDI_PROP_CANSLEEP, propstr, 208885025c03Sgd (char *)local_mac.ether_addr_octet, ETHERADDRL) 208985025c03Sgd != DDI_SUCCESS) { 20907c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 20917c478bd9Sstevel@tonic-gate } 20927c478bd9Sstevel@tonic-gate } else { 20937c478bd9Sstevel@tonic-gate if (ddi_prop_create(DDI_DEV_T_NONE, dip, 209485025c03Sgd DDI_PROP_CANSLEEP, propstr, vpdstr, 209585025c03Sgd strlen(vpdstr)+1) != DDI_SUCCESS) { 20967c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 20977c478bd9Sstevel@tonic-gate } 20987c478bd9Sstevel@tonic-gate } 20997c478bd9Sstevel@tonic-gate } 21007c478bd9Sstevel@tonic-gate return (0); 21017c478bd9Sstevel@tonic-gate } 21027c478bd9Sstevel@tonic-gate 21037c478bd9Sstevel@tonic-gate /* 21047c478bd9Sstevel@tonic-gate * Get properties from old VPD 21057c478bd9Sstevel@tonic-gate * for PCI cards 21067c478bd9Sstevel@tonic-gate */ 21077c478bd9Sstevel@tonic-gate static int 21087c478bd9Sstevel@tonic-gate hme_get_oldvpd_props(dev_info_t *dip, int vpd_base) 21097c478bd9Sstevel@tonic-gate { 21107c478bd9Sstevel@tonic-gate struct hme *hmep; 21117c478bd9Sstevel@tonic-gate int vpd_start, vpd_len, kw_start, kw_len, kw_ptr; 21127c478bd9Sstevel@tonic-gate char kw_namestr[3]; 21137c478bd9Sstevel@tonic-gate char kw_fieldstr[256]; 21147c478bd9Sstevel@tonic-gate int i; 21157c478bd9Sstevel@tonic-gate 21167c478bd9Sstevel@tonic-gate hmep = ddi_get_driver_private(dip); 21177c478bd9Sstevel@tonic-gate 21187c478bd9Sstevel@tonic-gate vpd_start = vpd_base; 21197c478bd9Sstevel@tonic-gate 21207c478bd9Sstevel@tonic-gate if ((GET_ROM8(&hmep->hme_romp[vpd_start]) & 0xff) != 0x90) { 21217c478bd9Sstevel@tonic-gate return (1); /* error */ 21227c478bd9Sstevel@tonic-gate } else { 21237c478bd9Sstevel@tonic-gate vpd_len = 9; 21247c478bd9Sstevel@tonic-gate } 21257c478bd9Sstevel@tonic-gate 21267c478bd9Sstevel@tonic-gate /* Get local-mac-address */ 21277c478bd9Sstevel@tonic-gate kw_start = vpd_start + 3; /* Location of 1st keyword */ 21287c478bd9Sstevel@tonic-gate kw_ptr = kw_start; 21297c478bd9Sstevel@tonic-gate while ((kw_ptr - kw_start) < vpd_len) { /* Get all keywords */ 21307c478bd9Sstevel@tonic-gate kw_namestr[0] = GET_ROM8(&hmep->hme_romp[kw_ptr]); 21317c478bd9Sstevel@tonic-gate kw_namestr[1] = GET_ROM8(&hmep->hme_romp[kw_ptr+1]); 21327c478bd9Sstevel@tonic-gate kw_namestr[2] = '\0'; 21337c478bd9Sstevel@tonic-gate kw_len = (int)(GET_ROM8(&hmep->hme_romp[kw_ptr+2]) & 0xff); 21347c478bd9Sstevel@tonic-gate for (i = 0, kw_ptr += 3; i < kw_len; i++) 21357c478bd9Sstevel@tonic-gate kw_fieldstr[i] = GET_ROM8(&hmep->hme_romp[kw_ptr+i]); 21367c478bd9Sstevel@tonic-gate kw_fieldstr[i] = '\0'; 21377c478bd9Sstevel@tonic-gate if (hme_create_prop_from_kw(dip, kw_namestr, kw_fieldstr)) { 21387c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 21397c478bd9Sstevel@tonic-gate } 21407c478bd9Sstevel@tonic-gate kw_ptr += kw_len; 21417c478bd9Sstevel@tonic-gate } /* next keyword */ 21427c478bd9Sstevel@tonic-gate 214385025c03Sgd if (ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, "model", 214485025c03Sgd "SUNW,cheerio", strlen("SUNW,cheerio")+1) != DDI_SUCCESS) { 21457c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 21467c478bd9Sstevel@tonic-gate } 21477c478bd9Sstevel@tonic-gate return (0); 21487c478bd9Sstevel@tonic-gate } 21497c478bd9Sstevel@tonic-gate 21507c478bd9Sstevel@tonic-gate 21517c478bd9Sstevel@tonic-gate /* 21527c478bd9Sstevel@tonic-gate * Get properties from new VPD 21537c478bd9Sstevel@tonic-gate * for CompactPCI cards 21547c478bd9Sstevel@tonic-gate */ 21557c478bd9Sstevel@tonic-gate static int 21567c478bd9Sstevel@tonic-gate hme_get_newvpd_props(dev_info_t *dip, int vpd_base) 21577c478bd9Sstevel@tonic-gate { 21587c478bd9Sstevel@tonic-gate struct hme *hmep; 21597c478bd9Sstevel@tonic-gate int vpd_start, vpd_len, kw_start, kw_len, kw_ptr; 21607c478bd9Sstevel@tonic-gate char kw_namestr[3]; 21617c478bd9Sstevel@tonic-gate char kw_fieldstr[256]; 21627c478bd9Sstevel@tonic-gate int maxvpdsize, i; 21637c478bd9Sstevel@tonic-gate 21647c478bd9Sstevel@tonic-gate hmep = ddi_get_driver_private(dip); 21657c478bd9Sstevel@tonic-gate 21667c478bd9Sstevel@tonic-gate maxvpdsize = 1024; /* Real size not known until after it is read */ 21677c478bd9Sstevel@tonic-gate 21687c478bd9Sstevel@tonic-gate vpd_start = (int)((GET_ROM8(&(hmep->hme_romp[vpd_base+1])) & 0xff) | 216985025c03Sgd ((GET_ROM8(&hmep->hme_romp[vpd_base+2]) & 0xff) << 8)) +3; 21707c478bd9Sstevel@tonic-gate vpd_start = vpd_base + vpd_start; 21717c478bd9Sstevel@tonic-gate while (vpd_start < (vpd_base + maxvpdsize)) { /* Get all VPDs */ 21727c478bd9Sstevel@tonic-gate if ((GET_ROM8(&hmep->hme_romp[vpd_start]) & 0xff) != 0x90) { 21737c478bd9Sstevel@tonic-gate break; /* no VPD found */ 21747c478bd9Sstevel@tonic-gate } else { 21757c478bd9Sstevel@tonic-gate vpd_len = (int)((GET_ROM8(&hmep->hme_romp[vpd_start 217685025c03Sgd + 1]) & 0xff) | (GET_ROM8(&hmep->hme_romp[vpd_start 217785025c03Sgd + 2]) & 0xff) << 8); 21787c478bd9Sstevel@tonic-gate } 21797c478bd9Sstevel@tonic-gate /* Get all keywords in this VPD */ 21807c478bd9Sstevel@tonic-gate kw_start = vpd_start + 3; /* Location of 1st keyword */ 21817c478bd9Sstevel@tonic-gate kw_ptr = kw_start; 21827c478bd9Sstevel@tonic-gate while ((kw_ptr - kw_start) < vpd_len) { /* Get all keywords */ 21837c478bd9Sstevel@tonic-gate kw_namestr[0] = GET_ROM8(&hmep->hme_romp[kw_ptr]); 21847c478bd9Sstevel@tonic-gate kw_namestr[1] = GET_ROM8(&hmep->hme_romp[kw_ptr+1]); 21857c478bd9Sstevel@tonic-gate kw_namestr[2] = '\0'; 218685025c03Sgd kw_len = 218785025c03Sgd (int)(GET_ROM8(&hmep->hme_romp[kw_ptr+2]) & 0xff); 21887c478bd9Sstevel@tonic-gate for (i = 0, kw_ptr += 3; i < kw_len; i++) 218985025c03Sgd kw_fieldstr[i] = 219085025c03Sgd GET_ROM8(&hmep->hme_romp[kw_ptr+i]); 21917c478bd9Sstevel@tonic-gate kw_fieldstr[i] = '\0'; 21927c478bd9Sstevel@tonic-gate if (hme_create_prop_from_kw(dip, kw_namestr, 219385025c03Sgd kw_fieldstr)) { 21947c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 21957c478bd9Sstevel@tonic-gate } 21967c478bd9Sstevel@tonic-gate kw_ptr += kw_len; 21977c478bd9Sstevel@tonic-gate } /* next keyword */ 21987c478bd9Sstevel@tonic-gate vpd_start += (vpd_len + 3); 21997c478bd9Sstevel@tonic-gate } /* next VPD */ 22007c478bd9Sstevel@tonic-gate return (0); 22017c478bd9Sstevel@tonic-gate } 22027c478bd9Sstevel@tonic-gate 22037c478bd9Sstevel@tonic-gate 22047c478bd9Sstevel@tonic-gate /* 22057c478bd9Sstevel@tonic-gate * Get properties from VPD 22067c478bd9Sstevel@tonic-gate */ 22077c478bd9Sstevel@tonic-gate static int 22087c478bd9Sstevel@tonic-gate hme_get_vpd_props(dev_info_t *dip) 22097c478bd9Sstevel@tonic-gate { 22107c478bd9Sstevel@tonic-gate struct hme *hmep; 22117c478bd9Sstevel@tonic-gate int v0, v1, vpd_base; 22127c478bd9Sstevel@tonic-gate int i, epromsrchlimit; 22137c478bd9Sstevel@tonic-gate 22147c478bd9Sstevel@tonic-gate 22157c478bd9Sstevel@tonic-gate hmep = ddi_get_driver_private(dip); 22167c478bd9Sstevel@tonic-gate 22177c478bd9Sstevel@tonic-gate v0 = (int)(GET_ROM8(&(hmep->hme_romp[0]))); 22187c478bd9Sstevel@tonic-gate v1 = (int)(GET_ROM8(&(hmep->hme_romp[1]))); 22197c478bd9Sstevel@tonic-gate v0 = ((v0 & 0xff) << 8 | v1); 22207c478bd9Sstevel@tonic-gate 22217c478bd9Sstevel@tonic-gate if ((v0 & 0xffff) != 0x55aa) { 22227c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, " Valid pci prom not found \n"); 22237c478bd9Sstevel@tonic-gate return (1); 22247c478bd9Sstevel@tonic-gate } 22257c478bd9Sstevel@tonic-gate 22267c478bd9Sstevel@tonic-gate epromsrchlimit = 4096; 22277c478bd9Sstevel@tonic-gate for (i = 2; i < epromsrchlimit; i++) { 222885025c03Sgd /* "PCIR" */ 222985025c03Sgd if (((GET_ROM8(&(hmep->hme_romp[i])) & 0xff) == 'P') && 223085025c03Sgd ((GET_ROM8(&(hmep->hme_romp[i+1])) & 0xff) == 'C') && 223185025c03Sgd ((GET_ROM8(&(hmep->hme_romp[i+2])) & 0xff) == 'I') && 223285025c03Sgd ((GET_ROM8(&(hmep->hme_romp[i+3])) & 0xff) == 'R')) { 223385025c03Sgd vpd_base = 223485025c03Sgd (int)((GET_ROM8(&(hmep->hme_romp[i+8])) & 0xff) | 223585025c03Sgd (GET_ROM8(&(hmep->hme_romp[i+9])) & 0xff) << 8); 22367c478bd9Sstevel@tonic-gate break; /* VPD pointer found */ 22377c478bd9Sstevel@tonic-gate } 22387c478bd9Sstevel@tonic-gate } 22397c478bd9Sstevel@tonic-gate 22407c478bd9Sstevel@tonic-gate /* No VPD found */ 22417c478bd9Sstevel@tonic-gate if (vpd_base == 0) { 22427c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, " Vital Product Data pointer not found \n"); 22437c478bd9Sstevel@tonic-gate return (1); 22447c478bd9Sstevel@tonic-gate } 22457c478bd9Sstevel@tonic-gate 22467c478bd9Sstevel@tonic-gate v0 = (int)(GET_ROM8(&(hmep->hme_romp[vpd_base]))); 22477c478bd9Sstevel@tonic-gate if (v0 == 0x82) { 22487c478bd9Sstevel@tonic-gate if (hme_get_newvpd_props(dip, vpd_base)) 22497c478bd9Sstevel@tonic-gate return (1); 22507c478bd9Sstevel@tonic-gate return (0); 22517c478bd9Sstevel@tonic-gate } else if (v0 == 0x90) { 2252*0219346bSGarrett D'Amore /* If we are are SUNW,qfe card, look for the Nth "NA" descr */ 2253*0219346bSGarrett D'Amore if ((GET_ROM8(&hmep->hme_romp[vpd_base + 12]) != 0x79) && 2254*0219346bSGarrett D'Amore GET_ROM8(&hmep->hme_romp[vpd_base + 4 * 12]) == 0x79) { 2255*0219346bSGarrett D'Amore vpd_base += hmep->hme_devno * 12; 2256*0219346bSGarrett D'Amore } 22577c478bd9Sstevel@tonic-gate if (hme_get_oldvpd_props(dip, vpd_base)) 22587c478bd9Sstevel@tonic-gate return (1); 22597c478bd9Sstevel@tonic-gate return (0); 22607c478bd9Sstevel@tonic-gate } else 22617c478bd9Sstevel@tonic-gate return (1); /* unknown start byte in VPD */ 22627c478bd9Sstevel@tonic-gate } 22637c478bd9Sstevel@tonic-gate 2264*0219346bSGarrett D'Amore /* 2265*0219346bSGarrett D'Amore * For x86, the BIOS doesn't map the PCI Rom register for the qfe 2266*0219346bSGarrett D'Amore * cards, so we have to extract it from the ebus bridge that is 2267*0219346bSGarrett D'Amore * function zero of the same device. This is a bit of an ugly hack. 2268*0219346bSGarrett D'Amore * (The ebus bridge leaves the entire ROM mapped at base address 2269*0219346bSGarrett D'Amore * register 0x10.) 2270*0219346bSGarrett D'Amore */ 2271*0219346bSGarrett D'Amore 2272*0219346bSGarrett D'Amore typedef struct { 2273*0219346bSGarrett D'Amore struct hme *hmep; 2274*0219346bSGarrett D'Amore dev_info_t *parent; 2275*0219346bSGarrett D'Amore uint8_t bus, dev; 2276*0219346bSGarrett D'Amore ddi_acc_handle_t acch; 2277*0219346bSGarrett D'Amore caddr_t romp; 2278*0219346bSGarrett D'Amore } ebus_rom_t; 2279*0219346bSGarrett D'Amore 2280*0219346bSGarrett D'Amore static int 2281*0219346bSGarrett D'Amore hme_mapebusrom(dev_info_t *dip, void *arg) 2282*0219346bSGarrett D'Amore { 2283*0219346bSGarrett D'Amore int *regs; 2284*0219346bSGarrett D'Amore unsigned nregs; 2285*0219346bSGarrett D'Amore int reg; 2286*0219346bSGarrett D'Amore ebus_rom_t *rom = arg; 2287*0219346bSGarrett D'Amore struct hme *hmep = rom->hmep; 2288*0219346bSGarrett D'Amore 2289*0219346bSGarrett D'Amore /* 2290*0219346bSGarrett D'Amore * We only want to look at our peers. Skip our parent. 2291*0219346bSGarrett D'Amore */ 2292*0219346bSGarrett D'Amore if (dip == rom->parent) { 2293*0219346bSGarrett D'Amore return (DDI_WALK_PRUNESIB); 2294*0219346bSGarrett D'Amore } 2295*0219346bSGarrett D'Amore 2296*0219346bSGarrett D'Amore if ((ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 0, 2297*0219346bSGarrett D'Amore "reg", ®s, &nregs)) != DDI_PROP_SUCCESS) { 2298*0219346bSGarrett D'Amore return (DDI_WALK_PRUNECHILD); 2299*0219346bSGarrett D'Amore } 2300*0219346bSGarrett D'Amore 2301*0219346bSGarrett D'Amore if (nregs < 1) { 2302*0219346bSGarrett D'Amore ddi_prop_free(regs); 2303*0219346bSGarrett D'Amore return (DDI_WALK_PRUNECHILD); 2304*0219346bSGarrett D'Amore } 2305*0219346bSGarrett D'Amore reg = regs[0]; 2306*0219346bSGarrett D'Amore ddi_prop_free(regs); 2307*0219346bSGarrett D'Amore 2308*0219346bSGarrett D'Amore /* 2309*0219346bSGarrett D'Amore * Look for function 0 on our bus and device. If the device doesn't 2310*0219346bSGarrett D'Amore * match, it might be an alternate peer, in which case we don't want 2311*0219346bSGarrett D'Amore * to examine any of its children. 2312*0219346bSGarrett D'Amore */ 2313*0219346bSGarrett D'Amore if ((PCI_REG_BUS_G(reg) != rom->bus) || 2314*0219346bSGarrett D'Amore (PCI_REG_DEV_G(reg) != rom->dev) || 2315*0219346bSGarrett D'Amore (PCI_REG_FUNC_G(reg) != 0)) { 2316*0219346bSGarrett D'Amore return (DDI_WALK_PRUNECHILD); 2317*0219346bSGarrett D'Amore } 2318*0219346bSGarrett D'Amore 2319*0219346bSGarrett D'Amore (void) ddi_regs_map_setup(dip, 1, &rom->romp, 0, 0, &hmep->hme_dev_attr, 2320*0219346bSGarrett D'Amore &rom->acch); 2321*0219346bSGarrett D'Amore /* 2322*0219346bSGarrett D'Amore * If we can't map the registers, the caller will notice that 2323*0219346bSGarrett D'Amore * the acch is NULL. 2324*0219346bSGarrett D'Amore */ 2325*0219346bSGarrett D'Amore return (DDI_WALK_TERMINATE); 2326*0219346bSGarrett D'Amore } 2327*0219346bSGarrett D'Amore 2328*0219346bSGarrett D'Amore static int 2329*0219346bSGarrett D'Amore hmeget_promebus(dev_info_t *dip) 2330*0219346bSGarrett D'Amore { 2331*0219346bSGarrett D'Amore ebus_rom_t rom; 2332*0219346bSGarrett D'Amore int *regs; 2333*0219346bSGarrett D'Amore unsigned nregs; 2334*0219346bSGarrett D'Amore struct hme *hmep; 2335*0219346bSGarrett D'Amore 2336*0219346bSGarrett D'Amore hmep = ddi_get_driver_private(dip); 2337*0219346bSGarrett D'Amore 2338*0219346bSGarrett D'Amore bzero(&rom, sizeof (rom)); 2339*0219346bSGarrett D'Amore 2340*0219346bSGarrett D'Amore /* 2341*0219346bSGarrett D'Amore * For x86, the BIOS doesn't map the PCI Rom register for the qfe 2342*0219346bSGarrett D'Amore * cards, so we have to extract it from the eBus bridge that is 2343*0219346bSGarrett D'Amore * function zero. This is a bit of an ugly hack. 2344*0219346bSGarrett D'Amore */ 2345*0219346bSGarrett D'Amore if ((ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 0, 2346*0219346bSGarrett D'Amore "reg", ®s, &nregs)) != DDI_PROP_SUCCESS) { 2347*0219346bSGarrett D'Amore return (DDI_FAILURE); 2348*0219346bSGarrett D'Amore } 2349*0219346bSGarrett D'Amore 2350*0219346bSGarrett D'Amore if (nregs < 5) { 2351*0219346bSGarrett D'Amore ddi_prop_free(regs); 2352*0219346bSGarrett D'Amore return (DDI_FAILURE); 2353*0219346bSGarrett D'Amore } 2354*0219346bSGarrett D'Amore rom.hmep = hmep; 2355*0219346bSGarrett D'Amore rom.bus = PCI_REG_BUS_G(regs[0]); 2356*0219346bSGarrett D'Amore rom.dev = PCI_REG_DEV_G(regs[0]); 2357*0219346bSGarrett D'Amore hmep->hme_devno = rom.dev; 2358*0219346bSGarrett D'Amore rom.parent = ddi_get_parent(dip); 2359*0219346bSGarrett D'Amore 2360*0219346bSGarrett D'Amore /* 2361*0219346bSGarrett D'Amore * The implementation of ddi_walk_devs says that we must not 2362*0219346bSGarrett D'Amore * be called during autoconfiguration. However, upon close 2363*0219346bSGarrett D'Amore * examination, one will find the following is true: 2364*0219346bSGarrett D'Amore * 2365*0219346bSGarrett D'Amore * 1) since we're called at attach time, 2366*0219346bSGarrett D'Amore * DEVI_BUSY_OWNED(ddi_get_parent(dip)) is implicitly true. 2367*0219346bSGarrett D'Amore * 2368*0219346bSGarrett D'Amore * 2) we carefully ensure that we prune siblings for all cases 2369*0219346bSGarrett D'Amore * except our own device, so we can't wind up walking down 2370*0219346bSGarrett D'Amore * a changing sibling pointer. 2371*0219346bSGarrett D'Amore * 2372*0219346bSGarrett D'Amore * 3) since we are attaching, our peers will already have their 2373*0219346bSGarrett D'Amore * dev_info nodes on the tree... hence our own sibling pointer 2374*0219346bSGarrett D'Amore * (and those of our siblings) will be stable. 2375*0219346bSGarrett D'Amore * 2376*0219346bSGarrett D'Amore * 4) also, because of #3, our parents child pointer will be 2377*0219346bSGarrett D'Amore * stable. 2378*0219346bSGarrett D'Amore * 2379*0219346bSGarrett D'Amore * So it should be safe to do this, because of our carefully 2380*0219346bSGarrett D'Amore * constructed restrictions. 2381*0219346bSGarrett D'Amore */ 2382*0219346bSGarrett D'Amore ddi_walk_devs(ddi_get_parent(dip), hme_mapebusrom, &rom); 2383*0219346bSGarrett D'Amore 2384*0219346bSGarrett D'Amore if (rom.acch) { 2385*0219346bSGarrett D'Amore hmep->hme_romh = rom.acch; 2386*0219346bSGarrett D'Amore hmep->hme_romp = (unsigned char *)rom.romp; 2387*0219346bSGarrett D'Amore return (DDI_SUCCESS); 2388*0219346bSGarrett D'Amore } 2389*0219346bSGarrett D'Amore return (DDI_FAILURE); 2390*0219346bSGarrett D'Amore } 2391*0219346bSGarrett D'Amore 23927c478bd9Sstevel@tonic-gate static int 23937c478bd9Sstevel@tonic-gate hmeget_promprops(dev_info_t *dip) 23947c478bd9Sstevel@tonic-gate { 23957c478bd9Sstevel@tonic-gate struct hme *hmep; 23967c478bd9Sstevel@tonic-gate int rom_bar; 23977c478bd9Sstevel@tonic-gate ddi_acc_handle_t cfg_handle; 23987c478bd9Sstevel@tonic-gate struct { 23997c478bd9Sstevel@tonic-gate uint16_t vendorid; 24007c478bd9Sstevel@tonic-gate uint16_t devid; 24017c478bd9Sstevel@tonic-gate uint16_t command; 24027c478bd9Sstevel@tonic-gate uint16_t status; 24037c478bd9Sstevel@tonic-gate uint32_t junk1; 24047c478bd9Sstevel@tonic-gate uint8_t cache_line; 24057c478bd9Sstevel@tonic-gate uint8_t latency; 24067c478bd9Sstevel@tonic-gate uint8_t header; 24077c478bd9Sstevel@tonic-gate uint8_t bist; 24087c478bd9Sstevel@tonic-gate uint32_t base; 24097c478bd9Sstevel@tonic-gate uint32_t base14; 24107c478bd9Sstevel@tonic-gate uint32_t base18; 24117c478bd9Sstevel@tonic-gate uint32_t base1c; 24127c478bd9Sstevel@tonic-gate uint32_t base20; 24137c478bd9Sstevel@tonic-gate uint32_t base24; 24147c478bd9Sstevel@tonic-gate uint32_t base28; 24157c478bd9Sstevel@tonic-gate uint32_t base2c; 24167c478bd9Sstevel@tonic-gate uint32_t base30; 24177c478bd9Sstevel@tonic-gate } *cfg_ptr; 24187c478bd9Sstevel@tonic-gate 24197c478bd9Sstevel@tonic-gate hmep = ddi_get_driver_private(dip); 24207c478bd9Sstevel@tonic-gate 24217c478bd9Sstevel@tonic-gate 24227c478bd9Sstevel@tonic-gate /* 24237c478bd9Sstevel@tonic-gate * map configuration space 24247c478bd9Sstevel@tonic-gate */ 24257c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(hmep->dip, 0, (caddr_t *)&cfg_ptr, 242685025c03Sgd 0, 0, &hmep->hme_dev_attr, &cfg_handle)) { 24277c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 24287c478bd9Sstevel@tonic-gate } 24297c478bd9Sstevel@tonic-gate 24307c478bd9Sstevel@tonic-gate /* 24317c478bd9Sstevel@tonic-gate * Enable bus-master and memory accesses 24327c478bd9Sstevel@tonic-gate */ 24337c478bd9Sstevel@tonic-gate ddi_put16(cfg_handle, &cfg_ptr->command, 243485025c03Sgd PCI_COMM_SERR_ENABLE | PCI_COMM_PARITY_DETECT | 243585025c03Sgd PCI_COMM_MAE | PCI_COMM_ME); 24367c478bd9Sstevel@tonic-gate 24377c478bd9Sstevel@tonic-gate /* 24387c478bd9Sstevel@tonic-gate * Enable rom accesses 24397c478bd9Sstevel@tonic-gate */ 24407c478bd9Sstevel@tonic-gate rom_bar = ddi_get32(cfg_handle, &cfg_ptr->base30); 24417c478bd9Sstevel@tonic-gate ddi_put32(cfg_handle, &cfg_ptr->base30, rom_bar | 1); 24427c478bd9Sstevel@tonic-gate 24437c478bd9Sstevel@tonic-gate 2444*0219346bSGarrett D'Amore if ((ddi_regs_map_setup(dip, 2, (caddr_t *)&(hmep->hme_romp), 0, 0, 2445*0219346bSGarrett D'Amore &hmep->hme_dev_attr, &hmep->hme_romh) != DDI_SUCCESS) && 2446*0219346bSGarrett D'Amore (hmeget_promebus(dip) != DDI_SUCCESS)) { 2447*0219346bSGarrett D'Amore 24487c478bd9Sstevel@tonic-gate if (cfg_ptr) 24497c478bd9Sstevel@tonic-gate ddi_regs_map_free(&cfg_handle); 24507c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 24517c478bd9Sstevel@tonic-gate } else { 24527c478bd9Sstevel@tonic-gate if (hme_get_vpd_props(dip)) 2453*0219346bSGarrett D'Amore return (DDI_FAILURE); 24547c478bd9Sstevel@tonic-gate } 24557c478bd9Sstevel@tonic-gate if (hmep->hme_romp) 24567c478bd9Sstevel@tonic-gate ddi_regs_map_free(&hmep->hme_romh); 24577c478bd9Sstevel@tonic-gate if (cfg_ptr) 24587c478bd9Sstevel@tonic-gate ddi_regs_map_free(&cfg_handle); 2459*0219346bSGarrett D'Amore return (DDI_SUCCESS); 24607c478bd9Sstevel@tonic-gate 24617c478bd9Sstevel@tonic-gate } 24627c478bd9Sstevel@tonic-gate 24637c478bd9Sstevel@tonic-gate static void 24647c478bd9Sstevel@tonic-gate hmeget_hm_rev_property(struct hme *hmep) 24657c478bd9Sstevel@tonic-gate { 24667c478bd9Sstevel@tonic-gate int hm_rev; 24677c478bd9Sstevel@tonic-gate 24687c478bd9Sstevel@tonic-gate 24697c478bd9Sstevel@tonic-gate hm_rev = hmep->asic_rev; 24707c478bd9Sstevel@tonic-gate switch (hm_rev) { 24717c478bd9Sstevel@tonic-gate case HME_2P1_REVID: 24727c478bd9Sstevel@tonic-gate case HME_2P1_REVID_OBP: 24737c478bd9Sstevel@tonic-gate HME_FAULT_MSG2(hmep, SEVERITY_NONE, DISPLAY_MSG, 247485025c03Sgd "SBus 2.1 Found (Rev Id = %x)", hm_rev); 24757c478bd9Sstevel@tonic-gate hmep->hme_mifpoll_enable = 1; 24767c478bd9Sstevel@tonic-gate hmep->hme_frame_enable = 1; 24777c478bd9Sstevel@tonic-gate break; 24787c478bd9Sstevel@tonic-gate 24797c478bd9Sstevel@tonic-gate case HME_2P0_REVID: 24807c478bd9Sstevel@tonic-gate HME_FAULT_MSG2(hmep, SEVERITY_NONE, DISPLAY_MSG, 248185025c03Sgd "SBus 2.0 Found (Rev Id = %x)", hm_rev); 24827c478bd9Sstevel@tonic-gate break; 24837c478bd9Sstevel@tonic-gate 24847c478bd9Sstevel@tonic-gate case HME_1C0_REVID: 24857c478bd9Sstevel@tonic-gate HME_FAULT_MSG2(hmep, SEVERITY_NONE, DISPLAY_MSG, 248685025c03Sgd "PCI IO 1.0 Found (Rev Id = %x)", hm_rev); 24877c478bd9Sstevel@tonic-gate break; 24887c478bd9Sstevel@tonic-gate 24897c478bd9Sstevel@tonic-gate default: 24907c478bd9Sstevel@tonic-gate HME_FAULT_MSG3(hmep, SEVERITY_HIGH, DISPLAY_MSG, 249185025c03Sgd "%s (Rev Id = %x) Found", 249285025c03Sgd (hm_rev == HME_2C0_REVID) ? "PCI IO 2.0" : "Sbus", hm_rev); 24937c478bd9Sstevel@tonic-gate hmep->hme_mifpoll_enable = 1; 24947c478bd9Sstevel@tonic-gate hmep->hme_frame_enable = 1; 24957c478bd9Sstevel@tonic-gate hmep->hme_lance_mode_enable = 1; 24967c478bd9Sstevel@tonic-gate hmep->hme_rxcv_enable = 1; 24977c478bd9Sstevel@tonic-gate break; 24987c478bd9Sstevel@tonic-gate } 24997c478bd9Sstevel@tonic-gate } 25007c478bd9Sstevel@tonic-gate 25017c478bd9Sstevel@tonic-gate /* 25027c478bd9Sstevel@tonic-gate * Interface exists: make available by filling in network interface 25037c478bd9Sstevel@tonic-gate * record. System will initialize the interface when it is ready 25047c478bd9Sstevel@tonic-gate * to accept packets. 25057c478bd9Sstevel@tonic-gate */ 2506f2cd0f02Sgd int 25077c478bd9Sstevel@tonic-gate hmeattach(dev_info_t *dip, ddi_attach_cmd_t cmd) 25087c478bd9Sstevel@tonic-gate { 25097c478bd9Sstevel@tonic-gate struct hme *hmep; 251085025c03Sgd mac_register_t *macp = NULL; 25117c478bd9Sstevel@tonic-gate int regno; 25127c478bd9Sstevel@tonic-gate int hm_rev = 0; 25137c478bd9Sstevel@tonic-gate int prop_len = sizeof (int); 25147c478bd9Sstevel@tonic-gate ddi_acc_handle_t cfg_handle; 25157c478bd9Sstevel@tonic-gate struct { 25167c478bd9Sstevel@tonic-gate uint16_t vendorid; 25177c478bd9Sstevel@tonic-gate uint16_t devid; 25187c478bd9Sstevel@tonic-gate uint16_t command; 25197c478bd9Sstevel@tonic-gate uint16_t status; 25207c478bd9Sstevel@tonic-gate uint8_t revid; 25217c478bd9Sstevel@tonic-gate uint8_t j1; 25227c478bd9Sstevel@tonic-gate uint16_t j2; 25237c478bd9Sstevel@tonic-gate } *cfg_ptr; 25247c478bd9Sstevel@tonic-gate 25257c478bd9Sstevel@tonic-gate switch (cmd) { 25267c478bd9Sstevel@tonic-gate case DDI_ATTACH: 25277c478bd9Sstevel@tonic-gate break; 25287c478bd9Sstevel@tonic-gate 25297c478bd9Sstevel@tonic-gate case DDI_RESUME: 25307c478bd9Sstevel@tonic-gate if ((hmep = ddi_get_driver_private(dip)) == NULL) 253185025c03Sgd return (DDI_FAILURE); 25327c478bd9Sstevel@tonic-gate 25337c478bd9Sstevel@tonic-gate hmep->hme_flags &= ~HMESUSPENDED; 25347c478bd9Sstevel@tonic-gate hmep->hme_linkcheck = 0; 253585025c03Sgd 2536228fdff0Sgd if (hmep->hme_started) 253785025c03Sgd (void) hmeinit(hmep); 25387c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 25397c478bd9Sstevel@tonic-gate 25407c478bd9Sstevel@tonic-gate default: 25417c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 25427c478bd9Sstevel@tonic-gate } 25437c478bd9Sstevel@tonic-gate 25447c478bd9Sstevel@tonic-gate /* 25457c478bd9Sstevel@tonic-gate * Allocate soft device data structure 25467c478bd9Sstevel@tonic-gate */ 2547*0219346bSGarrett D'Amore hmep = kmem_zalloc(sizeof (*hmep), KM_SLEEP); 25487c478bd9Sstevel@tonic-gate 25497c478bd9Sstevel@tonic-gate /* 25507c478bd9Sstevel@tonic-gate * Might as well set up elements of data structure 25517c478bd9Sstevel@tonic-gate */ 25527c478bd9Sstevel@tonic-gate hmep->dip = dip; 25537c478bd9Sstevel@tonic-gate hmep->instance = ddi_get_instance(dip); 25547c478bd9Sstevel@tonic-gate hmep->pagesize = ddi_ptob(dip, (ulong_t)1); /* IOMMU PSize */ 25557c478bd9Sstevel@tonic-gate 25567c478bd9Sstevel@tonic-gate /* 25577c478bd9Sstevel@tonic-gate * Might as well setup the driver private 25587c478bd9Sstevel@tonic-gate * structure as part of the dip. 25597c478bd9Sstevel@tonic-gate */ 25607c478bd9Sstevel@tonic-gate ddi_set_driver_private(dip, hmep); 25617c478bd9Sstevel@tonic-gate 25627c478bd9Sstevel@tonic-gate /* 25637c478bd9Sstevel@tonic-gate * Reject this device if it's in a slave-only slot. 25647c478bd9Sstevel@tonic-gate */ 25657c478bd9Sstevel@tonic-gate if (ddi_slaveonly(dip) == DDI_SUCCESS) { 25667c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG, 2567*0219346bSGarrett D'Amore "Dev not used - dev in slave only slot"); 25687c478bd9Sstevel@tonic-gate goto error_state; 25697c478bd9Sstevel@tonic-gate } 25707c478bd9Sstevel@tonic-gate 25717c478bd9Sstevel@tonic-gate /* 25727c478bd9Sstevel@tonic-gate * Map in the device registers. 25737c478bd9Sstevel@tonic-gate * 25747c478bd9Sstevel@tonic-gate * Reg # 0 is the Global register set 25757c478bd9Sstevel@tonic-gate * Reg # 1 is the ETX register set 25767c478bd9Sstevel@tonic-gate * Reg # 2 is the ERX register set 25777c478bd9Sstevel@tonic-gate * Reg # 3 is the BigMAC register set. 25787c478bd9Sstevel@tonic-gate * Reg # 4 is the MIF register set 25797c478bd9Sstevel@tonic-gate */ 25807c478bd9Sstevel@tonic-gate if (ddi_dev_nregs(dip, ®no) != (DDI_SUCCESS)) { 25817c478bd9Sstevel@tonic-gate HME_FAULT_MSG2(hmep, SEVERITY_HIGH, INIT_MSG, 258285025c03Sgd ddi_nregs_fail_msg, regno); 25837c478bd9Sstevel@tonic-gate goto error_state; 25847c478bd9Sstevel@tonic-gate } 25857c478bd9Sstevel@tonic-gate 25867c478bd9Sstevel@tonic-gate switch (regno) { 25877c478bd9Sstevel@tonic-gate case 5: 25887c478bd9Sstevel@tonic-gate hmep->hme_cheerio_mode = 0; 25897c478bd9Sstevel@tonic-gate break; 25907c478bd9Sstevel@tonic-gate case 2: 25917c478bd9Sstevel@tonic-gate case 3: /* for hot swap/plug, there will be 3 entries in "reg" prop */ 25927c478bd9Sstevel@tonic-gate hmep->hme_cheerio_mode = 1; 25937c478bd9Sstevel@tonic-gate break; 25947c478bd9Sstevel@tonic-gate default: 259585025c03Sgd HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 259685025c03Sgd bad_num_regs_msg); 25977c478bd9Sstevel@tonic-gate goto error_state; 25987c478bd9Sstevel@tonic-gate } 25997c478bd9Sstevel@tonic-gate 26007c478bd9Sstevel@tonic-gate /* Initialize device attributes structure */ 26017c478bd9Sstevel@tonic-gate hmep->hme_dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 26027c478bd9Sstevel@tonic-gate 26037c478bd9Sstevel@tonic-gate if (hmep->hme_cheerio_mode) 260485025c03Sgd hmep->hme_dev_attr.devacc_attr_endian_flags = 260585025c03Sgd DDI_STRUCTURE_LE_ACC; 26067c478bd9Sstevel@tonic-gate else 260785025c03Sgd hmep->hme_dev_attr.devacc_attr_endian_flags = 260885025c03Sgd DDI_STRUCTURE_BE_ACC; 26097c478bd9Sstevel@tonic-gate 26107c478bd9Sstevel@tonic-gate hmep->hme_dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 26117c478bd9Sstevel@tonic-gate 26127c478bd9Sstevel@tonic-gate if (hmep->hme_cheerio_mode) { 26137c478bd9Sstevel@tonic-gate uint8_t oldLT; 26147c478bd9Sstevel@tonic-gate uint8_t newLT = 0; 26157c478bd9Sstevel@tonic-gate dev_info_t *pdip; 26167c478bd9Sstevel@tonic-gate const char *pdrvname; 26177c478bd9Sstevel@tonic-gate 26187c478bd9Sstevel@tonic-gate /* 26197c478bd9Sstevel@tonic-gate * Map the PCI config space 26207c478bd9Sstevel@tonic-gate */ 26217c478bd9Sstevel@tonic-gate if (pci_config_setup(dip, &hmep->pci_config_handle) != 262285025c03Sgd DDI_SUCCESS) { 26237c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG, 262485025c03Sgd "pci_config_setup() failed.."); 26257c478bd9Sstevel@tonic-gate goto error_state; 26267c478bd9Sstevel@tonic-gate } 26277c478bd9Sstevel@tonic-gate 26287c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(dip, 1, 262985025c03Sgd (caddr_t *)&(hmep->hme_globregp), 0, 0, 263085025c03Sgd &hmep->hme_dev_attr, &hmep->hme_globregh)) { 26317c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG, 263285025c03Sgd mregs_4global_reg_fail_msg); 26337c478bd9Sstevel@tonic-gate goto error_unmap; 26347c478bd9Sstevel@tonic-gate } 26357c478bd9Sstevel@tonic-gate hmep->hme_etxregh = hmep->hme_erxregh = hmep->hme_bmacregh = 26367c478bd9Sstevel@tonic-gate hmep->hme_mifregh = hmep->hme_globregh; 26377c478bd9Sstevel@tonic-gate 263885025c03Sgd hmep->hme_etxregp = 263985025c03Sgd (void *)(((caddr_t)hmep->hme_globregp) + 0x2000); 264085025c03Sgd hmep->hme_erxregp = 264185025c03Sgd (void *)(((caddr_t)hmep->hme_globregp) + 0x4000); 264285025c03Sgd hmep->hme_bmacregp = 264385025c03Sgd (void *)(((caddr_t)hmep->hme_globregp) + 0x6000); 264485025c03Sgd hmep->hme_mifregp = 264585025c03Sgd (void *)(((caddr_t)hmep->hme_globregp) + 0x7000); 26467c478bd9Sstevel@tonic-gate 26477c478bd9Sstevel@tonic-gate /* 26487c478bd9Sstevel@tonic-gate * Get parent pci bridge info. 26497c478bd9Sstevel@tonic-gate */ 26507c478bd9Sstevel@tonic-gate pdip = ddi_get_parent(dip); 26517c478bd9Sstevel@tonic-gate pdrvname = ddi_driver_name(pdip); 26527c478bd9Sstevel@tonic-gate 26537c478bd9Sstevel@tonic-gate oldLT = pci_config_get8(hmep->pci_config_handle, 265485025c03Sgd PCI_CONF_LATENCY_TIMER); 26557c478bd9Sstevel@tonic-gate /* 26567c478bd9Sstevel@tonic-gate * Honor value set in /etc/system 26577c478bd9Sstevel@tonic-gate * "set hme:pci_latency_timer=0xYY" 26587c478bd9Sstevel@tonic-gate */ 26597c478bd9Sstevel@tonic-gate if (pci_latency_timer) 26607c478bd9Sstevel@tonic-gate newLT = pci_latency_timer; 26617c478bd9Sstevel@tonic-gate /* 26627c478bd9Sstevel@tonic-gate * Modify LT for simba 26637c478bd9Sstevel@tonic-gate */ 26647c478bd9Sstevel@tonic-gate else if (strcmp("simba", pdrvname) == 0) 26657c478bd9Sstevel@tonic-gate newLT = 0xf0; 26667c478bd9Sstevel@tonic-gate /* 26677c478bd9Sstevel@tonic-gate * Ensure minimum cheerio latency timer of 0x50 26687c478bd9Sstevel@tonic-gate * Usually OBP or pci bridge should set this value 26697c478bd9Sstevel@tonic-gate * based on cheerio 26707c478bd9Sstevel@tonic-gate * min_grant * 8(33MHz) = 0x50 = 0xa * 0x8 26717c478bd9Sstevel@tonic-gate * Some system set cheerio LT at 0x40 26727c478bd9Sstevel@tonic-gate */ 26737c478bd9Sstevel@tonic-gate else if (oldLT < 0x40) 26747c478bd9Sstevel@tonic-gate newLT = 0x50; 26757c478bd9Sstevel@tonic-gate 26767c478bd9Sstevel@tonic-gate /* 26777c478bd9Sstevel@tonic-gate * Now program cheerio's pci latency timer with newLT 26787c478bd9Sstevel@tonic-gate */ 26797c478bd9Sstevel@tonic-gate if (newLT) 26807c478bd9Sstevel@tonic-gate pci_config_put8(hmep->pci_config_handle, 268185025c03Sgd PCI_CONF_LATENCY_TIMER, (uchar_t)newLT); 26827c478bd9Sstevel@tonic-gate } else { /* Map register sets */ 26837c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(dip, 0, 268485025c03Sgd (caddr_t *)&(hmep->hme_globregp), 0, 0, 268585025c03Sgd &hmep->hme_dev_attr, &hmep->hme_globregh)) { 26867c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG, 268785025c03Sgd mregs_4global_reg_fail_msg); 26887c478bd9Sstevel@tonic-gate goto error_state; 26897c478bd9Sstevel@tonic-gate } 26907c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(dip, 1, 269185025c03Sgd (caddr_t *)&(hmep->hme_etxregp), 0, 0, 269285025c03Sgd &hmep->hme_dev_attr, &hmep->hme_etxregh)) { 26937c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG, 269485025c03Sgd mregs_4etx_reg_fail_msg); 26957c478bd9Sstevel@tonic-gate goto error_unmap; 26967c478bd9Sstevel@tonic-gate } 26977c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(dip, 2, 269885025c03Sgd (caddr_t *)&(hmep->hme_erxregp), 0, 0, 269985025c03Sgd &hmep->hme_dev_attr, &hmep->hme_erxregh)) { 27007c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG, 270185025c03Sgd mregs_4erx_reg_fail_msg); 27027c478bd9Sstevel@tonic-gate goto error_unmap; 27037c478bd9Sstevel@tonic-gate } 27047c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(dip, 3, 270585025c03Sgd (caddr_t *)&(hmep->hme_bmacregp), 0, 0, 270685025c03Sgd &hmep->hme_dev_attr, &hmep->hme_bmacregh)) { 27077c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG, 270885025c03Sgd mregs_4bmac_reg_fail_msg); 27097c478bd9Sstevel@tonic-gate goto error_unmap; 27107c478bd9Sstevel@tonic-gate } 27117c478bd9Sstevel@tonic-gate 27127c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(dip, 4, 271385025c03Sgd (caddr_t *)&(hmep->hme_mifregp), 0, 0, 271485025c03Sgd &hmep->hme_dev_attr, &hmep->hme_mifregh)) { 27157c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG, 271685025c03Sgd mregs_4mif_reg_fail_msg); 27177c478bd9Sstevel@tonic-gate goto error_unmap; 27187c478bd9Sstevel@tonic-gate } 27197c478bd9Sstevel@tonic-gate } /* Endif cheerio_mode */ 27207c478bd9Sstevel@tonic-gate 27217c478bd9Sstevel@tonic-gate /* 27227c478bd9Sstevel@tonic-gate * Based on the hm-rev, set some capabilities 27237c478bd9Sstevel@tonic-gate * Set up default capabilities for HM 2.0 27247c478bd9Sstevel@tonic-gate */ 27257c478bd9Sstevel@tonic-gate hmep->hme_mifpoll_enable = 0; 27267c478bd9Sstevel@tonic-gate hmep->hme_frame_enable = 0; 27277c478bd9Sstevel@tonic-gate hmep->hme_lance_mode_enable = 0; 27287c478bd9Sstevel@tonic-gate hmep->hme_rxcv_enable = 0; 27297c478bd9Sstevel@tonic-gate 27307c478bd9Sstevel@tonic-gate /* NEW routine to get the properties */ 27317c478bd9Sstevel@tonic-gate 27327c478bd9Sstevel@tonic-gate if (ddi_getlongprop_buf(DDI_DEV_T_ANY, hmep->dip, 0, "hm-rev", 273385025c03Sgd (caddr_t)&hm_rev, &prop_len) == DDI_PROP_SUCCESS) { 27347c478bd9Sstevel@tonic-gate 27357c478bd9Sstevel@tonic-gate hmep->asic_rev = hm_rev; 27367c478bd9Sstevel@tonic-gate hmeget_hm_rev_property(hmep); 27377c478bd9Sstevel@tonic-gate } else { 27387c478bd9Sstevel@tonic-gate /* 27397c478bd9Sstevel@tonic-gate * hm_rev property not found so, this is 27407c478bd9Sstevel@tonic-gate * case of hot insertion of card without interpreting fcode. 27417c478bd9Sstevel@tonic-gate * Get it from revid in config space after mapping it. 27427c478bd9Sstevel@tonic-gate */ 27437c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(hmep->dip, 0, (caddr_t *)&cfg_ptr, 274485025c03Sgd 0, 0, &hmep->hme_dev_attr, &cfg_handle)) { 27457c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 27467c478bd9Sstevel@tonic-gate } 27477c478bd9Sstevel@tonic-gate /* 27487c478bd9Sstevel@tonic-gate * Since this is cheerio-based PCI card, we write 0xC in the 27497c478bd9Sstevel@tonic-gate * top 4 bits(4-7) of hm-rev and retain the bottom(0-3) bits 27507c478bd9Sstevel@tonic-gate * for Cheerio version(1.0 or 2.0 = 0xC0 or 0xC1) 27517c478bd9Sstevel@tonic-gate */ 27527c478bd9Sstevel@tonic-gate hm_rev = ddi_get8(cfg_handle, &cfg_ptr->revid); 27537c478bd9Sstevel@tonic-gate hm_rev = HME_1C0_REVID | (hm_rev & HME_REV_VERS_MASK); 27547c478bd9Sstevel@tonic-gate hmep->asic_rev = hm_rev; 27557c478bd9Sstevel@tonic-gate if (ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, 275685025c03Sgd "hm-rev", (caddr_t)&hm_rev, sizeof (hm_rev)) != 275785025c03Sgd DDI_SUCCESS) { 27587c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, AUTOCONFIG_MSG, 275985025c03Sgd "hmeattach: ddi_prop_create error for hm_rev"); 27607c478bd9Sstevel@tonic-gate } 27617c478bd9Sstevel@tonic-gate ddi_regs_map_free(&cfg_handle); 27627c478bd9Sstevel@tonic-gate 27637c478bd9Sstevel@tonic-gate hmeget_hm_rev_property(hmep); 27647c478bd9Sstevel@tonic-gate 27657c478bd9Sstevel@tonic-gate /* get info via VPD */ 2766*0219346bSGarrett D'Amore if (hmeget_promprops(dip) != DDI_SUCCESS) { 27677c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, AUTOCONFIG_MSG, 276885025c03Sgd "hmeattach: no promprops"); 27697c478bd9Sstevel@tonic-gate } 27707c478bd9Sstevel@tonic-gate } 27717c478bd9Sstevel@tonic-gate 27727c478bd9Sstevel@tonic-gate if (!hme_mifpoll_enable) 27737c478bd9Sstevel@tonic-gate hmep->hme_mifpoll_enable = 0; 27747c478bd9Sstevel@tonic-gate 27757c478bd9Sstevel@tonic-gate if (ddi_intr_hilevel(dip, 0)) { 27767c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_HIGH, NFATAL_ERR_MSG, 277785025c03Sgd " high-level interrupts are not supported"); 27787c478bd9Sstevel@tonic-gate goto error_unmap; 27797c478bd9Sstevel@tonic-gate } 27807c478bd9Sstevel@tonic-gate 27817c478bd9Sstevel@tonic-gate /* 27827c478bd9Sstevel@tonic-gate * Get intr. block cookie so that mutex locks can be initialized. 27837c478bd9Sstevel@tonic-gate */ 27847c478bd9Sstevel@tonic-gate if (ddi_get_iblock_cookie(dip, 0, &hmep->hme_cookie) != DDI_SUCCESS) 27857c478bd9Sstevel@tonic-gate goto error_unmap; 27867c478bd9Sstevel@tonic-gate 27877c478bd9Sstevel@tonic-gate /* 27887c478bd9Sstevel@tonic-gate * Initialize mutex's for this device. 27897c478bd9Sstevel@tonic-gate */ 279085025c03Sgd mutex_init(&hmep->hme_xmitlock, NULL, MUTEX_DRIVER, hmep->hme_cookie); 279185025c03Sgd mutex_init(&hmep->hme_intrlock, NULL, MUTEX_DRIVER, hmep->hme_cookie); 279285025c03Sgd mutex_init(&hmep->hme_linklock, NULL, MUTEX_DRIVER, hmep->hme_cookie); 27937c478bd9Sstevel@tonic-gate 27947c478bd9Sstevel@tonic-gate /* 27957c478bd9Sstevel@tonic-gate * Quiesce the hardware. 27967c478bd9Sstevel@tonic-gate */ 27977c478bd9Sstevel@tonic-gate (void) hmestop(hmep); 27987c478bd9Sstevel@tonic-gate 27997c478bd9Sstevel@tonic-gate /* 28007c478bd9Sstevel@tonic-gate * Add interrupt to system 28017c478bd9Sstevel@tonic-gate */ 28027c478bd9Sstevel@tonic-gate if (ddi_add_intr(dip, 0, (ddi_iblock_cookie_t *)NULL, 28037c478bd9Sstevel@tonic-gate (ddi_idevice_cookie_t *)NULL, hmeintr, (caddr_t)hmep)) { 28047c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG, 280585025c03Sgd add_intr_fail_msg); 28067c478bd9Sstevel@tonic-gate goto error_mutex; 28077c478bd9Sstevel@tonic-gate } 28087c478bd9Sstevel@tonic-gate 28097c478bd9Sstevel@tonic-gate /* 28107c478bd9Sstevel@tonic-gate * Set up the ethernet mac address. 28117c478bd9Sstevel@tonic-gate */ 28127c478bd9Sstevel@tonic-gate hme_setup_mac_address(hmep, dip); 28137c478bd9Sstevel@tonic-gate 28147c478bd9Sstevel@tonic-gate if (!hmeinit_xfer_params(hmep)) 281585025c03Sgd goto error_intr; 28167c478bd9Sstevel@tonic-gate 28177c478bd9Sstevel@tonic-gate if (hmeburstsizes(hmep) == DDI_FAILURE) { 28187c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, burst_size_msg); 281985025c03Sgd goto error_intr; 28207c478bd9Sstevel@tonic-gate } 28217c478bd9Sstevel@tonic-gate 2822*0219346bSGarrett D'Amore if (hmeallocthings(hmep) != DDI_SUCCESS) { 2823*0219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, CONFIG_MSG, 2824*0219346bSGarrett D'Amore "resource allocation failed"); 2825*0219346bSGarrett D'Amore goto error_intr; 2826*0219346bSGarrett D'Amore } 2827*0219346bSGarrett D'Amore 2828*0219346bSGarrett D'Amore if (hmeallocbufs(hmep) != DDI_SUCCESS) { 2829*0219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, CONFIG_MSG, 2830*0219346bSGarrett D'Amore "buffer allocation failed"); 2831*0219346bSGarrett D'Amore goto error_intr; 2832*0219346bSGarrett D'Amore } 28337c478bd9Sstevel@tonic-gate 28347c478bd9Sstevel@tonic-gate hmestatinit(hmep); 283585025c03Sgd 283685025c03Sgd if ((macp = mac_alloc(MAC_VERSION)) == NULL) { 283785025c03Sgd HME_FAULT_MSG1(hmep, SEVERITY_HIGH, CONFIG_MSG, 283885025c03Sgd "mac_alloc failed"); 283985025c03Sgd goto error_intr; 284085025c03Sgd } 284185025c03Sgd macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 284285025c03Sgd macp->m_driver = hmep; 284385025c03Sgd macp->m_dip = dip; 284485025c03Sgd macp->m_src_addr = hmep->hme_ouraddr.ether_addr_octet; 284585025c03Sgd macp->m_callbacks = &hme_m_callbacks; 284685025c03Sgd macp->m_min_sdu = 0; 284785025c03Sgd macp->m_max_sdu = ETHERMTU; 2848d62bc4baSyz macp->m_margin = VLAN_TAGSZ; 284985025c03Sgd if (mac_register(macp, &hmep->hme_mh) != 0) { 285085025c03Sgd mac_free(macp); 285185025c03Sgd goto error_intr; 285285025c03Sgd } 285385025c03Sgd 285485025c03Sgd mac_free(macp); 285585025c03Sgd 28567c478bd9Sstevel@tonic-gate ddi_report_dev(dip); 28577c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 28587c478bd9Sstevel@tonic-gate 28597c478bd9Sstevel@tonic-gate /* 28607c478bd9Sstevel@tonic-gate * Failure Exit 28617c478bd9Sstevel@tonic-gate */ 28627c478bd9Sstevel@tonic-gate 28637c478bd9Sstevel@tonic-gate error_intr: 28647c478bd9Sstevel@tonic-gate if (hmep->hme_cookie) 28657c478bd9Sstevel@tonic-gate ddi_remove_intr(dip, 0, (ddi_iblock_cookie_t)0); 28667c478bd9Sstevel@tonic-gate 28677c478bd9Sstevel@tonic-gate error_mutex: 28687c478bd9Sstevel@tonic-gate mutex_destroy(&hmep->hme_xmitlock); 28697c478bd9Sstevel@tonic-gate mutex_destroy(&hmep->hme_intrlock); 28707c478bd9Sstevel@tonic-gate mutex_destroy(&hmep->hme_linklock); 28717c478bd9Sstevel@tonic-gate 28727c478bd9Sstevel@tonic-gate error_unmap: 28737c478bd9Sstevel@tonic-gate if (hmep->hme_globregh) 287485025c03Sgd ddi_regs_map_free(&hmep->hme_globregh); 28757c478bd9Sstevel@tonic-gate if (hmep->hme_cheerio_mode == 0) { 28767c478bd9Sstevel@tonic-gate if (hmep->hme_etxregh) 287785025c03Sgd ddi_regs_map_free(&hmep->hme_etxregh); 28787c478bd9Sstevel@tonic-gate if (hmep->hme_erxregh) 287985025c03Sgd ddi_regs_map_free(&hmep->hme_erxregh); 28807c478bd9Sstevel@tonic-gate if (hmep->hme_bmacregh) 288185025c03Sgd ddi_regs_map_free(&hmep->hme_bmacregh); 28827c478bd9Sstevel@tonic-gate if (hmep->hme_mifregh) 288385025c03Sgd ddi_regs_map_free(&hmep->hme_mifregh); 28847c478bd9Sstevel@tonic-gate } else { 28857c478bd9Sstevel@tonic-gate if (hmep->pci_config_handle) 28867c478bd9Sstevel@tonic-gate (void) pci_config_teardown(&hmep->pci_config_handle); 28877c478bd9Sstevel@tonic-gate hmep->hme_etxregh = hmep->hme_erxregh = hmep->hme_bmacregh = 28887c478bd9Sstevel@tonic-gate hmep->hme_mifregh = hmep->hme_globregh = NULL; 28897c478bd9Sstevel@tonic-gate } 28907c478bd9Sstevel@tonic-gate 28917c478bd9Sstevel@tonic-gate error_state: 2892*0219346bSGarrett D'Amore hmefreethings(hmep); 2893*0219346bSGarrett D'Amore hmefreebufs(hmep); 2894*0219346bSGarrett D'Amore 28957c478bd9Sstevel@tonic-gate if (hmep) { 28967c478bd9Sstevel@tonic-gate kmem_free((caddr_t)hmep, sizeof (*hmep)); 28977c478bd9Sstevel@tonic-gate ddi_set_driver_private(dip, NULL); 28987c478bd9Sstevel@tonic-gate } 28997c478bd9Sstevel@tonic-gate 29007c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 29017c478bd9Sstevel@tonic-gate } 29027c478bd9Sstevel@tonic-gate 2903f2cd0f02Sgd int 29047c478bd9Sstevel@tonic-gate hmedetach(dev_info_t *dip, ddi_detach_cmd_t cmd) 29057c478bd9Sstevel@tonic-gate { 290685025c03Sgd struct hme *hmep; 29077c478bd9Sstevel@tonic-gate 29087c478bd9Sstevel@tonic-gate if ((hmep = ddi_get_driver_private(dip)) == NULL) 29097c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 29107c478bd9Sstevel@tonic-gate 29117c478bd9Sstevel@tonic-gate switch (cmd) { 29127c478bd9Sstevel@tonic-gate case DDI_DETACH: 29137c478bd9Sstevel@tonic-gate break; 29147c478bd9Sstevel@tonic-gate 29157c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 29167c478bd9Sstevel@tonic-gate hmep->hme_flags |= HMESUSPENDED; 29177c478bd9Sstevel@tonic-gate hmeuninit(hmep); 29187c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 29197c478bd9Sstevel@tonic-gate 29207c478bd9Sstevel@tonic-gate default: 292185025c03Sgd return (DDI_FAILURE); 292285025c03Sgd } 292385025c03Sgd 292485025c03Sgd 292585025c03Sgd if (mac_unregister(hmep->hme_mh) != 0) { 29267c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 29277c478bd9Sstevel@tonic-gate } 29287c478bd9Sstevel@tonic-gate 29297c478bd9Sstevel@tonic-gate /* 29307c478bd9Sstevel@tonic-gate * Make driver quiescent, we don't want to prevent the 29314dd87b61Sgd * detach on failure. Note that this should be redundant, 29324dd87b61Sgd * since mac_stop should already have called hmeuninit(). 29337c478bd9Sstevel@tonic-gate */ 29344dd87b61Sgd if (!(hmep->hme_flags & HMESUSPENDED)) { 29354dd87b61Sgd (void) hmestop(hmep); 29364dd87b61Sgd } 29377c478bd9Sstevel@tonic-gate 29387c478bd9Sstevel@tonic-gate /* 29397c478bd9Sstevel@tonic-gate * Remove instance of the intr 29407c478bd9Sstevel@tonic-gate */ 29417c478bd9Sstevel@tonic-gate ddi_remove_intr(dip, 0, (ddi_iblock_cookie_t)0); 29427c478bd9Sstevel@tonic-gate 294385025c03Sgd /* 294485025c03Sgd * Unregister kstats. 294585025c03Sgd */ 294685025c03Sgd if (hmep->hme_ksp != NULL) 294785025c03Sgd kstat_delete(hmep->hme_ksp); 294885025c03Sgd if (hmep->hme_intrstats != NULL) 294985025c03Sgd kstat_delete(hmep->hme_intrstats); 295085025c03Sgd 295185025c03Sgd hmep->hme_ksp = NULL; 295285025c03Sgd hmep->hme_intrstats = NULL; 295385025c03Sgd 295485025c03Sgd /* 295585025c03Sgd * Stop asynchronous timer events. 295685025c03Sgd */ 295785025c03Sgd hme_stop_timer(hmep); 295885025c03Sgd mutex_exit(&hmep->hme_linklock); 295985025c03Sgd 29607c478bd9Sstevel@tonic-gate /* 29617c478bd9Sstevel@tonic-gate * Destroy all mutexes and data structures allocated during 29627c478bd9Sstevel@tonic-gate * attach time. 296385025c03Sgd * 296485025c03Sgd * Note: at this time we should be the only thread accessing 296585025c03Sgd * the structures for this instance. 29667c478bd9Sstevel@tonic-gate */ 29677c478bd9Sstevel@tonic-gate 29687c478bd9Sstevel@tonic-gate if (hmep->hme_globregh) 29697c478bd9Sstevel@tonic-gate ddi_regs_map_free(&hmep->hme_globregh); 29707c478bd9Sstevel@tonic-gate if (hmep->hme_cheerio_mode == 0) { 29717c478bd9Sstevel@tonic-gate if (hmep->hme_etxregh) 297285025c03Sgd ddi_regs_map_free(&hmep->hme_etxregh); 29737c478bd9Sstevel@tonic-gate if (hmep->hme_erxregh) 297485025c03Sgd ddi_regs_map_free(&hmep->hme_erxregh); 29757c478bd9Sstevel@tonic-gate if (hmep->hme_bmacregh) 297685025c03Sgd ddi_regs_map_free(&hmep->hme_bmacregh); 29777c478bd9Sstevel@tonic-gate if (hmep->hme_mifregh) 297885025c03Sgd ddi_regs_map_free(&hmep->hme_mifregh); 29797c478bd9Sstevel@tonic-gate } else { 29807c478bd9Sstevel@tonic-gate if (hmep->pci_config_handle) 29817c478bd9Sstevel@tonic-gate (void) pci_config_teardown(&hmep->pci_config_handle); 29827c478bd9Sstevel@tonic-gate hmep->hme_etxregh = hmep->hme_erxregh = hmep->hme_bmacregh = 29837c478bd9Sstevel@tonic-gate hmep->hme_mifregh = hmep->hme_globregh = NULL; 29847c478bd9Sstevel@tonic-gate } 29857c478bd9Sstevel@tonic-gate 298685025c03Sgd mutex_destroy(&hmep->hme_xmitlock); 298785025c03Sgd mutex_destroy(&hmep->hme_intrlock); 298885025c03Sgd mutex_destroy(&hmep->hme_linklock); 29897c478bd9Sstevel@tonic-gate 2990*0219346bSGarrett D'Amore hmefreethings(hmep); 299185025c03Sgd hmefreebufs(hmep); 29927c478bd9Sstevel@tonic-gate 299385025c03Sgd hme_param_cleanup(hmep); 29947c478bd9Sstevel@tonic-gate 299585025c03Sgd ddi_set_driver_private(dip, NULL); 299685025c03Sgd kmem_free(hmep, sizeof (struct hme)); 29977c478bd9Sstevel@tonic-gate 29987c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 29997c478bd9Sstevel@tonic-gate } 30007c478bd9Sstevel@tonic-gate 3001*0219346bSGarrett D'Amore int 3002*0219346bSGarrett D'Amore hmequiesce(dev_info_t *dip) 3003*0219346bSGarrett D'Amore { 3004*0219346bSGarrett D'Amore struct hme *hmep; 3005*0219346bSGarrett D'Amore 3006*0219346bSGarrett D'Amore if ((hmep = ddi_get_driver_private(dip)) == NULL) 3007*0219346bSGarrett D'Amore return (DDI_FAILURE); 3008*0219346bSGarrett D'Amore 3009*0219346bSGarrett D'Amore hme_stop_mifpoll(hmep); 3010*0219346bSGarrett D'Amore (void) hmestop(hmep); 3011*0219346bSGarrett D'Amore return (DDI_SUCCESS); 3012*0219346bSGarrett D'Amore } 3013*0219346bSGarrett D'Amore 301485025c03Sgd static boolean_t 30157c478bd9Sstevel@tonic-gate hmeinit_xfer_params(struct hme *hmep) 30167c478bd9Sstevel@tonic-gate { 30177c478bd9Sstevel@tonic-gate int i; 30187c478bd9Sstevel@tonic-gate int hme_ipg1_conf, hme_ipg2_conf; 30197c478bd9Sstevel@tonic-gate int hme_use_int_xcvr_conf, hme_pace_count_conf; 30207c478bd9Sstevel@tonic-gate int hme_autoneg_conf; 30217c478bd9Sstevel@tonic-gate int hme_anar_100T4_conf; 30227c478bd9Sstevel@tonic-gate int hme_anar_100fdx_conf, hme_anar_100hdx_conf; 30237c478bd9Sstevel@tonic-gate int hme_anar_10fdx_conf, hme_anar_10hdx_conf; 30247c478bd9Sstevel@tonic-gate int hme_ipg0_conf, hme_lance_mode_conf; 30257c478bd9Sstevel@tonic-gate int prop_len = sizeof (int); 30267c478bd9Sstevel@tonic-gate dev_info_t *dip; 30277c478bd9Sstevel@tonic-gate 30287c478bd9Sstevel@tonic-gate dip = hmep->dip; 30297c478bd9Sstevel@tonic-gate 30307c478bd9Sstevel@tonic-gate for (i = 0; i < A_CNT(hme_param_arr); i++) 30317c478bd9Sstevel@tonic-gate hmep->hme_param_arr[i] = hme_param_arr[i]; 30327c478bd9Sstevel@tonic-gate 30337c478bd9Sstevel@tonic-gate if (!hmep->hme_g_nd && !hme_param_register(hmep, hmep->hme_param_arr, 303485025c03Sgd A_CNT(hme_param_arr))) { 30357c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, NDD_MSG, 303685025c03Sgd param_reg_fail_msg); 30377c478bd9Sstevel@tonic-gate return (B_FALSE); 30387c478bd9Sstevel@tonic-gate } 30397c478bd9Sstevel@tonic-gate 30407c478bd9Sstevel@tonic-gate /* 30417c478bd9Sstevel@tonic-gate * Set up the start-up values for user-configurable parameters 30427c478bd9Sstevel@tonic-gate * Get the values from the global variables first. 30437c478bd9Sstevel@tonic-gate * Use the MASK to limit the value to allowed maximum. 30447c478bd9Sstevel@tonic-gate */ 30457c478bd9Sstevel@tonic-gate hme_param_ipg1 = hme_ipg1 & HME_MASK_8BIT; 30467c478bd9Sstevel@tonic-gate hme_param_ipg2 = hme_ipg2 & HME_MASK_8BIT; 30477c478bd9Sstevel@tonic-gate hme_param_use_intphy = hme_use_int_xcvr & HME_MASK_1BIT; 30487c478bd9Sstevel@tonic-gate hme_param_pace_count = hme_pace_size & HME_MASK_8BIT; 30497c478bd9Sstevel@tonic-gate hme_param_autoneg = hme_adv_autoneg_cap; 30507c478bd9Sstevel@tonic-gate hme_param_anar_100T4 = hme_adv_100T4_cap; 30517c478bd9Sstevel@tonic-gate hme_param_anar_100fdx = hme_adv_100fdx_cap; 30527c478bd9Sstevel@tonic-gate hme_param_anar_100hdx = hme_adv_100hdx_cap; 30537c478bd9Sstevel@tonic-gate hme_param_anar_10fdx = hme_adv_10fdx_cap; 30547c478bd9Sstevel@tonic-gate hme_param_anar_10hdx = hme_adv_10hdx_cap; 30557c478bd9Sstevel@tonic-gate hme_param_ipg0 = hme_ipg0 & HME_MASK_5BIT; 30567c478bd9Sstevel@tonic-gate hme_param_lance_mode = hme_lance_mode & HME_MASK_1BIT; 30577c478bd9Sstevel@tonic-gate 30587c478bd9Sstevel@tonic-gate /* 30597c478bd9Sstevel@tonic-gate * The link speed may be forced to either 10 Mbps or 100 Mbps using the 30607c478bd9Sstevel@tonic-gate * property "transfer-speed". This may be done in OBP by using the 30617c478bd9Sstevel@tonic-gate * command "apply transfer-speed=<speed> <device>". The speed may be 30627c478bd9Sstevel@tonic-gate * either 10 or 100. 30637c478bd9Sstevel@tonic-gate */ 30647c478bd9Sstevel@tonic-gate if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, 306585025c03Sgd "transfer-speed", (caddr_t)&i, &prop_len) == DDI_PROP_SUCCESS) { 30667c478bd9Sstevel@tonic-gate hme_param_autoneg = 0; /* force speed */ 30677c478bd9Sstevel@tonic-gate hme_param_anar_100T4 = 0; 30687c478bd9Sstevel@tonic-gate hme_param_anar_100fdx = 0; 30697c478bd9Sstevel@tonic-gate hme_param_anar_10fdx = 0; 30707c478bd9Sstevel@tonic-gate if (i == 10) { 30717c478bd9Sstevel@tonic-gate hme_param_anar_10hdx = 1; 30727c478bd9Sstevel@tonic-gate hme_param_anar_100hdx = 0; 30737c478bd9Sstevel@tonic-gate } else { 30747c478bd9Sstevel@tonic-gate hme_param_anar_10hdx = 0; 30757c478bd9Sstevel@tonic-gate hme_param_anar_100hdx = 1; 30767c478bd9Sstevel@tonic-gate } 30777c478bd9Sstevel@tonic-gate } 30787c478bd9Sstevel@tonic-gate 30797c478bd9Sstevel@tonic-gate /* 30807c478bd9Sstevel@tonic-gate * Get the parameter values configured in .conf file. 30817c478bd9Sstevel@tonic-gate */ 30827c478bd9Sstevel@tonic-gate if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "ipg1", 308385025c03Sgd (caddr_t)&hme_ipg1_conf, &prop_len) == DDI_PROP_SUCCESS) { 30847c478bd9Sstevel@tonic-gate hme_param_ipg1 = hme_ipg1_conf & HME_MASK_8BIT; 30857c478bd9Sstevel@tonic-gate } 30867c478bd9Sstevel@tonic-gate 30877c478bd9Sstevel@tonic-gate if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "ipg2", 308885025c03Sgd (caddr_t)&hme_ipg2_conf, &prop_len) == DDI_PROP_SUCCESS) { 30897c478bd9Sstevel@tonic-gate hme_param_ipg2 = hme_ipg2_conf & HME_MASK_8BIT; 30907c478bd9Sstevel@tonic-gate } 30917c478bd9Sstevel@tonic-gate 30927c478bd9Sstevel@tonic-gate if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "use_int_xcvr", 309385025c03Sgd (caddr_t)&hme_use_int_xcvr_conf, &prop_len) == DDI_PROP_SUCCESS) { 30947c478bd9Sstevel@tonic-gate hme_param_use_intphy = hme_use_int_xcvr_conf & HME_MASK_1BIT; 30957c478bd9Sstevel@tonic-gate } 30967c478bd9Sstevel@tonic-gate 30977c478bd9Sstevel@tonic-gate if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "pace_size", 309885025c03Sgd (caddr_t)&hme_pace_count_conf, &prop_len) == DDI_PROP_SUCCESS) { 30997c478bd9Sstevel@tonic-gate hme_param_pace_count = hme_pace_count_conf & HME_MASK_8BIT; 31007c478bd9Sstevel@tonic-gate } 31017c478bd9Sstevel@tonic-gate 31027c478bd9Sstevel@tonic-gate if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "adv_autoneg_cap", 310385025c03Sgd (caddr_t)&hme_autoneg_conf, &prop_len) == DDI_PROP_SUCCESS) { 31047c478bd9Sstevel@tonic-gate hme_param_autoneg = hme_autoneg_conf & HME_MASK_1BIT; 31057c478bd9Sstevel@tonic-gate } 31067c478bd9Sstevel@tonic-gate 31077c478bd9Sstevel@tonic-gate if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "adv_100T4_cap", 310885025c03Sgd (caddr_t)&hme_anar_100T4_conf, &prop_len) == DDI_PROP_SUCCESS) { 31097c478bd9Sstevel@tonic-gate hme_param_anar_100T4 = hme_anar_100T4_conf & HME_MASK_1BIT; 31107c478bd9Sstevel@tonic-gate } 31117c478bd9Sstevel@tonic-gate 31127c478bd9Sstevel@tonic-gate if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "adv_100fdx_cap", 311385025c03Sgd (caddr_t)&hme_anar_100fdx_conf, &prop_len) == DDI_PROP_SUCCESS) { 31147c478bd9Sstevel@tonic-gate hme_param_anar_100fdx = hme_anar_100fdx_conf & HME_MASK_1BIT; 31157c478bd9Sstevel@tonic-gate } 31167c478bd9Sstevel@tonic-gate 31177c478bd9Sstevel@tonic-gate if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "adv_100hdx_cap", 311885025c03Sgd (caddr_t)&hme_anar_100hdx_conf, &prop_len) == DDI_PROP_SUCCESS) { 31197c478bd9Sstevel@tonic-gate hme_param_anar_100hdx = hme_anar_100hdx_conf & HME_MASK_1BIT; 31207c478bd9Sstevel@tonic-gate } 31217c478bd9Sstevel@tonic-gate 31227c478bd9Sstevel@tonic-gate if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "adv_10fdx_cap", 312385025c03Sgd (caddr_t)&hme_anar_10fdx_conf, &prop_len) == DDI_PROP_SUCCESS) { 31247c478bd9Sstevel@tonic-gate hme_param_anar_10fdx = hme_anar_10fdx_conf & HME_MASK_1BIT; 31257c478bd9Sstevel@tonic-gate } 31267c478bd9Sstevel@tonic-gate 31277c478bd9Sstevel@tonic-gate if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "adv_10hdx_cap", 312885025c03Sgd (caddr_t)&hme_anar_10hdx_conf, &prop_len) == DDI_PROP_SUCCESS) { 31297c478bd9Sstevel@tonic-gate hme_param_anar_10hdx = hme_anar_10hdx_conf & HME_MASK_1BIT; 31307c478bd9Sstevel@tonic-gate } 31317c478bd9Sstevel@tonic-gate 31327c478bd9Sstevel@tonic-gate if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "ipg0", 313385025c03Sgd (caddr_t)&hme_ipg0_conf, &prop_len) == DDI_PROP_SUCCESS) { 31347c478bd9Sstevel@tonic-gate hme_param_ipg0 = hme_ipg0_conf & HME_MASK_5BIT; 31357c478bd9Sstevel@tonic-gate } 31367c478bd9Sstevel@tonic-gate 31377c478bd9Sstevel@tonic-gate if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "lance_mode", 313885025c03Sgd (caddr_t)&hme_lance_mode_conf, &prop_len) == DDI_PROP_SUCCESS) { 31397c478bd9Sstevel@tonic-gate hme_param_lance_mode = hme_lance_mode_conf & HME_MASK_1BIT; 31407c478bd9Sstevel@tonic-gate } 31417c478bd9Sstevel@tonic-gate 31427c478bd9Sstevel@tonic-gate if (hme_link_pulse_disabled) 31437c478bd9Sstevel@tonic-gate hmep->hme_link_pulse_disabled = 1; 31447c478bd9Sstevel@tonic-gate else if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, 314585025c03Sgd "link-pulse-disabled", (caddr_t)&i, &prop_len) 314685025c03Sgd == DDI_PROP_SUCCESS) { 31477c478bd9Sstevel@tonic-gate hmep->hme_link_pulse_disabled = 1; 31487c478bd9Sstevel@tonic-gate } 31497c478bd9Sstevel@tonic-gate return (B_TRUE); 31507c478bd9Sstevel@tonic-gate } 31517c478bd9Sstevel@tonic-gate 31527c478bd9Sstevel@tonic-gate /* 31537c478bd9Sstevel@tonic-gate * Return 0 upon success, 1 on failure. 31547c478bd9Sstevel@tonic-gate */ 31557c478bd9Sstevel@tonic-gate static uint_t 31567c478bd9Sstevel@tonic-gate hmestop(struct hme *hmep) 31577c478bd9Sstevel@tonic-gate { 31587c478bd9Sstevel@tonic-gate /* 31597c478bd9Sstevel@tonic-gate * Disable the Tx dma engine. 31607c478bd9Sstevel@tonic-gate */ 31617c478bd9Sstevel@tonic-gate PUT_ETXREG(config, (GET_ETXREG(config) & ~HMET_CONFIG_TXDMA_EN)); 31627c478bd9Sstevel@tonic-gate HMEDELAY(((GET_ETXREG(state_mach) & 0x1f) == 0x1), HMEMAXRSTDELAY); 31637c478bd9Sstevel@tonic-gate 31647c478bd9Sstevel@tonic-gate /* 31657c478bd9Sstevel@tonic-gate * Disable the Rx dma engine. 31667c478bd9Sstevel@tonic-gate */ 31677c478bd9Sstevel@tonic-gate PUT_ERXREG(config, (GET_ERXREG(config) & ~HMER_CONFIG_RXDMA_EN)); 31687c478bd9Sstevel@tonic-gate HMEDELAY(((GET_ERXREG(state_mach) & 0x3f) == 0), HMEMAXRSTDELAY); 31697c478bd9Sstevel@tonic-gate 31707c478bd9Sstevel@tonic-gate /* 31717c478bd9Sstevel@tonic-gate * By this time all things should be quiet, so hit the 31727c478bd9Sstevel@tonic-gate * chip with a reset. 31737c478bd9Sstevel@tonic-gate */ 31747c478bd9Sstevel@tonic-gate PUT_GLOBREG(reset, HMEG_RESET_GLOBAL); 31757c478bd9Sstevel@tonic-gate 31767c478bd9Sstevel@tonic-gate HMEDELAY((GET_GLOBREG(reset) == 0), HMEMAXRSTDELAY); 31777c478bd9Sstevel@tonic-gate if (GET_GLOBREG(reset)) { 31787c478bd9Sstevel@tonic-gate return (1); 31797c478bd9Sstevel@tonic-gate } 31807c478bd9Sstevel@tonic-gate 31817c478bd9Sstevel@tonic-gate CHECK_GLOBREG(); 31827c478bd9Sstevel@tonic-gate return (0); 31837c478bd9Sstevel@tonic-gate } 31847c478bd9Sstevel@tonic-gate 31857c478bd9Sstevel@tonic-gate static int 31867c478bd9Sstevel@tonic-gate hmestat_kstat_update(kstat_t *ksp, int rw) 31877c478bd9Sstevel@tonic-gate { 31887c478bd9Sstevel@tonic-gate struct hme *hmep; 31897c478bd9Sstevel@tonic-gate struct hmekstat *hkp; 31907c478bd9Sstevel@tonic-gate 31917c478bd9Sstevel@tonic-gate hmep = (struct hme *)ksp->ks_private; 31927c478bd9Sstevel@tonic-gate hkp = (struct hmekstat *)ksp->ks_data; 31937c478bd9Sstevel@tonic-gate 319485025c03Sgd if (rw != KSTAT_READ) 319585025c03Sgd return (EACCES); 319685025c03Sgd 31977c478bd9Sstevel@tonic-gate /* 31987c478bd9Sstevel@tonic-gate * Update all the stats by reading all the counter registers. 31997c478bd9Sstevel@tonic-gate * Counter register stats are not updated till they overflow 32007c478bd9Sstevel@tonic-gate * and interrupt. 32017c478bd9Sstevel@tonic-gate */ 32027c478bd9Sstevel@tonic-gate 32037c478bd9Sstevel@tonic-gate mutex_enter(&hmep->hme_xmitlock); 32044dd87b61Sgd if (hmep->hme_flags & HMERUNNING) { 32057c478bd9Sstevel@tonic-gate hmereclaim(hmep); 32064dd87b61Sgd hmesavecntrs(hmep); 32074dd87b61Sgd } 32087c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_xmitlock); 32097c478bd9Sstevel@tonic-gate 321085025c03Sgd hkp->hk_cvc.value.ul = hmep->hme_cvc; 321185025c03Sgd hkp->hk_lenerr.value.ul = hmep->hme_lenerr; 321285025c03Sgd hkp->hk_buff.value.ul = hmep->hme_buff; 321385025c03Sgd hkp->hk_missed.value.ul = hmep->hme_missed; 321485025c03Sgd hkp->hk_allocbfail.value.ul = hmep->hme_allocbfail; 321585025c03Sgd hkp->hk_babl.value.ul = hmep->hme_babl; 321685025c03Sgd hkp->hk_tmder.value.ul = hmep->hme_tmder; 321785025c03Sgd hkp->hk_txlaterr.value.ul = hmep->hme_txlaterr; 321885025c03Sgd hkp->hk_rxlaterr.value.ul = hmep->hme_rxlaterr; 321985025c03Sgd hkp->hk_slvparerr.value.ul = hmep->hme_slvparerr; 322085025c03Sgd hkp->hk_txparerr.value.ul = hmep->hme_txparerr; 322185025c03Sgd hkp->hk_rxparerr.value.ul = hmep->hme_rxparerr; 322285025c03Sgd hkp->hk_slverrack.value.ul = hmep->hme_slverrack; 322385025c03Sgd hkp->hk_txerrack.value.ul = hmep->hme_txerrack; 322485025c03Sgd hkp->hk_rxerrack.value.ul = hmep->hme_rxerrack; 322585025c03Sgd hkp->hk_txtagerr.value.ul = hmep->hme_txtagerr; 322685025c03Sgd hkp->hk_rxtagerr.value.ul = hmep->hme_rxtagerr; 322785025c03Sgd hkp->hk_eoperr.value.ul = hmep->hme_eoperr; 322885025c03Sgd hkp->hk_notmds.value.ul = hmep->hme_notmds; 322985025c03Sgd hkp->hk_notbufs.value.ul = hmep->hme_notbufs; 323085025c03Sgd hkp->hk_norbufs.value.ul = hmep->hme_norbufs; 32317c478bd9Sstevel@tonic-gate 323285025c03Sgd /* 323385025c03Sgd * Debug kstats 323485025c03Sgd */ 323585025c03Sgd hkp->hk_inits.value.ul = hmep->inits; 323685025c03Sgd hkp->hk_phyfail.value.ul = hmep->phyfail; 32377c478bd9Sstevel@tonic-gate 323885025c03Sgd /* 323985025c03Sgd * xcvr kstats 324085025c03Sgd */ 324185025c03Sgd hkp->hk_asic_rev.value.ul = hmep->asic_rev; 32427c478bd9Sstevel@tonic-gate 32437c478bd9Sstevel@tonic-gate return (0); 32447c478bd9Sstevel@tonic-gate } 32457c478bd9Sstevel@tonic-gate 32467c478bd9Sstevel@tonic-gate static void 32477c478bd9Sstevel@tonic-gate hmestatinit(struct hme *hmep) 32487c478bd9Sstevel@tonic-gate { 32497c478bd9Sstevel@tonic-gate struct kstat *ksp; 32507c478bd9Sstevel@tonic-gate struct hmekstat *hkp; 3251f2cd0f02Sgd const char *driver; 32527c478bd9Sstevel@tonic-gate int instance; 32537c478bd9Sstevel@tonic-gate char buf[16]; 32547c478bd9Sstevel@tonic-gate 32557c478bd9Sstevel@tonic-gate instance = hmep->instance; 3256f2cd0f02Sgd driver = ddi_driver_name(hmep->dip); 32577c478bd9Sstevel@tonic-gate 3258f2cd0f02Sgd if ((ksp = kstat_create(driver, instance, 325985025c03Sgd "driver_info", "net", KSTAT_TYPE_NAMED, 32607c478bd9Sstevel@tonic-gate sizeof (struct hmekstat) / sizeof (kstat_named_t), 0)) == NULL) { 32617c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, INIT_MSG, 3262*0219346bSGarrett D'Amore "kstat_create failed"); 32637c478bd9Sstevel@tonic-gate return; 32647c478bd9Sstevel@tonic-gate } 32657c478bd9Sstevel@tonic-gate 3266f2cd0f02Sgd (void) snprintf(buf, sizeof (buf), "%sc%d", driver, instance); 3267f2cd0f02Sgd hmep->hme_intrstats = kstat_create(driver, instance, buf, "controller", 326885025c03Sgd KSTAT_TYPE_INTR, 1, KSTAT_FLAG_PERSISTENT); 32697c478bd9Sstevel@tonic-gate if (hmep->hme_intrstats) 32707c478bd9Sstevel@tonic-gate kstat_install(hmep->hme_intrstats); 32717c478bd9Sstevel@tonic-gate 32727c478bd9Sstevel@tonic-gate hmep->hme_ksp = ksp; 32737c478bd9Sstevel@tonic-gate hkp = (struct hmekstat *)ksp->ks_data; 32747c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_cvc, "code_violations", 327585025c03Sgd KSTAT_DATA_ULONG); 32767c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_lenerr, "len_errors", 327785025c03Sgd KSTAT_DATA_ULONG); 32787c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_buff, "buff", 327985025c03Sgd KSTAT_DATA_ULONG); 32807c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_missed, "missed", 328185025c03Sgd KSTAT_DATA_ULONG); 32827c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_nocanput, "nocanput", 328385025c03Sgd KSTAT_DATA_ULONG); 32847c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_allocbfail, "allocbfail", 328585025c03Sgd KSTAT_DATA_ULONG); 32867c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_babl, "babble", 328785025c03Sgd KSTAT_DATA_ULONG); 32887c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_tmder, "tmd_error", 328985025c03Sgd KSTAT_DATA_ULONG); 32907c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_txlaterr, "tx_late_error", 329185025c03Sgd KSTAT_DATA_ULONG); 32927c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_rxlaterr, "rx_late_error", 329385025c03Sgd KSTAT_DATA_ULONG); 32947c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_slvparerr, "slv_parity_error", 329585025c03Sgd KSTAT_DATA_ULONG); 32967c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_txparerr, "tx_parity_error", 329785025c03Sgd KSTAT_DATA_ULONG); 32987c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_rxparerr, "rx_parity_error", 329985025c03Sgd KSTAT_DATA_ULONG); 33007c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_slverrack, "slv_error_ack", 330185025c03Sgd KSTAT_DATA_ULONG); 33027c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_txerrack, "tx_error_ack", 330385025c03Sgd KSTAT_DATA_ULONG); 33047c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_rxerrack, "rx_error_ack", 330585025c03Sgd KSTAT_DATA_ULONG); 33067c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_txtagerr, "tx_tag_error", 330785025c03Sgd KSTAT_DATA_ULONG); 33087c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_rxtagerr, "rx_tag_error", 330985025c03Sgd KSTAT_DATA_ULONG); 33107c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_eoperr, "eop_error", 331185025c03Sgd KSTAT_DATA_ULONG); 33127c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_notmds, "no_tmds", 331385025c03Sgd KSTAT_DATA_ULONG); 33147c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_notbufs, "no_tbufs", 331585025c03Sgd KSTAT_DATA_ULONG); 33167c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_norbufs, "no_rbufs", 331785025c03Sgd KSTAT_DATA_ULONG); 33187c478bd9Sstevel@tonic-gate 33197c478bd9Sstevel@tonic-gate /* 33207c478bd9Sstevel@tonic-gate * Debugging kstats 33217c478bd9Sstevel@tonic-gate */ 33227c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_inits, "inits", 332385025c03Sgd KSTAT_DATA_ULONG); 33247c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_phyfail, "phy_failures", 332585025c03Sgd KSTAT_DATA_ULONG); 33267c478bd9Sstevel@tonic-gate 33277c478bd9Sstevel@tonic-gate /* 33287c478bd9Sstevel@tonic-gate * I/O bus kstats 33297c478bd9Sstevel@tonic-gate * kstat_named_init(&hkp->hk_pci_speed, "pci_bus_speed", 33307c478bd9Sstevel@tonic-gate * KSTAT_DATA_ULONG); 33317c478bd9Sstevel@tonic-gate * kstat_named_init(&hkp->hk_pci_size, "pci_bus_width", 33327c478bd9Sstevel@tonic-gate * KSTAT_DATA_ULONG); 33337c478bd9Sstevel@tonic-gate */ 33347c478bd9Sstevel@tonic-gate 33357c478bd9Sstevel@tonic-gate /* 33367c478bd9Sstevel@tonic-gate * xcvr kstats 33377c478bd9Sstevel@tonic-gate */ 33387c478bd9Sstevel@tonic-gate kstat_named_init(&hkp->hk_asic_rev, "asic_rev", 333985025c03Sgd KSTAT_DATA_ULONG); 33407c478bd9Sstevel@tonic-gate 33417c478bd9Sstevel@tonic-gate ksp->ks_update = hmestat_kstat_update; 33427c478bd9Sstevel@tonic-gate ksp->ks_private = (void *) hmep; 33437c478bd9Sstevel@tonic-gate kstat_install(ksp); 33447c478bd9Sstevel@tonic-gate } 33457c478bd9Sstevel@tonic-gate 33467c478bd9Sstevel@tonic-gate static void 334785025c03Sgd hme_m_ioctl(void *arg, queue_t *wq, mblk_t *mp) 33487c478bd9Sstevel@tonic-gate { 334985025c03Sgd struct hme *hmep = arg; 335085025c03Sgd struct iocblk *iocp = (void *)mp->b_rptr; 33517c478bd9Sstevel@tonic-gate uint32_t old_ipg1, old_ipg2, old_use_int_xcvr, old_autoneg; 33527c478bd9Sstevel@tonic-gate uint32_t old_100T4; 33537c478bd9Sstevel@tonic-gate uint32_t old_100fdx, old_100hdx, old_10fdx, old_10hdx; 33547c478bd9Sstevel@tonic-gate uint32_t old_ipg0, old_lance_mode; 33557c478bd9Sstevel@tonic-gate 33567c478bd9Sstevel@tonic-gate switch (iocp->ioc_cmd) { 33577c478bd9Sstevel@tonic-gate 33587c478bd9Sstevel@tonic-gate case HME_ND_GET: 335985025c03Sgd 33607c478bd9Sstevel@tonic-gate old_autoneg = hme_param_autoneg; 33617c478bd9Sstevel@tonic-gate old_100T4 = hme_param_anar_100T4; 33627c478bd9Sstevel@tonic-gate old_100fdx = hme_param_anar_100fdx; 33637c478bd9Sstevel@tonic-gate old_100hdx = hme_param_anar_100hdx; 33647c478bd9Sstevel@tonic-gate old_10fdx = hme_param_anar_10fdx; 33657c478bd9Sstevel@tonic-gate old_10hdx = hme_param_anar_10hdx; 33667c478bd9Sstevel@tonic-gate 33677c478bd9Sstevel@tonic-gate hme_param_autoneg = old_autoneg & ~HME_NOTUSR; 33687c478bd9Sstevel@tonic-gate hme_param_anar_100T4 = old_100T4 & ~HME_NOTUSR; 33697c478bd9Sstevel@tonic-gate hme_param_anar_100fdx = old_100fdx & ~HME_NOTUSR; 33707c478bd9Sstevel@tonic-gate hme_param_anar_100hdx = old_100hdx & ~HME_NOTUSR; 33717c478bd9Sstevel@tonic-gate hme_param_anar_10fdx = old_10fdx & ~HME_NOTUSR; 33727c478bd9Sstevel@tonic-gate hme_param_anar_10hdx = old_10hdx & ~HME_NOTUSR; 33737c478bd9Sstevel@tonic-gate 33747c478bd9Sstevel@tonic-gate if (!hme_nd_getset(wq, hmep->hme_g_nd, mp)) { 33757c478bd9Sstevel@tonic-gate hme_param_autoneg = old_autoneg; 33767c478bd9Sstevel@tonic-gate hme_param_anar_100T4 = old_100T4; 33777c478bd9Sstevel@tonic-gate hme_param_anar_100fdx = old_100fdx; 33787c478bd9Sstevel@tonic-gate hme_param_anar_100hdx = old_100hdx; 33797c478bd9Sstevel@tonic-gate hme_param_anar_10fdx = old_10fdx; 33807c478bd9Sstevel@tonic-gate hme_param_anar_10hdx = old_10hdx; 33817c478bd9Sstevel@tonic-gate miocnak(wq, mp, 0, EINVAL); 33827c478bd9Sstevel@tonic-gate return; 33837c478bd9Sstevel@tonic-gate } 33847c478bd9Sstevel@tonic-gate hme_param_autoneg = old_autoneg; 33857c478bd9Sstevel@tonic-gate hme_param_anar_100T4 = old_100T4; 33867c478bd9Sstevel@tonic-gate hme_param_anar_100fdx = old_100fdx; 33877c478bd9Sstevel@tonic-gate hme_param_anar_100hdx = old_100hdx; 33887c478bd9Sstevel@tonic-gate hme_param_anar_10fdx = old_10fdx; 33897c478bd9Sstevel@tonic-gate hme_param_anar_10hdx = old_10hdx; 33907c478bd9Sstevel@tonic-gate 33917c478bd9Sstevel@tonic-gate qreply(wq, mp); 339285025c03Sgd break; 33937c478bd9Sstevel@tonic-gate 339485025c03Sgd case HME_ND_SET: 339585025c03Sgd old_ipg0 = hme_param_ipg0; 339685025c03Sgd old_lance_mode = hme_param_lance_mode; 339785025c03Sgd old_ipg1 = hme_param_ipg1; 339885025c03Sgd old_ipg2 = hme_param_ipg2; 339985025c03Sgd old_use_int_xcvr = hme_param_use_intphy; 340085025c03Sgd old_autoneg = hme_param_autoneg; 340185025c03Sgd hme_param_autoneg = 0xff; 34027c478bd9Sstevel@tonic-gate 340385025c03Sgd if (!hme_nd_getset(wq, hmep->hme_g_nd, mp)) { 340485025c03Sgd hme_param_autoneg = old_autoneg; 340585025c03Sgd miocnak(wq, mp, 0, EINVAL); 340685025c03Sgd return; 340785025c03Sgd } 34087c478bd9Sstevel@tonic-gate 340985025c03Sgd qreply(wq, mp); 34107c478bd9Sstevel@tonic-gate 341185025c03Sgd if (hme_param_autoneg != 0xff) { 341285025c03Sgd hmep->hme_linkcheck = 0; 341385025c03Sgd (void) hmeinit(hmep); 341485025c03Sgd } else { 341585025c03Sgd hme_param_autoneg = old_autoneg; 341685025c03Sgd if (old_use_int_xcvr != hme_param_use_intphy) { 341785025c03Sgd hmep->hme_linkcheck = 0; 341885025c03Sgd (void) hmeinit(hmep); 341985025c03Sgd } else if ((old_ipg1 != hme_param_ipg1) || 342085025c03Sgd (old_ipg2 != hme_param_ipg2) || 342185025c03Sgd (old_ipg0 != hme_param_ipg0) || 342285025c03Sgd (old_lance_mode != hme_param_lance_mode)) { 342385025c03Sgd (void) hmeinit(hmep); 34247c478bd9Sstevel@tonic-gate } 34257c478bd9Sstevel@tonic-gate } 34267c478bd9Sstevel@tonic-gate break; 34277c478bd9Sstevel@tonic-gate 34287c478bd9Sstevel@tonic-gate default: 342985025c03Sgd miocnak(wq, mp, 0, EINVAL); 343085025c03Sgd break; 34317c478bd9Sstevel@tonic-gate } 34327c478bd9Sstevel@tonic-gate } 34337c478bd9Sstevel@tonic-gate 343485025c03Sgd /*ARGSUSED*/ 343585025c03Sgd static boolean_t 343685025c03Sgd hme_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) 34377c478bd9Sstevel@tonic-gate { 343885025c03Sgd switch (cap) { 343985025c03Sgd case MAC_CAPAB_HCKSUM: 344085025c03Sgd *(uint32_t *)cap_data = HCKSUM_INET_PARTIAL; 344185025c03Sgd return (B_TRUE); 344285025c03Sgd default: 344385025c03Sgd return (B_FALSE); 34447c478bd9Sstevel@tonic-gate } 344585025c03Sgd } 34467c478bd9Sstevel@tonic-gate 344785025c03Sgd static int 344885025c03Sgd hme_m_promisc(void *arg, boolean_t on) 344985025c03Sgd { 345085025c03Sgd struct hme *hmep = arg; 34517c478bd9Sstevel@tonic-gate 345285025c03Sgd hmep->hme_promisc = on; 345385025c03Sgd (void) hmeinit(hmep); 345485025c03Sgd return (0); 345585025c03Sgd } 34567c478bd9Sstevel@tonic-gate 345785025c03Sgd static int 345885025c03Sgd hme_m_unicst(void *arg, const uint8_t *macaddr) 345985025c03Sgd { 346085025c03Sgd struct hme *hmep = arg; 34617c478bd9Sstevel@tonic-gate 34627c478bd9Sstevel@tonic-gate /* 34637c478bd9Sstevel@tonic-gate * Set new interface local address and re-init device. 34647c478bd9Sstevel@tonic-gate * This is destructive to any other streams attached 34657c478bd9Sstevel@tonic-gate * to this device. 34667c478bd9Sstevel@tonic-gate */ 346785025c03Sgd mutex_enter(&hmep->hme_intrlock); 346885025c03Sgd bcopy(macaddr, &hmep->hme_ouraddr, ETHERADDRL); 346985025c03Sgd mutex_exit(&hmep->hme_intrlock); 347085025c03Sgd (void) hmeinit(hmep); 347185025c03Sgd return (0); 34727c478bd9Sstevel@tonic-gate } 34737c478bd9Sstevel@tonic-gate 347485025c03Sgd static int 347585025c03Sgd hme_m_multicst(void *arg, boolean_t add, const uint8_t *macaddr) 34767c478bd9Sstevel@tonic-gate { 347785025c03Sgd struct hme *hmep = arg; 347885025c03Sgd uint32_t ladrf_bit; 347985025c03Sgd boolean_t doinit = B_FALSE; 34807c478bd9Sstevel@tonic-gate 34817c478bd9Sstevel@tonic-gate /* 348285025c03Sgd * If this address's bit was not already set in the local address 348385025c03Sgd * filter, add it and re-initialize the Hardware. 34847c478bd9Sstevel@tonic-gate */ 348585025c03Sgd ladrf_bit = hmeladrf_bit(macaddr); 34867c478bd9Sstevel@tonic-gate 348785025c03Sgd mutex_enter(&hmep->hme_intrlock); 348885025c03Sgd if (add) { 348985025c03Sgd hmep->hme_ladrf_refcnt[ladrf_bit]++; 349085025c03Sgd if (hmep->hme_ladrf_refcnt[ladrf_bit] == 1) { 349185025c03Sgd hmep->hme_ladrf[ladrf_bit >> 4] |= 349285025c03Sgd 1 << (ladrf_bit & 0xf); 349385025c03Sgd hmep->hme_multi++; 349485025c03Sgd doinit = B_TRUE; 349585025c03Sgd } 34967c478bd9Sstevel@tonic-gate } else { 349785025c03Sgd hmep->hme_ladrf_refcnt[ladrf_bit]--; 349885025c03Sgd if (hmep->hme_ladrf_refcnt[ladrf_bit] == 0) { 349985025c03Sgd hmep->hme_ladrf[ladrf_bit >> 4] &= 350085025c03Sgd ~(1 << (ladrf_bit & 0xf)); 350185025c03Sgd doinit = B_TRUE; 35027c478bd9Sstevel@tonic-gate } 35037c478bd9Sstevel@tonic-gate } 350485025c03Sgd mutex_exit(&hmep->hme_intrlock); 35057c478bd9Sstevel@tonic-gate 3506*0219346bSGarrett D'Amore if (doinit) { 350785025c03Sgd (void) hmeinit(hmep); 3508*0219346bSGarrett D'Amore } 35097c478bd9Sstevel@tonic-gate 351085025c03Sgd return (0); 35117c478bd9Sstevel@tonic-gate } 35127c478bd9Sstevel@tonic-gate 351385025c03Sgd static int 351485025c03Sgd hme_m_start(void *arg) 35157c478bd9Sstevel@tonic-gate { 351685025c03Sgd struct hme *hmep = arg; 35177c478bd9Sstevel@tonic-gate 3518228fdff0Sgd if (hmeinit(hmep) != 0) { 3519228fdff0Sgd /* initialization failed -- really want DL_INITFAILED */ 3520228fdff0Sgd return (EIO); 3521228fdff0Sgd } else { 3522228fdff0Sgd hmep->hme_started = B_TRUE; 3523228fdff0Sgd return (0); 3524228fdff0Sgd } 352585025c03Sgd } 35267c478bd9Sstevel@tonic-gate 352785025c03Sgd static void 352885025c03Sgd hme_m_stop(void *arg) 352985025c03Sgd { 353085025c03Sgd struct hme *hmep = arg; 35317c478bd9Sstevel@tonic-gate 3532228fdff0Sgd hmep->hme_started = B_FALSE; 353385025c03Sgd hmeuninit(hmep); 353485025c03Sgd } 35357c478bd9Sstevel@tonic-gate 353685025c03Sgd static int 353785025c03Sgd hme_m_stat(void *arg, uint_t stat, uint64_t *val) 353885025c03Sgd { 353985025c03Sgd struct hme *hmep = arg; 35407c478bd9Sstevel@tonic-gate 354185025c03Sgd mutex_enter(&hmep->hme_xmitlock); 35424dd87b61Sgd if (hmep->hme_flags & HMERUNNING) { 354385025c03Sgd hmereclaim(hmep); 35444dd87b61Sgd hmesavecntrs(hmep); 35454dd87b61Sgd } 354685025c03Sgd mutex_exit(&hmep->hme_xmitlock); 35477c478bd9Sstevel@tonic-gate 35487c478bd9Sstevel@tonic-gate 354985025c03Sgd switch (stat) { 355085025c03Sgd case MAC_STAT_IFSPEED: 355185025c03Sgd *val = hmep->hme_ifspeed * 1000000; 355285025c03Sgd break; 355385025c03Sgd case MAC_STAT_IPACKETS: 355485025c03Sgd *val = hmep->hme_ipackets; 355585025c03Sgd break; 355685025c03Sgd case MAC_STAT_RBYTES: 355785025c03Sgd *val = hmep->hme_rbytes; 355885025c03Sgd break; 355985025c03Sgd case MAC_STAT_IERRORS: 356085025c03Sgd *val = hmep->hme_ierrors; 356185025c03Sgd break; 356285025c03Sgd case MAC_STAT_OPACKETS: 356385025c03Sgd *val = hmep->hme_opackets; 356485025c03Sgd break; 356585025c03Sgd case MAC_STAT_OBYTES: 356685025c03Sgd *val = hmep->hme_obytes; 356785025c03Sgd break; 356885025c03Sgd case MAC_STAT_OERRORS: 356985025c03Sgd *val = hmep->hme_oerrors; 357085025c03Sgd break; 357185025c03Sgd case MAC_STAT_MULTIRCV: 357285025c03Sgd *val = hmep->hme_multircv; 357385025c03Sgd break; 357485025c03Sgd case MAC_STAT_MULTIXMT: 357585025c03Sgd *val = hmep->hme_multixmt; 357685025c03Sgd break; 357785025c03Sgd case MAC_STAT_BRDCSTRCV: 357885025c03Sgd *val = hmep->hme_brdcstrcv; 357985025c03Sgd break; 358085025c03Sgd case MAC_STAT_BRDCSTXMT: 358185025c03Sgd *val = hmep->hme_brdcstxmt; 358285025c03Sgd break; 358385025c03Sgd case MAC_STAT_UNDERFLOWS: 358485025c03Sgd *val = hmep->hme_uflo; 358585025c03Sgd break; 358685025c03Sgd case MAC_STAT_OVERFLOWS: 358785025c03Sgd *val = hmep->hme_oflo; 358885025c03Sgd break; 358985025c03Sgd case MAC_STAT_COLLISIONS: 359085025c03Sgd *val = hmep->hme_coll; 359185025c03Sgd break; 359285025c03Sgd case MAC_STAT_NORCVBUF: 359385025c03Sgd *val = hmep->hme_norcvbuf; 359485025c03Sgd break; 359585025c03Sgd case MAC_STAT_NOXMTBUF: 359685025c03Sgd *val = hmep->hme_noxmtbuf; 359785025c03Sgd break; 359885025c03Sgd case ETHER_STAT_LINK_DUPLEX: 359985025c03Sgd *val = hmep->hme_duplex; 360085025c03Sgd break; 360185025c03Sgd case ETHER_STAT_ALIGN_ERRORS: 360285025c03Sgd *val = hmep->hme_align_errors; 360385025c03Sgd break; 360485025c03Sgd case ETHER_STAT_FCS_ERRORS: 360585025c03Sgd *val = hmep->hme_fcs_errors; 360685025c03Sgd break; 360785025c03Sgd case ETHER_STAT_EX_COLLISIONS: 360885025c03Sgd *val = hmep->hme_excol; 360985025c03Sgd break; 361085025c03Sgd case ETHER_STAT_DEFER_XMTS: 361185025c03Sgd *val = hmep->hme_defer_xmts; 361285025c03Sgd break; 361385025c03Sgd case ETHER_STAT_SQE_ERRORS: 361485025c03Sgd *val = hmep->hme_sqe_errors; 361585025c03Sgd break; 361685025c03Sgd case ETHER_STAT_FIRST_COLLISIONS: 361785025c03Sgd *val = hmep->hme_fstcol; 361885025c03Sgd break; 361985025c03Sgd case ETHER_STAT_TX_LATE_COLLISIONS: 362085025c03Sgd *val = hmep->hme_tlcol; 362185025c03Sgd break; 362285025c03Sgd case ETHER_STAT_TOOLONG_ERRORS: 362385025c03Sgd *val = hmep->hme_toolong_errors; 362485025c03Sgd break; 362585025c03Sgd case ETHER_STAT_TOOSHORT_ERRORS: 362685025c03Sgd *val = hmep->hme_runt; 362785025c03Sgd break; 36284dd87b61Sgd case ETHER_STAT_CARRIER_ERRORS: 36294dd87b61Sgd *val = hmep->hme_carrier_errors; 36304dd87b61Sgd break; 363185025c03Sgd case ETHER_STAT_XCVR_ADDR: 363285025c03Sgd *val = hmep->hme_phyad; 363385025c03Sgd break; 363485025c03Sgd case ETHER_STAT_XCVR_ID: 363585025c03Sgd *val = (hmep->hme_idr1 << 16U) | (hmep->hme_idr2); 363685025c03Sgd break; 363785025c03Sgd case ETHER_STAT_XCVR_INUSE: 363885025c03Sgd switch (hmep->hme_transceiver) { 363985025c03Sgd case HME_INTERNAL_TRANSCEIVER: 364085025c03Sgd *val = XCVR_100X; 364185025c03Sgd break; 364285025c03Sgd case HME_NO_TRANSCEIVER: 364385025c03Sgd *val = XCVR_NONE; 364485025c03Sgd break; 364585025c03Sgd default: 364685025c03Sgd *val = XCVR_UNDEFINED; 36477c478bd9Sstevel@tonic-gate break; 36487c478bd9Sstevel@tonic-gate } 364985025c03Sgd break; 365085025c03Sgd case ETHER_STAT_CAP_100T4: 365185025c03Sgd *val = hme_param_bmsr_100T4; 365285025c03Sgd break; 365385025c03Sgd case ETHER_STAT_ADV_CAP_100T4: 365485025c03Sgd *val = hme_param_anar_100T4 & ~HME_NOTUSR; 365585025c03Sgd break; 365685025c03Sgd case ETHER_STAT_LP_CAP_100T4: 365785025c03Sgd *val = hme_param_anlpar_100T4; 365885025c03Sgd break; 365985025c03Sgd case ETHER_STAT_CAP_100FDX: 366085025c03Sgd *val = hme_param_bmsr_100fdx; 366185025c03Sgd break; 366285025c03Sgd case ETHER_STAT_ADV_CAP_100FDX: 366385025c03Sgd *val = hme_param_anar_100fdx & ~HME_NOTUSR; 366485025c03Sgd break; 366585025c03Sgd case ETHER_STAT_LP_CAP_100FDX: 366685025c03Sgd *val = hme_param_anlpar_100fdx; 366785025c03Sgd break; 366885025c03Sgd case ETHER_STAT_CAP_100HDX: 366985025c03Sgd *val = hme_param_bmsr_100hdx; 367085025c03Sgd break; 367185025c03Sgd case ETHER_STAT_ADV_CAP_100HDX: 367285025c03Sgd *val = hme_param_anar_100hdx & ~HME_NOTUSR; 367385025c03Sgd break; 367485025c03Sgd case ETHER_STAT_LP_CAP_100HDX: 367585025c03Sgd *val = hme_param_anlpar_100hdx; 367685025c03Sgd break; 367785025c03Sgd case ETHER_STAT_CAP_10FDX: 367885025c03Sgd *val = hme_param_bmsr_10fdx; 367985025c03Sgd break; 368085025c03Sgd case ETHER_STAT_ADV_CAP_10FDX: 368185025c03Sgd *val = hme_param_anar_10fdx & ~HME_NOTUSR; 368285025c03Sgd break; 368385025c03Sgd case ETHER_STAT_LP_CAP_10FDX: 368485025c03Sgd *val = hme_param_anlpar_10fdx; 368585025c03Sgd break; 368685025c03Sgd case ETHER_STAT_CAP_10HDX: 368785025c03Sgd *val = hme_param_bmsr_10hdx; 368885025c03Sgd break; 368985025c03Sgd case ETHER_STAT_ADV_CAP_10HDX: 369085025c03Sgd *val = hme_param_anar_10hdx & ~HME_NOTUSR; 369185025c03Sgd break; 369285025c03Sgd case ETHER_STAT_LP_CAP_10HDX: 369385025c03Sgd *val = hme_param_anlpar_10hdx; 369485025c03Sgd break; 369585025c03Sgd case ETHER_STAT_CAP_AUTONEG: 369685025c03Sgd *val = hme_param_bmsr_ancap; 369785025c03Sgd break; 369885025c03Sgd case ETHER_STAT_ADV_CAP_AUTONEG: 369985025c03Sgd *val = hme_param_autoneg & ~HME_NOTUSR; 370085025c03Sgd break; 370185025c03Sgd case ETHER_STAT_LP_CAP_AUTONEG: 370285025c03Sgd *val = hme_param_aner_lpancap; 370385025c03Sgd break; 370485025c03Sgd default: 370585025c03Sgd return (EINVAL); 37067c478bd9Sstevel@tonic-gate } 370785025c03Sgd return (0); 37087c478bd9Sstevel@tonic-gate } 37097c478bd9Sstevel@tonic-gate 371085025c03Sgd static mblk_t * 371185025c03Sgd hme_m_tx(void *arg, mblk_t *mp) 37127c478bd9Sstevel@tonic-gate { 371385025c03Sgd struct hme *hmep = arg; 371485025c03Sgd mblk_t *next; 37157c478bd9Sstevel@tonic-gate 371685025c03Sgd while (mp != NULL) { 371785025c03Sgd next = mp->b_next; 371885025c03Sgd mp->b_next = NULL; 371985025c03Sgd if (!hmestart(hmep, mp)) { 372085025c03Sgd mp->b_next = next; 372185025c03Sgd break; 37227c478bd9Sstevel@tonic-gate } 372385025c03Sgd mp = next; 37247c478bd9Sstevel@tonic-gate } 372585025c03Sgd return (mp); 37267c478bd9Sstevel@tonic-gate } 37277c478bd9Sstevel@tonic-gate 3728eb7b3d20Sgd /* 3729eb7b3d20Sgd * Software IP checksum, for the edge cases that the 3730eb7b3d20Sgd * hardware can't handle. See hmestart for more info. 3731eb7b3d20Sgd */ 3732eb7b3d20Sgd static uint16_t 3733eb7b3d20Sgd hme_cksum(void *data, int len) 3734eb7b3d20Sgd { 3735eb7b3d20Sgd uint16_t *words = data; 3736eb7b3d20Sgd int i, nwords = len / 2; 3737eb7b3d20Sgd uint32_t sum = 0; 3738eb7b3d20Sgd 3739eb7b3d20Sgd /* just add up the words */ 3740eb7b3d20Sgd for (i = 0; i < nwords; i++) { 3741eb7b3d20Sgd sum += *words++; 3742eb7b3d20Sgd } 3743eb7b3d20Sgd 3744eb7b3d20Sgd /* pick up residual byte ... assume even half-word allocations */ 3745eb7b3d20Sgd if (len % 2) { 3746*0219346bSGarrett D'Amore sum += (*words & htons(0xff00)); 3747eb7b3d20Sgd } 3748eb7b3d20Sgd 3749eb7b3d20Sgd sum = (sum >> 16) + (sum & 0xffff); 3750eb7b3d20Sgd sum = (sum >> 16) + (sum & 0xffff); 3751eb7b3d20Sgd 3752eb7b3d20Sgd return (~(sum & 0xffff)); 3753eb7b3d20Sgd } 3754eb7b3d20Sgd 375585025c03Sgd static boolean_t 3756*0219346bSGarrett D'Amore hmestart(struct hme *hmep, mblk_t *mp) 37577c478bd9Sstevel@tonic-gate { 3758*0219346bSGarrett D'Amore uint32_t len; 3759*0219346bSGarrett D'Amore boolean_t retval = B_TRUE; 3760*0219346bSGarrett D'Amore hmebuf_t *tbuf; 3761*0219346bSGarrett D'Amore uint32_t txptr; 37627c478bd9Sstevel@tonic-gate 376385025c03Sgd uint32_t csflags = 0; 376485025c03Sgd uint32_t flags; 376585025c03Sgd uint32_t start_offset; 376685025c03Sgd uint32_t stuff_offset; 37677c478bd9Sstevel@tonic-gate 376885025c03Sgd hcksum_retrieve(mp, NULL, NULL, &start_offset, &stuff_offset, 376985025c03Sgd NULL, NULL, &flags); 37707c478bd9Sstevel@tonic-gate 377185025c03Sgd if (flags & HCK_PARTIALCKSUM) { 377285025c03Sgd if (get_ether_type(mp->b_rptr) == ETHERTYPE_VLAN) { 377385025c03Sgd start_offset += sizeof (struct ether_header) + 4; 377485025c03Sgd stuff_offset += sizeof (struct ether_header) + 4; 377585025c03Sgd } else { 377685025c03Sgd start_offset += sizeof (struct ether_header); 377785025c03Sgd stuff_offset += sizeof (struct ether_header); 37787c478bd9Sstevel@tonic-gate } 377985025c03Sgd csflags = HMETMD_CSENABL | 378085025c03Sgd (start_offset << HMETMD_CSSTART_SHIFT) | 378185025c03Sgd (stuff_offset << HMETMD_CSSTUFF_SHIFT); 378285025c03Sgd } 37837c478bd9Sstevel@tonic-gate 37847c478bd9Sstevel@tonic-gate mutex_enter(&hmep->hme_xmitlock); 37857c478bd9Sstevel@tonic-gate 37864dd87b61Sgd if (hmep->hme_flags & HMESUSPENDED) { 37874dd87b61Sgd hmep->hme_carrier_errors++; 37884dd87b61Sgd hmep->hme_oerrors++; 37894dd87b61Sgd goto bad; 37904dd87b61Sgd } 37914dd87b61Sgd 3792*0219346bSGarrett D'Amore if (hmep->hme_txindex != hmep->hme_txreclaim) { 3793*0219346bSGarrett D'Amore hmereclaim(hmep); 37947c478bd9Sstevel@tonic-gate } 3795*0219346bSGarrett D'Amore if ((hmep->hme_txindex - HME_TMDMAX) == hmep->hme_txreclaim) 37967c478bd9Sstevel@tonic-gate goto notmds; 3797*0219346bSGarrett D'Amore txptr = hmep->hme_txindex % HME_TMDMAX; 3798*0219346bSGarrett D'Amore tbuf = &hmep->hme_tbuf[txptr]; 37997c478bd9Sstevel@tonic-gate 3800eb7b3d20Sgd /* 3801eb7b3d20Sgd * Note that for checksum offload, the hardware cannot 3802eb7b3d20Sgd * generate correct checksums if the packet is smaller than 3803eb7b3d20Sgd * 64-bytes. In such a case, we bcopy the packet and use 3804eb7b3d20Sgd * a software checksum. 3805eb7b3d20Sgd */ 3806eb7b3d20Sgd 3807*0219346bSGarrett D'Amore len = msgsize(mp); 3808*0219346bSGarrett D'Amore if (len < 64) { 3809*0219346bSGarrett D'Amore /* zero fill the padding */ 3810*0219346bSGarrett D'Amore bzero(tbuf->kaddr, 64); 38117c478bd9Sstevel@tonic-gate } 3812*0219346bSGarrett D'Amore mcopymsg(mp, tbuf->kaddr); 38137c478bd9Sstevel@tonic-gate 3814*0219346bSGarrett D'Amore if ((csflags != 0) && (len < 64)) { 3815*0219346bSGarrett D'Amore uint16_t sum; 3816*0219346bSGarrett D'Amore sum = hme_cksum(tbuf->kaddr + start_offset, 3817*0219346bSGarrett D'Amore len - start_offset); 3818*0219346bSGarrett D'Amore bcopy(&sum, tbuf->kaddr + stuff_offset, sizeof (sum)); 3819*0219346bSGarrett D'Amore csflags = 0; 38207c478bd9Sstevel@tonic-gate } 38217c478bd9Sstevel@tonic-gate 3822*0219346bSGarrett D'Amore if (ddi_dma_sync(tbuf->dmah, 0, len, DDI_DMA_SYNC_FORDEV) == 3823*0219346bSGarrett D'Amore DDI_FAILURE) { 38247c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_HIGH, DDI_MSG, 382585025c03Sgd "ddi_dma_sync failed"); 38267c478bd9Sstevel@tonic-gate } 38277c478bd9Sstevel@tonic-gate 3828*0219346bSGarrett D'Amore /* 3829*0219346bSGarrett D'Amore * update MIB II statistics 3830*0219346bSGarrett D'Amore */ 3831*0219346bSGarrett D'Amore BUMP_OutNUcast(hmep, tbuf->kaddr); 3832*0219346bSGarrett D'Amore 3833*0219346bSGarrett D'Amore PUT_TMD(txptr, tbuf->paddr, len, 3834*0219346bSGarrett D'Amore HMETMD_OWN | HMETMD_SOP | HMETMD_EOP | csflags); 38357c478bd9Sstevel@tonic-gate 3836*0219346bSGarrett D'Amore HMESYNCTMD(txptr, DDI_DMA_SYNC_FORDEV); 3837*0219346bSGarrett D'Amore hmep->hme_txindex++; 38387c478bd9Sstevel@tonic-gate 38397c478bd9Sstevel@tonic-gate PUT_ETXREG(txpend, HMET_TXPEND_TDMD); 38407c478bd9Sstevel@tonic-gate CHECK_ETXREG(); 38417c478bd9Sstevel@tonic-gate 38427c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_xmitlock); 38437c478bd9Sstevel@tonic-gate 38447c478bd9Sstevel@tonic-gate hmep->hme_starts++; 384585025c03Sgd return (B_TRUE); 38467c478bd9Sstevel@tonic-gate 38477c478bd9Sstevel@tonic-gate bad: 38487c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_xmitlock); 38497c478bd9Sstevel@tonic-gate freemsg(mp); 385085025c03Sgd return (B_TRUE); 38517c478bd9Sstevel@tonic-gate 38527c478bd9Sstevel@tonic-gate notmds: 38537c478bd9Sstevel@tonic-gate hmep->hme_notmds++; 385485025c03Sgd hmep->hme_wantw = B_TRUE; 38557c478bd9Sstevel@tonic-gate hmereclaim(hmep); 385685025c03Sgd retval = B_FALSE; 38577c478bd9Sstevel@tonic-gate done: 38587c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_xmitlock); 38597c478bd9Sstevel@tonic-gate 386085025c03Sgd return (retval); 38617c478bd9Sstevel@tonic-gate } 38627c478bd9Sstevel@tonic-gate 38637c478bd9Sstevel@tonic-gate /* 38647c478bd9Sstevel@tonic-gate * Initialize channel. 38657c478bd9Sstevel@tonic-gate * Return 0 on success, nonzero on error. 38667c478bd9Sstevel@tonic-gate * 38677c478bd9Sstevel@tonic-gate * The recommended sequence for initialization is: 38687c478bd9Sstevel@tonic-gate * 1. Issue a Global Reset command to the Ethernet Channel. 38697c478bd9Sstevel@tonic-gate * 2. Poll the Global_Reset bits until the execution of the reset has been 38707c478bd9Sstevel@tonic-gate * completed. 38717c478bd9Sstevel@tonic-gate * 2(a). Use the MIF Frame/Output register to reset the transceiver. 38727c478bd9Sstevel@tonic-gate * Poll Register 0 to till the Resetbit is 0. 38737c478bd9Sstevel@tonic-gate * 2(b). Use the MIF Frame/Output register to set the PHY in in Normal-Op, 38747c478bd9Sstevel@tonic-gate * 100Mbps and Non-Isolated mode. The main point here is to bring the 38757c478bd9Sstevel@tonic-gate * PHY out of Isolate mode so that it can generate the rx_clk and tx_clk 38767c478bd9Sstevel@tonic-gate * to the MII interface so that the Bigmac core can correctly reset 38777c478bd9Sstevel@tonic-gate * upon a software reset. 38787c478bd9Sstevel@tonic-gate * 2(c). Issue another Global Reset command to the Ethernet Channel and poll 38797c478bd9Sstevel@tonic-gate * the Global_Reset bits till completion. 38807c478bd9Sstevel@tonic-gate * 3. Set up all the data structures in the host memory. 38817c478bd9Sstevel@tonic-gate * 4. Program the TX_MAC registers/counters (excluding the TX_MAC Configuration 38827c478bd9Sstevel@tonic-gate * Register). 38837c478bd9Sstevel@tonic-gate * 5. Program the RX_MAC registers/counters (excluding the RX_MAC Configuration 38847c478bd9Sstevel@tonic-gate * Register). 38857c478bd9Sstevel@tonic-gate * 6. Program the Transmit Descriptor Ring Base Address in the ETX. 38867c478bd9Sstevel@tonic-gate * 7. Program the Receive Descriptor Ring Base Address in the ERX. 38877c478bd9Sstevel@tonic-gate * 8. Program the Global Configuration and the Global Interrupt Mask Registers. 38887c478bd9Sstevel@tonic-gate * 9. Program the ETX Configuration register (enable the Transmit DMA channel). 38897c478bd9Sstevel@tonic-gate * 10. Program the ERX Configuration register (enable the Receive DMA channel). 38907c478bd9Sstevel@tonic-gate * 11. Program the XIF Configuration Register (enable the XIF). 38917c478bd9Sstevel@tonic-gate * 12. Program the RX_MAC Configuration Register (Enable the RX_MAC). 38927c478bd9Sstevel@tonic-gate * 13. Program the TX_MAC Configuration Register (Enable the TX_MAC). 38937c478bd9Sstevel@tonic-gate */ 38947c478bd9Sstevel@tonic-gate 38957c478bd9Sstevel@tonic-gate 38967c478bd9Sstevel@tonic-gate #ifdef FEPS_URUN_BUG 38977c478bd9Sstevel@tonic-gate static int hme_palen = 32; 38987c478bd9Sstevel@tonic-gate #endif 38997c478bd9Sstevel@tonic-gate 39007c478bd9Sstevel@tonic-gate static int 39017c478bd9Sstevel@tonic-gate hmeinit(struct hme *hmep) 39027c478bd9Sstevel@tonic-gate { 3903*0219346bSGarrett D'Amore uint32_t i; 3904*0219346bSGarrett D'Amore int ret; 39057c478bd9Sstevel@tonic-gate 390685025c03Sgd /* 390785025c03Sgd * Lock sequence: 390885025c03Sgd * hme_intrlock, hme_xmitlock. 390985025c03Sgd */ 391085025c03Sgd mutex_enter(&hmep->hme_intrlock); 39117c478bd9Sstevel@tonic-gate 39127c478bd9Sstevel@tonic-gate /* 391385025c03Sgd * Don't touch the hardware if we are suspended. But don't 391485025c03Sgd * fail either. Some time later we may be resumed, and then 391585025c03Sgd * we'll be back here to program the device using the settings 391685025c03Sgd * in the soft state. 39177c478bd9Sstevel@tonic-gate */ 391885025c03Sgd if (hmep->hme_flags & HMESUSPENDED) { 391985025c03Sgd mutex_exit(&hmep->hme_intrlock); 392085025c03Sgd return (0); 392185025c03Sgd } 39227c478bd9Sstevel@tonic-gate 39237c478bd9Sstevel@tonic-gate /* 392485025c03Sgd * This should prevent us from clearing any interrupts that 392585025c03Sgd * may occur by temporarily stopping interrupts from occurring 392685025c03Sgd * for a short time. We need to update the interrupt mask 392785025c03Sgd * later in this function. 39287c478bd9Sstevel@tonic-gate */ 392985025c03Sgd PUT_GLOBREG(intmask, ~HMEG_MASK_MIF_INTR); 39307c478bd9Sstevel@tonic-gate 39317c478bd9Sstevel@tonic-gate 39327c478bd9Sstevel@tonic-gate /* 39337c478bd9Sstevel@tonic-gate * Rearranged the mutex acquisition order to solve the deadlock 39347c478bd9Sstevel@tonic-gate * situation as described in bug ID 4065896. 39357c478bd9Sstevel@tonic-gate */ 39367c478bd9Sstevel@tonic-gate 39377c478bd9Sstevel@tonic-gate hme_stop_timer(hmep); /* acquire hme_linklock */ 39387c478bd9Sstevel@tonic-gate mutex_enter(&hmep->hme_xmitlock); 39397c478bd9Sstevel@tonic-gate 39407c478bd9Sstevel@tonic-gate hmep->hme_flags = 0; 394185025c03Sgd hmep->hme_wantw = B_FALSE; 39427c478bd9Sstevel@tonic-gate hmep->hme_txhung = 0; 39437c478bd9Sstevel@tonic-gate 39447c478bd9Sstevel@tonic-gate /* 39457c478bd9Sstevel@tonic-gate * Initializing 'hmep->hme_iipackets' to match current 39467c478bd9Sstevel@tonic-gate * number of received packets. 39477c478bd9Sstevel@tonic-gate */ 39487c478bd9Sstevel@tonic-gate hmep->hme_iipackets = hmep->hme_ipackets; 39497c478bd9Sstevel@tonic-gate 39507c478bd9Sstevel@tonic-gate if (hmep->inits) 39517c478bd9Sstevel@tonic-gate hmesavecntrs(hmep); 39527c478bd9Sstevel@tonic-gate 39537c478bd9Sstevel@tonic-gate hme_stop_mifpoll(hmep); 39547c478bd9Sstevel@tonic-gate 39557c478bd9Sstevel@tonic-gate /* 39567c478bd9Sstevel@tonic-gate * Perform Global reset of the Sbus/FEPS ENET channel. 39577c478bd9Sstevel@tonic-gate */ 39587c478bd9Sstevel@tonic-gate (void) hmestop(hmep); 39597c478bd9Sstevel@tonic-gate 39607c478bd9Sstevel@tonic-gate /* 39617c478bd9Sstevel@tonic-gate * Clear all descriptors. 39627c478bd9Sstevel@tonic-gate */ 39637c478bd9Sstevel@tonic-gate bzero(hmep->hme_rmdp, HME_RMDMAX * sizeof (struct hme_rmd)); 39647c478bd9Sstevel@tonic-gate bzero(hmep->hme_tmdp, HME_TMDMAX * sizeof (struct hme_tmd)); 39657c478bd9Sstevel@tonic-gate 39667c478bd9Sstevel@tonic-gate /* 39677c478bd9Sstevel@tonic-gate * Hang out receive buffers. 39687c478bd9Sstevel@tonic-gate */ 3969*0219346bSGarrett D'Amore for (i = 0; i < HME_RMDMAX; i++) { 3970*0219346bSGarrett D'Amore PUT_RMD(i, hmep->hme_rbuf[i].paddr); 39717c478bd9Sstevel@tonic-gate } 39727c478bd9Sstevel@tonic-gate 39737c478bd9Sstevel@tonic-gate /* 39747c478bd9Sstevel@tonic-gate * DMA sync descriptors. 39757c478bd9Sstevel@tonic-gate */ 3976*0219346bSGarrett D'Amore (void) ddi_dma_sync(hmep->hme_rmd_dmah, 0, 0, DDI_DMA_SYNC_FORDEV); 3977*0219346bSGarrett D'Amore (void) ddi_dma_sync(hmep->hme_tmd_dmah, 0, 0, DDI_DMA_SYNC_FORDEV); 39787c478bd9Sstevel@tonic-gate 39797c478bd9Sstevel@tonic-gate /* 39807c478bd9Sstevel@tonic-gate * Reset RMD and TMD 'walking' pointers. 39817c478bd9Sstevel@tonic-gate */ 3982*0219346bSGarrett D'Amore hmep->hme_rxindex = 0; 3983*0219346bSGarrett D'Amore hmep->hme_txindex = hmep->hme_txreclaim = 0; 39847c478bd9Sstevel@tonic-gate 39857c478bd9Sstevel@tonic-gate /* 39867c478bd9Sstevel@tonic-gate * This is the right place to initialize MIF !!! 39877c478bd9Sstevel@tonic-gate */ 39887c478bd9Sstevel@tonic-gate 39897c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_imask, HME_MIF_INTMASK); /* mask all interrupts */ 39907c478bd9Sstevel@tonic-gate 39917c478bd9Sstevel@tonic-gate if (!hmep->hme_frame_enable) 39927c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_cfg, GET_MIFREG(mif_cfg) | HME_MIF_CFGBB); 39937c478bd9Sstevel@tonic-gate else 39947c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_cfg, GET_MIFREG(mif_cfg) & ~HME_MIF_CFGBB); 39957c478bd9Sstevel@tonic-gate /* enable frame mode */ 39967c478bd9Sstevel@tonic-gate 39977c478bd9Sstevel@tonic-gate /* 39987c478bd9Sstevel@tonic-gate * Depending on the transceiver detected, select the source 39997c478bd9Sstevel@tonic-gate * of the clocks for the MAC. Without the clocks, TX_MAC does 40007c478bd9Sstevel@tonic-gate * not reset. When the Global Reset is issued to the Sbus/FEPS 40017c478bd9Sstevel@tonic-gate * ASIC, it selects Internal by default. 40027c478bd9Sstevel@tonic-gate */ 40037c478bd9Sstevel@tonic-gate 40047c478bd9Sstevel@tonic-gate hme_check_transceiver(hmep); 40057c478bd9Sstevel@tonic-gate if (hmep->hme_transceiver == HME_NO_TRANSCEIVER) { 40067c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_HIGH, XCVR_MSG, no_xcvr_msg); 40077c478bd9Sstevel@tonic-gate hme_start_timer(hmep, hme_check_link, HME_LINKCHECK_TIMER); 40087c478bd9Sstevel@tonic-gate goto init_fail; /* abort initialization */ 40097c478bd9Sstevel@tonic-gate 40107c478bd9Sstevel@tonic-gate } else if (hmep->hme_transceiver == HME_INTERNAL_TRANSCEIVER) 40117c478bd9Sstevel@tonic-gate PUT_MACREG(xifc, 0); 40127c478bd9Sstevel@tonic-gate else 40137c478bd9Sstevel@tonic-gate PUT_MACREG(xifc, BMAC_XIFC_MIIBUFDIS); 40147c478bd9Sstevel@tonic-gate /* Isolate the Int. xcvr */ 40157c478bd9Sstevel@tonic-gate /* 40167c478bd9Sstevel@tonic-gate * Perform transceiver reset and speed selection only if 40177c478bd9Sstevel@tonic-gate * the link is down. 40187c478bd9Sstevel@tonic-gate */ 40197c478bd9Sstevel@tonic-gate if (!hmep->hme_linkcheck) 40207c478bd9Sstevel@tonic-gate /* 40217c478bd9Sstevel@tonic-gate * Reset the PHY and bring up the link 40227c478bd9Sstevel@tonic-gate * If it fails we will then increment a kstat. 40237c478bd9Sstevel@tonic-gate */ 40247c478bd9Sstevel@tonic-gate hme_reset_transceiver(hmep); 40257c478bd9Sstevel@tonic-gate else { 40267c478bd9Sstevel@tonic-gate if (hmep->hme_linkup) 40277c478bd9Sstevel@tonic-gate hme_start_mifpoll(hmep); 40287c478bd9Sstevel@tonic-gate hme_start_timer(hmep, hme_check_link, HME_LINKCHECK_TIMER); 40297c478bd9Sstevel@tonic-gate } 40307c478bd9Sstevel@tonic-gate hmep->inits++; 40317c478bd9Sstevel@tonic-gate 40327c478bd9Sstevel@tonic-gate /* 40337c478bd9Sstevel@tonic-gate * Initialize BigMAC registers. 40347c478bd9Sstevel@tonic-gate * First set the tx enable bit in tx config reg to 0 and poll on 40357c478bd9Sstevel@tonic-gate * it till it turns to 0. Same for rx config, hash and address 40367c478bd9Sstevel@tonic-gate * filter reg. 40377c478bd9Sstevel@tonic-gate * Here is the sequence per the spec. 40387c478bd9Sstevel@tonic-gate * MADD2 - MAC Address 2 40397c478bd9Sstevel@tonic-gate * MADD1 - MAC Address 1 40407c478bd9Sstevel@tonic-gate * MADD0 - MAC Address 0 40417c478bd9Sstevel@tonic-gate * HASH3, HASH2, HASH1, HASH0 for group address 40427c478bd9Sstevel@tonic-gate * AFR2, AFR1, AFR0 and AFMR for address filter mask 40437c478bd9Sstevel@tonic-gate * Program RXMIN and RXMAX for packet length if not 802.3 40447c478bd9Sstevel@tonic-gate * RXCFG - Rx config for not stripping CRC 40457c478bd9Sstevel@tonic-gate * XXX Anything else to hme configured in RXCFG 40467c478bd9Sstevel@tonic-gate * IPG1, IPG2, ALIMIT, SLOT, PALEN, PAPAT, TXSFD, JAM, TXMAX, TXMIN 40477c478bd9Sstevel@tonic-gate * if not 802.3 compliant 40487c478bd9Sstevel@tonic-gate * XIF register for speed selection 40497c478bd9Sstevel@tonic-gate * MASK - Interrupt mask 40507c478bd9Sstevel@tonic-gate * Set bit 0 of TXCFG 40517c478bd9Sstevel@tonic-gate * Set bit 0 of RXCFG 40527c478bd9Sstevel@tonic-gate */ 40537c478bd9Sstevel@tonic-gate 40547c478bd9Sstevel@tonic-gate /* 40557c478bd9Sstevel@tonic-gate * Initialize the TX_MAC registers 40567c478bd9Sstevel@tonic-gate * Initialization of jamsize to work around rx crc bug 40577c478bd9Sstevel@tonic-gate */ 40587c478bd9Sstevel@tonic-gate PUT_MACREG(jam, jamsize); 40597c478bd9Sstevel@tonic-gate 40607c478bd9Sstevel@tonic-gate #ifdef FEPS_URUN_BUG 40617c478bd9Sstevel@tonic-gate if (hme_urun_fix) 40627c478bd9Sstevel@tonic-gate PUT_MACREG(palen, hme_palen); 40637c478bd9Sstevel@tonic-gate #endif 40647c478bd9Sstevel@tonic-gate 40657c478bd9Sstevel@tonic-gate PUT_MACREG(ipg1, hme_param_ipg1); 40667c478bd9Sstevel@tonic-gate PUT_MACREG(ipg2, hme_param_ipg2); 40677c478bd9Sstevel@tonic-gate 40687c478bd9Sstevel@tonic-gate PUT_MACREG(rseed, 406985025c03Sgd ((hmep->hme_ouraddr.ether_addr_octet[0] << 8) & 0x3) | 407085025c03Sgd hmep->hme_ouraddr.ether_addr_octet[1]); 40717c478bd9Sstevel@tonic-gate 40727c478bd9Sstevel@tonic-gate /* Initialize the RX_MAC registers */ 40737c478bd9Sstevel@tonic-gate 40747c478bd9Sstevel@tonic-gate /* 40757c478bd9Sstevel@tonic-gate * Program BigMAC with local individual ethernet address. 40767c478bd9Sstevel@tonic-gate */ 40777c478bd9Sstevel@tonic-gate PUT_MACREG(madd2, (hmep->hme_ouraddr.ether_addr_octet[4] << 8) | 407885025c03Sgd hmep->hme_ouraddr.ether_addr_octet[5]); 40797c478bd9Sstevel@tonic-gate PUT_MACREG(madd1, (hmep->hme_ouraddr.ether_addr_octet[2] << 8) | 408085025c03Sgd hmep->hme_ouraddr.ether_addr_octet[3]); 40817c478bd9Sstevel@tonic-gate PUT_MACREG(madd0, (hmep->hme_ouraddr.ether_addr_octet[0] << 8) | 408285025c03Sgd hmep->hme_ouraddr.ether_addr_octet[1]); 40837c478bd9Sstevel@tonic-gate 40847c478bd9Sstevel@tonic-gate /* 40857c478bd9Sstevel@tonic-gate * Set up multicast address filter by passing all multicast 40867c478bd9Sstevel@tonic-gate * addresses through a crc generator, and then using the 40877c478bd9Sstevel@tonic-gate * low order 6 bits as a index into the 64 bit logical 40887c478bd9Sstevel@tonic-gate * address filter. The high order three bits select the word, 40897c478bd9Sstevel@tonic-gate * while the rest of the bits select the bit within the word. 40907c478bd9Sstevel@tonic-gate */ 409185025c03Sgd PUT_MACREG(hash0, hmep->hme_ladrf[0]); 409285025c03Sgd PUT_MACREG(hash1, hmep->hme_ladrf[1]); 409385025c03Sgd PUT_MACREG(hash2, hmep->hme_ladrf[2]); 409485025c03Sgd PUT_MACREG(hash3, hmep->hme_ladrf[3]); 40957c478bd9Sstevel@tonic-gate 40967c478bd9Sstevel@tonic-gate /* 409785025c03Sgd * Configure parameters to support VLAN. (VLAN encapsulation adds 409885025c03Sgd * four bytes.) 40997c478bd9Sstevel@tonic-gate */ 410085025c03Sgd PUT_MACREG(txmax, ETHERMAX + ETHERFCSL + 4); 410185025c03Sgd PUT_MACREG(rxmax, ETHERMAX + ETHERFCSL + 4); 41027c478bd9Sstevel@tonic-gate 41037c478bd9Sstevel@tonic-gate /* 41047c478bd9Sstevel@tonic-gate * Initialize HME Global registers, ETX registers and ERX registers. 41057c478bd9Sstevel@tonic-gate */ 41067c478bd9Sstevel@tonic-gate 4107*0219346bSGarrett D'Amore PUT_ETXREG(txring, hmep->hme_tmd_paddr); 4108*0219346bSGarrett D'Amore PUT_ERXREG(rxring, hmep->hme_rmd_paddr); 41097c478bd9Sstevel@tonic-gate 41107c478bd9Sstevel@tonic-gate /* 41117c478bd9Sstevel@tonic-gate * ERX registers can be written only if they have even no. of bits set. 41127c478bd9Sstevel@tonic-gate * So, if the value written is not read back, set the lsb and write 41137c478bd9Sstevel@tonic-gate * again. 41147c478bd9Sstevel@tonic-gate * static int hme_erx_fix = 1; : Use the fix for erx bug 41157c478bd9Sstevel@tonic-gate */ 41167c478bd9Sstevel@tonic-gate { 41177c478bd9Sstevel@tonic-gate uint32_t temp; 4118*0219346bSGarrett D'Amore temp = hmep->hme_rmd_paddr; 41197c478bd9Sstevel@tonic-gate 41207c478bd9Sstevel@tonic-gate if (GET_ERXREG(rxring) != temp) 41217c478bd9Sstevel@tonic-gate PUT_ERXREG(rxring, (temp | 4)); 41227c478bd9Sstevel@tonic-gate } 41237c478bd9Sstevel@tonic-gate 412485025c03Sgd PUT_GLOBREG(config, (hmep->hme_config | 412585025c03Sgd (hmep->hme_64bit_xfer << HMEG_CONFIG_64BIT_SHIFT))); 41267c478bd9Sstevel@tonic-gate 41277c478bd9Sstevel@tonic-gate /* 41287c478bd9Sstevel@tonic-gate * Significant performance improvements can be achieved by 41297c478bd9Sstevel@tonic-gate * disabling transmit interrupt. Thus TMD's are reclaimed only 41307c478bd9Sstevel@tonic-gate * when we run out of them in hmestart(). 41317c478bd9Sstevel@tonic-gate */ 41327c478bd9Sstevel@tonic-gate PUT_GLOBREG(intmask, 413385025c03Sgd HMEG_MASK_INTR | HMEG_MASK_TINT | HMEG_MASK_TX_ALL); 41347c478bd9Sstevel@tonic-gate 41357c478bd9Sstevel@tonic-gate PUT_ETXREG(txring_size, ((HME_TMDMAX -1)>> HMET_RINGSZ_SHIFT)); 41367c478bd9Sstevel@tonic-gate PUT_ETXREG(config, (GET_ETXREG(config) | HMET_CONFIG_TXDMA_EN 413785025c03Sgd | HMET_CONFIG_TXFIFOTH)); 41387c478bd9Sstevel@tonic-gate /* get the rxring size bits */ 41397c478bd9Sstevel@tonic-gate switch (HME_RMDMAX) { 41407c478bd9Sstevel@tonic-gate case 32: 41417c478bd9Sstevel@tonic-gate i = HMER_CONFIG_RXRINGSZ32; 41427c478bd9Sstevel@tonic-gate break; 41437c478bd9Sstevel@tonic-gate case 64: 41447c478bd9Sstevel@tonic-gate i = HMER_CONFIG_RXRINGSZ64; 41457c478bd9Sstevel@tonic-gate break; 41467c478bd9Sstevel@tonic-gate case 128: 41477c478bd9Sstevel@tonic-gate i = HMER_CONFIG_RXRINGSZ128; 41487c478bd9Sstevel@tonic-gate break; 41497c478bd9Sstevel@tonic-gate case 256: 41507c478bd9Sstevel@tonic-gate i = HMER_CONFIG_RXRINGSZ256; 41517c478bd9Sstevel@tonic-gate break; 41527c478bd9Sstevel@tonic-gate default: 41537c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 415485025c03Sgd unk_rx_ringsz_msg); 41557c478bd9Sstevel@tonic-gate goto init_fail; 41567c478bd9Sstevel@tonic-gate } 41577c478bd9Sstevel@tonic-gate i |= (HME_FSTBYTE_OFFSET << HMER_CONFIG_FBO_SHIFT) 415885025c03Sgd | HMER_CONFIG_RXDMA_EN; 415985025c03Sgd 416085025c03Sgd /* h/w checks start offset in half words */ 416185025c03Sgd i |= ((sizeof (struct ether_header) / 2) << HMER_RX_CSSTART_SHIFT); 416285025c03Sgd 41637c478bd9Sstevel@tonic-gate PUT_ERXREG(config, i); 41647c478bd9Sstevel@tonic-gate 41657c478bd9Sstevel@tonic-gate /* 41667c478bd9Sstevel@tonic-gate * Bug related to the parity handling in ERX. When erxp-config is 41677c478bd9Sstevel@tonic-gate * read back. 41687c478bd9Sstevel@tonic-gate * Sbus/FEPS drives the parity bit. This value is used while 41697c478bd9Sstevel@tonic-gate * writing again. 41707c478bd9Sstevel@tonic-gate * This fixes the RECV problem in SS5. 41717c478bd9Sstevel@tonic-gate * static int hme_erx_fix = 1; : Use the fix for erx bug 41727c478bd9Sstevel@tonic-gate */ 41737c478bd9Sstevel@tonic-gate { 41747c478bd9Sstevel@tonic-gate uint32_t temp; 41757c478bd9Sstevel@tonic-gate temp = GET_ERXREG(config); 41767c478bd9Sstevel@tonic-gate PUT_ERXREG(config, i); 41777c478bd9Sstevel@tonic-gate 41787c478bd9Sstevel@tonic-gate if (GET_ERXREG(config) != i) 41797c478bd9Sstevel@tonic-gate HME_FAULT_MSG4(hmep, SEVERITY_UNKNOWN, ERX_MSG, 418085025c03Sgd "error:temp = %x erxp->config = %x, should be %x", 418185025c03Sgd temp, GET_ERXREG(config), i); 41827c478bd9Sstevel@tonic-gate } 41837c478bd9Sstevel@tonic-gate 41847c478bd9Sstevel@tonic-gate /* 41857c478bd9Sstevel@tonic-gate * Set up the rxconfig, txconfig and seed register without enabling 41867c478bd9Sstevel@tonic-gate * them the former two at this time 41877c478bd9Sstevel@tonic-gate * 41887c478bd9Sstevel@tonic-gate * BigMAC strips the CRC bytes by default. Since this is 41897c478bd9Sstevel@tonic-gate * contrary to other pieces of hardware, this bit needs to 41907c478bd9Sstevel@tonic-gate * enabled to tell BigMAC not to strip the CRC bytes. 41917c478bd9Sstevel@tonic-gate * Do not filter this node's own packets. 41927c478bd9Sstevel@tonic-gate */ 41937c478bd9Sstevel@tonic-gate 41947c478bd9Sstevel@tonic-gate if (hme_reject_own) { 41957c478bd9Sstevel@tonic-gate PUT_MACREG(rxcfg, 4196228fdff0Sgd ((hmep->hme_promisc ? BMAC_RXCFG_PROMIS : 0) | 419785025c03Sgd BMAC_RXCFG_MYOWN | BMAC_RXCFG_HASH)); 41987c478bd9Sstevel@tonic-gate } else { 41997c478bd9Sstevel@tonic-gate PUT_MACREG(rxcfg, 4200228fdff0Sgd ((hmep->hme_promisc ? BMAC_RXCFG_PROMIS : 0) | 420185025c03Sgd BMAC_RXCFG_HASH)); 42027c478bd9Sstevel@tonic-gate } 42037c478bd9Sstevel@tonic-gate 42047c478bd9Sstevel@tonic-gate drv_usecwait(10); /* wait after setting Hash Enable bit */ 42057c478bd9Sstevel@tonic-gate 42067c478bd9Sstevel@tonic-gate if (hme_ngu_enable) 42077c478bd9Sstevel@tonic-gate PUT_MACREG(txcfg, (hmep->hme_fdx ? BMAC_TXCFG_FDX: 0) | 420885025c03Sgd BMAC_TXCFG_NGU); 42097c478bd9Sstevel@tonic-gate else 42107c478bd9Sstevel@tonic-gate PUT_MACREG(txcfg, (hmep->hme_fdx ? BMAC_TXCFG_FDX: 0)); 42117c478bd9Sstevel@tonic-gate hmep->hme_macfdx = hmep->hme_fdx; 42127c478bd9Sstevel@tonic-gate 42137c478bd9Sstevel@tonic-gate 42147c478bd9Sstevel@tonic-gate i = 0; 42157c478bd9Sstevel@tonic-gate if ((hme_param_lance_mode) && (hmep->hme_lance_mode_enable)) 42167c478bd9Sstevel@tonic-gate i = ((hme_param_ipg0 & HME_MASK_5BIT) << BMAC_XIFC_IPG0_SHIFT) 421785025c03Sgd | BMAC_XIFC_LANCE_ENAB; 42187c478bd9Sstevel@tonic-gate if (hmep->hme_transceiver == HME_INTERNAL_TRANSCEIVER) 42197c478bd9Sstevel@tonic-gate PUT_MACREG(xifc, i | (BMAC_XIFC_ENAB)); 42207c478bd9Sstevel@tonic-gate else 42217c478bd9Sstevel@tonic-gate PUT_MACREG(xifc, i | (BMAC_XIFC_ENAB | BMAC_XIFC_MIIBUFDIS)); 42227c478bd9Sstevel@tonic-gate 42237c478bd9Sstevel@tonic-gate PUT_MACREG(rxcfg, GET_MACREG(rxcfg) | BMAC_RXCFG_ENAB); 42247c478bd9Sstevel@tonic-gate PUT_MACREG(txcfg, GET_MACREG(txcfg) | BMAC_TXCFG_ENAB); 42257c478bd9Sstevel@tonic-gate 42267c478bd9Sstevel@tonic-gate hmep->hme_flags |= (HMERUNNING | HMEINITIALIZED); 42277c478bd9Sstevel@tonic-gate /* 42287c478bd9Sstevel@tonic-gate * Update the interrupt mask : this will re-allow interrupts to occur 42297c478bd9Sstevel@tonic-gate */ 423085025c03Sgd PUT_GLOBREG(intmask, HMEG_MASK_INTR); 423185025c03Sgd mac_tx_update(hmep->hme_mh); 42327c478bd9Sstevel@tonic-gate 42337c478bd9Sstevel@tonic-gate init_fail: 42347c478bd9Sstevel@tonic-gate /* 42357c478bd9Sstevel@tonic-gate * Release the locks in reverse order 42367c478bd9Sstevel@tonic-gate */ 42377c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_xmitlock); 42387c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_intrlock); 42397c478bd9Sstevel@tonic-gate 42407c478bd9Sstevel@tonic-gate ret = !(hmep->hme_flags & HMERUNNING); 42417c478bd9Sstevel@tonic-gate if (ret) { 42427c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 424385025c03Sgd init_fail_gen_msg); 42447c478bd9Sstevel@tonic-gate } 42457c478bd9Sstevel@tonic-gate 42467c478bd9Sstevel@tonic-gate /* 42477c478bd9Sstevel@tonic-gate * Hardware checks. 42487c478bd9Sstevel@tonic-gate */ 42497c478bd9Sstevel@tonic-gate CHECK_GLOBREG(); 42507c478bd9Sstevel@tonic-gate CHECK_MIFREG(); 42517c478bd9Sstevel@tonic-gate CHECK_MACREG(); 42527c478bd9Sstevel@tonic-gate CHECK_ERXREG(); 42537c478bd9Sstevel@tonic-gate CHECK_ETXREG(); 42547c478bd9Sstevel@tonic-gate 42557c478bd9Sstevel@tonic-gate init_exit: 42567c478bd9Sstevel@tonic-gate return (ret); 42577c478bd9Sstevel@tonic-gate } 42587c478bd9Sstevel@tonic-gate 42597c478bd9Sstevel@tonic-gate /* 42607c478bd9Sstevel@tonic-gate * Calculate the dvma burstsize by setting up a dvma temporarily. Return 42617c478bd9Sstevel@tonic-gate * 0 as burstsize upon failure as it signifies no burst size. 42627c478bd9Sstevel@tonic-gate * Requests for 64-bit transfer setup, if the platform supports it. 42637c478bd9Sstevel@tonic-gate * NOTE: Do not use ddi_dma_alloc_handle(9f) then ddi_dma_burstsize(9f), 42647c478bd9Sstevel@tonic-gate * sun4u Ultra-2 incorrectly returns a 32bit transfer. 42657c478bd9Sstevel@tonic-gate */ 42667c478bd9Sstevel@tonic-gate static int 42677c478bd9Sstevel@tonic-gate hmeburstsizes(struct hme *hmep) 42687c478bd9Sstevel@tonic-gate { 42697c478bd9Sstevel@tonic-gate int burstsizes; 42707c478bd9Sstevel@tonic-gate ddi_dma_handle_t handle; 42717c478bd9Sstevel@tonic-gate 42727c478bd9Sstevel@tonic-gate if (ddi_dma_alloc_handle(hmep->dip, &hme_dma_attr, 42737c478bd9Sstevel@tonic-gate DDI_DMA_DONTWAIT, NULL, &handle)) { 42747c478bd9Sstevel@tonic-gate return (0); 42757c478bd9Sstevel@tonic-gate } 42767c478bd9Sstevel@tonic-gate 42777c478bd9Sstevel@tonic-gate hmep->hme_burstsizes = burstsizes = ddi_dma_burstsizes(handle); 42787c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&handle); 42797c478bd9Sstevel@tonic-gate 42807c478bd9Sstevel@tonic-gate /* 42817c478bd9Sstevel@tonic-gate * Use user-configurable parameter for enabling 64-bit transfers 42827c478bd9Sstevel@tonic-gate */ 42837c478bd9Sstevel@tonic-gate burstsizes = (hmep->hme_burstsizes >> 16); 42847c478bd9Sstevel@tonic-gate if (burstsizes) 42857c478bd9Sstevel@tonic-gate hmep->hme_64bit_xfer = hme_64bit_enable; /* user config value */ 42867c478bd9Sstevel@tonic-gate else 42877c478bd9Sstevel@tonic-gate burstsizes = hmep->hme_burstsizes; 42887c478bd9Sstevel@tonic-gate 42897c478bd9Sstevel@tonic-gate if (hmep->hme_cheerio_mode) 42907c478bd9Sstevel@tonic-gate hmep->hme_64bit_xfer = 0; /* Disable for cheerio */ 42917c478bd9Sstevel@tonic-gate 42927c478bd9Sstevel@tonic-gate if (burstsizes & 0x40) 42937c478bd9Sstevel@tonic-gate hmep->hme_config = HMEG_CONFIG_BURST64; 42947c478bd9Sstevel@tonic-gate else if (burstsizes & 0x20) 42957c478bd9Sstevel@tonic-gate hmep->hme_config = HMEG_CONFIG_BURST32; 42967c478bd9Sstevel@tonic-gate else 42977c478bd9Sstevel@tonic-gate hmep->hme_config = HMEG_CONFIG_BURST16; 42987c478bd9Sstevel@tonic-gate 4299*0219346bSGarrett D'Amore return (DDI_SUCCESS); 4300*0219346bSGarrett D'Amore } 4301*0219346bSGarrett D'Amore 4302*0219346bSGarrett D'Amore static int 4303*0219346bSGarrett D'Amore hmeallocbuf(struct hme *hmep, hmebuf_t *buf, int dir) 4304*0219346bSGarrett D'Amore { 4305*0219346bSGarrett D'Amore ddi_dma_cookie_t dmac; 4306*0219346bSGarrett D'Amore size_t len; 4307*0219346bSGarrett D'Amore unsigned ccnt; 4308*0219346bSGarrett D'Amore 4309*0219346bSGarrett D'Amore if (ddi_dma_alloc_handle(hmep->dip, &hme_dma_attr, 4310*0219346bSGarrett D'Amore DDI_DMA_DONTWAIT, NULL, &buf->dmah) != DDI_SUCCESS) { 4311*0219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 4312*0219346bSGarrett D'Amore "cannot allocate buf dma handle - failed"); 4313*0219346bSGarrett D'Amore return (DDI_FAILURE); 4314*0219346bSGarrett D'Amore } 4315*0219346bSGarrett D'Amore 4316*0219346bSGarrett D'Amore if (ddi_dma_mem_alloc(buf->dmah, ROUNDUP(HMEBUFSIZE, 512), 4317*0219346bSGarrett D'Amore &hme_buf_attr, DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, NULL, 4318*0219346bSGarrett D'Amore &buf->kaddr, &len, &buf->acch) != DDI_SUCCESS) { 4319*0219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 4320*0219346bSGarrett D'Amore "cannot allocate buf memory - failed"); 4321*0219346bSGarrett D'Amore return (DDI_FAILURE); 4322*0219346bSGarrett D'Amore } 4323*0219346bSGarrett D'Amore 4324*0219346bSGarrett D'Amore if (ddi_dma_addr_bind_handle(buf->dmah, NULL, buf->kaddr, 4325*0219346bSGarrett D'Amore len, dir | DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL, 4326*0219346bSGarrett D'Amore &dmac, &ccnt) != DDI_DMA_MAPPED) { 4327*0219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 4328*0219346bSGarrett D'Amore "cannot map buf for dma - failed"); 4329*0219346bSGarrett D'Amore return (DDI_FAILURE); 4330*0219346bSGarrett D'Amore } 4331*0219346bSGarrett D'Amore buf->paddr = dmac.dmac_address; 4332*0219346bSGarrett D'Amore 4333*0219346bSGarrett D'Amore /* apparently they don't handle multiple cookies */ 4334*0219346bSGarrett D'Amore if (ccnt > 1) { 4335*0219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 4336*0219346bSGarrett D'Amore "too many buf dma cookies"); 4337*0219346bSGarrett D'Amore return (DDI_FAILURE); 4338*0219346bSGarrett D'Amore } 4339*0219346bSGarrett D'Amore return (DDI_SUCCESS); 4340*0219346bSGarrett D'Amore } 4341*0219346bSGarrett D'Amore 4342*0219346bSGarrett D'Amore static int 4343*0219346bSGarrett D'Amore hmeallocbufs(struct hme *hmep) 4344*0219346bSGarrett D'Amore { 4345*0219346bSGarrett D'Amore hmep->hme_tbuf = kmem_zalloc(HME_TMDMAX * sizeof (hmebuf_t), KM_SLEEP); 4346*0219346bSGarrett D'Amore hmep->hme_rbuf = kmem_zalloc(HME_RMDMAX * sizeof (hmebuf_t), KM_SLEEP); 4347*0219346bSGarrett D'Amore 4348*0219346bSGarrett D'Amore /* Alloc RX buffers. */ 4349*0219346bSGarrett D'Amore for (int i = 0; i < HME_RMDMAX; i++) { 4350*0219346bSGarrett D'Amore if (hmeallocbuf(hmep, &hmep->hme_rbuf[i], DDI_DMA_READ) != 4351*0219346bSGarrett D'Amore DDI_SUCCESS) { 4352*0219346bSGarrett D'Amore return (DDI_FAILURE); 4353*0219346bSGarrett D'Amore } 4354*0219346bSGarrett D'Amore } 4355*0219346bSGarrett D'Amore 4356*0219346bSGarrett D'Amore /* Alloc TX buffers. */ 4357*0219346bSGarrett D'Amore for (int i = 0; i < HME_TMDMAX; i++) { 4358*0219346bSGarrett D'Amore if (hmeallocbuf(hmep, &hmep->hme_tbuf[i], DDI_DMA_WRITE) != 4359*0219346bSGarrett D'Amore DDI_SUCCESS) { 4360*0219346bSGarrett D'Amore return (DDI_FAILURE); 4361*0219346bSGarrett D'Amore } 4362*0219346bSGarrett D'Amore } 43637c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 43647c478bd9Sstevel@tonic-gate } 43657c478bd9Sstevel@tonic-gate 43667c478bd9Sstevel@tonic-gate static void 43677c478bd9Sstevel@tonic-gate hmefreebufs(struct hme *hmep) 43687c478bd9Sstevel@tonic-gate { 43697c478bd9Sstevel@tonic-gate int i; 4370*0219346bSGarrett D'Amore 4371*0219346bSGarrett D'Amore if (hmep->hme_rbuf == NULL) 4372*0219346bSGarrett D'Amore return; 43737c478bd9Sstevel@tonic-gate 43747c478bd9Sstevel@tonic-gate /* 4375*0219346bSGarrett D'Amore * Free and unload pending xmit and recv buffers. 43767c478bd9Sstevel@tonic-gate * Maintaining the 1-to-1 ordered sequence of 4377*0219346bSGarrett D'Amore * We have written the routine to be idempotent. 43787c478bd9Sstevel@tonic-gate */ 43797c478bd9Sstevel@tonic-gate 43807c478bd9Sstevel@tonic-gate for (i = 0; i < HME_TMDMAX; i++) { 4381*0219346bSGarrett D'Amore hmebuf_t *tbuf = &hmep->hme_tbuf[i]; 4382*0219346bSGarrett D'Amore if (tbuf->paddr) { 4383*0219346bSGarrett D'Amore (void) ddi_dma_unbind_handle(tbuf->dmah); 4384*0219346bSGarrett D'Amore } 4385*0219346bSGarrett D'Amore if (tbuf->kaddr) { 4386*0219346bSGarrett D'Amore ddi_dma_mem_free(&tbuf->acch); 4387*0219346bSGarrett D'Amore } 4388*0219346bSGarrett D'Amore if (tbuf->dmah) { 4389*0219346bSGarrett D'Amore ddi_dma_free_handle(&tbuf->dmah); 43907c478bd9Sstevel@tonic-gate } 43917c478bd9Sstevel@tonic-gate } 43927c478bd9Sstevel@tonic-gate for (i = 0; i < HME_RMDMAX; i++) { 4393*0219346bSGarrett D'Amore hmebuf_t *rbuf = &hmep->hme_rbuf[i]; 4394*0219346bSGarrett D'Amore if (rbuf->paddr) { 4395*0219346bSGarrett D'Amore (void) ddi_dma_unbind_handle(rbuf->dmah); 4396*0219346bSGarrett D'Amore } 4397*0219346bSGarrett D'Amore if (rbuf->kaddr) { 4398*0219346bSGarrett D'Amore ddi_dma_mem_free(&rbuf->acch); 4399*0219346bSGarrett D'Amore } 4400*0219346bSGarrett D'Amore if (rbuf->dmah) { 4401*0219346bSGarrett D'Amore ddi_dma_free_handle(&rbuf->dmah); 44027c478bd9Sstevel@tonic-gate } 44037c478bd9Sstevel@tonic-gate } 4404*0219346bSGarrett D'Amore kmem_free(hmep->hme_rbuf, HME_RMDMAX * sizeof (hmebuf_t)); 4405*0219346bSGarrett D'Amore kmem_free(hmep->hme_tbuf, HME_TMDMAX * sizeof (hmebuf_t)); 44067c478bd9Sstevel@tonic-gate } 44077c478bd9Sstevel@tonic-gate 44087c478bd9Sstevel@tonic-gate /* 44097c478bd9Sstevel@tonic-gate * hme_start_mifpoll() - Enables the polling of the BMSR register of the PHY. 44107c478bd9Sstevel@tonic-gate * After enabling the poll, delay for atleast 62us for one poll to be done. 44117c478bd9Sstevel@tonic-gate * Then read the MIF status register to auto-clear the MIF status field. 44127c478bd9Sstevel@tonic-gate * Then program the MIF interrupt mask register to enable interrupts for the 44137c478bd9Sstevel@tonic-gate * LINK_STATUS and JABBER_DETECT bits. 44147c478bd9Sstevel@tonic-gate */ 44157c478bd9Sstevel@tonic-gate 44167c478bd9Sstevel@tonic-gate static void 44177c478bd9Sstevel@tonic-gate hme_start_mifpoll(struct hme *hmep) 44187c478bd9Sstevel@tonic-gate { 44197c478bd9Sstevel@tonic-gate uint32_t cfg; 44207c478bd9Sstevel@tonic-gate 44217c478bd9Sstevel@tonic-gate if (!hmep->hme_mifpoll_enable) 44227c478bd9Sstevel@tonic-gate return; 44237c478bd9Sstevel@tonic-gate 44247c478bd9Sstevel@tonic-gate cfg = (GET_MIFREG(mif_cfg) & ~(HME_MIF_CFGPD | HME_MIF_CFGPR)); 44257c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_cfg, 442685025c03Sgd (cfg = (cfg | (hmep->hme_phyad << HME_MIF_CFGPD_SHIFT) | 442785025c03Sgd (HME_PHY_BMSR << HME_MIF_CFGPR_SHIFT) | HME_MIF_CFGPE))); 44287c478bd9Sstevel@tonic-gate 44297c478bd9Sstevel@tonic-gate drv_usecwait(HME_MIF_POLL_DELAY); 44307c478bd9Sstevel@tonic-gate hmep->hme_polling_on = 1; 44317c478bd9Sstevel@tonic-gate hmep->hme_mifpoll_flag = 0; 44327c478bd9Sstevel@tonic-gate hmep->hme_mifpoll_data = (GET_MIFREG(mif_bsts) >> 16); 44337c478bd9Sstevel@tonic-gate 44347c478bd9Sstevel@tonic-gate /* Do not poll for Jabber Detect for 100 Mbps speed */ 44357c478bd9Sstevel@tonic-gate if (((hmep->hme_mode == HME_AUTO_SPEED) && 443685025c03Sgd (hmep->hme_tryspeed == HME_SPEED_100)) || 443785025c03Sgd ((hmep->hme_mode == HME_FORCE_SPEED) && 443885025c03Sgd (hmep->hme_forcespeed == HME_SPEED_100))) 44397c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_imask, ((uint16_t)~(PHY_BMSR_LNKSTS))); 44407c478bd9Sstevel@tonic-gate else 44417c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_imask, 444285025c03Sgd (uint16_t)~(PHY_BMSR_LNKSTS | PHY_BMSR_JABDET)); 44437c478bd9Sstevel@tonic-gate 44447c478bd9Sstevel@tonic-gate CHECK_MIFREG(); 44457c478bd9Sstevel@tonic-gate } 44467c478bd9Sstevel@tonic-gate 44477c478bd9Sstevel@tonic-gate static void 44487c478bd9Sstevel@tonic-gate hme_stop_mifpoll(struct hme *hmep) 44497c478bd9Sstevel@tonic-gate { 44507c478bd9Sstevel@tonic-gate if ((!hmep->hme_mifpoll_enable) || (!hmep->hme_polling_on)) 44517c478bd9Sstevel@tonic-gate return; 44527c478bd9Sstevel@tonic-gate 44537c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_imask, 0xffff); /* mask interrupts */ 44547c478bd9Sstevel@tonic-gate PUT_MIFREG(mif_cfg, (GET_MIFREG(mif_cfg) & ~HME_MIF_CFGPE)); 44557c478bd9Sstevel@tonic-gate 44567c478bd9Sstevel@tonic-gate hmep->hme_polling_on = 0; 44577c478bd9Sstevel@tonic-gate drv_usecwait(HME_MIF_POLL_DELAY); 44587c478bd9Sstevel@tonic-gate CHECK_MIFREG(); 44597c478bd9Sstevel@tonic-gate } 44607c478bd9Sstevel@tonic-gate 44617c478bd9Sstevel@tonic-gate /* 44627c478bd9Sstevel@tonic-gate * Un-initialize (STOP) HME channel. 44637c478bd9Sstevel@tonic-gate */ 44647c478bd9Sstevel@tonic-gate static void 44657c478bd9Sstevel@tonic-gate hmeuninit(struct hme *hmep) 44667c478bd9Sstevel@tonic-gate { 44677c478bd9Sstevel@tonic-gate /* 44687c478bd9Sstevel@tonic-gate * Allow up to 'HMEDRAINTIME' for pending xmit's to complete. 44697c478bd9Sstevel@tonic-gate */ 4470*0219346bSGarrett D'Amore HMEDELAY((hmep->hme_txindex == hmep->hme_txreclaim), HMEDRAINTIME); 44717c478bd9Sstevel@tonic-gate 44727c478bd9Sstevel@tonic-gate hme_stop_timer(hmep); /* acquire hme_linklock */ 44737c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_linklock); 44747c478bd9Sstevel@tonic-gate 44757c478bd9Sstevel@tonic-gate mutex_enter(&hmep->hme_intrlock); 44767c478bd9Sstevel@tonic-gate mutex_enter(&hmep->hme_xmitlock); 44777c478bd9Sstevel@tonic-gate 44787c478bd9Sstevel@tonic-gate hme_stop_mifpoll(hmep); 44797c478bd9Sstevel@tonic-gate 44807c478bd9Sstevel@tonic-gate hmep->hme_flags &= ~HMERUNNING; 44817c478bd9Sstevel@tonic-gate 44827c478bd9Sstevel@tonic-gate (void) hmestop(hmep); 44837c478bd9Sstevel@tonic-gate 44847c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_xmitlock); 44857c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_intrlock); 44867c478bd9Sstevel@tonic-gate } 44877c478bd9Sstevel@tonic-gate 44887c478bd9Sstevel@tonic-gate /* 44897c478bd9Sstevel@tonic-gate * Allocate CONSISTENT memory for rmds and tmds with appropriate alignment and 44907c478bd9Sstevel@tonic-gate * map it in IO space. Allocate space for transmit and receive ddi_dma_handle 44917c478bd9Sstevel@tonic-gate * structures to use the DMA interface. 44927c478bd9Sstevel@tonic-gate */ 44937c478bd9Sstevel@tonic-gate static int 44947c478bd9Sstevel@tonic-gate hmeallocthings(struct hme *hmep) 44957c478bd9Sstevel@tonic-gate { 4496*0219346bSGarrett D'Amore int size; 4497*0219346bSGarrett D'Amore int rval; 4498*0219346bSGarrett D'Amore size_t real_len; 4499*0219346bSGarrett D'Amore uint_t cookiec; 4500*0219346bSGarrett D'Amore ddi_dma_cookie_t dmac; 4501*0219346bSGarrett D'Amore dev_info_t *dip = hmep->dip; 45027c478bd9Sstevel@tonic-gate 45037c478bd9Sstevel@tonic-gate /* 45047c478bd9Sstevel@tonic-gate * Allocate the TMD and RMD descriptors and extra for page alignment. 45057c478bd9Sstevel@tonic-gate */ 45067c478bd9Sstevel@tonic-gate 4507*0219346bSGarrett D'Amore rval = ddi_dma_alloc_handle(dip, &hme_dma_attr, DDI_DMA_DONTWAIT, NULL, 4508*0219346bSGarrett D'Amore &hmep->hme_rmd_dmah); 45097c478bd9Sstevel@tonic-gate if (rval != DDI_SUCCESS) { 451085025c03Sgd HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 451185025c03Sgd "cannot allocate rmd handle - failed"); 4512*0219346bSGarrett D'Amore return (DDI_FAILURE); 45137c478bd9Sstevel@tonic-gate } 4514*0219346bSGarrett D'Amore size = HME_RMDMAX * sizeof (struct hme_rmd); 4515*0219346bSGarrett D'Amore rval = ddi_dma_mem_alloc(hmep->hme_rmd_dmah, size, 4516*0219346bSGarrett D'Amore &hmep->hme_dev_attr, DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL, 4517*0219346bSGarrett D'Amore &hmep->hme_rmd_kaddr, &real_len, &hmep->hme_rmd_acch); 45187c478bd9Sstevel@tonic-gate if (rval != DDI_SUCCESS) { 451985025c03Sgd HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 4520*0219346bSGarrett D'Amore "cannot allocate rmd dma mem - failed"); 4521*0219346bSGarrett D'Amore return (DDI_FAILURE); 45227c478bd9Sstevel@tonic-gate } 4523*0219346bSGarrett D'Amore hmep->hme_rmdp = (void *)(hmep->hme_rmd_kaddr); 4524*0219346bSGarrett D'Amore rval = ddi_dma_addr_bind_handle(hmep->hme_rmd_dmah, NULL, 4525*0219346bSGarrett D'Amore hmep->hme_rmd_kaddr, size, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 4526*0219346bSGarrett D'Amore DDI_DMA_DONTWAIT, NULL, &dmac, &cookiec); 45277c478bd9Sstevel@tonic-gate if (rval != DDI_DMA_MAPPED) { 452885025c03Sgd HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 4529*0219346bSGarrett D'Amore "cannot allocate rmd dma - failed"); 4530*0219346bSGarrett D'Amore return (DDI_FAILURE); 45317c478bd9Sstevel@tonic-gate } 4532*0219346bSGarrett D'Amore hmep->hme_rmd_paddr = dmac.dmac_address; 45337c478bd9Sstevel@tonic-gate if (cookiec != 1) { 453485025c03Sgd HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 4535*0219346bSGarrett D'Amore "too many rmd cookies - failed"); 4536*0219346bSGarrett D'Amore return (DDI_FAILURE); 45377c478bd9Sstevel@tonic-gate } 45387c478bd9Sstevel@tonic-gate 4539*0219346bSGarrett D'Amore rval = ddi_dma_alloc_handle(dip, &hme_dma_attr, DDI_DMA_DONTWAIT, NULL, 4540*0219346bSGarrett D'Amore &hmep->hme_tmd_dmah); 4541*0219346bSGarrett D'Amore if (rval != DDI_SUCCESS) { 4542*0219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 4543*0219346bSGarrett D'Amore "cannot allocate tmd handle - failed"); 4544*0219346bSGarrett D'Amore return (DDI_FAILURE); 4545*0219346bSGarrett D'Amore } 4546*0219346bSGarrett D'Amore size = HME_TMDMAX * sizeof (struct hme_rmd); 4547*0219346bSGarrett D'Amore rval = ddi_dma_mem_alloc(hmep->hme_tmd_dmah, size, 4548*0219346bSGarrett D'Amore &hmep->hme_dev_attr, DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL, 4549*0219346bSGarrett D'Amore &hmep->hme_tmd_kaddr, &real_len, &hmep->hme_tmd_acch); 4550*0219346bSGarrett D'Amore if (rval != DDI_SUCCESS) { 4551*0219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 4552*0219346bSGarrett D'Amore "cannot allocate tmd dma mem - failed"); 4553*0219346bSGarrett D'Amore return (DDI_FAILURE); 4554*0219346bSGarrett D'Amore } 4555*0219346bSGarrett D'Amore hmep->hme_tmdp = (void *)(hmep->hme_tmd_kaddr); 4556*0219346bSGarrett D'Amore rval = ddi_dma_addr_bind_handle(hmep->hme_tmd_dmah, NULL, 4557*0219346bSGarrett D'Amore hmep->hme_tmd_kaddr, size, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 4558*0219346bSGarrett D'Amore DDI_DMA_DONTWAIT, NULL, &dmac, &cookiec); 4559*0219346bSGarrett D'Amore if (rval != DDI_DMA_MAPPED) { 4560*0219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 4561*0219346bSGarrett D'Amore "cannot allocate tmd dma - failed"); 4562*0219346bSGarrett D'Amore return (DDI_FAILURE); 4563*0219346bSGarrett D'Amore } 4564*0219346bSGarrett D'Amore hmep->hme_tmd_paddr = dmac.dmac_address; 4565*0219346bSGarrett D'Amore if (cookiec != 1) { 4566*0219346bSGarrett D'Amore HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, 4567*0219346bSGarrett D'Amore "too many tmd cookies - failed"); 4568*0219346bSGarrett D'Amore return (DDI_FAILURE); 45697c478bd9Sstevel@tonic-gate } 45707c478bd9Sstevel@tonic-gate 4571*0219346bSGarrett D'Amore return (DDI_SUCCESS); 45727c478bd9Sstevel@tonic-gate } 45737c478bd9Sstevel@tonic-gate 4574*0219346bSGarrett D'Amore static void 4575*0219346bSGarrett D'Amore hmefreethings(struct hme *hmep) 4576*0219346bSGarrett D'Amore { 4577*0219346bSGarrett D'Amore if (hmep->hme_rmd_paddr) { 4578*0219346bSGarrett D'Amore (void) ddi_dma_unbind_handle(hmep->hme_rmd_dmah); 4579*0219346bSGarrett D'Amore hmep->hme_rmd_paddr = 0; 4580*0219346bSGarrett D'Amore } 4581*0219346bSGarrett D'Amore if (hmep->hme_rmd_acch) 4582*0219346bSGarrett D'Amore ddi_dma_mem_free(&hmep->hme_rmd_acch); 4583*0219346bSGarrett D'Amore if (hmep->hme_rmd_dmah) 4584*0219346bSGarrett D'Amore ddi_dma_free_handle(&hmep->hme_rmd_dmah); 4585*0219346bSGarrett D'Amore 4586*0219346bSGarrett D'Amore if (hmep->hme_tmd_paddr) { 4587*0219346bSGarrett D'Amore (void) ddi_dma_unbind_handle(hmep->hme_tmd_dmah); 4588*0219346bSGarrett D'Amore hmep->hme_tmd_paddr = 0; 4589*0219346bSGarrett D'Amore } 4590*0219346bSGarrett D'Amore if (hmep->hme_tmd_acch) 4591*0219346bSGarrett D'Amore ddi_dma_mem_free(&hmep->hme_tmd_acch); 4592*0219346bSGarrett D'Amore if (hmep->hme_tmd_dmah) 4593*0219346bSGarrett D'Amore ddi_dma_free_handle(&hmep->hme_tmd_dmah); 4594*0219346bSGarrett D'Amore } 45957c478bd9Sstevel@tonic-gate 45967c478bd9Sstevel@tonic-gate /* 45977c478bd9Sstevel@tonic-gate * First check to see if it our device interrupting. 45987c478bd9Sstevel@tonic-gate */ 45997c478bd9Sstevel@tonic-gate static uint_t 460085025c03Sgd hmeintr(caddr_t arg) 46017c478bd9Sstevel@tonic-gate { 460285025c03Sgd struct hme *hmep = (void *)arg; 46037c478bd9Sstevel@tonic-gate uint32_t hmesbits; 46047c478bd9Sstevel@tonic-gate uint32_t mif_status; 46057c478bd9Sstevel@tonic-gate uint32_t serviced = DDI_INTR_UNCLAIMED; 46067c478bd9Sstevel@tonic-gate uint32_t num_reads = 0; 460785025c03Sgd uint32_t rflags; 460885025c03Sgd mblk_t *mp, *head, **tail; 46097c478bd9Sstevel@tonic-gate 46107c478bd9Sstevel@tonic-gate 461185025c03Sgd head = NULL; 461285025c03Sgd tail = &head; 46137c478bd9Sstevel@tonic-gate 46147c478bd9Sstevel@tonic-gate mutex_enter(&hmep->hme_intrlock); 46157c478bd9Sstevel@tonic-gate 46167c478bd9Sstevel@tonic-gate /* 46177c478bd9Sstevel@tonic-gate * The status register auto-clears on read except for 46187c478bd9Sstevel@tonic-gate * MIF Interrupt bit 46197c478bd9Sstevel@tonic-gate */ 46207c478bd9Sstevel@tonic-gate hmesbits = GET_GLOBREG(status); 46217c478bd9Sstevel@tonic-gate CHECK_GLOBREG(); 46227c478bd9Sstevel@tonic-gate 46237c478bd9Sstevel@tonic-gate /* 46247c478bd9Sstevel@tonic-gate * Note: TINT is sometimes enabled in thr hmereclaim() 46257c478bd9Sstevel@tonic-gate */ 46267c478bd9Sstevel@tonic-gate 46277c478bd9Sstevel@tonic-gate /* 46287c478bd9Sstevel@tonic-gate * Bugid 1227832 - to handle spurious interrupts on fusion systems. 46297c478bd9Sstevel@tonic-gate * Claim the first interrupt after initialization 46307c478bd9Sstevel@tonic-gate */ 46317c478bd9Sstevel@tonic-gate if (hmep->hme_flags & HMEINITIALIZED) { 46327c478bd9Sstevel@tonic-gate hmep->hme_flags &= ~HMEINITIALIZED; 46337c478bd9Sstevel@tonic-gate serviced = DDI_INTR_CLAIMED; 46347c478bd9Sstevel@tonic-gate } 46357c478bd9Sstevel@tonic-gate 46367c478bd9Sstevel@tonic-gate if ((hmesbits & (HMEG_STATUS_INTR | HMEG_STATUS_TINT)) == 0) { 46377c478bd9Sstevel@tonic-gate /* No interesting interrupt */ 46387c478bd9Sstevel@tonic-gate if (hmep->hme_intrstats) { 46397c478bd9Sstevel@tonic-gate if (serviced == DDI_INTR_UNCLAIMED) 46407c478bd9Sstevel@tonic-gate KIOIP->intrs[KSTAT_INTR_SPURIOUS]++; 46417c478bd9Sstevel@tonic-gate else 46427c478bd9Sstevel@tonic-gate KIOIP->intrs[KSTAT_INTR_HARD]++; 46437c478bd9Sstevel@tonic-gate } 46447c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_intrlock); 46457c478bd9Sstevel@tonic-gate return (serviced); 46467c478bd9Sstevel@tonic-gate } 46477c478bd9Sstevel@tonic-gate 46487c478bd9Sstevel@tonic-gate serviced = DDI_INTR_CLAIMED; 46497c478bd9Sstevel@tonic-gate 46507c478bd9Sstevel@tonic-gate if (!(hmep->hme_flags & HMERUNNING)) { 46517c478bd9Sstevel@tonic-gate if (hmep->hme_intrstats) 46527c478bd9Sstevel@tonic-gate KIOIP->intrs[KSTAT_INTR_HARD]++; 46537c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_intrlock); 46547c478bd9Sstevel@tonic-gate hmeuninit(hmep); 46557c478bd9Sstevel@tonic-gate return (serviced); 46567c478bd9Sstevel@tonic-gate } 46577c478bd9Sstevel@tonic-gate 46587c478bd9Sstevel@tonic-gate if (hmesbits & (HMEG_STATUS_FATAL_ERR | HMEG_STATUS_NONFATAL_ERR)) { 46597c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_FATAL_ERR) { 46607c478bd9Sstevel@tonic-gate 46617c478bd9Sstevel@tonic-gate if (hmep->hme_intrstats) 46627c478bd9Sstevel@tonic-gate KIOIP->intrs[KSTAT_INTR_HARD]++; 46637c478bd9Sstevel@tonic-gate hme_fatal_err(hmep, hmesbits); 46647c478bd9Sstevel@tonic-gate 46657c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_intrlock); 46667c478bd9Sstevel@tonic-gate (void) hmeinit(hmep); 46677c478bd9Sstevel@tonic-gate return (serviced); 46687c478bd9Sstevel@tonic-gate } 46697c478bd9Sstevel@tonic-gate hme_nonfatal_err(hmep, hmesbits); 46707c478bd9Sstevel@tonic-gate } 46717c478bd9Sstevel@tonic-gate 46727c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_MIF_INTR) { 46737c478bd9Sstevel@tonic-gate mif_status = (GET_MIFREG(mif_bsts) >> 16); 46747c478bd9Sstevel@tonic-gate if (!(mif_status & PHY_BMSR_LNKSTS)) { 46757c478bd9Sstevel@tonic-gate 46767c478bd9Sstevel@tonic-gate if (hmep->hme_intrstats) 46777c478bd9Sstevel@tonic-gate KIOIP->intrs[KSTAT_INTR_HARD]++; 46787c478bd9Sstevel@tonic-gate 46797c478bd9Sstevel@tonic-gate hme_stop_mifpoll(hmep); 46807c478bd9Sstevel@tonic-gate hmep->hme_mifpoll_flag = 1; 46817c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_intrlock); 46827c478bd9Sstevel@tonic-gate hme_stop_timer(hmep); 46837c478bd9Sstevel@tonic-gate hme_start_timer(hmep, hme_check_link, MSECOND(1)); 46847c478bd9Sstevel@tonic-gate return (serviced); 46857c478bd9Sstevel@tonic-gate } 46867c478bd9Sstevel@tonic-gate /* 46877c478bd9Sstevel@tonic-gate * 46887c478bd9Sstevel@tonic-gate * BugId 1261889 EscId 50699 ftp hangs @ 10 Mbps 46897c478bd9Sstevel@tonic-gate * 46907c478bd9Sstevel@tonic-gate * Here could be one cause: 46917c478bd9Sstevel@tonic-gate * national PHY sees jabber, goes into "Jabber function", 46927c478bd9Sstevel@tonic-gate * (see section 3.7.6 in PHY specs.), disables transmitter, 46937c478bd9Sstevel@tonic-gate * and waits for internal transmit enable to be de-asserted 46947c478bd9Sstevel@tonic-gate * for at least 750ms (the "unjab" time). Also, the PHY 46957c478bd9Sstevel@tonic-gate * has asserted COL, the collision detect signal. 46967c478bd9Sstevel@tonic-gate * 46977c478bd9Sstevel@tonic-gate * In the meantime, the Sbus/FEPS, in never-give-up mode, 46987c478bd9Sstevel@tonic-gate * continually retries, backs off 16 times as per spec, 46997c478bd9Sstevel@tonic-gate * and restarts the transmission, so TX_EN is never 47007c478bd9Sstevel@tonic-gate * deasserted long enough, in particular TX_EN is turned 47017c478bd9Sstevel@tonic-gate * on approximately once every 4 microseconds on the 47027c478bd9Sstevel@tonic-gate * average. PHY and MAC are deadlocked. 47037c478bd9Sstevel@tonic-gate * 47047c478bd9Sstevel@tonic-gate * Here is part of the fix: 47057c478bd9Sstevel@tonic-gate * On seeing the jabber, treat it like a hme_fatal_err 47067c478bd9Sstevel@tonic-gate * and reset both the Sbus/FEPS and the PHY. 47077c478bd9Sstevel@tonic-gate */ 47087c478bd9Sstevel@tonic-gate 47097c478bd9Sstevel@tonic-gate if (mif_status & (PHY_BMSR_JABDET)) { 47107c478bd9Sstevel@tonic-gate 47117c478bd9Sstevel@tonic-gate /* national phy only defines this at 10 Mbps */ 47127c478bd9Sstevel@tonic-gate if (hme_param_speed == 0) { /* 10 Mbps speed ? */ 47137c478bd9Sstevel@tonic-gate hmep->hme_jab++; 47147c478bd9Sstevel@tonic-gate 47157c478bd9Sstevel@tonic-gate /* treat jabber like a fatal error */ 47167c478bd9Sstevel@tonic-gate hmep->hme_linkcheck = 0; /* force PHY reset */ 47177c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_intrlock); 47187c478bd9Sstevel@tonic-gate (void) hmeinit(hmep); 47197c478bd9Sstevel@tonic-gate 47207c478bd9Sstevel@tonic-gate return (serviced); 47217c478bd9Sstevel@tonic-gate } 47227c478bd9Sstevel@tonic-gate } 47237c478bd9Sstevel@tonic-gate hme_start_mifpoll(hmep); 47247c478bd9Sstevel@tonic-gate } 47257c478bd9Sstevel@tonic-gate 47267c478bd9Sstevel@tonic-gate if (hmesbits & (HMEG_STATUS_TX_ALL | HMEG_STATUS_TINT)) { 47277c478bd9Sstevel@tonic-gate mutex_enter(&hmep->hme_xmitlock); 47287c478bd9Sstevel@tonic-gate 47297c478bd9Sstevel@tonic-gate hmereclaim(hmep); 47307c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_xmitlock); 47317c478bd9Sstevel@tonic-gate } 47327c478bd9Sstevel@tonic-gate 47337c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_RINT) { 47347c478bd9Sstevel@tonic-gate 47357c478bd9Sstevel@tonic-gate /* 47367c478bd9Sstevel@tonic-gate * This dummy PIO is required to flush the SBus 47377c478bd9Sstevel@tonic-gate * Bridge buffers in QFE. 47387c478bd9Sstevel@tonic-gate */ 4739*0219346bSGarrett D'Amore (void) GET_GLOBREG(config); 47407c478bd9Sstevel@tonic-gate 47417c478bd9Sstevel@tonic-gate /* 4742*0219346bSGarrett D'Amore * Loop through each RMD no more than once. 47437c478bd9Sstevel@tonic-gate */ 4744*0219346bSGarrett D'Amore while (num_reads++ < HME_RMDMAX) { 4745*0219346bSGarrett D'Amore hmebuf_t *rbuf; 4746*0219346bSGarrett D'Amore int rxptr; 4747*0219346bSGarrett D'Amore 4748*0219346bSGarrett D'Amore rxptr = hmep->hme_rxindex % HME_RMDMAX; 4749*0219346bSGarrett D'Amore HMESYNCRMD(rxptr, DDI_DMA_SYNC_FORKERNEL); 4750*0219346bSGarrett D'Amore 4751*0219346bSGarrett D'Amore rflags = GET_RMD_FLAGS(rxptr); 4752*0219346bSGarrett D'Amore if (rflags & HMERMD_OWN) { 4753*0219346bSGarrett D'Amore /* 4754*0219346bSGarrett D'Amore * Chip still owns it. We're done. 4755*0219346bSGarrett D'Amore */ 4756*0219346bSGarrett D'Amore break; 4757*0219346bSGarrett D'Amore } 475885025c03Sgd 4759*0219346bSGarrett D'Amore /* 4760*0219346bSGarrett D'Amore * Retrieve the packet. 4761*0219346bSGarrett D'Amore */ 4762*0219346bSGarrett D'Amore rbuf = &hmep->hme_rbuf[rxptr]; 4763*0219346bSGarrett D'Amore mp = hmeread(hmep, rbuf, rflags); 476485025c03Sgd 47657c478bd9Sstevel@tonic-gate /* 4766*0219346bSGarrett D'Amore * Return ownership of the RMD. 47677c478bd9Sstevel@tonic-gate */ 4768*0219346bSGarrett D'Amore PUT_RMD(rxptr, rbuf->paddr); 4769*0219346bSGarrett D'Amore HMESYNCRMD(rxptr, DDI_DMA_SYNC_FORDEV); 47707c478bd9Sstevel@tonic-gate 477185025c03Sgd if (mp != NULL) { 477285025c03Sgd *tail = mp; 477385025c03Sgd tail = &mp->b_next; 477485025c03Sgd } 477585025c03Sgd 47767c478bd9Sstevel@tonic-gate /* 4777*0219346bSGarrett D'Amore * Advance to the next RMD. 47787c478bd9Sstevel@tonic-gate */ 4779*0219346bSGarrett D'Amore hmep->hme_rxindex++; 47807c478bd9Sstevel@tonic-gate } 47817c478bd9Sstevel@tonic-gate } 47827c478bd9Sstevel@tonic-gate 47837c478bd9Sstevel@tonic-gate if (hmep->hme_intrstats) 47847c478bd9Sstevel@tonic-gate KIOIP->intrs[KSTAT_INTR_HARD]++; 47857c478bd9Sstevel@tonic-gate 47867c478bd9Sstevel@tonic-gate mutex_exit(&hmep->hme_intrlock); 478785025c03Sgd 478885025c03Sgd if (head != NULL) 478985025c03Sgd mac_rx(hmep->hme_mh, NULL, head); 479085025c03Sgd 47917c478bd9Sstevel@tonic-gate return (serviced); 47927c478bd9Sstevel@tonic-gate } 47937c478bd9Sstevel@tonic-gate 47947c478bd9Sstevel@tonic-gate /* 47957c478bd9Sstevel@tonic-gate * Transmit completion reclaiming. 47967c478bd9Sstevel@tonic-gate */ 47977c478bd9Sstevel@tonic-gate static void 47987c478bd9Sstevel@tonic-gate hmereclaim(struct hme *hmep) 47997c478bd9Sstevel@tonic-gate { 4800*0219346bSGarrett D'Amore boolean_t reclaimed = B_FALSE; 48017c478bd9Sstevel@tonic-gate 48027c478bd9Sstevel@tonic-gate /* 48037c478bd9Sstevel@tonic-gate * Loop through each TMD. 48047c478bd9Sstevel@tonic-gate */ 4805*0219346bSGarrett D'Amore while (hmep->hme_txindex > hmep->hme_txreclaim) { 4806*0219346bSGarrett D'Amore 4807*0219346bSGarrett D'Amore int reclaim; 4808*0219346bSGarrett D'Amore uint32_t flags; 4809*0219346bSGarrett D'Amore 4810*0219346bSGarrett D'Amore reclaim = hmep->hme_txreclaim % HME_TMDMAX; 4811*0219346bSGarrett D'Amore HMESYNCTMD(reclaim, DDI_DMA_SYNC_FORKERNEL); 4812*0219346bSGarrett D'Amore 4813*0219346bSGarrett D'Amore flags = GET_TMD_FLAGS(reclaim); 4814*0219346bSGarrett D'Amore if (flags & HMETMD_OWN) { 4815*0219346bSGarrett D'Amore /* 4816*0219346bSGarrett D'Amore * Chip still owns it. We're done. 4817*0219346bSGarrett D'Amore */ 4818*0219346bSGarrett D'Amore break; 4819*0219346bSGarrett D'Amore } 48207c478bd9Sstevel@tonic-gate 48217c478bd9Sstevel@tonic-gate /* 4822*0219346bSGarrett D'Amore * Count a chained packet only once. 48237c478bd9Sstevel@tonic-gate */ 4824*0219346bSGarrett D'Amore if (flags & HMETMD_SOP) { 48257c478bd9Sstevel@tonic-gate hmep->hme_opackets++; 48267c478bd9Sstevel@tonic-gate } 48277c478bd9Sstevel@tonic-gate 48287c478bd9Sstevel@tonic-gate /* 48297c478bd9Sstevel@tonic-gate * MIB II 48307c478bd9Sstevel@tonic-gate */ 4831*0219346bSGarrett D'Amore hmep->hme_obytes += flags & HMETMD_BUFSIZE; 48327c478bd9Sstevel@tonic-gate 4833*0219346bSGarrett D'Amore reclaimed = B_TRUE; 4834*0219346bSGarrett D'Amore hmep->hme_txreclaim++; 48357c478bd9Sstevel@tonic-gate } 48367c478bd9Sstevel@tonic-gate 4837*0219346bSGarrett D'Amore if (reclaimed) { 48387c478bd9Sstevel@tonic-gate /* 48397c478bd9Sstevel@tonic-gate * we could reclaim some TMDs so turn off interrupts 48407c478bd9Sstevel@tonic-gate */ 48417c478bd9Sstevel@tonic-gate if (hmep->hme_wantw) { 48427c478bd9Sstevel@tonic-gate PUT_GLOBREG(intmask, 484385025c03Sgd HMEG_MASK_INTR | HMEG_MASK_TINT | 484485025c03Sgd HMEG_MASK_TX_ALL); 484585025c03Sgd hmep->hme_wantw = B_FALSE; 484685025c03Sgd mac_tx_update(hmep->hme_mh); 48477c478bd9Sstevel@tonic-gate } 48487c478bd9Sstevel@tonic-gate } else { 48497c478bd9Sstevel@tonic-gate /* 48507c478bd9Sstevel@tonic-gate * enable TINTS: so that even if there is no further activity 48517c478bd9Sstevel@tonic-gate * hmereclaim will get called 48527c478bd9Sstevel@tonic-gate */ 48537c478bd9Sstevel@tonic-gate if (hmep->hme_wantw) 485485025c03Sgd PUT_GLOBREG(intmask, 485585025c03Sgd GET_GLOBREG(intmask) & ~HMEG_MASK_TX_ALL); 48567c478bd9Sstevel@tonic-gate } 48577c478bd9Sstevel@tonic-gate CHECK_GLOBREG(); 48587c478bd9Sstevel@tonic-gate } 48597c478bd9Sstevel@tonic-gate 48607c478bd9Sstevel@tonic-gate /* 48617c478bd9Sstevel@tonic-gate * Handle interrupts for fatal errors 48627c478bd9Sstevel@tonic-gate * Need reinitialization of the ENET channel. 48637c478bd9Sstevel@tonic-gate */ 48647c478bd9Sstevel@tonic-gate static void 48657c478bd9Sstevel@tonic-gate hme_fatal_err(struct hme *hmep, uint_t hmesbits) 48667c478bd9Sstevel@tonic-gate { 48677c478bd9Sstevel@tonic-gate 48687c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_SLV_PAR_ERR) { 48697c478bd9Sstevel@tonic-gate hmep->hme_slvparerr++; 48707c478bd9Sstevel@tonic-gate } 48717c478bd9Sstevel@tonic-gate 48727c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_SLV_ERR_ACK) { 48737c478bd9Sstevel@tonic-gate hmep->hme_slverrack++; 48747c478bd9Sstevel@tonic-gate } 48757c478bd9Sstevel@tonic-gate 48767c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_TX_TAG_ERR) { 48777c478bd9Sstevel@tonic-gate hmep->hme_txtagerr++; 48787c478bd9Sstevel@tonic-gate hmep->hme_oerrors++; 48797c478bd9Sstevel@tonic-gate } 48807c478bd9Sstevel@tonic-gate 48817c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_TX_PAR_ERR) { 48827c478bd9Sstevel@tonic-gate hmep->hme_txparerr++; 48837c478bd9Sstevel@tonic-gate hmep->hme_oerrors++; 48847c478bd9Sstevel@tonic-gate } 48857c478bd9Sstevel@tonic-gate 48867c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_TX_LATE_ERR) { 48877c478bd9Sstevel@tonic-gate hmep->hme_txlaterr++; 48887c478bd9Sstevel@tonic-gate hmep->hme_oerrors++; 48897c478bd9Sstevel@tonic-gate } 48907c478bd9Sstevel@tonic-gate 48917c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_TX_ERR_ACK) { 48927c478bd9Sstevel@tonic-gate hmep->hme_txerrack++; 48937c478bd9Sstevel@tonic-gate hmep->hme_oerrors++; 48947c478bd9Sstevel@tonic-gate } 48957c478bd9Sstevel@tonic-gate 48967c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_EOP_ERR) { 48977c478bd9Sstevel@tonic-gate hmep->hme_eoperr++; 48987c478bd9Sstevel@tonic-gate } 48997c478bd9Sstevel@tonic-gate 49007c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_RX_TAG_ERR) { 49017c478bd9Sstevel@tonic-gate hmep->hme_rxtagerr++; 49027c478bd9Sstevel@tonic-gate hmep->hme_ierrors++; 49037c478bd9Sstevel@tonic-gate } 49047c478bd9Sstevel@tonic-gate 49057c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_RX_PAR_ERR) { 49067c478bd9Sstevel@tonic-gate hmep->hme_rxparerr++; 49077c478bd9Sstevel@tonic-gate hmep->hme_ierrors++; 49087c478bd9Sstevel@tonic-gate } 49097c478bd9Sstevel@tonic-gate 49107c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_RX_LATE_ERR) { 49117c478bd9Sstevel@tonic-gate hmep->hme_rxlaterr++; 49127c478bd9Sstevel@tonic-gate hmep->hme_ierrors++; 49137c478bd9Sstevel@tonic-gate } 49147c478bd9Sstevel@tonic-gate 49157c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_RX_ERR_ACK) { 49167c478bd9Sstevel@tonic-gate hmep->hme_rxerrack++; 49177c478bd9Sstevel@tonic-gate hmep->hme_ierrors++; 49187c478bd9Sstevel@tonic-gate } 49197c478bd9Sstevel@tonic-gate } 49207c478bd9Sstevel@tonic-gate 49217c478bd9Sstevel@tonic-gate /* 49227c478bd9Sstevel@tonic-gate * Handle interrupts regarding non-fatal errors. 49237c478bd9Sstevel@tonic-gate */ 49247c478bd9Sstevel@tonic-gate static void 49257c478bd9Sstevel@tonic-gate hme_nonfatal_err(struct hme *hmep, uint_t hmesbits) 49267c478bd9Sstevel@tonic-gate { 49277c478bd9Sstevel@tonic-gate 49287c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_RX_DROP) { 49297c478bd9Sstevel@tonic-gate hmep->hme_missed++; 49307c478bd9Sstevel@tonic-gate hmep->hme_ierrors++; 49317c478bd9Sstevel@tonic-gate } 49327c478bd9Sstevel@tonic-gate 49337c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_DEFTIMR_EXP) { 49347c478bd9Sstevel@tonic-gate hmep->hme_defer_xmts++; 49357c478bd9Sstevel@tonic-gate } 49367c478bd9Sstevel@tonic-gate 49377c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_FSTCOLC_EXP) { 49387c478bd9Sstevel@tonic-gate hmep->hme_fstcol += 256; 49397c478bd9Sstevel@tonic-gate } 49407c478bd9Sstevel@tonic-gate 49417c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_LATCOLC_EXP) { 49427c478bd9Sstevel@tonic-gate hmep->hme_tlcol += 256; 49437c478bd9Sstevel@tonic-gate hmep->hme_oerrors += 256; 49447c478bd9Sstevel@tonic-gate } 49457c478bd9Sstevel@tonic-gate 49467c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_EXCOLC_EXP) { 494785025c03Sgd hmep->hme_excol += 256; 49487c478bd9Sstevel@tonic-gate hmep->hme_oerrors += 256; 49497c478bd9Sstevel@tonic-gate } 49507c478bd9Sstevel@tonic-gate 49517c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_NRMCOLC_EXP) { 49527c478bd9Sstevel@tonic-gate hmep->hme_coll += 256; 49537c478bd9Sstevel@tonic-gate } 49547c478bd9Sstevel@tonic-gate 49557c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_MXPKTSZ_ERR) { 49567c478bd9Sstevel@tonic-gate hmep->hme_babl++; 49577c478bd9Sstevel@tonic-gate hmep->hme_oerrors++; 49587c478bd9Sstevel@tonic-gate } 49597c478bd9Sstevel@tonic-gate 49607c478bd9Sstevel@tonic-gate /* 49617c478bd9Sstevel@tonic-gate * This error is fatal and the board needs to 49627c478bd9Sstevel@tonic-gate * be reinitialized. Comments? 49637c478bd9Sstevel@tonic-gate */ 49647c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_TXFIFO_UNDR) { 49657c478bd9Sstevel@tonic-gate hmep->hme_uflo++; 49667c478bd9Sstevel@tonic-gate hmep->hme_oerrors++; 49677c478bd9Sstevel@tonic-gate } 49687c478bd9Sstevel@tonic-gate 49697c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_SQE_TST_ERR) { 49707c478bd9Sstevel@tonic-gate hmep->hme_sqe_errors++; 49717c478bd9Sstevel@tonic-gate } 49727c478bd9Sstevel@tonic-gate 49737c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_RCV_CNT_EXP) { 49747c478bd9Sstevel@tonic-gate if (hmep->hme_rxcv_enable) { 49757c478bd9Sstevel@tonic-gate hmep->hme_cvc += 256; 49767c478bd9Sstevel@tonic-gate } 49777c478bd9Sstevel@tonic-gate } 49787c478bd9Sstevel@tonic-gate 49797c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_RXFIFO_OVFL) { 49807c478bd9Sstevel@tonic-gate hmep->hme_oflo++; 49817c478bd9Sstevel@tonic-gate hmep->hme_ierrors++; 49827c478bd9Sstevel@tonic-gate } 49837c478bd9Sstevel@tonic-gate 49847c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_LEN_CNT_EXP) { 49857c478bd9Sstevel@tonic-gate hmep->hme_lenerr += 256; 49867c478bd9Sstevel@tonic-gate hmep->hme_ierrors += 256; 49877c478bd9Sstevel@tonic-gate } 49887c478bd9Sstevel@tonic-gate 49897c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_ALN_CNT_EXP) { 49907c478bd9Sstevel@tonic-gate hmep->hme_align_errors += 256; 49917c478bd9Sstevel@tonic-gate hmep->hme_ierrors += 256; 49927c478bd9Sstevel@tonic-gate } 49937c478bd9Sstevel@tonic-gate 49947c478bd9Sstevel@tonic-gate if (hmesbits & HMEG_STATUS_CRC_CNT_EXP) { 49957c478bd9Sstevel@tonic-gate hmep->hme_fcs_errors += 256; 49967c478bd9Sstevel@tonic-gate hmep->hme_ierrors += 256; 49977c478bd9Sstevel@tonic-gate } 49987c478bd9Sstevel@tonic-gate } 49997c478bd9Sstevel@tonic-gate 500085025c03Sgd static mblk_t * 5001*0219346bSGarrett D'Amore hmeread(struct hme *hmep, hmebuf_t *rbuf, uint32_t rflags) 50027c478bd9Sstevel@tonic-gate { 5003*0219346bSGarrett D'Amore mblk_t *bp; 5004*0219346bSGarrett D'Amore uint32_t len; 5005*0219346bSGarrett D'Amore t_uscalar_t type; 5006*0219346bSGarrett D'Amore 500785025c03Sgd len = (rflags & HMERMD_BUFSIZE) >> HMERMD_BUFSIZE_SHIFT; 50087c478bd9Sstevel@tonic-gate 50097c478bd9Sstevel@tonic-gate /* 50107c478bd9Sstevel@tonic-gate * Check for short packet 50117c478bd9Sstevel@tonic-gate * and check for overflow packet also. The processing is the 50127c478bd9Sstevel@tonic-gate * same for both the cases - reuse the buffer. Update the Buffer 50137c478bd9Sstevel@tonic-gate * overflow counter. 50147c478bd9Sstevel@tonic-gate */ 501585025c03Sgd if ((len < ETHERMIN) || (rflags & HMERMD_OVFLOW) || 501685025c03Sgd (len > (ETHERMAX + 4))) { 50177c478bd9Sstevel@tonic-gate if (len < ETHERMIN) 50187c478bd9Sstevel@tonic-gate hmep->hme_runt++; 50197c478bd9Sstevel@tonic-gate 50207c478bd9Sstevel@tonic-gate else { 50217c478bd9Sstevel@tonic-gate hmep->hme_buff++; 50227c478bd9Sstevel@tonic-gate hmep->hme_toolong_errors++; 50237c478bd9Sstevel@tonic-gate } 50247c478bd9Sstevel@tonic-gate hmep->hme_ierrors++; 502585025c03Sgd return (NULL); 50267c478bd9Sstevel@tonic-gate } 50277c478bd9Sstevel@tonic-gate 50287c478bd9Sstevel@tonic-gate /* 50297c478bd9Sstevel@tonic-gate * Sync the received buffer before looking at it. 50307c478bd9Sstevel@tonic-gate */ 50317c478bd9Sstevel@tonic-gate 5032*0219346bSGarrett D'Amore (void) ddi_dma_sync(rbuf->dmah, 0, 0, DDI_DMA_SYNC_FORKERNEL); 50337c478bd9Sstevel@tonic-gate 50347c478bd9Sstevel@tonic-gate /* 50357c478bd9Sstevel@tonic-gate * copy the packet data and then recycle the descriptor. 50367c478bd9Sstevel@tonic-gate */ 50377c478bd9Sstevel@tonic-gate 5038*0219346bSGarrett D'Amore if ((bp = allocb(len + HME_FSTBYTE_OFFSET, BPRI_HI)) == NULL) { 50397c478bd9Sstevel@tonic-gate 50407c478bd9Sstevel@tonic-gate hmep->hme_allocbfail++; 50417c478bd9Sstevel@tonic-gate hmep->hme_norcvbuf++; 504285025c03Sgd 504385025c03Sgd return (NULL); 50447c478bd9Sstevel@tonic-gate } 50457c478bd9Sstevel@tonic-gate 5046*0219346bSGarrett D'Amore bcopy(rbuf->kaddr, bp->b_rptr, len + HME_FSTBYTE_OFFSET); 50477c478bd9Sstevel@tonic-gate 5048*0219346bSGarrett D'Amore hmep->hme_ipackets++; 50497c478bd9Sstevel@tonic-gate 5050*0219346bSGarrett D'Amore /* Add the First Byte offset to the b_rptr and copy */ 5051*0219346bSGarrett D'Amore bp->b_rptr += HME_FSTBYTE_OFFSET; 5052*0219346bSGarrett D'Amore bp->b_wptr = bp->b_rptr + len; 50537c478bd9Sstevel@tonic-gate 50547c478bd9Sstevel@tonic-gate /* 5055*0219346bSGarrett D'Amore * update MIB II statistics 50567c478bd9Sstevel@tonic-gate */ 5057*0219346bSGarrett D'Amore BUMP_InNUcast(hmep, bp->b_rptr); 5058*0219346bSGarrett D'Amore hmep->hme_rbytes += len; 50597c478bd9Sstevel@tonic-gate 5060*0219346bSGarrett D'Amore type = get_ether_type(bp->b_rptr); 50617c478bd9Sstevel@tonic-gate 50627c478bd9Sstevel@tonic-gate /* 5063*0219346bSGarrett D'Amore * TCP partial checksum in hardware 50647c478bd9Sstevel@tonic-gate */ 5065*0219346bSGarrett D'Amore if (type == ETHERTYPE_IP || type == ETHERTYPE_IPV6) { 5066*0219346bSGarrett D'Amore uint16_t cksum = ~rflags & HMERMD_CKSUM; 5067*0219346bSGarrett D'Amore uint_t end = len - sizeof (struct ether_header); 5068*0219346bSGarrett D'Amore (void) hcksum_assoc(bp, NULL, NULL, 0, 5069*0219346bSGarrett D'Amore 0, end, htons(cksum), HCK_PARTIALCKSUM, 0); 50707c478bd9Sstevel@tonic-gate } 50717c478bd9Sstevel@tonic-gate 507285025c03Sgd return (bp); 50737c478bd9Sstevel@tonic-gate } 50747c478bd9Sstevel@tonic-gate 50757c478bd9Sstevel@tonic-gate /*VARARGS*/ 50767c478bd9Sstevel@tonic-gate static void 5077*0219346bSGarrett D'Amore hme_fault_msg(struct hme *hmep, uint_t severity, msg_t type, char *fmt, ...) 50787c478bd9Sstevel@tonic-gate { 50797c478bd9Sstevel@tonic-gate char msg_buffer[255]; 50807c478bd9Sstevel@tonic-gate va_list ap; 50817c478bd9Sstevel@tonic-gate 50827c478bd9Sstevel@tonic-gate va_start(ap, fmt); 5083228fdff0Sgd (void) vsnprintf(msg_buffer, sizeof (msg_buffer), fmt, ap); 50847c478bd9Sstevel@tonic-gate 508585025c03Sgd if (hmep == NULL) { 50867c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "hme : %s", msg_buffer); 50877c478bd9Sstevel@tonic-gate 508885025c03Sgd } else if (type == DISPLAY_MSG) { 508985025c03Sgd cmn_err(CE_CONT, "?%s%d : %s\n", ddi_driver_name(hmep->dip), 509085025c03Sgd hmep->instance, msg_buffer); 509185025c03Sgd } else if (severity == SEVERITY_HIGH) { 509285025c03Sgd cmn_err(CE_WARN, "%s%d : %s, SEVERITY_HIGH, %s\n", 509385025c03Sgd ddi_driver_name(hmep->dip), hmep->instance, 509485025c03Sgd msg_buffer, msg_string[type]); 509585025c03Sgd } else { 509685025c03Sgd cmn_err(CE_CONT, "%s%d : %s\n", ddi_driver_name(hmep->dip), 509785025c03Sgd hmep->instance, msg_buffer); 509885025c03Sgd } 50997c478bd9Sstevel@tonic-gate va_end(ap); 51007c478bd9Sstevel@tonic-gate } 51017c478bd9Sstevel@tonic-gate 51027c478bd9Sstevel@tonic-gate /* 51037c478bd9Sstevel@tonic-gate * if this is the first init do not bother to save the 51047c478bd9Sstevel@tonic-gate * counters. They should be 0, but do not count on it. 51057c478bd9Sstevel@tonic-gate */ 51067c478bd9Sstevel@tonic-gate static void 51077c478bd9Sstevel@tonic-gate hmesavecntrs(struct hme *hmep) 51087c478bd9Sstevel@tonic-gate { 51097c478bd9Sstevel@tonic-gate uint32_t fecnt, aecnt, lecnt, rxcv; 51107c478bd9Sstevel@tonic-gate uint32_t ltcnt, excnt; 51117c478bd9Sstevel@tonic-gate 51127c478bd9Sstevel@tonic-gate /* XXX What all gets added in ierrors and oerrors? */ 51137c478bd9Sstevel@tonic-gate fecnt = GET_MACREG(fecnt); 51147c478bd9Sstevel@tonic-gate PUT_MACREG(fecnt, 0); 51157c478bd9Sstevel@tonic-gate 51167c478bd9Sstevel@tonic-gate aecnt = GET_MACREG(aecnt); 51177c478bd9Sstevel@tonic-gate hmep->hme_align_errors += aecnt; 51187c478bd9Sstevel@tonic-gate PUT_MACREG(aecnt, 0); 51197c478bd9Sstevel@tonic-gate 51207c478bd9Sstevel@tonic-gate lecnt = GET_MACREG(lecnt); 51217c478bd9Sstevel@tonic-gate hmep->hme_lenerr += lecnt; 51227c478bd9Sstevel@tonic-gate PUT_MACREG(lecnt, 0); 51237c478bd9Sstevel@tonic-gate 51247c478bd9Sstevel@tonic-gate rxcv = GET_MACREG(rxcv); 51257c478bd9Sstevel@tonic-gate #ifdef HME_CODEVIOL_BUG 51267c478bd9Sstevel@tonic-gate /* 51277c478bd9Sstevel@tonic-gate * Ignore rxcv errors for Sbus/FEPS 2.1 or earlier 51287c478bd9Sstevel@tonic-gate */ 51297c478bd9Sstevel@tonic-gate if (!hmep->hme_rxcv_enable) { 51307c478bd9Sstevel@tonic-gate rxcv = 0; 51317c478bd9Sstevel@tonic-gate } 51327c478bd9Sstevel@tonic-gate #endif 51337c478bd9Sstevel@tonic-gate hmep->hme_cvc += rxcv; 51347c478bd9Sstevel@tonic-gate PUT_MACREG(rxcv, 0); 51357c478bd9Sstevel@tonic-gate 51367c478bd9Sstevel@tonic-gate ltcnt = GET_MACREG(ltcnt); 51377c478bd9Sstevel@tonic-gate hmep->hme_tlcol += ltcnt; 51387c478bd9Sstevel@tonic-gate PUT_MACREG(ltcnt, 0); 51397c478bd9Sstevel@tonic-gate 51407c478bd9Sstevel@tonic-gate excnt = GET_MACREG(excnt); 514185025c03Sgd hmep->hme_excol += excnt; 51427c478bd9Sstevel@tonic-gate PUT_MACREG(excnt, 0); 51437c478bd9Sstevel@tonic-gate 51447c478bd9Sstevel@tonic-gate hmep->hme_fcs_errors += fecnt; 51457c478bd9Sstevel@tonic-gate hmep->hme_ierrors += (fecnt + aecnt + lecnt); 51467c478bd9Sstevel@tonic-gate hmep->hme_oerrors += (ltcnt + excnt); 51477c478bd9Sstevel@tonic-gate hmep->hme_coll += (GET_MACREG(nccnt) + ltcnt); 51487c478bd9Sstevel@tonic-gate 51497c478bd9Sstevel@tonic-gate PUT_MACREG(nccnt, 0); 51507c478bd9Sstevel@tonic-gate CHECK_MACREG(); 51517c478bd9Sstevel@tonic-gate } 51527c478bd9Sstevel@tonic-gate 51537c478bd9Sstevel@tonic-gate /* 51547c478bd9Sstevel@tonic-gate * ndd support functions to get/set parameters 51557c478bd9Sstevel@tonic-gate */ 51567c478bd9Sstevel@tonic-gate /* Free the Named Dispatch Table by calling hme_nd_free */ 51577c478bd9Sstevel@tonic-gate static void 51587c478bd9Sstevel@tonic-gate hme_param_cleanup(struct hme *hmep) 51597c478bd9Sstevel@tonic-gate { 51607c478bd9Sstevel@tonic-gate if (hmep->hme_g_nd) 51617c478bd9Sstevel@tonic-gate (void) hme_nd_free(&hmep->hme_g_nd); 51627c478bd9Sstevel@tonic-gate } 51637c478bd9Sstevel@tonic-gate 51647c478bd9Sstevel@tonic-gate /* 51657c478bd9Sstevel@tonic-gate * Extracts the value from the hme parameter array and prints the 51667c478bd9Sstevel@tonic-gate * parameter value. cp points to the required parameter. 51677c478bd9Sstevel@tonic-gate */ 51687c478bd9Sstevel@tonic-gate /* ARGSUSED */ 51697c478bd9Sstevel@tonic-gate static int 51707c478bd9Sstevel@tonic-gate hme_param_get(queue_t *q, mblk_t *mp, caddr_t cp) 51717c478bd9Sstevel@tonic-gate { 5172*0219346bSGarrett D'Amore hmeparam_t *hmepa = (void *)cp; 51737c478bd9Sstevel@tonic-gate 51747c478bd9Sstevel@tonic-gate (void) mi_mpprintf(mp, "%d", hmepa->hme_param_val); 51757c478bd9Sstevel@tonic-gate return (0); 51767c478bd9Sstevel@tonic-gate } 51777c478bd9Sstevel@tonic-gate 51787c478bd9Sstevel@tonic-gate /* 51797c478bd9Sstevel@tonic-gate * Register each element of the parameter array with the 51807c478bd9Sstevel@tonic-gate * named dispatch handler. Each element is loaded using 51817c478bd9Sstevel@tonic-gate * hme_nd_load() 51827c478bd9Sstevel@tonic-gate */ 51837c478bd9Sstevel@tonic-gate /* ARGSUSED */ 51847c478bd9Sstevel@tonic-gate static int 51857c478bd9Sstevel@tonic-gate hme_param_register(struct hme *hmep, hmeparam_t *hmepa, int cnt) 51867c478bd9Sstevel@tonic-gate { 51877c478bd9Sstevel@tonic-gate int i; 51887c478bd9Sstevel@tonic-gate 51897c478bd9Sstevel@tonic-gate /* First 4 elements are read-only */ 51907c478bd9Sstevel@tonic-gate for (i = 0; i < 4; i++, hmepa++) 51917c478bd9Sstevel@tonic-gate if (!hme_nd_load(&hmep->hme_g_nd, hmepa->hme_param_name, 519285025c03Sgd (pfi_t)hme_param_get, (pfi_t)0, (caddr_t)hmepa)) { 51937c478bd9Sstevel@tonic-gate (void) hme_nd_free(&hmep->hme_g_nd); 51947c478bd9Sstevel@tonic-gate return (B_FALSE); 51957c478bd9Sstevel@tonic-gate } 51967c478bd9Sstevel@tonic-gate /* Next 10 elements are read and write */ 51977c478bd9Sstevel@tonic-gate for (i = 0; i < 10; i++, hmepa++) 51987c478bd9Sstevel@tonic-gate if (hmepa->hme_param_name && hmepa->hme_param_name[0]) { 51997c478bd9Sstevel@tonic-gate if (!hme_nd_load(&hmep->hme_g_nd, 520085025c03Sgd hmepa->hme_param_name, (pfi_t)hme_param_get, 520185025c03Sgd (pfi_t)hme_param_set, (caddr_t)hmepa)) { 52027c478bd9Sstevel@tonic-gate (void) hme_nd_free(&hmep->hme_g_nd); 52037c478bd9Sstevel@tonic-gate return (B_FALSE); 52047c478bd9Sstevel@tonic-gate 52057c478bd9Sstevel@tonic-gate } 52067c478bd9Sstevel@tonic-gate } 52077c478bd9Sstevel@tonic-gate /* next 12 elements are read-only */ 52087c478bd9Sstevel@tonic-gate for (i = 0; i < 12; i++, hmepa++) 52097c478bd9Sstevel@tonic-gate if (!hme_nd_load(&hmep->hme_g_nd, hmepa->hme_param_name, 521085025c03Sgd (pfi_t)hme_param_get, (pfi_t)0, (caddr_t)hmepa)) { 52117c478bd9Sstevel@tonic-gate (void) hme_nd_free(&hmep->hme_g_nd); 52127c478bd9Sstevel@tonic-gate return (B_FALSE); 52137c478bd9Sstevel@tonic-gate } 52147c478bd9Sstevel@tonic-gate /* Next 3 elements are read and write */ 52157c478bd9Sstevel@tonic-gate for (i = 0; i < 3; i++, hmepa++) 52167c478bd9Sstevel@tonic-gate if (hmepa->hme_param_name && hmepa->hme_param_name[0]) { 52177c478bd9Sstevel@tonic-gate if (!hme_nd_load(&hmep->hme_g_nd, 521885025c03Sgd hmepa->hme_param_name, (pfi_t)hme_param_get, 521985025c03Sgd (pfi_t)hme_param_set, (caddr_t)hmepa)) { 52207c478bd9Sstevel@tonic-gate (void) hme_nd_free(&hmep->hme_g_nd); 52217c478bd9Sstevel@tonic-gate return (B_FALSE); 52227c478bd9Sstevel@tonic-gate } 52237c478bd9Sstevel@tonic-gate } 52247c478bd9Sstevel@tonic-gate 52257c478bd9Sstevel@tonic-gate return (B_TRUE); 52267c478bd9Sstevel@tonic-gate } 52277c478bd9Sstevel@tonic-gate 52287c478bd9Sstevel@tonic-gate /* 52297c478bd9Sstevel@tonic-gate * Sets the hme parameter to the value in the hme_param_register using 52307c478bd9Sstevel@tonic-gate * hme_nd_load(). 52317c478bd9Sstevel@tonic-gate */ 52327c478bd9Sstevel@tonic-gate /* ARGSUSED */ 52337c478bd9Sstevel@tonic-gate static int 52347c478bd9Sstevel@tonic-gate hme_param_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp) 52357c478bd9Sstevel@tonic-gate { 52367c478bd9Sstevel@tonic-gate char *end; 52377c478bd9Sstevel@tonic-gate size_t new_value; 5238*0219346bSGarrett D'Amore hmeparam_t *hmepa = (void *)cp; 52397c478bd9Sstevel@tonic-gate 52407c478bd9Sstevel@tonic-gate new_value = mi_strtol(value, &end, 10); 52417c478bd9Sstevel@tonic-gate if (end == value || new_value < hmepa->hme_param_min || 524285025c03Sgd new_value > hmepa->hme_param_max) { 52437c478bd9Sstevel@tonic-gate return (EINVAL); 52447c478bd9Sstevel@tonic-gate } 5245*0219346bSGarrett D'Amore hmepa->hme_param_val = (uint32_t)new_value; 52467c478bd9Sstevel@tonic-gate return (0); 52477c478bd9Sstevel@tonic-gate 52487c478bd9Sstevel@tonic-gate } 52497c478bd9Sstevel@tonic-gate 52507c478bd9Sstevel@tonic-gate /* Free the table pointed to by 'ndp' */ 52517c478bd9Sstevel@tonic-gate static void 52527c478bd9Sstevel@tonic-gate hme_nd_free(caddr_t *nd_pparam) 52537c478bd9Sstevel@tonic-gate { 52547c478bd9Sstevel@tonic-gate ND *nd; 52557c478bd9Sstevel@tonic-gate 5256*0219346bSGarrett D'Amore if ((nd = (void *)(*nd_pparam)) != NULL) { 52577c478bd9Sstevel@tonic-gate if (nd->nd_tbl) 52587c478bd9Sstevel@tonic-gate mi_free((char *)nd->nd_tbl); 52597c478bd9Sstevel@tonic-gate mi_free((char *)nd); 52607c478bd9Sstevel@tonic-gate *nd_pparam = NULL; 52617c478bd9Sstevel@tonic-gate } 52627c478bd9Sstevel@tonic-gate } 52637c478bd9Sstevel@tonic-gate 52647c478bd9Sstevel@tonic-gate static int 52657c478bd9Sstevel@tonic-gate hme_nd_getset(queue_t *q, caddr_t nd_param, MBLKP mp) 52667c478bd9Sstevel@tonic-gate { 52677c478bd9Sstevel@tonic-gate int err; 52687c478bd9Sstevel@tonic-gate IOCP iocp; 52697c478bd9Sstevel@tonic-gate MBLKP mp1; 52707c478bd9Sstevel@tonic-gate ND *nd; 52717c478bd9Sstevel@tonic-gate NDE *nde; 52727c478bd9Sstevel@tonic-gate char *valp; 52737c478bd9Sstevel@tonic-gate size_t avail; 52747c478bd9Sstevel@tonic-gate 52757c478bd9Sstevel@tonic-gate if (!nd_param) 52767c478bd9Sstevel@tonic-gate return (B_FALSE); 52777c478bd9Sstevel@tonic-gate 5278*0219346bSGarrett D'Amore nd = (void *)nd_param; 5279*0219346bSGarrett D'Amore iocp = (void *)mp->b_rptr; 52807c478bd9Sstevel@tonic-gate if ((iocp->ioc_count == 0) || !(mp1 = mp->b_cont)) { 52817c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 52827c478bd9Sstevel@tonic-gate iocp->ioc_count = 0; 52837c478bd9Sstevel@tonic-gate iocp->ioc_error = EINVAL; 52847c478bd9Sstevel@tonic-gate return (B_TRUE); 52857c478bd9Sstevel@tonic-gate } 52867c478bd9Sstevel@tonic-gate 52877c478bd9Sstevel@tonic-gate /* 52887c478bd9Sstevel@tonic-gate * NOTE - logic throughout nd_xxx assumes single data block for ioctl. 52897c478bd9Sstevel@tonic-gate * However, existing code sends in some big buffers. 52907c478bd9Sstevel@tonic-gate */ 52917c478bd9Sstevel@tonic-gate avail = iocp->ioc_count; 52927c478bd9Sstevel@tonic-gate if (mp1->b_cont) { 52937c478bd9Sstevel@tonic-gate freemsg(mp1->b_cont); 52947c478bd9Sstevel@tonic-gate mp1->b_cont = NULL; 52957c478bd9Sstevel@tonic-gate } 52967c478bd9Sstevel@tonic-gate 52977c478bd9Sstevel@tonic-gate mp1->b_datap->db_lim[-1] = '\0'; /* Force null termination */ 52987c478bd9Sstevel@tonic-gate valp = (char *)mp1->b_rptr; 52997c478bd9Sstevel@tonic-gate for (nde = nd->nd_tbl; /* */; nde++) { 53007c478bd9Sstevel@tonic-gate if (!nde->nde_name) 53017c478bd9Sstevel@tonic-gate return (B_FALSE); 53027c478bd9Sstevel@tonic-gate if (mi_strcmp(nde->nde_name, valp) == 0) 53037c478bd9Sstevel@tonic-gate break; 53047c478bd9Sstevel@tonic-gate } 53057c478bd9Sstevel@tonic-gate 53067c478bd9Sstevel@tonic-gate err = EINVAL; 53077c478bd9Sstevel@tonic-gate while (*valp++) 53087c478bd9Sstevel@tonic-gate ; 53097c478bd9Sstevel@tonic-gate if (!*valp || valp >= (char *)mp1->b_wptr) 53107c478bd9Sstevel@tonic-gate valp = NULL; 53117c478bd9Sstevel@tonic-gate switch (iocp->ioc_cmd) { 53127c478bd9Sstevel@tonic-gate case ND_GET: 53137c478bd9Sstevel@tonic-gate /* 53147c478bd9Sstevel@tonic-gate * (temporary) hack: "*valp" is size of user buffer for copyout. If result 53157c478bd9Sstevel@tonic-gate * of action routine is too big, free excess and return ioc_rval as buffer 53167c478bd9Sstevel@tonic-gate * size needed. Return as many mblocks as will fit, free the rest. For 53177c478bd9Sstevel@tonic-gate * backward compatibility, assume size of original ioctl buffer if "*valp" 53187c478bd9Sstevel@tonic-gate * bad or not given. 53197c478bd9Sstevel@tonic-gate */ 53207c478bd9Sstevel@tonic-gate if (valp) 53217c478bd9Sstevel@tonic-gate avail = mi_strtol(valp, (char **)0, 10); 53227c478bd9Sstevel@tonic-gate /* We overwrite the name/value with the reply data */ 53237c478bd9Sstevel@tonic-gate { 53247c478bd9Sstevel@tonic-gate mblk_t *mp2 = mp1; 53257c478bd9Sstevel@tonic-gate 53267c478bd9Sstevel@tonic-gate while (mp2) { 53277c478bd9Sstevel@tonic-gate mp2->b_wptr = mp2->b_rptr; 53287c478bd9Sstevel@tonic-gate mp2 = mp2->b_cont; 53297c478bd9Sstevel@tonic-gate } 53307c478bd9Sstevel@tonic-gate } 53317c478bd9Sstevel@tonic-gate err = (*nde->nde_get_pfi)(q, mp1, nde->nde_data, iocp->ioc_cr); 53327c478bd9Sstevel@tonic-gate if (!err) { 53337c478bd9Sstevel@tonic-gate size_t size_out; 53347c478bd9Sstevel@tonic-gate ssize_t excess; 53357c478bd9Sstevel@tonic-gate 53367c478bd9Sstevel@tonic-gate iocp->ioc_rval = 0; 53377c478bd9Sstevel@tonic-gate 53387c478bd9Sstevel@tonic-gate /* Tack on the null */ 53397c478bd9Sstevel@tonic-gate (void) mi_mpprintf_putc((char *)mp1, '\0'); 53407c478bd9Sstevel@tonic-gate size_out = msgdsize(mp1); 53417c478bd9Sstevel@tonic-gate excess = size_out - avail; 53427c478bd9Sstevel@tonic-gate if (excess > 0) { 53437c478bd9Sstevel@tonic-gate iocp->ioc_rval = (int)size_out; 53447c478bd9Sstevel@tonic-gate size_out -= excess; 53457c478bd9Sstevel@tonic-gate (void) adjmsg(mp1, -(excess + 1)); 53467c478bd9Sstevel@tonic-gate (void) mi_mpprintf_putc((char *)mp1, '\0'); 53477c478bd9Sstevel@tonic-gate } 53487c478bd9Sstevel@tonic-gate iocp->ioc_count = size_out; 53497c478bd9Sstevel@tonic-gate } 53507c478bd9Sstevel@tonic-gate break; 53517c478bd9Sstevel@tonic-gate 53527c478bd9Sstevel@tonic-gate case ND_SET: 53537c478bd9Sstevel@tonic-gate if (valp) { 53547c478bd9Sstevel@tonic-gate if ((iocp->ioc_cr != NULL) && 53557c478bd9Sstevel@tonic-gate ((err = secpolicy_net_config(iocp->ioc_cr, B_FALSE)) 53567c478bd9Sstevel@tonic-gate == 0)) { 53577c478bd9Sstevel@tonic-gate err = (*nde->nde_set_pfi)(q, mp1, valp, 53587c478bd9Sstevel@tonic-gate nde->nde_data, iocp->ioc_cr); 53597c478bd9Sstevel@tonic-gate } 53607c478bd9Sstevel@tonic-gate iocp->ioc_count = 0; 53617c478bd9Sstevel@tonic-gate freemsg(mp1); 53627c478bd9Sstevel@tonic-gate mp->b_cont = NULL; 53637c478bd9Sstevel@tonic-gate } 53647c478bd9Sstevel@tonic-gate break; 53657c478bd9Sstevel@tonic-gate 53667c478bd9Sstevel@tonic-gate default: 53677c478bd9Sstevel@tonic-gate break; 53687c478bd9Sstevel@tonic-gate } 53697c478bd9Sstevel@tonic-gate 53707c478bd9Sstevel@tonic-gate iocp->ioc_error = err; 53717c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 53727c478bd9Sstevel@tonic-gate return (B_TRUE); 53737c478bd9Sstevel@tonic-gate } 53747c478bd9Sstevel@tonic-gate 53757c478bd9Sstevel@tonic-gate /* 53767c478bd9Sstevel@tonic-gate * Load 'name' into the named dispatch table pointed to by 'ndp'. 53777c478bd9Sstevel@tonic-gate * 'ndp' should be the address of a char pointer cell. If the table 53787c478bd9Sstevel@tonic-gate * does not exist (*ndp == 0), a new table is allocated and 'ndp' 53797c478bd9Sstevel@tonic-gate * is stuffed. If there is not enough space in the table for a new 53807c478bd9Sstevel@tonic-gate * entry, more space is allocated. 53817c478bd9Sstevel@tonic-gate */ 53827c478bd9Sstevel@tonic-gate static boolean_t 53837c478bd9Sstevel@tonic-gate hme_nd_load(caddr_t *nd_pparam, char *name, pfi_t get_pfi, 53847c478bd9Sstevel@tonic-gate pfi_t set_pfi, caddr_t data) 53857c478bd9Sstevel@tonic-gate { 53867c478bd9Sstevel@tonic-gate ND *nd; 53877c478bd9Sstevel@tonic-gate NDE *nde; 53887c478bd9Sstevel@tonic-gate 53897c478bd9Sstevel@tonic-gate if (!nd_pparam) 53907c478bd9Sstevel@tonic-gate return (B_FALSE); 53917c478bd9Sstevel@tonic-gate 5392*0219346bSGarrett D'Amore if ((nd = (void *)(*nd_pparam)) == NULL) { 5393*0219346bSGarrett D'Amore if ((nd = (void *)mi_alloc(sizeof (ND), BPRI_MED)) == NULL) 53947c478bd9Sstevel@tonic-gate return (B_FALSE); 53957c478bd9Sstevel@tonic-gate bzero(nd, sizeof (ND)); 53967c478bd9Sstevel@tonic-gate *nd_pparam = (caddr_t)nd; 53977c478bd9Sstevel@tonic-gate } 53987c478bd9Sstevel@tonic-gate 53997c478bd9Sstevel@tonic-gate if (nd->nd_tbl) { 54007c478bd9Sstevel@tonic-gate for (nde = nd->nd_tbl; nde->nde_name; nde++) { 54017c478bd9Sstevel@tonic-gate if (mi_strcmp(name, nde->nde_name) == 0) 54027c478bd9Sstevel@tonic-gate goto fill_it; 54037c478bd9Sstevel@tonic-gate } 54047c478bd9Sstevel@tonic-gate } 54057c478bd9Sstevel@tonic-gate 54067c478bd9Sstevel@tonic-gate if (nd->nd_free_count <= 1) { 54077c478bd9Sstevel@tonic-gate if ((nde = (NDE *)mi_alloc(nd->nd_size + 54087c478bd9Sstevel@tonic-gate NDE_ALLOC_SIZE, BPRI_MED)) == NULL) 54097c478bd9Sstevel@tonic-gate return (B_FALSE); 54107c478bd9Sstevel@tonic-gate bzero(nde, nd->nd_size + NDE_ALLOC_SIZE); 54117c478bd9Sstevel@tonic-gate nd->nd_free_count += NDE_ALLOC_COUNT; 54127c478bd9Sstevel@tonic-gate if (nd->nd_tbl) { 54137c478bd9Sstevel@tonic-gate bcopy(nd->nd_tbl, nde, nd->nd_size); 54147c478bd9Sstevel@tonic-gate mi_free((char *)nd->nd_tbl); 54157c478bd9Sstevel@tonic-gate } else { 54167c478bd9Sstevel@tonic-gate nd->nd_free_count--; 54177c478bd9Sstevel@tonic-gate nde->nde_name = "?"; 54187c478bd9Sstevel@tonic-gate nde->nde_get_pfi = nd_get_names; 54197c478bd9Sstevel@tonic-gate nde->nde_set_pfi = nd_set_default; 54207c478bd9Sstevel@tonic-gate } 54217c478bd9Sstevel@tonic-gate nde->nde_data = (caddr_t)nd; 54227c478bd9Sstevel@tonic-gate nd->nd_tbl = nde; 54237c478bd9Sstevel@tonic-gate nd->nd_size += NDE_ALLOC_SIZE; 54247c478bd9Sstevel@tonic-gate } 54257c478bd9Sstevel@tonic-gate 54267c478bd9Sstevel@tonic-gate for (nde = nd->nd_tbl; nde->nde_name; nde++) 54277c478bd9Sstevel@tonic-gate ; 54287c478bd9Sstevel@tonic-gate nd->nd_free_count--; 54297c478bd9Sstevel@tonic-gate fill_it: 54307c478bd9Sstevel@tonic-gate nde->nde_name = name; 54317c478bd9Sstevel@tonic-gate nde->nde_get_pfi = get_pfi ? get_pfi : nd_get_default; 54327c478bd9Sstevel@tonic-gate nde->nde_set_pfi = set_pfi ? set_pfi : nd_set_default; 54337c478bd9Sstevel@tonic-gate nde->nde_data = data; 54347c478bd9Sstevel@tonic-gate return (B_TRUE); 54357c478bd9Sstevel@tonic-gate } 54367c478bd9Sstevel@tonic-gate 54377c478bd9Sstevel@tonic-gate /* 54387c478bd9Sstevel@tonic-gate * To set up the mac address for the network interface: 54397c478bd9Sstevel@tonic-gate * The adapter card may support a local mac address which is published 54407c478bd9Sstevel@tonic-gate * in a device node property "local-mac-address". This mac address is 54417c478bd9Sstevel@tonic-gate * treated as the factory-installed mac address for DLPI interface. 54427c478bd9Sstevel@tonic-gate * If the adapter firmware has used the device for diskless boot 54437c478bd9Sstevel@tonic-gate * operation it publishes a property called "mac-address" for use by 54447c478bd9Sstevel@tonic-gate * inetboot and the device driver. 54457c478bd9Sstevel@tonic-gate * If "mac-address" is not found, the system options property 54467c478bd9Sstevel@tonic-gate * "local-mac-address" is used to select the mac-address. If this option 54477c478bd9Sstevel@tonic-gate * is set to "true", and "local-mac-address" has been found, then 54487c478bd9Sstevel@tonic-gate * local-mac-address is used; otherwise the system mac address is used 54497c478bd9Sstevel@tonic-gate * by calling the "localetheraddr()" function. 54507c478bd9Sstevel@tonic-gate */ 54517c478bd9Sstevel@tonic-gate static void 54527c478bd9Sstevel@tonic-gate hme_setup_mac_address(struct hme *hmep, dev_info_t *dip) 54537c478bd9Sstevel@tonic-gate { 54547c478bd9Sstevel@tonic-gate char *prop; 54557c478bd9Sstevel@tonic-gate int prop_len = sizeof (int); 54567c478bd9Sstevel@tonic-gate 54577c478bd9Sstevel@tonic-gate hmep->hme_addrflags = 0; 54587c478bd9Sstevel@tonic-gate 54597c478bd9Sstevel@tonic-gate /* 54607c478bd9Sstevel@tonic-gate * Check if it is an adapter with its own local mac address 54617c478bd9Sstevel@tonic-gate * If it is present, save it as the "factory-address" 54627c478bd9Sstevel@tonic-gate * for this adapter. 54637c478bd9Sstevel@tonic-gate */ 546485025c03Sgd if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 546585025c03Sgd "local-mac-address", 546685025c03Sgd (caddr_t)&prop, &prop_len) == DDI_PROP_SUCCESS) { 54677c478bd9Sstevel@tonic-gate if (prop_len == ETHERADDRL) { 54687c478bd9Sstevel@tonic-gate hmep->hme_addrflags = HME_FACTADDR_PRESENT; 54697c478bd9Sstevel@tonic-gate ether_bcopy(prop, &hmep->hme_factaddr); 54707c478bd9Sstevel@tonic-gate HME_FAULT_MSG2(hmep, SEVERITY_NONE, DISPLAY_MSG, 5471*0219346bSGarrett D'Amore "Local Ethernet address = %s", 547285025c03Sgd ether_sprintf(&hmep->hme_factaddr)); 54737c478bd9Sstevel@tonic-gate } 54747c478bd9Sstevel@tonic-gate kmem_free(prop, prop_len); 54757c478bd9Sstevel@tonic-gate } 54767c478bd9Sstevel@tonic-gate 54777c478bd9Sstevel@tonic-gate /* 54787c478bd9Sstevel@tonic-gate * Check if the adapter has published "mac-address" property. 54797c478bd9Sstevel@tonic-gate * If it is present, use it as the mac address for this device. 54807c478bd9Sstevel@tonic-gate */ 548185025c03Sgd if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 548285025c03Sgd "mac-address", (caddr_t)&prop, &prop_len) == DDI_PROP_SUCCESS) { 54837c478bd9Sstevel@tonic-gate if (prop_len >= ETHERADDRL) { 54847c478bd9Sstevel@tonic-gate ether_bcopy(prop, &hmep->hme_ouraddr); 54857c478bd9Sstevel@tonic-gate kmem_free(prop, prop_len); 54867c478bd9Sstevel@tonic-gate return; 54877c478bd9Sstevel@tonic-gate } 54887c478bd9Sstevel@tonic-gate kmem_free(prop, prop_len); 54897c478bd9Sstevel@tonic-gate } 54907c478bd9Sstevel@tonic-gate 5491*0219346bSGarrett D'Amore #ifdef __sparc 5492*0219346bSGarrett D'Amore /* 5493*0219346bSGarrett D'Amore * On sparc, we might be able to use the mac address from the 5494*0219346bSGarrett D'Amore * system. However, on all other systems, we need to use the 5495*0219346bSGarrett D'Amore * address from the PROM. 5496*0219346bSGarrett D'Amore */ 54977c478bd9Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 0, "local-mac-address?", 549885025c03Sgd (caddr_t)&prop, &prop_len) == DDI_PROP_SUCCESS) { 54997c478bd9Sstevel@tonic-gate if ((strncmp("true", prop, prop_len) == 0) && 550085025c03Sgd (hmep->hme_addrflags & HME_FACTADDR_PRESENT)) { 55017c478bd9Sstevel@tonic-gate hmep->hme_addrflags |= HME_FACTADDR_USE; 55027c478bd9Sstevel@tonic-gate ether_bcopy(&hmep->hme_factaddr, &hmep->hme_ouraddr); 55037c478bd9Sstevel@tonic-gate kmem_free(prop, prop_len); 55047c478bd9Sstevel@tonic-gate HME_FAULT_MSG1(hmep, SEVERITY_NONE, DISPLAY_MSG, 5505*0219346bSGarrett D'Amore "Using local MAC address"); 55067c478bd9Sstevel@tonic-gate return; 55077c478bd9Sstevel@tonic-gate } 55087c478bd9Sstevel@tonic-gate kmem_free(prop, prop_len); 55097c478bd9Sstevel@tonic-gate } 55107c478bd9Sstevel@tonic-gate 55117c478bd9Sstevel@tonic-gate /* 55127c478bd9Sstevel@tonic-gate * Get the system ethernet address. 55137c478bd9Sstevel@tonic-gate */ 55147c478bd9Sstevel@tonic-gate (void) localetheraddr((struct ether_addr *)NULL, &hmep->hme_ouraddr); 5515*0219346bSGarrett D'Amore #else 5516*0219346bSGarrett D'Amore ether_bcopy(&hmep->hme_factaddr, &hmep->hme_ouraddr); 5517*0219346bSGarrett D'Amore #endif 55187c478bd9Sstevel@tonic-gate } 55197c478bd9Sstevel@tonic-gate 55207c478bd9Sstevel@tonic-gate /* ARGSUSED */ 55217c478bd9Sstevel@tonic-gate static void 55227c478bd9Sstevel@tonic-gate hme_check_acc_handle(char *file, uint_t line, struct hme *hmep, 55237c478bd9Sstevel@tonic-gate ddi_acc_handle_t handle) 55247c478bd9Sstevel@tonic-gate { 55257c478bd9Sstevel@tonic-gate } 5526