1f8919bdaSduboff /* 2f8919bdaSduboff * sfe.c : DP83815/DP83816/SiS900 Fast Ethernet MAC driver for Solaris 3f8919bdaSduboff * 423d366e3Sduboff * Copyright (c) 2002-2008 Masayuki Murayama. All rights reserved. 5f8919bdaSduboff * 6f8919bdaSduboff * Redistribution and use in source and binary forms, with or without 7f8919bdaSduboff * modification, are permitted provided that the following conditions are met: 8f8919bdaSduboff * 9f8919bdaSduboff * 1. Redistributions of source code must retain the above copyright notice, 10f8919bdaSduboff * this list of conditions and the following disclaimer. 11f8919bdaSduboff * 12f8919bdaSduboff * 2. Redistributions in binary form must reproduce the above copyright notice, 13f8919bdaSduboff * this list of conditions and the following disclaimer in the documentation 14f8919bdaSduboff * and/or other materials provided with the distribution. 15f8919bdaSduboff * 16f8919bdaSduboff * 3. Neither the name of the author nor the names of its contributors may be 17f8919bdaSduboff * used to endorse or promote products derived from this software without 18f8919bdaSduboff * specific prior written permission. 19f8919bdaSduboff * 20f8919bdaSduboff * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21f8919bdaSduboff * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22f8919bdaSduboff * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23f8919bdaSduboff * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24f8919bdaSduboff * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25f8919bdaSduboff * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26f8919bdaSduboff * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27f8919bdaSduboff * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28f8919bdaSduboff * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29f8919bdaSduboff * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 30f8919bdaSduboff * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 31f8919bdaSduboff * DAMAGE. 32f8919bdaSduboff */ 33f8919bdaSduboff 34*19397407SSherry Moore /* 35*19397407SSherry Moore * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 36*19397407SSherry Moore * Use is subject to license terms. 37*19397407SSherry Moore */ 38f8919bdaSduboff 39f8919bdaSduboff /* 40f8919bdaSduboff * System Header files. 41f8919bdaSduboff */ 42f8919bdaSduboff #include <sys/types.h> 43f8919bdaSduboff #include <sys/conf.h> 44f8919bdaSduboff #include <sys/debug.h> 45f8919bdaSduboff #include <sys/kmem.h> 46f8919bdaSduboff #include <sys/modctl.h> 47f8919bdaSduboff #include <sys/errno.h> 48f8919bdaSduboff #include <sys/ddi.h> 49f8919bdaSduboff #include <sys/sunddi.h> 50f8919bdaSduboff #include <sys/byteorder.h> 51f8919bdaSduboff #include <sys/ethernet.h> 52f8919bdaSduboff #include <sys/pci.h> 53f8919bdaSduboff 54f8919bdaSduboff #include "sfe_mii.h" 55f8919bdaSduboff #include "sfe_util.h" 56f8919bdaSduboff #include "sfereg.h" 57f8919bdaSduboff 58*19397407SSherry Moore char ident[] = "sis900/dp83815 driver"; 59f8919bdaSduboff 60f8919bdaSduboff /* Debugging support */ 61f8919bdaSduboff #ifdef DEBUG_LEVEL 62f8919bdaSduboff static int sfe_debug = DEBUG_LEVEL; 63f8919bdaSduboff #if DEBUG_LEVEL > 4 64f8919bdaSduboff #define CONS "^" 65f8919bdaSduboff #else 66f8919bdaSduboff #define CONS "!" 67f8919bdaSduboff #endif 68f8919bdaSduboff #define DPRINTF(n, args) if (sfe_debug > (n)) cmn_err args 69f8919bdaSduboff #else 70f8919bdaSduboff #define CONS "!" 71f8919bdaSduboff #define DPRINTF(n, args) 72f8919bdaSduboff #endif 73f8919bdaSduboff 74f8919bdaSduboff /* 75f8919bdaSduboff * Useful macros and typedefs 76f8919bdaSduboff */ 77f8919bdaSduboff #define ONESEC (drv_usectohz(1*1000000)) 78f8919bdaSduboff #define ROUNDUP2(x, a) (((x) + (a) - 1) & ~((a) - 1)) 79f8919bdaSduboff 80f8919bdaSduboff /* 81f8919bdaSduboff * Our configuration 82f8919bdaSduboff */ 83f8919bdaSduboff #define MAXTXFRAGS 1 84f8919bdaSduboff #define MAXRXFRAGS 1 85f8919bdaSduboff 86f8919bdaSduboff #ifndef TX_BUF_SIZE 87f8919bdaSduboff #define TX_BUF_SIZE 64 88f8919bdaSduboff #endif 89f8919bdaSduboff #ifndef TX_RING_SIZE 90f8919bdaSduboff #if MAXTXFRAGS == 1 91f8919bdaSduboff #define TX_RING_SIZE TX_BUF_SIZE 92f8919bdaSduboff #else 93f8919bdaSduboff #define TX_RING_SIZE (TX_BUF_SIZE * 4) 94f8919bdaSduboff #endif 95f8919bdaSduboff #endif 96f8919bdaSduboff 97f8919bdaSduboff #ifndef RX_BUF_SIZE 98f8919bdaSduboff #define RX_BUF_SIZE 256 99f8919bdaSduboff #endif 100f8919bdaSduboff #ifndef RX_RING_SIZE 101f8919bdaSduboff #define RX_RING_SIZE RX_BUF_SIZE 102f8919bdaSduboff #endif 103f8919bdaSduboff 104f8919bdaSduboff #define OUR_INTR_BITS \ 105f8919bdaSduboff (ISR_DPERR | ISR_SSERR | ISR_RMABT | ISR_RTABT | ISR_RXSOVR | \ 106f8919bdaSduboff ISR_TXURN | ISR_TXDESC | ISR_TXERR | \ 107f8919bdaSduboff ISR_RXORN | ISR_RXIDLE | ISR_RXOK | ISR_RXERR) 108f8919bdaSduboff 109f8919bdaSduboff #define USE_MULTICAST_HASHTBL 110f8919bdaSduboff 111f8919bdaSduboff static int sfe_tx_copy_thresh = 256; 112f8919bdaSduboff static int sfe_rx_copy_thresh = 256; 113f8919bdaSduboff 114f8919bdaSduboff /* special PHY registers for SIS900 */ 115f8919bdaSduboff #define MII_CONFIG1 0x0010 116f8919bdaSduboff #define MII_CONFIG2 0x0011 117f8919bdaSduboff #define MII_MASK 0x0013 118f8919bdaSduboff #define MII_RESV 0x0014 119f8919bdaSduboff 120f8919bdaSduboff #define PHY_MASK 0xfffffff0 121f8919bdaSduboff #define PHY_SIS900_INTERNAL 0x001d8000 122f8919bdaSduboff #define PHY_ICS1893 0x0015f440 123f8919bdaSduboff 124f8919bdaSduboff 125f8919bdaSduboff #define SFE_DESC_SIZE 16 /* including pads rounding up to power of 2 */ 126f8919bdaSduboff 127f8919bdaSduboff /* 128f8919bdaSduboff * Supported chips 129f8919bdaSduboff */ 130f8919bdaSduboff struct chip_info { 131f8919bdaSduboff uint16_t venid; 132f8919bdaSduboff uint16_t devid; 133f8919bdaSduboff char *chip_name; 134f8919bdaSduboff int chip_type; 135f8919bdaSduboff #define CHIPTYPE_DP83815 0 136f8919bdaSduboff #define CHIPTYPE_SIS900 1 137f8919bdaSduboff }; 138f8919bdaSduboff 139f8919bdaSduboff /* 140f8919bdaSduboff * Chip dependent MAC state 141f8919bdaSduboff */ 142f8919bdaSduboff struct sfe_dev { 143f8919bdaSduboff /* misc HW information */ 144f8919bdaSduboff struct chip_info *chip; 145f8919bdaSduboff uint32_t our_intr_bits; 14623d366e3Sduboff uint32_t isr_pended; 147f8919bdaSduboff uint32_t cr; 148f8919bdaSduboff uint_t tx_drain_threshold; 149f8919bdaSduboff uint_t tx_fill_threshold; 150f8919bdaSduboff uint_t rx_drain_threshold; 151f8919bdaSduboff uint_t rx_fill_threshold; 152f8919bdaSduboff uint8_t revid; /* revision from PCI configuration */ 153f8919bdaSduboff boolean_t (*get_mac_addr)(struct gem_dev *); 154f8919bdaSduboff uint8_t mac_addr[ETHERADDRL]; 155f8919bdaSduboff uint8_t bridge_revid; 156f8919bdaSduboff }; 157f8919bdaSduboff 158f8919bdaSduboff /* 159f8919bdaSduboff * Hardware information 160f8919bdaSduboff */ 161f8919bdaSduboff struct chip_info sfe_chiptbl[] = { 162f8919bdaSduboff { 0x1039, 0x0900, "SiS900", CHIPTYPE_SIS900, }, 163f8919bdaSduboff { 0x100b, 0x0020, "DP83815/83816", CHIPTYPE_DP83815, }, 164f8919bdaSduboff { 0x1039, 0x7016, "SiS7016", CHIPTYPE_SIS900, }, 165f8919bdaSduboff }; 166f8919bdaSduboff #define CHIPTABLESIZE (sizeof (sfe_chiptbl)/sizeof (struct chip_info)) 167f8919bdaSduboff 168f8919bdaSduboff /* ======================================================== */ 169f8919bdaSduboff 170f8919bdaSduboff /* mii operations */ 171f8919bdaSduboff static void sfe_mii_sync_dp83815(struct gem_dev *); 172f8919bdaSduboff static void sfe_mii_sync_sis900(struct gem_dev *); 173f8919bdaSduboff static uint16_t sfe_mii_read_dp83815(struct gem_dev *, uint_t); 174f8919bdaSduboff static uint16_t sfe_mii_read_sis900(struct gem_dev *, uint_t); 175f8919bdaSduboff static void sfe_mii_write_dp83815(struct gem_dev *, uint_t, uint16_t); 176f8919bdaSduboff static void sfe_mii_write_sis900(struct gem_dev *, uint_t, uint16_t); 177f8919bdaSduboff static void sfe_set_eq_sis630(struct gem_dev *dp); 178f8919bdaSduboff /* nic operations */ 179f8919bdaSduboff static int sfe_reset_chip_sis900(struct gem_dev *); 180f8919bdaSduboff static int sfe_reset_chip_dp83815(struct gem_dev *); 181f8919bdaSduboff static int sfe_init_chip(struct gem_dev *); 182f8919bdaSduboff static int sfe_start_chip(struct gem_dev *); 183f8919bdaSduboff static int sfe_stop_chip(struct gem_dev *); 184f8919bdaSduboff static int sfe_set_media(struct gem_dev *); 185f8919bdaSduboff static int sfe_set_rx_filter_dp83815(struct gem_dev *); 186f8919bdaSduboff static int sfe_set_rx_filter_sis900(struct gem_dev *); 187f8919bdaSduboff static int sfe_get_stats(struct gem_dev *); 188f8919bdaSduboff static int sfe_attach_chip(struct gem_dev *); 189f8919bdaSduboff 190f8919bdaSduboff /* descriptor operations */ 191f8919bdaSduboff static int sfe_tx_desc_write(struct gem_dev *dp, int slot, 192f8919bdaSduboff ddi_dma_cookie_t *dmacookie, int frags, uint64_t flags); 193f8919bdaSduboff static void sfe_tx_start(struct gem_dev *dp, int startslot, int nslot); 194f8919bdaSduboff static void sfe_rx_desc_write(struct gem_dev *dp, int slot, 195f8919bdaSduboff ddi_dma_cookie_t *dmacookie, int frags); 196f8919bdaSduboff static uint_t sfe_tx_desc_stat(struct gem_dev *dp, int slot, int ndesc); 197f8919bdaSduboff static uint64_t sfe_rx_desc_stat(struct gem_dev *dp, int slot, int ndesc); 198f8919bdaSduboff 199f8919bdaSduboff static void sfe_tx_desc_init(struct gem_dev *dp, int slot); 200f8919bdaSduboff static void sfe_rx_desc_init(struct gem_dev *dp, int slot); 201f8919bdaSduboff static void sfe_tx_desc_clean(struct gem_dev *dp, int slot); 202f8919bdaSduboff static void sfe_rx_desc_clean(struct gem_dev *dp, int slot); 203f8919bdaSduboff 204f8919bdaSduboff /* interrupt handler */ 205f8919bdaSduboff static uint_t sfe_interrupt(struct gem_dev *dp); 206f8919bdaSduboff 207f8919bdaSduboff /* ======================================================== */ 208f8919bdaSduboff 209f8919bdaSduboff /* mapping attributes */ 210f8919bdaSduboff /* Data access requirements. */ 211f8919bdaSduboff static struct ddi_device_acc_attr sfe_dev_attr = { 212f8919bdaSduboff DDI_DEVICE_ATTR_V0, 213f8919bdaSduboff DDI_STRUCTURE_LE_ACC, 214f8919bdaSduboff DDI_STRICTORDER_ACC 215f8919bdaSduboff }; 216f8919bdaSduboff 217f8919bdaSduboff /* On sparc, Buffers should be native endian for speed */ 218f8919bdaSduboff static struct ddi_device_acc_attr sfe_buf_attr = { 219f8919bdaSduboff DDI_DEVICE_ATTR_V0, 220f8919bdaSduboff DDI_NEVERSWAP_ACC, /* native endianness */ 221f8919bdaSduboff DDI_STRICTORDER_ACC 222f8919bdaSduboff }; 223f8919bdaSduboff 224f8919bdaSduboff static ddi_dma_attr_t sfe_dma_attr_buf = { 225f8919bdaSduboff DMA_ATTR_V0, /* dma_attr_version */ 226f8919bdaSduboff 0, /* dma_attr_addr_lo */ 227f8919bdaSduboff 0xffffffffull, /* dma_attr_addr_hi */ 228f8919bdaSduboff 0x00000fffull, /* dma_attr_count_max */ 229f8919bdaSduboff 0, /* patched later */ /* dma_attr_align */ 230f8919bdaSduboff 0x000003fc, /* dma_attr_burstsizes */ 231f8919bdaSduboff 1, /* dma_attr_minxfer */ 232f8919bdaSduboff 0x00000fffull, /* dma_attr_maxxfer */ 233f8919bdaSduboff 0xffffffffull, /* dma_attr_seg */ 234f8919bdaSduboff 0, /* patched later */ /* dma_attr_sgllen */ 235f8919bdaSduboff 1, /* dma_attr_granular */ 236f8919bdaSduboff 0 /* dma_attr_flags */ 237f8919bdaSduboff }; 238f8919bdaSduboff 239f8919bdaSduboff static ddi_dma_attr_t sfe_dma_attr_desc = { 240f8919bdaSduboff DMA_ATTR_V0, /* dma_attr_version */ 241f8919bdaSduboff 16, /* dma_attr_addr_lo */ 242f8919bdaSduboff 0xffffffffull, /* dma_attr_addr_hi */ 243f8919bdaSduboff 0xffffffffull, /* dma_attr_count_max */ 244f8919bdaSduboff 16, /* dma_attr_align */ 245f8919bdaSduboff 0x000003fc, /* dma_attr_burstsizes */ 246f8919bdaSduboff 1, /* dma_attr_minxfer */ 247f8919bdaSduboff 0xffffffffull, /* dma_attr_maxxfer */ 248f8919bdaSduboff 0xffffffffull, /* dma_attr_seg */ 249f8919bdaSduboff 1, /* dma_attr_sgllen */ 250f8919bdaSduboff 1, /* dma_attr_granular */ 251f8919bdaSduboff 0 /* dma_attr_flags */ 252f8919bdaSduboff }; 253f8919bdaSduboff 254f8919bdaSduboff uint32_t sfe_use_pcimemspace = 0; 255f8919bdaSduboff 256f8919bdaSduboff /* ======================================================== */ 257f8919bdaSduboff /* 258f8919bdaSduboff * HW manipulation routines 259f8919bdaSduboff */ 260f8919bdaSduboff /* ======================================================== */ 261f8919bdaSduboff 262f8919bdaSduboff #define SFE_EEPROM_DELAY(dp) \ 263f8919bdaSduboff { (void) INL(dp, EROMAR); (void) INL(dp, EROMAR); } 264f8919bdaSduboff #define EE_CMD_READ 6 265f8919bdaSduboff #define EE_CMD_SHIFT 6 266f8919bdaSduboff 267f8919bdaSduboff static uint16_t 268f8919bdaSduboff sfe_read_eeprom(struct gem_dev *dp, uint_t offset) 269f8919bdaSduboff { 270f8919bdaSduboff int eedi; 271f8919bdaSduboff int i; 272f8919bdaSduboff uint16_t ret; 273f8919bdaSduboff 274f8919bdaSduboff /* ensure de-assert chip select */ 275f8919bdaSduboff OUTL(dp, EROMAR, 0); 276f8919bdaSduboff SFE_EEPROM_DELAY(dp); 277f8919bdaSduboff OUTL(dp, EROMAR, EROMAR_EESK); 278f8919bdaSduboff SFE_EEPROM_DELAY(dp); 279f8919bdaSduboff 280f8919bdaSduboff /* assert chip select */ 281f8919bdaSduboff offset |= EE_CMD_READ << EE_CMD_SHIFT; 282f8919bdaSduboff 283f8919bdaSduboff for (i = 8; i >= 0; i--) { 284f8919bdaSduboff /* make command */ 285f8919bdaSduboff eedi = ((offset >> i) & 1) << EROMAR_EEDI_SHIFT; 286f8919bdaSduboff 287f8919bdaSduboff /* send 1 bit */ 288f8919bdaSduboff OUTL(dp, EROMAR, EROMAR_EECS | eedi); 289f8919bdaSduboff SFE_EEPROM_DELAY(dp); 290f8919bdaSduboff OUTL(dp, EROMAR, EROMAR_EECS | eedi | EROMAR_EESK); 291f8919bdaSduboff SFE_EEPROM_DELAY(dp); 292f8919bdaSduboff } 293f8919bdaSduboff 294f8919bdaSduboff OUTL(dp, EROMAR, EROMAR_EECS); 295f8919bdaSduboff 296f8919bdaSduboff ret = 0; 297f8919bdaSduboff for (i = 0; i < 16; i++) { 298f8919bdaSduboff /* Get 1 bit */ 299f8919bdaSduboff OUTL(dp, EROMAR, EROMAR_EECS); 300f8919bdaSduboff SFE_EEPROM_DELAY(dp); 301f8919bdaSduboff OUTL(dp, EROMAR, EROMAR_EECS | EROMAR_EESK); 302f8919bdaSduboff SFE_EEPROM_DELAY(dp); 303f8919bdaSduboff 304f8919bdaSduboff ret = (ret << 1) | ((INL(dp, EROMAR) >> EROMAR_EEDO_SHIFT) & 1); 305f8919bdaSduboff } 306f8919bdaSduboff 307f8919bdaSduboff OUTL(dp, EROMAR, 0); 308f8919bdaSduboff SFE_EEPROM_DELAY(dp); 309f8919bdaSduboff 310f8919bdaSduboff return (ret); 311f8919bdaSduboff } 312f8919bdaSduboff #undef SFE_EEPROM_DELAY 313f8919bdaSduboff 314f8919bdaSduboff static boolean_t 315f8919bdaSduboff sfe_get_mac_addr_dp83815(struct gem_dev *dp) 316f8919bdaSduboff { 317f8919bdaSduboff uint8_t *mac; 318f8919bdaSduboff uint_t val; 319f8919bdaSduboff int i; 320f8919bdaSduboff 321f8919bdaSduboff #define BITSET(p, ix, v) (p)[(ix)/8] |= ((v) ? 1 : 0) << ((ix) & 0x7) 322f8919bdaSduboff 323f8919bdaSduboff DPRINTF(4, (CE_CONT, CONS "%s: %s: called", dp->name, __func__)); 324f8919bdaSduboff 325f8919bdaSduboff mac = dp->dev_addr.ether_addr_octet; 326f8919bdaSduboff 327f8919bdaSduboff /* first of all, clear MAC address buffer */ 328f8919bdaSduboff bzero(mac, ETHERADDRL); 329f8919bdaSduboff 330f8919bdaSduboff /* get bit 0 */ 331f8919bdaSduboff val = sfe_read_eeprom(dp, 0x6); 332f8919bdaSduboff BITSET(mac, 0, val & 1); 333f8919bdaSduboff 334f8919bdaSduboff /* get bit 1 - 16 */ 335f8919bdaSduboff val = sfe_read_eeprom(dp, 0x7); 336f8919bdaSduboff for (i = 0; i < 16; i++) { 337f8919bdaSduboff BITSET(mac, 1 + i, val & (1 << (15 - i))); 338f8919bdaSduboff } 339f8919bdaSduboff 340f8919bdaSduboff /* get bit 17 - 32 */ 341f8919bdaSduboff val = sfe_read_eeprom(dp, 0x8); 342f8919bdaSduboff for (i = 0; i < 16; i++) { 343f8919bdaSduboff BITSET(mac, 17 + i, val & (1 << (15 - i))); 344f8919bdaSduboff } 345f8919bdaSduboff 346f8919bdaSduboff /* get bit 33 - 47 */ 347f8919bdaSduboff val = sfe_read_eeprom(dp, 0x9); 348f8919bdaSduboff for (i = 0; i < 15; i++) { 349f8919bdaSduboff BITSET(mac, 33 + i, val & (1 << (15 - i))); 350f8919bdaSduboff } 351f8919bdaSduboff 352f8919bdaSduboff return (B_TRUE); 353f8919bdaSduboff #undef BITSET 354f8919bdaSduboff } 355f8919bdaSduboff 356f8919bdaSduboff static boolean_t 357f8919bdaSduboff sfe_get_mac_addr_sis900(struct gem_dev *dp) 358f8919bdaSduboff { 359f8919bdaSduboff uint_t val; 360f8919bdaSduboff int i; 361f8919bdaSduboff uint8_t *mac; 362f8919bdaSduboff 363f8919bdaSduboff mac = dp->dev_addr.ether_addr_octet; 364f8919bdaSduboff 365f8919bdaSduboff for (i = 0; i < ETHERADDRL/2; i++) { 366f8919bdaSduboff val = sfe_read_eeprom(dp, 0x8 + i); 367f8919bdaSduboff *mac++ = (uint8_t)val; 368f8919bdaSduboff *mac++ = (uint8_t)(val >> 8); 369f8919bdaSduboff } 370f8919bdaSduboff 371f8919bdaSduboff return (B_TRUE); 372f8919bdaSduboff } 373f8919bdaSduboff 374f8919bdaSduboff static dev_info_t * 375f8919bdaSduboff sfe_search_pci_dev_subr(dev_info_t *cur_node, int vendor_id, int device_id) 376f8919bdaSduboff { 377f8919bdaSduboff dev_info_t *child_id; 378f8919bdaSduboff dev_info_t *ret; 379f8919bdaSduboff int vid, did; 380f8919bdaSduboff 381f8919bdaSduboff if (cur_node == NULL) { 382f8919bdaSduboff return (NULL); 383f8919bdaSduboff } 384f8919bdaSduboff 385f8919bdaSduboff /* check brothers */ 386f8919bdaSduboff do { 387f8919bdaSduboff vid = ddi_prop_get_int(DDI_DEV_T_ANY, cur_node, 388f8919bdaSduboff DDI_PROP_DONTPASS, "vendor-id", -1); 389f8919bdaSduboff did = ddi_prop_get_int(DDI_DEV_T_ANY, cur_node, 390f8919bdaSduboff DDI_PROP_DONTPASS, "device-id", -1); 391f8919bdaSduboff 392f8919bdaSduboff if (vid == vendor_id && did == device_id) { 393f8919bdaSduboff /* found */ 394f8919bdaSduboff return (cur_node); 395f8919bdaSduboff } 396f8919bdaSduboff 397f8919bdaSduboff /* check children */ 398f8919bdaSduboff if ((child_id = ddi_get_child(cur_node)) != NULL) { 399f8919bdaSduboff if ((ret = sfe_search_pci_dev_subr(child_id, 400f8919bdaSduboff vendor_id, device_id)) != NULL) { 401f8919bdaSduboff return (ret); 402f8919bdaSduboff } 403f8919bdaSduboff } 404f8919bdaSduboff 405f8919bdaSduboff } while ((cur_node = ddi_get_next_sibling(cur_node)) != NULL); 406f8919bdaSduboff 407f8919bdaSduboff /* not found */ 408f8919bdaSduboff return (NULL); 409f8919bdaSduboff } 410f8919bdaSduboff 411f8919bdaSduboff static dev_info_t * 412f8919bdaSduboff sfe_search_pci_dev(int vendor_id, int device_id) 413f8919bdaSduboff { 414f8919bdaSduboff return (sfe_search_pci_dev_subr(ddi_root_node(), vendor_id, device_id)); 415f8919bdaSduboff } 416f8919bdaSduboff 417f8919bdaSduboff /* Avoid undefined symbol for non IA architectures */ 418f8919bdaSduboff #pragma weak inb 419f8919bdaSduboff #pragma weak outb 420f8919bdaSduboff 421f8919bdaSduboff static boolean_t 422f8919bdaSduboff sfe_get_mac_addr_sis630e(struct gem_dev *dp) 423f8919bdaSduboff { 424f8919bdaSduboff int i; 425f8919bdaSduboff dev_info_t *isa_bridge; 426f8919bdaSduboff ddi_acc_handle_t isa_handle; 427f8919bdaSduboff int reg; 428f8919bdaSduboff 429f8919bdaSduboff if (inb == NULL || outb == NULL) { 430f8919bdaSduboff /* this is not IA architecture */ 431f8919bdaSduboff return (B_FALSE); 432f8919bdaSduboff } 433f8919bdaSduboff 434f8919bdaSduboff if ((isa_bridge = sfe_search_pci_dev(0x1039, 0x8)) == NULL) { 435f8919bdaSduboff cmn_err(CE_WARN, "%s: failed to find isa-bridge pci1039,8", 436f8919bdaSduboff dp->name); 437f8919bdaSduboff return (B_FALSE); 438f8919bdaSduboff } 439f8919bdaSduboff 440f8919bdaSduboff if (pci_config_setup(isa_bridge, &isa_handle) != DDI_SUCCESS) { 441f8919bdaSduboff cmn_err(CE_WARN, "%s: ddi_regs_map_setup failed", 442f8919bdaSduboff dp->name); 443f8919bdaSduboff return (B_FALSE); 444f8919bdaSduboff } 445f8919bdaSduboff 446f8919bdaSduboff /* enable to access CMOS RAM */ 447f8919bdaSduboff reg = pci_config_get8(isa_handle, 0x48); 448f8919bdaSduboff pci_config_put8(isa_handle, 0x48, reg | 0x40); 449f8919bdaSduboff 450f8919bdaSduboff for (i = 0; i < ETHERADDRL; i++) { 451f8919bdaSduboff outb(0x70, 0x09 + i); 452f8919bdaSduboff dp->dev_addr.ether_addr_octet[i] = inb(0x71); 453f8919bdaSduboff } 454f8919bdaSduboff 455f8919bdaSduboff /* disable to access CMOS RAM */ 456f8919bdaSduboff pci_config_put8(isa_handle, 0x48, reg); 457f8919bdaSduboff pci_config_teardown(&isa_handle); 458f8919bdaSduboff 459f8919bdaSduboff return (B_TRUE); 460f8919bdaSduboff } 461f8919bdaSduboff 462f8919bdaSduboff static boolean_t 463f8919bdaSduboff sfe_get_mac_addr_sis635(struct gem_dev *dp) 464f8919bdaSduboff { 465f8919bdaSduboff int i; 466f8919bdaSduboff uint32_t rfcr; 467f8919bdaSduboff uint16_t v; 468f8919bdaSduboff struct sfe_dev *lp = dp->private; 469f8919bdaSduboff 470f8919bdaSduboff DPRINTF(2, (CE_CONT, CONS "%s: %s: called", dp->name, __func__)); 471f8919bdaSduboff rfcr = INL(dp, RFCR); 472f8919bdaSduboff 473f8919bdaSduboff OUTL(dp, CR, lp->cr | CR_RELOAD); 474f8919bdaSduboff OUTL(dp, CR, lp->cr); 475f8919bdaSduboff 476f8919bdaSduboff /* disable packet filtering before reading filter */ 477f8919bdaSduboff OUTL(dp, RFCR, rfcr & ~RFCR_RFEN); 478f8919bdaSduboff 479f8919bdaSduboff /* load MAC addr from filter data register */ 480f8919bdaSduboff for (i = 0; i < ETHERADDRL; i += 2) { 481f8919bdaSduboff OUTL(dp, RFCR, 482f8919bdaSduboff (RFADDR_MAC_SIS900 + (i/2)) << RFCR_RFADDR_SHIFT_SIS900); 483f8919bdaSduboff v = INL(dp, RFDR); 484f8919bdaSduboff dp->dev_addr.ether_addr_octet[i] = (uint8_t)v; 485f8919bdaSduboff dp->dev_addr.ether_addr_octet[i+1] = (uint8_t)(v >> 8); 486f8919bdaSduboff } 487f8919bdaSduboff 488f8919bdaSduboff /* re-enable packet filtering */ 489f8919bdaSduboff OUTL(dp, RFCR, rfcr | RFCR_RFEN); 490f8919bdaSduboff 491f8919bdaSduboff return (B_TRUE); 492f8919bdaSduboff } 493f8919bdaSduboff 494f8919bdaSduboff static boolean_t 495f8919bdaSduboff sfe_get_mac_addr_sis962(struct gem_dev *dp) 496f8919bdaSduboff { 497f8919bdaSduboff boolean_t ret; 498f8919bdaSduboff int i; 499f8919bdaSduboff 500f8919bdaSduboff ret = B_FALSE; 501f8919bdaSduboff 502f8919bdaSduboff /* rise request signal to access EEPROM */ 503f8919bdaSduboff OUTL(dp, MEAR, EROMAR_EEREQ); 504f8919bdaSduboff for (i = 0; (INL(dp, MEAR) & EROMAR_EEGNT) == 0; i++) { 505f8919bdaSduboff if (i > 200) { 506f8919bdaSduboff /* failed to acquire eeprom */ 507f8919bdaSduboff cmn_err(CE_NOTE, 508f8919bdaSduboff CONS "%s: failed to access eeprom", dp->name); 509f8919bdaSduboff goto x; 510f8919bdaSduboff } 511f8919bdaSduboff drv_usecwait(10); 512f8919bdaSduboff } 513f8919bdaSduboff ret = sfe_get_mac_addr_sis900(dp); 514f8919bdaSduboff x: 515f8919bdaSduboff /* release EEPROM */ 516f8919bdaSduboff OUTL(dp, MEAR, EROMAR_EEDONE); 517f8919bdaSduboff 518f8919bdaSduboff return (ret); 519f8919bdaSduboff } 520f8919bdaSduboff 521f8919bdaSduboff static int 522f8919bdaSduboff sfe_reset_chip_sis900(struct gem_dev *dp) 523f8919bdaSduboff { 524f8919bdaSduboff int i; 525f8919bdaSduboff uint32_t done; 526f8919bdaSduboff uint32_t val; 527f8919bdaSduboff struct sfe_dev *lp = dp->private; 528f8919bdaSduboff 529f8919bdaSduboff DPRINTF(4, (CE_CONT, CONS "%s: %s called", dp->name, __func__)); 530f8919bdaSduboff 531f8919bdaSduboff /* invalidate mac addr cache */ 532f8919bdaSduboff bzero(lp->mac_addr, sizeof (lp->mac_addr)); 533f8919bdaSduboff 534f8919bdaSduboff lp->cr = 0; 535f8919bdaSduboff 536f8919bdaSduboff /* inhibit interrupt */ 537f8919bdaSduboff OUTL(dp, IMR, 0); 53823d366e3Sduboff lp->isr_pended |= INL(dp, ISR) & lp->our_intr_bits; 539f8919bdaSduboff 540f8919bdaSduboff OUTL(dp, RFCR, 0); 541f8919bdaSduboff 542f8919bdaSduboff OUTL(dp, CR, CR_RST | CR_TXR | CR_RXR); 543f8919bdaSduboff drv_usecwait(10); 544f8919bdaSduboff 545f8919bdaSduboff done = 0; 546f8919bdaSduboff for (i = 0; done != (ISR_TXRCMP | ISR_RXRCMP); i++) { 547f8919bdaSduboff if (i > 1000) { 548f8919bdaSduboff cmn_err(CE_WARN, "%s: chip reset timeout", dp->name); 549f8919bdaSduboff return (GEM_FAILURE); 550f8919bdaSduboff } 551f8919bdaSduboff done |= INL(dp, ISR) & (ISR_TXRCMP | ISR_RXRCMP); 552f8919bdaSduboff drv_usecwait(10); 553f8919bdaSduboff } 554f8919bdaSduboff 555f8919bdaSduboff if (lp->revid == SIS630ET_900_REV) { 556f8919bdaSduboff lp->cr |= CR_ACCESSMODE; 557f8919bdaSduboff OUTL(dp, CR, lp->cr | INL(dp, CR)); 558f8919bdaSduboff } 559f8919bdaSduboff 560f8919bdaSduboff /* Configuration register: enable PCI parity */ 561f8919bdaSduboff DPRINTF(2, (CE_CONT, CONS "%s: cfg:%b", 562f8919bdaSduboff dp->name, INL(dp, CFG), CFG_BITS_SIS900)); 56323d366e3Sduboff val = 0; 564f8919bdaSduboff if (lp->revid >= SIS635A_900_REV || 565f8919bdaSduboff lp->revid == SIS900B_900_REV) { 566f8919bdaSduboff /* what is this ? */ 567f8919bdaSduboff val |= CFG_RND_CNT; 568f8919bdaSduboff } 569f8919bdaSduboff OUTL(dp, CFG, val); 570f8919bdaSduboff DPRINTF(2, (CE_CONT, CONS "%s: cfg:%b", dp->name, 571f8919bdaSduboff INL(dp, CFG), CFG_BITS_SIS900)); 572f8919bdaSduboff 573f8919bdaSduboff return (GEM_SUCCESS); 574f8919bdaSduboff } 575f8919bdaSduboff 576f8919bdaSduboff static int 577f8919bdaSduboff sfe_reset_chip_dp83815(struct gem_dev *dp) 578f8919bdaSduboff { 579f8919bdaSduboff int i; 58023d366e3Sduboff uint32_t val; 581f8919bdaSduboff struct sfe_dev *lp = dp->private; 582f8919bdaSduboff 583f8919bdaSduboff DPRINTF(4, (CE_CONT, CONS "%s: %s called", dp->name, __func__)); 584f8919bdaSduboff 585f8919bdaSduboff /* invalidate mac addr cache */ 586f8919bdaSduboff bzero(lp->mac_addr, sizeof (lp->mac_addr)); 587f8919bdaSduboff 588f8919bdaSduboff lp->cr = 0; 589f8919bdaSduboff 590f8919bdaSduboff /* inhibit interrupts */ 591f8919bdaSduboff OUTL(dp, IMR, 0); 59223d366e3Sduboff lp->isr_pended |= INL(dp, ISR) & lp->our_intr_bits; 593f8919bdaSduboff 594f8919bdaSduboff OUTL(dp, RFCR, 0); 595f8919bdaSduboff 596f8919bdaSduboff OUTL(dp, CR, CR_RST); 597f8919bdaSduboff drv_usecwait(10); 598f8919bdaSduboff 599f8919bdaSduboff for (i = 0; INL(dp, CR) & CR_RST; i++) { 600f8919bdaSduboff if (i > 100) { 601f8919bdaSduboff cmn_err(CE_WARN, "!%s: chip reset timeout", dp->name); 602f8919bdaSduboff return (GEM_FAILURE); 603f8919bdaSduboff } 604f8919bdaSduboff drv_usecwait(10); 605f8919bdaSduboff } 606f8919bdaSduboff DPRINTF(0, (CE_CONT, "!%s: chip reset in %duS", dp->name, i*10)); 607f8919bdaSduboff 608f8919bdaSduboff OUTL(dp, CCSR, CCSR_PMESTS); 609f8919bdaSduboff OUTL(dp, CCSR, 0); 610f8919bdaSduboff 611f8919bdaSduboff /* Configuration register: enable PCI parity */ 612f8919bdaSduboff DPRINTF(2, (CE_CONT, CONS "%s: cfg:%b", 613f8919bdaSduboff dp->name, INL(dp, CFG), CFG_BITS_DP83815)); 61423d366e3Sduboff val = INL(dp, CFG) & (CFG_ANEG_SEL | CFG_PHY_CFG); 61523d366e3Sduboff OUTL(dp, CFG, val | CFG_PAUSE_ADV); 616f8919bdaSduboff DPRINTF(2, (CE_CONT, CONS "%s: cfg:%b", dp->name, 617f8919bdaSduboff INL(dp, CFG), CFG_BITS_DP83815)); 618f8919bdaSduboff 619f8919bdaSduboff return (GEM_SUCCESS); 620f8919bdaSduboff } 621f8919bdaSduboff 622f8919bdaSduboff static int 623f8919bdaSduboff sfe_init_chip(struct gem_dev *dp) 624f8919bdaSduboff { 625f8919bdaSduboff /* Configuration register: have been set up in sfe_chip_reset */ 626f8919bdaSduboff 627f8919bdaSduboff /* PCI test control register: do nothing */ 628f8919bdaSduboff 629f8919bdaSduboff /* Interrupt status register : do nothing */ 630f8919bdaSduboff 631f8919bdaSduboff /* Interrupt mask register: clear, but leave lp->our_intr_bits */ 632f8919bdaSduboff OUTL(dp, IMR, 0); 633f8919bdaSduboff 634f8919bdaSduboff /* Enhanced PHY Access register (sis900): do nothing */ 635f8919bdaSduboff 636f8919bdaSduboff /* Transmit Descriptor Pointer register: base addr of TX ring */ 637f8919bdaSduboff OUTL(dp, TXDP, dp->tx_ring_dma); 638f8919bdaSduboff 639f8919bdaSduboff /* Receive descriptor pointer register: base addr of RX ring */ 640f8919bdaSduboff OUTL(dp, RXDP, dp->rx_ring_dma); 641f8919bdaSduboff 642f8919bdaSduboff return (GEM_SUCCESS); 643f8919bdaSduboff } 644f8919bdaSduboff 645f8919bdaSduboff static uint_t 646f8919bdaSduboff sfe_mcast_hash(struct gem_dev *dp, uint8_t *addr) 647f8919bdaSduboff { 648f8919bdaSduboff return (gem_ether_crc_be(addr, ETHERADDRL)); 649f8919bdaSduboff } 650f8919bdaSduboff 651f8919bdaSduboff #ifdef DEBUG_LEVEL 652f8919bdaSduboff static void 653f8919bdaSduboff sfe_rxfilter_dump(struct gem_dev *dp, int start, int end) 654f8919bdaSduboff { 655f8919bdaSduboff int i; 656f8919bdaSduboff int j; 657f8919bdaSduboff uint16_t ram[0x10]; 658f8919bdaSduboff 659f8919bdaSduboff cmn_err(CE_CONT, "!%s: rx filter ram dump:", dp->name); 660f8919bdaSduboff #define WORDS_PER_LINE 4 661f8919bdaSduboff for (i = start; i < end; i += WORDS_PER_LINE*2) { 662f8919bdaSduboff for (j = 0; j < WORDS_PER_LINE; j++) { 663f8919bdaSduboff OUTL(dp, RFCR, RFADDR_MAC_DP83815 + i + j*2); 664f8919bdaSduboff ram[j] = INL(dp, RFDR); 665f8919bdaSduboff } 666f8919bdaSduboff 667f8919bdaSduboff cmn_err(CE_CONT, "!0x%02x: 0x%04x 0x%04x 0x%04x 0x%04x", 668f8919bdaSduboff i, ram[0], ram[1], ram[2], ram[3]); 669f8919bdaSduboff } 670f8919bdaSduboff 671f8919bdaSduboff #undef WORDS_PER_LINE 672f8919bdaSduboff } 673f8919bdaSduboff #endif 674f8919bdaSduboff 675f8919bdaSduboff static uint_t sfe_rf_perfect_base_dp83815[] = { 676f8919bdaSduboff RFADDR_PMATCH0_DP83815, 677f8919bdaSduboff RFADDR_PMATCH1_DP83815, 678f8919bdaSduboff RFADDR_PMATCH2_DP83815, 679f8919bdaSduboff RFADDR_PMATCH3_DP83815, 680f8919bdaSduboff }; 681f8919bdaSduboff 682f8919bdaSduboff static int 683f8919bdaSduboff sfe_set_rx_filter_dp83815(struct gem_dev *dp) 684f8919bdaSduboff { 685f8919bdaSduboff int i; 686f8919bdaSduboff int j; 687f8919bdaSduboff uint32_t mode; 688f8919bdaSduboff uint8_t *mac = dp->cur_addr.ether_addr_octet; 689f8919bdaSduboff uint16_t hash_tbl[32]; 690f8919bdaSduboff struct sfe_dev *lp = dp->private; 691f8919bdaSduboff 692f8919bdaSduboff DPRINTF(1, (CE_CONT, CONS "%s: %s: called, mc_count:%d, mode:0x%b", 693f8919bdaSduboff dp->name, __func__, dp->mc_count, dp->rxmode, RXMODE_BITS)); 694f8919bdaSduboff 695f8919bdaSduboff #if DEBUG_LEVEL > 0 696f8919bdaSduboff for (i = 0; i < dp->mc_count; i++) { 697f8919bdaSduboff cmn_err(CE_CONT, 698f8919bdaSduboff "!%s: adding mcast(%d) %02x:%02x:%02x:%02x:%02x:%02x", 699f8919bdaSduboff dp->name, i, 700f8919bdaSduboff dp->mc_list[i].addr.ether_addr_octet[0], 701f8919bdaSduboff dp->mc_list[i].addr.ether_addr_octet[1], 702f8919bdaSduboff dp->mc_list[i].addr.ether_addr_octet[2], 703f8919bdaSduboff dp->mc_list[i].addr.ether_addr_octet[3], 704f8919bdaSduboff dp->mc_list[i].addr.ether_addr_octet[4], 705f8919bdaSduboff dp->mc_list[i].addr.ether_addr_octet[5]); 706f8919bdaSduboff } 707f8919bdaSduboff #endif 708f8919bdaSduboff if ((dp->rxmode & RXMODE_ENABLE) == 0) { 709f8919bdaSduboff /* disable rx filter */ 710f8919bdaSduboff OUTL(dp, RFCR, 0); 711f8919bdaSduboff return (GEM_SUCCESS); 712f8919bdaSduboff } 713f8919bdaSduboff 714f8919bdaSduboff /* 715f8919bdaSduboff * Set Receive filter control register 716f8919bdaSduboff */ 717f8919bdaSduboff if (dp->rxmode & RXMODE_PROMISC) { 718f8919bdaSduboff /* all broadcast, all multicast, all physical */ 719f8919bdaSduboff mode = RFCR_AAB | RFCR_AAM | RFCR_AAP; 720f8919bdaSduboff } else if ((dp->rxmode & RXMODE_ALLMULTI) || dp->mc_count > 16*32/2) { 721f8919bdaSduboff /* all broadcast, all multicast, physical for the chip */ 722f8919bdaSduboff mode = RFCR_AAB | RFCR_AAM | RFCR_APM_DP83815; 723f8919bdaSduboff } else if (dp->mc_count > 4) { 724f8919bdaSduboff /* 725f8919bdaSduboff * Use multicast hash table, 726f8919bdaSduboff * accept all broadcast and physical for the chip. 727f8919bdaSduboff */ 728f8919bdaSduboff mode = RFCR_AAB | RFCR_MHEN_DP83815 | RFCR_APM_DP83815; 729f8919bdaSduboff 730f8919bdaSduboff bzero(hash_tbl, sizeof (hash_tbl)); 731f8919bdaSduboff for (i = 0; i < dp->mc_count; i++) { 732f8919bdaSduboff j = dp->mc_list[i].hash >> (32 - 9); 733f8919bdaSduboff hash_tbl[j / 16] |= 1 << (j % 16); 734f8919bdaSduboff } 735f8919bdaSduboff } else { 736f8919bdaSduboff /* 737f8919bdaSduboff * Use pattern mach filter for multicast address, 738f8919bdaSduboff * accept all broadcast and physical for the chip 739f8919bdaSduboff */ 740f8919bdaSduboff /* need to enable corresponding pattern registers */ 741f8919bdaSduboff mode = RFCR_AAB | RFCR_APM_DP83815 | 742f8919bdaSduboff (((1 << dp->mc_count) - 1) << RFCR_APAT_SHIFT); 743f8919bdaSduboff } 744f8919bdaSduboff 745f8919bdaSduboff #if DEBUG_LEVEL > 1 746f8919bdaSduboff cmn_err(CE_CONT, 747f8919bdaSduboff "!%s: mac %02x:%02x:%02x:%02x:%02x:%02x" 748f8919bdaSduboff " cache %02x:%02x:%02x:%02x:%02x:%02x", 749f8919bdaSduboff dp->name, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], 750f8919bdaSduboff lp->mac_addr[0], lp->mac_addr[1], 751f8919bdaSduboff lp->mac_addr[2], lp->mac_addr[3], 752f8919bdaSduboff lp->mac_addr[4], lp->mac_addr[5]); 753f8919bdaSduboff #endif 754f8919bdaSduboff if (bcmp(mac, lp->mac_addr, ETHERADDRL) != 0) { 755f8919bdaSduboff /* 756f8919bdaSduboff * XXX - need to *disable* rx filter to load mac address for 757f8919bdaSduboff * the chip. otherwise, we cannot setup rxfilter correctly. 758f8919bdaSduboff */ 759f8919bdaSduboff /* setup perfect match register for my station address */ 760f8919bdaSduboff for (i = 0; i < ETHERADDRL; i += 2) { 761f8919bdaSduboff OUTL(dp, RFCR, RFADDR_MAC_DP83815 + i); 762f8919bdaSduboff OUTL(dp, RFDR, (mac[i+1] << 8) | mac[i]); 763f8919bdaSduboff } 764f8919bdaSduboff 765f8919bdaSduboff bcopy(mac, lp->mac_addr, ETHERADDRL); 766f8919bdaSduboff } 767f8919bdaSduboff 768f8919bdaSduboff #if DEBUG_LEVEL > 3 769f8919bdaSduboff /* clear pattern ram */ 770f8919bdaSduboff for (j = 0x200; j < 0x380; j += 2) { 771f8919bdaSduboff OUTL(dp, RFCR, j); 772f8919bdaSduboff OUTL(dp, RFDR, 0); 773f8919bdaSduboff } 774f8919bdaSduboff #endif 775f8919bdaSduboff if (mode & RFCR_APAT_DP83815) { 776f8919bdaSduboff /* setup multicast address into pattern match registers */ 777f8919bdaSduboff for (j = 0; j < dp->mc_count; j++) { 778f8919bdaSduboff mac = &dp->mc_list[j].addr.ether_addr_octet[0]; 779f8919bdaSduboff for (i = 0; i < ETHERADDRL; i += 2) { 780f8919bdaSduboff OUTL(dp, RFCR, 781f8919bdaSduboff sfe_rf_perfect_base_dp83815[j] + i*2); 782f8919bdaSduboff OUTL(dp, RFDR, (mac[i+1] << 8) | mac[i]); 783f8919bdaSduboff } 784f8919bdaSduboff } 785f8919bdaSduboff 786f8919bdaSduboff /* setup pattern count registers */ 787f8919bdaSduboff OUTL(dp, RFCR, RFADDR_PCOUNT01_DP83815); 788f8919bdaSduboff OUTL(dp, RFDR, (ETHERADDRL << 8) | ETHERADDRL); 789f8919bdaSduboff OUTL(dp, RFCR, RFADDR_PCOUNT23_DP83815); 790f8919bdaSduboff OUTL(dp, RFDR, (ETHERADDRL << 8) | ETHERADDRL); 791f8919bdaSduboff } 792f8919bdaSduboff 793f8919bdaSduboff if (mode & RFCR_MHEN_DP83815) { 794f8919bdaSduboff /* Load Multicast hash table */ 795f8919bdaSduboff for (i = 0; i < 32; i++) { 796f8919bdaSduboff /* for DP83815, index is in byte */ 797f8919bdaSduboff OUTL(dp, RFCR, RFADDR_MULTICAST_DP83815 + i*2); 798f8919bdaSduboff OUTL(dp, RFDR, hash_tbl[i]); 799f8919bdaSduboff } 800f8919bdaSduboff } 801f8919bdaSduboff #if DEBUG_LEVEL > 2 802f8919bdaSduboff sfe_rxfilter_dump(dp, 0, 0x10); 803f8919bdaSduboff sfe_rxfilter_dump(dp, 0x200, 0x380); 804f8919bdaSduboff #endif 805f8919bdaSduboff /* Set rx filter mode and enable rx filter */ 806f8919bdaSduboff OUTL(dp, RFCR, RFCR_RFEN | mode); 807f8919bdaSduboff 808f8919bdaSduboff return (GEM_SUCCESS); 809f8919bdaSduboff } 810f8919bdaSduboff 811f8919bdaSduboff static int 812f8919bdaSduboff sfe_set_rx_filter_sis900(struct gem_dev *dp) 813f8919bdaSduboff { 814f8919bdaSduboff int i; 815f8919bdaSduboff uint32_t mode; 816f8919bdaSduboff uint16_t hash_tbl[16]; 817f8919bdaSduboff uint8_t *mac = dp->cur_addr.ether_addr_octet; 818f8919bdaSduboff int hash_size; 819f8919bdaSduboff int hash_shift; 820f8919bdaSduboff struct sfe_dev *lp = dp->private; 821f8919bdaSduboff 822f8919bdaSduboff DPRINTF(4, (CE_CONT, CONS "%s: %s: called", dp->name, __func__)); 823f8919bdaSduboff 824f8919bdaSduboff if ((dp->rxmode & RXMODE_ENABLE) == 0) { 825f8919bdaSduboff /* disalbe rx filter */ 826f8919bdaSduboff OUTL(dp, RFCR, 0); 827f8919bdaSduboff return (GEM_SUCCESS); 828f8919bdaSduboff } 829f8919bdaSduboff 830f8919bdaSduboff /* 831f8919bdaSduboff * determine hardware hash table size in word. 832f8919bdaSduboff */ 833f8919bdaSduboff hash_shift = 25; 834f8919bdaSduboff if (lp->revid >= SIS635A_900_REV || lp->revid == SIS900B_900_REV) { 835f8919bdaSduboff hash_shift = 24; 836f8919bdaSduboff } 837f8919bdaSduboff hash_size = (1 << (32 - hash_shift)) / 16; 838f8919bdaSduboff bzero(hash_tbl, sizeof (hash_tbl)); 839f8919bdaSduboff 840f8919bdaSduboff /* Set Receive filter control register */ 841f8919bdaSduboff 842f8919bdaSduboff if (dp->rxmode & RXMODE_PROMISC) { 843f8919bdaSduboff /* all broadcast, all multicast, all physical */ 844f8919bdaSduboff mode = RFCR_AAB | RFCR_AAM | RFCR_AAP; 845f8919bdaSduboff } else if ((dp->rxmode & RXMODE_ALLMULTI) || 846f8919bdaSduboff dp->mc_count > hash_size*16/2) { 847f8919bdaSduboff /* all broadcast, all multicast, physical for the chip */ 848f8919bdaSduboff mode = RFCR_AAB | RFCR_AAM; 849f8919bdaSduboff } else { 850f8919bdaSduboff /* all broadcast, physical for the chip */ 851f8919bdaSduboff mode = RFCR_AAB; 852f8919bdaSduboff } 853f8919bdaSduboff 854f8919bdaSduboff /* make hash table */ 855f8919bdaSduboff for (i = 0; i < dp->mc_count; i++) { 856f8919bdaSduboff uint_t h; 857f8919bdaSduboff h = dp->mc_list[i].hash >> hash_shift; 858f8919bdaSduboff hash_tbl[h / 16] |= 1 << (h % 16); 859f8919bdaSduboff } 860f8919bdaSduboff 861f8919bdaSduboff if (bcmp(mac, lp->mac_addr, ETHERADDRL) != 0) { 862f8919bdaSduboff /* Disable Rx filter and load mac address */ 863f8919bdaSduboff for (i = 0; i < ETHERADDRL/2; i++) { 864f8919bdaSduboff /* For sis900, index is in word */ 865f8919bdaSduboff OUTL(dp, RFCR, 866f8919bdaSduboff (RFADDR_MAC_SIS900+i) << RFCR_RFADDR_SHIFT_SIS900); 867f8919bdaSduboff OUTL(dp, RFDR, (mac[i*2+1] << 8) | mac[i*2]); 868f8919bdaSduboff } 869f8919bdaSduboff 870f8919bdaSduboff bcopy(mac, lp->mac_addr, ETHERADDRL); 871f8919bdaSduboff } 872f8919bdaSduboff 873f8919bdaSduboff /* Load Multicast hash table */ 874f8919bdaSduboff for (i = 0; i < hash_size; i++) { 875f8919bdaSduboff /* For sis900, index is in word */ 876f8919bdaSduboff OUTL(dp, RFCR, 877f8919bdaSduboff (RFADDR_MULTICAST_SIS900 + i) << RFCR_RFADDR_SHIFT_SIS900); 878f8919bdaSduboff OUTL(dp, RFDR, hash_tbl[i]); 879f8919bdaSduboff } 880f8919bdaSduboff 881f8919bdaSduboff /* Load rx filter mode and enable rx filter */ 882f8919bdaSduboff OUTL(dp, RFCR, RFCR_RFEN | mode); 883f8919bdaSduboff 884f8919bdaSduboff return (GEM_SUCCESS); 885f8919bdaSduboff } 886f8919bdaSduboff 887f8919bdaSduboff static int 888f8919bdaSduboff sfe_start_chip(struct gem_dev *dp) 889f8919bdaSduboff { 890f8919bdaSduboff struct sfe_dev *lp = dp->private; 891f8919bdaSduboff 892f8919bdaSduboff DPRINTF(4, (CE_CONT, CONS "%s: %s: called", dp->name, __func__)); 893f8919bdaSduboff 894f8919bdaSduboff /* 895f8919bdaSduboff * setup interrupt mask, which shouldn't include ISR_TOK 896f8919bdaSduboff * to improve performance. 897f8919bdaSduboff */ 898f8919bdaSduboff lp->our_intr_bits = OUR_INTR_BITS; 899f8919bdaSduboff 900f8919bdaSduboff /* enable interrupt */ 901f8919bdaSduboff if ((dp->misc_flag & GEM_NOINTR) == 0) { 902f8919bdaSduboff OUTL(dp, IER, 1); 903f8919bdaSduboff OUTL(dp, IMR, lp->our_intr_bits); 904f8919bdaSduboff } 905f8919bdaSduboff 906f8919bdaSduboff /* Kick RX */ 907f8919bdaSduboff OUTL(dp, CR, lp->cr | CR_RXE); 908f8919bdaSduboff 909f8919bdaSduboff return (GEM_SUCCESS); 910f8919bdaSduboff } 911f8919bdaSduboff 912f8919bdaSduboff /* 913f8919bdaSduboff * Stop nic core gracefully. 914f8919bdaSduboff */ 915f8919bdaSduboff static int 916f8919bdaSduboff sfe_stop_chip(struct gem_dev *dp) 917f8919bdaSduboff { 918f8919bdaSduboff struct sfe_dev *lp = dp->private; 919f8919bdaSduboff uint32_t done; 920f8919bdaSduboff int i; 92123d366e3Sduboff uint32_t val; 922f8919bdaSduboff 923f8919bdaSduboff DPRINTF(4, (CE_CONT, CONS "%s: %s: called", dp->name, __func__)); 924f8919bdaSduboff 925f8919bdaSduboff /* 926f8919bdaSduboff * Although we inhibit interrupt here, we don't clear soft copy of 927f8919bdaSduboff * interrupt mask to avoid bogus interrupts. 928f8919bdaSduboff */ 929f8919bdaSduboff OUTL(dp, IMR, 0); 930f8919bdaSduboff 931f8919bdaSduboff /* stop TX and RX immediately */ 932f8919bdaSduboff OUTL(dp, CR, lp->cr | CR_TXR | CR_RXR); 933f8919bdaSduboff 934f8919bdaSduboff done = 0; 935f8919bdaSduboff for (i = 0; done != (ISR_RXRCMP | ISR_TXRCMP); i++) { 936f8919bdaSduboff if (i > 1000) { 937f8919bdaSduboff /* 938f8919bdaSduboff * As gem layer will call sfe_reset_chip(), 939f8919bdaSduboff * we don't neet to reset futher 940f8919bdaSduboff */ 941f8919bdaSduboff cmn_err(CE_NOTE, "!%s: %s: Tx/Rx reset timeout", 942f8919bdaSduboff dp->name, __func__); 943f8919bdaSduboff 944f8919bdaSduboff return (GEM_FAILURE); 945f8919bdaSduboff } 94623d366e3Sduboff val = INL(dp, ISR); 94723d366e3Sduboff done |= val & (ISR_RXRCMP | ISR_TXRCMP); 94823d366e3Sduboff lp->isr_pended |= val & lp->our_intr_bits; 949f8919bdaSduboff drv_usecwait(10); 950f8919bdaSduboff } 951f8919bdaSduboff 952f8919bdaSduboff return (GEM_SUCCESS); 953f8919bdaSduboff } 954f8919bdaSduboff 955f8919bdaSduboff /* 956f8919bdaSduboff * Setup media mode 957f8919bdaSduboff */ 958f8919bdaSduboff static uint_t 959f8919bdaSduboff sfe_mxdma_value[] = { 512, 4, 8, 16, 32, 64, 128, 256, }; 960f8919bdaSduboff 961f8919bdaSduboff static uint_t 962f8919bdaSduboff sfe_encode_mxdma(uint_t burstsize) 963f8919bdaSduboff { 964f8919bdaSduboff int i; 965f8919bdaSduboff 966f8919bdaSduboff if (burstsize > 256) { 967f8919bdaSduboff /* choose 512 */ 968f8919bdaSduboff return (0); 969f8919bdaSduboff } 970f8919bdaSduboff 971f8919bdaSduboff for (i = 1; i < 8; i++) { 972f8919bdaSduboff if (burstsize <= sfe_mxdma_value[i]) { 973f8919bdaSduboff break; 974f8919bdaSduboff } 975f8919bdaSduboff } 976f8919bdaSduboff return (i); 977f8919bdaSduboff } 978f8919bdaSduboff 979f8919bdaSduboff static int 980f8919bdaSduboff sfe_set_media(struct gem_dev *dp) 981f8919bdaSduboff { 982f8919bdaSduboff uint32_t txcfg; 983f8919bdaSduboff uint32_t rxcfg; 984f8919bdaSduboff uint32_t pcr; 985f8919bdaSduboff uint32_t val; 986f8919bdaSduboff uint32_t txmxdma; 987f8919bdaSduboff uint32_t rxmxdma; 988f8919bdaSduboff struct sfe_dev *lp = dp->private; 989f8919bdaSduboff #ifdef DEBUG_LEVEL 990f8919bdaSduboff extern int gem_speed_value[]; 991f8919bdaSduboff #endif 992f8919bdaSduboff DPRINTF(2, (CE_CONT, CONS "%s: %s: %s duplex, %d Mbps", 993f8919bdaSduboff dp->name, __func__, 994f8919bdaSduboff dp->full_duplex ? "full" : "half", gem_speed_value[dp->speed])); 995f8919bdaSduboff 996f8919bdaSduboff /* initialize txcfg and rxcfg */ 997f8919bdaSduboff txcfg = TXCFG_ATP; 998f8919bdaSduboff if (dp->full_duplex) { 999f8919bdaSduboff txcfg |= (TXCFG_CSI | TXCFG_HBI); 1000f8919bdaSduboff } 100123d366e3Sduboff rxcfg = RXCFG_AEP | RXCFG_ARP; 1002f8919bdaSduboff if (dp->full_duplex) { 1003f8919bdaSduboff rxcfg |= RXCFG_ATX; 1004f8919bdaSduboff } 1005f8919bdaSduboff 1006f8919bdaSduboff /* select txmxdma and rxmxdma, maxmum burst length */ 1007f8919bdaSduboff if (lp->chip->chip_type == CHIPTYPE_SIS900) { 1008f8919bdaSduboff #ifdef DEBUG_SIS900_EDB 1009f8919bdaSduboff val = CFG_EDB_MASTER; 1010f8919bdaSduboff #else 1011f8919bdaSduboff val = INL(dp, CFG) & CFG_EDB_MASTER; 1012f8919bdaSduboff #endif 1013f8919bdaSduboff if (val) { 1014f8919bdaSduboff /* 1015f8919bdaSduboff * sis900 built-in cores: 1016f8919bdaSduboff * max burst length must be fixed to 64 1017f8919bdaSduboff */ 1018f8919bdaSduboff txmxdma = 64; 1019f8919bdaSduboff rxmxdma = 64; 1020f8919bdaSduboff } else { 1021f8919bdaSduboff /* 1022f8919bdaSduboff * sis900 pci chipset: 1023f8919bdaSduboff * the vendor recommended to fix max burst length 1024f8919bdaSduboff * to 512 1025f8919bdaSduboff */ 1026f8919bdaSduboff txmxdma = 512; 1027f8919bdaSduboff rxmxdma = 512; 1028f8919bdaSduboff } 1029f8919bdaSduboff } else { 1030f8919bdaSduboff /* 1031f8919bdaSduboff * NS dp83815/816: 1032f8919bdaSduboff * use user defined or default for tx/rx max burst length 1033f8919bdaSduboff */ 1034f8919bdaSduboff txmxdma = max(dp->txmaxdma, 256); 1035f8919bdaSduboff rxmxdma = max(dp->rxmaxdma, 256); 1036f8919bdaSduboff } 1037f8919bdaSduboff 1038f8919bdaSduboff 1039f8919bdaSduboff /* tx high water mark */ 1040f8919bdaSduboff lp->tx_drain_threshold = ROUNDUP2(dp->txthr, TXCFG_FIFO_UNIT); 1041f8919bdaSduboff 1042f8919bdaSduboff /* determine tx_fill_threshold accroding drain threshold */ 1043f8919bdaSduboff lp->tx_fill_threshold = 1044f8919bdaSduboff TXFIFOSIZE - lp->tx_drain_threshold - TXCFG_FIFO_UNIT; 1045f8919bdaSduboff 1046f8919bdaSduboff /* tune txmxdma not to exceed tx_fill_threshold */ 1047f8919bdaSduboff for (; ; ) { 1048f8919bdaSduboff /* normalize txmxdma requested */ 1049f8919bdaSduboff val = sfe_encode_mxdma(txmxdma); 1050f8919bdaSduboff txmxdma = sfe_mxdma_value[val]; 1051f8919bdaSduboff 1052f8919bdaSduboff if (txmxdma <= lp->tx_fill_threshold) { 1053f8919bdaSduboff break; 1054f8919bdaSduboff } 1055f8919bdaSduboff /* select new txmxdma */ 1056f8919bdaSduboff txmxdma = txmxdma / 2; 1057f8919bdaSduboff } 1058f8919bdaSduboff txcfg |= val << TXCFG_MXDMA_SHIFT; 1059f8919bdaSduboff 1060f8919bdaSduboff /* encode rxmxdma, maxmum burst length for rx */ 1061f8919bdaSduboff val = sfe_encode_mxdma(rxmxdma); 106223d366e3Sduboff rxcfg |= val << RXCFG_MXDMA_SHIFT; 1063f8919bdaSduboff rxmxdma = sfe_mxdma_value[val]; 1064f8919bdaSduboff 1065f8919bdaSduboff /* receive starting threshold - it have only 5bit-wide field */ 1066f8919bdaSduboff val = ROUNDUP2(max(dp->rxthr, ETHERMIN), RXCFG_FIFO_UNIT); 1067f8919bdaSduboff lp->rx_drain_threshold = 1068f8919bdaSduboff min(val, (RXCFG_DRTH >> RXCFG_DRTH_SHIFT) * RXCFG_FIFO_UNIT); 1069f8919bdaSduboff 1070f8919bdaSduboff DPRINTF(0, (CE_CONT, 1071f8919bdaSduboff "%s: %s: tx: drain:%d(rest %d) fill:%d mxdma:%d," 1072f8919bdaSduboff " rx: drain:%d mxdma:%d", 1073f8919bdaSduboff dp->name, __func__, 1074f8919bdaSduboff lp->tx_drain_threshold, TXFIFOSIZE - lp->tx_drain_threshold, 1075f8919bdaSduboff lp->tx_fill_threshold, txmxdma, 1076f8919bdaSduboff lp->rx_drain_threshold, rxmxdma)); 1077f8919bdaSduboff 1078f8919bdaSduboff ASSERT(lp->tx_drain_threshold < 64*TXCFG_FIFO_UNIT); 1079f8919bdaSduboff ASSERT(lp->tx_fill_threshold < 64*TXCFG_FIFO_UNIT); 1080f8919bdaSduboff ASSERT(lp->rx_drain_threshold < 32*RXCFG_FIFO_UNIT); 1081f8919bdaSduboff 1082f8919bdaSduboff txcfg |= ((lp->tx_fill_threshold/TXCFG_FIFO_UNIT) << TXCFG_FLTH_SHIFT) 1083f8919bdaSduboff | (lp->tx_drain_threshold/TXCFG_FIFO_UNIT); 1084f8919bdaSduboff OUTL(dp, TXCFG, txcfg); 1085f8919bdaSduboff 1086f8919bdaSduboff rxcfg |= ((lp->rx_drain_threshold/RXCFG_FIFO_UNIT) << RXCFG_DRTH_SHIFT); 1087f8919bdaSduboff if (lp->chip->chip_type == CHIPTYPE_DP83815) { 1088f8919bdaSduboff rxcfg |= RXCFG_ALP_DP83815; 1089f8919bdaSduboff } 1090f8919bdaSduboff OUTL(dp, RXCFG, rxcfg); 1091f8919bdaSduboff 1092f8919bdaSduboff DPRINTF(0, (CE_CONT, CONS "%s: %s: txcfg:%b rxcfg:%b", 1093f8919bdaSduboff dp->name, __func__, 1094f8919bdaSduboff txcfg, TXCFG_BITS, rxcfg, RXCFG_BITS)); 1095f8919bdaSduboff 1096f8919bdaSduboff /* Flow control */ 1097f8919bdaSduboff if (lp->chip->chip_type == CHIPTYPE_DP83815) { 1098f8919bdaSduboff pcr = INL(dp, PCR); 1099f8919bdaSduboff switch (dp->flow_control) { 1100f8919bdaSduboff case FLOW_CONTROL_SYMMETRIC: 1101f8919bdaSduboff case FLOW_CONTROL_RX_PAUSE: 1102f8919bdaSduboff OUTL(dp, PCR, pcr | PCR_PSEN | PCR_PS_MCAST); 1103f8919bdaSduboff break; 1104f8919bdaSduboff 1105f8919bdaSduboff default: 1106f8919bdaSduboff OUTL(dp, PCR, 1107f8919bdaSduboff pcr & ~(PCR_PSEN | PCR_PS_MCAST | PCR_PS_DA)); 1108f8919bdaSduboff break; 1109f8919bdaSduboff } 1110f8919bdaSduboff DPRINTF(2, (CE_CONT, CONS "%s: PCR: %b", dp->name, 1111f8919bdaSduboff INL(dp, PCR), PCR_BITS)); 1112f8919bdaSduboff 1113f8919bdaSduboff } else if (lp->chip->chip_type == CHIPTYPE_SIS900) { 1114f8919bdaSduboff switch (dp->flow_control) { 1115f8919bdaSduboff case FLOW_CONTROL_SYMMETRIC: 1116f8919bdaSduboff case FLOW_CONTROL_RX_PAUSE: 1117f8919bdaSduboff OUTL(dp, FLOWCTL, FLOWCTL_FLOWEN); 1118f8919bdaSduboff break; 1119f8919bdaSduboff default: 1120f8919bdaSduboff OUTL(dp, FLOWCTL, 0); 1121f8919bdaSduboff break; 1122f8919bdaSduboff } 1123f8919bdaSduboff DPRINTF(2, (CE_CONT, CONS "%s: FLOWCTL: %b", 1124f8919bdaSduboff dp->name, INL(dp, FLOWCTL), FLOWCTL_BITS)); 1125f8919bdaSduboff } 1126f8919bdaSduboff return (GEM_SUCCESS); 1127f8919bdaSduboff } 1128f8919bdaSduboff 1129f8919bdaSduboff static int 1130f8919bdaSduboff sfe_get_stats(struct gem_dev *dp) 1131f8919bdaSduboff { 1132f8919bdaSduboff /* do nothing */ 1133f8919bdaSduboff return (GEM_SUCCESS); 1134f8919bdaSduboff } 1135f8919bdaSduboff 1136f8919bdaSduboff /* 1137f8919bdaSduboff * descriptor manipulations 1138f8919bdaSduboff */ 1139f8919bdaSduboff static int 1140f8919bdaSduboff sfe_tx_desc_write(struct gem_dev *dp, int slot, 1141f8919bdaSduboff ddi_dma_cookie_t *dmacookie, int frags, uint64_t flags) 1142f8919bdaSduboff { 1143f8919bdaSduboff uint32_t mark; 1144f8919bdaSduboff struct sfe_desc *tdp; 1145f8919bdaSduboff ddi_dma_cookie_t *dcp; 114623d366e3Sduboff uint32_t tmp0; 114723d366e3Sduboff #if DEBUG_LEVEL > 2 1148f8919bdaSduboff int i; 1149f8919bdaSduboff 1150f8919bdaSduboff cmn_err(CE_CONT, 1151f8919bdaSduboff CONS "%s: time:%d %s seqnum: %d, slot %d, frags: %d flags: %llx", 1152f8919bdaSduboff dp->name, ddi_get_lbolt(), __func__, 1153f8919bdaSduboff dp->tx_desc_tail, slot, frags, flags); 1154f8919bdaSduboff 1155f8919bdaSduboff for (i = 0; i < frags; i++) { 1156f8919bdaSduboff cmn_err(CE_CONT, CONS "%d: addr: 0x%x, len: 0x%x", 1157f8919bdaSduboff i, dmacookie[i].dmac_address, dmacookie[i].dmac_size); 115823d366e3Sduboff } 1159f8919bdaSduboff #endif 1160f8919bdaSduboff /* 1161f8919bdaSduboff * write tx descriptor in reversed order. 1162f8919bdaSduboff */ 1163f8919bdaSduboff #if DEBUG_LEVEL > 3 1164f8919bdaSduboff flags |= GEM_TXFLAG_INTR; 1165f8919bdaSduboff #endif 1166f8919bdaSduboff mark = (flags & GEM_TXFLAG_INTR) 116723d366e3Sduboff ? (CMDSTS_OWN | CMDSTS_INTR) : CMDSTS_OWN; 1168f8919bdaSduboff 1169f8919bdaSduboff ASSERT(frags == 1); 1170f8919bdaSduboff dcp = &dmacookie[0]; 1171f8919bdaSduboff if (flags & GEM_TXFLAG_HEAD) { 1172f8919bdaSduboff mark &= ~CMDSTS_OWN; 1173f8919bdaSduboff } 1174f8919bdaSduboff 1175f8919bdaSduboff tdp = (void *)&dp->tx_ring[SFE_DESC_SIZE * slot]; 117623d366e3Sduboff tmp0 = (uint32_t)dcp->dmac_address; 117723d366e3Sduboff mark |= (uint32_t)dcp->dmac_size; 117823d366e3Sduboff tdp->d_bufptr = LE_32(tmp0); 117923d366e3Sduboff tdp->d_cmdsts = LE_32(mark); 1180f8919bdaSduboff 1181f8919bdaSduboff return (frags); 1182f8919bdaSduboff } 1183f8919bdaSduboff 1184f8919bdaSduboff static void 1185f8919bdaSduboff sfe_tx_start(struct gem_dev *dp, int start_slot, int nslot) 1186f8919bdaSduboff { 118723d366e3Sduboff uint_t tx_ring_size = dp->gc.gc_tx_ring_size; 1188f8919bdaSduboff struct sfe_desc *tdp; 1189f8919bdaSduboff struct sfe_dev *lp = dp->private; 1190f8919bdaSduboff 1191f8919bdaSduboff if (nslot > 1) { 1192f8919bdaSduboff gem_tx_desc_dma_sync(dp, 119323d366e3Sduboff SLOT(start_slot + 1, tx_ring_size), 1194f8919bdaSduboff nslot - 1, DDI_DMA_SYNC_FORDEV); 1195f8919bdaSduboff } 1196f8919bdaSduboff 1197f8919bdaSduboff tdp = (void *)&dp->tx_ring[SFE_DESC_SIZE * start_slot]; 1198f8919bdaSduboff tdp->d_cmdsts |= LE_32(CMDSTS_OWN); 1199f8919bdaSduboff 1200f8919bdaSduboff gem_tx_desc_dma_sync(dp, start_slot, 1, DDI_DMA_SYNC_FORDEV); 1201f8919bdaSduboff 1202f8919bdaSduboff /* 1203f8919bdaSduboff * Let the Transmit Buffer Manager Fill state machine active. 1204f8919bdaSduboff */ 1205f8919bdaSduboff if (dp->mac_active) { 1206f8919bdaSduboff OUTL(dp, CR, lp->cr | CR_TXE); 1207f8919bdaSduboff } 1208f8919bdaSduboff } 1209f8919bdaSduboff 1210f8919bdaSduboff static void 1211f8919bdaSduboff sfe_rx_desc_write(struct gem_dev *dp, int slot, 1212f8919bdaSduboff ddi_dma_cookie_t *dmacookie, int frags) 1213f8919bdaSduboff { 1214f8919bdaSduboff struct sfe_desc *rdp; 121523d366e3Sduboff uint32_t tmp0; 121623d366e3Sduboff uint32_t tmp1; 1217f8919bdaSduboff #if DEBUG_LEVEL > 2 1218f8919bdaSduboff int i; 1219f8919bdaSduboff 1220f8919bdaSduboff ASSERT(frags == 1); 1221f8919bdaSduboff 1222f8919bdaSduboff cmn_err(CE_CONT, CONS 1223f8919bdaSduboff "%s: %s seqnum: %d, slot %d, frags: %d", 1224f8919bdaSduboff dp->name, __func__, dp->rx_active_tail, slot, frags); 1225f8919bdaSduboff for (i = 0; i < frags; i++) { 1226f8919bdaSduboff cmn_err(CE_CONT, CONS " frag: %d addr: 0x%llx, len: 0x%lx", 1227f8919bdaSduboff i, dmacookie[i].dmac_address, dmacookie[i].dmac_size); 1228f8919bdaSduboff } 1229f8919bdaSduboff #endif 1230f8919bdaSduboff /* for the last slot of the packet */ 1231f8919bdaSduboff rdp = (void *)&dp->rx_ring[SFE_DESC_SIZE * slot]; 1232f8919bdaSduboff 123323d366e3Sduboff tmp0 = (uint32_t)dmacookie->dmac_address; 123423d366e3Sduboff tmp1 = CMDSTS_INTR | (uint32_t)dmacookie->dmac_size; 123523d366e3Sduboff rdp->d_bufptr = LE_32(tmp0); 123623d366e3Sduboff rdp->d_cmdsts = LE_32(tmp1); 1237f8919bdaSduboff } 1238f8919bdaSduboff 1239f8919bdaSduboff static uint_t 1240f8919bdaSduboff sfe_tx_desc_stat(struct gem_dev *dp, int slot, int ndesc) 1241f8919bdaSduboff { 124223d366e3Sduboff uint_t tx_ring_size = dp->gc.gc_tx_ring_size; 1243f8919bdaSduboff struct sfe_desc *tdp; 1244f8919bdaSduboff uint32_t status; 1245f8919bdaSduboff int cols; 124623d366e3Sduboff struct sfe_dev *lp = dp->private; 1247f8919bdaSduboff #ifdef DEBUG_LEVEL 1248f8919bdaSduboff int i; 1249f8919bdaSduboff clock_t delay; 1250f8919bdaSduboff #endif 1251f8919bdaSduboff /* check status of the last descriptor */ 1252f8919bdaSduboff tdp = (void *) 125323d366e3Sduboff &dp->tx_ring[SFE_DESC_SIZE * SLOT(slot + ndesc - 1, tx_ring_size)]; 1254f8919bdaSduboff 125523d366e3Sduboff /* 125623d366e3Sduboff * Don't use LE_32() directly to refer tdp->d_cmdsts. 125723d366e3Sduboff * It is not atomic for big endian cpus. 125823d366e3Sduboff */ 125923d366e3Sduboff status = tdp->d_cmdsts; 126023d366e3Sduboff status = LE_32(status); 1261f8919bdaSduboff 1262f8919bdaSduboff DPRINTF(2, (CE_CONT, CONS "%s: time:%ld %s: slot:%d, status:0x%b", 1263f8919bdaSduboff dp->name, ddi_get_lbolt(), __func__, 1264f8919bdaSduboff slot, status, TXSTAT_BITS)); 1265f8919bdaSduboff 1266f8919bdaSduboff if (status & CMDSTS_OWN) { 1267f8919bdaSduboff /* 1268f8919bdaSduboff * not yet transmitted 1269f8919bdaSduboff */ 127023d366e3Sduboff /* workaround for tx hang */ 127123d366e3Sduboff if (lp->chip->chip_type == CHIPTYPE_DP83815 && 127223d366e3Sduboff dp->mac_active) { 127323d366e3Sduboff OUTL(dp, CR, lp->cr | CR_TXE); 127423d366e3Sduboff } 1275f8919bdaSduboff return (0); 1276f8919bdaSduboff } 1277f8919bdaSduboff 1278f8919bdaSduboff if (status & CMDSTS_MORE) { 1279f8919bdaSduboff /* XXX - the hardware problem but don't panic the system */ 1280f8919bdaSduboff /* avoid lint bug for %b format string including 32nd bit */ 1281f8919bdaSduboff cmn_err(CE_NOTE, CONS 1282f8919bdaSduboff "%s: tx status bits incorrect: slot:%d, status:0x%x", 1283f8919bdaSduboff dp->name, slot, status); 1284f8919bdaSduboff } 1285f8919bdaSduboff 1286f8919bdaSduboff #if DEBUG_LEVEL > 3 1287f8919bdaSduboff delay = (ddi_get_lbolt() - dp->tx_buf_head->txb_stime) * 10; 1288f8919bdaSduboff if (delay >= 50) { 1289f8919bdaSduboff DPRINTF(0, (CE_NOTE, "%s: tx deferred %d mS: slot %d", 1290f8919bdaSduboff dp->name, delay, slot)); 1291f8919bdaSduboff } 1292f8919bdaSduboff #endif 1293f8919bdaSduboff 1294f8919bdaSduboff #if DEBUG_LEVEL > 3 1295f8919bdaSduboff for (i = 0; i < nfrag-1; i++) { 1296f8919bdaSduboff uint32_t s; 1297f8919bdaSduboff int n; 1298f8919bdaSduboff 129923d366e3Sduboff n = SLOT(slot + i, tx_ring_size); 1300f8919bdaSduboff s = LE_32( 1301f8919bdaSduboff ((struct sfe_desc *)((void *) 1302f8919bdaSduboff &dp->tx_ring[SFE_DESC_SIZE * n]))->d_cmdsts); 1303f8919bdaSduboff 1304f8919bdaSduboff ASSERT(s & CMDSTS_MORE); 1305f8919bdaSduboff ASSERT((s & CMDSTS_OWN) == 0); 1306f8919bdaSduboff } 1307f8919bdaSduboff #endif 1308f8919bdaSduboff 1309f8919bdaSduboff /* 1310f8919bdaSduboff * collect statistics 1311f8919bdaSduboff */ 1312f8919bdaSduboff if ((status & CMDSTS_OK) == 0) { 1313f8919bdaSduboff 1314f8919bdaSduboff /* failed to transmit the packet */ 1315f8919bdaSduboff 1316f8919bdaSduboff DPRINTF(0, (CE_CONT, CONS "%s: Transmit error, Tx status %b", 1317f8919bdaSduboff dp->name, status, TXSTAT_BITS)); 1318f8919bdaSduboff 1319f8919bdaSduboff dp->stats.errxmt++; 1320f8919bdaSduboff 1321f8919bdaSduboff if (status & CMDSTS_TFU) { 1322f8919bdaSduboff dp->stats.underflow++; 1323f8919bdaSduboff } else if (status & CMDSTS_CRS) { 1324f8919bdaSduboff dp->stats.nocarrier++; 1325f8919bdaSduboff } else if (status & CMDSTS_OWC) { 1326f8919bdaSduboff dp->stats.xmtlatecoll++; 1327f8919bdaSduboff } else if ((!dp->full_duplex) && (status & CMDSTS_EC)) { 1328f8919bdaSduboff dp->stats.excoll++; 1329f8919bdaSduboff dp->stats.collisions += 16; 1330f8919bdaSduboff } else { 1331f8919bdaSduboff dp->stats.xmit_internal_err++; 1332f8919bdaSduboff } 1333f8919bdaSduboff } else if (!dp->full_duplex) { 1334f8919bdaSduboff cols = (status >> CMDSTS_CCNT_SHIFT) & CCNT_MASK; 1335f8919bdaSduboff 1336f8919bdaSduboff if (cols > 0) { 1337f8919bdaSduboff if (cols == 1) { 1338f8919bdaSduboff dp->stats.first_coll++; 1339f8919bdaSduboff } else /* (cols > 1) */ { 1340f8919bdaSduboff dp->stats.multi_coll++; 1341f8919bdaSduboff } 1342f8919bdaSduboff dp->stats.collisions += cols; 1343f8919bdaSduboff } else if (status & CMDSTS_TD) { 1344f8919bdaSduboff dp->stats.defer++; 1345f8919bdaSduboff } 1346f8919bdaSduboff } 1347f8919bdaSduboff return (GEM_TX_DONE); 1348f8919bdaSduboff } 1349f8919bdaSduboff 1350f8919bdaSduboff static uint64_t 1351f8919bdaSduboff sfe_rx_desc_stat(struct gem_dev *dp, int slot, int ndesc) 1352f8919bdaSduboff { 1353f8919bdaSduboff struct sfe_desc *rdp; 1354f8919bdaSduboff uint_t len; 1355f8919bdaSduboff uint_t flag; 1356f8919bdaSduboff uint32_t status; 1357f8919bdaSduboff 1358f8919bdaSduboff flag = GEM_RX_DONE; 1359f8919bdaSduboff 1360f8919bdaSduboff /* Dont read ISR because we cannot ack only to rx interrupt. */ 1361f8919bdaSduboff 1362f8919bdaSduboff rdp = (void *)&dp->rx_ring[SFE_DESC_SIZE * slot]; 1363f8919bdaSduboff 136423d366e3Sduboff /* 136523d366e3Sduboff * Don't use LE_32() directly to refer rdp->d_cmdsts. 136623d366e3Sduboff * It is not atomic for big endian cpus. 136723d366e3Sduboff */ 136823d366e3Sduboff status = rdp->d_cmdsts; 136923d366e3Sduboff status = LE_32(status); 1370f8919bdaSduboff 1371f8919bdaSduboff DPRINTF(2, (CE_CONT, CONS "%s: time:%ld %s: slot:%d, status:0x%b", 1372f8919bdaSduboff dp->name, ddi_get_lbolt(), __func__, 1373f8919bdaSduboff slot, status, RXSTAT_BITS)); 1374f8919bdaSduboff 1375f8919bdaSduboff if ((status & CMDSTS_OWN) == 0) { 1376f8919bdaSduboff /* 1377f8919bdaSduboff * No more received packets because 1378f8919bdaSduboff * this buffer is owned by NIC. 1379f8919bdaSduboff */ 1380f8919bdaSduboff return (0); 1381f8919bdaSduboff } 1382f8919bdaSduboff 1383f8919bdaSduboff #define RX_ERR_BITS \ 1384f8919bdaSduboff (CMDSTS_RXA | CMDSTS_RXO | CMDSTS_LONG | CMDSTS_RUNT | \ 1385f8919bdaSduboff CMDSTS_ISE | CMDSTS_CRCE | CMDSTS_FAE | CMDSTS_MORE) 1386f8919bdaSduboff 1387f8919bdaSduboff if (status & RX_ERR_BITS) { 1388f8919bdaSduboff /* 1389f8919bdaSduboff * Packet with error received 1390f8919bdaSduboff */ 1391f8919bdaSduboff DPRINTF(0, (CE_CONT, CONS "%s: Corrupted packet " 1392f8919bdaSduboff "received, buffer status: %b", 1393f8919bdaSduboff dp->name, status, RXSTAT_BITS)); 1394f8919bdaSduboff 1395f8919bdaSduboff /* collect statistics information */ 1396f8919bdaSduboff dp->stats.errrcv++; 1397f8919bdaSduboff 1398f8919bdaSduboff if (status & CMDSTS_RXO) { 1399f8919bdaSduboff dp->stats.overflow++; 1400f8919bdaSduboff } else if (status & (CMDSTS_LONG | CMDSTS_MORE)) { 1401f8919bdaSduboff dp->stats.frame_too_long++; 1402f8919bdaSduboff } else if (status & CMDSTS_RUNT) { 1403f8919bdaSduboff dp->stats.runt++; 1404f8919bdaSduboff } else if (status & (CMDSTS_ISE | CMDSTS_FAE)) { 1405f8919bdaSduboff dp->stats.frame++; 1406f8919bdaSduboff } else if (status & CMDSTS_CRCE) { 1407f8919bdaSduboff dp->stats.crc++; 1408f8919bdaSduboff } else { 1409f8919bdaSduboff dp->stats.rcv_internal_err++; 1410f8919bdaSduboff } 1411f8919bdaSduboff 1412f8919bdaSduboff return (flag | GEM_RX_ERR); 1413f8919bdaSduboff } 1414f8919bdaSduboff 1415f8919bdaSduboff /* 1416f8919bdaSduboff * this packet was received without errors 1417f8919bdaSduboff */ 1418f8919bdaSduboff if ((len = (status & CMDSTS_SIZE)) >= ETHERFCSL) { 1419f8919bdaSduboff len -= ETHERFCSL; 1420f8919bdaSduboff } 1421f8919bdaSduboff 1422f8919bdaSduboff #if DEBUG_LEVEL > 10 1423f8919bdaSduboff { 1424f8919bdaSduboff int i; 1425f8919bdaSduboff uint8_t *bp = dp->rx_buf_head->rxb_buf; 1426f8919bdaSduboff 1427f8919bdaSduboff cmn_err(CE_CONT, CONS "%s: len:%d", dp->name, len); 1428f8919bdaSduboff 1429f8919bdaSduboff for (i = 0; i < 60; i += 10) { 1430f8919bdaSduboff cmn_err(CE_CONT, CONS 1431f8919bdaSduboff "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", 1432f8919bdaSduboff bp[0], bp[1], bp[2], bp[3], bp[4], 1433f8919bdaSduboff bp[5], bp[6], bp[7], bp[8], bp[9]); 1434f8919bdaSduboff } 1435f8919bdaSduboff bp += 10; 1436f8919bdaSduboff } 1437f8919bdaSduboff #endif 1438f8919bdaSduboff return (flag | (len & GEM_RX_LEN)); 1439f8919bdaSduboff } 1440f8919bdaSduboff 1441f8919bdaSduboff static void 1442f8919bdaSduboff sfe_tx_desc_init(struct gem_dev *dp, int slot) 1443f8919bdaSduboff { 144423d366e3Sduboff uint_t tx_ring_size = dp->gc.gc_tx_ring_size; 1445f8919bdaSduboff struct sfe_desc *tdp; 1446f8919bdaSduboff uint32_t here; 1447f8919bdaSduboff 1448f8919bdaSduboff tdp = (void *)&dp->tx_ring[SFE_DESC_SIZE * slot]; 1449f8919bdaSduboff 1450f8919bdaSduboff /* don't clear d_link field, which have a valid pointer */ 1451f8919bdaSduboff tdp->d_cmdsts = 0; 1452f8919bdaSduboff 1453f8919bdaSduboff /* make a link to this from the previous descriptor */ 1454f8919bdaSduboff here = ((uint32_t)dp->tx_ring_dma) + SFE_DESC_SIZE*slot; 1455f8919bdaSduboff 1456f8919bdaSduboff tdp = (void *) 145723d366e3Sduboff &dp->tx_ring[SFE_DESC_SIZE * SLOT(slot - 1, tx_ring_size)]; 1458f8919bdaSduboff tdp->d_link = LE_32(here); 1459f8919bdaSduboff } 1460f8919bdaSduboff 1461f8919bdaSduboff static void 1462f8919bdaSduboff sfe_rx_desc_init(struct gem_dev *dp, int slot) 1463f8919bdaSduboff { 146423d366e3Sduboff uint_t rx_ring_size = dp->gc.gc_rx_ring_size; 1465f8919bdaSduboff struct sfe_desc *rdp; 1466f8919bdaSduboff uint32_t here; 1467f8919bdaSduboff 1468f8919bdaSduboff rdp = (void *)&dp->rx_ring[SFE_DESC_SIZE * slot]; 1469f8919bdaSduboff 1470f8919bdaSduboff /* don't clear d_link field, which have a valid pointer */ 1471f8919bdaSduboff rdp->d_cmdsts = LE_32(CMDSTS_OWN); 1472f8919bdaSduboff 1473f8919bdaSduboff /* make a link to this from the previous descriptor */ 1474f8919bdaSduboff here = ((uint32_t)dp->rx_ring_dma) + SFE_DESC_SIZE*slot; 1475f8919bdaSduboff 1476f8919bdaSduboff rdp = (void *) 147723d366e3Sduboff &dp->rx_ring[SFE_DESC_SIZE * SLOT(slot - 1, rx_ring_size)]; 1478f8919bdaSduboff rdp->d_link = LE_32(here); 1479f8919bdaSduboff } 1480f8919bdaSduboff 1481f8919bdaSduboff static void 1482f8919bdaSduboff sfe_tx_desc_clean(struct gem_dev *dp, int slot) 1483f8919bdaSduboff { 1484f8919bdaSduboff struct sfe_desc *tdp; 1485f8919bdaSduboff 1486f8919bdaSduboff tdp = (void *)&dp->tx_ring[SFE_DESC_SIZE * slot]; 1487f8919bdaSduboff tdp->d_cmdsts = 0; 1488f8919bdaSduboff } 1489f8919bdaSduboff 1490f8919bdaSduboff static void 1491f8919bdaSduboff sfe_rx_desc_clean(struct gem_dev *dp, int slot) 1492f8919bdaSduboff { 1493f8919bdaSduboff struct sfe_desc *rdp; 1494f8919bdaSduboff 1495f8919bdaSduboff rdp = (void *)&dp->rx_ring[SFE_DESC_SIZE * slot]; 1496f8919bdaSduboff rdp->d_cmdsts = LE_32(CMDSTS_OWN); 1497f8919bdaSduboff } 1498f8919bdaSduboff 1499f8919bdaSduboff /* 1500f8919bdaSduboff * Device depend interrupt handler 1501f8919bdaSduboff */ 1502f8919bdaSduboff static uint_t 1503f8919bdaSduboff sfe_interrupt(struct gem_dev *dp) 1504f8919bdaSduboff { 150523d366e3Sduboff uint_t rx_ring_size = dp->gc.gc_rx_ring_size; 1506f8919bdaSduboff uint32_t isr; 150723d366e3Sduboff uint32_t isr_bogus; 1508f8919bdaSduboff uint_t flags = 0; 1509f8919bdaSduboff boolean_t need_to_reset = B_FALSE; 1510f8919bdaSduboff struct sfe_dev *lp = dp->private; 1511f8919bdaSduboff 1512f8919bdaSduboff /* read reason and clear interrupt */ 1513f8919bdaSduboff isr = INL(dp, ISR); 1514f8919bdaSduboff 151523d366e3Sduboff isr_bogus = lp->isr_pended; 151623d366e3Sduboff lp->isr_pended = 0; 151723d366e3Sduboff 151823d366e3Sduboff if (((isr | isr_bogus) & lp->our_intr_bits) == 0) { 1519f8919bdaSduboff /* we are not the interrupt source */ 1520f8919bdaSduboff return (DDI_INTR_UNCLAIMED); 1521f8919bdaSduboff } 1522f8919bdaSduboff 1523f8919bdaSduboff DPRINTF(3, (CE_CONT, 1524f8919bdaSduboff CONS "%s: time:%ld %s:called: isr:0x%b rx_active_head: %d", 1525f8919bdaSduboff dp->name, ddi_get_lbolt(), __func__, 1526f8919bdaSduboff isr, INTR_BITS, dp->rx_active_head)); 1527f8919bdaSduboff 1528f8919bdaSduboff if (!dp->mac_active) { 1529f8919bdaSduboff /* the device is going to stop */ 1530f8919bdaSduboff lp->our_intr_bits = 0; 1531f8919bdaSduboff return (DDI_INTR_CLAIMED); 1532f8919bdaSduboff } 1533f8919bdaSduboff 1534f8919bdaSduboff isr &= lp->our_intr_bits; 1535f8919bdaSduboff 1536f8919bdaSduboff if (isr & (ISR_RXSOVR | ISR_RXORN | ISR_RXIDLE | ISR_RXERR | 1537f8919bdaSduboff ISR_RXDESC | ISR_RXOK)) { 1538f8919bdaSduboff (void) gem_receive(dp); 1539f8919bdaSduboff 1540f8919bdaSduboff if (isr & (ISR_RXSOVR | ISR_RXORN)) { 1541f8919bdaSduboff DPRINTF(0, (CE_CONT, 1542f8919bdaSduboff CONS "%s: rx fifo overrun: isr %b", 1543f8919bdaSduboff dp->name, isr, INTR_BITS)); 1544f8919bdaSduboff /* no need restart rx */ 1545f8919bdaSduboff dp->stats.overflow++; 1546f8919bdaSduboff } 1547f8919bdaSduboff 1548f8919bdaSduboff if (isr & ISR_RXIDLE) { 1549f8919bdaSduboff DPRINTF(0, (CE_CONT, 1550f8919bdaSduboff CONS "%s: rx buffer ran out: isr %b", 1551f8919bdaSduboff dp->name, isr, INTR_BITS)); 1552f8919bdaSduboff 1553f8919bdaSduboff dp->stats.norcvbuf++; 1554f8919bdaSduboff 1555f8919bdaSduboff /* 1556f8919bdaSduboff * Make RXDP points the head of receive 1557f8919bdaSduboff * buffer list. 1558f8919bdaSduboff */ 1559f8919bdaSduboff OUTL(dp, RXDP, dp->rx_ring_dma + 1560f8919bdaSduboff SFE_DESC_SIZE * 156123d366e3Sduboff SLOT(dp->rx_active_head, rx_ring_size)); 1562f8919bdaSduboff 1563f8919bdaSduboff /* Restart the receive engine */ 1564f8919bdaSduboff OUTL(dp, CR, lp->cr | CR_RXE); 1565f8919bdaSduboff } 1566f8919bdaSduboff } 1567f8919bdaSduboff 1568f8919bdaSduboff if (isr & (ISR_TXURN | ISR_TXERR | ISR_TXDESC | 1569f8919bdaSduboff ISR_TXIDLE | ISR_TXOK)) { 1570f8919bdaSduboff /* need to reclaim tx buffers */ 1571f8919bdaSduboff if (gem_tx_done(dp)) { 1572f8919bdaSduboff flags |= INTR_RESTART_TX; 1573f8919bdaSduboff } 1574f8919bdaSduboff /* 1575f8919bdaSduboff * XXX - tx error statistics will be counted in 1576f8919bdaSduboff * sfe_tx_desc_stat() and no need to restart tx on errors. 1577f8919bdaSduboff */ 1578f8919bdaSduboff } 1579f8919bdaSduboff 1580f8919bdaSduboff if (isr & (ISR_DPERR | ISR_SSERR | ISR_RMABT | ISR_RTABT)) { 1581f8919bdaSduboff cmn_err(CE_WARN, "%s: ERROR interrupt: isr %b.", 1582f8919bdaSduboff dp->name, isr, INTR_BITS); 1583f8919bdaSduboff need_to_reset = B_TRUE; 1584f8919bdaSduboff } 1585f8919bdaSduboff reset: 1586f8919bdaSduboff if (need_to_reset) { 1587f8919bdaSduboff (void) gem_restart_nic(dp, GEM_RESTART_KEEP_BUF); 1588f8919bdaSduboff flags |= INTR_RESTART_TX; 1589f8919bdaSduboff } 1590f8919bdaSduboff 1591f8919bdaSduboff DPRINTF(5, (CE_CONT, CONS "%s: %s: return: isr: %b", 1592f8919bdaSduboff dp->name, __func__, isr, INTR_BITS)); 1593f8919bdaSduboff 1594f8919bdaSduboff return (DDI_INTR_CLAIMED | flags); 1595f8919bdaSduboff } 1596f8919bdaSduboff 1597f8919bdaSduboff /* ======================================================== */ 1598f8919bdaSduboff /* 1599f8919bdaSduboff * HW depend MII routine 1600f8919bdaSduboff */ 1601f8919bdaSduboff /* ======================================================== */ 1602f8919bdaSduboff 1603f8919bdaSduboff /* 1604f8919bdaSduboff * MII routines for NS DP83815 1605f8919bdaSduboff */ 1606f8919bdaSduboff static void 1607f8919bdaSduboff sfe_mii_sync_dp83815(struct gem_dev *dp) 1608f8919bdaSduboff { 1609f8919bdaSduboff /* do nothing */ 1610f8919bdaSduboff } 1611f8919bdaSduboff 1612f8919bdaSduboff static uint16_t 1613f8919bdaSduboff sfe_mii_read_dp83815(struct gem_dev *dp, uint_t offset) 1614f8919bdaSduboff { 1615f8919bdaSduboff DPRINTF(4, (CE_CONT, CONS"%s: %s: offset 0x%x", 1616f8919bdaSduboff dp->name, __func__, offset)); 1617f8919bdaSduboff return ((uint16_t)INL(dp, MII_REGS_BASE + offset*4)); 1618f8919bdaSduboff } 1619f8919bdaSduboff 1620f8919bdaSduboff static void 1621f8919bdaSduboff sfe_mii_write_dp83815(struct gem_dev *dp, uint_t offset, uint16_t val) 1622f8919bdaSduboff { 1623f8919bdaSduboff DPRINTF(4, (CE_CONT, CONS"%s: %s: offset 0x%x 0x%x", 1624f8919bdaSduboff dp->name, __func__, offset, val)); 1625f8919bdaSduboff OUTL(dp, MII_REGS_BASE + offset*4, val); 1626f8919bdaSduboff } 1627f8919bdaSduboff 1628f8919bdaSduboff static int 1629f8919bdaSduboff sfe_mii_config_dp83815(struct gem_dev *dp) 1630f8919bdaSduboff { 1631f8919bdaSduboff uint32_t srr; 1632f8919bdaSduboff 1633f8919bdaSduboff srr = INL(dp, SRR) & SRR_REV; 1634f8919bdaSduboff 1635f8919bdaSduboff DPRINTF(0, (CE_CONT, CONS "%s: srr:0x%04x %04x %04x %04x %04x %04x", 1636f8919bdaSduboff dp->name, srr, 1637f8919bdaSduboff INW(dp, 0x00cc), /* PGSEL */ 1638f8919bdaSduboff INW(dp, 0x00e4), /* PMDCSR */ 1639f8919bdaSduboff INW(dp, 0x00fc), /* TSTDAT */ 1640f8919bdaSduboff INW(dp, 0x00f4), /* DSPCFG */ 1641f8919bdaSduboff INW(dp, 0x00f8))); /* SDCFG */ 1642f8919bdaSduboff 164323d366e3Sduboff if (srr == SRR_REV_DP83815CVNG) { 1644f8919bdaSduboff /* 1645f8919bdaSduboff * NS datasheet says that DP83815CVNG needs following 1646f8919bdaSduboff * registers to be patched for optimizing its performance. 164723d366e3Sduboff * A report said that CRC errors on RX disappeared 1648f8919bdaSduboff * with the patch. 1649f8919bdaSduboff */ 1650f8919bdaSduboff OUTW(dp, 0x00cc, 0x0001); /* PGSEL */ 1651f8919bdaSduboff OUTW(dp, 0x00e4, 0x189c); /* PMDCSR */ 1652f8919bdaSduboff OUTW(dp, 0x00fc, 0x0000); /* TSTDAT */ 1653f8919bdaSduboff OUTW(dp, 0x00f4, 0x5040); /* DSPCFG */ 1654f8919bdaSduboff OUTW(dp, 0x00f8, 0x008c); /* SDCFG */ 165523d366e3Sduboff OUTW(dp, 0x00cc, 0x0000); /* PGSEL */ 1656f8919bdaSduboff 1657f8919bdaSduboff DPRINTF(0, (CE_CONT, 1658f8919bdaSduboff CONS "%s: PHY patched %04x %04x %04x %04x %04x", 1659f8919bdaSduboff dp->name, 1660f8919bdaSduboff INW(dp, 0x00cc), /* PGSEL */ 1661f8919bdaSduboff INW(dp, 0x00e4), /* PMDCSR */ 1662f8919bdaSduboff INW(dp, 0x00fc), /* TSTDAT */ 1663f8919bdaSduboff INW(dp, 0x00f4), /* DSPCFG */ 1664f8919bdaSduboff INW(dp, 0x00f8))); /* SDCFG */ 166523d366e3Sduboff } else if (((srr ^ SRR_REV_DP83815DVNG) & 0xff00) == 0 || 166623d366e3Sduboff ((srr ^ SRR_REV_DP83816AVNG) & 0xff00) == 0) { 166723d366e3Sduboff /* 166823d366e3Sduboff * Additional packets for later chipset 166923d366e3Sduboff */ 167023d366e3Sduboff OUTW(dp, 0x00cc, 0x0001); /* PGSEL */ 167123d366e3Sduboff OUTW(dp, 0x00e4, 0x189c); /* PMDCSR */ 167223d366e3Sduboff OUTW(dp, 0x00cc, 0x0000); /* PGSEL */ 167323d366e3Sduboff 167423d366e3Sduboff DPRINTF(0, (CE_CONT, 167523d366e3Sduboff CONS "%s: PHY patched %04x %04x", 167623d366e3Sduboff dp->name, 167723d366e3Sduboff INW(dp, 0x00cc), /* PGSEL */ 167823d366e3Sduboff INW(dp, 0x00e4))); /* PMDCSR */ 1679f8919bdaSduboff } 1680f8919bdaSduboff 1681f8919bdaSduboff return (gem_mii_config_default(dp)); 1682f8919bdaSduboff } 1683f8919bdaSduboff 168423d366e3Sduboff static int 168523d366e3Sduboff sfe_mii_probe_dp83815(struct gem_dev *dp) 168623d366e3Sduboff { 168723d366e3Sduboff uint32_t val; 168823d366e3Sduboff 168923d366e3Sduboff /* try external phy first */ 169023d366e3Sduboff DPRINTF(0, (CE_CONT, CONS "%s: %s: trying external phy", 169123d366e3Sduboff dp->name, __func__)); 169223d366e3Sduboff dp->mii_phy_addr = 0; 169323d366e3Sduboff dp->gc.gc_mii_sync = &sfe_mii_sync_sis900; 169423d366e3Sduboff dp->gc.gc_mii_read = &sfe_mii_read_sis900; 169523d366e3Sduboff dp->gc.gc_mii_write = &sfe_mii_write_sis900; 169623d366e3Sduboff 169723d366e3Sduboff val = INL(dp, CFG) & (CFG_ANEG_SEL | CFG_PHY_CFG); 169823d366e3Sduboff OUTL(dp, CFG, val | CFG_EXT_PHY | CFG_PHY_DIS); 169923d366e3Sduboff 170023d366e3Sduboff if (gem_mii_probe_default(dp) == GEM_SUCCESS) { 170123d366e3Sduboff return (GEM_SUCCESS); 170223d366e3Sduboff } 170323d366e3Sduboff 170423d366e3Sduboff /* switch to internal phy */ 170523d366e3Sduboff DPRINTF(0, (CE_CONT, CONS "%s: %s: switching to internal phy", 170623d366e3Sduboff dp->name, __func__)); 170723d366e3Sduboff dp->mii_phy_addr = -1; 170823d366e3Sduboff dp->gc.gc_mii_sync = &sfe_mii_sync_dp83815; 170923d366e3Sduboff dp->gc.gc_mii_read = &sfe_mii_read_dp83815; 171023d366e3Sduboff dp->gc.gc_mii_write = &sfe_mii_write_dp83815; 171123d366e3Sduboff 171223d366e3Sduboff val = INL(dp, CFG) & (CFG_ANEG_SEL | CFG_PHY_CFG); 171323d366e3Sduboff OUTL(dp, CFG, val | CFG_PAUSE_ADV | CFG_PHY_RST); 171423d366e3Sduboff drv_usecwait(100); /* keep to assert RST bit for a while */ 171523d366e3Sduboff OUTL(dp, CFG, val | CFG_PAUSE_ADV); 171623d366e3Sduboff 171723d366e3Sduboff /* wait for PHY reset */ 171823d366e3Sduboff delay(drv_usectohz(10000)); 171923d366e3Sduboff 172023d366e3Sduboff return (gem_mii_probe_default(dp)); 172123d366e3Sduboff } 172223d366e3Sduboff 172323d366e3Sduboff static int 172423d366e3Sduboff sfe_mii_init_dp83815(struct gem_dev *dp) 172523d366e3Sduboff { 172623d366e3Sduboff uint32_t val; 172723d366e3Sduboff 172823d366e3Sduboff val = INL(dp, CFG) & (CFG_ANEG_SEL | CFG_PHY_CFG); 172923d366e3Sduboff 173023d366e3Sduboff if (dp->mii_phy_addr == -1) { 173123d366e3Sduboff /* select internal phy */ 173223d366e3Sduboff OUTL(dp, CFG, val | CFG_PAUSE_ADV); 173323d366e3Sduboff } else { 173423d366e3Sduboff /* select external phy */ 173523d366e3Sduboff OUTL(dp, CFG, val | CFG_EXT_PHY | CFG_PHY_DIS); 173623d366e3Sduboff } 173723d366e3Sduboff 173823d366e3Sduboff return (GEM_SUCCESS); 173923d366e3Sduboff } 1740f8919bdaSduboff 1741f8919bdaSduboff /* 1742f8919bdaSduboff * MII routines for SiS900 1743f8919bdaSduboff */ 174423d366e3Sduboff #define MDIO_DELAY(dp) {(void) INL(dp, MEAR); (void) INL(dp, MEAR); } 1745f8919bdaSduboff static void 1746f8919bdaSduboff sfe_mii_sync_sis900(struct gem_dev *dp) 1747f8919bdaSduboff { 1748f8919bdaSduboff int i; 1749f8919bdaSduboff 175023d366e3Sduboff /* send 32 ONE's to make MII line idle */ 1751f8919bdaSduboff for (i = 0; i < 32; i++) { 1752f8919bdaSduboff OUTL(dp, MEAR, MEAR_MDDIR | MEAR_MDIO); 1753f8919bdaSduboff MDIO_DELAY(dp); 1754f8919bdaSduboff OUTL(dp, MEAR, MEAR_MDDIR | MEAR_MDIO | MEAR_MDC); 1755f8919bdaSduboff MDIO_DELAY(dp); 1756f8919bdaSduboff } 1757f8919bdaSduboff } 1758f8919bdaSduboff 1759f8919bdaSduboff static int 1760f8919bdaSduboff sfe_mii_config_sis900(struct gem_dev *dp) 1761f8919bdaSduboff { 1762f8919bdaSduboff struct sfe_dev *lp = dp->private; 1763f8919bdaSduboff 1764f8919bdaSduboff /* Do chip depend setup */ 1765f8919bdaSduboff if ((dp->mii_phy_id & PHY_MASK) == PHY_ICS1893) { 1766f8919bdaSduboff /* workaround for ICS1893 PHY */ 1767f8919bdaSduboff gem_mii_write(dp, 0x0018, 0xD200); 1768f8919bdaSduboff } 1769f8919bdaSduboff 1770f8919bdaSduboff if (lp->revid == SIS630E_900_REV) { 1771f8919bdaSduboff /* 1772f8919bdaSduboff * SiS 630E has bugs on default values 1773f8919bdaSduboff * of PHY registers 1774f8919bdaSduboff */ 1775f8919bdaSduboff gem_mii_write(dp, MII_AN_ADVERT, 0x05e1); 1776f8919bdaSduboff gem_mii_write(dp, MII_CONFIG1, 0x0022); 1777f8919bdaSduboff gem_mii_write(dp, MII_CONFIG2, 0xff00); 1778f8919bdaSduboff gem_mii_write(dp, MII_MASK, 0xffc0); 1779f8919bdaSduboff } 1780f8919bdaSduboff sfe_set_eq_sis630(dp); 1781f8919bdaSduboff 1782f8919bdaSduboff return (gem_mii_config_default(dp)); 1783f8919bdaSduboff } 1784f8919bdaSduboff 1785f8919bdaSduboff static uint16_t 1786f8919bdaSduboff sfe_mii_read_sis900(struct gem_dev *dp, uint_t reg) 1787f8919bdaSduboff { 1788f8919bdaSduboff uint32_t cmd; 1789f8919bdaSduboff uint16_t ret; 1790f8919bdaSduboff int i; 1791f8919bdaSduboff uint32_t data; 1792f8919bdaSduboff 1793f8919bdaSduboff cmd = MII_READ_CMD(dp->mii_phy_addr, reg); 1794f8919bdaSduboff 1795f8919bdaSduboff for (i = 31; i >= 18; i--) { 1796f8919bdaSduboff data = ((cmd >> i) & 1) << MEAR_MDIO_SHIFT; 1797f8919bdaSduboff OUTL(dp, MEAR, data | MEAR_MDDIR); 1798f8919bdaSduboff MDIO_DELAY(dp); 1799f8919bdaSduboff OUTL(dp, MEAR, data | MEAR_MDDIR | MEAR_MDC); 1800f8919bdaSduboff MDIO_DELAY(dp); 1801f8919bdaSduboff } 1802f8919bdaSduboff 1803f8919bdaSduboff /* turn around cycle */ 180423d366e3Sduboff OUTL(dp, MEAR, 0); 1805f8919bdaSduboff MDIO_DELAY(dp); 1806f8919bdaSduboff 1807f8919bdaSduboff /* get response from PHY */ 1808f8919bdaSduboff OUTL(dp, MEAR, MEAR_MDC); 1809f8919bdaSduboff MDIO_DELAY(dp); 1810f8919bdaSduboff 181123d366e3Sduboff OUTL(dp, MEAR, 0); 1812f8919bdaSduboff #if DEBUG_LEBEL > 0 181323d366e3Sduboff (void) INL(dp, MEAR); /* delay */ 1814f8919bdaSduboff if (INL(dp, MEAR) & MEAR_MDIO) { 1815f8919bdaSduboff cmn_err(CE_WARN, "%s: PHY@%d not responded", 1816f8919bdaSduboff dp->name, dp->mii_phy_addr); 1817f8919bdaSduboff } 181823d366e3Sduboff #else 181923d366e3Sduboff MDIO_DELAY(dp); 1820f8919bdaSduboff #endif 1821f8919bdaSduboff /* terminate response cycle */ 1822f8919bdaSduboff OUTL(dp, MEAR, MEAR_MDC); 182323d366e3Sduboff MDIO_DELAY(dp); 1824f8919bdaSduboff 1825f8919bdaSduboff ret = 0; /* to avoid lint errors */ 1826f8919bdaSduboff for (i = 16; i > 0; i--) { 1827f8919bdaSduboff OUTL(dp, MEAR, 0); 182823d366e3Sduboff (void) INL(dp, MEAR); /* delay */ 1829f8919bdaSduboff ret = (ret << 1) | ((INL(dp, MEAR) >> MEAR_MDIO_SHIFT) & 1); 1830f8919bdaSduboff OUTL(dp, MEAR, MEAR_MDC); 1831f8919bdaSduboff MDIO_DELAY(dp); 1832f8919bdaSduboff } 1833f8919bdaSduboff 183423d366e3Sduboff /* send two idle(Z) bits to terminate the read cycle */ 183523d366e3Sduboff for (i = 0; i < 2; i++) { 183623d366e3Sduboff OUTL(dp, MEAR, 0); 183723d366e3Sduboff MDIO_DELAY(dp); 183823d366e3Sduboff OUTL(dp, MEAR, MEAR_MDC); 183923d366e3Sduboff MDIO_DELAY(dp); 184023d366e3Sduboff } 1841f8919bdaSduboff 1842f8919bdaSduboff return (ret); 1843f8919bdaSduboff } 1844f8919bdaSduboff 1845f8919bdaSduboff static void 1846f8919bdaSduboff sfe_mii_write_sis900(struct gem_dev *dp, uint_t reg, uint16_t val) 1847f8919bdaSduboff { 1848f8919bdaSduboff uint32_t cmd; 1849f8919bdaSduboff int i; 1850f8919bdaSduboff uint32_t data; 1851f8919bdaSduboff 1852f8919bdaSduboff cmd = MII_WRITE_CMD(dp->mii_phy_addr, reg, val); 1853f8919bdaSduboff 1854f8919bdaSduboff for (i = 31; i >= 0; i--) { 1855f8919bdaSduboff data = ((cmd >> i) & 1) << MEAR_MDIO_SHIFT; 1856f8919bdaSduboff OUTL(dp, MEAR, data | MEAR_MDDIR); 1857f8919bdaSduboff MDIO_DELAY(dp); 1858f8919bdaSduboff OUTL(dp, MEAR, data | MEAR_MDDIR | MEAR_MDC); 1859f8919bdaSduboff MDIO_DELAY(dp); 1860f8919bdaSduboff } 1861f8919bdaSduboff 186223d366e3Sduboff /* send two idle(Z) bits to terminate the write cycle. */ 1863f8919bdaSduboff for (i = 0; i < 2; i++) { 186423d366e3Sduboff OUTL(dp, MEAR, 0); 1865f8919bdaSduboff MDIO_DELAY(dp); 186623d366e3Sduboff OUTL(dp, MEAR, MEAR_MDC); 1867f8919bdaSduboff MDIO_DELAY(dp); 1868f8919bdaSduboff } 1869f8919bdaSduboff } 1870f8919bdaSduboff #undef MDIO_DELAY 1871f8919bdaSduboff 1872f8919bdaSduboff static void 1873f8919bdaSduboff sfe_set_eq_sis630(struct gem_dev *dp) 1874f8919bdaSduboff { 1875f8919bdaSduboff uint16_t reg14h; 1876f8919bdaSduboff uint16_t eq_value; 1877f8919bdaSduboff uint16_t max_value; 1878f8919bdaSduboff uint16_t min_value; 1879f8919bdaSduboff int i; 1880f8919bdaSduboff uint8_t rev; 1881f8919bdaSduboff struct sfe_dev *lp = dp->private; 1882f8919bdaSduboff 1883f8919bdaSduboff rev = lp->revid; 1884f8919bdaSduboff 1885f8919bdaSduboff if (!(rev == SIS630E_900_REV || rev == SIS630EA1_900_REV || 1886f8919bdaSduboff rev == SIS630A_900_REV || rev == SIS630ET_900_REV)) { 1887f8919bdaSduboff /* it doesn't have a internal PHY */ 1888f8919bdaSduboff return; 1889f8919bdaSduboff } 1890f8919bdaSduboff 1891f8919bdaSduboff if (dp->mii_state == MII_STATE_LINKUP) { 1892f8919bdaSduboff reg14h = gem_mii_read(dp, MII_RESV); 1893f8919bdaSduboff gem_mii_write(dp, MII_RESV, (0x2200 | reg14h) & 0xBFFF); 1894f8919bdaSduboff 1895f8919bdaSduboff eq_value = (0x00f8 & gem_mii_read(dp, MII_RESV)) >> 3; 1896f8919bdaSduboff max_value = min_value = eq_value; 1897f8919bdaSduboff for (i = 1; i < 10; i++) { 1898f8919bdaSduboff eq_value = (0x00f8 & gem_mii_read(dp, MII_RESV)) >> 3; 1899f8919bdaSduboff max_value = max(eq_value, max_value); 1900f8919bdaSduboff min_value = min(eq_value, min_value); 1901f8919bdaSduboff } 1902f8919bdaSduboff 1903f8919bdaSduboff /* for 630E, rule to determine the equalizer value */ 1904f8919bdaSduboff if (rev == SIS630E_900_REV || rev == SIS630EA1_900_REV || 1905f8919bdaSduboff rev == SIS630ET_900_REV) { 1906f8919bdaSduboff if (max_value < 5) { 1907f8919bdaSduboff eq_value = max_value; 1908f8919bdaSduboff } else if (5 <= max_value && max_value < 15) { 1909f8919bdaSduboff eq_value = 1910f8919bdaSduboff max(max_value + 1, 1911f8919bdaSduboff min_value + 2); 1912f8919bdaSduboff } else if (15 <= max_value) { 1913f8919bdaSduboff eq_value = 1914f8919bdaSduboff max(max_value + 5, 1915f8919bdaSduboff min_value + 6); 1916f8919bdaSduboff } 1917f8919bdaSduboff } 1918f8919bdaSduboff /* for 630B0&B1, rule to determine the equalizer value */ 1919f8919bdaSduboff else 1920f8919bdaSduboff if (rev == SIS630A_900_REV && 1921f8919bdaSduboff (lp->bridge_revid == SIS630B0 || 1922f8919bdaSduboff lp->bridge_revid == SIS630B1)) { 1923f8919bdaSduboff 1924f8919bdaSduboff if (max_value == 0) { 1925f8919bdaSduboff eq_value = 3; 1926f8919bdaSduboff } else { 1927f8919bdaSduboff eq_value = (max_value + min_value + 1)/2; 1928f8919bdaSduboff } 1929f8919bdaSduboff } 1930f8919bdaSduboff /* write equalizer value and setting */ 1931f8919bdaSduboff reg14h = gem_mii_read(dp, MII_RESV) & ~0x02f8; 1932f8919bdaSduboff reg14h |= 0x6000 | (eq_value << 3); 1933f8919bdaSduboff gem_mii_write(dp, MII_RESV, reg14h); 1934f8919bdaSduboff } else { 1935f8919bdaSduboff reg14h = (gem_mii_read(dp, MII_RESV) & ~0x4000) | 0x2000; 1936f8919bdaSduboff if (rev == SIS630A_900_REV && 1937f8919bdaSduboff (lp->bridge_revid == SIS630B0 || 1938f8919bdaSduboff lp->bridge_revid == SIS630B1)) { 1939f8919bdaSduboff 1940f8919bdaSduboff reg14h |= 0x0200; 1941f8919bdaSduboff } 1942f8919bdaSduboff gem_mii_write(dp, MII_RESV, reg14h); 1943f8919bdaSduboff } 1944f8919bdaSduboff } 1945f8919bdaSduboff 1946f8919bdaSduboff /* ======================================================== */ 1947f8919bdaSduboff /* 1948f8919bdaSduboff * OS depend (device driver) routine 1949f8919bdaSduboff */ 1950f8919bdaSduboff /* ======================================================== */ 1951f8919bdaSduboff static void 1952f8919bdaSduboff sfe_chipinfo_init_sis900(struct gem_dev *dp) 1953f8919bdaSduboff { 1954f8919bdaSduboff int rev; 1955f8919bdaSduboff struct sfe_dev *lp = (struct sfe_dev *)dp->private; 1956f8919bdaSduboff 1957f8919bdaSduboff rev = lp->revid; 1958f8919bdaSduboff 1959f8919bdaSduboff if (rev == SIS630E_900_REV /* 0x81 */) { 1960f8919bdaSduboff /* sis630E */ 1961f8919bdaSduboff lp->get_mac_addr = &sfe_get_mac_addr_sis630e; 1962f8919bdaSduboff } else if (rev > 0x81 && rev <= 0x90) { 1963f8919bdaSduboff /* 630S, 630EA1, 630ET, 635A */ 1964f8919bdaSduboff lp->get_mac_addr = &sfe_get_mac_addr_sis635; 1965f8919bdaSduboff } else if (rev == SIS962_900_REV /* 0x91 */) { 1966f8919bdaSduboff /* sis962 or later */ 1967f8919bdaSduboff lp->get_mac_addr = &sfe_get_mac_addr_sis962; 1968f8919bdaSduboff } else { 1969f8919bdaSduboff /* sis900 */ 1970f8919bdaSduboff lp->get_mac_addr = &sfe_get_mac_addr_sis900; 1971f8919bdaSduboff } 1972f8919bdaSduboff 1973f8919bdaSduboff lp->bridge_revid = 0; 1974f8919bdaSduboff 1975f8919bdaSduboff if (rev == SIS630E_900_REV || rev == SIS630EA1_900_REV || 1976f8919bdaSduboff rev == SIS630A_900_REV || rev == SIS630ET_900_REV) { 1977f8919bdaSduboff /* 1978f8919bdaSduboff * read host bridge revision 1979f8919bdaSduboff */ 1980f8919bdaSduboff dev_info_t *bridge; 1981f8919bdaSduboff ddi_acc_handle_t bridge_handle; 1982f8919bdaSduboff 1983f8919bdaSduboff if ((bridge = sfe_search_pci_dev(0x1039, 0x630)) == NULL) { 1984f8919bdaSduboff cmn_err(CE_WARN, 1985f8919bdaSduboff "%s: cannot find host bridge (pci1039,630)", 1986f8919bdaSduboff dp->name); 1987f8919bdaSduboff return; 1988f8919bdaSduboff } 1989f8919bdaSduboff 1990f8919bdaSduboff if (pci_config_setup(bridge, &bridge_handle) != DDI_SUCCESS) { 1991f8919bdaSduboff cmn_err(CE_WARN, "%s: pci_config_setup failed", 1992f8919bdaSduboff dp->name); 1993f8919bdaSduboff return; 1994f8919bdaSduboff } 1995f8919bdaSduboff 1996f8919bdaSduboff lp->bridge_revid = 1997f8919bdaSduboff pci_config_get8(bridge_handle, PCI_CONF_REVID); 1998f8919bdaSduboff pci_config_teardown(&bridge_handle); 1999f8919bdaSduboff } 2000f8919bdaSduboff } 2001f8919bdaSduboff 2002f8919bdaSduboff static int 2003f8919bdaSduboff sfe_attach_chip(struct gem_dev *dp) 2004f8919bdaSduboff { 2005f8919bdaSduboff struct sfe_dev *lp = (struct sfe_dev *)dp->private; 2006f8919bdaSduboff 2007f8919bdaSduboff DPRINTF(4, (CE_CONT, CONS "!%s: %s called", dp->name, __func__)); 2008f8919bdaSduboff 2009f8919bdaSduboff /* setup chip-depend get_mac_address function */ 2010f8919bdaSduboff if (lp->chip->chip_type == CHIPTYPE_SIS900) { 2011f8919bdaSduboff sfe_chipinfo_init_sis900(dp); 2012f8919bdaSduboff } else { 2013f8919bdaSduboff lp->get_mac_addr = &sfe_get_mac_addr_dp83815; 2014f8919bdaSduboff } 2015f8919bdaSduboff 2016f8919bdaSduboff /* read MAC address */ 2017f8919bdaSduboff if (!(lp->get_mac_addr)(dp)) { 2018f8919bdaSduboff cmn_err(CE_WARN, 2019f8919bdaSduboff "!%s: %s: failed to get factory mac address" 2020f8919bdaSduboff " please specify a mac address in sfe.conf", 2021f8919bdaSduboff dp->name, __func__); 2022f8919bdaSduboff return (GEM_FAILURE); 2023f8919bdaSduboff } 2024f8919bdaSduboff 2025f8919bdaSduboff if (lp->chip->chip_type == CHIPTYPE_DP83815) { 2026f8919bdaSduboff dp->mii_phy_addr = -1; /* no need to scan PHY */ 2027f8919bdaSduboff dp->misc_flag |= GEM_VLAN_SOFT; 2028f8919bdaSduboff dp->txthr += 4; /* VTAG_SIZE */ 2029f8919bdaSduboff } 2030f8919bdaSduboff dp->txthr = min(dp->txthr, TXFIFOSIZE - 2); 2031f8919bdaSduboff 2032f8919bdaSduboff return (GEM_SUCCESS); 2033f8919bdaSduboff } 2034f8919bdaSduboff 2035f8919bdaSduboff static int 2036f8919bdaSduboff sfeattach(dev_info_t *dip, ddi_attach_cmd_t cmd) 2037f8919bdaSduboff { 2038f8919bdaSduboff int unit; 2039f8919bdaSduboff const char *drv_name; 2040f8919bdaSduboff int i; 2041f8919bdaSduboff ddi_acc_handle_t conf_handle; 2042f8919bdaSduboff uint16_t vid; 2043f8919bdaSduboff uint16_t did; 2044f8919bdaSduboff uint8_t rev; 2045f8919bdaSduboff #ifdef DEBUG_LEVEL 2046f8919bdaSduboff uint32_t iline; 2047f8919bdaSduboff uint8_t latim; 2048f8919bdaSduboff #endif 2049f8919bdaSduboff struct chip_info *p; 2050f8919bdaSduboff struct gem_dev *dp; 2051f8919bdaSduboff struct sfe_dev *lp; 2052f8919bdaSduboff caddr_t base; 2053f8919bdaSduboff ddi_acc_handle_t regs_ha; 2054f8919bdaSduboff struct gem_conf *gcp; 2055f8919bdaSduboff 2056f8919bdaSduboff unit = ddi_get_instance(dip); 2057f8919bdaSduboff drv_name = ddi_driver_name(dip); 2058f8919bdaSduboff 2059f8919bdaSduboff DPRINTF(3, (CE_CONT, CONS "%s%d: sfeattach: called", drv_name, unit)); 2060f8919bdaSduboff 2061f8919bdaSduboff /* 2062f8919bdaSduboff * Common codes after power-up 2063f8919bdaSduboff */ 2064f8919bdaSduboff if (pci_config_setup(dip, &conf_handle) != DDI_SUCCESS) { 2065f8919bdaSduboff cmn_err(CE_WARN, "%s%d: ddi_regs_map_setup failed", 2066f8919bdaSduboff drv_name, unit); 2067f8919bdaSduboff goto err; 2068f8919bdaSduboff } 2069f8919bdaSduboff 2070f8919bdaSduboff vid = pci_config_get16(conf_handle, PCI_CONF_VENID); 2071f8919bdaSduboff did = pci_config_get16(conf_handle, PCI_CONF_DEVID); 2072f8919bdaSduboff rev = pci_config_get16(conf_handle, PCI_CONF_REVID); 2073f8919bdaSduboff #ifdef DEBUG_LEVEL 207423d366e3Sduboff iline = pci_config_get32(conf_handle, PCI_CONF_ILINE); 207523d366e3Sduboff latim = pci_config_get8(conf_handle, PCI_CONF_LATENCY_TIMER); 2076f8919bdaSduboff #endif 2077f8919bdaSduboff #ifdef DEBUG_BUILT_IN_SIS900 2078f8919bdaSduboff rev = SIS630E_900_REV; 2079f8919bdaSduboff #endif 2080f8919bdaSduboff for (i = 0, p = sfe_chiptbl; i < CHIPTABLESIZE; i++, p++) { 2081f8919bdaSduboff if (p->venid == vid && p->devid == did) { 2082f8919bdaSduboff /* found */ 2083f8919bdaSduboff goto chip_found; 2084f8919bdaSduboff } 2085f8919bdaSduboff } 2086f8919bdaSduboff 2087f8919bdaSduboff /* Not found */ 2088f8919bdaSduboff cmn_err(CE_WARN, 2089f8919bdaSduboff "%s%d: sfe_attach: wrong PCI venid/devid (0x%x, 0x%x)", 2090f8919bdaSduboff drv_name, unit, vid, did); 2091f8919bdaSduboff pci_config_teardown(&conf_handle); 2092f8919bdaSduboff goto err; 2093f8919bdaSduboff 2094f8919bdaSduboff chip_found: 2095f8919bdaSduboff pci_config_put16(conf_handle, PCI_CONF_COMM, 2096f8919bdaSduboff PCI_COMM_IO | PCI_COMM_MAE | PCI_COMM_ME | 2097f8919bdaSduboff pci_config_get16(conf_handle, PCI_CONF_COMM)); 2098f8919bdaSduboff 2099f8919bdaSduboff /* ensure D0 mode */ 2100f8919bdaSduboff (void) gem_pci_set_power_state(dip, conf_handle, PCI_PMCSR_D0); 2101f8919bdaSduboff 2102f8919bdaSduboff pci_config_teardown(&conf_handle); 2103f8919bdaSduboff 2104f8919bdaSduboff switch (cmd) { 2105f8919bdaSduboff case DDI_RESUME: 2106f8919bdaSduboff return (gem_resume(dip)); 2107f8919bdaSduboff 2108f8919bdaSduboff case DDI_ATTACH: 2109f8919bdaSduboff 2110f8919bdaSduboff DPRINTF(0, (CE_CONT, 2111f8919bdaSduboff CONS "%s%d: ilr 0x%08x, latency_timer:0x%02x", 2112f8919bdaSduboff drv_name, unit, iline, latim)); 2113f8919bdaSduboff 2114f8919bdaSduboff /* 2115f8919bdaSduboff * Map in the device registers. 2116f8919bdaSduboff */ 2117f8919bdaSduboff if (gem_pci_regs_map_setup(dip, 2118f8919bdaSduboff (sfe_use_pcimemspace && p->chip_type == CHIPTYPE_DP83815) 2119f8919bdaSduboff ? PCI_ADDR_MEM32 : PCI_ADDR_IO, PCI_ADDR_MASK, 2120f8919bdaSduboff &sfe_dev_attr, &base, ®s_ha) != DDI_SUCCESS) { 2121f8919bdaSduboff cmn_err(CE_WARN, 2122f8919bdaSduboff "%s%d: ddi_regs_map_setup failed", 2123f8919bdaSduboff drv_name, unit); 2124f8919bdaSduboff goto err; 2125f8919bdaSduboff } 2126f8919bdaSduboff 2127f8919bdaSduboff /* 2128f8919bdaSduboff * construct gem configuration 2129f8919bdaSduboff */ 2130f8919bdaSduboff gcp = kmem_zalloc(sizeof (*gcp), KM_SLEEP); 2131f8919bdaSduboff 2132f8919bdaSduboff /* name */ 2133f8919bdaSduboff (void) sprintf(gcp->gc_name, "%s%d", drv_name, unit); 2134f8919bdaSduboff 2135f8919bdaSduboff /* consistency on tx and rx */ 2136f8919bdaSduboff gcp->gc_tx_buf_align = sizeof (uint8_t) - 1; 2137f8919bdaSduboff gcp->gc_tx_max_frags = MAXTXFRAGS; 2138f8919bdaSduboff gcp->gc_tx_max_descs_per_pkt = gcp->gc_tx_max_frags; 2139f8919bdaSduboff gcp->gc_tx_desc_unit_shift = 4; /* 16 byte */ 2140f8919bdaSduboff gcp->gc_tx_buf_size = TX_BUF_SIZE; 2141f8919bdaSduboff gcp->gc_tx_buf_limit = gcp->gc_tx_buf_size; 2142f8919bdaSduboff gcp->gc_tx_ring_size = TX_RING_SIZE; 2143f8919bdaSduboff gcp->gc_tx_ring_limit = gcp->gc_tx_ring_size; 2144f8919bdaSduboff gcp->gc_tx_auto_pad = B_TRUE; 2145f8919bdaSduboff gcp->gc_tx_copy_thresh = sfe_tx_copy_thresh; 2146f8919bdaSduboff gcp->gc_tx_desc_write_oo = B_TRUE; 2147f8919bdaSduboff 2148f8919bdaSduboff gcp->gc_rx_buf_align = sizeof (uint8_t) - 1; 2149f8919bdaSduboff gcp->gc_rx_max_frags = MAXRXFRAGS; 2150f8919bdaSduboff gcp->gc_rx_desc_unit_shift = 4; 2151f8919bdaSduboff gcp->gc_rx_ring_size = RX_RING_SIZE; 2152f8919bdaSduboff gcp->gc_rx_buf_max = RX_BUF_SIZE; 2153f8919bdaSduboff gcp->gc_rx_copy_thresh = sfe_rx_copy_thresh; 2154f8919bdaSduboff 2155f8919bdaSduboff /* map attributes */ 2156f8919bdaSduboff gcp->gc_dev_attr = sfe_dev_attr; 2157f8919bdaSduboff gcp->gc_buf_attr = sfe_buf_attr; 2158f8919bdaSduboff gcp->gc_desc_attr = sfe_buf_attr; 2159f8919bdaSduboff 2160f8919bdaSduboff /* dma attributes */ 2161f8919bdaSduboff gcp->gc_dma_attr_desc = sfe_dma_attr_desc; 2162f8919bdaSduboff 2163f8919bdaSduboff gcp->gc_dma_attr_txbuf = sfe_dma_attr_buf; 2164f8919bdaSduboff gcp->gc_dma_attr_txbuf.dma_attr_align = gcp->gc_tx_buf_align+1; 2165f8919bdaSduboff gcp->gc_dma_attr_txbuf.dma_attr_sgllen = gcp->gc_tx_max_frags; 2166f8919bdaSduboff 2167f8919bdaSduboff gcp->gc_dma_attr_rxbuf = sfe_dma_attr_buf; 2168f8919bdaSduboff gcp->gc_dma_attr_rxbuf.dma_attr_align = gcp->gc_rx_buf_align+1; 2169f8919bdaSduboff gcp->gc_dma_attr_rxbuf.dma_attr_sgllen = gcp->gc_rx_max_frags; 2170f8919bdaSduboff 2171f8919bdaSduboff /* time out parameters */ 2172f8919bdaSduboff gcp->gc_tx_timeout = 3*ONESEC; 2173f8919bdaSduboff gcp->gc_tx_timeout_interval = ONESEC; 217423d366e3Sduboff if (p->chip_type == CHIPTYPE_DP83815) { 217523d366e3Sduboff /* workaround for tx hang */ 217623d366e3Sduboff gcp->gc_tx_timeout_interval = ONESEC/20; /* 50mS */ 217723d366e3Sduboff } 2178f8919bdaSduboff 2179f8919bdaSduboff /* MII timeout parameters */ 2180f8919bdaSduboff gcp->gc_mii_link_watch_interval = ONESEC; 2181f8919bdaSduboff gcp->gc_mii_an_watch_interval = ONESEC/5; 2182f8919bdaSduboff gcp->gc_mii_reset_timeout = MII_RESET_TIMEOUT; /* 1 sec */ 2183f8919bdaSduboff gcp->gc_mii_an_timeout = MII_AN_TIMEOUT; /* 5 sec */ 2184f8919bdaSduboff gcp->gc_mii_an_wait = 0; 2185f8919bdaSduboff gcp->gc_mii_linkdown_timeout = MII_LINKDOWN_TIMEOUT; 2186f8919bdaSduboff 2187f8919bdaSduboff /* setting for general PHY */ 2188f8919bdaSduboff gcp->gc_mii_an_delay = 0; 2189f8919bdaSduboff gcp->gc_mii_linkdown_action = MII_ACTION_RSA; 2190f8919bdaSduboff gcp->gc_mii_linkdown_timeout_action = MII_ACTION_RESET; 2191f8919bdaSduboff gcp->gc_mii_dont_reset = B_FALSE; 2192f8919bdaSduboff 2193f8919bdaSduboff 2194f8919bdaSduboff /* I/O methods */ 2195f8919bdaSduboff 2196f8919bdaSduboff /* mac operation */ 2197f8919bdaSduboff gcp->gc_attach_chip = &sfe_attach_chip; 2198f8919bdaSduboff if (p->chip_type == CHIPTYPE_DP83815) { 2199f8919bdaSduboff gcp->gc_reset_chip = &sfe_reset_chip_dp83815; 2200f8919bdaSduboff } else { 2201f8919bdaSduboff gcp->gc_reset_chip = &sfe_reset_chip_sis900; 2202f8919bdaSduboff } 2203f8919bdaSduboff gcp->gc_init_chip = &sfe_init_chip; 2204f8919bdaSduboff gcp->gc_start_chip = &sfe_start_chip; 2205f8919bdaSduboff gcp->gc_stop_chip = &sfe_stop_chip; 2206f8919bdaSduboff #ifdef USE_MULTICAST_HASHTBL 2207f8919bdaSduboff gcp->gc_multicast_hash = &sfe_mcast_hash; 2208f8919bdaSduboff #endif 2209f8919bdaSduboff if (p->chip_type == CHIPTYPE_DP83815) { 2210f8919bdaSduboff gcp->gc_set_rx_filter = &sfe_set_rx_filter_dp83815; 2211f8919bdaSduboff } else { 2212f8919bdaSduboff gcp->gc_set_rx_filter = &sfe_set_rx_filter_sis900; 2213f8919bdaSduboff } 2214f8919bdaSduboff gcp->gc_set_media = &sfe_set_media; 2215f8919bdaSduboff gcp->gc_get_stats = &sfe_get_stats; 2216f8919bdaSduboff gcp->gc_interrupt = &sfe_interrupt; 2217f8919bdaSduboff 2218f8919bdaSduboff /* descriptor operation */ 2219f8919bdaSduboff gcp->gc_tx_desc_write = &sfe_tx_desc_write; 2220f8919bdaSduboff gcp->gc_tx_start = &sfe_tx_start; 2221f8919bdaSduboff gcp->gc_rx_desc_write = &sfe_rx_desc_write; 2222f8919bdaSduboff gcp->gc_rx_start = NULL; 2223f8919bdaSduboff 2224f8919bdaSduboff gcp->gc_tx_desc_stat = &sfe_tx_desc_stat; 2225f8919bdaSduboff gcp->gc_rx_desc_stat = &sfe_rx_desc_stat; 2226f8919bdaSduboff gcp->gc_tx_desc_init = &sfe_tx_desc_init; 2227f8919bdaSduboff gcp->gc_rx_desc_init = &sfe_rx_desc_init; 2228f8919bdaSduboff gcp->gc_tx_desc_clean = &sfe_tx_desc_clean; 2229f8919bdaSduboff gcp->gc_rx_desc_clean = &sfe_rx_desc_clean; 2230f8919bdaSduboff 2231f8919bdaSduboff /* mii operations */ 2232f8919bdaSduboff if (p->chip_type == CHIPTYPE_DP83815) { 223323d366e3Sduboff gcp->gc_mii_probe = &sfe_mii_probe_dp83815; 223423d366e3Sduboff gcp->gc_mii_init = &sfe_mii_init_dp83815; 2235f8919bdaSduboff gcp->gc_mii_config = &sfe_mii_config_dp83815; 2236f8919bdaSduboff gcp->gc_mii_sync = &sfe_mii_sync_dp83815; 2237f8919bdaSduboff gcp->gc_mii_read = &sfe_mii_read_dp83815; 2238f8919bdaSduboff gcp->gc_mii_write = &sfe_mii_write_dp83815; 2239f8919bdaSduboff gcp->gc_mii_tune_phy = NULL; 2240f8919bdaSduboff gcp->gc_flow_control = FLOW_CONTROL_NONE; 2241f8919bdaSduboff } else { 2242f8919bdaSduboff gcp->gc_mii_probe = &gem_mii_probe_default; 2243f8919bdaSduboff gcp->gc_mii_init = NULL; 2244f8919bdaSduboff gcp->gc_mii_config = &sfe_mii_config_sis900; 2245f8919bdaSduboff gcp->gc_mii_sync = &sfe_mii_sync_sis900; 2246f8919bdaSduboff gcp->gc_mii_read = &sfe_mii_read_sis900; 2247f8919bdaSduboff gcp->gc_mii_write = &sfe_mii_write_sis900; 2248f8919bdaSduboff gcp->gc_mii_tune_phy = &sfe_set_eq_sis630; 2249f8919bdaSduboff gcp->gc_flow_control = FLOW_CONTROL_RX_PAUSE; 2250f8919bdaSduboff } 2251f8919bdaSduboff 2252f8919bdaSduboff lp = kmem_zalloc(sizeof (*lp), KM_SLEEP); 2253f8919bdaSduboff lp->chip = p; 2254f8919bdaSduboff lp->revid = rev; 225523d366e3Sduboff lp->our_intr_bits = 0; 225623d366e3Sduboff lp->isr_pended = 0; 2257f8919bdaSduboff 2258f8919bdaSduboff cmn_err(CE_CONT, CONS "%s%d: chip:%s rev:0x%02x", 2259f8919bdaSduboff drv_name, unit, p->chip_name, rev); 2260f8919bdaSduboff 2261f8919bdaSduboff dp = gem_do_attach(dip, 0, gcp, base, ®s_ha, 2262f8919bdaSduboff lp, sizeof (*lp)); 2263f8919bdaSduboff kmem_free(gcp, sizeof (*gcp)); 2264f8919bdaSduboff 2265f8919bdaSduboff if (dp == NULL) { 2266f8919bdaSduboff goto err_freelp; 2267f8919bdaSduboff } 2268f8919bdaSduboff 2269f8919bdaSduboff return (DDI_SUCCESS); 2270f8919bdaSduboff 2271f8919bdaSduboff err_freelp: 2272f8919bdaSduboff kmem_free(lp, sizeof (struct sfe_dev)); 2273f8919bdaSduboff err: 2274f8919bdaSduboff return (DDI_FAILURE); 2275f8919bdaSduboff } 2276f8919bdaSduboff return (DDI_FAILURE); 2277f8919bdaSduboff } 2278f8919bdaSduboff 2279f8919bdaSduboff static int 2280f8919bdaSduboff sfedetach(dev_info_t *dip, ddi_detach_cmd_t cmd) 2281f8919bdaSduboff { 2282f8919bdaSduboff switch (cmd) { 2283f8919bdaSduboff case DDI_SUSPEND: 2284f8919bdaSduboff return (gem_suspend(dip)); 2285f8919bdaSduboff 2286f8919bdaSduboff case DDI_DETACH: 2287f8919bdaSduboff return (gem_do_detach(dip)); 2288f8919bdaSduboff } 2289f8919bdaSduboff return (DDI_FAILURE); 2290f8919bdaSduboff } 2291f8919bdaSduboff 2292f8919bdaSduboff /* ======================================================== */ 2293f8919bdaSduboff /* 2294f8919bdaSduboff * OS depend (loadable streams driver) routine 2295f8919bdaSduboff */ 2296f8919bdaSduboff /* ======================================================== */ 2297f8919bdaSduboff DDI_DEFINE_STREAM_OPS(sfe_ops, nulldev, nulldev, sfeattach, sfedetach, 2298*19397407SSherry Moore nodev, NULL, D_MP, NULL, ddi_quiesce_not_supported); 2299f8919bdaSduboff 2300f8919bdaSduboff static struct modldrv modldrv = { 2301f8919bdaSduboff &mod_driverops, /* Type of module. This one is a driver */ 2302f8919bdaSduboff ident, 2303f8919bdaSduboff &sfe_ops, /* driver ops */ 2304f8919bdaSduboff }; 2305f8919bdaSduboff 2306f8919bdaSduboff static struct modlinkage modlinkage = { 2307f8919bdaSduboff MODREV_1, &modldrv, NULL 2308f8919bdaSduboff }; 2309f8919bdaSduboff 2310f8919bdaSduboff /* ======================================================== */ 2311f8919bdaSduboff /* 2312f8919bdaSduboff * Loadable module support 2313f8919bdaSduboff */ 2314f8919bdaSduboff /* ======================================================== */ 2315f8919bdaSduboff int 2316f8919bdaSduboff _init(void) 2317f8919bdaSduboff { 2318f8919bdaSduboff int status; 2319f8919bdaSduboff 2320f8919bdaSduboff DPRINTF(2, (CE_CONT, CONS "sfe: _init: called")); 2321f8919bdaSduboff gem_mod_init(&sfe_ops, "sfe"); 2322f8919bdaSduboff status = mod_install(&modlinkage); 2323f8919bdaSduboff if (status != DDI_SUCCESS) { 2324f8919bdaSduboff gem_mod_fini(&sfe_ops); 2325f8919bdaSduboff } 2326f8919bdaSduboff return (status); 2327f8919bdaSduboff } 2328f8919bdaSduboff 2329f8919bdaSduboff /* 2330f8919bdaSduboff * _fini : done 2331f8919bdaSduboff */ 2332f8919bdaSduboff int 2333f8919bdaSduboff _fini(void) 2334f8919bdaSduboff { 2335f8919bdaSduboff int status; 2336f8919bdaSduboff 2337f8919bdaSduboff DPRINTF(2, (CE_CONT, CONS "sfe: _fini: called")); 2338f8919bdaSduboff status = mod_remove(&modlinkage); 2339f8919bdaSduboff if (status == DDI_SUCCESS) { 2340f8919bdaSduboff gem_mod_fini(&sfe_ops); 2341f8919bdaSduboff } 2342f8919bdaSduboff return (status); 2343f8919bdaSduboff } 2344f8919bdaSduboff 2345f8919bdaSduboff int 2346f8919bdaSduboff _info(struct modinfo *modinfop) 2347f8919bdaSduboff { 2348f8919bdaSduboff return (mod_info(&modlinkage, modinfop)); 2349f8919bdaSduboff } 2350