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