15748Sduboff /* 25748Sduboff * sfe.c : DP83815/DP83816/SiS900 Fast Ethernet MAC driver for Solaris 35748Sduboff * 47116Sduboff * Copyright (c) 2002-2008 Masayuki Murayama. All rights reserved. 55748Sduboff * 65748Sduboff * Redistribution and use in source and binary forms, with or without 75748Sduboff * modification, are permitted provided that the following conditions are met: 85748Sduboff * 95748Sduboff * 1. Redistributions of source code must retain the above copyright notice, 105748Sduboff * this list of conditions and the following disclaimer. 115748Sduboff * 125748Sduboff * 2. Redistributions in binary form must reproduce the above copyright notice, 135748Sduboff * this list of conditions and the following disclaimer in the documentation 145748Sduboff * and/or other materials provided with the distribution. 155748Sduboff * 165748Sduboff * 3. Neither the name of the author nor the names of its contributors may be 175748Sduboff * used to endorse or promote products derived from this software without 185748Sduboff * specific prior written permission. 195748Sduboff * 205748Sduboff * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 215748Sduboff * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 225748Sduboff * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 235748Sduboff * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 245748Sduboff * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 255748Sduboff * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 265748Sduboff * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 275748Sduboff * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 285748Sduboff * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 295748Sduboff * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 305748Sduboff * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 315748Sduboff * DAMAGE. 325748Sduboff */ 335748Sduboff 34*7656SSherry.Moore@Sun.COM /* 35*7656SSherry.Moore@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 36*7656SSherry.Moore@Sun.COM * Use is subject to license terms. 37*7656SSherry.Moore@Sun.COM */ 385748Sduboff 395748Sduboff /* 405748Sduboff * System Header files. 415748Sduboff */ 425748Sduboff #include <sys/types.h> 435748Sduboff #include <sys/conf.h> 445748Sduboff #include <sys/debug.h> 455748Sduboff #include <sys/kmem.h> 465748Sduboff #include <sys/modctl.h> 475748Sduboff #include <sys/errno.h> 485748Sduboff #include <sys/ddi.h> 495748Sduboff #include <sys/sunddi.h> 505748Sduboff #include <sys/byteorder.h> 515748Sduboff #include <sys/ethernet.h> 525748Sduboff #include <sys/pci.h> 535748Sduboff 545748Sduboff #include "sfe_mii.h" 555748Sduboff #include "sfe_util.h" 565748Sduboff #include "sfereg.h" 575748Sduboff 58*7656SSherry.Moore@Sun.COM char ident[] = "sis900/dp83815 driver"; 595748Sduboff 605748Sduboff /* Debugging support */ 615748Sduboff #ifdef DEBUG_LEVEL 625748Sduboff static int sfe_debug = DEBUG_LEVEL; 635748Sduboff #if DEBUG_LEVEL > 4 645748Sduboff #define CONS "^" 655748Sduboff #else 665748Sduboff #define CONS "!" 675748Sduboff #endif 685748Sduboff #define DPRINTF(n, args) if (sfe_debug > (n)) cmn_err args 695748Sduboff #else 705748Sduboff #define CONS "!" 715748Sduboff #define DPRINTF(n, args) 725748Sduboff #endif 735748Sduboff 745748Sduboff /* 755748Sduboff * Useful macros and typedefs 765748Sduboff */ 775748Sduboff #define ONESEC (drv_usectohz(1*1000000)) 785748Sduboff #define ROUNDUP2(x, a) (((x) + (a) - 1) & ~((a) - 1)) 795748Sduboff 805748Sduboff /* 815748Sduboff * Our configuration 825748Sduboff */ 835748Sduboff #define MAXTXFRAGS 1 845748Sduboff #define MAXRXFRAGS 1 855748Sduboff 865748Sduboff #ifndef TX_BUF_SIZE 875748Sduboff #define TX_BUF_SIZE 64 885748Sduboff #endif 895748Sduboff #ifndef TX_RING_SIZE 905748Sduboff #if MAXTXFRAGS == 1 915748Sduboff #define TX_RING_SIZE TX_BUF_SIZE 925748Sduboff #else 935748Sduboff #define TX_RING_SIZE (TX_BUF_SIZE * 4) 945748Sduboff #endif 955748Sduboff #endif 965748Sduboff 975748Sduboff #ifndef RX_BUF_SIZE 985748Sduboff #define RX_BUF_SIZE 256 995748Sduboff #endif 1005748Sduboff #ifndef RX_RING_SIZE 1015748Sduboff #define RX_RING_SIZE RX_BUF_SIZE 1025748Sduboff #endif 1035748Sduboff 1045748Sduboff #define OUR_INTR_BITS \ 1055748Sduboff (ISR_DPERR | ISR_SSERR | ISR_RMABT | ISR_RTABT | ISR_RXSOVR | \ 1065748Sduboff ISR_TXURN | ISR_TXDESC | ISR_TXERR | \ 1075748Sduboff ISR_RXORN | ISR_RXIDLE | ISR_RXOK | ISR_RXERR) 1085748Sduboff 1095748Sduboff #define USE_MULTICAST_HASHTBL 1105748Sduboff 1115748Sduboff static int sfe_tx_copy_thresh = 256; 1125748Sduboff static int sfe_rx_copy_thresh = 256; 1135748Sduboff 1145748Sduboff /* special PHY registers for SIS900 */ 1155748Sduboff #define MII_CONFIG1 0x0010 1165748Sduboff #define MII_CONFIG2 0x0011 1175748Sduboff #define MII_MASK 0x0013 1185748Sduboff #define MII_RESV 0x0014 1195748Sduboff 1205748Sduboff #define PHY_MASK 0xfffffff0 1215748Sduboff #define PHY_SIS900_INTERNAL 0x001d8000 1225748Sduboff #define PHY_ICS1893 0x0015f440 1235748Sduboff 1245748Sduboff 1255748Sduboff #define SFE_DESC_SIZE 16 /* including pads rounding up to power of 2 */ 1265748Sduboff 1275748Sduboff /* 1285748Sduboff * Supported chips 1295748Sduboff */ 1305748Sduboff struct chip_info { 1315748Sduboff uint16_t venid; 1325748Sduboff uint16_t devid; 1335748Sduboff char *chip_name; 1345748Sduboff int chip_type; 1355748Sduboff #define CHIPTYPE_DP83815 0 1365748Sduboff #define CHIPTYPE_SIS900 1 1375748Sduboff }; 1385748Sduboff 1395748Sduboff /* 1405748Sduboff * Chip dependent MAC state 1415748Sduboff */ 1425748Sduboff struct sfe_dev { 1435748Sduboff /* misc HW information */ 1445748Sduboff struct chip_info *chip; 1455748Sduboff uint32_t our_intr_bits; 1467116Sduboff uint32_t isr_pended; 1475748Sduboff uint32_t cr; 1485748Sduboff uint_t tx_drain_threshold; 1495748Sduboff uint_t tx_fill_threshold; 1505748Sduboff uint_t rx_drain_threshold; 1515748Sduboff uint_t rx_fill_threshold; 1525748Sduboff uint8_t revid; /* revision from PCI configuration */ 1535748Sduboff boolean_t (*get_mac_addr)(struct gem_dev *); 1545748Sduboff uint8_t mac_addr[ETHERADDRL]; 1555748Sduboff uint8_t bridge_revid; 1565748Sduboff }; 1575748Sduboff 1585748Sduboff /* 1595748Sduboff * Hardware information 1605748Sduboff */ 1615748Sduboff struct chip_info sfe_chiptbl[] = { 1625748Sduboff { 0x1039, 0x0900, "SiS900", CHIPTYPE_SIS900, }, 1635748Sduboff { 0x100b, 0x0020, "DP83815/83816", CHIPTYPE_DP83815, }, 1645748Sduboff { 0x1039, 0x7016, "SiS7016", CHIPTYPE_SIS900, }, 1655748Sduboff }; 1665748Sduboff #define CHIPTABLESIZE (sizeof (sfe_chiptbl)/sizeof (struct chip_info)) 1675748Sduboff 1685748Sduboff /* ======================================================== */ 1695748Sduboff 1705748Sduboff /* mii operations */ 1715748Sduboff static void sfe_mii_sync_dp83815(struct gem_dev *); 1725748Sduboff static void sfe_mii_sync_sis900(struct gem_dev *); 1735748Sduboff static uint16_t sfe_mii_read_dp83815(struct gem_dev *, uint_t); 1745748Sduboff static uint16_t sfe_mii_read_sis900(struct gem_dev *, uint_t); 1755748Sduboff static void sfe_mii_write_dp83815(struct gem_dev *, uint_t, uint16_t); 1765748Sduboff static void sfe_mii_write_sis900(struct gem_dev *, uint_t, uint16_t); 1775748Sduboff static void sfe_set_eq_sis630(struct gem_dev *dp); 1785748Sduboff /* nic operations */ 1795748Sduboff static int sfe_reset_chip_sis900(struct gem_dev *); 1805748Sduboff static int sfe_reset_chip_dp83815(struct gem_dev *); 1815748Sduboff static int sfe_init_chip(struct gem_dev *); 1825748Sduboff static int sfe_start_chip(struct gem_dev *); 1835748Sduboff static int sfe_stop_chip(struct gem_dev *); 1845748Sduboff static int sfe_set_media(struct gem_dev *); 1855748Sduboff static int sfe_set_rx_filter_dp83815(struct gem_dev *); 1865748Sduboff static int sfe_set_rx_filter_sis900(struct gem_dev *); 1875748Sduboff static int sfe_get_stats(struct gem_dev *); 1885748Sduboff static int sfe_attach_chip(struct gem_dev *); 1895748Sduboff 1905748Sduboff /* descriptor operations */ 1915748Sduboff static int sfe_tx_desc_write(struct gem_dev *dp, int slot, 1925748Sduboff ddi_dma_cookie_t *dmacookie, int frags, uint64_t flags); 1935748Sduboff static void sfe_tx_start(struct gem_dev *dp, int startslot, int nslot); 1945748Sduboff static void sfe_rx_desc_write(struct gem_dev *dp, int slot, 1955748Sduboff ddi_dma_cookie_t *dmacookie, int frags); 1965748Sduboff static uint_t sfe_tx_desc_stat(struct gem_dev *dp, int slot, int ndesc); 1975748Sduboff static uint64_t sfe_rx_desc_stat(struct gem_dev *dp, int slot, int ndesc); 1985748Sduboff 1995748Sduboff static void sfe_tx_desc_init(struct gem_dev *dp, int slot); 2005748Sduboff static void sfe_rx_desc_init(struct gem_dev *dp, int slot); 2015748Sduboff static void sfe_tx_desc_clean(struct gem_dev *dp, int slot); 2025748Sduboff static void sfe_rx_desc_clean(struct gem_dev *dp, int slot); 2035748Sduboff 2045748Sduboff /* interrupt handler */ 2055748Sduboff static uint_t sfe_interrupt(struct gem_dev *dp); 2065748Sduboff 2075748Sduboff /* ======================================================== */ 2085748Sduboff 2095748Sduboff /* mapping attributes */ 2105748Sduboff /* Data access requirements. */ 2115748Sduboff static struct ddi_device_acc_attr sfe_dev_attr = { 2125748Sduboff DDI_DEVICE_ATTR_V0, 2135748Sduboff DDI_STRUCTURE_LE_ACC, 2145748Sduboff DDI_STRICTORDER_ACC 2155748Sduboff }; 2165748Sduboff 2175748Sduboff /* On sparc, Buffers should be native endian for speed */ 2185748Sduboff static struct ddi_device_acc_attr sfe_buf_attr = { 2195748Sduboff DDI_DEVICE_ATTR_V0, 2205748Sduboff DDI_NEVERSWAP_ACC, /* native endianness */ 2215748Sduboff DDI_STRICTORDER_ACC 2225748Sduboff }; 2235748Sduboff 2245748Sduboff static ddi_dma_attr_t sfe_dma_attr_buf = { 2255748Sduboff DMA_ATTR_V0, /* dma_attr_version */ 2265748Sduboff 0, /* dma_attr_addr_lo */ 2275748Sduboff 0xffffffffull, /* dma_attr_addr_hi */ 2285748Sduboff 0x00000fffull, /* dma_attr_count_max */ 2295748Sduboff 0, /* patched later */ /* dma_attr_align */ 2305748Sduboff 0x000003fc, /* dma_attr_burstsizes */ 2315748Sduboff 1, /* dma_attr_minxfer */ 2325748Sduboff 0x00000fffull, /* dma_attr_maxxfer */ 2335748Sduboff 0xffffffffull, /* dma_attr_seg */ 2345748Sduboff 0, /* patched later */ /* dma_attr_sgllen */ 2355748Sduboff 1, /* dma_attr_granular */ 2365748Sduboff 0 /* dma_attr_flags */ 2375748Sduboff }; 2385748Sduboff 2395748Sduboff static ddi_dma_attr_t sfe_dma_attr_desc = { 2405748Sduboff DMA_ATTR_V0, /* dma_attr_version */ 2415748Sduboff 16, /* dma_attr_addr_lo */ 2425748Sduboff 0xffffffffull, /* dma_attr_addr_hi */ 2435748Sduboff 0xffffffffull, /* dma_attr_count_max */ 2445748Sduboff 16, /* dma_attr_align */ 2455748Sduboff 0x000003fc, /* dma_attr_burstsizes */ 2465748Sduboff 1, /* dma_attr_minxfer */ 2475748Sduboff 0xffffffffull, /* dma_attr_maxxfer */ 2485748Sduboff 0xffffffffull, /* dma_attr_seg */ 2495748Sduboff 1, /* dma_attr_sgllen */ 2505748Sduboff 1, /* dma_attr_granular */ 2515748Sduboff 0 /* dma_attr_flags */ 2525748Sduboff }; 2535748Sduboff 2545748Sduboff uint32_t sfe_use_pcimemspace = 0; 2555748Sduboff 2565748Sduboff /* ======================================================== */ 2575748Sduboff /* 2585748Sduboff * HW manipulation routines 2595748Sduboff */ 2605748Sduboff /* ======================================================== */ 2615748Sduboff 2625748Sduboff #define SFE_EEPROM_DELAY(dp) \ 2635748Sduboff { (void) INL(dp, EROMAR); (void) INL(dp, EROMAR); } 2645748Sduboff #define EE_CMD_READ 6 2655748Sduboff #define EE_CMD_SHIFT 6 2665748Sduboff 2675748Sduboff static uint16_t 2685748Sduboff sfe_read_eeprom(struct gem_dev *dp, uint_t offset) 2695748Sduboff { 2705748Sduboff int eedi; 2715748Sduboff int i; 2725748Sduboff uint16_t ret; 2735748Sduboff 2745748Sduboff /* ensure de-assert chip select */ 2755748Sduboff OUTL(dp, EROMAR, 0); 2765748Sduboff SFE_EEPROM_DELAY(dp); 2775748Sduboff OUTL(dp, EROMAR, EROMAR_EESK); 2785748Sduboff SFE_EEPROM_DELAY(dp); 2795748Sduboff 2805748Sduboff /* assert chip select */ 2815748Sduboff offset |= EE_CMD_READ << EE_CMD_SHIFT; 2825748Sduboff 2835748Sduboff for (i = 8; i >= 0; i--) { 2845748Sduboff /* make command */ 2855748Sduboff eedi = ((offset >> i) & 1) << EROMAR_EEDI_SHIFT; 2865748Sduboff 2875748Sduboff /* send 1 bit */ 2885748Sduboff OUTL(dp, EROMAR, EROMAR_EECS | eedi); 2895748Sduboff SFE_EEPROM_DELAY(dp); 2905748Sduboff OUTL(dp, EROMAR, EROMAR_EECS | eedi | EROMAR_EESK); 2915748Sduboff SFE_EEPROM_DELAY(dp); 2925748Sduboff } 2935748Sduboff 2945748Sduboff OUTL(dp, EROMAR, EROMAR_EECS); 2955748Sduboff 2965748Sduboff ret = 0; 2975748Sduboff for (i = 0; i < 16; i++) { 2985748Sduboff /* Get 1 bit */ 2995748Sduboff OUTL(dp, EROMAR, EROMAR_EECS); 3005748Sduboff SFE_EEPROM_DELAY(dp); 3015748Sduboff OUTL(dp, EROMAR, EROMAR_EECS | EROMAR_EESK); 3025748Sduboff SFE_EEPROM_DELAY(dp); 3035748Sduboff 3045748Sduboff ret = (ret << 1) | ((INL(dp, EROMAR) >> EROMAR_EEDO_SHIFT) & 1); 3055748Sduboff } 3065748Sduboff 3075748Sduboff OUTL(dp, EROMAR, 0); 3085748Sduboff SFE_EEPROM_DELAY(dp); 3095748Sduboff 3105748Sduboff return (ret); 3115748Sduboff } 3125748Sduboff #undef SFE_EEPROM_DELAY 3135748Sduboff 3145748Sduboff static boolean_t 3155748Sduboff sfe_get_mac_addr_dp83815(struct gem_dev *dp) 3165748Sduboff { 3175748Sduboff uint8_t *mac; 3185748Sduboff uint_t val; 3195748Sduboff int i; 3205748Sduboff 3215748Sduboff #define BITSET(p, ix, v) (p)[(ix)/8] |= ((v) ? 1 : 0) << ((ix) & 0x7) 3225748Sduboff 3235748Sduboff DPRINTF(4, (CE_CONT, CONS "%s: %s: called", dp->name, __func__)); 3245748Sduboff 3255748Sduboff mac = dp->dev_addr.ether_addr_octet; 3265748Sduboff 3275748Sduboff /* first of all, clear MAC address buffer */ 3285748Sduboff bzero(mac, ETHERADDRL); 3295748Sduboff 3305748Sduboff /* get bit 0 */ 3315748Sduboff val = sfe_read_eeprom(dp, 0x6); 3325748Sduboff BITSET(mac, 0, val & 1); 3335748Sduboff 3345748Sduboff /* get bit 1 - 16 */ 3355748Sduboff val = sfe_read_eeprom(dp, 0x7); 3365748Sduboff for (i = 0; i < 16; i++) { 3375748Sduboff BITSET(mac, 1 + i, val & (1 << (15 - i))); 3385748Sduboff } 3395748Sduboff 3405748Sduboff /* get bit 17 - 32 */ 3415748Sduboff val = sfe_read_eeprom(dp, 0x8); 3425748Sduboff for (i = 0; i < 16; i++) { 3435748Sduboff BITSET(mac, 17 + i, val & (1 << (15 - i))); 3445748Sduboff } 3455748Sduboff 3465748Sduboff /* get bit 33 - 47 */ 3475748Sduboff val = sfe_read_eeprom(dp, 0x9); 3485748Sduboff for (i = 0; i < 15; i++) { 3495748Sduboff BITSET(mac, 33 + i, val & (1 << (15 - i))); 3505748Sduboff } 3515748Sduboff 3525748Sduboff return (B_TRUE); 3535748Sduboff #undef BITSET 3545748Sduboff } 3555748Sduboff 3565748Sduboff static boolean_t 3575748Sduboff sfe_get_mac_addr_sis900(struct gem_dev *dp) 3585748Sduboff { 3595748Sduboff uint_t val; 3605748Sduboff int i; 3615748Sduboff uint8_t *mac; 3625748Sduboff 3635748Sduboff mac = dp->dev_addr.ether_addr_octet; 3645748Sduboff 3655748Sduboff for (i = 0; i < ETHERADDRL/2; i++) { 3665748Sduboff val = sfe_read_eeprom(dp, 0x8 + i); 3675748Sduboff *mac++ = (uint8_t)val; 3685748Sduboff *mac++ = (uint8_t)(val >> 8); 3695748Sduboff } 3705748Sduboff 3715748Sduboff return (B_TRUE); 3725748Sduboff } 3735748Sduboff 3745748Sduboff static dev_info_t * 3755748Sduboff sfe_search_pci_dev_subr(dev_info_t *cur_node, int vendor_id, int device_id) 3765748Sduboff { 3775748Sduboff dev_info_t *child_id; 3785748Sduboff dev_info_t *ret; 3795748Sduboff int vid, did; 3805748Sduboff 3815748Sduboff if (cur_node == NULL) { 3825748Sduboff return (NULL); 3835748Sduboff } 3845748Sduboff 3855748Sduboff /* check brothers */ 3865748Sduboff do { 3875748Sduboff vid = ddi_prop_get_int(DDI_DEV_T_ANY, cur_node, 3885748Sduboff DDI_PROP_DONTPASS, "vendor-id", -1); 3895748Sduboff did = ddi_prop_get_int(DDI_DEV_T_ANY, cur_node, 3905748Sduboff DDI_PROP_DONTPASS, "device-id", -1); 3915748Sduboff 3925748Sduboff if (vid == vendor_id && did == device_id) { 3935748Sduboff /* found */ 3945748Sduboff return (cur_node); 3955748Sduboff } 3965748Sduboff 3975748Sduboff /* check children */ 3985748Sduboff if ((child_id = ddi_get_child(cur_node)) != NULL) { 3995748Sduboff if ((ret = sfe_search_pci_dev_subr(child_id, 4005748Sduboff vendor_id, device_id)) != NULL) { 4015748Sduboff return (ret); 4025748Sduboff } 4035748Sduboff } 4045748Sduboff 4055748Sduboff } while ((cur_node = ddi_get_next_sibling(cur_node)) != NULL); 4065748Sduboff 4075748Sduboff /* not found */ 4085748Sduboff return (NULL); 4095748Sduboff } 4105748Sduboff 4115748Sduboff static dev_info_t * 4125748Sduboff sfe_search_pci_dev(int vendor_id, int device_id) 4135748Sduboff { 4145748Sduboff return (sfe_search_pci_dev_subr(ddi_root_node(), vendor_id, device_id)); 4155748Sduboff } 4165748Sduboff 4175748Sduboff /* Avoid undefined symbol for non IA architectures */ 4185748Sduboff #pragma weak inb 4195748Sduboff #pragma weak outb 4205748Sduboff 4215748Sduboff static boolean_t 4225748Sduboff sfe_get_mac_addr_sis630e(struct gem_dev *dp) 4235748Sduboff { 4245748Sduboff int i; 4255748Sduboff dev_info_t *isa_bridge; 4265748Sduboff ddi_acc_handle_t isa_handle; 4275748Sduboff int reg; 4285748Sduboff 4295748Sduboff if (inb == NULL || outb == NULL) { 4305748Sduboff /* this is not IA architecture */ 4315748Sduboff return (B_FALSE); 4325748Sduboff } 4335748Sduboff 4345748Sduboff if ((isa_bridge = sfe_search_pci_dev(0x1039, 0x8)) == NULL) { 4355748Sduboff cmn_err(CE_WARN, "%s: failed to find isa-bridge pci1039,8", 4365748Sduboff dp->name); 4375748Sduboff return (B_FALSE); 4385748Sduboff } 4395748Sduboff 4405748Sduboff if (pci_config_setup(isa_bridge, &isa_handle) != DDI_SUCCESS) { 4415748Sduboff cmn_err(CE_WARN, "%s: ddi_regs_map_setup failed", 4425748Sduboff dp->name); 4435748Sduboff return (B_FALSE); 4445748Sduboff } 4455748Sduboff 4465748Sduboff /* enable to access CMOS RAM */ 4475748Sduboff reg = pci_config_get8(isa_handle, 0x48); 4485748Sduboff pci_config_put8(isa_handle, 0x48, reg | 0x40); 4495748Sduboff 4505748Sduboff for (i = 0; i < ETHERADDRL; i++) { 4515748Sduboff outb(0x70, 0x09 + i); 4525748Sduboff dp->dev_addr.ether_addr_octet[i] = inb(0x71); 4535748Sduboff } 4545748Sduboff 4555748Sduboff /* disable to access CMOS RAM */ 4565748Sduboff pci_config_put8(isa_handle, 0x48, reg); 4575748Sduboff pci_config_teardown(&isa_handle); 4585748Sduboff 4595748Sduboff return (B_TRUE); 4605748Sduboff } 4615748Sduboff 4625748Sduboff static boolean_t 4635748Sduboff sfe_get_mac_addr_sis635(struct gem_dev *dp) 4645748Sduboff { 4655748Sduboff int i; 4665748Sduboff uint32_t rfcr; 4675748Sduboff uint16_t v; 4685748Sduboff struct sfe_dev *lp = dp->private; 4695748Sduboff 4705748Sduboff DPRINTF(2, (CE_CONT, CONS "%s: %s: called", dp->name, __func__)); 4715748Sduboff rfcr = INL(dp, RFCR); 4725748Sduboff 4735748Sduboff OUTL(dp, CR, lp->cr | CR_RELOAD); 4745748Sduboff OUTL(dp, CR, lp->cr); 4755748Sduboff 4765748Sduboff /* disable packet filtering before reading filter */ 4775748Sduboff OUTL(dp, RFCR, rfcr & ~RFCR_RFEN); 4785748Sduboff 4795748Sduboff /* load MAC addr from filter data register */ 4805748Sduboff for (i = 0; i < ETHERADDRL; i += 2) { 4815748Sduboff OUTL(dp, RFCR, 4825748Sduboff (RFADDR_MAC_SIS900 + (i/2)) << RFCR_RFADDR_SHIFT_SIS900); 4835748Sduboff v = INL(dp, RFDR); 4845748Sduboff dp->dev_addr.ether_addr_octet[i] = (uint8_t)v; 4855748Sduboff dp->dev_addr.ether_addr_octet[i+1] = (uint8_t)(v >> 8); 4865748Sduboff } 4875748Sduboff 4885748Sduboff /* re-enable packet filtering */ 4895748Sduboff OUTL(dp, RFCR, rfcr | RFCR_RFEN); 4905748Sduboff 4915748Sduboff return (B_TRUE); 4925748Sduboff } 4935748Sduboff 4945748Sduboff static boolean_t 4955748Sduboff sfe_get_mac_addr_sis962(struct gem_dev *dp) 4965748Sduboff { 4975748Sduboff boolean_t ret; 4985748Sduboff int i; 4995748Sduboff 5005748Sduboff ret = B_FALSE; 5015748Sduboff 5025748Sduboff /* rise request signal to access EEPROM */ 5035748Sduboff OUTL(dp, MEAR, EROMAR_EEREQ); 5045748Sduboff for (i = 0; (INL(dp, MEAR) & EROMAR_EEGNT) == 0; i++) { 5055748Sduboff if (i > 200) { 5065748Sduboff /* failed to acquire eeprom */ 5075748Sduboff cmn_err(CE_NOTE, 5085748Sduboff CONS "%s: failed to access eeprom", dp->name); 5095748Sduboff goto x; 5105748Sduboff } 5115748Sduboff drv_usecwait(10); 5125748Sduboff } 5135748Sduboff ret = sfe_get_mac_addr_sis900(dp); 5145748Sduboff x: 5155748Sduboff /* release EEPROM */ 5165748Sduboff OUTL(dp, MEAR, EROMAR_EEDONE); 5175748Sduboff 5185748Sduboff return (ret); 5195748Sduboff } 5205748Sduboff 5215748Sduboff static int 5225748Sduboff sfe_reset_chip_sis900(struct gem_dev *dp) 5235748Sduboff { 5245748Sduboff int i; 5255748Sduboff uint32_t done; 5265748Sduboff uint32_t val; 5275748Sduboff struct sfe_dev *lp = dp->private; 5285748Sduboff 5295748Sduboff DPRINTF(4, (CE_CONT, CONS "%s: %s called", dp->name, __func__)); 5305748Sduboff 5315748Sduboff /* invalidate mac addr cache */ 5325748Sduboff bzero(lp->mac_addr, sizeof (lp->mac_addr)); 5335748Sduboff 5345748Sduboff lp->cr = 0; 5355748Sduboff 5365748Sduboff /* inhibit interrupt */ 5375748Sduboff OUTL(dp, IMR, 0); 5387116Sduboff lp->isr_pended |= INL(dp, ISR) & lp->our_intr_bits; 5395748Sduboff 5405748Sduboff OUTL(dp, RFCR, 0); 5415748Sduboff 5425748Sduboff OUTL(dp, CR, CR_RST | CR_TXR | CR_RXR); 5435748Sduboff drv_usecwait(10); 5445748Sduboff 5455748Sduboff done = 0; 5465748Sduboff for (i = 0; done != (ISR_TXRCMP | ISR_RXRCMP); i++) { 5475748Sduboff if (i > 1000) { 5485748Sduboff cmn_err(CE_WARN, "%s: chip reset timeout", dp->name); 5495748Sduboff return (GEM_FAILURE); 5505748Sduboff } 5515748Sduboff done |= INL(dp, ISR) & (ISR_TXRCMP | ISR_RXRCMP); 5525748Sduboff drv_usecwait(10); 5535748Sduboff } 5545748Sduboff 5555748Sduboff if (lp->revid == SIS630ET_900_REV) { 5565748Sduboff lp->cr |= CR_ACCESSMODE; 5575748Sduboff OUTL(dp, CR, lp->cr | INL(dp, CR)); 5585748Sduboff } 5595748Sduboff 5605748Sduboff /* Configuration register: enable PCI parity */ 5615748Sduboff DPRINTF(2, (CE_CONT, CONS "%s: cfg:%b", 5625748Sduboff dp->name, INL(dp, CFG), CFG_BITS_SIS900)); 5637116Sduboff val = 0; 5645748Sduboff if (lp->revid >= SIS635A_900_REV || 5655748Sduboff lp->revid == SIS900B_900_REV) { 5665748Sduboff /* what is this ? */ 5675748Sduboff val |= CFG_RND_CNT; 5685748Sduboff } 5695748Sduboff OUTL(dp, CFG, val); 5705748Sduboff DPRINTF(2, (CE_CONT, CONS "%s: cfg:%b", dp->name, 5715748Sduboff INL(dp, CFG), CFG_BITS_SIS900)); 5725748Sduboff 5735748Sduboff return (GEM_SUCCESS); 5745748Sduboff } 5755748Sduboff 5765748Sduboff static int 5775748Sduboff sfe_reset_chip_dp83815(struct gem_dev *dp) 5785748Sduboff { 5795748Sduboff int i; 5807116Sduboff uint32_t val; 5815748Sduboff struct sfe_dev *lp = dp->private; 5825748Sduboff 5835748Sduboff DPRINTF(4, (CE_CONT, CONS "%s: %s called", dp->name, __func__)); 5845748Sduboff 5855748Sduboff /* invalidate mac addr cache */ 5865748Sduboff bzero(lp->mac_addr, sizeof (lp->mac_addr)); 5875748Sduboff 5885748Sduboff lp->cr = 0; 5895748Sduboff 5905748Sduboff /* inhibit interrupts */ 5915748Sduboff OUTL(dp, IMR, 0); 5927116Sduboff lp->isr_pended |= INL(dp, ISR) & lp->our_intr_bits; 5935748Sduboff 5945748Sduboff OUTL(dp, RFCR, 0); 5955748Sduboff 5965748Sduboff OUTL(dp, CR, CR_RST); 5975748Sduboff drv_usecwait(10); 5985748Sduboff 5995748Sduboff for (i = 0; INL(dp, CR) & CR_RST; i++) { 6005748Sduboff if (i > 100) { 6015748Sduboff cmn_err(CE_WARN, "!%s: chip reset timeout", dp->name); 6025748Sduboff return (GEM_FAILURE); 6035748Sduboff } 6045748Sduboff drv_usecwait(10); 6055748Sduboff } 6065748Sduboff DPRINTF(0, (CE_CONT, "!%s: chip reset in %duS", dp->name, i*10)); 6075748Sduboff 6085748Sduboff OUTL(dp, CCSR, CCSR_PMESTS); 6095748Sduboff OUTL(dp, CCSR, 0); 6105748Sduboff 6115748Sduboff /* Configuration register: enable PCI parity */ 6125748Sduboff DPRINTF(2, (CE_CONT, CONS "%s: cfg:%b", 6135748Sduboff dp->name, INL(dp, CFG), CFG_BITS_DP83815)); 6147116Sduboff val = INL(dp, CFG) & (CFG_ANEG_SEL | CFG_PHY_CFG); 6157116Sduboff OUTL(dp, CFG, val | CFG_PAUSE_ADV); 6165748Sduboff DPRINTF(2, (CE_CONT, CONS "%s: cfg:%b", dp->name, 6175748Sduboff INL(dp, CFG), CFG_BITS_DP83815)); 6185748Sduboff 6195748Sduboff return (GEM_SUCCESS); 6205748Sduboff } 6215748Sduboff 6225748Sduboff static int 6235748Sduboff sfe_init_chip(struct gem_dev *dp) 6245748Sduboff { 6255748Sduboff /* Configuration register: have been set up in sfe_chip_reset */ 6265748Sduboff 6275748Sduboff /* PCI test control register: do nothing */ 6285748Sduboff 6295748Sduboff /* Interrupt status register : do nothing */ 6305748Sduboff 6315748Sduboff /* Interrupt mask register: clear, but leave lp->our_intr_bits */ 6325748Sduboff OUTL(dp, IMR, 0); 6335748Sduboff 6345748Sduboff /* Enhanced PHY Access register (sis900): do nothing */ 6355748Sduboff 6365748Sduboff /* Transmit Descriptor Pointer register: base addr of TX ring */ 6375748Sduboff OUTL(dp, TXDP, dp->tx_ring_dma); 6385748Sduboff 6395748Sduboff /* Receive descriptor pointer register: base addr of RX ring */ 6405748Sduboff OUTL(dp, RXDP, dp->rx_ring_dma); 6415748Sduboff 6425748Sduboff return (GEM_SUCCESS); 6435748Sduboff } 6445748Sduboff 6455748Sduboff static uint_t 6465748Sduboff sfe_mcast_hash(struct gem_dev *dp, uint8_t *addr) 6475748Sduboff { 6485748Sduboff return (gem_ether_crc_be(addr, ETHERADDRL)); 6495748Sduboff } 6505748Sduboff 6515748Sduboff #ifdef DEBUG_LEVEL 6525748Sduboff static void 6535748Sduboff sfe_rxfilter_dump(struct gem_dev *dp, int start, int end) 6545748Sduboff { 6555748Sduboff int i; 6565748Sduboff int j; 6575748Sduboff uint16_t ram[0x10]; 6585748Sduboff 6595748Sduboff cmn_err(CE_CONT, "!%s: rx filter ram dump:", dp->name); 6605748Sduboff #define WORDS_PER_LINE 4 6615748Sduboff for (i = start; i < end; i += WORDS_PER_LINE*2) { 6625748Sduboff for (j = 0; j < WORDS_PER_LINE; j++) { 6635748Sduboff OUTL(dp, RFCR, RFADDR_MAC_DP83815 + i + j*2); 6645748Sduboff ram[j] = INL(dp, RFDR); 6655748Sduboff } 6665748Sduboff 6675748Sduboff cmn_err(CE_CONT, "!0x%02x: 0x%04x 0x%04x 0x%04x 0x%04x", 6685748Sduboff i, ram[0], ram[1], ram[2], ram[3]); 6695748Sduboff } 6705748Sduboff 6715748Sduboff #undef WORDS_PER_LINE 6725748Sduboff } 6735748Sduboff #endif 6745748Sduboff 6755748Sduboff static uint_t sfe_rf_perfect_base_dp83815[] = { 6765748Sduboff RFADDR_PMATCH0_DP83815, 6775748Sduboff RFADDR_PMATCH1_DP83815, 6785748Sduboff RFADDR_PMATCH2_DP83815, 6795748Sduboff RFADDR_PMATCH3_DP83815, 6805748Sduboff }; 6815748Sduboff 6825748Sduboff static int 6835748Sduboff sfe_set_rx_filter_dp83815(struct gem_dev *dp) 6845748Sduboff { 6855748Sduboff int i; 6865748Sduboff int j; 6875748Sduboff uint32_t mode; 6885748Sduboff uint8_t *mac = dp->cur_addr.ether_addr_octet; 6895748Sduboff uint16_t hash_tbl[32]; 6905748Sduboff struct sfe_dev *lp = dp->private; 6915748Sduboff 6925748Sduboff DPRINTF(1, (CE_CONT, CONS "%s: %s: called, mc_count:%d, mode:0x%b", 6935748Sduboff dp->name, __func__, dp->mc_count, dp->rxmode, RXMODE_BITS)); 6945748Sduboff 6955748Sduboff #if DEBUG_LEVEL > 0 6965748Sduboff for (i = 0; i < dp->mc_count; i++) { 6975748Sduboff cmn_err(CE_CONT, 6985748Sduboff "!%s: adding mcast(%d) %02x:%02x:%02x:%02x:%02x:%02x", 6995748Sduboff dp->name, i, 7005748Sduboff dp->mc_list[i].addr.ether_addr_octet[0], 7015748Sduboff dp->mc_list[i].addr.ether_addr_octet[1], 7025748Sduboff dp->mc_list[i].addr.ether_addr_octet[2], 7035748Sduboff dp->mc_list[i].addr.ether_addr_octet[3], 7045748Sduboff dp->mc_list[i].addr.ether_addr_octet[4], 7055748Sduboff dp->mc_list[i].addr.ether_addr_octet[5]); 7065748Sduboff } 7075748Sduboff #endif 7085748Sduboff if ((dp->rxmode & RXMODE_ENABLE) == 0) { 7095748Sduboff /* disable rx filter */ 7105748Sduboff OUTL(dp, RFCR, 0); 7115748Sduboff return (GEM_SUCCESS); 7125748Sduboff } 7135748Sduboff 7145748Sduboff /* 7155748Sduboff * Set Receive filter control register 7165748Sduboff */ 7175748Sduboff if (dp->rxmode & RXMODE_PROMISC) { 7185748Sduboff /* all broadcast, all multicast, all physical */ 7195748Sduboff mode = RFCR_AAB | RFCR_AAM | RFCR_AAP; 7205748Sduboff } else if ((dp->rxmode & RXMODE_ALLMULTI) || dp->mc_count > 16*32/2) { 7215748Sduboff /* all broadcast, all multicast, physical for the chip */ 7225748Sduboff mode = RFCR_AAB | RFCR_AAM | RFCR_APM_DP83815; 7235748Sduboff } else if (dp->mc_count > 4) { 7245748Sduboff /* 7255748Sduboff * Use multicast hash table, 7265748Sduboff * accept all broadcast and physical for the chip. 7275748Sduboff */ 7285748Sduboff mode = RFCR_AAB | RFCR_MHEN_DP83815 | RFCR_APM_DP83815; 7295748Sduboff 7305748Sduboff bzero(hash_tbl, sizeof (hash_tbl)); 7315748Sduboff for (i = 0; i < dp->mc_count; i++) { 7325748Sduboff j = dp->mc_list[i].hash >> (32 - 9); 7335748Sduboff hash_tbl[j / 16] |= 1 << (j % 16); 7345748Sduboff } 7355748Sduboff } else { 7365748Sduboff /* 7375748Sduboff * Use pattern mach filter for multicast address, 7385748Sduboff * accept all broadcast and physical for the chip 7395748Sduboff */ 7405748Sduboff /* need to enable corresponding pattern registers */ 7415748Sduboff mode = RFCR_AAB | RFCR_APM_DP83815 | 7425748Sduboff (((1 << dp->mc_count) - 1) << RFCR_APAT_SHIFT); 7435748Sduboff } 7445748Sduboff 7455748Sduboff #if DEBUG_LEVEL > 1 7465748Sduboff cmn_err(CE_CONT, 7475748Sduboff "!%s: mac %02x:%02x:%02x:%02x:%02x:%02x" 7485748Sduboff " cache %02x:%02x:%02x:%02x:%02x:%02x", 7495748Sduboff dp->name, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], 7505748Sduboff lp->mac_addr[0], lp->mac_addr[1], 7515748Sduboff lp->mac_addr[2], lp->mac_addr[3], 7525748Sduboff lp->mac_addr[4], lp->mac_addr[5]); 7535748Sduboff #endif 7545748Sduboff if (bcmp(mac, lp->mac_addr, ETHERADDRL) != 0) { 7555748Sduboff /* 7565748Sduboff * XXX - need to *disable* rx filter to load mac address for 7575748Sduboff * the chip. otherwise, we cannot setup rxfilter correctly. 7585748Sduboff */ 7595748Sduboff /* setup perfect match register for my station address */ 7605748Sduboff for (i = 0; i < ETHERADDRL; i += 2) { 7615748Sduboff OUTL(dp, RFCR, RFADDR_MAC_DP83815 + i); 7625748Sduboff OUTL(dp, RFDR, (mac[i+1] << 8) | mac[i]); 7635748Sduboff } 7645748Sduboff 7655748Sduboff bcopy(mac, lp->mac_addr, ETHERADDRL); 7665748Sduboff } 7675748Sduboff 7685748Sduboff #if DEBUG_LEVEL > 3 7695748Sduboff /* clear pattern ram */ 7705748Sduboff for (j = 0x200; j < 0x380; j += 2) { 7715748Sduboff OUTL(dp, RFCR, j); 7725748Sduboff OUTL(dp, RFDR, 0); 7735748Sduboff } 7745748Sduboff #endif 7755748Sduboff if (mode & RFCR_APAT_DP83815) { 7765748Sduboff /* setup multicast address into pattern match registers */ 7775748Sduboff for (j = 0; j < dp->mc_count; j++) { 7785748Sduboff mac = &dp->mc_list[j].addr.ether_addr_octet[0]; 7795748Sduboff for (i = 0; i < ETHERADDRL; i += 2) { 7805748Sduboff OUTL(dp, RFCR, 7815748Sduboff sfe_rf_perfect_base_dp83815[j] + i*2); 7825748Sduboff OUTL(dp, RFDR, (mac[i+1] << 8) | mac[i]); 7835748Sduboff } 7845748Sduboff } 7855748Sduboff 7865748Sduboff /* setup pattern count registers */ 7875748Sduboff OUTL(dp, RFCR, RFADDR_PCOUNT01_DP83815); 7885748Sduboff OUTL(dp, RFDR, (ETHERADDRL << 8) | ETHERADDRL); 7895748Sduboff OUTL(dp, RFCR, RFADDR_PCOUNT23_DP83815); 7905748Sduboff OUTL(dp, RFDR, (ETHERADDRL << 8) | ETHERADDRL); 7915748Sduboff } 7925748Sduboff 7935748Sduboff if (mode & RFCR_MHEN_DP83815) { 7945748Sduboff /* Load Multicast hash table */ 7955748Sduboff for (i = 0; i < 32; i++) { 7965748Sduboff /* for DP83815, index is in byte */ 7975748Sduboff OUTL(dp, RFCR, RFADDR_MULTICAST_DP83815 + i*2); 7985748Sduboff OUTL(dp, RFDR, hash_tbl[i]); 7995748Sduboff } 8005748Sduboff } 8015748Sduboff #if DEBUG_LEVEL > 2 8025748Sduboff sfe_rxfilter_dump(dp, 0, 0x10); 8035748Sduboff sfe_rxfilter_dump(dp, 0x200, 0x380); 8045748Sduboff #endif 8055748Sduboff /* Set rx filter mode and enable rx filter */ 8065748Sduboff OUTL(dp, RFCR, RFCR_RFEN | mode); 8075748Sduboff 8085748Sduboff return (GEM_SUCCESS); 8095748Sduboff } 8105748Sduboff 8115748Sduboff static int 8125748Sduboff sfe_set_rx_filter_sis900(struct gem_dev *dp) 8135748Sduboff { 8145748Sduboff int i; 8155748Sduboff uint32_t mode; 8165748Sduboff uint16_t hash_tbl[16]; 8175748Sduboff uint8_t *mac = dp->cur_addr.ether_addr_octet; 8185748Sduboff int hash_size; 8195748Sduboff int hash_shift; 8205748Sduboff struct sfe_dev *lp = dp->private; 8215748Sduboff 8225748Sduboff DPRINTF(4, (CE_CONT, CONS "%s: %s: called", dp->name, __func__)); 8235748Sduboff 8245748Sduboff if ((dp->rxmode & RXMODE_ENABLE) == 0) { 8255748Sduboff /* disalbe rx filter */ 8265748Sduboff OUTL(dp, RFCR, 0); 8275748Sduboff return (GEM_SUCCESS); 8285748Sduboff } 8295748Sduboff 8305748Sduboff /* 8315748Sduboff * determine hardware hash table size in word. 8325748Sduboff */ 8335748Sduboff hash_shift = 25; 8345748Sduboff if (lp->revid >= SIS635A_900_REV || lp->revid == SIS900B_900_REV) { 8355748Sduboff hash_shift = 24; 8365748Sduboff } 8375748Sduboff hash_size = (1 << (32 - hash_shift)) / 16; 8385748Sduboff bzero(hash_tbl, sizeof (hash_tbl)); 8395748Sduboff 8405748Sduboff /* Set Receive filter control register */ 8415748Sduboff 8425748Sduboff if (dp->rxmode & RXMODE_PROMISC) { 8435748Sduboff /* all broadcast, all multicast, all physical */ 8445748Sduboff mode = RFCR_AAB | RFCR_AAM | RFCR_AAP; 8455748Sduboff } else if ((dp->rxmode & RXMODE_ALLMULTI) || 8465748Sduboff dp->mc_count > hash_size*16/2) { 8475748Sduboff /* all broadcast, all multicast, physical for the chip */ 8485748Sduboff mode = RFCR_AAB | RFCR_AAM; 8495748Sduboff } else { 8505748Sduboff /* all broadcast, physical for the chip */ 8515748Sduboff mode = RFCR_AAB; 8525748Sduboff } 8535748Sduboff 8545748Sduboff /* make hash table */ 8555748Sduboff for (i = 0; i < dp->mc_count; i++) { 8565748Sduboff uint_t h; 8575748Sduboff h = dp->mc_list[i].hash >> hash_shift; 8585748Sduboff hash_tbl[h / 16] |= 1 << (h % 16); 8595748Sduboff } 8605748Sduboff 8615748Sduboff if (bcmp(mac, lp->mac_addr, ETHERADDRL) != 0) { 8625748Sduboff /* Disable Rx filter and load mac address */ 8635748Sduboff for (i = 0; i < ETHERADDRL/2; i++) { 8645748Sduboff /* For sis900, index is in word */ 8655748Sduboff OUTL(dp, RFCR, 8665748Sduboff (RFADDR_MAC_SIS900+i) << RFCR_RFADDR_SHIFT_SIS900); 8675748Sduboff OUTL(dp, RFDR, (mac[i*2+1] << 8) | mac[i*2]); 8685748Sduboff } 8695748Sduboff 8705748Sduboff bcopy(mac, lp->mac_addr, ETHERADDRL); 8715748Sduboff } 8725748Sduboff 8735748Sduboff /* Load Multicast hash table */ 8745748Sduboff for (i = 0; i < hash_size; i++) { 8755748Sduboff /* For sis900, index is in word */ 8765748Sduboff OUTL(dp, RFCR, 8775748Sduboff (RFADDR_MULTICAST_SIS900 + i) << RFCR_RFADDR_SHIFT_SIS900); 8785748Sduboff OUTL(dp, RFDR, hash_tbl[i]); 8795748Sduboff } 8805748Sduboff 8815748Sduboff /* Load rx filter mode and enable rx filter */ 8825748Sduboff OUTL(dp, RFCR, RFCR_RFEN | mode); 8835748Sduboff 8845748Sduboff return (GEM_SUCCESS); 8855748Sduboff } 8865748Sduboff 8875748Sduboff static int 8885748Sduboff sfe_start_chip(struct gem_dev *dp) 8895748Sduboff { 8905748Sduboff struct sfe_dev *lp = dp->private; 8915748Sduboff 8925748Sduboff DPRINTF(4, (CE_CONT, CONS "%s: %s: called", dp->name, __func__)); 8935748Sduboff 8945748Sduboff /* 8955748Sduboff * setup interrupt mask, which shouldn't include ISR_TOK 8965748Sduboff * to improve performance. 8975748Sduboff */ 8985748Sduboff lp->our_intr_bits = OUR_INTR_BITS; 8995748Sduboff 9005748Sduboff /* enable interrupt */ 9015748Sduboff if ((dp->misc_flag & GEM_NOINTR) == 0) { 9025748Sduboff OUTL(dp, IER, 1); 9035748Sduboff OUTL(dp, IMR, lp->our_intr_bits); 9045748Sduboff } 9055748Sduboff 9065748Sduboff /* Kick RX */ 9075748Sduboff OUTL(dp, CR, lp->cr | CR_RXE); 9085748Sduboff 9095748Sduboff return (GEM_SUCCESS); 9105748Sduboff } 9115748Sduboff 9125748Sduboff /* 9135748Sduboff * Stop nic core gracefully. 9145748Sduboff */ 9155748Sduboff static int 9165748Sduboff sfe_stop_chip(struct gem_dev *dp) 9175748Sduboff { 9185748Sduboff struct sfe_dev *lp = dp->private; 9195748Sduboff uint32_t done; 9205748Sduboff int i; 9217116Sduboff uint32_t val; 9225748Sduboff 9235748Sduboff DPRINTF(4, (CE_CONT, CONS "%s: %s: called", dp->name, __func__)); 9245748Sduboff 9255748Sduboff /* 9265748Sduboff * Although we inhibit interrupt here, we don't clear soft copy of 9275748Sduboff * interrupt mask to avoid bogus interrupts. 9285748Sduboff */ 9295748Sduboff OUTL(dp, IMR, 0); 9305748Sduboff 9315748Sduboff /* stop TX and RX immediately */ 9325748Sduboff OUTL(dp, CR, lp->cr | CR_TXR | CR_RXR); 9335748Sduboff 9345748Sduboff done = 0; 9355748Sduboff for (i = 0; done != (ISR_RXRCMP | ISR_TXRCMP); i++) { 9365748Sduboff if (i > 1000) { 9375748Sduboff /* 9385748Sduboff * As gem layer will call sfe_reset_chip(), 9395748Sduboff * we don't neet to reset futher 9405748Sduboff */ 9415748Sduboff cmn_err(CE_NOTE, "!%s: %s: Tx/Rx reset timeout", 9425748Sduboff dp->name, __func__); 9435748Sduboff 9445748Sduboff return (GEM_FAILURE); 9455748Sduboff } 9467116Sduboff val = INL(dp, ISR); 9477116Sduboff done |= val & (ISR_RXRCMP | ISR_TXRCMP); 9487116Sduboff lp->isr_pended |= val & lp->our_intr_bits; 9495748Sduboff drv_usecwait(10); 9505748Sduboff } 9515748Sduboff 9525748Sduboff return (GEM_SUCCESS); 9535748Sduboff } 9545748Sduboff 9555748Sduboff /* 9565748Sduboff * Setup media mode 9575748Sduboff */ 9585748Sduboff static uint_t 9595748Sduboff sfe_mxdma_value[] = { 512, 4, 8, 16, 32, 64, 128, 256, }; 9605748Sduboff 9615748Sduboff static uint_t 9625748Sduboff sfe_encode_mxdma(uint_t burstsize) 9635748Sduboff { 9645748Sduboff int i; 9655748Sduboff 9665748Sduboff if (burstsize > 256) { 9675748Sduboff /* choose 512 */ 9685748Sduboff return (0); 9695748Sduboff } 9705748Sduboff 9715748Sduboff for (i = 1; i < 8; i++) { 9725748Sduboff if (burstsize <= sfe_mxdma_value[i]) { 9735748Sduboff break; 9745748Sduboff } 9755748Sduboff } 9765748Sduboff return (i); 9775748Sduboff } 9785748Sduboff 9795748Sduboff static int 9805748Sduboff sfe_set_media(struct gem_dev *dp) 9815748Sduboff { 9825748Sduboff uint32_t txcfg; 9835748Sduboff uint32_t rxcfg; 9845748Sduboff uint32_t pcr; 9855748Sduboff uint32_t val; 9865748Sduboff uint32_t txmxdma; 9875748Sduboff uint32_t rxmxdma; 9885748Sduboff struct sfe_dev *lp = dp->private; 9895748Sduboff #ifdef DEBUG_LEVEL 9905748Sduboff extern int gem_speed_value[]; 9915748Sduboff #endif 9925748Sduboff DPRINTF(2, (CE_CONT, CONS "%s: %s: %s duplex, %d Mbps", 9935748Sduboff dp->name, __func__, 9945748Sduboff dp->full_duplex ? "full" : "half", gem_speed_value[dp->speed])); 9955748Sduboff 9965748Sduboff /* initialize txcfg and rxcfg */ 9975748Sduboff txcfg = TXCFG_ATP; 9985748Sduboff if (dp->full_duplex) { 9995748Sduboff txcfg |= (TXCFG_CSI | TXCFG_HBI); 10005748Sduboff } 10017116Sduboff rxcfg = RXCFG_AEP | RXCFG_ARP; 10025748Sduboff if (dp->full_duplex) { 10035748Sduboff rxcfg |= RXCFG_ATX; 10045748Sduboff } 10055748Sduboff 10065748Sduboff /* select txmxdma and rxmxdma, maxmum burst length */ 10075748Sduboff if (lp->chip->chip_type == CHIPTYPE_SIS900) { 10085748Sduboff #ifdef DEBUG_SIS900_EDB 10095748Sduboff val = CFG_EDB_MASTER; 10105748Sduboff #else 10115748Sduboff val = INL(dp, CFG) & CFG_EDB_MASTER; 10125748Sduboff #endif 10135748Sduboff if (val) { 10145748Sduboff /* 10155748Sduboff * sis900 built-in cores: 10165748Sduboff * max burst length must be fixed to 64 10175748Sduboff */ 10185748Sduboff txmxdma = 64; 10195748Sduboff rxmxdma = 64; 10205748Sduboff } else { 10215748Sduboff /* 10225748Sduboff * sis900 pci chipset: 10235748Sduboff * the vendor recommended to fix max burst length 10245748Sduboff * to 512 10255748Sduboff */ 10265748Sduboff txmxdma = 512; 10275748Sduboff rxmxdma = 512; 10285748Sduboff } 10295748Sduboff } else { 10305748Sduboff /* 10315748Sduboff * NS dp83815/816: 10325748Sduboff * use user defined or default for tx/rx max burst length 10335748Sduboff */ 10345748Sduboff txmxdma = max(dp->txmaxdma, 256); 10355748Sduboff rxmxdma = max(dp->rxmaxdma, 256); 10365748Sduboff } 10375748Sduboff 10385748Sduboff 10395748Sduboff /* tx high water mark */ 10405748Sduboff lp->tx_drain_threshold = ROUNDUP2(dp->txthr, TXCFG_FIFO_UNIT); 10415748Sduboff 10425748Sduboff /* determine tx_fill_threshold accroding drain threshold */ 10435748Sduboff lp->tx_fill_threshold = 10445748Sduboff TXFIFOSIZE - lp->tx_drain_threshold - TXCFG_FIFO_UNIT; 10455748Sduboff 10465748Sduboff /* tune txmxdma not to exceed tx_fill_threshold */ 10475748Sduboff for (; ; ) { 10485748Sduboff /* normalize txmxdma requested */ 10495748Sduboff val = sfe_encode_mxdma(txmxdma); 10505748Sduboff txmxdma = sfe_mxdma_value[val]; 10515748Sduboff 10525748Sduboff if (txmxdma <= lp->tx_fill_threshold) { 10535748Sduboff break; 10545748Sduboff } 10555748Sduboff /* select new txmxdma */ 10565748Sduboff txmxdma = txmxdma / 2; 10575748Sduboff } 10585748Sduboff txcfg |= val << TXCFG_MXDMA_SHIFT; 10595748Sduboff 10605748Sduboff /* encode rxmxdma, maxmum burst length for rx */ 10615748Sduboff val = sfe_encode_mxdma(rxmxdma); 10627116Sduboff rxcfg |= val << RXCFG_MXDMA_SHIFT; 10635748Sduboff rxmxdma = sfe_mxdma_value[val]; 10645748Sduboff 10655748Sduboff /* receive starting threshold - it have only 5bit-wide field */ 10665748Sduboff val = ROUNDUP2(max(dp->rxthr, ETHERMIN), RXCFG_FIFO_UNIT); 10675748Sduboff lp->rx_drain_threshold = 10685748Sduboff min(val, (RXCFG_DRTH >> RXCFG_DRTH_SHIFT) * RXCFG_FIFO_UNIT); 10695748Sduboff 10705748Sduboff DPRINTF(0, (CE_CONT, 10715748Sduboff "%s: %s: tx: drain:%d(rest %d) fill:%d mxdma:%d," 10725748Sduboff " rx: drain:%d mxdma:%d", 10735748Sduboff dp->name, __func__, 10745748Sduboff lp->tx_drain_threshold, TXFIFOSIZE - lp->tx_drain_threshold, 10755748Sduboff lp->tx_fill_threshold, txmxdma, 10765748Sduboff lp->rx_drain_threshold, rxmxdma)); 10775748Sduboff 10785748Sduboff ASSERT(lp->tx_drain_threshold < 64*TXCFG_FIFO_UNIT); 10795748Sduboff ASSERT(lp->tx_fill_threshold < 64*TXCFG_FIFO_UNIT); 10805748Sduboff ASSERT(lp->rx_drain_threshold < 32*RXCFG_FIFO_UNIT); 10815748Sduboff 10825748Sduboff txcfg |= ((lp->tx_fill_threshold/TXCFG_FIFO_UNIT) << TXCFG_FLTH_SHIFT) 10835748Sduboff | (lp->tx_drain_threshold/TXCFG_FIFO_UNIT); 10845748Sduboff OUTL(dp, TXCFG, txcfg); 10855748Sduboff 10865748Sduboff rxcfg |= ((lp->rx_drain_threshold/RXCFG_FIFO_UNIT) << RXCFG_DRTH_SHIFT); 10875748Sduboff if (lp->chip->chip_type == CHIPTYPE_DP83815) { 10885748Sduboff rxcfg |= RXCFG_ALP_DP83815; 10895748Sduboff } 10905748Sduboff OUTL(dp, RXCFG, rxcfg); 10915748Sduboff 10925748Sduboff DPRINTF(0, (CE_CONT, CONS "%s: %s: txcfg:%b rxcfg:%b", 10935748Sduboff dp->name, __func__, 10945748Sduboff txcfg, TXCFG_BITS, rxcfg, RXCFG_BITS)); 10955748Sduboff 10965748Sduboff /* Flow control */ 10975748Sduboff if (lp->chip->chip_type == CHIPTYPE_DP83815) { 10985748Sduboff pcr = INL(dp, PCR); 10995748Sduboff switch (dp->flow_control) { 11005748Sduboff case FLOW_CONTROL_SYMMETRIC: 11015748Sduboff case FLOW_CONTROL_RX_PAUSE: 11025748Sduboff OUTL(dp, PCR, pcr | PCR_PSEN | PCR_PS_MCAST); 11035748Sduboff break; 11045748Sduboff 11055748Sduboff default: 11065748Sduboff OUTL(dp, PCR, 11075748Sduboff pcr & ~(PCR_PSEN | PCR_PS_MCAST | PCR_PS_DA)); 11085748Sduboff break; 11095748Sduboff } 11105748Sduboff DPRINTF(2, (CE_CONT, CONS "%s: PCR: %b", dp->name, 11115748Sduboff INL(dp, PCR), PCR_BITS)); 11125748Sduboff 11135748Sduboff } else if (lp->chip->chip_type == CHIPTYPE_SIS900) { 11145748Sduboff switch (dp->flow_control) { 11155748Sduboff case FLOW_CONTROL_SYMMETRIC: 11165748Sduboff case FLOW_CONTROL_RX_PAUSE: 11175748Sduboff OUTL(dp, FLOWCTL, FLOWCTL_FLOWEN); 11185748Sduboff break; 11195748Sduboff default: 11205748Sduboff OUTL(dp, FLOWCTL, 0); 11215748Sduboff break; 11225748Sduboff } 11235748Sduboff DPRINTF(2, (CE_CONT, CONS "%s: FLOWCTL: %b", 11245748Sduboff dp->name, INL(dp, FLOWCTL), FLOWCTL_BITS)); 11255748Sduboff } 11265748Sduboff return (GEM_SUCCESS); 11275748Sduboff } 11285748Sduboff 11295748Sduboff static int 11305748Sduboff sfe_get_stats(struct gem_dev *dp) 11315748Sduboff { 11325748Sduboff /* do nothing */ 11335748Sduboff return (GEM_SUCCESS); 11345748Sduboff } 11355748Sduboff 11365748Sduboff /* 11375748Sduboff * descriptor manipulations 11385748Sduboff */ 11395748Sduboff static int 11405748Sduboff sfe_tx_desc_write(struct gem_dev *dp, int slot, 11415748Sduboff ddi_dma_cookie_t *dmacookie, int frags, uint64_t flags) 11425748Sduboff { 11435748Sduboff uint32_t mark; 11445748Sduboff struct sfe_desc *tdp; 11455748Sduboff ddi_dma_cookie_t *dcp; 11467116Sduboff uint32_t tmp0; 11477116Sduboff #if DEBUG_LEVEL > 2 11485748Sduboff int i; 11495748Sduboff 11505748Sduboff cmn_err(CE_CONT, 11515748Sduboff CONS "%s: time:%d %s seqnum: %d, slot %d, frags: %d flags: %llx", 11525748Sduboff dp->name, ddi_get_lbolt(), __func__, 11535748Sduboff dp->tx_desc_tail, slot, frags, flags); 11545748Sduboff 11555748Sduboff for (i = 0; i < frags; i++) { 11565748Sduboff cmn_err(CE_CONT, CONS "%d: addr: 0x%x, len: 0x%x", 11575748Sduboff i, dmacookie[i].dmac_address, dmacookie[i].dmac_size); 11587116Sduboff } 11595748Sduboff #endif 11605748Sduboff /* 11615748Sduboff * write tx descriptor in reversed order. 11625748Sduboff */ 11635748Sduboff #if DEBUG_LEVEL > 3 11645748Sduboff flags |= GEM_TXFLAG_INTR; 11655748Sduboff #endif 11665748Sduboff mark = (flags & GEM_TXFLAG_INTR) 11677116Sduboff ? (CMDSTS_OWN | CMDSTS_INTR) : CMDSTS_OWN; 11685748Sduboff 11695748Sduboff ASSERT(frags == 1); 11705748Sduboff dcp = &dmacookie[0]; 11715748Sduboff if (flags & GEM_TXFLAG_HEAD) { 11725748Sduboff mark &= ~CMDSTS_OWN; 11735748Sduboff } 11745748Sduboff 11755748Sduboff tdp = (void *)&dp->tx_ring[SFE_DESC_SIZE * slot]; 11767116Sduboff tmp0 = (uint32_t)dcp->dmac_address; 11777116Sduboff mark |= (uint32_t)dcp->dmac_size; 11787116Sduboff tdp->d_bufptr = LE_32(tmp0); 11797116Sduboff tdp->d_cmdsts = LE_32(mark); 11805748Sduboff 11815748Sduboff return (frags); 11825748Sduboff } 11835748Sduboff 11845748Sduboff static void 11855748Sduboff sfe_tx_start(struct gem_dev *dp, int start_slot, int nslot) 11865748Sduboff { 11877116Sduboff uint_t tx_ring_size = dp->gc.gc_tx_ring_size; 11885748Sduboff struct sfe_desc *tdp; 11895748Sduboff struct sfe_dev *lp = dp->private; 11905748Sduboff 11915748Sduboff if (nslot > 1) { 11925748Sduboff gem_tx_desc_dma_sync(dp, 11937116Sduboff SLOT(start_slot + 1, tx_ring_size), 11945748Sduboff nslot - 1, DDI_DMA_SYNC_FORDEV); 11955748Sduboff } 11965748Sduboff 11975748Sduboff tdp = (void *)&dp->tx_ring[SFE_DESC_SIZE * start_slot]; 11985748Sduboff tdp->d_cmdsts |= LE_32(CMDSTS_OWN); 11995748Sduboff 12005748Sduboff gem_tx_desc_dma_sync(dp, start_slot, 1, DDI_DMA_SYNC_FORDEV); 12015748Sduboff 12025748Sduboff /* 12035748Sduboff * Let the Transmit Buffer Manager Fill state machine active. 12045748Sduboff */ 12055748Sduboff if (dp->mac_active) { 12065748Sduboff OUTL(dp, CR, lp->cr | CR_TXE); 12075748Sduboff } 12085748Sduboff } 12095748Sduboff 12105748Sduboff static void 12115748Sduboff sfe_rx_desc_write(struct gem_dev *dp, int slot, 12125748Sduboff ddi_dma_cookie_t *dmacookie, int frags) 12135748Sduboff { 12145748Sduboff struct sfe_desc *rdp; 12157116Sduboff uint32_t tmp0; 12167116Sduboff uint32_t tmp1; 12175748Sduboff #if DEBUG_LEVEL > 2 12185748Sduboff int i; 12195748Sduboff 12205748Sduboff ASSERT(frags == 1); 12215748Sduboff 12225748Sduboff cmn_err(CE_CONT, CONS 12235748Sduboff "%s: %s seqnum: %d, slot %d, frags: %d", 12245748Sduboff dp->name, __func__, dp->rx_active_tail, slot, frags); 12255748Sduboff for (i = 0; i < frags; i++) { 12265748Sduboff cmn_err(CE_CONT, CONS " frag: %d addr: 0x%llx, len: 0x%lx", 12275748Sduboff i, dmacookie[i].dmac_address, dmacookie[i].dmac_size); 12285748Sduboff } 12295748Sduboff #endif 12305748Sduboff /* for the last slot of the packet */ 12315748Sduboff rdp = (void *)&dp->rx_ring[SFE_DESC_SIZE * slot]; 12325748Sduboff 12337116Sduboff tmp0 = (uint32_t)dmacookie->dmac_address; 12347116Sduboff tmp1 = CMDSTS_INTR | (uint32_t)dmacookie->dmac_size; 12357116Sduboff rdp->d_bufptr = LE_32(tmp0); 12367116Sduboff rdp->d_cmdsts = LE_32(tmp1); 12375748Sduboff } 12385748Sduboff 12395748Sduboff static uint_t 12405748Sduboff sfe_tx_desc_stat(struct gem_dev *dp, int slot, int ndesc) 12415748Sduboff { 12427116Sduboff uint_t tx_ring_size = dp->gc.gc_tx_ring_size; 12435748Sduboff struct sfe_desc *tdp; 12445748Sduboff uint32_t status; 12455748Sduboff int cols; 12467116Sduboff struct sfe_dev *lp = dp->private; 12475748Sduboff #ifdef DEBUG_LEVEL 12485748Sduboff int i; 12495748Sduboff clock_t delay; 12505748Sduboff #endif 12515748Sduboff /* check status of the last descriptor */ 12525748Sduboff tdp = (void *) 12537116Sduboff &dp->tx_ring[SFE_DESC_SIZE * SLOT(slot + ndesc - 1, tx_ring_size)]; 12545748Sduboff 12557116Sduboff /* 12567116Sduboff * Don't use LE_32() directly to refer tdp->d_cmdsts. 12577116Sduboff * It is not atomic for big endian cpus. 12587116Sduboff */ 12597116Sduboff status = tdp->d_cmdsts; 12607116Sduboff status = LE_32(status); 12615748Sduboff 12625748Sduboff DPRINTF(2, (CE_CONT, CONS "%s: time:%ld %s: slot:%d, status:0x%b", 12635748Sduboff dp->name, ddi_get_lbolt(), __func__, 12645748Sduboff slot, status, TXSTAT_BITS)); 12655748Sduboff 12665748Sduboff if (status & CMDSTS_OWN) { 12675748Sduboff /* 12685748Sduboff * not yet transmitted 12695748Sduboff */ 12707116Sduboff /* workaround for tx hang */ 12717116Sduboff if (lp->chip->chip_type == CHIPTYPE_DP83815 && 12727116Sduboff dp->mac_active) { 12737116Sduboff OUTL(dp, CR, lp->cr | CR_TXE); 12747116Sduboff } 12755748Sduboff return (0); 12765748Sduboff } 12775748Sduboff 12785748Sduboff if (status & CMDSTS_MORE) { 12795748Sduboff /* XXX - the hardware problem but don't panic the system */ 12805748Sduboff /* avoid lint bug for %b format string including 32nd bit */ 12815748Sduboff cmn_err(CE_NOTE, CONS 12825748Sduboff "%s: tx status bits incorrect: slot:%d, status:0x%x", 12835748Sduboff dp->name, slot, status); 12845748Sduboff } 12855748Sduboff 12865748Sduboff #if DEBUG_LEVEL > 3 12875748Sduboff delay = (ddi_get_lbolt() - dp->tx_buf_head->txb_stime) * 10; 12885748Sduboff if (delay >= 50) { 12895748Sduboff DPRINTF(0, (CE_NOTE, "%s: tx deferred %d mS: slot %d", 12905748Sduboff dp->name, delay, slot)); 12915748Sduboff } 12925748Sduboff #endif 12935748Sduboff 12945748Sduboff #if DEBUG_LEVEL > 3 12955748Sduboff for (i = 0; i < nfrag-1; i++) { 12965748Sduboff uint32_t s; 12975748Sduboff int n; 12985748Sduboff 12997116Sduboff n = SLOT(slot + i, tx_ring_size); 13005748Sduboff s = LE_32( 13015748Sduboff ((struct sfe_desc *)((void *) 13025748Sduboff &dp->tx_ring[SFE_DESC_SIZE * n]))->d_cmdsts); 13035748Sduboff 13045748Sduboff ASSERT(s & CMDSTS_MORE); 13055748Sduboff ASSERT((s & CMDSTS_OWN) == 0); 13065748Sduboff } 13075748Sduboff #endif 13085748Sduboff 13095748Sduboff /* 13105748Sduboff * collect statistics 13115748Sduboff */ 13125748Sduboff if ((status & CMDSTS_OK) == 0) { 13135748Sduboff 13145748Sduboff /* failed to transmit the packet */ 13155748Sduboff 13165748Sduboff DPRINTF(0, (CE_CONT, CONS "%s: Transmit error, Tx status %b", 13175748Sduboff dp->name, status, TXSTAT_BITS)); 13185748Sduboff 13195748Sduboff dp->stats.errxmt++; 13205748Sduboff 13215748Sduboff if (status & CMDSTS_TFU) { 13225748Sduboff dp->stats.underflow++; 13235748Sduboff } else if (status & CMDSTS_CRS) { 13245748Sduboff dp->stats.nocarrier++; 13255748Sduboff } else if (status & CMDSTS_OWC) { 13265748Sduboff dp->stats.xmtlatecoll++; 13275748Sduboff } else if ((!dp->full_duplex) && (status & CMDSTS_EC)) { 13285748Sduboff dp->stats.excoll++; 13295748Sduboff dp->stats.collisions += 16; 13305748Sduboff } else { 13315748Sduboff dp->stats.xmit_internal_err++; 13325748Sduboff } 13335748Sduboff } else if (!dp->full_duplex) { 13345748Sduboff cols = (status >> CMDSTS_CCNT_SHIFT) & CCNT_MASK; 13355748Sduboff 13365748Sduboff if (cols > 0) { 13375748Sduboff if (cols == 1) { 13385748Sduboff dp->stats.first_coll++; 13395748Sduboff } else /* (cols > 1) */ { 13405748Sduboff dp->stats.multi_coll++; 13415748Sduboff } 13425748Sduboff dp->stats.collisions += cols; 13435748Sduboff } else if (status & CMDSTS_TD) { 13445748Sduboff dp->stats.defer++; 13455748Sduboff } 13465748Sduboff } 13475748Sduboff return (GEM_TX_DONE); 13485748Sduboff } 13495748Sduboff 13505748Sduboff static uint64_t 13515748Sduboff sfe_rx_desc_stat(struct gem_dev *dp, int slot, int ndesc) 13525748Sduboff { 13535748Sduboff struct sfe_desc *rdp; 13545748Sduboff uint_t len; 13555748Sduboff uint_t flag; 13565748Sduboff uint32_t status; 13575748Sduboff 13585748Sduboff flag = GEM_RX_DONE; 13595748Sduboff 13605748Sduboff /* Dont read ISR because we cannot ack only to rx interrupt. */ 13615748Sduboff 13625748Sduboff rdp = (void *)&dp->rx_ring[SFE_DESC_SIZE * slot]; 13635748Sduboff 13647116Sduboff /* 13657116Sduboff * Don't use LE_32() directly to refer rdp->d_cmdsts. 13667116Sduboff * It is not atomic for big endian cpus. 13677116Sduboff */ 13687116Sduboff status = rdp->d_cmdsts; 13697116Sduboff status = LE_32(status); 13705748Sduboff 13715748Sduboff DPRINTF(2, (CE_CONT, CONS "%s: time:%ld %s: slot:%d, status:0x%b", 13725748Sduboff dp->name, ddi_get_lbolt(), __func__, 13735748Sduboff slot, status, RXSTAT_BITS)); 13745748Sduboff 13755748Sduboff if ((status & CMDSTS_OWN) == 0) { 13765748Sduboff /* 13775748Sduboff * No more received packets because 13785748Sduboff * this buffer is owned by NIC. 13795748Sduboff */ 13805748Sduboff return (0); 13815748Sduboff } 13825748Sduboff 13835748Sduboff #define RX_ERR_BITS \ 13845748Sduboff (CMDSTS_RXA | CMDSTS_RXO | CMDSTS_LONG | CMDSTS_RUNT | \ 13855748Sduboff CMDSTS_ISE | CMDSTS_CRCE | CMDSTS_FAE | CMDSTS_MORE) 13865748Sduboff 13875748Sduboff if (status & RX_ERR_BITS) { 13885748Sduboff /* 13895748Sduboff * Packet with error received 13905748Sduboff */ 13915748Sduboff DPRINTF(0, (CE_CONT, CONS "%s: Corrupted packet " 13925748Sduboff "received, buffer status: %b", 13935748Sduboff dp->name, status, RXSTAT_BITS)); 13945748Sduboff 13955748Sduboff /* collect statistics information */ 13965748Sduboff dp->stats.errrcv++; 13975748Sduboff 13985748Sduboff if (status & CMDSTS_RXO) { 13995748Sduboff dp->stats.overflow++; 14005748Sduboff } else if (status & (CMDSTS_LONG | CMDSTS_MORE)) { 14015748Sduboff dp->stats.frame_too_long++; 14025748Sduboff } else if (status & CMDSTS_RUNT) { 14035748Sduboff dp->stats.runt++; 14045748Sduboff } else if (status & (CMDSTS_ISE | CMDSTS_FAE)) { 14055748Sduboff dp->stats.frame++; 14065748Sduboff } else if (status & CMDSTS_CRCE) { 14075748Sduboff dp->stats.crc++; 14085748Sduboff } else { 14095748Sduboff dp->stats.rcv_internal_err++; 14105748Sduboff } 14115748Sduboff 14125748Sduboff return (flag | GEM_RX_ERR); 14135748Sduboff } 14145748Sduboff 14155748Sduboff /* 14165748Sduboff * this packet was received without errors 14175748Sduboff */ 14185748Sduboff if ((len = (status & CMDSTS_SIZE)) >= ETHERFCSL) { 14195748Sduboff len -= ETHERFCSL; 14205748Sduboff } 14215748Sduboff 14225748Sduboff #if DEBUG_LEVEL > 10 14235748Sduboff { 14245748Sduboff int i; 14255748Sduboff uint8_t *bp = dp->rx_buf_head->rxb_buf; 14265748Sduboff 14275748Sduboff cmn_err(CE_CONT, CONS "%s: len:%d", dp->name, len); 14285748Sduboff 14295748Sduboff for (i = 0; i < 60; i += 10) { 14305748Sduboff cmn_err(CE_CONT, CONS 14315748Sduboff "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", 14325748Sduboff bp[0], bp[1], bp[2], bp[3], bp[4], 14335748Sduboff bp[5], bp[6], bp[7], bp[8], bp[9]); 14345748Sduboff } 14355748Sduboff bp += 10; 14365748Sduboff } 14375748Sduboff #endif 14385748Sduboff return (flag | (len & GEM_RX_LEN)); 14395748Sduboff } 14405748Sduboff 14415748Sduboff static void 14425748Sduboff sfe_tx_desc_init(struct gem_dev *dp, int slot) 14435748Sduboff { 14447116Sduboff uint_t tx_ring_size = dp->gc.gc_tx_ring_size; 14455748Sduboff struct sfe_desc *tdp; 14465748Sduboff uint32_t here; 14475748Sduboff 14485748Sduboff tdp = (void *)&dp->tx_ring[SFE_DESC_SIZE * slot]; 14495748Sduboff 14505748Sduboff /* don't clear d_link field, which have a valid pointer */ 14515748Sduboff tdp->d_cmdsts = 0; 14525748Sduboff 14535748Sduboff /* make a link to this from the previous descriptor */ 14545748Sduboff here = ((uint32_t)dp->tx_ring_dma) + SFE_DESC_SIZE*slot; 14555748Sduboff 14565748Sduboff tdp = (void *) 14577116Sduboff &dp->tx_ring[SFE_DESC_SIZE * SLOT(slot - 1, tx_ring_size)]; 14585748Sduboff tdp->d_link = LE_32(here); 14595748Sduboff } 14605748Sduboff 14615748Sduboff static void 14625748Sduboff sfe_rx_desc_init(struct gem_dev *dp, int slot) 14635748Sduboff { 14647116Sduboff uint_t rx_ring_size = dp->gc.gc_rx_ring_size; 14655748Sduboff struct sfe_desc *rdp; 14665748Sduboff uint32_t here; 14675748Sduboff 14685748Sduboff rdp = (void *)&dp->rx_ring[SFE_DESC_SIZE * slot]; 14695748Sduboff 14705748Sduboff /* don't clear d_link field, which have a valid pointer */ 14715748Sduboff rdp->d_cmdsts = LE_32(CMDSTS_OWN); 14725748Sduboff 14735748Sduboff /* make a link to this from the previous descriptor */ 14745748Sduboff here = ((uint32_t)dp->rx_ring_dma) + SFE_DESC_SIZE*slot; 14755748Sduboff 14765748Sduboff rdp = (void *) 14777116Sduboff &dp->rx_ring[SFE_DESC_SIZE * SLOT(slot - 1, rx_ring_size)]; 14785748Sduboff rdp->d_link = LE_32(here); 14795748Sduboff } 14805748Sduboff 14815748Sduboff static void 14825748Sduboff sfe_tx_desc_clean(struct gem_dev *dp, int slot) 14835748Sduboff { 14845748Sduboff struct sfe_desc *tdp; 14855748Sduboff 14865748Sduboff tdp = (void *)&dp->tx_ring[SFE_DESC_SIZE * slot]; 14875748Sduboff tdp->d_cmdsts = 0; 14885748Sduboff } 14895748Sduboff 14905748Sduboff static void 14915748Sduboff sfe_rx_desc_clean(struct gem_dev *dp, int slot) 14925748Sduboff { 14935748Sduboff struct sfe_desc *rdp; 14945748Sduboff 14955748Sduboff rdp = (void *)&dp->rx_ring[SFE_DESC_SIZE * slot]; 14965748Sduboff rdp->d_cmdsts = LE_32(CMDSTS_OWN); 14975748Sduboff } 14985748Sduboff 14995748Sduboff /* 15005748Sduboff * Device depend interrupt handler 15015748Sduboff */ 15025748Sduboff static uint_t 15035748Sduboff sfe_interrupt(struct gem_dev *dp) 15045748Sduboff { 15057116Sduboff uint_t rx_ring_size = dp->gc.gc_rx_ring_size; 15065748Sduboff uint32_t isr; 15077116Sduboff uint32_t isr_bogus; 15085748Sduboff uint_t flags = 0; 15095748Sduboff boolean_t need_to_reset = B_FALSE; 15105748Sduboff struct sfe_dev *lp = dp->private; 15115748Sduboff 15125748Sduboff /* read reason and clear interrupt */ 15135748Sduboff isr = INL(dp, ISR); 15145748Sduboff 15157116Sduboff isr_bogus = lp->isr_pended; 15167116Sduboff lp->isr_pended = 0; 15177116Sduboff 15187116Sduboff if (((isr | isr_bogus) & lp->our_intr_bits) == 0) { 15195748Sduboff /* we are not the interrupt source */ 15205748Sduboff return (DDI_INTR_UNCLAIMED); 15215748Sduboff } 15225748Sduboff 15235748Sduboff DPRINTF(3, (CE_CONT, 15245748Sduboff CONS "%s: time:%ld %s:called: isr:0x%b rx_active_head: %d", 15255748Sduboff dp->name, ddi_get_lbolt(), __func__, 15265748Sduboff isr, INTR_BITS, dp->rx_active_head)); 15275748Sduboff 15285748Sduboff if (!dp->mac_active) { 15295748Sduboff /* the device is going to stop */ 15305748Sduboff lp->our_intr_bits = 0; 15315748Sduboff return (DDI_INTR_CLAIMED); 15325748Sduboff } 15335748Sduboff 15345748Sduboff isr &= lp->our_intr_bits; 15355748Sduboff 15365748Sduboff if (isr & (ISR_RXSOVR | ISR_RXORN | ISR_RXIDLE | ISR_RXERR | 15375748Sduboff ISR_RXDESC | ISR_RXOK)) { 15385748Sduboff (void) gem_receive(dp); 15395748Sduboff 15405748Sduboff if (isr & (ISR_RXSOVR | ISR_RXORN)) { 15415748Sduboff DPRINTF(0, (CE_CONT, 15425748Sduboff CONS "%s: rx fifo overrun: isr %b", 15435748Sduboff dp->name, isr, INTR_BITS)); 15445748Sduboff /* no need restart rx */ 15455748Sduboff dp->stats.overflow++; 15465748Sduboff } 15475748Sduboff 15485748Sduboff if (isr & ISR_RXIDLE) { 15495748Sduboff DPRINTF(0, (CE_CONT, 15505748Sduboff CONS "%s: rx buffer ran out: isr %b", 15515748Sduboff dp->name, isr, INTR_BITS)); 15525748Sduboff 15535748Sduboff dp->stats.norcvbuf++; 15545748Sduboff 15555748Sduboff /* 15565748Sduboff * Make RXDP points the head of receive 15575748Sduboff * buffer list. 15585748Sduboff */ 15595748Sduboff OUTL(dp, RXDP, dp->rx_ring_dma + 15605748Sduboff SFE_DESC_SIZE * 15617116Sduboff SLOT(dp->rx_active_head, rx_ring_size)); 15625748Sduboff 15635748Sduboff /* Restart the receive engine */ 15645748Sduboff OUTL(dp, CR, lp->cr | CR_RXE); 15655748Sduboff } 15665748Sduboff } 15675748Sduboff 15685748Sduboff if (isr & (ISR_TXURN | ISR_TXERR | ISR_TXDESC | 15695748Sduboff ISR_TXIDLE | ISR_TXOK)) { 15705748Sduboff /* need to reclaim tx buffers */ 15715748Sduboff if (gem_tx_done(dp)) { 15725748Sduboff flags |= INTR_RESTART_TX; 15735748Sduboff } 15745748Sduboff /* 15755748Sduboff * XXX - tx error statistics will be counted in 15765748Sduboff * sfe_tx_desc_stat() and no need to restart tx on errors. 15775748Sduboff */ 15785748Sduboff } 15795748Sduboff 15805748Sduboff if (isr & (ISR_DPERR | ISR_SSERR | ISR_RMABT | ISR_RTABT)) { 15815748Sduboff cmn_err(CE_WARN, "%s: ERROR interrupt: isr %b.", 15825748Sduboff dp->name, isr, INTR_BITS); 15835748Sduboff need_to_reset = B_TRUE; 15845748Sduboff } 15855748Sduboff reset: 15865748Sduboff if (need_to_reset) { 15875748Sduboff (void) gem_restart_nic(dp, GEM_RESTART_KEEP_BUF); 15885748Sduboff flags |= INTR_RESTART_TX; 15895748Sduboff } 15905748Sduboff 15915748Sduboff DPRINTF(5, (CE_CONT, CONS "%s: %s: return: isr: %b", 15925748Sduboff dp->name, __func__, isr, INTR_BITS)); 15935748Sduboff 15945748Sduboff return (DDI_INTR_CLAIMED | flags); 15955748Sduboff } 15965748Sduboff 15975748Sduboff /* ======================================================== */ 15985748Sduboff /* 15995748Sduboff * HW depend MII routine 16005748Sduboff */ 16015748Sduboff /* ======================================================== */ 16025748Sduboff 16035748Sduboff /* 16045748Sduboff * MII routines for NS DP83815 16055748Sduboff */ 16065748Sduboff static void 16075748Sduboff sfe_mii_sync_dp83815(struct gem_dev *dp) 16085748Sduboff { 16095748Sduboff /* do nothing */ 16105748Sduboff } 16115748Sduboff 16125748Sduboff static uint16_t 16135748Sduboff sfe_mii_read_dp83815(struct gem_dev *dp, uint_t offset) 16145748Sduboff { 16155748Sduboff DPRINTF(4, (CE_CONT, CONS"%s: %s: offset 0x%x", 16165748Sduboff dp->name, __func__, offset)); 16175748Sduboff return ((uint16_t)INL(dp, MII_REGS_BASE + offset*4)); 16185748Sduboff } 16195748Sduboff 16205748Sduboff static void 16215748Sduboff sfe_mii_write_dp83815(struct gem_dev *dp, uint_t offset, uint16_t val) 16225748Sduboff { 16235748Sduboff DPRINTF(4, (CE_CONT, CONS"%s: %s: offset 0x%x 0x%x", 16245748Sduboff dp->name, __func__, offset, val)); 16255748Sduboff OUTL(dp, MII_REGS_BASE + offset*4, val); 16265748Sduboff } 16275748Sduboff 16285748Sduboff static int 16295748Sduboff sfe_mii_config_dp83815(struct gem_dev *dp) 16305748Sduboff { 16315748Sduboff uint32_t srr; 16325748Sduboff 16335748Sduboff srr = INL(dp, SRR) & SRR_REV; 16345748Sduboff 16355748Sduboff DPRINTF(0, (CE_CONT, CONS "%s: srr:0x%04x %04x %04x %04x %04x %04x", 16365748Sduboff dp->name, srr, 16375748Sduboff INW(dp, 0x00cc), /* PGSEL */ 16385748Sduboff INW(dp, 0x00e4), /* PMDCSR */ 16395748Sduboff INW(dp, 0x00fc), /* TSTDAT */ 16405748Sduboff INW(dp, 0x00f4), /* DSPCFG */ 16415748Sduboff INW(dp, 0x00f8))); /* SDCFG */ 16425748Sduboff 16437116Sduboff if (srr == SRR_REV_DP83815CVNG) { 16445748Sduboff /* 16455748Sduboff * NS datasheet says that DP83815CVNG needs following 16465748Sduboff * registers to be patched for optimizing its performance. 16477116Sduboff * A report said that CRC errors on RX disappeared 16485748Sduboff * with the patch. 16495748Sduboff */ 16505748Sduboff OUTW(dp, 0x00cc, 0x0001); /* PGSEL */ 16515748Sduboff OUTW(dp, 0x00e4, 0x189c); /* PMDCSR */ 16525748Sduboff OUTW(dp, 0x00fc, 0x0000); /* TSTDAT */ 16535748Sduboff OUTW(dp, 0x00f4, 0x5040); /* DSPCFG */ 16545748Sduboff OUTW(dp, 0x00f8, 0x008c); /* SDCFG */ 16557116Sduboff OUTW(dp, 0x00cc, 0x0000); /* PGSEL */ 16565748Sduboff 16575748Sduboff DPRINTF(0, (CE_CONT, 16585748Sduboff CONS "%s: PHY patched %04x %04x %04x %04x %04x", 16595748Sduboff dp->name, 16605748Sduboff INW(dp, 0x00cc), /* PGSEL */ 16615748Sduboff INW(dp, 0x00e4), /* PMDCSR */ 16625748Sduboff INW(dp, 0x00fc), /* TSTDAT */ 16635748Sduboff INW(dp, 0x00f4), /* DSPCFG */ 16645748Sduboff INW(dp, 0x00f8))); /* SDCFG */ 16657116Sduboff } else if (((srr ^ SRR_REV_DP83815DVNG) & 0xff00) == 0 || 16667116Sduboff ((srr ^ SRR_REV_DP83816AVNG) & 0xff00) == 0) { 16677116Sduboff /* 16687116Sduboff * Additional packets for later chipset 16697116Sduboff */ 16707116Sduboff OUTW(dp, 0x00cc, 0x0001); /* PGSEL */ 16717116Sduboff OUTW(dp, 0x00e4, 0x189c); /* PMDCSR */ 16727116Sduboff OUTW(dp, 0x00cc, 0x0000); /* PGSEL */ 16737116Sduboff 16747116Sduboff DPRINTF(0, (CE_CONT, 16757116Sduboff CONS "%s: PHY patched %04x %04x", 16767116Sduboff dp->name, 16777116Sduboff INW(dp, 0x00cc), /* PGSEL */ 16787116Sduboff INW(dp, 0x00e4))); /* PMDCSR */ 16795748Sduboff } 16805748Sduboff 16815748Sduboff return (gem_mii_config_default(dp)); 16825748Sduboff } 16835748Sduboff 16847116Sduboff static int 16857116Sduboff sfe_mii_probe_dp83815(struct gem_dev *dp) 16867116Sduboff { 16877116Sduboff uint32_t val; 16887116Sduboff 16897116Sduboff /* try external phy first */ 16907116Sduboff DPRINTF(0, (CE_CONT, CONS "%s: %s: trying external phy", 16917116Sduboff dp->name, __func__)); 16927116Sduboff dp->mii_phy_addr = 0; 16937116Sduboff dp->gc.gc_mii_sync = &sfe_mii_sync_sis900; 16947116Sduboff dp->gc.gc_mii_read = &sfe_mii_read_sis900; 16957116Sduboff dp->gc.gc_mii_write = &sfe_mii_write_sis900; 16967116Sduboff 16977116Sduboff val = INL(dp, CFG) & (CFG_ANEG_SEL | CFG_PHY_CFG); 16987116Sduboff OUTL(dp, CFG, val | CFG_EXT_PHY | CFG_PHY_DIS); 16997116Sduboff 17007116Sduboff if (gem_mii_probe_default(dp) == GEM_SUCCESS) { 17017116Sduboff return (GEM_SUCCESS); 17027116Sduboff } 17037116Sduboff 17047116Sduboff /* switch to internal phy */ 17057116Sduboff DPRINTF(0, (CE_CONT, CONS "%s: %s: switching to internal phy", 17067116Sduboff dp->name, __func__)); 17077116Sduboff dp->mii_phy_addr = -1; 17087116Sduboff dp->gc.gc_mii_sync = &sfe_mii_sync_dp83815; 17097116Sduboff dp->gc.gc_mii_read = &sfe_mii_read_dp83815; 17107116Sduboff dp->gc.gc_mii_write = &sfe_mii_write_dp83815; 17117116Sduboff 17127116Sduboff val = INL(dp, CFG) & (CFG_ANEG_SEL | CFG_PHY_CFG); 17137116Sduboff OUTL(dp, CFG, val | CFG_PAUSE_ADV | CFG_PHY_RST); 17147116Sduboff drv_usecwait(100); /* keep to assert RST bit for a while */ 17157116Sduboff OUTL(dp, CFG, val | CFG_PAUSE_ADV); 17167116Sduboff 17177116Sduboff /* wait for PHY reset */ 17187116Sduboff delay(drv_usectohz(10000)); 17197116Sduboff 17207116Sduboff return (gem_mii_probe_default(dp)); 17217116Sduboff } 17227116Sduboff 17237116Sduboff static int 17247116Sduboff sfe_mii_init_dp83815(struct gem_dev *dp) 17257116Sduboff { 17267116Sduboff uint32_t val; 17277116Sduboff 17287116Sduboff val = INL(dp, CFG) & (CFG_ANEG_SEL | CFG_PHY_CFG); 17297116Sduboff 17307116Sduboff if (dp->mii_phy_addr == -1) { 17317116Sduboff /* select internal phy */ 17327116Sduboff OUTL(dp, CFG, val | CFG_PAUSE_ADV); 17337116Sduboff } else { 17347116Sduboff /* select external phy */ 17357116Sduboff OUTL(dp, CFG, val | CFG_EXT_PHY | CFG_PHY_DIS); 17367116Sduboff } 17377116Sduboff 17387116Sduboff return (GEM_SUCCESS); 17397116Sduboff } 17405748Sduboff 17415748Sduboff /* 17425748Sduboff * MII routines for SiS900 17435748Sduboff */ 17447116Sduboff #define MDIO_DELAY(dp) {(void) INL(dp, MEAR); (void) INL(dp, MEAR); } 17455748Sduboff static void 17465748Sduboff sfe_mii_sync_sis900(struct gem_dev *dp) 17475748Sduboff { 17485748Sduboff int i; 17495748Sduboff 17507116Sduboff /* send 32 ONE's to make MII line idle */ 17515748Sduboff for (i = 0; i < 32; i++) { 17525748Sduboff OUTL(dp, MEAR, MEAR_MDDIR | MEAR_MDIO); 17535748Sduboff MDIO_DELAY(dp); 17545748Sduboff OUTL(dp, MEAR, MEAR_MDDIR | MEAR_MDIO | MEAR_MDC); 17555748Sduboff MDIO_DELAY(dp); 17565748Sduboff } 17575748Sduboff } 17585748Sduboff 17595748Sduboff static int 17605748Sduboff sfe_mii_config_sis900(struct gem_dev *dp) 17615748Sduboff { 17625748Sduboff struct sfe_dev *lp = dp->private; 17635748Sduboff 17645748Sduboff /* Do chip depend setup */ 17655748Sduboff if ((dp->mii_phy_id & PHY_MASK) == PHY_ICS1893) { 17665748Sduboff /* workaround for ICS1893 PHY */ 17675748Sduboff gem_mii_write(dp, 0x0018, 0xD200); 17685748Sduboff } 17695748Sduboff 17705748Sduboff if (lp->revid == SIS630E_900_REV) { 17715748Sduboff /* 17725748Sduboff * SiS 630E has bugs on default values 17735748Sduboff * of PHY registers 17745748Sduboff */ 17755748Sduboff gem_mii_write(dp, MII_AN_ADVERT, 0x05e1); 17765748Sduboff gem_mii_write(dp, MII_CONFIG1, 0x0022); 17775748Sduboff gem_mii_write(dp, MII_CONFIG2, 0xff00); 17785748Sduboff gem_mii_write(dp, MII_MASK, 0xffc0); 17795748Sduboff } 17805748Sduboff sfe_set_eq_sis630(dp); 17815748Sduboff 17825748Sduboff return (gem_mii_config_default(dp)); 17835748Sduboff } 17845748Sduboff 17855748Sduboff static uint16_t 17865748Sduboff sfe_mii_read_sis900(struct gem_dev *dp, uint_t reg) 17875748Sduboff { 17885748Sduboff uint32_t cmd; 17895748Sduboff uint16_t ret; 17905748Sduboff int i; 17915748Sduboff uint32_t data; 17925748Sduboff 17935748Sduboff cmd = MII_READ_CMD(dp->mii_phy_addr, reg); 17945748Sduboff 17955748Sduboff for (i = 31; i >= 18; i--) { 17965748Sduboff data = ((cmd >> i) & 1) << MEAR_MDIO_SHIFT; 17975748Sduboff OUTL(dp, MEAR, data | MEAR_MDDIR); 17985748Sduboff MDIO_DELAY(dp); 17995748Sduboff OUTL(dp, MEAR, data | MEAR_MDDIR | MEAR_MDC); 18005748Sduboff MDIO_DELAY(dp); 18015748Sduboff } 18025748Sduboff 18035748Sduboff /* turn around cycle */ 18047116Sduboff OUTL(dp, MEAR, 0); 18055748Sduboff MDIO_DELAY(dp); 18065748Sduboff 18075748Sduboff /* get response from PHY */ 18085748Sduboff OUTL(dp, MEAR, MEAR_MDC); 18095748Sduboff MDIO_DELAY(dp); 18107116Sduboff 18115748Sduboff OUTL(dp, MEAR, 0); 18125748Sduboff #if DEBUG_LEBEL > 0 18137116Sduboff (void) INL(dp, MEAR); /* delay */ 18145748Sduboff if (INL(dp, MEAR) & MEAR_MDIO) { 18155748Sduboff cmn_err(CE_WARN, "%s: PHY@%d not responded", 18165748Sduboff dp->name, dp->mii_phy_addr); 18175748Sduboff } 18187116Sduboff #else 18197116Sduboff MDIO_DELAY(dp); 18205748Sduboff #endif 18215748Sduboff /* terminate response cycle */ 18225748Sduboff OUTL(dp, MEAR, MEAR_MDC); 18237116Sduboff MDIO_DELAY(dp); 18245748Sduboff 18255748Sduboff ret = 0; /* to avoid lint errors */ 18265748Sduboff for (i = 16; i > 0; i--) { 18275748Sduboff OUTL(dp, MEAR, 0); 18287116Sduboff (void) INL(dp, MEAR); /* delay */ 18295748Sduboff ret = (ret << 1) | ((INL(dp, MEAR) >> MEAR_MDIO_SHIFT) & 1); 18305748Sduboff OUTL(dp, MEAR, MEAR_MDC); 18315748Sduboff MDIO_DELAY(dp); 18325748Sduboff } 18335748Sduboff 18347116Sduboff /* send two idle(Z) bits to terminate the read cycle */ 18357116Sduboff for (i = 0; i < 2; i++) { 18367116Sduboff OUTL(dp, MEAR, 0); 18377116Sduboff MDIO_DELAY(dp); 18387116Sduboff OUTL(dp, MEAR, MEAR_MDC); 18397116Sduboff MDIO_DELAY(dp); 18407116Sduboff } 18415748Sduboff 18425748Sduboff return (ret); 18435748Sduboff } 18445748Sduboff 18455748Sduboff static void 18465748Sduboff sfe_mii_write_sis900(struct gem_dev *dp, uint_t reg, uint16_t val) 18475748Sduboff { 18485748Sduboff uint32_t cmd; 18495748Sduboff int i; 18505748Sduboff uint32_t data; 18515748Sduboff 18525748Sduboff cmd = MII_WRITE_CMD(dp->mii_phy_addr, reg, val); 18535748Sduboff 18545748Sduboff for (i = 31; i >= 0; i--) { 18555748Sduboff data = ((cmd >> i) & 1) << MEAR_MDIO_SHIFT; 18565748Sduboff OUTL(dp, MEAR, data | MEAR_MDDIR); 18575748Sduboff MDIO_DELAY(dp); 18585748Sduboff OUTL(dp, MEAR, data | MEAR_MDDIR | MEAR_MDC); 18595748Sduboff MDIO_DELAY(dp); 18605748Sduboff } 18615748Sduboff 18627116Sduboff /* send two idle(Z) bits to terminate the write cycle. */ 18635748Sduboff for (i = 0; i < 2; i++) { 18647116Sduboff OUTL(dp, MEAR, 0); 18655748Sduboff MDIO_DELAY(dp); 18667116Sduboff OUTL(dp, MEAR, MEAR_MDC); 18675748Sduboff MDIO_DELAY(dp); 18685748Sduboff } 18695748Sduboff } 18705748Sduboff #undef MDIO_DELAY 18715748Sduboff 18725748Sduboff static void 18735748Sduboff sfe_set_eq_sis630(struct gem_dev *dp) 18745748Sduboff { 18755748Sduboff uint16_t reg14h; 18765748Sduboff uint16_t eq_value; 18775748Sduboff uint16_t max_value; 18785748Sduboff uint16_t min_value; 18795748Sduboff int i; 18805748Sduboff uint8_t rev; 18815748Sduboff struct sfe_dev *lp = dp->private; 18825748Sduboff 18835748Sduboff rev = lp->revid; 18845748Sduboff 18855748Sduboff if (!(rev == SIS630E_900_REV || rev == SIS630EA1_900_REV || 18865748Sduboff rev == SIS630A_900_REV || rev == SIS630ET_900_REV)) { 18875748Sduboff /* it doesn't have a internal PHY */ 18885748Sduboff return; 18895748Sduboff } 18905748Sduboff 18915748Sduboff if (dp->mii_state == MII_STATE_LINKUP) { 18925748Sduboff reg14h = gem_mii_read(dp, MII_RESV); 18935748Sduboff gem_mii_write(dp, MII_RESV, (0x2200 | reg14h) & 0xBFFF); 18945748Sduboff 18955748Sduboff eq_value = (0x00f8 & gem_mii_read(dp, MII_RESV)) >> 3; 18965748Sduboff max_value = min_value = eq_value; 18975748Sduboff for (i = 1; i < 10; i++) { 18985748Sduboff eq_value = (0x00f8 & gem_mii_read(dp, MII_RESV)) >> 3; 18995748Sduboff max_value = max(eq_value, max_value); 19005748Sduboff min_value = min(eq_value, min_value); 19015748Sduboff } 19025748Sduboff 19035748Sduboff /* for 630E, rule to determine the equalizer value */ 19045748Sduboff if (rev == SIS630E_900_REV || rev == SIS630EA1_900_REV || 19055748Sduboff rev == SIS630ET_900_REV) { 19065748Sduboff if (max_value < 5) { 19075748Sduboff eq_value = max_value; 19085748Sduboff } else if (5 <= max_value && max_value < 15) { 19095748Sduboff eq_value = 19105748Sduboff max(max_value + 1, 19115748Sduboff min_value + 2); 19125748Sduboff } else if (15 <= max_value) { 19135748Sduboff eq_value = 19145748Sduboff max(max_value + 5, 19155748Sduboff min_value + 6); 19165748Sduboff } 19175748Sduboff } 19185748Sduboff /* for 630B0&B1, rule to determine the equalizer value */ 19195748Sduboff else 19205748Sduboff if (rev == SIS630A_900_REV && 19215748Sduboff (lp->bridge_revid == SIS630B0 || 19225748Sduboff lp->bridge_revid == SIS630B1)) { 19235748Sduboff 19245748Sduboff if (max_value == 0) { 19255748Sduboff eq_value = 3; 19265748Sduboff } else { 19275748Sduboff eq_value = (max_value + min_value + 1)/2; 19285748Sduboff } 19295748Sduboff } 19305748Sduboff /* write equalizer value and setting */ 19315748Sduboff reg14h = gem_mii_read(dp, MII_RESV) & ~0x02f8; 19325748Sduboff reg14h |= 0x6000 | (eq_value << 3); 19335748Sduboff gem_mii_write(dp, MII_RESV, reg14h); 19345748Sduboff } else { 19355748Sduboff reg14h = (gem_mii_read(dp, MII_RESV) & ~0x4000) | 0x2000; 19365748Sduboff if (rev == SIS630A_900_REV && 19375748Sduboff (lp->bridge_revid == SIS630B0 || 19385748Sduboff lp->bridge_revid == SIS630B1)) { 19395748Sduboff 19405748Sduboff reg14h |= 0x0200; 19415748Sduboff } 19425748Sduboff gem_mii_write(dp, MII_RESV, reg14h); 19435748Sduboff } 19445748Sduboff } 19455748Sduboff 19465748Sduboff /* ======================================================== */ 19475748Sduboff /* 19485748Sduboff * OS depend (device driver) routine 19495748Sduboff */ 19505748Sduboff /* ======================================================== */ 19515748Sduboff static void 19525748Sduboff sfe_chipinfo_init_sis900(struct gem_dev *dp) 19535748Sduboff { 19545748Sduboff int rev; 19555748Sduboff struct sfe_dev *lp = (struct sfe_dev *)dp->private; 19565748Sduboff 19575748Sduboff rev = lp->revid; 19585748Sduboff 19595748Sduboff if (rev == SIS630E_900_REV /* 0x81 */) { 19605748Sduboff /* sis630E */ 19615748Sduboff lp->get_mac_addr = &sfe_get_mac_addr_sis630e; 19625748Sduboff } else if (rev > 0x81 && rev <= 0x90) { 19635748Sduboff /* 630S, 630EA1, 630ET, 635A */ 19645748Sduboff lp->get_mac_addr = &sfe_get_mac_addr_sis635; 19655748Sduboff } else if (rev == SIS962_900_REV /* 0x91 */) { 19665748Sduboff /* sis962 or later */ 19675748Sduboff lp->get_mac_addr = &sfe_get_mac_addr_sis962; 19685748Sduboff } else { 19695748Sduboff /* sis900 */ 19705748Sduboff lp->get_mac_addr = &sfe_get_mac_addr_sis900; 19715748Sduboff } 19725748Sduboff 19735748Sduboff lp->bridge_revid = 0; 19745748Sduboff 19755748Sduboff if (rev == SIS630E_900_REV || rev == SIS630EA1_900_REV || 19765748Sduboff rev == SIS630A_900_REV || rev == SIS630ET_900_REV) { 19775748Sduboff /* 19785748Sduboff * read host bridge revision 19795748Sduboff */ 19805748Sduboff dev_info_t *bridge; 19815748Sduboff ddi_acc_handle_t bridge_handle; 19825748Sduboff 19835748Sduboff if ((bridge = sfe_search_pci_dev(0x1039, 0x630)) == NULL) { 19845748Sduboff cmn_err(CE_WARN, 19855748Sduboff "%s: cannot find host bridge (pci1039,630)", 19865748Sduboff dp->name); 19875748Sduboff return; 19885748Sduboff } 19895748Sduboff 19905748Sduboff if (pci_config_setup(bridge, &bridge_handle) != DDI_SUCCESS) { 19915748Sduboff cmn_err(CE_WARN, "%s: pci_config_setup failed", 19925748Sduboff dp->name); 19935748Sduboff return; 19945748Sduboff } 19955748Sduboff 19965748Sduboff lp->bridge_revid = 19975748Sduboff pci_config_get8(bridge_handle, PCI_CONF_REVID); 19985748Sduboff pci_config_teardown(&bridge_handle); 19995748Sduboff } 20005748Sduboff } 20015748Sduboff 20025748Sduboff static int 20035748Sduboff sfe_attach_chip(struct gem_dev *dp) 20045748Sduboff { 20055748Sduboff struct sfe_dev *lp = (struct sfe_dev *)dp->private; 20065748Sduboff 20075748Sduboff DPRINTF(4, (CE_CONT, CONS "!%s: %s called", dp->name, __func__)); 20085748Sduboff 20095748Sduboff /* setup chip-depend get_mac_address function */ 20105748Sduboff if (lp->chip->chip_type == CHIPTYPE_SIS900) { 20115748Sduboff sfe_chipinfo_init_sis900(dp); 20125748Sduboff } else { 20135748Sduboff lp->get_mac_addr = &sfe_get_mac_addr_dp83815; 20145748Sduboff } 20155748Sduboff 20165748Sduboff /* read MAC address */ 20175748Sduboff if (!(lp->get_mac_addr)(dp)) { 20185748Sduboff cmn_err(CE_WARN, 20195748Sduboff "!%s: %s: failed to get factory mac address" 20205748Sduboff " please specify a mac address in sfe.conf", 20215748Sduboff dp->name, __func__); 20225748Sduboff return (GEM_FAILURE); 20235748Sduboff } 20245748Sduboff 20255748Sduboff if (lp->chip->chip_type == CHIPTYPE_DP83815) { 20265748Sduboff dp->mii_phy_addr = -1; /* no need to scan PHY */ 20275748Sduboff dp->misc_flag |= GEM_VLAN_SOFT; 20285748Sduboff dp->txthr += 4; /* VTAG_SIZE */ 20295748Sduboff } 20305748Sduboff dp->txthr = min(dp->txthr, TXFIFOSIZE - 2); 20315748Sduboff 20325748Sduboff return (GEM_SUCCESS); 20335748Sduboff } 20345748Sduboff 20355748Sduboff static int 20365748Sduboff sfeattach(dev_info_t *dip, ddi_attach_cmd_t cmd) 20375748Sduboff { 20385748Sduboff int unit; 20395748Sduboff const char *drv_name; 20405748Sduboff int i; 20415748Sduboff ddi_acc_handle_t conf_handle; 20425748Sduboff uint16_t vid; 20435748Sduboff uint16_t did; 20445748Sduboff uint8_t rev; 20455748Sduboff #ifdef DEBUG_LEVEL 20465748Sduboff uint32_t iline; 20475748Sduboff uint8_t latim; 20485748Sduboff #endif 20495748Sduboff struct chip_info *p; 20505748Sduboff struct gem_dev *dp; 20515748Sduboff struct sfe_dev *lp; 20525748Sduboff caddr_t base; 20535748Sduboff ddi_acc_handle_t regs_ha; 20545748Sduboff struct gem_conf *gcp; 20555748Sduboff 20565748Sduboff unit = ddi_get_instance(dip); 20575748Sduboff drv_name = ddi_driver_name(dip); 20585748Sduboff 20595748Sduboff DPRINTF(3, (CE_CONT, CONS "%s%d: sfeattach: called", drv_name, unit)); 20605748Sduboff 20615748Sduboff /* 20625748Sduboff * Common codes after power-up 20635748Sduboff */ 20645748Sduboff if (pci_config_setup(dip, &conf_handle) != DDI_SUCCESS) { 20655748Sduboff cmn_err(CE_WARN, "%s%d: ddi_regs_map_setup failed", 20665748Sduboff drv_name, unit); 20675748Sduboff goto err; 20685748Sduboff } 20695748Sduboff 20705748Sduboff vid = pci_config_get16(conf_handle, PCI_CONF_VENID); 20715748Sduboff did = pci_config_get16(conf_handle, PCI_CONF_DEVID); 20725748Sduboff rev = pci_config_get16(conf_handle, PCI_CONF_REVID); 20735748Sduboff #ifdef DEBUG_LEVEL 20747116Sduboff iline = pci_config_get32(conf_handle, PCI_CONF_ILINE); 20757116Sduboff latim = pci_config_get8(conf_handle, PCI_CONF_LATENCY_TIMER); 20765748Sduboff #endif 20775748Sduboff #ifdef DEBUG_BUILT_IN_SIS900 20785748Sduboff rev = SIS630E_900_REV; 20795748Sduboff #endif 20805748Sduboff for (i = 0, p = sfe_chiptbl; i < CHIPTABLESIZE; i++, p++) { 20815748Sduboff if (p->venid == vid && p->devid == did) { 20825748Sduboff /* found */ 20835748Sduboff goto chip_found; 20845748Sduboff } 20855748Sduboff } 20865748Sduboff 20875748Sduboff /* Not found */ 20885748Sduboff cmn_err(CE_WARN, 20895748Sduboff "%s%d: sfe_attach: wrong PCI venid/devid (0x%x, 0x%x)", 20905748Sduboff drv_name, unit, vid, did); 20915748Sduboff pci_config_teardown(&conf_handle); 20925748Sduboff goto err; 20935748Sduboff 20945748Sduboff chip_found: 20955748Sduboff pci_config_put16(conf_handle, PCI_CONF_COMM, 20965748Sduboff PCI_COMM_IO | PCI_COMM_MAE | PCI_COMM_ME | 20975748Sduboff pci_config_get16(conf_handle, PCI_CONF_COMM)); 20985748Sduboff 20995748Sduboff /* ensure D0 mode */ 21005748Sduboff (void) gem_pci_set_power_state(dip, conf_handle, PCI_PMCSR_D0); 21015748Sduboff 21025748Sduboff pci_config_teardown(&conf_handle); 21035748Sduboff 21045748Sduboff switch (cmd) { 21055748Sduboff case DDI_RESUME: 21065748Sduboff return (gem_resume(dip)); 21075748Sduboff 21085748Sduboff case DDI_ATTACH: 21095748Sduboff 21105748Sduboff DPRINTF(0, (CE_CONT, 21115748Sduboff CONS "%s%d: ilr 0x%08x, latency_timer:0x%02x", 21125748Sduboff drv_name, unit, iline, latim)); 21135748Sduboff 21145748Sduboff /* 21155748Sduboff * Map in the device registers. 21165748Sduboff */ 21175748Sduboff if (gem_pci_regs_map_setup(dip, 21185748Sduboff (sfe_use_pcimemspace && p->chip_type == CHIPTYPE_DP83815) 21195748Sduboff ? PCI_ADDR_MEM32 : PCI_ADDR_IO, PCI_ADDR_MASK, 21205748Sduboff &sfe_dev_attr, &base, ®s_ha) != DDI_SUCCESS) { 21215748Sduboff cmn_err(CE_WARN, 21225748Sduboff "%s%d: ddi_regs_map_setup failed", 21235748Sduboff drv_name, unit); 21245748Sduboff goto err; 21255748Sduboff } 21265748Sduboff 21275748Sduboff /* 21285748Sduboff * construct gem configuration 21295748Sduboff */ 21305748Sduboff gcp = kmem_zalloc(sizeof (*gcp), KM_SLEEP); 21315748Sduboff 21325748Sduboff /* name */ 21335748Sduboff (void) sprintf(gcp->gc_name, "%s%d", drv_name, unit); 21345748Sduboff 21355748Sduboff /* consistency on tx and rx */ 21365748Sduboff gcp->gc_tx_buf_align = sizeof (uint8_t) - 1; 21375748Sduboff gcp->gc_tx_max_frags = MAXTXFRAGS; 21385748Sduboff gcp->gc_tx_max_descs_per_pkt = gcp->gc_tx_max_frags; 21395748Sduboff gcp->gc_tx_desc_unit_shift = 4; /* 16 byte */ 21405748Sduboff gcp->gc_tx_buf_size = TX_BUF_SIZE; 21415748Sduboff gcp->gc_tx_buf_limit = gcp->gc_tx_buf_size; 21425748Sduboff gcp->gc_tx_ring_size = TX_RING_SIZE; 21435748Sduboff gcp->gc_tx_ring_limit = gcp->gc_tx_ring_size; 21445748Sduboff gcp->gc_tx_auto_pad = B_TRUE; 21455748Sduboff gcp->gc_tx_copy_thresh = sfe_tx_copy_thresh; 21465748Sduboff gcp->gc_tx_desc_write_oo = B_TRUE; 21475748Sduboff 21485748Sduboff gcp->gc_rx_buf_align = sizeof (uint8_t) - 1; 21495748Sduboff gcp->gc_rx_max_frags = MAXRXFRAGS; 21505748Sduboff gcp->gc_rx_desc_unit_shift = 4; 21515748Sduboff gcp->gc_rx_ring_size = RX_RING_SIZE; 21525748Sduboff gcp->gc_rx_buf_max = RX_BUF_SIZE; 21535748Sduboff gcp->gc_rx_copy_thresh = sfe_rx_copy_thresh; 21545748Sduboff 21555748Sduboff /* map attributes */ 21565748Sduboff gcp->gc_dev_attr = sfe_dev_attr; 21575748Sduboff gcp->gc_buf_attr = sfe_buf_attr; 21585748Sduboff gcp->gc_desc_attr = sfe_buf_attr; 21595748Sduboff 21605748Sduboff /* dma attributes */ 21615748Sduboff gcp->gc_dma_attr_desc = sfe_dma_attr_desc; 21625748Sduboff 21635748Sduboff gcp->gc_dma_attr_txbuf = sfe_dma_attr_buf; 21645748Sduboff gcp->gc_dma_attr_txbuf.dma_attr_align = gcp->gc_tx_buf_align+1; 21655748Sduboff gcp->gc_dma_attr_txbuf.dma_attr_sgllen = gcp->gc_tx_max_frags; 21665748Sduboff 21675748Sduboff gcp->gc_dma_attr_rxbuf = sfe_dma_attr_buf; 21685748Sduboff gcp->gc_dma_attr_rxbuf.dma_attr_align = gcp->gc_rx_buf_align+1; 21695748Sduboff gcp->gc_dma_attr_rxbuf.dma_attr_sgllen = gcp->gc_rx_max_frags; 21705748Sduboff 21715748Sduboff /* time out parameters */ 21725748Sduboff gcp->gc_tx_timeout = 3*ONESEC; 21735748Sduboff gcp->gc_tx_timeout_interval = ONESEC; 21747116Sduboff if (p->chip_type == CHIPTYPE_DP83815) { 21757116Sduboff /* workaround for tx hang */ 21767116Sduboff gcp->gc_tx_timeout_interval = ONESEC/20; /* 50mS */ 21777116Sduboff } 21785748Sduboff 21795748Sduboff /* MII timeout parameters */ 21805748Sduboff gcp->gc_mii_link_watch_interval = ONESEC; 21815748Sduboff gcp->gc_mii_an_watch_interval = ONESEC/5; 21825748Sduboff gcp->gc_mii_reset_timeout = MII_RESET_TIMEOUT; /* 1 sec */ 21835748Sduboff gcp->gc_mii_an_timeout = MII_AN_TIMEOUT; /* 5 sec */ 21845748Sduboff gcp->gc_mii_an_wait = 0; 21855748Sduboff gcp->gc_mii_linkdown_timeout = MII_LINKDOWN_TIMEOUT; 21865748Sduboff 21875748Sduboff /* setting for general PHY */ 21885748Sduboff gcp->gc_mii_an_delay = 0; 21895748Sduboff gcp->gc_mii_linkdown_action = MII_ACTION_RSA; 21905748Sduboff gcp->gc_mii_linkdown_timeout_action = MII_ACTION_RESET; 21915748Sduboff gcp->gc_mii_dont_reset = B_FALSE; 21925748Sduboff 21935748Sduboff 21945748Sduboff /* I/O methods */ 21955748Sduboff 21965748Sduboff /* mac operation */ 21975748Sduboff gcp->gc_attach_chip = &sfe_attach_chip; 21985748Sduboff if (p->chip_type == CHIPTYPE_DP83815) { 21995748Sduboff gcp->gc_reset_chip = &sfe_reset_chip_dp83815; 22005748Sduboff } else { 22015748Sduboff gcp->gc_reset_chip = &sfe_reset_chip_sis900; 22025748Sduboff } 22035748Sduboff gcp->gc_init_chip = &sfe_init_chip; 22045748Sduboff gcp->gc_start_chip = &sfe_start_chip; 22055748Sduboff gcp->gc_stop_chip = &sfe_stop_chip; 22065748Sduboff #ifdef USE_MULTICAST_HASHTBL 22075748Sduboff gcp->gc_multicast_hash = &sfe_mcast_hash; 22085748Sduboff #endif 22095748Sduboff if (p->chip_type == CHIPTYPE_DP83815) { 22105748Sduboff gcp->gc_set_rx_filter = &sfe_set_rx_filter_dp83815; 22115748Sduboff } else { 22125748Sduboff gcp->gc_set_rx_filter = &sfe_set_rx_filter_sis900; 22135748Sduboff } 22145748Sduboff gcp->gc_set_media = &sfe_set_media; 22155748Sduboff gcp->gc_get_stats = &sfe_get_stats; 22165748Sduboff gcp->gc_interrupt = &sfe_interrupt; 22175748Sduboff 22185748Sduboff /* descriptor operation */ 22195748Sduboff gcp->gc_tx_desc_write = &sfe_tx_desc_write; 22205748Sduboff gcp->gc_tx_start = &sfe_tx_start; 22215748Sduboff gcp->gc_rx_desc_write = &sfe_rx_desc_write; 22225748Sduboff gcp->gc_rx_start = NULL; 22235748Sduboff 22245748Sduboff gcp->gc_tx_desc_stat = &sfe_tx_desc_stat; 22255748Sduboff gcp->gc_rx_desc_stat = &sfe_rx_desc_stat; 22265748Sduboff gcp->gc_tx_desc_init = &sfe_tx_desc_init; 22275748Sduboff gcp->gc_rx_desc_init = &sfe_rx_desc_init; 22285748Sduboff gcp->gc_tx_desc_clean = &sfe_tx_desc_clean; 22295748Sduboff gcp->gc_rx_desc_clean = &sfe_rx_desc_clean; 22305748Sduboff 22315748Sduboff /* mii operations */ 22325748Sduboff if (p->chip_type == CHIPTYPE_DP83815) { 22337116Sduboff gcp->gc_mii_probe = &sfe_mii_probe_dp83815; 22347116Sduboff gcp->gc_mii_init = &sfe_mii_init_dp83815; 22355748Sduboff gcp->gc_mii_config = &sfe_mii_config_dp83815; 22365748Sduboff gcp->gc_mii_sync = &sfe_mii_sync_dp83815; 22375748Sduboff gcp->gc_mii_read = &sfe_mii_read_dp83815; 22385748Sduboff gcp->gc_mii_write = &sfe_mii_write_dp83815; 22395748Sduboff gcp->gc_mii_tune_phy = NULL; 22405748Sduboff gcp->gc_flow_control = FLOW_CONTROL_NONE; 22415748Sduboff } else { 22425748Sduboff gcp->gc_mii_probe = &gem_mii_probe_default; 22435748Sduboff gcp->gc_mii_init = NULL; 22445748Sduboff gcp->gc_mii_config = &sfe_mii_config_sis900; 22455748Sduboff gcp->gc_mii_sync = &sfe_mii_sync_sis900; 22465748Sduboff gcp->gc_mii_read = &sfe_mii_read_sis900; 22475748Sduboff gcp->gc_mii_write = &sfe_mii_write_sis900; 22485748Sduboff gcp->gc_mii_tune_phy = &sfe_set_eq_sis630; 22495748Sduboff gcp->gc_flow_control = FLOW_CONTROL_RX_PAUSE; 22505748Sduboff } 22515748Sduboff 22525748Sduboff lp = kmem_zalloc(sizeof (*lp), KM_SLEEP); 22535748Sduboff lp->chip = p; 22545748Sduboff lp->revid = rev; 22557116Sduboff lp->our_intr_bits = 0; 22567116Sduboff lp->isr_pended = 0; 22575748Sduboff 22585748Sduboff cmn_err(CE_CONT, CONS "%s%d: chip:%s rev:0x%02x", 22595748Sduboff drv_name, unit, p->chip_name, rev); 22605748Sduboff 22615748Sduboff dp = gem_do_attach(dip, 0, gcp, base, ®s_ha, 22625748Sduboff lp, sizeof (*lp)); 22635748Sduboff kmem_free(gcp, sizeof (*gcp)); 22645748Sduboff 22655748Sduboff if (dp == NULL) { 22665748Sduboff goto err_freelp; 22675748Sduboff } 22685748Sduboff 22695748Sduboff return (DDI_SUCCESS); 22705748Sduboff 22715748Sduboff err_freelp: 22725748Sduboff kmem_free(lp, sizeof (struct sfe_dev)); 22735748Sduboff err: 22745748Sduboff return (DDI_FAILURE); 22755748Sduboff } 22765748Sduboff return (DDI_FAILURE); 22775748Sduboff } 22785748Sduboff 22795748Sduboff static int 22805748Sduboff sfedetach(dev_info_t *dip, ddi_detach_cmd_t cmd) 22815748Sduboff { 22825748Sduboff switch (cmd) { 22835748Sduboff case DDI_SUSPEND: 22845748Sduboff return (gem_suspend(dip)); 22855748Sduboff 22865748Sduboff case DDI_DETACH: 22875748Sduboff return (gem_do_detach(dip)); 22885748Sduboff } 22895748Sduboff return (DDI_FAILURE); 22905748Sduboff } 22915748Sduboff 22925748Sduboff /* ======================================================== */ 22935748Sduboff /* 22945748Sduboff * OS depend (loadable streams driver) routine 22955748Sduboff */ 22965748Sduboff /* ======================================================== */ 22975748Sduboff DDI_DEFINE_STREAM_OPS(sfe_ops, nulldev, nulldev, sfeattach, sfedetach, 2298*7656SSherry.Moore@Sun.COM nodev, NULL, D_MP, NULL, ddi_quiesce_not_supported); 22995748Sduboff 23005748Sduboff static struct modldrv modldrv = { 23015748Sduboff &mod_driverops, /* Type of module. This one is a driver */ 23025748Sduboff ident, 23035748Sduboff &sfe_ops, /* driver ops */ 23045748Sduboff }; 23055748Sduboff 23065748Sduboff static struct modlinkage modlinkage = { 23075748Sduboff MODREV_1, &modldrv, NULL 23085748Sduboff }; 23095748Sduboff 23105748Sduboff /* ======================================================== */ 23115748Sduboff /* 23125748Sduboff * Loadable module support 23135748Sduboff */ 23145748Sduboff /* ======================================================== */ 23155748Sduboff int 23165748Sduboff _init(void) 23175748Sduboff { 23185748Sduboff int status; 23195748Sduboff 23205748Sduboff DPRINTF(2, (CE_CONT, CONS "sfe: _init: called")); 23215748Sduboff gem_mod_init(&sfe_ops, "sfe"); 23225748Sduboff status = mod_install(&modlinkage); 23235748Sduboff if (status != DDI_SUCCESS) { 23245748Sduboff gem_mod_fini(&sfe_ops); 23255748Sduboff } 23265748Sduboff return (status); 23275748Sduboff } 23285748Sduboff 23295748Sduboff /* 23305748Sduboff * _fini : done 23315748Sduboff */ 23325748Sduboff int 23335748Sduboff _fini(void) 23345748Sduboff { 23355748Sduboff int status; 23365748Sduboff 23375748Sduboff DPRINTF(2, (CE_CONT, CONS "sfe: _fini: called")); 23385748Sduboff status = mod_remove(&modlinkage); 23395748Sduboff if (status == DDI_SUCCESS) { 23405748Sduboff gem_mod_fini(&sfe_ops); 23415748Sduboff } 23425748Sduboff return (status); 23435748Sduboff } 23445748Sduboff 23455748Sduboff int 23465748Sduboff _info(struct modinfo *modinfop) 23475748Sduboff { 23485748Sduboff return (mod_info(&modlinkage, modinfop)); 23495748Sduboff } 2350