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 347656SSherry.Moore@Sun.COM /* 35*8611SSherry.Moore@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 367656SSherry.Moore@Sun.COM * Use is subject to license terms. 377656SSherry.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*8611SSherry.Moore@Sun.COM char ident[] = "sis900/dp83815 driver v" "2.6.1t30os"; 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 5407893SAlan.Duboff@Sun.COM OUTLINL(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) { 8257893SAlan.Duboff@Sun.COM /* disable rx filter */ 8267893SAlan.Duboff@Sun.COM OUTLINL(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 */ 8657893SAlan.Duboff@Sun.COM OUTLINL(dp, RFCR, 8665748Sduboff (RFADDR_MAC_SIS900+i) << RFCR_RFADDR_SHIFT_SIS900); 8677893SAlan.Duboff@Sun.COM OUTLINL(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 */ 8767893SAlan.Duboff@Sun.COM OUTLINL(dp, RFCR, 8775748Sduboff (RFADDR_MULTICAST_SIS900 + i) << RFCR_RFADDR_SHIFT_SIS900); 8787893SAlan.Duboff@Sun.COM OUTLINL(dp, RFDR, hash_tbl[i]); 8795748Sduboff } 8805748Sduboff 8815748Sduboff /* Load rx filter mode and enable rx filter */ 8827893SAlan.Duboff@Sun.COM OUTLINL(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 955*8611SSherry.Moore@Sun.COM #ifndef __sparc 956*8611SSherry.Moore@Sun.COM /* 957*8611SSherry.Moore@Sun.COM * Stop nic core gracefully for quiesce 958*8611SSherry.Moore@Sun.COM */ 959*8611SSherry.Moore@Sun.COM static int 960*8611SSherry.Moore@Sun.COM sfe_stop_chip_quiesce(struct gem_dev *dp) 961*8611SSherry.Moore@Sun.COM { 962*8611SSherry.Moore@Sun.COM struct sfe_dev *lp = dp->private; 963*8611SSherry.Moore@Sun.COM uint32_t done; 964*8611SSherry.Moore@Sun.COM int i; 965*8611SSherry.Moore@Sun.COM uint32_t val; 966*8611SSherry.Moore@Sun.COM 967*8611SSherry.Moore@Sun.COM /* 968*8611SSherry.Moore@Sun.COM * Although we inhibit interrupt here, we don't clear soft copy of 969*8611SSherry.Moore@Sun.COM * interrupt mask to avoid bogus interrupts. 970*8611SSherry.Moore@Sun.COM */ 971*8611SSherry.Moore@Sun.COM OUTL(dp, IMR, 0); 972*8611SSherry.Moore@Sun.COM 973*8611SSherry.Moore@Sun.COM /* stop TX and RX immediately */ 974*8611SSherry.Moore@Sun.COM OUTL(dp, CR, CR_TXR | CR_RXR); 975*8611SSherry.Moore@Sun.COM 976*8611SSherry.Moore@Sun.COM done = 0; 977*8611SSherry.Moore@Sun.COM for (i = 0; done != (ISR_RXRCMP | ISR_TXRCMP); i++) { 978*8611SSherry.Moore@Sun.COM if (i > 1000) { 979*8611SSherry.Moore@Sun.COM /* 980*8611SSherry.Moore@Sun.COM * As gem layer will call sfe_reset_chip(), 981*8611SSherry.Moore@Sun.COM * we don't neet to reset futher 982*8611SSherry.Moore@Sun.COM */ 983*8611SSherry.Moore@Sun.COM 984*8611SSherry.Moore@Sun.COM return (DDI_FAILURE); 985*8611SSherry.Moore@Sun.COM } 986*8611SSherry.Moore@Sun.COM val = INL(dp, ISR); 987*8611SSherry.Moore@Sun.COM done |= val & (ISR_RXRCMP | ISR_TXRCMP); 988*8611SSherry.Moore@Sun.COM lp->isr_pended |= val & lp->our_intr_bits; 989*8611SSherry.Moore@Sun.COM drv_usecwait(10); 990*8611SSherry.Moore@Sun.COM } 991*8611SSherry.Moore@Sun.COM return (DDI_SUCCESS); 992*8611SSherry.Moore@Sun.COM } 993*8611SSherry.Moore@Sun.COM #endif 994*8611SSherry.Moore@Sun.COM 9955748Sduboff /* 9965748Sduboff * Setup media mode 9975748Sduboff */ 9985748Sduboff static uint_t 9995748Sduboff sfe_mxdma_value[] = { 512, 4, 8, 16, 32, 64, 128, 256, }; 10005748Sduboff 10015748Sduboff static uint_t 10025748Sduboff sfe_encode_mxdma(uint_t burstsize) 10035748Sduboff { 10045748Sduboff int i; 10055748Sduboff 10065748Sduboff if (burstsize > 256) { 10075748Sduboff /* choose 512 */ 10085748Sduboff return (0); 10095748Sduboff } 10105748Sduboff 10115748Sduboff for (i = 1; i < 8; i++) { 10125748Sduboff if (burstsize <= sfe_mxdma_value[i]) { 10135748Sduboff break; 10145748Sduboff } 10155748Sduboff } 10165748Sduboff return (i); 10175748Sduboff } 10185748Sduboff 10195748Sduboff static int 10205748Sduboff sfe_set_media(struct gem_dev *dp) 10215748Sduboff { 10225748Sduboff uint32_t txcfg; 10235748Sduboff uint32_t rxcfg; 10245748Sduboff uint32_t pcr; 10255748Sduboff uint32_t val; 10265748Sduboff uint32_t txmxdma; 10275748Sduboff uint32_t rxmxdma; 10285748Sduboff struct sfe_dev *lp = dp->private; 10295748Sduboff #ifdef DEBUG_LEVEL 10305748Sduboff extern int gem_speed_value[]; 10315748Sduboff #endif 10325748Sduboff DPRINTF(2, (CE_CONT, CONS "%s: %s: %s duplex, %d Mbps", 10335748Sduboff dp->name, __func__, 10345748Sduboff dp->full_duplex ? "full" : "half", gem_speed_value[dp->speed])); 10355748Sduboff 10365748Sduboff /* initialize txcfg and rxcfg */ 10375748Sduboff txcfg = TXCFG_ATP; 10385748Sduboff if (dp->full_duplex) { 10395748Sduboff txcfg |= (TXCFG_CSI | TXCFG_HBI); 10405748Sduboff } 10417116Sduboff rxcfg = RXCFG_AEP | RXCFG_ARP; 10425748Sduboff if (dp->full_duplex) { 10435748Sduboff rxcfg |= RXCFG_ATX; 10445748Sduboff } 10455748Sduboff 10465748Sduboff /* select txmxdma and rxmxdma, maxmum burst length */ 10475748Sduboff if (lp->chip->chip_type == CHIPTYPE_SIS900) { 10485748Sduboff #ifdef DEBUG_SIS900_EDB 10495748Sduboff val = CFG_EDB_MASTER; 10505748Sduboff #else 10515748Sduboff val = INL(dp, CFG) & CFG_EDB_MASTER; 10525748Sduboff #endif 10535748Sduboff if (val) { 10545748Sduboff /* 10555748Sduboff * sis900 built-in cores: 10565748Sduboff * max burst length must be fixed to 64 10575748Sduboff */ 10585748Sduboff txmxdma = 64; 10595748Sduboff rxmxdma = 64; 10605748Sduboff } else { 10615748Sduboff /* 10625748Sduboff * sis900 pci chipset: 10635748Sduboff * the vendor recommended to fix max burst length 10645748Sduboff * to 512 10655748Sduboff */ 10665748Sduboff txmxdma = 512; 10675748Sduboff rxmxdma = 512; 10685748Sduboff } 10695748Sduboff } else { 10705748Sduboff /* 10715748Sduboff * NS dp83815/816: 10725748Sduboff * use user defined or default for tx/rx max burst length 10735748Sduboff */ 10745748Sduboff txmxdma = max(dp->txmaxdma, 256); 10755748Sduboff rxmxdma = max(dp->rxmaxdma, 256); 10765748Sduboff } 10775748Sduboff 10785748Sduboff 10795748Sduboff /* tx high water mark */ 10805748Sduboff lp->tx_drain_threshold = ROUNDUP2(dp->txthr, TXCFG_FIFO_UNIT); 10815748Sduboff 10825748Sduboff /* determine tx_fill_threshold accroding drain threshold */ 10835748Sduboff lp->tx_fill_threshold = 10845748Sduboff TXFIFOSIZE - lp->tx_drain_threshold - TXCFG_FIFO_UNIT; 10855748Sduboff 10865748Sduboff /* tune txmxdma not to exceed tx_fill_threshold */ 10875748Sduboff for (; ; ) { 10885748Sduboff /* normalize txmxdma requested */ 10895748Sduboff val = sfe_encode_mxdma(txmxdma); 10905748Sduboff txmxdma = sfe_mxdma_value[val]; 10915748Sduboff 10925748Sduboff if (txmxdma <= lp->tx_fill_threshold) { 10935748Sduboff break; 10945748Sduboff } 10955748Sduboff /* select new txmxdma */ 10965748Sduboff txmxdma = txmxdma / 2; 10975748Sduboff } 10985748Sduboff txcfg |= val << TXCFG_MXDMA_SHIFT; 10995748Sduboff 11005748Sduboff /* encode rxmxdma, maxmum burst length for rx */ 11015748Sduboff val = sfe_encode_mxdma(rxmxdma); 11027116Sduboff rxcfg |= val << RXCFG_MXDMA_SHIFT; 11035748Sduboff rxmxdma = sfe_mxdma_value[val]; 11045748Sduboff 11055748Sduboff /* receive starting threshold - it have only 5bit-wide field */ 11065748Sduboff val = ROUNDUP2(max(dp->rxthr, ETHERMIN), RXCFG_FIFO_UNIT); 11075748Sduboff lp->rx_drain_threshold = 11085748Sduboff min(val, (RXCFG_DRTH >> RXCFG_DRTH_SHIFT) * RXCFG_FIFO_UNIT); 11095748Sduboff 11105748Sduboff DPRINTF(0, (CE_CONT, 11115748Sduboff "%s: %s: tx: drain:%d(rest %d) fill:%d mxdma:%d," 11125748Sduboff " rx: drain:%d mxdma:%d", 11135748Sduboff dp->name, __func__, 11145748Sduboff lp->tx_drain_threshold, TXFIFOSIZE - lp->tx_drain_threshold, 11155748Sduboff lp->tx_fill_threshold, txmxdma, 11165748Sduboff lp->rx_drain_threshold, rxmxdma)); 11175748Sduboff 11185748Sduboff ASSERT(lp->tx_drain_threshold < 64*TXCFG_FIFO_UNIT); 11195748Sduboff ASSERT(lp->tx_fill_threshold < 64*TXCFG_FIFO_UNIT); 11205748Sduboff ASSERT(lp->rx_drain_threshold < 32*RXCFG_FIFO_UNIT); 11215748Sduboff 11225748Sduboff txcfg |= ((lp->tx_fill_threshold/TXCFG_FIFO_UNIT) << TXCFG_FLTH_SHIFT) 11235748Sduboff | (lp->tx_drain_threshold/TXCFG_FIFO_UNIT); 11245748Sduboff OUTL(dp, TXCFG, txcfg); 11255748Sduboff 11265748Sduboff rxcfg |= ((lp->rx_drain_threshold/RXCFG_FIFO_UNIT) << RXCFG_DRTH_SHIFT); 11275748Sduboff if (lp->chip->chip_type == CHIPTYPE_DP83815) { 11285748Sduboff rxcfg |= RXCFG_ALP_DP83815; 11295748Sduboff } 11305748Sduboff OUTL(dp, RXCFG, rxcfg); 11315748Sduboff 11325748Sduboff DPRINTF(0, (CE_CONT, CONS "%s: %s: txcfg:%b rxcfg:%b", 11335748Sduboff dp->name, __func__, 11345748Sduboff txcfg, TXCFG_BITS, rxcfg, RXCFG_BITS)); 11355748Sduboff 11365748Sduboff /* Flow control */ 11375748Sduboff if (lp->chip->chip_type == CHIPTYPE_DP83815) { 11385748Sduboff pcr = INL(dp, PCR); 11395748Sduboff switch (dp->flow_control) { 11405748Sduboff case FLOW_CONTROL_SYMMETRIC: 11415748Sduboff case FLOW_CONTROL_RX_PAUSE: 11425748Sduboff OUTL(dp, PCR, pcr | PCR_PSEN | PCR_PS_MCAST); 11435748Sduboff break; 11445748Sduboff 11455748Sduboff default: 11465748Sduboff OUTL(dp, PCR, 11475748Sduboff pcr & ~(PCR_PSEN | PCR_PS_MCAST | PCR_PS_DA)); 11485748Sduboff break; 11495748Sduboff } 11505748Sduboff DPRINTF(2, (CE_CONT, CONS "%s: PCR: %b", dp->name, 11515748Sduboff INL(dp, PCR), PCR_BITS)); 11525748Sduboff 11535748Sduboff } else if (lp->chip->chip_type == CHIPTYPE_SIS900) { 11545748Sduboff switch (dp->flow_control) { 11555748Sduboff case FLOW_CONTROL_SYMMETRIC: 11565748Sduboff case FLOW_CONTROL_RX_PAUSE: 11575748Sduboff OUTL(dp, FLOWCTL, FLOWCTL_FLOWEN); 11585748Sduboff break; 11595748Sduboff default: 11605748Sduboff OUTL(dp, FLOWCTL, 0); 11615748Sduboff break; 11625748Sduboff } 11635748Sduboff DPRINTF(2, (CE_CONT, CONS "%s: FLOWCTL: %b", 11645748Sduboff dp->name, INL(dp, FLOWCTL), FLOWCTL_BITS)); 11655748Sduboff } 11665748Sduboff return (GEM_SUCCESS); 11675748Sduboff } 11685748Sduboff 11695748Sduboff static int 11705748Sduboff sfe_get_stats(struct gem_dev *dp) 11715748Sduboff { 11725748Sduboff /* do nothing */ 11735748Sduboff return (GEM_SUCCESS); 11745748Sduboff } 11755748Sduboff 11765748Sduboff /* 11775748Sduboff * descriptor manipulations 11785748Sduboff */ 11795748Sduboff static int 11805748Sduboff sfe_tx_desc_write(struct gem_dev *dp, int slot, 11815748Sduboff ddi_dma_cookie_t *dmacookie, int frags, uint64_t flags) 11825748Sduboff { 11835748Sduboff uint32_t mark; 11845748Sduboff struct sfe_desc *tdp; 11855748Sduboff ddi_dma_cookie_t *dcp; 11867116Sduboff uint32_t tmp0; 11877116Sduboff #if DEBUG_LEVEL > 2 11885748Sduboff int i; 11895748Sduboff 11905748Sduboff cmn_err(CE_CONT, 11915748Sduboff CONS "%s: time:%d %s seqnum: %d, slot %d, frags: %d flags: %llx", 11925748Sduboff dp->name, ddi_get_lbolt(), __func__, 11935748Sduboff dp->tx_desc_tail, slot, frags, flags); 11945748Sduboff 11955748Sduboff for (i = 0; i < frags; i++) { 11965748Sduboff cmn_err(CE_CONT, CONS "%d: addr: 0x%x, len: 0x%x", 11975748Sduboff i, dmacookie[i].dmac_address, dmacookie[i].dmac_size); 11987116Sduboff } 11995748Sduboff #endif 12005748Sduboff /* 12015748Sduboff * write tx descriptor in reversed order. 12025748Sduboff */ 12035748Sduboff #if DEBUG_LEVEL > 3 12045748Sduboff flags |= GEM_TXFLAG_INTR; 12055748Sduboff #endif 12065748Sduboff mark = (flags & GEM_TXFLAG_INTR) 12077116Sduboff ? (CMDSTS_OWN | CMDSTS_INTR) : CMDSTS_OWN; 12085748Sduboff 12095748Sduboff ASSERT(frags == 1); 12105748Sduboff dcp = &dmacookie[0]; 12115748Sduboff if (flags & GEM_TXFLAG_HEAD) { 12125748Sduboff mark &= ~CMDSTS_OWN; 12135748Sduboff } 12145748Sduboff 12155748Sduboff tdp = (void *)&dp->tx_ring[SFE_DESC_SIZE * slot]; 12167116Sduboff tmp0 = (uint32_t)dcp->dmac_address; 12177116Sduboff mark |= (uint32_t)dcp->dmac_size; 12187116Sduboff tdp->d_bufptr = LE_32(tmp0); 12197116Sduboff tdp->d_cmdsts = LE_32(mark); 12205748Sduboff 12215748Sduboff return (frags); 12225748Sduboff } 12235748Sduboff 12245748Sduboff static void 12255748Sduboff sfe_tx_start(struct gem_dev *dp, int start_slot, int nslot) 12265748Sduboff { 12277116Sduboff uint_t tx_ring_size = dp->gc.gc_tx_ring_size; 12285748Sduboff struct sfe_desc *tdp; 12295748Sduboff struct sfe_dev *lp = dp->private; 12305748Sduboff 12315748Sduboff if (nslot > 1) { 12325748Sduboff gem_tx_desc_dma_sync(dp, 12337116Sduboff SLOT(start_slot + 1, tx_ring_size), 12345748Sduboff nslot - 1, DDI_DMA_SYNC_FORDEV); 12355748Sduboff } 12365748Sduboff 12375748Sduboff tdp = (void *)&dp->tx_ring[SFE_DESC_SIZE * start_slot]; 12385748Sduboff tdp->d_cmdsts |= LE_32(CMDSTS_OWN); 12395748Sduboff 12405748Sduboff gem_tx_desc_dma_sync(dp, start_slot, 1, DDI_DMA_SYNC_FORDEV); 12415748Sduboff 12425748Sduboff /* 12435748Sduboff * Let the Transmit Buffer Manager Fill state machine active. 12445748Sduboff */ 12455748Sduboff if (dp->mac_active) { 12465748Sduboff OUTL(dp, CR, lp->cr | CR_TXE); 12475748Sduboff } 12485748Sduboff } 12495748Sduboff 12505748Sduboff static void 12515748Sduboff sfe_rx_desc_write(struct gem_dev *dp, int slot, 12525748Sduboff ddi_dma_cookie_t *dmacookie, int frags) 12535748Sduboff { 12545748Sduboff struct sfe_desc *rdp; 12557116Sduboff uint32_t tmp0; 12567116Sduboff uint32_t tmp1; 12575748Sduboff #if DEBUG_LEVEL > 2 12585748Sduboff int i; 12595748Sduboff 12605748Sduboff ASSERT(frags == 1); 12615748Sduboff 12625748Sduboff cmn_err(CE_CONT, CONS 12635748Sduboff "%s: %s seqnum: %d, slot %d, frags: %d", 12645748Sduboff dp->name, __func__, dp->rx_active_tail, slot, frags); 12655748Sduboff for (i = 0; i < frags; i++) { 12665748Sduboff cmn_err(CE_CONT, CONS " frag: %d addr: 0x%llx, len: 0x%lx", 12675748Sduboff i, dmacookie[i].dmac_address, dmacookie[i].dmac_size); 12685748Sduboff } 12695748Sduboff #endif 12705748Sduboff /* for the last slot of the packet */ 12715748Sduboff rdp = (void *)&dp->rx_ring[SFE_DESC_SIZE * slot]; 12725748Sduboff 12737116Sduboff tmp0 = (uint32_t)dmacookie->dmac_address; 12747116Sduboff tmp1 = CMDSTS_INTR | (uint32_t)dmacookie->dmac_size; 12757116Sduboff rdp->d_bufptr = LE_32(tmp0); 12767116Sduboff rdp->d_cmdsts = LE_32(tmp1); 12775748Sduboff } 12785748Sduboff 12795748Sduboff static uint_t 12805748Sduboff sfe_tx_desc_stat(struct gem_dev *dp, int slot, int ndesc) 12815748Sduboff { 12827116Sduboff uint_t tx_ring_size = dp->gc.gc_tx_ring_size; 12835748Sduboff struct sfe_desc *tdp; 12845748Sduboff uint32_t status; 12855748Sduboff int cols; 12867116Sduboff struct sfe_dev *lp = dp->private; 12875748Sduboff #ifdef DEBUG_LEVEL 12885748Sduboff int i; 12895748Sduboff clock_t delay; 12905748Sduboff #endif 12915748Sduboff /* check status of the last descriptor */ 12925748Sduboff tdp = (void *) 12937116Sduboff &dp->tx_ring[SFE_DESC_SIZE * SLOT(slot + ndesc - 1, tx_ring_size)]; 12945748Sduboff 12957116Sduboff /* 12967116Sduboff * Don't use LE_32() directly to refer tdp->d_cmdsts. 12977116Sduboff * It is not atomic for big endian cpus. 12987116Sduboff */ 12997116Sduboff status = tdp->d_cmdsts; 13007116Sduboff status = LE_32(status); 13015748Sduboff 13025748Sduboff DPRINTF(2, (CE_CONT, CONS "%s: time:%ld %s: slot:%d, status:0x%b", 13035748Sduboff dp->name, ddi_get_lbolt(), __func__, 13045748Sduboff slot, status, TXSTAT_BITS)); 13055748Sduboff 13065748Sduboff if (status & CMDSTS_OWN) { 13075748Sduboff /* 13085748Sduboff * not yet transmitted 13095748Sduboff */ 13107116Sduboff /* workaround for tx hang */ 13117116Sduboff if (lp->chip->chip_type == CHIPTYPE_DP83815 && 13127116Sduboff dp->mac_active) { 13137116Sduboff OUTL(dp, CR, lp->cr | CR_TXE); 13147116Sduboff } 13155748Sduboff return (0); 13165748Sduboff } 13175748Sduboff 13185748Sduboff if (status & CMDSTS_MORE) { 13195748Sduboff /* XXX - the hardware problem but don't panic the system */ 13205748Sduboff /* avoid lint bug for %b format string including 32nd bit */ 13215748Sduboff cmn_err(CE_NOTE, CONS 13225748Sduboff "%s: tx status bits incorrect: slot:%d, status:0x%x", 13235748Sduboff dp->name, slot, status); 13245748Sduboff } 13255748Sduboff 13265748Sduboff #if DEBUG_LEVEL > 3 13275748Sduboff delay = (ddi_get_lbolt() - dp->tx_buf_head->txb_stime) * 10; 13285748Sduboff if (delay >= 50) { 13295748Sduboff DPRINTF(0, (CE_NOTE, "%s: tx deferred %d mS: slot %d", 13305748Sduboff dp->name, delay, slot)); 13315748Sduboff } 13325748Sduboff #endif 13335748Sduboff 13345748Sduboff #if DEBUG_LEVEL > 3 13355748Sduboff for (i = 0; i < nfrag-1; i++) { 13365748Sduboff uint32_t s; 13375748Sduboff int n; 13385748Sduboff 13397116Sduboff n = SLOT(slot + i, tx_ring_size); 13405748Sduboff s = LE_32( 13415748Sduboff ((struct sfe_desc *)((void *) 13425748Sduboff &dp->tx_ring[SFE_DESC_SIZE * n]))->d_cmdsts); 13435748Sduboff 13445748Sduboff ASSERT(s & CMDSTS_MORE); 13455748Sduboff ASSERT((s & CMDSTS_OWN) == 0); 13465748Sduboff } 13475748Sduboff #endif 13485748Sduboff 13495748Sduboff /* 13505748Sduboff * collect statistics 13515748Sduboff */ 13525748Sduboff if ((status & CMDSTS_OK) == 0) { 13535748Sduboff 13545748Sduboff /* failed to transmit the packet */ 13555748Sduboff 13565748Sduboff DPRINTF(0, (CE_CONT, CONS "%s: Transmit error, Tx status %b", 13575748Sduboff dp->name, status, TXSTAT_BITS)); 13585748Sduboff 13595748Sduboff dp->stats.errxmt++; 13605748Sduboff 13615748Sduboff if (status & CMDSTS_TFU) { 13625748Sduboff dp->stats.underflow++; 13635748Sduboff } else if (status & CMDSTS_CRS) { 13645748Sduboff dp->stats.nocarrier++; 13655748Sduboff } else if (status & CMDSTS_OWC) { 13665748Sduboff dp->stats.xmtlatecoll++; 13675748Sduboff } else if ((!dp->full_duplex) && (status & CMDSTS_EC)) { 13685748Sduboff dp->stats.excoll++; 13695748Sduboff dp->stats.collisions += 16; 13705748Sduboff } else { 13715748Sduboff dp->stats.xmit_internal_err++; 13725748Sduboff } 13735748Sduboff } else if (!dp->full_duplex) { 13745748Sduboff cols = (status >> CMDSTS_CCNT_SHIFT) & CCNT_MASK; 13755748Sduboff 13765748Sduboff if (cols > 0) { 13775748Sduboff if (cols == 1) { 13785748Sduboff dp->stats.first_coll++; 13795748Sduboff } else /* (cols > 1) */ { 13805748Sduboff dp->stats.multi_coll++; 13815748Sduboff } 13825748Sduboff dp->stats.collisions += cols; 13835748Sduboff } else if (status & CMDSTS_TD) { 13845748Sduboff dp->stats.defer++; 13855748Sduboff } 13865748Sduboff } 13875748Sduboff return (GEM_TX_DONE); 13885748Sduboff } 13895748Sduboff 13905748Sduboff static uint64_t 13915748Sduboff sfe_rx_desc_stat(struct gem_dev *dp, int slot, int ndesc) 13925748Sduboff { 13935748Sduboff struct sfe_desc *rdp; 13945748Sduboff uint_t len; 13955748Sduboff uint_t flag; 13965748Sduboff uint32_t status; 13975748Sduboff 13985748Sduboff flag = GEM_RX_DONE; 13995748Sduboff 14005748Sduboff /* Dont read ISR because we cannot ack only to rx interrupt. */ 14015748Sduboff 14025748Sduboff rdp = (void *)&dp->rx_ring[SFE_DESC_SIZE * slot]; 14035748Sduboff 14047116Sduboff /* 14057116Sduboff * Don't use LE_32() directly to refer rdp->d_cmdsts. 14067116Sduboff * It is not atomic for big endian cpus. 14077116Sduboff */ 14087116Sduboff status = rdp->d_cmdsts; 14097116Sduboff status = LE_32(status); 14105748Sduboff 14115748Sduboff DPRINTF(2, (CE_CONT, CONS "%s: time:%ld %s: slot:%d, status:0x%b", 14125748Sduboff dp->name, ddi_get_lbolt(), __func__, 14135748Sduboff slot, status, RXSTAT_BITS)); 14145748Sduboff 14155748Sduboff if ((status & CMDSTS_OWN) == 0) { 14165748Sduboff /* 14175748Sduboff * No more received packets because 14185748Sduboff * this buffer is owned by NIC. 14195748Sduboff */ 14205748Sduboff return (0); 14215748Sduboff } 14225748Sduboff 14235748Sduboff #define RX_ERR_BITS \ 14245748Sduboff (CMDSTS_RXA | CMDSTS_RXO | CMDSTS_LONG | CMDSTS_RUNT | \ 14255748Sduboff CMDSTS_ISE | CMDSTS_CRCE | CMDSTS_FAE | CMDSTS_MORE) 14265748Sduboff 14275748Sduboff if (status & RX_ERR_BITS) { 14285748Sduboff /* 14295748Sduboff * Packet with error received 14305748Sduboff */ 14315748Sduboff DPRINTF(0, (CE_CONT, CONS "%s: Corrupted packet " 14325748Sduboff "received, buffer status: %b", 14335748Sduboff dp->name, status, RXSTAT_BITS)); 14345748Sduboff 14355748Sduboff /* collect statistics information */ 14365748Sduboff dp->stats.errrcv++; 14375748Sduboff 14385748Sduboff if (status & CMDSTS_RXO) { 14395748Sduboff dp->stats.overflow++; 14405748Sduboff } else if (status & (CMDSTS_LONG | CMDSTS_MORE)) { 14415748Sduboff dp->stats.frame_too_long++; 14425748Sduboff } else if (status & CMDSTS_RUNT) { 14435748Sduboff dp->stats.runt++; 14445748Sduboff } else if (status & (CMDSTS_ISE | CMDSTS_FAE)) { 14455748Sduboff dp->stats.frame++; 14465748Sduboff } else if (status & CMDSTS_CRCE) { 14475748Sduboff dp->stats.crc++; 14485748Sduboff } else { 14495748Sduboff dp->stats.rcv_internal_err++; 14505748Sduboff } 14515748Sduboff 14525748Sduboff return (flag | GEM_RX_ERR); 14535748Sduboff } 14545748Sduboff 14555748Sduboff /* 14565748Sduboff * this packet was received without errors 14575748Sduboff */ 14585748Sduboff if ((len = (status & CMDSTS_SIZE)) >= ETHERFCSL) { 14595748Sduboff len -= ETHERFCSL; 14605748Sduboff } 14615748Sduboff 14625748Sduboff #if DEBUG_LEVEL > 10 14635748Sduboff { 14645748Sduboff int i; 14655748Sduboff uint8_t *bp = dp->rx_buf_head->rxb_buf; 14665748Sduboff 14675748Sduboff cmn_err(CE_CONT, CONS "%s: len:%d", dp->name, len); 14685748Sduboff 14695748Sduboff for (i = 0; i < 60; i += 10) { 14705748Sduboff cmn_err(CE_CONT, CONS 14715748Sduboff "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", 14725748Sduboff bp[0], bp[1], bp[2], bp[3], bp[4], 14735748Sduboff bp[5], bp[6], bp[7], bp[8], bp[9]); 14745748Sduboff } 14755748Sduboff bp += 10; 14765748Sduboff } 14775748Sduboff #endif 14785748Sduboff return (flag | (len & GEM_RX_LEN)); 14795748Sduboff } 14805748Sduboff 14815748Sduboff static void 14825748Sduboff sfe_tx_desc_init(struct gem_dev *dp, int slot) 14835748Sduboff { 14847116Sduboff uint_t tx_ring_size = dp->gc.gc_tx_ring_size; 14855748Sduboff struct sfe_desc *tdp; 14865748Sduboff uint32_t here; 14875748Sduboff 14885748Sduboff tdp = (void *)&dp->tx_ring[SFE_DESC_SIZE * slot]; 14895748Sduboff 14905748Sduboff /* don't clear d_link field, which have a valid pointer */ 14915748Sduboff tdp->d_cmdsts = 0; 14925748Sduboff 14935748Sduboff /* make a link to this from the previous descriptor */ 14945748Sduboff here = ((uint32_t)dp->tx_ring_dma) + SFE_DESC_SIZE*slot; 14955748Sduboff 14965748Sduboff tdp = (void *) 14977116Sduboff &dp->tx_ring[SFE_DESC_SIZE * SLOT(slot - 1, tx_ring_size)]; 14985748Sduboff tdp->d_link = LE_32(here); 14995748Sduboff } 15005748Sduboff 15015748Sduboff static void 15025748Sduboff sfe_rx_desc_init(struct gem_dev *dp, int slot) 15035748Sduboff { 15047116Sduboff uint_t rx_ring_size = dp->gc.gc_rx_ring_size; 15055748Sduboff struct sfe_desc *rdp; 15065748Sduboff uint32_t here; 15075748Sduboff 15085748Sduboff rdp = (void *)&dp->rx_ring[SFE_DESC_SIZE * slot]; 15095748Sduboff 15105748Sduboff /* don't clear d_link field, which have a valid pointer */ 15115748Sduboff rdp->d_cmdsts = LE_32(CMDSTS_OWN); 15125748Sduboff 15135748Sduboff /* make a link to this from the previous descriptor */ 15145748Sduboff here = ((uint32_t)dp->rx_ring_dma) + SFE_DESC_SIZE*slot; 15155748Sduboff 15165748Sduboff rdp = (void *) 15177116Sduboff &dp->rx_ring[SFE_DESC_SIZE * SLOT(slot - 1, rx_ring_size)]; 15185748Sduboff rdp->d_link = LE_32(here); 15195748Sduboff } 15205748Sduboff 15215748Sduboff static void 15225748Sduboff sfe_tx_desc_clean(struct gem_dev *dp, int slot) 15235748Sduboff { 15245748Sduboff struct sfe_desc *tdp; 15255748Sduboff 15265748Sduboff tdp = (void *)&dp->tx_ring[SFE_DESC_SIZE * slot]; 15275748Sduboff tdp->d_cmdsts = 0; 15285748Sduboff } 15295748Sduboff 15305748Sduboff static void 15315748Sduboff sfe_rx_desc_clean(struct gem_dev *dp, int slot) 15325748Sduboff { 15335748Sduboff struct sfe_desc *rdp; 15345748Sduboff 15355748Sduboff rdp = (void *)&dp->rx_ring[SFE_DESC_SIZE * slot]; 15365748Sduboff rdp->d_cmdsts = LE_32(CMDSTS_OWN); 15375748Sduboff } 15385748Sduboff 15395748Sduboff /* 15405748Sduboff * Device depend interrupt handler 15415748Sduboff */ 15425748Sduboff static uint_t 15435748Sduboff sfe_interrupt(struct gem_dev *dp) 15445748Sduboff { 15457116Sduboff uint_t rx_ring_size = dp->gc.gc_rx_ring_size; 15465748Sduboff uint32_t isr; 15477116Sduboff uint32_t isr_bogus; 15485748Sduboff uint_t flags = 0; 15495748Sduboff boolean_t need_to_reset = B_FALSE; 15505748Sduboff struct sfe_dev *lp = dp->private; 15515748Sduboff 15525748Sduboff /* read reason and clear interrupt */ 15535748Sduboff isr = INL(dp, ISR); 15545748Sduboff 15557116Sduboff isr_bogus = lp->isr_pended; 15567116Sduboff lp->isr_pended = 0; 15577116Sduboff 15587116Sduboff if (((isr | isr_bogus) & lp->our_intr_bits) == 0) { 15595748Sduboff /* we are not the interrupt source */ 15605748Sduboff return (DDI_INTR_UNCLAIMED); 15615748Sduboff } 15625748Sduboff 15635748Sduboff DPRINTF(3, (CE_CONT, 15645748Sduboff CONS "%s: time:%ld %s:called: isr:0x%b rx_active_head: %d", 15655748Sduboff dp->name, ddi_get_lbolt(), __func__, 15665748Sduboff isr, INTR_BITS, dp->rx_active_head)); 15675748Sduboff 15685748Sduboff if (!dp->mac_active) { 15695748Sduboff /* the device is going to stop */ 15705748Sduboff lp->our_intr_bits = 0; 15715748Sduboff return (DDI_INTR_CLAIMED); 15725748Sduboff } 15735748Sduboff 15745748Sduboff isr &= lp->our_intr_bits; 15755748Sduboff 15765748Sduboff if (isr & (ISR_RXSOVR | ISR_RXORN | ISR_RXIDLE | ISR_RXERR | 15775748Sduboff ISR_RXDESC | ISR_RXOK)) { 15785748Sduboff (void) gem_receive(dp); 15795748Sduboff 15805748Sduboff if (isr & (ISR_RXSOVR | ISR_RXORN)) { 15815748Sduboff DPRINTF(0, (CE_CONT, 15825748Sduboff CONS "%s: rx fifo overrun: isr %b", 15835748Sduboff dp->name, isr, INTR_BITS)); 15845748Sduboff /* no need restart rx */ 15855748Sduboff dp->stats.overflow++; 15865748Sduboff } 15875748Sduboff 15885748Sduboff if (isr & ISR_RXIDLE) { 15895748Sduboff DPRINTF(0, (CE_CONT, 15905748Sduboff CONS "%s: rx buffer ran out: isr %b", 15915748Sduboff dp->name, isr, INTR_BITS)); 15925748Sduboff 15935748Sduboff dp->stats.norcvbuf++; 15945748Sduboff 15955748Sduboff /* 15965748Sduboff * Make RXDP points the head of receive 15975748Sduboff * buffer list. 15985748Sduboff */ 15995748Sduboff OUTL(dp, RXDP, dp->rx_ring_dma + 16005748Sduboff SFE_DESC_SIZE * 16017116Sduboff SLOT(dp->rx_active_head, rx_ring_size)); 16025748Sduboff 16035748Sduboff /* Restart the receive engine */ 16045748Sduboff OUTL(dp, CR, lp->cr | CR_RXE); 16055748Sduboff } 16065748Sduboff } 16075748Sduboff 16085748Sduboff if (isr & (ISR_TXURN | ISR_TXERR | ISR_TXDESC | 16095748Sduboff ISR_TXIDLE | ISR_TXOK)) { 16105748Sduboff /* need to reclaim tx buffers */ 16115748Sduboff if (gem_tx_done(dp)) { 16125748Sduboff flags |= INTR_RESTART_TX; 16135748Sduboff } 16145748Sduboff /* 16155748Sduboff * XXX - tx error statistics will be counted in 16165748Sduboff * sfe_tx_desc_stat() and no need to restart tx on errors. 16175748Sduboff */ 16185748Sduboff } 16195748Sduboff 16205748Sduboff if (isr & (ISR_DPERR | ISR_SSERR | ISR_RMABT | ISR_RTABT)) { 16215748Sduboff cmn_err(CE_WARN, "%s: ERROR interrupt: isr %b.", 16225748Sduboff dp->name, isr, INTR_BITS); 16235748Sduboff need_to_reset = B_TRUE; 16245748Sduboff } 16255748Sduboff reset: 16265748Sduboff if (need_to_reset) { 16275748Sduboff (void) gem_restart_nic(dp, GEM_RESTART_KEEP_BUF); 16285748Sduboff flags |= INTR_RESTART_TX; 16295748Sduboff } 16305748Sduboff 16315748Sduboff DPRINTF(5, (CE_CONT, CONS "%s: %s: return: isr: %b", 16325748Sduboff dp->name, __func__, isr, INTR_BITS)); 16335748Sduboff 16345748Sduboff return (DDI_INTR_CLAIMED | flags); 16355748Sduboff } 16365748Sduboff 16375748Sduboff /* ======================================================== */ 16385748Sduboff /* 16395748Sduboff * HW depend MII routine 16405748Sduboff */ 16415748Sduboff /* ======================================================== */ 16425748Sduboff 16435748Sduboff /* 16445748Sduboff * MII routines for NS DP83815 16455748Sduboff */ 16465748Sduboff static void 16475748Sduboff sfe_mii_sync_dp83815(struct gem_dev *dp) 16485748Sduboff { 16495748Sduboff /* do nothing */ 16505748Sduboff } 16515748Sduboff 16525748Sduboff static uint16_t 16535748Sduboff sfe_mii_read_dp83815(struct gem_dev *dp, uint_t offset) 16545748Sduboff { 16555748Sduboff DPRINTF(4, (CE_CONT, CONS"%s: %s: offset 0x%x", 16565748Sduboff dp->name, __func__, offset)); 16575748Sduboff return ((uint16_t)INL(dp, MII_REGS_BASE + offset*4)); 16585748Sduboff } 16595748Sduboff 16605748Sduboff static void 16615748Sduboff sfe_mii_write_dp83815(struct gem_dev *dp, uint_t offset, uint16_t val) 16625748Sduboff { 16635748Sduboff DPRINTF(4, (CE_CONT, CONS"%s: %s: offset 0x%x 0x%x", 16645748Sduboff dp->name, __func__, offset, val)); 16655748Sduboff OUTL(dp, MII_REGS_BASE + offset*4, val); 16665748Sduboff } 16675748Sduboff 16685748Sduboff static int 16695748Sduboff sfe_mii_config_dp83815(struct gem_dev *dp) 16705748Sduboff { 16715748Sduboff uint32_t srr; 16725748Sduboff 16735748Sduboff srr = INL(dp, SRR) & SRR_REV; 16745748Sduboff 16755748Sduboff DPRINTF(0, (CE_CONT, CONS "%s: srr:0x%04x %04x %04x %04x %04x %04x", 16765748Sduboff dp->name, srr, 16775748Sduboff INW(dp, 0x00cc), /* PGSEL */ 16785748Sduboff INW(dp, 0x00e4), /* PMDCSR */ 16795748Sduboff INW(dp, 0x00fc), /* TSTDAT */ 16805748Sduboff INW(dp, 0x00f4), /* DSPCFG */ 16815748Sduboff INW(dp, 0x00f8))); /* SDCFG */ 16825748Sduboff 16837116Sduboff if (srr == SRR_REV_DP83815CVNG) { 16845748Sduboff /* 16855748Sduboff * NS datasheet says that DP83815CVNG needs following 16865748Sduboff * registers to be patched for optimizing its performance. 16877116Sduboff * A report said that CRC errors on RX disappeared 16885748Sduboff * with the patch. 16895748Sduboff */ 16905748Sduboff OUTW(dp, 0x00cc, 0x0001); /* PGSEL */ 16915748Sduboff OUTW(dp, 0x00e4, 0x189c); /* PMDCSR */ 16925748Sduboff OUTW(dp, 0x00fc, 0x0000); /* TSTDAT */ 16935748Sduboff OUTW(dp, 0x00f4, 0x5040); /* DSPCFG */ 16945748Sduboff OUTW(dp, 0x00f8, 0x008c); /* SDCFG */ 16957116Sduboff OUTW(dp, 0x00cc, 0x0000); /* PGSEL */ 16965748Sduboff 16975748Sduboff DPRINTF(0, (CE_CONT, 16985748Sduboff CONS "%s: PHY patched %04x %04x %04x %04x %04x", 16995748Sduboff dp->name, 17005748Sduboff INW(dp, 0x00cc), /* PGSEL */ 17015748Sduboff INW(dp, 0x00e4), /* PMDCSR */ 17025748Sduboff INW(dp, 0x00fc), /* TSTDAT */ 17035748Sduboff INW(dp, 0x00f4), /* DSPCFG */ 17045748Sduboff INW(dp, 0x00f8))); /* SDCFG */ 17057116Sduboff } else if (((srr ^ SRR_REV_DP83815DVNG) & 0xff00) == 0 || 17067116Sduboff ((srr ^ SRR_REV_DP83816AVNG) & 0xff00) == 0) { 17077116Sduboff /* 17087116Sduboff * Additional packets for later chipset 17097116Sduboff */ 17107116Sduboff OUTW(dp, 0x00cc, 0x0001); /* PGSEL */ 17117116Sduboff OUTW(dp, 0x00e4, 0x189c); /* PMDCSR */ 17127116Sduboff OUTW(dp, 0x00cc, 0x0000); /* PGSEL */ 17137116Sduboff 17147116Sduboff DPRINTF(0, (CE_CONT, 17157116Sduboff CONS "%s: PHY patched %04x %04x", 17167116Sduboff dp->name, 17177116Sduboff INW(dp, 0x00cc), /* PGSEL */ 17187116Sduboff INW(dp, 0x00e4))); /* PMDCSR */ 17195748Sduboff } 17205748Sduboff 17215748Sduboff return (gem_mii_config_default(dp)); 17225748Sduboff } 17235748Sduboff 17247116Sduboff static int 17257116Sduboff sfe_mii_probe_dp83815(struct gem_dev *dp) 17267116Sduboff { 17277116Sduboff uint32_t val; 17287116Sduboff 17297116Sduboff /* try external phy first */ 17307116Sduboff DPRINTF(0, (CE_CONT, CONS "%s: %s: trying external phy", 17317116Sduboff dp->name, __func__)); 17327116Sduboff dp->mii_phy_addr = 0; 17337116Sduboff dp->gc.gc_mii_sync = &sfe_mii_sync_sis900; 17347116Sduboff dp->gc.gc_mii_read = &sfe_mii_read_sis900; 17357116Sduboff dp->gc.gc_mii_write = &sfe_mii_write_sis900; 17367116Sduboff 17377116Sduboff val = INL(dp, CFG) & (CFG_ANEG_SEL | CFG_PHY_CFG); 17387116Sduboff OUTL(dp, CFG, val | CFG_EXT_PHY | CFG_PHY_DIS); 17397116Sduboff 17407116Sduboff if (gem_mii_probe_default(dp) == GEM_SUCCESS) { 17417116Sduboff return (GEM_SUCCESS); 17427116Sduboff } 17437116Sduboff 17447116Sduboff /* switch to internal phy */ 17457116Sduboff DPRINTF(0, (CE_CONT, CONS "%s: %s: switching to internal phy", 17467116Sduboff dp->name, __func__)); 17477116Sduboff dp->mii_phy_addr = -1; 17487116Sduboff dp->gc.gc_mii_sync = &sfe_mii_sync_dp83815; 17497116Sduboff dp->gc.gc_mii_read = &sfe_mii_read_dp83815; 17507116Sduboff dp->gc.gc_mii_write = &sfe_mii_write_dp83815; 17517116Sduboff 17527116Sduboff val = INL(dp, CFG) & (CFG_ANEG_SEL | CFG_PHY_CFG); 17537116Sduboff OUTL(dp, CFG, val | CFG_PAUSE_ADV | CFG_PHY_RST); 17547116Sduboff drv_usecwait(100); /* keep to assert RST bit for a while */ 17557116Sduboff OUTL(dp, CFG, val | CFG_PAUSE_ADV); 17567116Sduboff 17577116Sduboff /* wait for PHY reset */ 17587116Sduboff delay(drv_usectohz(10000)); 17597116Sduboff 17607116Sduboff return (gem_mii_probe_default(dp)); 17617116Sduboff } 17627116Sduboff 17637116Sduboff static int 17647116Sduboff sfe_mii_init_dp83815(struct gem_dev *dp) 17657116Sduboff { 17667116Sduboff uint32_t val; 17677116Sduboff 17687116Sduboff val = INL(dp, CFG) & (CFG_ANEG_SEL | CFG_PHY_CFG); 17697116Sduboff 17707116Sduboff if (dp->mii_phy_addr == -1) { 17717116Sduboff /* select internal phy */ 17727116Sduboff OUTL(dp, CFG, val | CFG_PAUSE_ADV); 17737116Sduboff } else { 17747116Sduboff /* select external phy */ 17757116Sduboff OUTL(dp, CFG, val | CFG_EXT_PHY | CFG_PHY_DIS); 17767116Sduboff } 17777116Sduboff 17787116Sduboff return (GEM_SUCCESS); 17797116Sduboff } 17805748Sduboff 17815748Sduboff /* 17825748Sduboff * MII routines for SiS900 17835748Sduboff */ 17847116Sduboff #define MDIO_DELAY(dp) {(void) INL(dp, MEAR); (void) INL(dp, MEAR); } 17855748Sduboff static void 17865748Sduboff sfe_mii_sync_sis900(struct gem_dev *dp) 17875748Sduboff { 17885748Sduboff int i; 17895748Sduboff 17907116Sduboff /* send 32 ONE's to make MII line idle */ 17915748Sduboff for (i = 0; i < 32; i++) { 17925748Sduboff OUTL(dp, MEAR, MEAR_MDDIR | MEAR_MDIO); 17935748Sduboff MDIO_DELAY(dp); 17945748Sduboff OUTL(dp, MEAR, MEAR_MDDIR | MEAR_MDIO | MEAR_MDC); 17955748Sduboff MDIO_DELAY(dp); 17965748Sduboff } 17975748Sduboff } 17985748Sduboff 17995748Sduboff static int 18005748Sduboff sfe_mii_config_sis900(struct gem_dev *dp) 18015748Sduboff { 18025748Sduboff struct sfe_dev *lp = dp->private; 18035748Sduboff 18045748Sduboff /* Do chip depend setup */ 18055748Sduboff if ((dp->mii_phy_id & PHY_MASK) == PHY_ICS1893) { 18065748Sduboff /* workaround for ICS1893 PHY */ 18075748Sduboff gem_mii_write(dp, 0x0018, 0xD200); 18085748Sduboff } 18095748Sduboff 18105748Sduboff if (lp->revid == SIS630E_900_REV) { 18115748Sduboff /* 18125748Sduboff * SiS 630E has bugs on default values 18135748Sduboff * of PHY registers 18145748Sduboff */ 18155748Sduboff gem_mii_write(dp, MII_AN_ADVERT, 0x05e1); 18165748Sduboff gem_mii_write(dp, MII_CONFIG1, 0x0022); 18175748Sduboff gem_mii_write(dp, MII_CONFIG2, 0xff00); 18185748Sduboff gem_mii_write(dp, MII_MASK, 0xffc0); 18195748Sduboff } 18205748Sduboff sfe_set_eq_sis630(dp); 18215748Sduboff 18225748Sduboff return (gem_mii_config_default(dp)); 18235748Sduboff } 18245748Sduboff 18255748Sduboff static uint16_t 18265748Sduboff sfe_mii_read_sis900(struct gem_dev *dp, uint_t reg) 18275748Sduboff { 18285748Sduboff uint32_t cmd; 18295748Sduboff uint16_t ret; 18305748Sduboff int i; 18315748Sduboff uint32_t data; 18325748Sduboff 18335748Sduboff cmd = MII_READ_CMD(dp->mii_phy_addr, reg); 18345748Sduboff 18355748Sduboff for (i = 31; i >= 18; i--) { 18365748Sduboff data = ((cmd >> i) & 1) << MEAR_MDIO_SHIFT; 18375748Sduboff OUTL(dp, MEAR, data | MEAR_MDDIR); 18385748Sduboff MDIO_DELAY(dp); 18395748Sduboff OUTL(dp, MEAR, data | MEAR_MDDIR | MEAR_MDC); 18405748Sduboff MDIO_DELAY(dp); 18415748Sduboff } 18425748Sduboff 18435748Sduboff /* turn around cycle */ 18447116Sduboff OUTL(dp, MEAR, 0); 18455748Sduboff MDIO_DELAY(dp); 18465748Sduboff 18475748Sduboff /* get response from PHY */ 18485748Sduboff OUTL(dp, MEAR, MEAR_MDC); 18495748Sduboff MDIO_DELAY(dp); 18507116Sduboff 18515748Sduboff OUTL(dp, MEAR, 0); 18525748Sduboff #if DEBUG_LEBEL > 0 18537116Sduboff (void) INL(dp, MEAR); /* delay */ 18545748Sduboff if (INL(dp, MEAR) & MEAR_MDIO) { 18555748Sduboff cmn_err(CE_WARN, "%s: PHY@%d not responded", 18565748Sduboff dp->name, dp->mii_phy_addr); 18575748Sduboff } 18587116Sduboff #else 18597116Sduboff MDIO_DELAY(dp); 18605748Sduboff #endif 18615748Sduboff /* terminate response cycle */ 18625748Sduboff OUTL(dp, MEAR, MEAR_MDC); 18637116Sduboff MDIO_DELAY(dp); 18645748Sduboff 18655748Sduboff ret = 0; /* to avoid lint errors */ 18665748Sduboff for (i = 16; i > 0; i--) { 18675748Sduboff OUTL(dp, MEAR, 0); 18687116Sduboff (void) INL(dp, MEAR); /* delay */ 18695748Sduboff ret = (ret << 1) | ((INL(dp, MEAR) >> MEAR_MDIO_SHIFT) & 1); 18705748Sduboff OUTL(dp, MEAR, MEAR_MDC); 18715748Sduboff MDIO_DELAY(dp); 18725748Sduboff } 18735748Sduboff 18747116Sduboff /* send two idle(Z) bits to terminate the read cycle */ 18757116Sduboff for (i = 0; i < 2; i++) { 18767116Sduboff OUTL(dp, MEAR, 0); 18777116Sduboff MDIO_DELAY(dp); 18787116Sduboff OUTL(dp, MEAR, MEAR_MDC); 18797116Sduboff MDIO_DELAY(dp); 18807116Sduboff } 18815748Sduboff 18825748Sduboff return (ret); 18835748Sduboff } 18845748Sduboff 18855748Sduboff static void 18865748Sduboff sfe_mii_write_sis900(struct gem_dev *dp, uint_t reg, uint16_t val) 18875748Sduboff { 18885748Sduboff uint32_t cmd; 18895748Sduboff int i; 18905748Sduboff uint32_t data; 18915748Sduboff 18925748Sduboff cmd = MII_WRITE_CMD(dp->mii_phy_addr, reg, val); 18935748Sduboff 18945748Sduboff for (i = 31; i >= 0; i--) { 18955748Sduboff data = ((cmd >> i) & 1) << MEAR_MDIO_SHIFT; 18965748Sduboff OUTL(dp, MEAR, data | MEAR_MDDIR); 18975748Sduboff MDIO_DELAY(dp); 18985748Sduboff OUTL(dp, MEAR, data | MEAR_MDDIR | MEAR_MDC); 18995748Sduboff MDIO_DELAY(dp); 19005748Sduboff } 19015748Sduboff 19027116Sduboff /* send two idle(Z) bits to terminate the write cycle. */ 19035748Sduboff for (i = 0; i < 2; i++) { 19047116Sduboff OUTL(dp, MEAR, 0); 19055748Sduboff MDIO_DELAY(dp); 19067116Sduboff OUTL(dp, MEAR, MEAR_MDC); 19075748Sduboff MDIO_DELAY(dp); 19085748Sduboff } 19095748Sduboff } 19105748Sduboff #undef MDIO_DELAY 19115748Sduboff 19125748Sduboff static void 19135748Sduboff sfe_set_eq_sis630(struct gem_dev *dp) 19145748Sduboff { 19155748Sduboff uint16_t reg14h; 19165748Sduboff uint16_t eq_value; 19175748Sduboff uint16_t max_value; 19185748Sduboff uint16_t min_value; 19195748Sduboff int i; 19205748Sduboff uint8_t rev; 19215748Sduboff struct sfe_dev *lp = dp->private; 19225748Sduboff 19235748Sduboff rev = lp->revid; 19245748Sduboff 19255748Sduboff if (!(rev == SIS630E_900_REV || rev == SIS630EA1_900_REV || 19265748Sduboff rev == SIS630A_900_REV || rev == SIS630ET_900_REV)) { 19275748Sduboff /* it doesn't have a internal PHY */ 19285748Sduboff return; 19295748Sduboff } 19305748Sduboff 19315748Sduboff if (dp->mii_state == MII_STATE_LINKUP) { 19325748Sduboff reg14h = gem_mii_read(dp, MII_RESV); 19335748Sduboff gem_mii_write(dp, MII_RESV, (0x2200 | reg14h) & 0xBFFF); 19345748Sduboff 19355748Sduboff eq_value = (0x00f8 & gem_mii_read(dp, MII_RESV)) >> 3; 19365748Sduboff max_value = min_value = eq_value; 19375748Sduboff for (i = 1; i < 10; i++) { 19385748Sduboff eq_value = (0x00f8 & gem_mii_read(dp, MII_RESV)) >> 3; 19395748Sduboff max_value = max(eq_value, max_value); 19405748Sduboff min_value = min(eq_value, min_value); 19415748Sduboff } 19425748Sduboff 19435748Sduboff /* for 630E, rule to determine the equalizer value */ 19445748Sduboff if (rev == SIS630E_900_REV || rev == SIS630EA1_900_REV || 19455748Sduboff rev == SIS630ET_900_REV) { 19465748Sduboff if (max_value < 5) { 19475748Sduboff eq_value = max_value; 19485748Sduboff } else if (5 <= max_value && max_value < 15) { 19495748Sduboff eq_value = 19505748Sduboff max(max_value + 1, 19515748Sduboff min_value + 2); 19525748Sduboff } else if (15 <= max_value) { 19535748Sduboff eq_value = 19545748Sduboff max(max_value + 5, 19555748Sduboff min_value + 6); 19565748Sduboff } 19575748Sduboff } 19585748Sduboff /* for 630B0&B1, rule to determine the equalizer value */ 19595748Sduboff else 19605748Sduboff if (rev == SIS630A_900_REV && 19615748Sduboff (lp->bridge_revid == SIS630B0 || 19625748Sduboff lp->bridge_revid == SIS630B1)) { 19635748Sduboff 19645748Sduboff if (max_value == 0) { 19655748Sduboff eq_value = 3; 19665748Sduboff } else { 19675748Sduboff eq_value = (max_value + min_value + 1)/2; 19685748Sduboff } 19695748Sduboff } 19705748Sduboff /* write equalizer value and setting */ 19715748Sduboff reg14h = gem_mii_read(dp, MII_RESV) & ~0x02f8; 19725748Sduboff reg14h |= 0x6000 | (eq_value << 3); 19735748Sduboff gem_mii_write(dp, MII_RESV, reg14h); 19745748Sduboff } else { 19755748Sduboff reg14h = (gem_mii_read(dp, MII_RESV) & ~0x4000) | 0x2000; 19765748Sduboff if (rev == SIS630A_900_REV && 19775748Sduboff (lp->bridge_revid == SIS630B0 || 19785748Sduboff lp->bridge_revid == SIS630B1)) { 19795748Sduboff 19805748Sduboff reg14h |= 0x0200; 19815748Sduboff } 19825748Sduboff gem_mii_write(dp, MII_RESV, reg14h); 19835748Sduboff } 19845748Sduboff } 19855748Sduboff 19865748Sduboff /* ======================================================== */ 19875748Sduboff /* 19885748Sduboff * OS depend (device driver) routine 19895748Sduboff */ 19905748Sduboff /* ======================================================== */ 19915748Sduboff static void 19925748Sduboff sfe_chipinfo_init_sis900(struct gem_dev *dp) 19935748Sduboff { 19945748Sduboff int rev; 19955748Sduboff struct sfe_dev *lp = (struct sfe_dev *)dp->private; 19965748Sduboff 19975748Sduboff rev = lp->revid; 19985748Sduboff 19995748Sduboff if (rev == SIS630E_900_REV /* 0x81 */) { 20005748Sduboff /* sis630E */ 20015748Sduboff lp->get_mac_addr = &sfe_get_mac_addr_sis630e; 20025748Sduboff } else if (rev > 0x81 && rev <= 0x90) { 20035748Sduboff /* 630S, 630EA1, 630ET, 635A */ 20045748Sduboff lp->get_mac_addr = &sfe_get_mac_addr_sis635; 20055748Sduboff } else if (rev == SIS962_900_REV /* 0x91 */) { 20065748Sduboff /* sis962 or later */ 20075748Sduboff lp->get_mac_addr = &sfe_get_mac_addr_sis962; 20085748Sduboff } else { 20095748Sduboff /* sis900 */ 20105748Sduboff lp->get_mac_addr = &sfe_get_mac_addr_sis900; 20115748Sduboff } 20125748Sduboff 20135748Sduboff lp->bridge_revid = 0; 20145748Sduboff 20155748Sduboff if (rev == SIS630E_900_REV || rev == SIS630EA1_900_REV || 20165748Sduboff rev == SIS630A_900_REV || rev == SIS630ET_900_REV) { 20175748Sduboff /* 20185748Sduboff * read host bridge revision 20195748Sduboff */ 20205748Sduboff dev_info_t *bridge; 20215748Sduboff ddi_acc_handle_t bridge_handle; 20225748Sduboff 20235748Sduboff if ((bridge = sfe_search_pci_dev(0x1039, 0x630)) == NULL) { 20245748Sduboff cmn_err(CE_WARN, 20255748Sduboff "%s: cannot find host bridge (pci1039,630)", 20265748Sduboff dp->name); 20275748Sduboff return; 20285748Sduboff } 20295748Sduboff 20305748Sduboff if (pci_config_setup(bridge, &bridge_handle) != DDI_SUCCESS) { 20315748Sduboff cmn_err(CE_WARN, "%s: pci_config_setup failed", 20325748Sduboff dp->name); 20335748Sduboff return; 20345748Sduboff } 20355748Sduboff 20365748Sduboff lp->bridge_revid = 20375748Sduboff pci_config_get8(bridge_handle, PCI_CONF_REVID); 20385748Sduboff pci_config_teardown(&bridge_handle); 20395748Sduboff } 20405748Sduboff } 20415748Sduboff 20425748Sduboff static int 20435748Sduboff sfe_attach_chip(struct gem_dev *dp) 20445748Sduboff { 20455748Sduboff struct sfe_dev *lp = (struct sfe_dev *)dp->private; 20465748Sduboff 20475748Sduboff DPRINTF(4, (CE_CONT, CONS "!%s: %s called", dp->name, __func__)); 20485748Sduboff 20495748Sduboff /* setup chip-depend get_mac_address function */ 20505748Sduboff if (lp->chip->chip_type == CHIPTYPE_SIS900) { 20515748Sduboff sfe_chipinfo_init_sis900(dp); 20525748Sduboff } else { 20535748Sduboff lp->get_mac_addr = &sfe_get_mac_addr_dp83815; 20545748Sduboff } 20555748Sduboff 20565748Sduboff /* read MAC address */ 20575748Sduboff if (!(lp->get_mac_addr)(dp)) { 20585748Sduboff cmn_err(CE_WARN, 20595748Sduboff "!%s: %s: failed to get factory mac address" 20605748Sduboff " please specify a mac address in sfe.conf", 20615748Sduboff dp->name, __func__); 20625748Sduboff return (GEM_FAILURE); 20635748Sduboff } 20645748Sduboff 20655748Sduboff if (lp->chip->chip_type == CHIPTYPE_DP83815) { 20665748Sduboff dp->mii_phy_addr = -1; /* no need to scan PHY */ 20675748Sduboff dp->misc_flag |= GEM_VLAN_SOFT; 20685748Sduboff dp->txthr += 4; /* VTAG_SIZE */ 20695748Sduboff } 20705748Sduboff dp->txthr = min(dp->txthr, TXFIFOSIZE - 2); 20715748Sduboff 20725748Sduboff return (GEM_SUCCESS); 20735748Sduboff } 20745748Sduboff 20755748Sduboff static int 20765748Sduboff sfeattach(dev_info_t *dip, ddi_attach_cmd_t cmd) 20775748Sduboff { 20785748Sduboff int unit; 20795748Sduboff const char *drv_name; 20805748Sduboff int i; 20815748Sduboff ddi_acc_handle_t conf_handle; 20825748Sduboff uint16_t vid; 20835748Sduboff uint16_t did; 20845748Sduboff uint8_t rev; 20855748Sduboff #ifdef DEBUG_LEVEL 20865748Sduboff uint32_t iline; 20875748Sduboff uint8_t latim; 20885748Sduboff #endif 20895748Sduboff struct chip_info *p; 20905748Sduboff struct gem_dev *dp; 20915748Sduboff struct sfe_dev *lp; 20925748Sduboff caddr_t base; 20935748Sduboff ddi_acc_handle_t regs_ha; 20945748Sduboff struct gem_conf *gcp; 20955748Sduboff 20965748Sduboff unit = ddi_get_instance(dip); 20975748Sduboff drv_name = ddi_driver_name(dip); 20985748Sduboff 20995748Sduboff DPRINTF(3, (CE_CONT, CONS "%s%d: sfeattach: called", drv_name, unit)); 21005748Sduboff 21015748Sduboff /* 21025748Sduboff * Common codes after power-up 21035748Sduboff */ 21045748Sduboff if (pci_config_setup(dip, &conf_handle) != DDI_SUCCESS) { 21055748Sduboff cmn_err(CE_WARN, "%s%d: ddi_regs_map_setup failed", 21065748Sduboff drv_name, unit); 21075748Sduboff goto err; 21085748Sduboff } 21095748Sduboff 21105748Sduboff vid = pci_config_get16(conf_handle, PCI_CONF_VENID); 21115748Sduboff did = pci_config_get16(conf_handle, PCI_CONF_DEVID); 21125748Sduboff rev = pci_config_get16(conf_handle, PCI_CONF_REVID); 21135748Sduboff #ifdef DEBUG_LEVEL 21147116Sduboff iline = pci_config_get32(conf_handle, PCI_CONF_ILINE); 21157116Sduboff latim = pci_config_get8(conf_handle, PCI_CONF_LATENCY_TIMER); 21165748Sduboff #endif 21175748Sduboff #ifdef DEBUG_BUILT_IN_SIS900 21185748Sduboff rev = SIS630E_900_REV; 21195748Sduboff #endif 21205748Sduboff for (i = 0, p = sfe_chiptbl; i < CHIPTABLESIZE; i++, p++) { 21215748Sduboff if (p->venid == vid && p->devid == did) { 21225748Sduboff /* found */ 21235748Sduboff goto chip_found; 21245748Sduboff } 21255748Sduboff } 21265748Sduboff 21275748Sduboff /* Not found */ 21285748Sduboff cmn_err(CE_WARN, 21295748Sduboff "%s%d: sfe_attach: wrong PCI venid/devid (0x%x, 0x%x)", 21305748Sduboff drv_name, unit, vid, did); 21315748Sduboff pci_config_teardown(&conf_handle); 21325748Sduboff goto err; 21335748Sduboff 21345748Sduboff chip_found: 21355748Sduboff pci_config_put16(conf_handle, PCI_CONF_COMM, 21365748Sduboff PCI_COMM_IO | PCI_COMM_MAE | PCI_COMM_ME | 21375748Sduboff pci_config_get16(conf_handle, PCI_CONF_COMM)); 21385748Sduboff 21395748Sduboff /* ensure D0 mode */ 21405748Sduboff (void) gem_pci_set_power_state(dip, conf_handle, PCI_PMCSR_D0); 21415748Sduboff 21425748Sduboff pci_config_teardown(&conf_handle); 21435748Sduboff 21445748Sduboff switch (cmd) { 21455748Sduboff case DDI_RESUME: 21465748Sduboff return (gem_resume(dip)); 21475748Sduboff 21485748Sduboff case DDI_ATTACH: 21495748Sduboff 21505748Sduboff DPRINTF(0, (CE_CONT, 21515748Sduboff CONS "%s%d: ilr 0x%08x, latency_timer:0x%02x", 21525748Sduboff drv_name, unit, iline, latim)); 21535748Sduboff 21545748Sduboff /* 21555748Sduboff * Map in the device registers. 21565748Sduboff */ 21575748Sduboff if (gem_pci_regs_map_setup(dip, 21585748Sduboff (sfe_use_pcimemspace && p->chip_type == CHIPTYPE_DP83815) 21595748Sduboff ? PCI_ADDR_MEM32 : PCI_ADDR_IO, PCI_ADDR_MASK, 21605748Sduboff &sfe_dev_attr, &base, ®s_ha) != DDI_SUCCESS) { 21615748Sduboff cmn_err(CE_WARN, 21625748Sduboff "%s%d: ddi_regs_map_setup failed", 21635748Sduboff drv_name, unit); 21645748Sduboff goto err; 21655748Sduboff } 21665748Sduboff 21675748Sduboff /* 21685748Sduboff * construct gem configuration 21695748Sduboff */ 21705748Sduboff gcp = kmem_zalloc(sizeof (*gcp), KM_SLEEP); 21715748Sduboff 21725748Sduboff /* name */ 21735748Sduboff (void) sprintf(gcp->gc_name, "%s%d", drv_name, unit); 21745748Sduboff 21755748Sduboff /* consistency on tx and rx */ 21765748Sduboff gcp->gc_tx_buf_align = sizeof (uint8_t) - 1; 21775748Sduboff gcp->gc_tx_max_frags = MAXTXFRAGS; 21785748Sduboff gcp->gc_tx_max_descs_per_pkt = gcp->gc_tx_max_frags; 21795748Sduboff gcp->gc_tx_desc_unit_shift = 4; /* 16 byte */ 21805748Sduboff gcp->gc_tx_buf_size = TX_BUF_SIZE; 21815748Sduboff gcp->gc_tx_buf_limit = gcp->gc_tx_buf_size; 21825748Sduboff gcp->gc_tx_ring_size = TX_RING_SIZE; 21835748Sduboff gcp->gc_tx_ring_limit = gcp->gc_tx_ring_size; 21845748Sduboff gcp->gc_tx_auto_pad = B_TRUE; 21855748Sduboff gcp->gc_tx_copy_thresh = sfe_tx_copy_thresh; 21865748Sduboff gcp->gc_tx_desc_write_oo = B_TRUE; 21875748Sduboff 21885748Sduboff gcp->gc_rx_buf_align = sizeof (uint8_t) - 1; 21895748Sduboff gcp->gc_rx_max_frags = MAXRXFRAGS; 21905748Sduboff gcp->gc_rx_desc_unit_shift = 4; 21915748Sduboff gcp->gc_rx_ring_size = RX_RING_SIZE; 21925748Sduboff gcp->gc_rx_buf_max = RX_BUF_SIZE; 21935748Sduboff gcp->gc_rx_copy_thresh = sfe_rx_copy_thresh; 21945748Sduboff 21955748Sduboff /* map attributes */ 21965748Sduboff gcp->gc_dev_attr = sfe_dev_attr; 21975748Sduboff gcp->gc_buf_attr = sfe_buf_attr; 21985748Sduboff gcp->gc_desc_attr = sfe_buf_attr; 21995748Sduboff 22005748Sduboff /* dma attributes */ 22015748Sduboff gcp->gc_dma_attr_desc = sfe_dma_attr_desc; 22025748Sduboff 22035748Sduboff gcp->gc_dma_attr_txbuf = sfe_dma_attr_buf; 22045748Sduboff gcp->gc_dma_attr_txbuf.dma_attr_align = gcp->gc_tx_buf_align+1; 22055748Sduboff gcp->gc_dma_attr_txbuf.dma_attr_sgllen = gcp->gc_tx_max_frags; 22065748Sduboff 22075748Sduboff gcp->gc_dma_attr_rxbuf = sfe_dma_attr_buf; 22085748Sduboff gcp->gc_dma_attr_rxbuf.dma_attr_align = gcp->gc_rx_buf_align+1; 22095748Sduboff gcp->gc_dma_attr_rxbuf.dma_attr_sgllen = gcp->gc_rx_max_frags; 22105748Sduboff 22115748Sduboff /* time out parameters */ 22125748Sduboff gcp->gc_tx_timeout = 3*ONESEC; 22135748Sduboff gcp->gc_tx_timeout_interval = ONESEC; 22147116Sduboff if (p->chip_type == CHIPTYPE_DP83815) { 22157116Sduboff /* workaround for tx hang */ 22167116Sduboff gcp->gc_tx_timeout_interval = ONESEC/20; /* 50mS */ 22177116Sduboff } 22185748Sduboff 22195748Sduboff /* MII timeout parameters */ 22205748Sduboff gcp->gc_mii_link_watch_interval = ONESEC; 22215748Sduboff gcp->gc_mii_an_watch_interval = ONESEC/5; 22225748Sduboff gcp->gc_mii_reset_timeout = MII_RESET_TIMEOUT; /* 1 sec */ 22235748Sduboff gcp->gc_mii_an_timeout = MII_AN_TIMEOUT; /* 5 sec */ 22245748Sduboff gcp->gc_mii_an_wait = 0; 22255748Sduboff gcp->gc_mii_linkdown_timeout = MII_LINKDOWN_TIMEOUT; 22265748Sduboff 22275748Sduboff /* setting for general PHY */ 22285748Sduboff gcp->gc_mii_an_delay = 0; 22295748Sduboff gcp->gc_mii_linkdown_action = MII_ACTION_RSA; 22305748Sduboff gcp->gc_mii_linkdown_timeout_action = MII_ACTION_RESET; 22315748Sduboff gcp->gc_mii_dont_reset = B_FALSE; 22325748Sduboff 22335748Sduboff 22345748Sduboff /* I/O methods */ 22355748Sduboff 22365748Sduboff /* mac operation */ 22375748Sduboff gcp->gc_attach_chip = &sfe_attach_chip; 22385748Sduboff if (p->chip_type == CHIPTYPE_DP83815) { 22395748Sduboff gcp->gc_reset_chip = &sfe_reset_chip_dp83815; 22405748Sduboff } else { 22415748Sduboff gcp->gc_reset_chip = &sfe_reset_chip_sis900; 22425748Sduboff } 22435748Sduboff gcp->gc_init_chip = &sfe_init_chip; 22445748Sduboff gcp->gc_start_chip = &sfe_start_chip; 22455748Sduboff gcp->gc_stop_chip = &sfe_stop_chip; 22465748Sduboff #ifdef USE_MULTICAST_HASHTBL 22475748Sduboff gcp->gc_multicast_hash = &sfe_mcast_hash; 22485748Sduboff #endif 22495748Sduboff if (p->chip_type == CHIPTYPE_DP83815) { 22505748Sduboff gcp->gc_set_rx_filter = &sfe_set_rx_filter_dp83815; 22515748Sduboff } else { 22525748Sduboff gcp->gc_set_rx_filter = &sfe_set_rx_filter_sis900; 22535748Sduboff } 22545748Sduboff gcp->gc_set_media = &sfe_set_media; 22555748Sduboff gcp->gc_get_stats = &sfe_get_stats; 22565748Sduboff gcp->gc_interrupt = &sfe_interrupt; 22575748Sduboff 22585748Sduboff /* descriptor operation */ 22595748Sduboff gcp->gc_tx_desc_write = &sfe_tx_desc_write; 22605748Sduboff gcp->gc_tx_start = &sfe_tx_start; 22615748Sduboff gcp->gc_rx_desc_write = &sfe_rx_desc_write; 22625748Sduboff gcp->gc_rx_start = NULL; 22635748Sduboff 22645748Sduboff gcp->gc_tx_desc_stat = &sfe_tx_desc_stat; 22655748Sduboff gcp->gc_rx_desc_stat = &sfe_rx_desc_stat; 22665748Sduboff gcp->gc_tx_desc_init = &sfe_tx_desc_init; 22675748Sduboff gcp->gc_rx_desc_init = &sfe_rx_desc_init; 22685748Sduboff gcp->gc_tx_desc_clean = &sfe_tx_desc_clean; 22695748Sduboff gcp->gc_rx_desc_clean = &sfe_rx_desc_clean; 22705748Sduboff 22715748Sduboff /* mii operations */ 22725748Sduboff if (p->chip_type == CHIPTYPE_DP83815) { 22737116Sduboff gcp->gc_mii_probe = &sfe_mii_probe_dp83815; 22747116Sduboff gcp->gc_mii_init = &sfe_mii_init_dp83815; 22755748Sduboff gcp->gc_mii_config = &sfe_mii_config_dp83815; 22765748Sduboff gcp->gc_mii_sync = &sfe_mii_sync_dp83815; 22775748Sduboff gcp->gc_mii_read = &sfe_mii_read_dp83815; 22785748Sduboff gcp->gc_mii_write = &sfe_mii_write_dp83815; 22795748Sduboff gcp->gc_mii_tune_phy = NULL; 22805748Sduboff gcp->gc_flow_control = FLOW_CONTROL_NONE; 22815748Sduboff } else { 22825748Sduboff gcp->gc_mii_probe = &gem_mii_probe_default; 22835748Sduboff gcp->gc_mii_init = NULL; 22845748Sduboff gcp->gc_mii_config = &sfe_mii_config_sis900; 22855748Sduboff gcp->gc_mii_sync = &sfe_mii_sync_sis900; 22865748Sduboff gcp->gc_mii_read = &sfe_mii_read_sis900; 22875748Sduboff gcp->gc_mii_write = &sfe_mii_write_sis900; 22885748Sduboff gcp->gc_mii_tune_phy = &sfe_set_eq_sis630; 22895748Sduboff gcp->gc_flow_control = FLOW_CONTROL_RX_PAUSE; 22905748Sduboff } 22915748Sduboff 22925748Sduboff lp = kmem_zalloc(sizeof (*lp), KM_SLEEP); 22935748Sduboff lp->chip = p; 22945748Sduboff lp->revid = rev; 22957116Sduboff lp->our_intr_bits = 0; 22967116Sduboff lp->isr_pended = 0; 22975748Sduboff 22985748Sduboff cmn_err(CE_CONT, CONS "%s%d: chip:%s rev:0x%02x", 22995748Sduboff drv_name, unit, p->chip_name, rev); 23005748Sduboff 23015748Sduboff dp = gem_do_attach(dip, 0, gcp, base, ®s_ha, 23025748Sduboff lp, sizeof (*lp)); 23035748Sduboff kmem_free(gcp, sizeof (*gcp)); 23045748Sduboff 23055748Sduboff if (dp == NULL) { 23065748Sduboff goto err_freelp; 23075748Sduboff } 23085748Sduboff 23095748Sduboff return (DDI_SUCCESS); 23105748Sduboff 23115748Sduboff err_freelp: 23125748Sduboff kmem_free(lp, sizeof (struct sfe_dev)); 23135748Sduboff err: 23145748Sduboff return (DDI_FAILURE); 23155748Sduboff } 23165748Sduboff return (DDI_FAILURE); 23175748Sduboff } 23185748Sduboff 23195748Sduboff static int 23205748Sduboff sfedetach(dev_info_t *dip, ddi_detach_cmd_t cmd) 23215748Sduboff { 23225748Sduboff switch (cmd) { 23235748Sduboff case DDI_SUSPEND: 23245748Sduboff return (gem_suspend(dip)); 23255748Sduboff 23265748Sduboff case DDI_DETACH: 23275748Sduboff return (gem_do_detach(dip)); 23285748Sduboff } 23295748Sduboff return (DDI_FAILURE); 23305748Sduboff } 23315748Sduboff 2332*8611SSherry.Moore@Sun.COM /* 2333*8611SSherry.Moore@Sun.COM * quiesce(9E) entry point. 2334*8611SSherry.Moore@Sun.COM * 2335*8611SSherry.Moore@Sun.COM * This function is called when the system is single-threaded at high 2336*8611SSherry.Moore@Sun.COM * PIL with preemption disabled. Therefore, this function must not be 2337*8611SSherry.Moore@Sun.COM * blocked. 2338*8611SSherry.Moore@Sun.COM * 2339*8611SSherry.Moore@Sun.COM * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure. 2340*8611SSherry.Moore@Sun.COM * DDI_FAILURE indicates an error condition and should almost never happen. 2341*8611SSherry.Moore@Sun.COM */ 2342*8611SSherry.Moore@Sun.COM #ifdef __sparc 2343*8611SSherry.Moore@Sun.COM #define sfe_quiesce ddi_quiesce_not_supported 2344*8611SSherry.Moore@Sun.COM #else 2345*8611SSherry.Moore@Sun.COM static int 2346*8611SSherry.Moore@Sun.COM sfe_quiesce(dev_info_t *dip) 2347*8611SSherry.Moore@Sun.COM { 2348*8611SSherry.Moore@Sun.COM struct gem_dev *dp; 2349*8611SSherry.Moore@Sun.COM int ret = 0; 2350*8611SSherry.Moore@Sun.COM 2351*8611SSherry.Moore@Sun.COM dp = GEM_GET_DEV(dip); 2352*8611SSherry.Moore@Sun.COM 2353*8611SSherry.Moore@Sun.COM if (dp == NULL) 2354*8611SSherry.Moore@Sun.COM return (DDI_FAILURE); 2355*8611SSherry.Moore@Sun.COM 2356*8611SSherry.Moore@Sun.COM ret = sfe_stop_chip_quiesce(dp); 2357*8611SSherry.Moore@Sun.COM 2358*8611SSherry.Moore@Sun.COM return (ret); 2359*8611SSherry.Moore@Sun.COM } 2360*8611SSherry.Moore@Sun.COM #endif 2361*8611SSherry.Moore@Sun.COM 23625748Sduboff /* ======================================================== */ 23635748Sduboff /* 23645748Sduboff * OS depend (loadable streams driver) routine 23655748Sduboff */ 23665748Sduboff /* ======================================================== */ 23675748Sduboff DDI_DEFINE_STREAM_OPS(sfe_ops, nulldev, nulldev, sfeattach, sfedetach, 2368*8611SSherry.Moore@Sun.COM nodev, NULL, D_MP, NULL, sfe_quiesce); 23695748Sduboff 23705748Sduboff static struct modldrv modldrv = { 23715748Sduboff &mod_driverops, /* Type of module. This one is a driver */ 23725748Sduboff ident, 23735748Sduboff &sfe_ops, /* driver ops */ 23745748Sduboff }; 23755748Sduboff 23765748Sduboff static struct modlinkage modlinkage = { 23775748Sduboff MODREV_1, &modldrv, NULL 23785748Sduboff }; 23795748Sduboff 23805748Sduboff /* ======================================================== */ 23815748Sduboff /* 23825748Sduboff * Loadable module support 23835748Sduboff */ 23845748Sduboff /* ======================================================== */ 23855748Sduboff int 23865748Sduboff _init(void) 23875748Sduboff { 23885748Sduboff int status; 23895748Sduboff 23905748Sduboff DPRINTF(2, (CE_CONT, CONS "sfe: _init: called")); 23915748Sduboff gem_mod_init(&sfe_ops, "sfe"); 23925748Sduboff status = mod_install(&modlinkage); 23935748Sduboff if (status != DDI_SUCCESS) { 23945748Sduboff gem_mod_fini(&sfe_ops); 23955748Sduboff } 23965748Sduboff return (status); 23975748Sduboff } 23985748Sduboff 23995748Sduboff /* 24005748Sduboff * _fini : done 24015748Sduboff */ 24025748Sduboff int 24035748Sduboff _fini(void) 24045748Sduboff { 24055748Sduboff int status; 24065748Sduboff 24075748Sduboff DPRINTF(2, (CE_CONT, CONS "sfe: _fini: called")); 24085748Sduboff status = mod_remove(&modlinkage); 24095748Sduboff if (status == DDI_SUCCESS) { 24105748Sduboff gem_mod_fini(&sfe_ops); 24115748Sduboff } 24125748Sduboff return (status); 24135748Sduboff } 24145748Sduboff 24155748Sduboff int 24165748Sduboff _info(struct modinfo *modinfop) 24175748Sduboff { 24185748Sduboff return (mod_info(&modlinkage, modinfop)); 24195748Sduboff } 2420