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