15181Sgd78059 /* 25181Sgd78059 * CDDL HEADER START 35181Sgd78059 * 45181Sgd78059 * The contents of this file are subject to the terms of the 55181Sgd78059 * Common Development and Distribution License (the "License"). 65181Sgd78059 * You may not use this file except in compliance with the License. 75181Sgd78059 * 85181Sgd78059 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95181Sgd78059 * or http://www.opensolaris.org/os/licensing. 105181Sgd78059 * See the License for the specific language governing permissions 115181Sgd78059 * and limitations under the License. 125181Sgd78059 * 135181Sgd78059 * When distributing Covered Code, include this CDDL HEADER in each 145181Sgd78059 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155181Sgd78059 * If applicable, add the following below this CDDL HEADER, with the 165181Sgd78059 * fields enclosed by brackets "[]" replaced with your own identifying 175181Sgd78059 * information: Portions Copyright [yyyy] [name of copyright owner] 185181Sgd78059 * 195181Sgd78059 * CDDL HEADER END 205181Sgd78059 */ 215181Sgd78059 /* 22*9860Sgdamore@opensolaris.org * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 235181Sgd78059 * Use is subject to license terms. 245181Sgd78059 */ 255181Sgd78059 265181Sgd78059 275181Sgd78059 #include <sys/types.h> 285181Sgd78059 #include <sys/sunddi.h> 29*9860Sgdamore@opensolaris.org #include <sys/policy.h> 30*9860Sgdamore@opensolaris.org #include <sys/sdt.h> 315181Sgd78059 #include "dmfe_impl.h" 325181Sgd78059 335181Sgd78059 /* 345181Sgd78059 * This is the string displayed by modinfo, etc. 355181Sgd78059 */ 365181Sgd78059 static char dmfe_ident[] = "Davicom DM9102 Ethernet"; 375181Sgd78059 385181Sgd78059 395181Sgd78059 /* 405181Sgd78059 * NOTES: 415181Sgd78059 * 425181Sgd78059 * #defines: 435181Sgd78059 * 445181Sgd78059 * DMFE_PCI_RNUMBER is the register-set number to use for the operating 455181Sgd78059 * registers. On an OBP-based machine, regset 0 refers to CONFIG space, 465181Sgd78059 * regset 1 will be the operating registers in I/O space, and regset 2 475181Sgd78059 * will be the operating registers in MEMORY space (preferred). If an 485181Sgd78059 * expansion ROM is fitted, it may appear as a further register set. 495181Sgd78059 * 505181Sgd78059 * DMFE_SLOP defines the amount by which the chip may read beyond 515181Sgd78059 * the end of a buffer or descriptor, apparently 6-8 dwords :( 525181Sgd78059 * We have to make sure this doesn't cause it to access unallocated 535181Sgd78059 * or unmapped memory. 545181Sgd78059 * 555181Sgd78059 * DMFE_BUF_SIZE must be at least (ETHERMAX + ETHERFCSL + DMFE_SLOP) 565181Sgd78059 * rounded up to a multiple of 4. Here we choose a power of two for 575181Sgd78059 * speed & simplicity at the cost of a bit more memory. 585181Sgd78059 * 595181Sgd78059 * However, the buffer length field in the TX/RX descriptors is only 605181Sgd78059 * eleven bits, so even though we allocate DMFE_BUF_SIZE (2048) bytes 615181Sgd78059 * per buffer, we tell the chip that they're only DMFE_BUF_SIZE_1 625181Sgd78059 * (2000) bytes each. 635181Sgd78059 * 645181Sgd78059 * DMFE_DMA_MODE defines the mode (STREAMING/CONSISTENT) used for 655181Sgd78059 * the data buffers. The descriptors are always set up in CONSISTENT 665181Sgd78059 * mode. 675181Sgd78059 * 685181Sgd78059 * DMFE_HEADROOM defines how much space we'll leave in allocated 695181Sgd78059 * mblks before the first valid data byte. This should be chosen 705181Sgd78059 * to be 2 modulo 4, so that once the ethernet header (14 bytes) 715181Sgd78059 * has been stripped off, the packet data will be 4-byte aligned. 725181Sgd78059 * The remaining space can be used by upstream modules to prepend 735181Sgd78059 * any headers required. 745181Sgd78059 * 755181Sgd78059 * Patchable globals: 765181Sgd78059 * 775181Sgd78059 * dmfe_bus_modes: the bus mode bits to be put into CSR0. 785181Sgd78059 * Setting READ_MULTIPLE in this register seems to cause 795181Sgd78059 * the chip to generate a READ LINE command with a parity 805181Sgd78059 * error! Don't do it! 815181Sgd78059 * 825181Sgd78059 * dmfe_setup_desc1: the value to be put into descriptor word 1 835181Sgd78059 * when sending a SETUP packet. 845181Sgd78059 * 855181Sgd78059 * Setting TX_LAST_DESC in desc1 in a setup packet seems 865181Sgd78059 * to make the chip spontaneously reset internally - it 875181Sgd78059 * attempts to give back the setup packet descriptor by 885181Sgd78059 * writing to PCI address 00000000 - which may or may not 895181Sgd78059 * get a MASTER ABORT - after which most of its registers 905181Sgd78059 * seem to have either default values or garbage! 915181Sgd78059 * 925181Sgd78059 * TX_FIRST_DESC doesn't seem to have the same effect but 935181Sgd78059 * it isn't needed on a setup packet so we'll leave it out 945181Sgd78059 * too, just in case it has some other wierd side-effect. 955181Sgd78059 * 965181Sgd78059 * The default hardware packet filtering mode is now 975181Sgd78059 * HASH_AND_PERFECT (imperfect filtering of multicast 985181Sgd78059 * packets and perfect filtering of unicast packets). 995181Sgd78059 * If this is found not to work reliably, setting the 1005181Sgd78059 * TX_FILTER_TYPE1 bit will cause a switchover to using 1015181Sgd78059 * HASH_ONLY mode (imperfect filtering of *all* packets). 1025181Sgd78059 * Software will then perform the additional filtering 1035181Sgd78059 * as required. 1045181Sgd78059 */ 1055181Sgd78059 1065181Sgd78059 #define DMFE_PCI_RNUMBER 2 1075181Sgd78059 #define DMFE_SLOP (8*sizeof (uint32_t)) 1085181Sgd78059 #define DMFE_BUF_SIZE 2048 1095181Sgd78059 #define DMFE_BUF_SIZE_1 2000 1105181Sgd78059 #define DMFE_DMA_MODE DDI_DMA_STREAMING 1115181Sgd78059 #define DMFE_HEADROOM 34 1125181Sgd78059 1135181Sgd78059 static uint32_t dmfe_bus_modes = TX_POLL_INTVL | CACHE_ALIGN; 1145181Sgd78059 static uint32_t dmfe_setup_desc1 = TX_SETUP_PACKET | SETUPBUF_SIZE | 1155181Sgd78059 TX_FILTER_TYPE0; 1165181Sgd78059 1175181Sgd78059 /* 1185181Sgd78059 * Some tunable parameters ... 1195181Sgd78059 * Number of RX/TX ring entries (128/128) 1205181Sgd78059 * Minimum number of TX ring slots to keep free (1) 1215181Sgd78059 * Low-water mark at which to try to reclaim TX ring slots (1) 1225181Sgd78059 * How often to take a TX-done interrupt (twice per ring cycle) 1235181Sgd78059 * Whether to reclaim TX ring entries on a TX-done interrupt (no) 1245181Sgd78059 */ 1255181Sgd78059 1265181Sgd78059 #define DMFE_TX_DESC 128 /* Should be a multiple of 4 <= 256 */ 1275181Sgd78059 #define DMFE_RX_DESC 128 /* Should be a multiple of 4 <= 256 */ 1285181Sgd78059 1295181Sgd78059 static uint32_t dmfe_rx_desc = DMFE_RX_DESC; 1305181Sgd78059 static uint32_t dmfe_tx_desc = DMFE_TX_DESC; 1315181Sgd78059 static uint32_t dmfe_tx_min_free = 1; 1325181Sgd78059 static uint32_t dmfe_tx_reclaim_level = 1; 1335181Sgd78059 static uint32_t dmfe_tx_int_factor = (DMFE_TX_DESC / 2) - 1; 1345181Sgd78059 static boolean_t dmfe_reclaim_on_done = B_FALSE; 1355181Sgd78059 1365181Sgd78059 /* 1375181Sgd78059 * Time-related parameters: 1385181Sgd78059 * 1395181Sgd78059 * We use a cyclic to provide a periodic callback; this is then used 1405181Sgd78059 * to check for TX-stall and poll the link status register. 1415181Sgd78059 * 1425181Sgd78059 * DMFE_TICK is the interval between cyclic callbacks, in microseconds. 1435181Sgd78059 * 1445181Sgd78059 * TX_STALL_TIME_100 is the timeout in microseconds between passing 1455181Sgd78059 * a packet to the chip for transmission and seeing that it's gone, 1465181Sgd78059 * when running at 100Mb/s. If we haven't reclaimed at least one 1475181Sgd78059 * descriptor in this time we assume the transmitter has stalled 1485181Sgd78059 * and reset the chip. 1495181Sgd78059 * 1505181Sgd78059 * TX_STALL_TIME_10 is the equivalent timeout when running at 10Mb/s. 1515181Sgd78059 * 1525181Sgd78059 * Patchable globals: 1535181Sgd78059 * 1545181Sgd78059 * dmfe_tick_us: DMFE_TICK 1555181Sgd78059 * dmfe_tx100_stall_us: TX_STALL_TIME_100 1565181Sgd78059 * dmfe_tx10_stall_us: TX_STALL_TIME_10 1575181Sgd78059 * 1585181Sgd78059 * These are then used in _init() to calculate: 1595181Sgd78059 * 1605181Sgd78059 * stall_100_tix[]: number of consecutive cyclic callbacks without a 1615181Sgd78059 * reclaim before the TX process is considered stalled, 1625181Sgd78059 * when running at 100Mb/s. The elements are indexed 1635181Sgd78059 * by transmit-engine-state. 1645181Sgd78059 * stall_10_tix[]: number of consecutive cyclic callbacks without a 1655181Sgd78059 * reclaim before the TX process is considered stalled, 1665181Sgd78059 * when running at 10Mb/s. The elements are indexed 1675181Sgd78059 * by transmit-engine-state. 1685181Sgd78059 */ 1695181Sgd78059 1705181Sgd78059 #define DMFE_TICK 25000 /* microseconds */ 1715181Sgd78059 #define TX_STALL_TIME_100 50000 /* microseconds */ 1725181Sgd78059 #define TX_STALL_TIME_10 200000 /* microseconds */ 1735181Sgd78059 1745181Sgd78059 static uint32_t dmfe_tick_us = DMFE_TICK; 1755181Sgd78059 static uint32_t dmfe_tx100_stall_us = TX_STALL_TIME_100; 1765181Sgd78059 static uint32_t dmfe_tx10_stall_us = TX_STALL_TIME_10; 1775181Sgd78059 1785181Sgd78059 /* 1795181Sgd78059 * Calculated from above in _init() 1805181Sgd78059 */ 1815181Sgd78059 1825181Sgd78059 static uint32_t stall_100_tix[TX_PROCESS_MAX_STATE+1]; 1835181Sgd78059 static uint32_t stall_10_tix[TX_PROCESS_MAX_STATE+1]; 1845181Sgd78059 1855181Sgd78059 /* 1865181Sgd78059 * Property names 1875181Sgd78059 */ 1885181Sgd78059 static char localmac_propname[] = "local-mac-address"; 1895181Sgd78059 static char opmode_propname[] = "opmode-reg-value"; 1905181Sgd78059 1915181Sgd78059 static int dmfe_m_start(void *); 1925181Sgd78059 static void dmfe_m_stop(void *); 1935181Sgd78059 static int dmfe_m_promisc(void *, boolean_t); 1945181Sgd78059 static int dmfe_m_multicst(void *, boolean_t, const uint8_t *); 1955181Sgd78059 static int dmfe_m_unicst(void *, const uint8_t *); 1965181Sgd78059 static void dmfe_m_ioctl(void *, queue_t *, mblk_t *); 1975181Sgd78059 static mblk_t *dmfe_m_tx(void *, mblk_t *); 1985181Sgd78059 static int dmfe_m_stat(void *, uint_t, uint64_t *); 199*9860Sgdamore@opensolaris.org static int dmfe_m_getprop(void *, const char *, mac_prop_id_t, 200*9860Sgdamore@opensolaris.org uint_t, uint_t, void *, uint_t *); 201*9860Sgdamore@opensolaris.org static int dmfe_m_setprop(void *, const char *, mac_prop_id_t, 202*9860Sgdamore@opensolaris.org uint_t, const void *); 2035181Sgd78059 2045181Sgd78059 static mac_callbacks_t dmfe_m_callbacks = { 205*9860Sgdamore@opensolaris.org (MC_IOCTL | MC_SETPROP | MC_GETPROP), 2065181Sgd78059 dmfe_m_stat, 2075181Sgd78059 dmfe_m_start, 2085181Sgd78059 dmfe_m_stop, 2095181Sgd78059 dmfe_m_promisc, 2105181Sgd78059 dmfe_m_multicst, 2115181Sgd78059 dmfe_m_unicst, 2125181Sgd78059 dmfe_m_tx, 2138275SEric Cheng dmfe_m_ioctl, 214*9860Sgdamore@opensolaris.org NULL, /* getcapab */ 215*9860Sgdamore@opensolaris.org NULL, /* open */ 216*9860Sgdamore@opensolaris.org NULL, /* close */ 217*9860Sgdamore@opensolaris.org dmfe_m_setprop, 218*9860Sgdamore@opensolaris.org dmfe_m_getprop 2195181Sgd78059 }; 2205181Sgd78059 2215181Sgd78059 2225181Sgd78059 /* 2235181Sgd78059 * Describes the chip's DMA engine 2245181Sgd78059 */ 2255181Sgd78059 static ddi_dma_attr_t dma_attr = { 2265181Sgd78059 DMA_ATTR_V0, /* dma_attr version */ 2275181Sgd78059 0, /* dma_attr_addr_lo */ 2285181Sgd78059 (uint32_t)0xFFFFFFFF, /* dma_attr_addr_hi */ 2295181Sgd78059 0x0FFFFFF, /* dma_attr_count_max */ 2305181Sgd78059 0x20, /* dma_attr_align */ 2315181Sgd78059 0x7F, /* dma_attr_burstsizes */ 2325181Sgd78059 1, /* dma_attr_minxfer */ 2335181Sgd78059 (uint32_t)0xFFFFFFFF, /* dma_attr_maxxfer */ 2345181Sgd78059 (uint32_t)0xFFFFFFFF, /* dma_attr_seg */ 2355181Sgd78059 1, /* dma_attr_sgllen */ 2365181Sgd78059 1, /* dma_attr_granular */ 2375181Sgd78059 0 /* dma_attr_flags */ 2385181Sgd78059 }; 2395181Sgd78059 2405181Sgd78059 /* 2415181Sgd78059 * DMA access attributes for registers and descriptors 2425181Sgd78059 */ 2435181Sgd78059 static ddi_device_acc_attr_t dmfe_reg_accattr = { 2445181Sgd78059 DDI_DEVICE_ATTR_V0, 2455181Sgd78059 DDI_STRUCTURE_LE_ACC, 2465181Sgd78059 DDI_STRICTORDER_ACC 2475181Sgd78059 }; 2485181Sgd78059 2495181Sgd78059 /* 2505181Sgd78059 * DMA access attributes for data: NOT to be byte swapped. 2515181Sgd78059 */ 2525181Sgd78059 static ddi_device_acc_attr_t dmfe_data_accattr = { 2535181Sgd78059 DDI_DEVICE_ATTR_V0, 2545181Sgd78059 DDI_NEVERSWAP_ACC, 2555181Sgd78059 DDI_STRICTORDER_ACC 2565181Sgd78059 }; 2575181Sgd78059 2585181Sgd78059 static uchar_t dmfe_broadcast_addr[ETHERADDRL] = { 2595181Sgd78059 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 2605181Sgd78059 }; 2615181Sgd78059 2625181Sgd78059 2635181Sgd78059 /* 2645181Sgd78059 * ========== Lowest-level chip register & ring access routines ========== 2655181Sgd78059 */ 2665181Sgd78059 2675181Sgd78059 /* 2685181Sgd78059 * I/O register get/put routines 2695181Sgd78059 */ 2705181Sgd78059 uint32_t 2715181Sgd78059 dmfe_chip_get32(dmfe_t *dmfep, off_t offset) 2725181Sgd78059 { 2736990Sgd78059 uint32_t *addr; 2746990Sgd78059 2756990Sgd78059 addr = (void *)(dmfep->io_reg + offset); 2766990Sgd78059 return (ddi_get32(dmfep->io_handle, addr)); 2775181Sgd78059 } 2785181Sgd78059 2795181Sgd78059 void 2805181Sgd78059 dmfe_chip_put32(dmfe_t *dmfep, off_t offset, uint32_t value) 2815181Sgd78059 { 2826990Sgd78059 uint32_t *addr; 2836990Sgd78059 2846990Sgd78059 addr = (void *)(dmfep->io_reg + offset); 2856990Sgd78059 ddi_put32(dmfep->io_handle, addr, value); 2865181Sgd78059 } 2875181Sgd78059 2885181Sgd78059 /* 2895181Sgd78059 * TX/RX ring get/put routines 2905181Sgd78059 */ 2915181Sgd78059 static uint32_t 2925181Sgd78059 dmfe_ring_get32(dma_area_t *dma_p, uint_t index, uint_t offset) 2935181Sgd78059 { 2945181Sgd78059 uint32_t *addr; 2955181Sgd78059 2966990Sgd78059 addr = (void *)dma_p->mem_va; 2975181Sgd78059 return (ddi_get32(dma_p->acc_hdl, addr + index*DESC_SIZE + offset)); 2985181Sgd78059 } 2995181Sgd78059 3005181Sgd78059 static void 3015181Sgd78059 dmfe_ring_put32(dma_area_t *dma_p, uint_t index, uint_t offset, uint32_t value) 3025181Sgd78059 { 3035181Sgd78059 uint32_t *addr; 3045181Sgd78059 3056990Sgd78059 addr = (void *)dma_p->mem_va; 3065181Sgd78059 ddi_put32(dma_p->acc_hdl, addr + index*DESC_SIZE + offset, value); 3075181Sgd78059 } 3085181Sgd78059 3095181Sgd78059 /* 3105181Sgd78059 * Setup buffer get/put routines 3115181Sgd78059 */ 3125181Sgd78059 static uint32_t 3135181Sgd78059 dmfe_setup_get32(dma_area_t *dma_p, uint_t index) 3145181Sgd78059 { 3155181Sgd78059 uint32_t *addr; 3165181Sgd78059 3176990Sgd78059 addr = (void *)dma_p->setup_va; 3185181Sgd78059 return (ddi_get32(dma_p->acc_hdl, addr + index)); 3195181Sgd78059 } 3205181Sgd78059 3215181Sgd78059 static void 3225181Sgd78059 dmfe_setup_put32(dma_area_t *dma_p, uint_t index, uint32_t value) 3235181Sgd78059 { 3245181Sgd78059 uint32_t *addr; 3255181Sgd78059 3266990Sgd78059 addr = (void *)dma_p->setup_va; 3275181Sgd78059 ddi_put32(dma_p->acc_hdl, addr + index, value); 3285181Sgd78059 } 3295181Sgd78059 3305181Sgd78059 3315181Sgd78059 /* 3325181Sgd78059 * ========== Low-level chip & ring buffer manipulation ========== 3335181Sgd78059 */ 3345181Sgd78059 3355181Sgd78059 /* 3365181Sgd78059 * dmfe_set_opmode() -- function to set operating mode 3375181Sgd78059 */ 3385181Sgd78059 static void 3395181Sgd78059 dmfe_set_opmode(dmfe_t *dmfep) 3405181Sgd78059 { 3415181Sgd78059 ASSERT(mutex_owned(dmfep->oplock)); 3425181Sgd78059 3435181Sgd78059 dmfe_chip_put32(dmfep, OPN_MODE_REG, dmfep->opmode); 3445181Sgd78059 drv_usecwait(10); 3455181Sgd78059 } 3465181Sgd78059 3475181Sgd78059 /* 3485181Sgd78059 * dmfe_stop_chip() -- stop all chip processing & optionally reset the h/w 3495181Sgd78059 */ 3505181Sgd78059 static void 3515181Sgd78059 dmfe_stop_chip(dmfe_t *dmfep, enum chip_state newstate) 3525181Sgd78059 { 3535181Sgd78059 ASSERT(mutex_owned(dmfep->oplock)); 3545181Sgd78059 3555181Sgd78059 /* 3565181Sgd78059 * Stop the chip: 3575181Sgd78059 * disable all interrupts 3585181Sgd78059 * stop TX/RX processes 3595181Sgd78059 * clear the status bits for TX/RX stopped 3605181Sgd78059 * If required, reset the chip 3615181Sgd78059 * Record the new state 3625181Sgd78059 */ 3635181Sgd78059 dmfe_chip_put32(dmfep, INT_MASK_REG, 0); 3645181Sgd78059 dmfep->opmode &= ~(START_TRANSMIT | START_RECEIVE); 3655181Sgd78059 dmfe_set_opmode(dmfep); 3665181Sgd78059 dmfe_chip_put32(dmfep, STATUS_REG, TX_STOPPED_INT | RX_STOPPED_INT); 3675181Sgd78059 3685181Sgd78059 switch (newstate) { 3695181Sgd78059 default: 3705181Sgd78059 ASSERT(!"can't get here"); 3715181Sgd78059 return; 3725181Sgd78059 3735181Sgd78059 case CHIP_STOPPED: 3745181Sgd78059 case CHIP_ERROR: 3755181Sgd78059 break; 3765181Sgd78059 3775181Sgd78059 case CHIP_RESET: 3785181Sgd78059 dmfe_chip_put32(dmfep, BUS_MODE_REG, SW_RESET); 3795181Sgd78059 drv_usecwait(10); 3805181Sgd78059 dmfe_chip_put32(dmfep, BUS_MODE_REG, 0); 3815181Sgd78059 drv_usecwait(10); 3825181Sgd78059 dmfe_chip_put32(dmfep, BUS_MODE_REG, dmfe_bus_modes); 3835181Sgd78059 break; 3845181Sgd78059 } 3855181Sgd78059 3865181Sgd78059 dmfep->chip_state = newstate; 3875181Sgd78059 } 3885181Sgd78059 3895181Sgd78059 /* 3905181Sgd78059 * Initialize transmit and receive descriptor rings, and 3915181Sgd78059 * set the chip to point to the first entry in each ring 3925181Sgd78059 */ 3935181Sgd78059 static void 3945181Sgd78059 dmfe_init_rings(dmfe_t *dmfep) 3955181Sgd78059 { 3965181Sgd78059 dma_area_t *descp; 3975181Sgd78059 uint32_t pstart; 3985181Sgd78059 uint32_t pnext; 3995181Sgd78059 uint32_t pbuff; 4005181Sgd78059 uint32_t desc1; 4015181Sgd78059 int i; 4025181Sgd78059 4035181Sgd78059 /* 4045181Sgd78059 * You need all the locks in order to rewrite the descriptor rings 4055181Sgd78059 */ 4065181Sgd78059 ASSERT(mutex_owned(dmfep->oplock)); 4075181Sgd78059 ASSERT(mutex_owned(dmfep->rxlock)); 4085181Sgd78059 ASSERT(mutex_owned(dmfep->txlock)); 4095181Sgd78059 4105181Sgd78059 /* 4115181Sgd78059 * Program the RX ring entries 4125181Sgd78059 */ 4135181Sgd78059 descp = &dmfep->rx_desc; 4145181Sgd78059 pstart = descp->mem_dvma; 4155181Sgd78059 pnext = pstart + sizeof (struct rx_desc_type); 4165181Sgd78059 pbuff = dmfep->rx_buff.mem_dvma; 4175181Sgd78059 desc1 = RX_CHAINING | DMFE_BUF_SIZE_1; 4185181Sgd78059 4195181Sgd78059 for (i = 0; i < dmfep->rx.n_desc; ++i) { 4205181Sgd78059 dmfe_ring_put32(descp, i, RD_NEXT, pnext); 4215181Sgd78059 dmfe_ring_put32(descp, i, BUFFER1, pbuff); 4225181Sgd78059 dmfe_ring_put32(descp, i, DESC1, desc1); 4235181Sgd78059 dmfe_ring_put32(descp, i, DESC0, RX_OWN); 4245181Sgd78059 4255181Sgd78059 pnext += sizeof (struct rx_desc_type); 4265181Sgd78059 pbuff += DMFE_BUF_SIZE; 4275181Sgd78059 } 4285181Sgd78059 4295181Sgd78059 /* 4305181Sgd78059 * Fix up last entry & sync 4315181Sgd78059 */ 4325181Sgd78059 dmfe_ring_put32(descp, --i, RD_NEXT, pstart); 4335181Sgd78059 DMA_SYNC(descp, DDI_DMA_SYNC_FORDEV); 4345181Sgd78059 dmfep->rx.next_free = 0; 4355181Sgd78059 4365181Sgd78059 /* 4375181Sgd78059 * Set the base address of the RX descriptor list in CSR3 4385181Sgd78059 */ 4395181Sgd78059 dmfe_chip_put32(dmfep, RX_BASE_ADDR_REG, descp->mem_dvma); 4405181Sgd78059 4415181Sgd78059 /* 4425181Sgd78059 * Program the TX ring entries 4435181Sgd78059 */ 4445181Sgd78059 descp = &dmfep->tx_desc; 4455181Sgd78059 pstart = descp->mem_dvma; 4465181Sgd78059 pnext = pstart + sizeof (struct tx_desc_type); 4475181Sgd78059 pbuff = dmfep->tx_buff.mem_dvma; 4485181Sgd78059 desc1 = TX_CHAINING; 4495181Sgd78059 4505181Sgd78059 for (i = 0; i < dmfep->tx.n_desc; ++i) { 4515181Sgd78059 dmfe_ring_put32(descp, i, TD_NEXT, pnext); 4525181Sgd78059 dmfe_ring_put32(descp, i, BUFFER1, pbuff); 4535181Sgd78059 dmfe_ring_put32(descp, i, DESC1, desc1); 4545181Sgd78059 dmfe_ring_put32(descp, i, DESC0, 0); 4555181Sgd78059 4565181Sgd78059 pnext += sizeof (struct tx_desc_type); 4575181Sgd78059 pbuff += DMFE_BUF_SIZE; 4585181Sgd78059 } 4595181Sgd78059 4605181Sgd78059 /* 4615181Sgd78059 * Fix up last entry & sync 4625181Sgd78059 */ 4635181Sgd78059 dmfe_ring_put32(descp, --i, TD_NEXT, pstart); 4645181Sgd78059 DMA_SYNC(descp, DDI_DMA_SYNC_FORDEV); 4655181Sgd78059 dmfep->tx.n_free = dmfep->tx.n_desc; 4665181Sgd78059 dmfep->tx.next_free = dmfep->tx.next_busy = 0; 4675181Sgd78059 4685181Sgd78059 /* 4695181Sgd78059 * Set the base address of the TX descrptor list in CSR4 4705181Sgd78059 */ 4715181Sgd78059 dmfe_chip_put32(dmfep, TX_BASE_ADDR_REG, descp->mem_dvma); 4725181Sgd78059 } 4735181Sgd78059 4745181Sgd78059 /* 4755181Sgd78059 * dmfe_start_chip() -- start the chip transmitting and/or receiving 4765181Sgd78059 */ 4775181Sgd78059 static void 4785181Sgd78059 dmfe_start_chip(dmfe_t *dmfep, int mode) 4795181Sgd78059 { 4805181Sgd78059 ASSERT(mutex_owned(dmfep->oplock)); 4815181Sgd78059 4825181Sgd78059 dmfep->opmode |= mode; 4835181Sgd78059 dmfe_set_opmode(dmfep); 4845181Sgd78059 4855181Sgd78059 dmfe_chip_put32(dmfep, W_J_TIMER_REG, 0); 4865181Sgd78059 /* 4875181Sgd78059 * Enable VLAN length mode (allows packets to be 4 bytes Longer). 4885181Sgd78059 */ 4895181Sgd78059 dmfe_chip_put32(dmfep, W_J_TIMER_REG, VLAN_ENABLE); 4905181Sgd78059 4915181Sgd78059 /* 4925181Sgd78059 * Clear any pending process-stopped interrupts 4935181Sgd78059 */ 4945181Sgd78059 dmfe_chip_put32(dmfep, STATUS_REG, TX_STOPPED_INT | RX_STOPPED_INT); 4955181Sgd78059 dmfep->chip_state = mode & START_RECEIVE ? CHIP_TX_RX : 4965181Sgd78059 mode & START_TRANSMIT ? CHIP_TX_ONLY : CHIP_STOPPED; 4975181Sgd78059 } 4985181Sgd78059 4995181Sgd78059 /* 5005181Sgd78059 * dmfe_enable_interrupts() -- enable our favourite set of interrupts. 5015181Sgd78059 * 5025181Sgd78059 * Normal interrupts: 5035181Sgd78059 * We always enable: 5045181Sgd78059 * RX_PKTDONE_INT (packet received) 5055181Sgd78059 * TX_PKTDONE_INT (TX complete) 5065181Sgd78059 * We never enable: 5075181Sgd78059 * TX_ALLDONE_INT (next TX buffer not ready) 5085181Sgd78059 * 5095181Sgd78059 * Abnormal interrupts: 5105181Sgd78059 * We always enable: 5115181Sgd78059 * RX_STOPPED_INT 5125181Sgd78059 * TX_STOPPED_INT 5135181Sgd78059 * SYSTEM_ERR_INT 5145181Sgd78059 * RX_UNAVAIL_INT 5155181Sgd78059 * We never enable: 5165181Sgd78059 * RX_EARLY_INT 5175181Sgd78059 * RX_WATCHDOG_INT 5185181Sgd78059 * TX_JABBER_INT 5195181Sgd78059 * TX_EARLY_INT 5205181Sgd78059 * TX_UNDERFLOW_INT 5215181Sgd78059 * GP_TIMER_INT (not valid in -9 chips) 5225181Sgd78059 * LINK_STATUS_INT (not valid in -9 chips) 5235181Sgd78059 */ 5245181Sgd78059 static void 5255181Sgd78059 dmfe_enable_interrupts(dmfe_t *dmfep) 5265181Sgd78059 { 5275181Sgd78059 ASSERT(mutex_owned(dmfep->oplock)); 5285181Sgd78059 5295181Sgd78059 /* 5305181Sgd78059 * Put 'the standard set of interrupts' in the interrupt mask register 5315181Sgd78059 */ 5325181Sgd78059 dmfep->imask = RX_PKTDONE_INT | TX_PKTDONE_INT | 5335181Sgd78059 RX_STOPPED_INT | TX_STOPPED_INT | RX_UNAVAIL_INT | SYSTEM_ERR_INT; 5345181Sgd78059 5355181Sgd78059 dmfe_chip_put32(dmfep, INT_MASK_REG, 5365181Sgd78059 NORMAL_SUMMARY_INT | ABNORMAL_SUMMARY_INT | dmfep->imask); 5375181Sgd78059 dmfep->chip_state = CHIP_RUNNING; 5385181Sgd78059 } 5395181Sgd78059 5405181Sgd78059 /* 5415181Sgd78059 * ========== RX side routines ========== 5425181Sgd78059 */ 5435181Sgd78059 5445181Sgd78059 /* 5455181Sgd78059 * Function to update receive statistics on various errors 5465181Sgd78059 */ 5475181Sgd78059 static void 5485181Sgd78059 dmfe_update_rx_stats(dmfe_t *dmfep, uint32_t desc0) 5495181Sgd78059 { 5505181Sgd78059 ASSERT(mutex_owned(dmfep->rxlock)); 5515181Sgd78059 5525181Sgd78059 /* 5535181Sgd78059 * The error summary bit and the error bits that it summarises 5545181Sgd78059 * are only valid if this is the last fragment. Therefore, a 5555181Sgd78059 * fragment only contributes to the error statistics if both 5565181Sgd78059 * the last-fragment and error summary bits are set. 5575181Sgd78059 */ 5585181Sgd78059 if (((RX_LAST_DESC | RX_ERR_SUMMARY) & ~desc0) == 0) { 5595181Sgd78059 dmfep->rx_stats_ierrors += 1; 5605181Sgd78059 5615181Sgd78059 /* 5625181Sgd78059 * There are some other error bits in the descriptor for 5635181Sgd78059 * which there don't seem to be appropriate MAC statistics, 5645181Sgd78059 * notably RX_COLLISION and perhaps RX_DESC_ERR. The 5655181Sgd78059 * latter may not be possible if it is supposed to indicate 5665181Sgd78059 * that one buffer has been filled with a partial packet 5675181Sgd78059 * and the next buffer required for the rest of the packet 5685181Sgd78059 * was not available, as all our buffers are more than large 5695181Sgd78059 * enough for a whole packet without fragmenting. 5705181Sgd78059 */ 5715181Sgd78059 5725181Sgd78059 if (desc0 & RX_OVERFLOW) { 5735181Sgd78059 dmfep->rx_stats_overflow += 1; 5745181Sgd78059 5755181Sgd78059 } else if (desc0 & RX_RUNT_FRAME) 5765181Sgd78059 dmfep->rx_stats_short += 1; 5775181Sgd78059 5785181Sgd78059 if (desc0 & RX_CRC) 5795181Sgd78059 dmfep->rx_stats_fcs += 1; 5805181Sgd78059 5815181Sgd78059 if (desc0 & RX_FRAME2LONG) 5825181Sgd78059 dmfep->rx_stats_toolong += 1; 5835181Sgd78059 } 5845181Sgd78059 5855181Sgd78059 /* 5865181Sgd78059 * A receive watchdog timeout is counted as a MAC-level receive 5875181Sgd78059 * error. Strangely, it doesn't set the packet error summary bit, 5885181Sgd78059 * according to the chip data sheet :-? 5895181Sgd78059 */ 5905181Sgd78059 if (desc0 & RX_RCV_WD_TO) 5915181Sgd78059 dmfep->rx_stats_macrcv_errors += 1; 5925181Sgd78059 5935181Sgd78059 if (desc0 & RX_DRIBBLING) 5945181Sgd78059 dmfep->rx_stats_align += 1; 5955181Sgd78059 5965181Sgd78059 if (desc0 & RX_MII_ERR) 5975181Sgd78059 dmfep->rx_stats_macrcv_errors += 1; 5985181Sgd78059 } 5995181Sgd78059 6005181Sgd78059 /* 6015181Sgd78059 * Receive incoming packet(s) and pass them up ... 6025181Sgd78059 */ 6035181Sgd78059 static mblk_t * 6045181Sgd78059 dmfe_getp(dmfe_t *dmfep) 6055181Sgd78059 { 6065181Sgd78059 dma_area_t *descp; 6075181Sgd78059 mblk_t **tail; 6085181Sgd78059 mblk_t *head; 6095181Sgd78059 mblk_t *mp; 6105181Sgd78059 char *rxb; 6115181Sgd78059 uchar_t *dp; 6125181Sgd78059 uint32_t desc0; 6135181Sgd78059 uint32_t misses; 6145181Sgd78059 int packet_length; 6155181Sgd78059 int index; 6165181Sgd78059 6175181Sgd78059 mutex_enter(dmfep->rxlock); 6185181Sgd78059 6195181Sgd78059 /* 6205181Sgd78059 * Update the missed frame statistic from the on-chip counter. 6215181Sgd78059 */ 6225181Sgd78059 misses = dmfe_chip_get32(dmfep, MISSED_FRAME_REG); 6235181Sgd78059 dmfep->rx_stats_norcvbuf += (misses & MISSED_FRAME_MASK); 6245181Sgd78059 6255181Sgd78059 /* 6265181Sgd78059 * sync (all) receive descriptors before inspecting them 6275181Sgd78059 */ 6285181Sgd78059 descp = &dmfep->rx_desc; 6295181Sgd78059 DMA_SYNC(descp, DDI_DMA_SYNC_FORKERNEL); 6305181Sgd78059 6315181Sgd78059 /* 6325181Sgd78059 * We should own at least one RX entry, since we've had a 6335181Sgd78059 * receive interrupt, but let's not be dogmatic about it. 6345181Sgd78059 */ 6355181Sgd78059 index = dmfep->rx.next_free; 6365181Sgd78059 desc0 = dmfe_ring_get32(descp, index, DESC0); 637*9860Sgdamore@opensolaris.org 638*9860Sgdamore@opensolaris.org DTRACE_PROBE1(rx__start, uint32_t, desc0); 6395181Sgd78059 for (head = NULL, tail = &head; (desc0 & RX_OWN) == 0; ) { 6405181Sgd78059 /* 6415181Sgd78059 * Maintain statistics for every descriptor returned 6425181Sgd78059 * to us by the chip ... 6435181Sgd78059 */ 6445181Sgd78059 dmfe_update_rx_stats(dmfep, desc0); 6455181Sgd78059 6465181Sgd78059 /* 6475181Sgd78059 * Check that the entry has both "packet start" and 6485181Sgd78059 * "packet end" flags. We really shouldn't get packet 6495181Sgd78059 * fragments, 'cos all the RX buffers are bigger than 6505181Sgd78059 * the largest valid packet. So we'll just drop any 6515181Sgd78059 * fragments we find & skip on to the next entry. 6525181Sgd78059 */ 6535181Sgd78059 if (((RX_FIRST_DESC | RX_LAST_DESC) & ~desc0) != 0) { 654*9860Sgdamore@opensolaris.org DTRACE_PROBE1(rx__frag, uint32_t, desc0); 6555181Sgd78059 goto skip; 6565181Sgd78059 } 6575181Sgd78059 6585181Sgd78059 /* 6595181Sgd78059 * A whole packet in one buffer. We have to check error 6605181Sgd78059 * status and packet length before forwarding it upstream. 6615181Sgd78059 */ 6625181Sgd78059 if (desc0 & RX_ERR_SUMMARY) { 663*9860Sgdamore@opensolaris.org DTRACE_PROBE1(rx__err, uint32_t, desc0); 6645181Sgd78059 goto skip; 6655181Sgd78059 } 6665181Sgd78059 6675181Sgd78059 packet_length = (desc0 >> 16) & 0x3fff; 6685181Sgd78059 if (packet_length > DMFE_MAX_PKT_SIZE) { 669*9860Sgdamore@opensolaris.org DTRACE_PROBE1(rx__toobig, int, packet_length); 6705181Sgd78059 goto skip; 6715181Sgd78059 } else if (packet_length < ETHERMIN) { 6725181Sgd78059 /* 6735181Sgd78059 * Note that VLAN packet would be even larger, 6745181Sgd78059 * but we don't worry about dropping runt VLAN 6755181Sgd78059 * frames. 6765181Sgd78059 * 6775181Sgd78059 * This check is probably redundant, as well, 6785181Sgd78059 * since the hardware should drop RUNT frames. 6795181Sgd78059 */ 680*9860Sgdamore@opensolaris.org DTRACE_PROBE1(rx__runt, int, packet_length); 6815181Sgd78059 goto skip; 6825181Sgd78059 } 6835181Sgd78059 6845181Sgd78059 /* 6855181Sgd78059 * Sync the data, so we can examine it; then check that 6865181Sgd78059 * the packet is really intended for us (remember that 6875181Sgd78059 * if we're using Imperfect Filtering, then the chip will 6885181Sgd78059 * receive unicast packets sent to stations whose addresses 6895181Sgd78059 * just happen to hash to the same value as our own; we 6905181Sgd78059 * discard these here so they don't get sent upstream ...) 6915181Sgd78059 */ 6925181Sgd78059 (void) ddi_dma_sync(dmfep->rx_buff.dma_hdl, 6935181Sgd78059 index * DMFE_BUF_SIZE, DMFE_BUF_SIZE, 6945181Sgd78059 DDI_DMA_SYNC_FORKERNEL); 6955181Sgd78059 rxb = &dmfep->rx_buff.mem_va[index*DMFE_BUF_SIZE]; 6965181Sgd78059 6975181Sgd78059 6985181Sgd78059 /* 6995181Sgd78059 * We do not bother to check that the packet is really for 7005181Sgd78059 * us, we let the MAC framework make that check instead. 7015181Sgd78059 * This is especially important if we ever want to support 7025181Sgd78059 * multiple MAC addresses. 7035181Sgd78059 */ 7045181Sgd78059 7055181Sgd78059 /* 7065181Sgd78059 * Packet looks good; get a buffer to copy it into. We 7075181Sgd78059 * allow some space at the front of the allocated buffer 7085181Sgd78059 * (HEADROOM) in case any upstream modules want to prepend 7095181Sgd78059 * some sort of header. The value has been carefully chosen 7105181Sgd78059 * So that it also has the side-effect of making the packet 7115181Sgd78059 * *contents* 4-byte aligned, as required by NCA! 7125181Sgd78059 */ 7135181Sgd78059 mp = allocb(DMFE_HEADROOM + packet_length, 0); 7145181Sgd78059 if (mp == NULL) { 715*9860Sgdamore@opensolaris.org DTRACE_PROBE(rx__no__buf); 7165181Sgd78059 dmfep->rx_stats_norcvbuf += 1; 7175181Sgd78059 goto skip; 7185181Sgd78059 } 7195181Sgd78059 7205181Sgd78059 /* 7215181Sgd78059 * Account for statistics of good packets. 7225181Sgd78059 */ 7235181Sgd78059 dmfep->rx_stats_ipackets += 1; 7245181Sgd78059 dmfep->rx_stats_rbytes += packet_length; 7255181Sgd78059 if (desc0 & RX_MULTI_FRAME) { 7265181Sgd78059 if (bcmp(rxb, dmfe_broadcast_addr, ETHERADDRL)) { 7275181Sgd78059 dmfep->rx_stats_multi += 1; 7285181Sgd78059 } else { 7295181Sgd78059 dmfep->rx_stats_bcast += 1; 7305181Sgd78059 } 7315181Sgd78059 } 7325181Sgd78059 7335181Sgd78059 /* 7345181Sgd78059 * Copy the packet into the STREAMS buffer 7355181Sgd78059 */ 7365181Sgd78059 dp = mp->b_rptr += DMFE_HEADROOM; 7375181Sgd78059 mp->b_cont = mp->b_next = NULL; 7385181Sgd78059 7395181Sgd78059 /* 7405181Sgd78059 * Don't worry about stripping the vlan tag, the MAC 7415181Sgd78059 * layer will take care of that for us. 7425181Sgd78059 */ 7435181Sgd78059 bcopy(rxb, dp, packet_length); 7445181Sgd78059 7455181Sgd78059 /* 7465181Sgd78059 * Fix up the packet length, and link it to the chain 7475181Sgd78059 */ 7485181Sgd78059 mp->b_wptr = mp->b_rptr + packet_length - ETHERFCSL; 7495181Sgd78059 *tail = mp; 7505181Sgd78059 tail = &mp->b_next; 7515181Sgd78059 7525181Sgd78059 skip: 7535181Sgd78059 /* 7545181Sgd78059 * Return ownership of ring entry & advance to next 7555181Sgd78059 */ 7565181Sgd78059 dmfe_ring_put32(descp, index, DESC0, RX_OWN); 7575181Sgd78059 index = NEXT(index, dmfep->rx.n_desc); 7585181Sgd78059 desc0 = dmfe_ring_get32(descp, index, DESC0); 7595181Sgd78059 } 7605181Sgd78059 7615181Sgd78059 /* 7625181Sgd78059 * Remember where to start looking next time ... 7635181Sgd78059 */ 7645181Sgd78059 dmfep->rx.next_free = index; 7655181Sgd78059 7665181Sgd78059 /* 7675181Sgd78059 * sync the receive descriptors that we've given back 7685181Sgd78059 * (actually, we sync all of them for simplicity), and 7695181Sgd78059 * wake the chip in case it had suspended receive 7705181Sgd78059 */ 7715181Sgd78059 DMA_SYNC(descp, DDI_DMA_SYNC_FORDEV); 7725181Sgd78059 dmfe_chip_put32(dmfep, RX_POLL_REG, 0); 7735181Sgd78059 7745181Sgd78059 mutex_exit(dmfep->rxlock); 7755181Sgd78059 return (head); 7765181Sgd78059 } 7775181Sgd78059 7785181Sgd78059 /* 7795181Sgd78059 * ========== Primary TX side routines ========== 7805181Sgd78059 */ 7815181Sgd78059 7825181Sgd78059 /* 7835181Sgd78059 * TX ring management: 7845181Sgd78059 * 7855181Sgd78059 * There are <tx.n_desc> entries in the ring, of which those from 7865181Sgd78059 * <tx.next_free> round to but not including <tx.next_busy> must 7875181Sgd78059 * be owned by the CPU. The number of such entries should equal 7885181Sgd78059 * <tx.n_free>; but there may also be some more entries which the 7895181Sgd78059 * chip has given back but which we haven't yet accounted for. 7905181Sgd78059 * The routine dmfe_reclaim_tx_desc() adjusts the indexes & counts 7915181Sgd78059 * as it discovers such entries. 7925181Sgd78059 * 7935181Sgd78059 * Initially, or when the ring is entirely free: 7945181Sgd78059 * C = Owned by CPU 7955181Sgd78059 * D = Owned by Davicom (DMFE) chip 7965181Sgd78059 * 7975181Sgd78059 * tx.next_free tx.n_desc = 16 7985181Sgd78059 * | 7995181Sgd78059 * v 8005181Sgd78059 * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 8015181Sgd78059 * | C | C | C | C | C | C | C | C | C | C | C | C | C | C | C | C | 8025181Sgd78059 * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 8035181Sgd78059 * ^ 8045181Sgd78059 * | 8055181Sgd78059 * tx.next_busy tx.n_free = 16 8065181Sgd78059 * 8075181Sgd78059 * On entry to reclaim() during normal use: 8085181Sgd78059 * 8095181Sgd78059 * tx.next_free tx.n_desc = 16 8105181Sgd78059 * | 8115181Sgd78059 * v 8125181Sgd78059 * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 8135181Sgd78059 * | C | C | C | C | C | C | D | D | D | C | C | C | C | C | C | C | 8145181Sgd78059 * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 8155181Sgd78059 * ^ 8165181Sgd78059 * | 8175181Sgd78059 * tx.next_busy tx.n_free = 9 8185181Sgd78059 * 8195181Sgd78059 * On exit from reclaim(): 8205181Sgd78059 * 8215181Sgd78059 * tx.next_free tx.n_desc = 16 8225181Sgd78059 * | 8235181Sgd78059 * v 8245181Sgd78059 * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 8255181Sgd78059 * | C | C | C | C | C | C | D | D | D | C | C | C | C | C | C | C | 8265181Sgd78059 * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 8275181Sgd78059 * ^ 8285181Sgd78059 * | 8295181Sgd78059 * tx.next_busy tx.n_free = 13 8305181Sgd78059 * 8315181Sgd78059 * The ring is considered "full" when only one entry is owned by 8325181Sgd78059 * the CPU; thus <tx.n_free> should always be >= 1. 8335181Sgd78059 * 8345181Sgd78059 * tx.next_free tx.n_desc = 16 8355181Sgd78059 * | 8365181Sgd78059 * v 8375181Sgd78059 * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 8385181Sgd78059 * | D | D | D | D | D | C | D | D | D | D | D | D | D | D | D | D | 8395181Sgd78059 * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 8405181Sgd78059 * ^ 8415181Sgd78059 * | 8425181Sgd78059 * tx.next_busy tx.n_free = 1 8435181Sgd78059 */ 8445181Sgd78059 8455181Sgd78059 /* 8465181Sgd78059 * Function to update transmit statistics on various errors 8475181Sgd78059 */ 8485181Sgd78059 static void 8495181Sgd78059 dmfe_update_tx_stats(dmfe_t *dmfep, int index, uint32_t desc0, uint32_t desc1) 8505181Sgd78059 { 8515181Sgd78059 uint32_t collisions; 8525181Sgd78059 uint32_t errbits; 8535181Sgd78059 uint32_t errsum; 8545181Sgd78059 8555181Sgd78059 ASSERT(mutex_owned(dmfep->txlock)); 8565181Sgd78059 8575181Sgd78059 collisions = ((desc0 >> 3) & 0x0f); 8585181Sgd78059 errsum = desc0 & TX_ERR_SUMMARY; 8595181Sgd78059 errbits = desc0 & (TX_UNDERFLOW | TX_LATE_COLL | TX_CARRIER_LOSS | 8605181Sgd78059 TX_NO_CARRIER | TX_EXCESS_COLL | TX_JABBER_TO); 8615181Sgd78059 if ((errsum == 0) != (errbits == 0)) { 8625181Sgd78059 dmfe_log(dmfep, "dubious TX error status 0x%x", desc0); 8635181Sgd78059 desc0 |= TX_ERR_SUMMARY; 8645181Sgd78059 } 8655181Sgd78059 8665181Sgd78059 if (desc0 & TX_ERR_SUMMARY) { 8675181Sgd78059 dmfep->tx_stats_oerrors += 1; 8685181Sgd78059 8695181Sgd78059 /* 8705181Sgd78059 * If we ever see a transmit jabber timeout, we count it 8715181Sgd78059 * as a MAC-level transmit error; but we probably won't 8725181Sgd78059 * see it as it causes an Abnormal interrupt and we reset 8735181Sgd78059 * the chip in order to recover 8745181Sgd78059 */ 8755181Sgd78059 if (desc0 & TX_JABBER_TO) { 8765181Sgd78059 dmfep->tx_stats_macxmt_errors += 1; 8775181Sgd78059 dmfep->tx_stats_jabber += 1; 8785181Sgd78059 } 8795181Sgd78059 8805181Sgd78059 if (desc0 & TX_UNDERFLOW) 8815181Sgd78059 dmfep->tx_stats_underflow += 1; 8825181Sgd78059 else if (desc0 & TX_LATE_COLL) 8835181Sgd78059 dmfep->tx_stats_xmtlatecoll += 1; 8845181Sgd78059 8855181Sgd78059 if (desc0 & (TX_CARRIER_LOSS | TX_NO_CARRIER)) 8865181Sgd78059 dmfep->tx_stats_nocarrier += 1; 8875181Sgd78059 8885181Sgd78059 if (desc0 & TX_EXCESS_COLL) { 8895181Sgd78059 dmfep->tx_stats_excoll += 1; 8905181Sgd78059 collisions = 16; 8915181Sgd78059 } 8925181Sgd78059 } else { 8935181Sgd78059 int bit = index % NBBY; 8945181Sgd78059 int byt = index / NBBY; 8955181Sgd78059 8965181Sgd78059 if (dmfep->tx_mcast[byt] & bit) { 8975181Sgd78059 dmfep->tx_mcast[byt] &= ~bit; 8985181Sgd78059 dmfep->tx_stats_multi += 1; 8995181Sgd78059 9005181Sgd78059 } else if (dmfep->tx_bcast[byt] & bit) { 9015181Sgd78059 dmfep->tx_bcast[byt] &= ~bit; 9025181Sgd78059 dmfep->tx_stats_bcast += 1; 9035181Sgd78059 } 9045181Sgd78059 9055181Sgd78059 dmfep->tx_stats_opackets += 1; 9065181Sgd78059 dmfep->tx_stats_obytes += desc1 & TX_BUFFER_SIZE1; 9075181Sgd78059 } 9085181Sgd78059 9095181Sgd78059 if (collisions == 1) 9105181Sgd78059 dmfep->tx_stats_first_coll += 1; 9115181Sgd78059 else if (collisions != 0) 9125181Sgd78059 dmfep->tx_stats_multi_coll += 1; 9135181Sgd78059 dmfep->tx_stats_collisions += collisions; 9145181Sgd78059 9155181Sgd78059 if (desc0 & TX_DEFERRED) 9165181Sgd78059 dmfep->tx_stats_defer += 1; 9175181Sgd78059 } 9185181Sgd78059 9195181Sgd78059 /* 9205181Sgd78059 * Reclaim all the ring entries that the chip has returned to us ... 9215181Sgd78059 * 9225181Sgd78059 * Returns B_FALSE if no entries could be reclaimed. Otherwise, reclaims 9235181Sgd78059 * as many as possible, restarts the TX stall timeout, and returns B_TRUE. 9245181Sgd78059 */ 9255181Sgd78059 static boolean_t 9265181Sgd78059 dmfe_reclaim_tx_desc(dmfe_t *dmfep) 9275181Sgd78059 { 9285181Sgd78059 dma_area_t *descp; 9295181Sgd78059 uint32_t desc0; 9305181Sgd78059 uint32_t desc1; 9315181Sgd78059 int i; 9325181Sgd78059 9335181Sgd78059 ASSERT(mutex_owned(dmfep->txlock)); 9345181Sgd78059 9355181Sgd78059 /* 9365181Sgd78059 * sync transmit descriptor ring before looking at it 9375181Sgd78059 */ 9385181Sgd78059 descp = &dmfep->tx_desc; 9395181Sgd78059 DMA_SYNC(descp, DDI_DMA_SYNC_FORKERNEL); 9405181Sgd78059 9415181Sgd78059 /* 9425181Sgd78059 * Early exit if there are no descriptors to reclaim, either 9435181Sgd78059 * because they're all reclaimed already, or because the next 9445181Sgd78059 * one is still owned by the chip ... 9455181Sgd78059 */ 9465181Sgd78059 i = dmfep->tx.next_busy; 9475181Sgd78059 if (i == dmfep->tx.next_free) 9485181Sgd78059 return (B_FALSE); 9495181Sgd78059 desc0 = dmfe_ring_get32(descp, i, DESC0); 9505181Sgd78059 if (desc0 & TX_OWN) 9515181Sgd78059 return (B_FALSE); 9525181Sgd78059 9535181Sgd78059 /* 9545181Sgd78059 * Reclaim as many descriptors as possible ... 9555181Sgd78059 */ 9565181Sgd78059 for (;;) { 9575181Sgd78059 desc1 = dmfe_ring_get32(descp, i, DESC1); 9585181Sgd78059 ASSERT((desc1 & (TX_SETUP_PACKET | TX_LAST_DESC)) != 0); 9595181Sgd78059 960*9860Sgdamore@opensolaris.org if ((desc1 & TX_SETUP_PACKET) == 0) { 9615181Sgd78059 /* 9625181Sgd78059 * Regular packet - just update stats 9635181Sgd78059 */ 9645181Sgd78059 dmfe_update_tx_stats(dmfep, i, desc0, desc1); 9655181Sgd78059 } 9665181Sgd78059 9675181Sgd78059 /* 9685181Sgd78059 * Update count & index; we're all done if the ring is 9695181Sgd78059 * now fully reclaimed, or the next entry if still owned 9705181Sgd78059 * by the chip ... 9715181Sgd78059 */ 9725181Sgd78059 dmfep->tx.n_free += 1; 9735181Sgd78059 i = NEXT(i, dmfep->tx.n_desc); 9745181Sgd78059 if (i == dmfep->tx.next_free) 9755181Sgd78059 break; 9765181Sgd78059 desc0 = dmfe_ring_get32(descp, i, DESC0); 9775181Sgd78059 if (desc0 & TX_OWN) 9785181Sgd78059 break; 9795181Sgd78059 } 9805181Sgd78059 9815181Sgd78059 dmfep->tx.next_busy = i; 9825181Sgd78059 dmfep->tx_pending_tix = 0; 9835181Sgd78059 return (B_TRUE); 9845181Sgd78059 } 9855181Sgd78059 9865181Sgd78059 /* 9875181Sgd78059 * Send the message in the message block chain <mp>. 9885181Sgd78059 * 9895181Sgd78059 * The message is freed if and only if its contents are successfully copied 9905181Sgd78059 * and queued for transmission (so that the return value is B_TRUE). 9915181Sgd78059 * If we can't queue the message, the return value is B_FALSE and 9925181Sgd78059 * the message is *not* freed. 9935181Sgd78059 * 9945181Sgd78059 * This routine handles the special case of <mp> == NULL, which indicates 9955181Sgd78059 * that we want to "send" the special "setup packet" allocated during 9965181Sgd78059 * startup. We have to use some different flags in the packet descriptor 9975181Sgd78059 * to say its a setup packet (from the global <dmfe_setup_desc1>), and the 9985181Sgd78059 * setup packet *isn't* freed after use. 9995181Sgd78059 */ 10005181Sgd78059 static boolean_t 10015181Sgd78059 dmfe_send_msg(dmfe_t *dmfep, mblk_t *mp) 10025181Sgd78059 { 10035181Sgd78059 dma_area_t *descp; 10045181Sgd78059 mblk_t *bp; 10055181Sgd78059 char *txb; 10065181Sgd78059 uint32_t desc1; 10075181Sgd78059 uint32_t index; 10085181Sgd78059 size_t totlen; 10095181Sgd78059 size_t mblen; 1010*9860Sgdamore@opensolaris.org uint32_t paddr; 10115181Sgd78059 10125181Sgd78059 /* 10135181Sgd78059 * If the number of free slots is below the reclaim threshold 10145181Sgd78059 * (soft limit), we'll try to reclaim some. If we fail, and 10155181Sgd78059 * the number of free slots is also below the minimum required 10165181Sgd78059 * (the hard limit, usually 1), then we can't send the packet. 10175181Sgd78059 */ 10185181Sgd78059 mutex_enter(dmfep->txlock); 1019*9860Sgdamore@opensolaris.org if (dmfep->suspended) 1020*9860Sgdamore@opensolaris.org return (B_FALSE); 1021*9860Sgdamore@opensolaris.org 10225181Sgd78059 if (dmfep->tx.n_free <= dmfe_tx_reclaim_level && 10235181Sgd78059 dmfe_reclaim_tx_desc(dmfep) == B_FALSE && 10245181Sgd78059 dmfep->tx.n_free <= dmfe_tx_min_free) { 10255181Sgd78059 /* 10265181Sgd78059 * Resource shortage - return B_FALSE so the packet 10275181Sgd78059 * will be queued for retry after the next TX-done 10285181Sgd78059 * interrupt. 10295181Sgd78059 */ 10305181Sgd78059 mutex_exit(dmfep->txlock); 1031*9860Sgdamore@opensolaris.org DTRACE_PROBE(tx__no__desc); 10325181Sgd78059 return (B_FALSE); 10335181Sgd78059 } 10345181Sgd78059 10355181Sgd78059 /* 10365181Sgd78059 * There's a slot available, so claim it by incrementing 10375181Sgd78059 * the next-free index and decrementing the free count. 10385181Sgd78059 * If the ring is currently empty, we also restart the 10395181Sgd78059 * stall-detect timer. The ASSERTions check that our 10405181Sgd78059 * invariants still hold: 10415181Sgd78059 * the next-free index must not match the next-busy index 10425181Sgd78059 * there must still be at least one free entry 10435181Sgd78059 * After this, we now have exclusive ownership of the ring 10445181Sgd78059 * entry (and matching buffer) indicated by <index>, so we 10455181Sgd78059 * don't need to hold the TX lock any longer 10465181Sgd78059 */ 10475181Sgd78059 index = dmfep->tx.next_free; 10485181Sgd78059 dmfep->tx.next_free = NEXT(index, dmfep->tx.n_desc); 10495181Sgd78059 ASSERT(dmfep->tx.next_free != dmfep->tx.next_busy); 10505181Sgd78059 if (dmfep->tx.n_free-- == dmfep->tx.n_desc) 10515181Sgd78059 dmfep->tx_pending_tix = 0; 10525181Sgd78059 ASSERT(dmfep->tx.n_free >= 1); 10535181Sgd78059 mutex_exit(dmfep->txlock); 10545181Sgd78059 10555181Sgd78059 /* 10565181Sgd78059 * Check the ownership of the ring entry ... 10575181Sgd78059 */ 10585181Sgd78059 descp = &dmfep->tx_desc; 10595181Sgd78059 ASSERT((dmfe_ring_get32(descp, index, DESC0) & TX_OWN) == 0); 10605181Sgd78059 10615181Sgd78059 if (mp == NULL) { 10625181Sgd78059 /* 10635181Sgd78059 * Indicates we should send a SETUP packet, which we do by 10645181Sgd78059 * temporarily switching the BUFFER1 pointer in the ring 10655181Sgd78059 * entry. The reclaim routine will restore BUFFER1 to its 10665181Sgd78059 * usual value. 10675181Sgd78059 * 10685181Sgd78059 * Note that as the setup packet is tagged on the end of 10695181Sgd78059 * the TX ring, when we sync the descriptor we're also 10705181Sgd78059 * implicitly syncing the setup packet - hence, we don't 10715181Sgd78059 * need a separate ddi_dma_sync() call here. 10725181Sgd78059 */ 10735181Sgd78059 desc1 = dmfe_setup_desc1; 1074*9860Sgdamore@opensolaris.org paddr = descp->setup_dvma; 10755181Sgd78059 } else { 10765181Sgd78059 /* 10775181Sgd78059 * A regular packet; we copy the data into a pre-mapped 10785181Sgd78059 * buffer, which avoids the overhead (and complication) 10795181Sgd78059 * of mapping/unmapping STREAMS buffers and keeping hold 10805181Sgd78059 * of them until the DMA has completed. 10815181Sgd78059 * 10825181Sgd78059 * Because all buffers are the same size, and larger 10835181Sgd78059 * than the longest single valid message, we don't have 10845181Sgd78059 * to bother about splitting the message across multiple 10855181Sgd78059 * buffers. 10865181Sgd78059 */ 10875181Sgd78059 txb = &dmfep->tx_buff.mem_va[index*DMFE_BUF_SIZE]; 10885181Sgd78059 totlen = 0; 10895181Sgd78059 bp = mp; 10905181Sgd78059 10915181Sgd78059 /* 10925181Sgd78059 * Copy all (remaining) mblks in the message ... 10935181Sgd78059 */ 10945181Sgd78059 for (; bp != NULL; bp = bp->b_cont) { 10956990Sgd78059 mblen = MBLKL(bp); 10965181Sgd78059 if ((totlen += mblen) <= DMFE_MAX_PKT_SIZE) { 10975181Sgd78059 bcopy(bp->b_rptr, txb, mblen); 10985181Sgd78059 txb += mblen; 10995181Sgd78059 } 11005181Sgd78059 } 11015181Sgd78059 11025181Sgd78059 /* 11035181Sgd78059 * Is this a multicast or broadcast packet? We do 11045181Sgd78059 * this so that we can track statistics accurately 11055181Sgd78059 * when we reclaim it. 11065181Sgd78059 */ 11075181Sgd78059 txb = &dmfep->tx_buff.mem_va[index*DMFE_BUF_SIZE]; 11085181Sgd78059 if (txb[0] & 0x1) { 11095181Sgd78059 if (bcmp(txb, dmfe_broadcast_addr, ETHERADDRL) == 0) { 11105181Sgd78059 dmfep->tx_bcast[index / NBBY] |= 11115181Sgd78059 (1 << (index % NBBY)); 11125181Sgd78059 } else { 11135181Sgd78059 dmfep->tx_mcast[index / NBBY] |= 11145181Sgd78059 (1 << (index % NBBY)); 11155181Sgd78059 } 11165181Sgd78059 } 11175181Sgd78059 11185181Sgd78059 /* 11195181Sgd78059 * We'e reached the end of the chain; and we should have 11205181Sgd78059 * collected no more than DMFE_MAX_PKT_SIZE bytes into our 11215181Sgd78059 * buffer. Note that the <size> field in the descriptor is 11225181Sgd78059 * only 11 bits, so bigger packets would be a problem! 11235181Sgd78059 */ 11245181Sgd78059 ASSERT(bp == NULL); 11255181Sgd78059 ASSERT(totlen <= DMFE_MAX_PKT_SIZE); 11265181Sgd78059 totlen &= TX_BUFFER_SIZE1; 11275181Sgd78059 desc1 = TX_FIRST_DESC | TX_LAST_DESC | totlen; 1128*9860Sgdamore@opensolaris.org paddr = dmfep->tx_buff.mem_dvma + index*DMFE_BUF_SIZE; 11295181Sgd78059 11305181Sgd78059 (void) ddi_dma_sync(dmfep->tx_buff.dma_hdl, 11315181Sgd78059 index * DMFE_BUF_SIZE, DMFE_BUF_SIZE, DDI_DMA_SYNC_FORDEV); 11325181Sgd78059 } 11335181Sgd78059 11345181Sgd78059 /* 11355181Sgd78059 * Update ring descriptor entries, sync them, and wake up the 11365181Sgd78059 * transmit process 11375181Sgd78059 */ 11385181Sgd78059 if ((index & dmfe_tx_int_factor) == 0) 11395181Sgd78059 desc1 |= TX_INT_ON_COMP; 11405181Sgd78059 desc1 |= TX_CHAINING; 1141*9860Sgdamore@opensolaris.org dmfe_ring_put32(descp, index, BUFFER1, paddr); 11425181Sgd78059 dmfe_ring_put32(descp, index, DESC1, desc1); 11435181Sgd78059 dmfe_ring_put32(descp, index, DESC0, TX_OWN); 11445181Sgd78059 DMA_SYNC(descp, DDI_DMA_SYNC_FORDEV); 11455181Sgd78059 dmfe_chip_put32(dmfep, TX_POLL_REG, 0); 11465181Sgd78059 11475181Sgd78059 /* 11485181Sgd78059 * Finally, free the message & return success 11495181Sgd78059 */ 11505181Sgd78059 if (mp) 11515181Sgd78059 freemsg(mp); 11525181Sgd78059 return (B_TRUE); 11535181Sgd78059 } 11545181Sgd78059 11555181Sgd78059 /* 11565181Sgd78059 * dmfe_m_tx() -- send a chain of packets 11575181Sgd78059 * 11585181Sgd78059 * Called when packet(s) are ready to be transmitted. A pointer to an 11595181Sgd78059 * M_DATA message that contains the packet is passed to this routine. 11605181Sgd78059 * The complete LLC header is contained in the message's first message 11615181Sgd78059 * block, and the remainder of the packet is contained within 11625181Sgd78059 * additional M_DATA message blocks linked to the first message block. 11635181Sgd78059 * 11645181Sgd78059 * Additional messages may be passed by linking with b_next. 11655181Sgd78059 */ 11665181Sgd78059 static mblk_t * 11675181Sgd78059 dmfe_m_tx(void *arg, mblk_t *mp) 11685181Sgd78059 { 11695181Sgd78059 dmfe_t *dmfep = arg; /* private device info */ 11705181Sgd78059 mblk_t *next; 11715181Sgd78059 11725181Sgd78059 ASSERT(mp != NULL); 11735181Sgd78059 ASSERT(dmfep->mac_state == DMFE_MAC_STARTED); 11745181Sgd78059 11755181Sgd78059 if (dmfep->chip_state != CHIP_RUNNING) 11765181Sgd78059 return (mp); 11775181Sgd78059 11785181Sgd78059 while (mp != NULL) { 11795181Sgd78059 next = mp->b_next; 11805181Sgd78059 mp->b_next = NULL; 11815181Sgd78059 if (!dmfe_send_msg(dmfep, mp)) { 11825181Sgd78059 mp->b_next = next; 11835181Sgd78059 break; 11845181Sgd78059 } 11855181Sgd78059 mp = next; 11865181Sgd78059 } 11875181Sgd78059 11885181Sgd78059 return (mp); 11895181Sgd78059 } 11905181Sgd78059 11915181Sgd78059 /* 11925181Sgd78059 * ========== Address-setting routines (TX-side) ========== 11935181Sgd78059 */ 11945181Sgd78059 11955181Sgd78059 /* 11965181Sgd78059 * Find the index of the relevant bit in the setup packet. 11975181Sgd78059 * This must mirror the way the hardware will actually calculate it! 11985181Sgd78059 */ 11995181Sgd78059 static uint32_t 12005181Sgd78059 dmfe_hash_index(const uint8_t *address) 12015181Sgd78059 { 12025181Sgd78059 uint32_t const POLY = HASH_POLY; 12035181Sgd78059 uint32_t crc = HASH_CRC; 12045181Sgd78059 uint32_t index; 12055181Sgd78059 uint32_t msb; 12065181Sgd78059 uchar_t currentbyte; 12075181Sgd78059 int byteslength; 12085181Sgd78059 int shift; 12095181Sgd78059 int bit; 12105181Sgd78059 12115181Sgd78059 for (byteslength = 0; byteslength < ETHERADDRL; ++byteslength) { 12125181Sgd78059 currentbyte = address[byteslength]; 12135181Sgd78059 for (bit = 0; bit < 8; ++bit) { 12145181Sgd78059 msb = crc >> 31; 12155181Sgd78059 crc <<= 1; 12165181Sgd78059 if (msb ^ (currentbyte & 1)) { 12175181Sgd78059 crc ^= POLY; 12185181Sgd78059 crc |= 0x00000001; 12195181Sgd78059 } 12205181Sgd78059 currentbyte >>= 1; 12215181Sgd78059 } 12225181Sgd78059 } 12235181Sgd78059 12245181Sgd78059 for (index = 0, bit = 23, shift = 8; shift >= 0; ++bit, --shift) 12255181Sgd78059 index |= (((crc >> bit) & 1) << shift); 12265181Sgd78059 12275181Sgd78059 return (index); 12285181Sgd78059 } 12295181Sgd78059 12305181Sgd78059 /* 12315181Sgd78059 * Find and set/clear the relevant bit in the setup packet hash table 12325181Sgd78059 * This must mirror the way the hardware will actually interpret it! 12335181Sgd78059 */ 12345181Sgd78059 static void 12355181Sgd78059 dmfe_update_hash(dmfe_t *dmfep, uint32_t index, boolean_t val) 12365181Sgd78059 { 12375181Sgd78059 dma_area_t *descp; 12385181Sgd78059 uint32_t tmp; 12395181Sgd78059 12405181Sgd78059 ASSERT(mutex_owned(dmfep->oplock)); 12415181Sgd78059 12425181Sgd78059 descp = &dmfep->tx_desc; 12435181Sgd78059 tmp = dmfe_setup_get32(descp, index/16); 12445181Sgd78059 if (val) 12455181Sgd78059 tmp |= 1 << (index%16); 12465181Sgd78059 else 12475181Sgd78059 tmp &= ~(1 << (index%16)); 12485181Sgd78059 dmfe_setup_put32(descp, index/16, tmp); 12495181Sgd78059 } 12505181Sgd78059 12515181Sgd78059 /* 12525181Sgd78059 * Update the refcount for the bit in the setup packet corresponding 12535181Sgd78059 * to the specified address; if it changes between zero & nonzero, 12545181Sgd78059 * also update the bitmap itself & return B_TRUE, so that the caller 12555181Sgd78059 * knows to re-send the setup packet. Otherwise (only the refcount 12565181Sgd78059 * changed), return B_FALSE 12575181Sgd78059 */ 12585181Sgd78059 static boolean_t 12595181Sgd78059 dmfe_update_mcast(dmfe_t *dmfep, const uint8_t *mca, boolean_t val) 12605181Sgd78059 { 12615181Sgd78059 uint32_t index; 12625181Sgd78059 uint8_t *refp; 12635181Sgd78059 boolean_t change; 12645181Sgd78059 12655181Sgd78059 index = dmfe_hash_index(mca); 12665181Sgd78059 refp = &dmfep->mcast_refs[index]; 12675181Sgd78059 change = (val ? (*refp)++ : --(*refp)) == 0; 12685181Sgd78059 12695181Sgd78059 if (change) 12705181Sgd78059 dmfe_update_hash(dmfep, index, val); 12715181Sgd78059 12725181Sgd78059 return (change); 12735181Sgd78059 } 12745181Sgd78059 12755181Sgd78059 /* 12765181Sgd78059 * "Transmit" the (possibly updated) magic setup packet 12775181Sgd78059 */ 12785181Sgd78059 static int 12795181Sgd78059 dmfe_send_setup(dmfe_t *dmfep) 12805181Sgd78059 { 12815181Sgd78059 int status; 12825181Sgd78059 12835181Sgd78059 ASSERT(mutex_owned(dmfep->oplock)); 12845181Sgd78059 1285*9860Sgdamore@opensolaris.org if (dmfep->suspended) 1286*9860Sgdamore@opensolaris.org return (0); 1287*9860Sgdamore@opensolaris.org 12885181Sgd78059 /* 12895181Sgd78059 * If the chip isn't running, we can't really send the setup frame 12905181Sgd78059 * now but it doesn't matter, 'cos it will be sent when the transmit 12915181Sgd78059 * process is restarted (see dmfe_start()). 12925181Sgd78059 */ 12935181Sgd78059 if ((dmfep->opmode & START_TRANSMIT) == 0) 12945181Sgd78059 return (0); 12955181Sgd78059 12965181Sgd78059 /* 12975181Sgd78059 * "Send" the setup frame. If it fails (e.g. no resources), 12985181Sgd78059 * set a flag; then the factotum will retry the "send". Once 12995181Sgd78059 * it works, we can clear the flag no matter how many attempts 13005181Sgd78059 * had previously failed. We tell the caller that it worked 13015181Sgd78059 * whether it did or not; after all, it *will* work eventually. 13025181Sgd78059 */ 13035181Sgd78059 status = dmfe_send_msg(dmfep, NULL); 13045181Sgd78059 dmfep->need_setup = status ? B_FALSE : B_TRUE; 13055181Sgd78059 return (0); 13065181Sgd78059 } 13075181Sgd78059 13085181Sgd78059 /* 13095181Sgd78059 * dmfe_m_unicst() -- set the physical network address 13105181Sgd78059 */ 13115181Sgd78059 static int 13125181Sgd78059 dmfe_m_unicst(void *arg, const uint8_t *macaddr) 13135181Sgd78059 { 13145181Sgd78059 dmfe_t *dmfep = arg; 13155181Sgd78059 int status; 13165181Sgd78059 int index; 13175181Sgd78059 13185181Sgd78059 /* 13195181Sgd78059 * Update our current address and send out a new setup packet 13205181Sgd78059 * 13215181Sgd78059 * Here we accommodate the use of HASH_ONLY or HASH_AND_PERFECT 13225181Sgd78059 * filtering modes (we don't support PERFECT_ONLY or INVERSE modes). 13235181Sgd78059 * 13245181Sgd78059 * It is said that there is a bug in the 21140 where it fails to 13255181Sgd78059 * receive packes addresses to the specified perfect filter address. 13265181Sgd78059 * If the same bug is present in the DM9102A, the TX_FILTER_TYPE1 13275181Sgd78059 * bit should be set in the module variable dmfe_setup_desc1. 13285181Sgd78059 * 13295181Sgd78059 * If TX_FILTER_TYPE1 is set, we will use HASH_ONLY filtering. 13305181Sgd78059 * In this mode, *all* incoming addresses are hashed and looked 13315181Sgd78059 * up in the bitmap described by the setup packet. Therefore, 13325181Sgd78059 * the bit representing the station address has to be added to 13335181Sgd78059 * the table before sending it out. If the address is changed, 13345181Sgd78059 * the old entry should be removed before the new entry is made. 13355181Sgd78059 * 13365181Sgd78059 * NOTE: in this mode, unicast packets that are not intended for 13375181Sgd78059 * this station may be received; it is up to software to filter 13385181Sgd78059 * them out afterwards! 13395181Sgd78059 * 13405181Sgd78059 * If TX_FILTER_TYPE1 is *not* set, we will use HASH_AND_PERFECT 13415181Sgd78059 * filtering. In this mode, multicast addresses are hashed and 13425181Sgd78059 * checked against the bitmap, while unicast addresses are simply 13435181Sgd78059 * matched against the one physical address specified in the setup 13445181Sgd78059 * packet. This means that we shouldn't receive unicast packets 13455181Sgd78059 * that aren't intended for us (but software still has to filter 13465181Sgd78059 * multicast packets just the same). 13475181Sgd78059 * 13485181Sgd78059 * Whichever mode we're using, we have to enter the broadcast 13495181Sgd78059 * address into the multicast filter map too, so we do this on 13505181Sgd78059 * the first time through after attach or reset. 13515181Sgd78059 */ 13525181Sgd78059 mutex_enter(dmfep->oplock); 13535181Sgd78059 13545181Sgd78059 if (dmfep->addr_set && dmfe_setup_desc1 & TX_FILTER_TYPE1) 13555181Sgd78059 (void) dmfe_update_mcast(dmfep, dmfep->curr_addr, B_FALSE); 13565181Sgd78059 if (dmfe_setup_desc1 & TX_FILTER_TYPE1) 13575181Sgd78059 (void) dmfe_update_mcast(dmfep, macaddr, B_TRUE); 13585181Sgd78059 if (!dmfep->addr_set) 13595181Sgd78059 (void) dmfe_update_mcast(dmfep, dmfe_broadcast_addr, B_TRUE); 13605181Sgd78059 13615181Sgd78059 /* 13625181Sgd78059 * Remember the new current address 13635181Sgd78059 */ 13645181Sgd78059 ethaddr_copy(macaddr, dmfep->curr_addr); 13655181Sgd78059 dmfep->addr_set = B_TRUE; 13665181Sgd78059 13675181Sgd78059 /* 13685181Sgd78059 * Install the new physical address into the proper position in 13695181Sgd78059 * the setup frame; this is only used if we select hash+perfect 13705181Sgd78059 * filtering, but we'll put it in anyway. The ugliness here is 13715181Sgd78059 * down to the usual war of the egg :( 13725181Sgd78059 */ 13735181Sgd78059 for (index = 0; index < ETHERADDRL; index += 2) 13745181Sgd78059 dmfe_setup_put32(&dmfep->tx_desc, SETUPBUF_PHYS+index/2, 13755181Sgd78059 (macaddr[index+1] << 8) | macaddr[index]); 13765181Sgd78059 13775181Sgd78059 /* 13785181Sgd78059 * Finally, we're ready to "transmit" the setup frame 13795181Sgd78059 */ 13805181Sgd78059 status = dmfe_send_setup(dmfep); 13815181Sgd78059 mutex_exit(dmfep->oplock); 13825181Sgd78059 13835181Sgd78059 return (status); 13845181Sgd78059 } 13855181Sgd78059 13865181Sgd78059 /* 13875181Sgd78059 * dmfe_m_multicst() -- enable or disable a multicast address 13885181Sgd78059 * 13895181Sgd78059 * Program the hardware to enable/disable the multicast address 13905181Sgd78059 * in "mca" (enable if add is true, otherwise disable it.) 13915181Sgd78059 * We keep a refcount for each bit in the map, so that it still 13925181Sgd78059 * works out properly if multiple addresses hash to the same bit. 13935181Sgd78059 * dmfe_update_mcast() tells us whether the map actually changed; 13945181Sgd78059 * if so, we have to re-"transmit" the magic setup packet. 13955181Sgd78059 */ 13965181Sgd78059 static int 13975181Sgd78059 dmfe_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 13985181Sgd78059 { 13995181Sgd78059 dmfe_t *dmfep = arg; /* private device info */ 14005181Sgd78059 int status = 0; 14015181Sgd78059 14025181Sgd78059 mutex_enter(dmfep->oplock); 14035181Sgd78059 if (dmfe_update_mcast(dmfep, mca, add)) 14045181Sgd78059 status = dmfe_send_setup(dmfep); 14055181Sgd78059 mutex_exit(dmfep->oplock); 14065181Sgd78059 14075181Sgd78059 return (status); 14085181Sgd78059 } 14095181Sgd78059 14105181Sgd78059 14115181Sgd78059 /* 14125181Sgd78059 * ========== Internal state management entry points ========== 14135181Sgd78059 */ 14145181Sgd78059 14155181Sgd78059 /* 14165181Sgd78059 * These routines provide all the functionality required by the 14175181Sgd78059 * corresponding MAC layer entry points, but don't update the MAC layer state 14185181Sgd78059 * so they can be called internally without disturbing our record 14195181Sgd78059 * of what MAC layer thinks we should be doing ... 14205181Sgd78059 */ 14215181Sgd78059 14225181Sgd78059 /* 14235181Sgd78059 * dmfe_stop() -- stop processing, don't reset h/w or rings 14245181Sgd78059 */ 14255181Sgd78059 static void 14265181Sgd78059 dmfe_stop(dmfe_t *dmfep) 14275181Sgd78059 { 14285181Sgd78059 ASSERT(mutex_owned(dmfep->oplock)); 14295181Sgd78059 14305181Sgd78059 dmfe_stop_chip(dmfep, CHIP_STOPPED); 14315181Sgd78059 } 14325181Sgd78059 14335181Sgd78059 /* 14345181Sgd78059 * dmfe_reset() -- stop processing, reset h/w & rings to initial state 14355181Sgd78059 */ 14365181Sgd78059 static void 14375181Sgd78059 dmfe_reset(dmfe_t *dmfep) 14385181Sgd78059 { 14395181Sgd78059 ASSERT(mutex_owned(dmfep->oplock)); 14405181Sgd78059 ASSERT(mutex_owned(dmfep->rxlock)); 14415181Sgd78059 ASSERT(mutex_owned(dmfep->txlock)); 14425181Sgd78059 14435181Sgd78059 dmfe_stop_chip(dmfep, CHIP_RESET); 14445181Sgd78059 dmfe_init_rings(dmfep); 14455181Sgd78059 } 14465181Sgd78059 14475181Sgd78059 /* 14485181Sgd78059 * dmfe_start() -- start transmitting/receiving 14495181Sgd78059 */ 14505181Sgd78059 static void 14515181Sgd78059 dmfe_start(dmfe_t *dmfep) 14525181Sgd78059 { 14535181Sgd78059 uint32_t gpsr; 14545181Sgd78059 14555181Sgd78059 ASSERT(mutex_owned(dmfep->oplock)); 14565181Sgd78059 14575181Sgd78059 ASSERT(dmfep->chip_state == CHIP_RESET || 14585181Sgd78059 dmfep->chip_state == CHIP_STOPPED); 14595181Sgd78059 14605181Sgd78059 /* 14615181Sgd78059 * Make opmode consistent with PHY duplex setting 14625181Sgd78059 */ 14635181Sgd78059 gpsr = dmfe_chip_get32(dmfep, PHY_STATUS_REG); 14645181Sgd78059 if (gpsr & GPS_FULL_DUPLEX) 14655181Sgd78059 dmfep->opmode |= FULL_DUPLEX; 14665181Sgd78059 else 14675181Sgd78059 dmfep->opmode &= ~FULL_DUPLEX; 14685181Sgd78059 14695181Sgd78059 /* 14705181Sgd78059 * Start transmit processing 14715181Sgd78059 * Set up the address filters 14725181Sgd78059 * Start receive processing 14735181Sgd78059 * Enable interrupts 14745181Sgd78059 */ 14755181Sgd78059 dmfe_start_chip(dmfep, START_TRANSMIT); 14765181Sgd78059 (void) dmfe_send_setup(dmfep); 14775181Sgd78059 drv_usecwait(10); 14785181Sgd78059 dmfe_start_chip(dmfep, START_RECEIVE); 14795181Sgd78059 dmfe_enable_interrupts(dmfep); 14805181Sgd78059 } 14815181Sgd78059 14825181Sgd78059 /* 14835181Sgd78059 * dmfe_restart - restart transmitting/receiving after error or suspend 14845181Sgd78059 */ 14855181Sgd78059 static void 14865181Sgd78059 dmfe_restart(dmfe_t *dmfep) 14875181Sgd78059 { 14885181Sgd78059 ASSERT(mutex_owned(dmfep->oplock)); 14895181Sgd78059 14905181Sgd78059 /* 14915181Sgd78059 * You need not only <oplock>, but also <rxlock> AND <txlock> 14925181Sgd78059 * in order to reset the rings, but then <txlock> *mustn't* 14935181Sgd78059 * be held across the call to dmfe_start() 14945181Sgd78059 */ 14955181Sgd78059 mutex_enter(dmfep->rxlock); 14965181Sgd78059 mutex_enter(dmfep->txlock); 14975181Sgd78059 dmfe_reset(dmfep); 14985181Sgd78059 mutex_exit(dmfep->txlock); 14995181Sgd78059 mutex_exit(dmfep->rxlock); 1500*9860Sgdamore@opensolaris.org if (dmfep->mac_state == DMFE_MAC_STARTED) { 15015181Sgd78059 dmfe_start(dmfep); 1502*9860Sgdamore@opensolaris.org } 15035181Sgd78059 } 15045181Sgd78059 15055181Sgd78059 15065181Sgd78059 /* 15075181Sgd78059 * ========== MAC-required management entry points ========== 15085181Sgd78059 */ 15095181Sgd78059 15105181Sgd78059 /* 15115181Sgd78059 * dmfe_m_stop() -- stop transmitting/receiving 15125181Sgd78059 */ 15135181Sgd78059 static void 15145181Sgd78059 dmfe_m_stop(void *arg) 15155181Sgd78059 { 15165181Sgd78059 dmfe_t *dmfep = arg; /* private device info */ 15175181Sgd78059 15185181Sgd78059 /* 15195181Sgd78059 * Just stop processing, then record new MAC state 15205181Sgd78059 */ 1521*9860Sgdamore@opensolaris.org mii_stop(dmfep->mii); 1522*9860Sgdamore@opensolaris.org 15235181Sgd78059 mutex_enter(dmfep->oplock); 1524*9860Sgdamore@opensolaris.org if (!dmfep->suspended) 1525*9860Sgdamore@opensolaris.org dmfe_stop(dmfep); 15265181Sgd78059 dmfep->mac_state = DMFE_MAC_STOPPED; 15275181Sgd78059 mutex_exit(dmfep->oplock); 15285181Sgd78059 } 15295181Sgd78059 15305181Sgd78059 /* 15315181Sgd78059 * dmfe_m_start() -- start transmitting/receiving 15325181Sgd78059 */ 15335181Sgd78059 static int 15345181Sgd78059 dmfe_m_start(void *arg) 15355181Sgd78059 { 15365181Sgd78059 dmfe_t *dmfep = arg; /* private device info */ 15375181Sgd78059 15385181Sgd78059 /* 15395181Sgd78059 * Start processing and record new MAC state 15405181Sgd78059 */ 15415181Sgd78059 mutex_enter(dmfep->oplock); 1542*9860Sgdamore@opensolaris.org if (!dmfep->suspended) 1543*9860Sgdamore@opensolaris.org dmfe_start(dmfep); 15445181Sgd78059 dmfep->mac_state = DMFE_MAC_STARTED; 15455181Sgd78059 mutex_exit(dmfep->oplock); 15465181Sgd78059 1547*9860Sgdamore@opensolaris.org mii_start(dmfep->mii); 1548*9860Sgdamore@opensolaris.org 15495181Sgd78059 return (0); 15505181Sgd78059 } 15515181Sgd78059 15525181Sgd78059 /* 15535181Sgd78059 * dmfe_m_promisc() -- set or reset promiscuous mode on the board 15545181Sgd78059 * 15555181Sgd78059 * Program the hardware to enable/disable promiscuous and/or 15565181Sgd78059 * receive-all-multicast modes. Davicom don't document this 15575181Sgd78059 * clearly, but it looks like we can do this on-the-fly (i.e. 15585181Sgd78059 * without stopping & restarting the TX/RX processes). 15595181Sgd78059 */ 15605181Sgd78059 static int 15615181Sgd78059 dmfe_m_promisc(void *arg, boolean_t on) 15625181Sgd78059 { 15635181Sgd78059 dmfe_t *dmfep = arg; 15645181Sgd78059 15655181Sgd78059 mutex_enter(dmfep->oplock); 15665181Sgd78059 dmfep->opmode &= ~(PROMISC_MODE | PASS_MULTICAST); 15675181Sgd78059 if (on) 15685181Sgd78059 dmfep->opmode |= PROMISC_MODE; 1569*9860Sgdamore@opensolaris.org if (!dmfep->suspended) 1570*9860Sgdamore@opensolaris.org dmfe_set_opmode(dmfep); 15715181Sgd78059 mutex_exit(dmfep->oplock); 15725181Sgd78059 15735181Sgd78059 return (0); 15745181Sgd78059 } 15755181Sgd78059 15765181Sgd78059 /* 15775181Sgd78059 * ========== Factotum, implemented as a softint handler ========== 15785181Sgd78059 */ 15795181Sgd78059 15805181Sgd78059 /* 15815181Sgd78059 * The factotum is woken up when there's something to do that we'd rather 15825181Sgd78059 * not do from inside a (high-level?) hardware interrupt handler. Its 15835181Sgd78059 * two main tasks are: 15845181Sgd78059 * reset & restart the chip after an error 15855181Sgd78059 * update & restart the chip after a link status change 15865181Sgd78059 */ 15875181Sgd78059 static uint_t 15885181Sgd78059 dmfe_factotum(caddr_t arg) 15895181Sgd78059 { 15905181Sgd78059 dmfe_t *dmfep; 15915181Sgd78059 15926990Sgd78059 dmfep = (void *)arg; 15935181Sgd78059 ASSERT(dmfep->dmfe_guard == DMFE_GUARD); 15945181Sgd78059 15955181Sgd78059 mutex_enter(dmfep->oplock); 1596*9860Sgdamore@opensolaris.org if (dmfep->suspended) { 1597*9860Sgdamore@opensolaris.org mutex_exit(dmfep->oplock); 1598*9860Sgdamore@opensolaris.org return (DDI_INTR_CLAIMED); 1599*9860Sgdamore@opensolaris.org } 16005181Sgd78059 16015181Sgd78059 dmfep->factotum_flag = 0; 16025181Sgd78059 DRV_KS_INC(dmfep, KS_FACTOTUM_RUN); 16035181Sgd78059 16045181Sgd78059 /* 16055181Sgd78059 * Check for chip error ... 16065181Sgd78059 */ 16075181Sgd78059 if (dmfep->chip_state == CHIP_ERROR) { 16085181Sgd78059 /* 16095181Sgd78059 * Error recovery required: reset the chip and the rings, 16105181Sgd78059 * then, if it's supposed to be running, kick it off again. 16115181Sgd78059 */ 16125181Sgd78059 DRV_KS_INC(dmfep, KS_RECOVERY); 16135181Sgd78059 dmfe_restart(dmfep); 1614*9860Sgdamore@opensolaris.org mutex_exit(dmfep->oplock); 1615*9860Sgdamore@opensolaris.org 1616*9860Sgdamore@opensolaris.org mii_reset(dmfep->mii); 1617*9860Sgdamore@opensolaris.org 16185181Sgd78059 } else if (dmfep->need_setup) { 16195181Sgd78059 (void) dmfe_send_setup(dmfep); 16205181Sgd78059 mutex_exit(dmfep->oplock); 16215181Sgd78059 } 16225181Sgd78059 16235181Sgd78059 return (DDI_INTR_CLAIMED); 16245181Sgd78059 } 16255181Sgd78059 16265181Sgd78059 static void 16275181Sgd78059 dmfe_wake_factotum(dmfe_t *dmfep, int ks_id, const char *why) 16285181Sgd78059 { 1629*9860Sgdamore@opensolaris.org _NOTE(ARGUNUSED(why)); 16305181Sgd78059 ASSERT(mutex_owned(dmfep->oplock)); 16315181Sgd78059 DRV_KS_INC(dmfep, ks_id); 16325181Sgd78059 16335181Sgd78059 if (dmfep->factotum_flag++ == 0) 16345181Sgd78059 ddi_trigger_softintr(dmfep->factotum_id); 16355181Sgd78059 } 16365181Sgd78059 16375181Sgd78059 16385181Sgd78059 /* 16395181Sgd78059 * ========== Periodic Tasks (Cyclic handler & friends) ========== 16405181Sgd78059 */ 16415181Sgd78059 16425181Sgd78059 /* 16435181Sgd78059 * Periodic tick tasks, run from the cyclic handler 16445181Sgd78059 * 16455181Sgd78059 * Check for TX stall; flag an error and wake the factotum if so. 16465181Sgd78059 */ 16475181Sgd78059 static void 16485181Sgd78059 dmfe_tick_stall_check(dmfe_t *dmfep, uint32_t gpsr, uint32_t istat) 16495181Sgd78059 { 16505181Sgd78059 boolean_t tx_stall; 16515181Sgd78059 uint32_t tx_state; 16525181Sgd78059 uint32_t limit; 16535181Sgd78059 16545181Sgd78059 ASSERT(mutex_owned(dmfep->oplock)); 16555181Sgd78059 16565181Sgd78059 /* 16575181Sgd78059 * Check for transmit stall ... 16585181Sgd78059 * 16595181Sgd78059 * IF there's at least one packet in the ring, AND the timeout 16605181Sgd78059 * has elapsed, AND we can't reclaim any descriptors, THEN we've 16615181Sgd78059 * stalled; we return B_TRUE to trigger a reset-and-recover cycle. 16625181Sgd78059 * 16635181Sgd78059 * Note that the timeout limit is based on the transmit engine 16645181Sgd78059 * state; we allow the transmitter longer to make progress in 16655181Sgd78059 * some states than in others, based on observations of this 16665181Sgd78059 * chip's actual behaviour in the lab. 16675181Sgd78059 * 16685181Sgd78059 * By observation, we find that on about 1 in 10000 passes through 16695181Sgd78059 * here, the TX lock is already held. In that case, we'll skip 16705181Sgd78059 * the check on this pass rather than wait. Most likely, the send 16715181Sgd78059 * routine was holding the lock when the interrupt happened, and 16725181Sgd78059 * we'll succeed next time through. In the event of a real stall, 16735181Sgd78059 * the TX ring will fill up, after which the send routine won't be 16745181Sgd78059 * called any more and then we're sure to get in. 16755181Sgd78059 */ 16765181Sgd78059 tx_stall = B_FALSE; 16775181Sgd78059 if (mutex_tryenter(dmfep->txlock)) { 16785181Sgd78059 if (dmfep->tx.n_free < dmfep->tx.n_desc) { 16795181Sgd78059 tx_state = TX_PROCESS_STATE(istat); 16805181Sgd78059 if (gpsr & GPS_LINK_100) 16815181Sgd78059 limit = stall_100_tix[tx_state]; 16825181Sgd78059 else 16835181Sgd78059 limit = stall_10_tix[tx_state]; 16845181Sgd78059 if (++dmfep->tx_pending_tix >= limit && 16855181Sgd78059 dmfe_reclaim_tx_desc(dmfep) == B_FALSE) { 16865181Sgd78059 dmfe_log(dmfep, "TX stall detected " 16875181Sgd78059 "after %d ticks in state %d; " 16885181Sgd78059 "automatic recovery initiated", 16895181Sgd78059 dmfep->tx_pending_tix, tx_state); 16905181Sgd78059 tx_stall = B_TRUE; 16915181Sgd78059 } 16925181Sgd78059 } 16935181Sgd78059 mutex_exit(dmfep->txlock); 16945181Sgd78059 } 16955181Sgd78059 16965181Sgd78059 if (tx_stall) { 16975181Sgd78059 dmfe_stop_chip(dmfep, CHIP_ERROR); 16985181Sgd78059 dmfe_wake_factotum(dmfep, KS_TX_STALL, "tick (TX stall)"); 16995181Sgd78059 } 17005181Sgd78059 } 17015181Sgd78059 17025181Sgd78059 /* 17035181Sgd78059 * Cyclic callback handler 17045181Sgd78059 */ 17055181Sgd78059 static void 17065181Sgd78059 dmfe_cyclic(void *arg) 17075181Sgd78059 { 17085181Sgd78059 dmfe_t *dmfep = arg; /* private device info */ 17095181Sgd78059 uint32_t istat; 17105181Sgd78059 uint32_t gpsr; 17115181Sgd78059 17125181Sgd78059 /* 17135181Sgd78059 * If the chip's not RUNNING, there's nothing to do. 17145181Sgd78059 * If we can't get the mutex straight away, we'll just 17155181Sgd78059 * skip this pass; we'll back back soon enough anyway. 17165181Sgd78059 */ 17175181Sgd78059 if (mutex_tryenter(dmfep->oplock) == 0) 17185181Sgd78059 return; 1719*9860Sgdamore@opensolaris.org if ((dmfep->suspended) || (dmfep->chip_state != CHIP_RUNNING)) { 1720*9860Sgdamore@opensolaris.org mutex_exit(dmfep->oplock); 1721*9860Sgdamore@opensolaris.org return; 1722*9860Sgdamore@opensolaris.org } 17235181Sgd78059 17245181Sgd78059 /* 17255181Sgd78059 * Recheck chip state (it might have been stopped since we 17265181Sgd78059 * checked above). If still running, call each of the *tick* 17275181Sgd78059 * tasks. They will check for link change, TX stall, etc ... 17285181Sgd78059 */ 17295181Sgd78059 if (dmfep->chip_state == CHIP_RUNNING) { 17305181Sgd78059 istat = dmfe_chip_get32(dmfep, STATUS_REG); 17315181Sgd78059 gpsr = dmfe_chip_get32(dmfep, PHY_STATUS_REG); 17325181Sgd78059 dmfe_tick_stall_check(dmfep, gpsr, istat); 17335181Sgd78059 } 17345181Sgd78059 17355181Sgd78059 DRV_KS_INC(dmfep, KS_CYCLIC_RUN); 17365181Sgd78059 mutex_exit(dmfep->oplock); 17375181Sgd78059 } 17385181Sgd78059 17395181Sgd78059 /* 17405181Sgd78059 * ========== Hardware interrupt handler ========== 17415181Sgd78059 */ 17425181Sgd78059 17435181Sgd78059 /* 17445181Sgd78059 * dmfe_interrupt() -- handle chip interrupts 17455181Sgd78059 */ 17465181Sgd78059 static uint_t 17475181Sgd78059 dmfe_interrupt(caddr_t arg) 17485181Sgd78059 { 17495181Sgd78059 dmfe_t *dmfep; /* private device info */ 17505181Sgd78059 uint32_t interrupts; 17515181Sgd78059 uint32_t istat; 17525181Sgd78059 const char *msg; 17535181Sgd78059 mblk_t *mp; 17545181Sgd78059 boolean_t warning_msg = B_TRUE; 17555181Sgd78059 17566990Sgd78059 dmfep = (void *)arg; 17575181Sgd78059 1758*9860Sgdamore@opensolaris.org mutex_enter(dmfep->oplock); 1759*9860Sgdamore@opensolaris.org if (dmfep->suspended) { 1760*9860Sgdamore@opensolaris.org mutex_exit(dmfep->oplock); 1761*9860Sgdamore@opensolaris.org return (DDI_INTR_UNCLAIMED); 1762*9860Sgdamore@opensolaris.org } 1763*9860Sgdamore@opensolaris.org 17645181Sgd78059 /* 17655181Sgd78059 * A quick check as to whether the interrupt was from this 17665181Sgd78059 * device, before we even finish setting up all our local 17675181Sgd78059 * variables. Note that reading the interrupt status register 17685181Sgd78059 * doesn't have any unpleasant side effects such as clearing 17695181Sgd78059 * the bits read, so it's quite OK to re-read it once we have 17705181Sgd78059 * determined that we are going to service this interrupt and 17715181Sgd78059 * grabbed the mutexen. 17725181Sgd78059 */ 17735181Sgd78059 istat = dmfe_chip_get32(dmfep, STATUS_REG); 1774*9860Sgdamore@opensolaris.org if ((istat & (NORMAL_SUMMARY_INT | ABNORMAL_SUMMARY_INT)) == 0) { 1775*9860Sgdamore@opensolaris.org 1776*9860Sgdamore@opensolaris.org mutex_exit(dmfep->oplock); 17775181Sgd78059 return (DDI_INTR_UNCLAIMED); 17785181Sgd78059 } 17795181Sgd78059 17805181Sgd78059 DRV_KS_INC(dmfep, KS_INTERRUPT); 17815181Sgd78059 17825181Sgd78059 /* 17835181Sgd78059 * Identify bits that represent enabled interrupts ... 17845181Sgd78059 */ 17855181Sgd78059 istat |= dmfe_chip_get32(dmfep, STATUS_REG); 17865181Sgd78059 interrupts = istat & dmfep->imask; 17875181Sgd78059 ASSERT(interrupts != 0); 17885181Sgd78059 1789*9860Sgdamore@opensolaris.org DTRACE_PROBE1(intr, uint32_t, istat); 17905181Sgd78059 17915181Sgd78059 /* 17925181Sgd78059 * Check for any interrupts other than TX/RX done. 17935181Sgd78059 * If there are any, they are considered Abnormal 17945181Sgd78059 * and will cause the chip to be reset. 17955181Sgd78059 */ 17965181Sgd78059 if (interrupts & ~(RX_PKTDONE_INT | TX_PKTDONE_INT)) { 17975181Sgd78059 if (istat & ABNORMAL_SUMMARY_INT) { 17985181Sgd78059 /* 17995181Sgd78059 * Any Abnormal interrupts will lead to us 18005181Sgd78059 * resetting the chip, so we don't bother 18015181Sgd78059 * to clear each interrupt individually. 18025181Sgd78059 * 18035181Sgd78059 * Our main task here is to identify the problem, 18045181Sgd78059 * by pointing out the most significant unexpected 18055181Sgd78059 * bit. Additional bits may well be consequences 18065181Sgd78059 * of the first problem, so we consider the possible 18075181Sgd78059 * causes in order of severity. 18085181Sgd78059 */ 18095181Sgd78059 if (interrupts & SYSTEM_ERR_INT) { 18105181Sgd78059 switch (istat & SYSTEM_ERR_BITS) { 18115181Sgd78059 case SYSTEM_ERR_M_ABORT: 18125181Sgd78059 msg = "Bus Master Abort"; 18135181Sgd78059 break; 18145181Sgd78059 18155181Sgd78059 case SYSTEM_ERR_T_ABORT: 18165181Sgd78059 msg = "Bus Target Abort"; 18175181Sgd78059 break; 18185181Sgd78059 18195181Sgd78059 case SYSTEM_ERR_PARITY: 18205181Sgd78059 msg = "Parity Error"; 18215181Sgd78059 break; 18225181Sgd78059 18235181Sgd78059 default: 18245181Sgd78059 msg = "Unknown System Bus Error"; 18255181Sgd78059 break; 18265181Sgd78059 } 18275181Sgd78059 } else if (interrupts & RX_STOPPED_INT) { 18285181Sgd78059 msg = "RX process stopped"; 18295181Sgd78059 } else if (interrupts & RX_UNAVAIL_INT) { 18305181Sgd78059 msg = "RX buffer unavailable"; 18315181Sgd78059 warning_msg = B_FALSE; 18325181Sgd78059 } else if (interrupts & RX_WATCHDOG_INT) { 18335181Sgd78059 msg = "RX watchdog timeout?"; 18345181Sgd78059 } else if (interrupts & RX_EARLY_INT) { 18355181Sgd78059 msg = "RX early interrupt?"; 18365181Sgd78059 } else if (interrupts & TX_STOPPED_INT) { 18375181Sgd78059 msg = "TX process stopped"; 18385181Sgd78059 } else if (interrupts & TX_JABBER_INT) { 18395181Sgd78059 msg = "TX jabber timeout"; 18405181Sgd78059 } else if (interrupts & TX_UNDERFLOW_INT) { 18415181Sgd78059 msg = "TX underflow?"; 18425181Sgd78059 } else if (interrupts & TX_EARLY_INT) { 18435181Sgd78059 msg = "TX early interrupt?"; 18445181Sgd78059 18455181Sgd78059 } else if (interrupts & LINK_STATUS_INT) { 18465181Sgd78059 msg = "Link status change?"; 18475181Sgd78059 } else if (interrupts & GP_TIMER_INT) { 18485181Sgd78059 msg = "Timer expired?"; 18495181Sgd78059 } 18505181Sgd78059 18515181Sgd78059 if (warning_msg) 18525181Sgd78059 dmfe_warning(dmfep, "abnormal interrupt, " 18535181Sgd78059 "status 0x%x: %s", istat, msg); 18545181Sgd78059 18555181Sgd78059 /* 18565181Sgd78059 * We don't want to run the entire reinitialisation 18575181Sgd78059 * code out of this (high-level?) interrupt, so we 18585181Sgd78059 * simply STOP the chip, and wake up the factotum 18595181Sgd78059 * to reinitalise it ... 18605181Sgd78059 */ 18615181Sgd78059 dmfe_stop_chip(dmfep, CHIP_ERROR); 18625181Sgd78059 dmfe_wake_factotum(dmfep, KS_CHIP_ERROR, 18635181Sgd78059 "interrupt (error)"); 18645181Sgd78059 } else { 18655181Sgd78059 /* 18665181Sgd78059 * We shouldn't really get here (it would mean 18675181Sgd78059 * there were some unprocessed enabled bits but 18685181Sgd78059 * they weren't Abnormal?), but we'll check just 18695181Sgd78059 * in case ... 18705181Sgd78059 */ 1871*9860Sgdamore@opensolaris.org DTRACE_PROBE1(intr__unexpected, uint32_t, istat); 18725181Sgd78059 } 18735181Sgd78059 } 18745181Sgd78059 18755181Sgd78059 /* 18765181Sgd78059 * Acknowledge all the original bits - except in the case of an 18775181Sgd78059 * error, when we leave them unacknowledged so that the recovery 18785181Sgd78059 * code can see what was going on when the problem occurred ... 18795181Sgd78059 */ 18805181Sgd78059 if (dmfep->chip_state != CHIP_ERROR) { 18815181Sgd78059 (void) dmfe_chip_put32(dmfep, STATUS_REG, istat); 18825181Sgd78059 /* 18835181Sgd78059 * Read-after-write forces completion on PCI bus. 18845181Sgd78059 * 18855181Sgd78059 */ 18865181Sgd78059 (void) dmfe_chip_get32(dmfep, STATUS_REG); 18875181Sgd78059 } 18885181Sgd78059 18895181Sgd78059 18905181Sgd78059 /* 18915181Sgd78059 * We've finished talking to the chip, so we can drop <oplock> 18925181Sgd78059 * before handling the normal interrupts, which only involve 18935181Sgd78059 * manipulation of descriptors ... 18945181Sgd78059 */ 18955181Sgd78059 mutex_exit(dmfep->oplock); 18965181Sgd78059 18975181Sgd78059 if (interrupts & RX_PKTDONE_INT) 18985181Sgd78059 if ((mp = dmfe_getp(dmfep)) != NULL) 18995181Sgd78059 mac_rx(dmfep->mh, NULL, mp); 19005181Sgd78059 19015181Sgd78059 if (interrupts & TX_PKTDONE_INT) { 19025181Sgd78059 /* 19035181Sgd78059 * The only reason for taking this interrupt is to give 19045181Sgd78059 * MAC a chance to schedule queued packets after a 19055181Sgd78059 * ring-full condition. To minimise the number of 19065181Sgd78059 * redundant TX-Done interrupts, we only mark two of the 19075181Sgd78059 * ring descriptors as 'interrupt-on-complete' - all the 19085181Sgd78059 * others are simply handed back without an interrupt. 19095181Sgd78059 */ 19105181Sgd78059 if (dmfe_reclaim_on_done && mutex_tryenter(dmfep->txlock)) { 19115181Sgd78059 (void) dmfe_reclaim_tx_desc(dmfep); 19125181Sgd78059 mutex_exit(dmfep->txlock); 19135181Sgd78059 } 19145181Sgd78059 mac_tx_update(dmfep->mh); 19155181Sgd78059 } 19165181Sgd78059 19175181Sgd78059 return (DDI_INTR_CLAIMED); 19185181Sgd78059 } 19195181Sgd78059 19205181Sgd78059 /* 19215181Sgd78059 * ========== Statistics update handler ========== 19225181Sgd78059 */ 19235181Sgd78059 19245181Sgd78059 static int 19255181Sgd78059 dmfe_m_stat(void *arg, uint_t stat, uint64_t *val) 19265181Sgd78059 { 19275181Sgd78059 dmfe_t *dmfep = arg; 19285181Sgd78059 int rv = 0; 19295181Sgd78059 1930*9860Sgdamore@opensolaris.org /* Let MII handle its own stats. */ 1931*9860Sgdamore@opensolaris.org if (mii_m_getstat(dmfep->mii, stat, val) == 0) { 1932*9860Sgdamore@opensolaris.org return (0); 1933*9860Sgdamore@opensolaris.org } 1934*9860Sgdamore@opensolaris.org 19355181Sgd78059 mutex_enter(dmfep->oplock); 19365181Sgd78059 mutex_enter(dmfep->rxlock); 19375181Sgd78059 mutex_enter(dmfep->txlock); 19385181Sgd78059 19395181Sgd78059 /* make sure we have all the stats collected */ 19405181Sgd78059 (void) dmfe_reclaim_tx_desc(dmfep); 19415181Sgd78059 19425181Sgd78059 switch (stat) { 19435181Sgd78059 19445181Sgd78059 case MAC_STAT_IPACKETS: 19455181Sgd78059 *val = dmfep->rx_stats_ipackets; 19465181Sgd78059 break; 19475181Sgd78059 19485181Sgd78059 case MAC_STAT_MULTIRCV: 19495181Sgd78059 *val = dmfep->rx_stats_multi; 19505181Sgd78059 break; 19515181Sgd78059 19525181Sgd78059 case MAC_STAT_BRDCSTRCV: 19535181Sgd78059 *val = dmfep->rx_stats_bcast; 19545181Sgd78059 break; 19555181Sgd78059 19565181Sgd78059 case MAC_STAT_RBYTES: 19575181Sgd78059 *val = dmfep->rx_stats_rbytes; 19585181Sgd78059 break; 19595181Sgd78059 19605181Sgd78059 case MAC_STAT_IERRORS: 19615181Sgd78059 *val = dmfep->rx_stats_ierrors; 19625181Sgd78059 break; 19635181Sgd78059 19645181Sgd78059 case MAC_STAT_NORCVBUF: 19655181Sgd78059 *val = dmfep->rx_stats_norcvbuf; 19665181Sgd78059 break; 19675181Sgd78059 19685181Sgd78059 case MAC_STAT_COLLISIONS: 19695181Sgd78059 *val = dmfep->tx_stats_collisions; 19705181Sgd78059 break; 19715181Sgd78059 19725181Sgd78059 case MAC_STAT_OERRORS: 19735181Sgd78059 *val = dmfep->tx_stats_oerrors; 19745181Sgd78059 break; 19755181Sgd78059 19765181Sgd78059 case MAC_STAT_OPACKETS: 19775181Sgd78059 *val = dmfep->tx_stats_opackets; 19785181Sgd78059 break; 19795181Sgd78059 19805181Sgd78059 case MAC_STAT_MULTIXMT: 19815181Sgd78059 *val = dmfep->tx_stats_multi; 19825181Sgd78059 break; 19835181Sgd78059 19845181Sgd78059 case MAC_STAT_BRDCSTXMT: 19855181Sgd78059 *val = dmfep->tx_stats_bcast; 19865181Sgd78059 break; 19875181Sgd78059 19885181Sgd78059 case MAC_STAT_OBYTES: 19895181Sgd78059 *val = dmfep->tx_stats_obytes; 19905181Sgd78059 break; 19915181Sgd78059 19925181Sgd78059 case MAC_STAT_OVERFLOWS: 19935181Sgd78059 *val = dmfep->rx_stats_overflow; 19945181Sgd78059 break; 19955181Sgd78059 19965181Sgd78059 case MAC_STAT_UNDERFLOWS: 19975181Sgd78059 *val = dmfep->tx_stats_underflow; 19985181Sgd78059 break; 19995181Sgd78059 20005181Sgd78059 case ETHER_STAT_ALIGN_ERRORS: 20015181Sgd78059 *val = dmfep->rx_stats_align; 20025181Sgd78059 break; 20035181Sgd78059 20045181Sgd78059 case ETHER_STAT_FCS_ERRORS: 20055181Sgd78059 *val = dmfep->rx_stats_fcs; 20065181Sgd78059 break; 20075181Sgd78059 20085181Sgd78059 case ETHER_STAT_TOOLONG_ERRORS: 20095181Sgd78059 *val = dmfep->rx_stats_toolong; 20105181Sgd78059 break; 20115181Sgd78059 20125181Sgd78059 case ETHER_STAT_TOOSHORT_ERRORS: 20135181Sgd78059 *val = dmfep->rx_stats_short; 20145181Sgd78059 break; 20155181Sgd78059 20165181Sgd78059 case ETHER_STAT_MACRCV_ERRORS: 20175181Sgd78059 *val = dmfep->rx_stats_macrcv_errors; 20185181Sgd78059 break; 20195181Sgd78059 20205181Sgd78059 case ETHER_STAT_MACXMT_ERRORS: 20215181Sgd78059 *val = dmfep->tx_stats_macxmt_errors; 20225181Sgd78059 break; 20235181Sgd78059 20245181Sgd78059 case ETHER_STAT_JABBER_ERRORS: 20255181Sgd78059 *val = dmfep->tx_stats_jabber; 20265181Sgd78059 break; 20275181Sgd78059 20285181Sgd78059 case ETHER_STAT_CARRIER_ERRORS: 20295181Sgd78059 *val = dmfep->tx_stats_nocarrier; 20305181Sgd78059 break; 20315181Sgd78059 20325181Sgd78059 case ETHER_STAT_TX_LATE_COLLISIONS: 20335181Sgd78059 *val = dmfep->tx_stats_xmtlatecoll; 20345181Sgd78059 break; 20355181Sgd78059 20365181Sgd78059 case ETHER_STAT_EX_COLLISIONS: 20375181Sgd78059 *val = dmfep->tx_stats_excoll; 20385181Sgd78059 break; 20395181Sgd78059 20405181Sgd78059 case ETHER_STAT_DEFER_XMTS: 20415181Sgd78059 *val = dmfep->tx_stats_defer; 20425181Sgd78059 break; 20435181Sgd78059 20445181Sgd78059 case ETHER_STAT_FIRST_COLLISIONS: 20455181Sgd78059 *val = dmfep->tx_stats_first_coll; 20465181Sgd78059 break; 20475181Sgd78059 20485181Sgd78059 case ETHER_STAT_MULTI_COLLISIONS: 20495181Sgd78059 *val = dmfep->tx_stats_multi_coll; 20505181Sgd78059 break; 20515181Sgd78059 20525181Sgd78059 default: 20535181Sgd78059 rv = ENOTSUP; 20545181Sgd78059 } 20555181Sgd78059 20565181Sgd78059 mutex_exit(dmfep->txlock); 20575181Sgd78059 mutex_exit(dmfep->rxlock); 20585181Sgd78059 mutex_exit(dmfep->oplock); 20595181Sgd78059 20605181Sgd78059 return (rv); 20615181Sgd78059 } 20625181Sgd78059 20635181Sgd78059 /* 20645181Sgd78059 * ========== Ioctl handler & subfunctions ========== 20655181Sgd78059 */ 20665181Sgd78059 2067*9860Sgdamore@opensolaris.org static lb_property_t dmfe_loopmodes[] = { 2068*9860Sgdamore@opensolaris.org { normal, "normal", 0 }, 2069*9860Sgdamore@opensolaris.org { internal, "Internal", 1 }, 2070*9860Sgdamore@opensolaris.org { external, "External", 2 }, 2071*9860Sgdamore@opensolaris.org }; 20725181Sgd78059 20735181Sgd78059 /* 20745181Sgd78059 * Specific dmfe IOCTLs, the mac module handles the generic ones. 2075*9860Sgdamore@opensolaris.org * Unfortunately, the DM9102 doesn't seem to work well with MII based 2076*9860Sgdamore@opensolaris.org * loopback, so we have to do something special for it. 20775181Sgd78059 */ 2078*9860Sgdamore@opensolaris.org 20795181Sgd78059 static void 20805181Sgd78059 dmfe_m_ioctl(void *arg, queue_t *wq, mblk_t *mp) 20815181Sgd78059 { 2082*9860Sgdamore@opensolaris.org dmfe_t *dmfep = arg; 2083*9860Sgdamore@opensolaris.org struct iocblk *iocp; 2084*9860Sgdamore@opensolaris.org int rv = 0; 2085*9860Sgdamore@opensolaris.org lb_info_sz_t sz; 2086*9860Sgdamore@opensolaris.org int cmd; 2087*9860Sgdamore@opensolaris.org uint32_t mode; 2088*9860Sgdamore@opensolaris.org 20896990Sgd78059 iocp = (void *)mp->b_rptr; 20905181Sgd78059 cmd = iocp->ioc_cmd; 2091*9860Sgdamore@opensolaris.org 2092*9860Sgdamore@opensolaris.org if (mp->b_cont == NULL) { 2093*9860Sgdamore@opensolaris.org /* 2094*9860Sgdamore@opensolaris.org * All of these ioctls need data! 2095*9860Sgdamore@opensolaris.org */ 20965181Sgd78059 miocnak(wq, mp, 0, EINVAL); 20975181Sgd78059 return; 20985181Sgd78059 } 20995181Sgd78059 21005181Sgd78059 switch (cmd) { 2101*9860Sgdamore@opensolaris.org case LB_GET_INFO_SIZE: 2102*9860Sgdamore@opensolaris.org if (iocp->ioc_count != sizeof (sz)) { 2103*9860Sgdamore@opensolaris.org rv = EINVAL; 2104*9860Sgdamore@opensolaris.org } else { 2105*9860Sgdamore@opensolaris.org sz = sizeof (dmfe_loopmodes); 2106*9860Sgdamore@opensolaris.org bcopy(&sz, mp->b_cont->b_rptr, sizeof (sz)); 2107*9860Sgdamore@opensolaris.org } 2108*9860Sgdamore@opensolaris.org break; 2109*9860Sgdamore@opensolaris.org 2110*9860Sgdamore@opensolaris.org case LB_GET_INFO: 2111*9860Sgdamore@opensolaris.org if (iocp->ioc_count != sizeof (dmfe_loopmodes)) { 2112*9860Sgdamore@opensolaris.org rv = EINVAL; 2113*9860Sgdamore@opensolaris.org } else { 2114*9860Sgdamore@opensolaris.org bcopy(dmfe_loopmodes, mp->b_cont->b_rptr, 2115*9860Sgdamore@opensolaris.org iocp->ioc_count); 2116*9860Sgdamore@opensolaris.org } 21175181Sgd78059 break; 21185181Sgd78059 2119*9860Sgdamore@opensolaris.org case LB_GET_MODE: 2120*9860Sgdamore@opensolaris.org if (iocp->ioc_count != sizeof (mode)) { 2121*9860Sgdamore@opensolaris.org rv = EINVAL; 2122*9860Sgdamore@opensolaris.org } else { 2123*9860Sgdamore@opensolaris.org mutex_enter(dmfep->oplock); 2124*9860Sgdamore@opensolaris.org switch (dmfep->opmode & LOOPBACK_MODE_MASK) { 2125*9860Sgdamore@opensolaris.org case LOOPBACK_OFF: 2126*9860Sgdamore@opensolaris.org mode = 0; 2127*9860Sgdamore@opensolaris.org break; 2128*9860Sgdamore@opensolaris.org case LOOPBACK_INTERNAL: 2129*9860Sgdamore@opensolaris.org mode = 1; 2130*9860Sgdamore@opensolaris.org break; 2131*9860Sgdamore@opensolaris.org default: 2132*9860Sgdamore@opensolaris.org mode = 2; 2133*9860Sgdamore@opensolaris.org break; 2134*9860Sgdamore@opensolaris.org } 2135*9860Sgdamore@opensolaris.org mutex_exit(dmfep->oplock); 2136*9860Sgdamore@opensolaris.org bcopy(&mode, mp->b_cont->b_rptr, sizeof (mode)); 2137*9860Sgdamore@opensolaris.org } 21385181Sgd78059 break; 21395181Sgd78059 2140*9860Sgdamore@opensolaris.org case LB_SET_MODE: 2141*9860Sgdamore@opensolaris.org rv = secpolicy_net_config(iocp->ioc_cr, B_FALSE); 2142*9860Sgdamore@opensolaris.org if (rv != 0) 2143*9860Sgdamore@opensolaris.org break; 2144*9860Sgdamore@opensolaris.org if (iocp->ioc_count != sizeof (mode)) { 2145*9860Sgdamore@opensolaris.org rv = EINVAL; 2146*9860Sgdamore@opensolaris.org break; 2147*9860Sgdamore@opensolaris.org } 2148*9860Sgdamore@opensolaris.org bcopy(mp->b_cont->b_rptr, &mode, sizeof (mode)); 2149*9860Sgdamore@opensolaris.org 2150*9860Sgdamore@opensolaris.org mutex_enter(dmfep->oplock); 2151*9860Sgdamore@opensolaris.org dmfep->opmode &= ~LOOPBACK_MODE_MASK; 2152*9860Sgdamore@opensolaris.org switch (mode) { 2153*9860Sgdamore@opensolaris.org case 2: 2154*9860Sgdamore@opensolaris.org dmfep->opmode |= LOOPBACK_PHY_D; 2155*9860Sgdamore@opensolaris.org break; 2156*9860Sgdamore@opensolaris.org case 1: 2157*9860Sgdamore@opensolaris.org dmfep->opmode |= LOOPBACK_INTERNAL; 2158*9860Sgdamore@opensolaris.org break; 2159*9860Sgdamore@opensolaris.org default: 2160*9860Sgdamore@opensolaris.org break; 2161*9860Sgdamore@opensolaris.org } 2162*9860Sgdamore@opensolaris.org if (!dmfep->suspended) { 2163*9860Sgdamore@opensolaris.org dmfe_restart(dmfep); 2164*9860Sgdamore@opensolaris.org } 2165*9860Sgdamore@opensolaris.org mutex_exit(dmfep->oplock); 2166*9860Sgdamore@opensolaris.org break; 2167*9860Sgdamore@opensolaris.org 2168*9860Sgdamore@opensolaris.org default: 2169*9860Sgdamore@opensolaris.org rv = EINVAL; 21705181Sgd78059 break; 21715181Sgd78059 } 21725181Sgd78059 2173*9860Sgdamore@opensolaris.org if (rv == 0) { 2174*9860Sgdamore@opensolaris.org miocack(wq, mp, iocp->ioc_count, 0); 2175*9860Sgdamore@opensolaris.org } else { 2176*9860Sgdamore@opensolaris.org miocnak(wq, mp, 0, rv); 21775181Sgd78059 } 21785181Sgd78059 } 21795181Sgd78059 2180*9860Sgdamore@opensolaris.org int 2181*9860Sgdamore@opensolaris.org dmfe_m_getprop(void *arg, const char *name, mac_prop_id_t num, uint_t flags, 2182*9860Sgdamore@opensolaris.org uint_t sz, void *val, uint_t *perm) 2183*9860Sgdamore@opensolaris.org { 2184*9860Sgdamore@opensolaris.org dmfe_t *dmfep = arg; 2185*9860Sgdamore@opensolaris.org 2186*9860Sgdamore@opensolaris.org return (mii_m_getprop(dmfep->mii, name, num, flags, sz, val, perm)); 2187*9860Sgdamore@opensolaris.org } 2188*9860Sgdamore@opensolaris.org 2189*9860Sgdamore@opensolaris.org int 2190*9860Sgdamore@opensolaris.org dmfe_m_setprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz, 2191*9860Sgdamore@opensolaris.org const void *val) 2192*9860Sgdamore@opensolaris.org { 2193*9860Sgdamore@opensolaris.org dmfe_t *dmfep = arg; 2194*9860Sgdamore@opensolaris.org 2195*9860Sgdamore@opensolaris.org return (mii_m_setprop(dmfep->mii, name, num, sz, val)); 2196*9860Sgdamore@opensolaris.org } 21975181Sgd78059 21985181Sgd78059 21995181Sgd78059 /* 22005181Sgd78059 * ========== Per-instance setup/teardown code ========== 22015181Sgd78059 */ 22025181Sgd78059 22035181Sgd78059 /* 22045181Sgd78059 * Determine local MAC address & broadcast address for this interface 22055181Sgd78059 */ 22065181Sgd78059 static void 22075181Sgd78059 dmfe_find_mac_address(dmfe_t *dmfep) 22085181Sgd78059 { 22095181Sgd78059 uchar_t *prop; 22105181Sgd78059 uint_t propsize; 22115181Sgd78059 int err; 22125181Sgd78059 22135181Sgd78059 /* 22145181Sgd78059 * We have to find the "vendor's factory-set address". This is 22155181Sgd78059 * the value of the property "local-mac-address", as set by OBP 22165181Sgd78059 * (or a .conf file!) 22175181Sgd78059 * 22185181Sgd78059 * If the property is not there, then we try to find the factory 22195181Sgd78059 * mac address from the devices serial EEPROM. 22205181Sgd78059 */ 22215181Sgd78059 bzero(dmfep->curr_addr, sizeof (dmfep->curr_addr)); 22225181Sgd78059 err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dmfep->devinfo, 22235181Sgd78059 DDI_PROP_DONTPASS, localmac_propname, &prop, &propsize); 22245181Sgd78059 if (err == DDI_PROP_SUCCESS) { 22255181Sgd78059 if (propsize == ETHERADDRL) 22265181Sgd78059 ethaddr_copy(prop, dmfep->curr_addr); 22275181Sgd78059 ddi_prop_free(prop); 22285181Sgd78059 } else { 22295181Sgd78059 /* no property set... check eeprom */ 22305181Sgd78059 dmfe_read_eeprom(dmfep, EEPROM_EN_ADDR, dmfep->curr_addr, 22315181Sgd78059 ETHERADDRL); 22325181Sgd78059 } 22335181Sgd78059 } 22345181Sgd78059 22355181Sgd78059 static int 22365181Sgd78059 dmfe_alloc_dma_mem(dmfe_t *dmfep, size_t memsize, 22375181Sgd78059 size_t setup, size_t slop, ddi_device_acc_attr_t *attr_p, 22385181Sgd78059 uint_t dma_flags, dma_area_t *dma_p) 22395181Sgd78059 { 22405181Sgd78059 ddi_dma_cookie_t dma_cookie; 22415181Sgd78059 uint_t ncookies; 22425181Sgd78059 int err; 22435181Sgd78059 22445181Sgd78059 /* 22455181Sgd78059 * Allocate handle 22465181Sgd78059 */ 22475181Sgd78059 err = ddi_dma_alloc_handle(dmfep->devinfo, &dma_attr, 22485181Sgd78059 DDI_DMA_SLEEP, NULL, &dma_p->dma_hdl); 2249*9860Sgdamore@opensolaris.org if (err != DDI_SUCCESS) { 2250*9860Sgdamore@opensolaris.org dmfe_error(dmfep, "DMA handle allocation failed"); 22515181Sgd78059 return (DDI_FAILURE); 2252*9860Sgdamore@opensolaris.org } 22535181Sgd78059 22545181Sgd78059 /* 22555181Sgd78059 * Allocate memory 22565181Sgd78059 */ 22575181Sgd78059 err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize + setup + slop, 22585181Sgd78059 attr_p, dma_flags & (DDI_DMA_CONSISTENT | DDI_DMA_STREAMING), 22595181Sgd78059 DDI_DMA_SLEEP, NULL, 22605181Sgd78059 &dma_p->mem_va, &dma_p->alength, &dma_p->acc_hdl); 2261*9860Sgdamore@opensolaris.org if (err != DDI_SUCCESS) { 2262*9860Sgdamore@opensolaris.org dmfe_error(dmfep, "DMA memory allocation failed: %d", err); 22635181Sgd78059 return (DDI_FAILURE); 2264*9860Sgdamore@opensolaris.org } 22655181Sgd78059 22665181Sgd78059 /* 22675181Sgd78059 * Bind the two together 22685181Sgd78059 */ 22695181Sgd78059 err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL, 22705181Sgd78059 dma_p->mem_va, dma_p->alength, dma_flags, 22715181Sgd78059 DDI_DMA_SLEEP, NULL, &dma_cookie, &ncookies); 2272*9860Sgdamore@opensolaris.org if (err != DDI_DMA_MAPPED) { 2273*9860Sgdamore@opensolaris.org dmfe_error(dmfep, "DMA mapping failed: %d", err); 22745181Sgd78059 return (DDI_FAILURE); 2275*9860Sgdamore@opensolaris.org } 2276*9860Sgdamore@opensolaris.org if ((dma_p->ncookies = ncookies) != 1) { 2277*9860Sgdamore@opensolaris.org dmfe_error(dmfep, "Too many DMA cookeis: %d", ncookies); 22785181Sgd78059 return (DDI_FAILURE); 2279*9860Sgdamore@opensolaris.org } 22805181Sgd78059 22815181Sgd78059 dma_p->mem_dvma = dma_cookie.dmac_address; 22825181Sgd78059 if (setup > 0) { 22835181Sgd78059 dma_p->setup_dvma = dma_p->mem_dvma + memsize; 22845181Sgd78059 dma_p->setup_va = dma_p->mem_va + memsize; 22855181Sgd78059 } else { 22865181Sgd78059 dma_p->setup_dvma = 0; 22875181Sgd78059 dma_p->setup_va = NULL; 22885181Sgd78059 } 22895181Sgd78059 22905181Sgd78059 return (DDI_SUCCESS); 22915181Sgd78059 } 22925181Sgd78059 22935181Sgd78059 /* 22945181Sgd78059 * This function allocates the transmit and receive buffers and descriptors. 22955181Sgd78059 */ 22965181Sgd78059 static int 22975181Sgd78059 dmfe_alloc_bufs(dmfe_t *dmfep) 22985181Sgd78059 { 22995181Sgd78059 size_t memsize; 23005181Sgd78059 int err; 23015181Sgd78059 23025181Sgd78059 /* 23035181Sgd78059 * Allocate memory & handles for TX descriptor ring 23045181Sgd78059 */ 23055181Sgd78059 memsize = dmfep->tx.n_desc * sizeof (struct tx_desc_type); 23065181Sgd78059 err = dmfe_alloc_dma_mem(dmfep, memsize, SETUPBUF_SIZE, DMFE_SLOP, 23075181Sgd78059 &dmfe_reg_accattr, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 23085181Sgd78059 &dmfep->tx_desc); 2309*9860Sgdamore@opensolaris.org if (err != DDI_SUCCESS) { 2310*9860Sgdamore@opensolaris.org dmfe_error(dmfep, "TX descriptor allocation failed"); 23115181Sgd78059 return (DDI_FAILURE); 2312*9860Sgdamore@opensolaris.org } 23135181Sgd78059 23145181Sgd78059 /* 23155181Sgd78059 * Allocate memory & handles for TX buffers 23165181Sgd78059 */ 23175181Sgd78059 memsize = dmfep->tx.n_desc * DMFE_BUF_SIZE; 23185181Sgd78059 err = dmfe_alloc_dma_mem(dmfep, memsize, 0, 0, 23195181Sgd78059 &dmfe_data_accattr, DDI_DMA_WRITE | DMFE_DMA_MODE, 23205181Sgd78059 &dmfep->tx_buff); 2321*9860Sgdamore@opensolaris.org if (err != DDI_SUCCESS) { 2322*9860Sgdamore@opensolaris.org dmfe_error(dmfep, "TX buffer allocation failed"); 23235181Sgd78059 return (DDI_FAILURE); 2324*9860Sgdamore@opensolaris.org } 23255181Sgd78059 23265181Sgd78059 /* 23275181Sgd78059 * Allocate memory & handles for RX descriptor ring 23285181Sgd78059 */ 23295181Sgd78059 memsize = dmfep->rx.n_desc * sizeof (struct rx_desc_type); 23305181Sgd78059 err = dmfe_alloc_dma_mem(dmfep, memsize, 0, DMFE_SLOP, 23315181Sgd78059 &dmfe_reg_accattr, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 23325181Sgd78059 &dmfep->rx_desc); 2333*9860Sgdamore@opensolaris.org if (err != DDI_SUCCESS) { 2334*9860Sgdamore@opensolaris.org dmfe_error(dmfep, "RX descriptor allocation failed"); 23355181Sgd78059 return (DDI_FAILURE); 2336*9860Sgdamore@opensolaris.org } 23375181Sgd78059 23385181Sgd78059 /* 23395181Sgd78059 * Allocate memory & handles for RX buffers 23405181Sgd78059 */ 23415181Sgd78059 memsize = dmfep->rx.n_desc * DMFE_BUF_SIZE; 23425181Sgd78059 err = dmfe_alloc_dma_mem(dmfep, memsize, 0, 0, 23435181Sgd78059 &dmfe_data_accattr, DDI_DMA_READ | DMFE_DMA_MODE, &dmfep->rx_buff); 2344*9860Sgdamore@opensolaris.org if (err != DDI_SUCCESS) { 2345*9860Sgdamore@opensolaris.org dmfe_error(dmfep, "RX buffer allocation failed"); 23465181Sgd78059 return (DDI_FAILURE); 2347*9860Sgdamore@opensolaris.org } 23485181Sgd78059 23495181Sgd78059 /* 23505181Sgd78059 * Allocate bitmasks for tx packet type tracking 23515181Sgd78059 */ 23525181Sgd78059 dmfep->tx_mcast = kmem_zalloc(dmfep->tx.n_desc / NBBY, KM_SLEEP); 23535181Sgd78059 dmfep->tx_bcast = kmem_zalloc(dmfep->tx.n_desc / NBBY, KM_SLEEP); 23545181Sgd78059 23555181Sgd78059 return (DDI_SUCCESS); 23565181Sgd78059 } 23575181Sgd78059 23585181Sgd78059 static void 23595181Sgd78059 dmfe_free_dma_mem(dma_area_t *dma_p) 23605181Sgd78059 { 23615181Sgd78059 if (dma_p->dma_hdl != NULL) { 23625181Sgd78059 if (dma_p->ncookies) { 23635181Sgd78059 (void) ddi_dma_unbind_handle(dma_p->dma_hdl); 23645181Sgd78059 dma_p->ncookies = 0; 23655181Sgd78059 } 23665181Sgd78059 ddi_dma_free_handle(&dma_p->dma_hdl); 23675181Sgd78059 dma_p->dma_hdl = NULL; 23685181Sgd78059 dma_p->mem_dvma = 0; 23695181Sgd78059 dma_p->setup_dvma = 0; 23705181Sgd78059 } 23715181Sgd78059 23725181Sgd78059 if (dma_p->acc_hdl != NULL) { 23735181Sgd78059 ddi_dma_mem_free(&dma_p->acc_hdl); 23745181Sgd78059 dma_p->acc_hdl = NULL; 23755181Sgd78059 dma_p->mem_va = NULL; 23765181Sgd78059 dma_p->setup_va = NULL; 23775181Sgd78059 } 23785181Sgd78059 } 23795181Sgd78059 23805181Sgd78059 /* 23815181Sgd78059 * This routine frees the transmit and receive buffers and descriptors. 23825181Sgd78059 * Make sure the chip is stopped before calling it! 23835181Sgd78059 */ 23845181Sgd78059 static void 23855181Sgd78059 dmfe_free_bufs(dmfe_t *dmfep) 23865181Sgd78059 { 23875181Sgd78059 dmfe_free_dma_mem(&dmfep->rx_buff); 23885181Sgd78059 dmfe_free_dma_mem(&dmfep->rx_desc); 23895181Sgd78059 dmfe_free_dma_mem(&dmfep->tx_buff); 23905181Sgd78059 dmfe_free_dma_mem(&dmfep->tx_desc); 2391*9860Sgdamore@opensolaris.org if (dmfep->tx_mcast) 2392*9860Sgdamore@opensolaris.org kmem_free(dmfep->tx_mcast, dmfep->tx.n_desc / NBBY); 2393*9860Sgdamore@opensolaris.org if (dmfep->tx_bcast) 2394*9860Sgdamore@opensolaris.org kmem_free(dmfep->tx_bcast, dmfep->tx.n_desc / NBBY); 23955181Sgd78059 } 23965181Sgd78059 23975181Sgd78059 static void 23985181Sgd78059 dmfe_unattach(dmfe_t *dmfep) 23995181Sgd78059 { 24005181Sgd78059 /* 24015181Sgd78059 * Clean up and free all DMFE data structures 24025181Sgd78059 */ 24035181Sgd78059 if (dmfep->cycid != NULL) { 24045181Sgd78059 ddi_periodic_delete(dmfep->cycid); 24055181Sgd78059 dmfep->cycid = NULL; 24065181Sgd78059 } 24075181Sgd78059 24085181Sgd78059 if (dmfep->ksp_drv != NULL) 24095181Sgd78059 kstat_delete(dmfep->ksp_drv); 24105181Sgd78059 if (dmfep->progress & PROGRESS_HWINT) { 24115181Sgd78059 ddi_remove_intr(dmfep->devinfo, 0, dmfep->iblk); 2412*9860Sgdamore@opensolaris.org } 2413*9860Sgdamore@opensolaris.org if (dmfep->progress & PROGRESS_SOFTINT) 2414*9860Sgdamore@opensolaris.org ddi_remove_softintr(dmfep->factotum_id); 2415*9860Sgdamore@opensolaris.org if (dmfep->mii != NULL) 2416*9860Sgdamore@opensolaris.org mii_free(dmfep->mii); 2417*9860Sgdamore@opensolaris.org if (dmfep->progress & PROGRESS_MUTEX) { 24185181Sgd78059 mutex_destroy(dmfep->txlock); 24195181Sgd78059 mutex_destroy(dmfep->rxlock); 24205181Sgd78059 mutex_destroy(dmfep->oplock); 24215181Sgd78059 } 2422*9860Sgdamore@opensolaris.org dmfe_free_bufs(dmfep); 2423*9860Sgdamore@opensolaris.org if (dmfep->io_handle != NULL) 24245181Sgd78059 ddi_regs_map_free(&dmfep->io_handle); 24255181Sgd78059 24265181Sgd78059 kmem_free(dmfep, sizeof (*dmfep)); 24275181Sgd78059 } 24285181Sgd78059 24295181Sgd78059 static int 24305181Sgd78059 dmfe_config_init(dmfe_t *dmfep, chip_id_t *idp) 24315181Sgd78059 { 24325181Sgd78059 ddi_acc_handle_t handle; 24335181Sgd78059 uint32_t regval; 24345181Sgd78059 24355181Sgd78059 if (pci_config_setup(dmfep->devinfo, &handle) != DDI_SUCCESS) 24365181Sgd78059 return (DDI_FAILURE); 24375181Sgd78059 24385181Sgd78059 /* 24395181Sgd78059 * Get vendor/device/revision. We expect (but don't check) that 24405181Sgd78059 * (vendorid == DAVICOM_VENDOR_ID) && (deviceid == DEVICE_ID_9102) 24415181Sgd78059 */ 24425181Sgd78059 idp->vendor = pci_config_get16(handle, PCI_CONF_VENID); 24435181Sgd78059 idp->device = pci_config_get16(handle, PCI_CONF_DEVID); 24445181Sgd78059 idp->revision = pci_config_get8(handle, PCI_CONF_REVID); 24455181Sgd78059 24465181Sgd78059 /* 24475181Sgd78059 * Turn on Bus Master Enable bit and ensure the device is not asleep 24485181Sgd78059 */ 24495181Sgd78059 regval = pci_config_get32(handle, PCI_CONF_COMM); 24505181Sgd78059 pci_config_put32(handle, PCI_CONF_COMM, (regval | PCI_COMM_ME)); 24515181Sgd78059 24525181Sgd78059 regval = pci_config_get32(handle, PCI_DMFE_CONF_CFDD); 24535181Sgd78059 pci_config_put32(handle, PCI_DMFE_CONF_CFDD, 24545181Sgd78059 regval & ~(CFDD_SLEEP | CFDD_SNOOZE)); 24555181Sgd78059 24565181Sgd78059 pci_config_teardown(&handle); 24575181Sgd78059 return (DDI_SUCCESS); 24585181Sgd78059 } 24595181Sgd78059 24605181Sgd78059 struct ks_index { 24615181Sgd78059 int index; 24625181Sgd78059 char *name; 24635181Sgd78059 }; 24645181Sgd78059 24655181Sgd78059 static const struct ks_index ks_drv_names[] = { 24665181Sgd78059 { KS_INTERRUPT, "intr" }, 24675181Sgd78059 { KS_CYCLIC_RUN, "cyclic_run" }, 24685181Sgd78059 24695181Sgd78059 { KS_TX_STALL, "tx_stall_detect" }, 24705181Sgd78059 { KS_CHIP_ERROR, "chip_error_interrupt" }, 24715181Sgd78059 24725181Sgd78059 { KS_FACTOTUM_RUN, "factotum_run" }, 24735181Sgd78059 { KS_RECOVERY, "factotum_recover" }, 24745181Sgd78059 24755181Sgd78059 { -1, NULL } 24765181Sgd78059 }; 24775181Sgd78059 24785181Sgd78059 static void 24795181Sgd78059 dmfe_init_kstats(dmfe_t *dmfep, int instance) 24805181Sgd78059 { 24815181Sgd78059 kstat_t *ksp; 24825181Sgd78059 kstat_named_t *knp; 24835181Sgd78059 const struct ks_index *ksip; 24845181Sgd78059 24855181Sgd78059 /* no need to create MII stats, the mac module already does it */ 24865181Sgd78059 24875181Sgd78059 /* Create and initialise driver-defined kstats */ 24885181Sgd78059 ksp = kstat_create(DRIVER_NAME, instance, "dmfe_events", "net", 24895181Sgd78059 KSTAT_TYPE_NAMED, KS_DRV_COUNT, KSTAT_FLAG_PERSISTENT); 24905181Sgd78059 if (ksp != NULL) { 24915181Sgd78059 for (knp = ksp->ks_data, ksip = ks_drv_names; 24925181Sgd78059 ksip->name != NULL; ++ksip) { 24935181Sgd78059 kstat_named_init(&knp[ksip->index], ksip->name, 24945181Sgd78059 KSTAT_DATA_UINT64); 24955181Sgd78059 } 24965181Sgd78059 dmfep->ksp_drv = ksp; 24975181Sgd78059 dmfep->knp_drv = knp; 24985181Sgd78059 kstat_install(ksp); 24995181Sgd78059 } else { 25005181Sgd78059 dmfe_error(dmfep, "kstat_create() for dmfe_events failed"); 25015181Sgd78059 } 25025181Sgd78059 } 25035181Sgd78059 25045181Sgd78059 static int 25055181Sgd78059 dmfe_resume(dev_info_t *devinfo) 25065181Sgd78059 { 25075181Sgd78059 dmfe_t *dmfep; /* Our private data */ 25085181Sgd78059 chip_id_t chipid; 2509*9860Sgdamore@opensolaris.org boolean_t restart = B_FALSE; 25105181Sgd78059 25115181Sgd78059 dmfep = ddi_get_driver_private(devinfo); 25125181Sgd78059 if (dmfep == NULL) 25135181Sgd78059 return (DDI_FAILURE); 25145181Sgd78059 25155181Sgd78059 /* 25165181Sgd78059 * Refuse to resume if the data structures aren't consistent 25175181Sgd78059 */ 25185181Sgd78059 if (dmfep->devinfo != devinfo) 25195181Sgd78059 return (DDI_FAILURE); 25205181Sgd78059 25215181Sgd78059 /* 25225181Sgd78059 * Refuse to resume if the chip's changed its identity (*boggle*) 25235181Sgd78059 */ 25245181Sgd78059 if (dmfe_config_init(dmfep, &chipid) != DDI_SUCCESS) 25255181Sgd78059 return (DDI_FAILURE); 25265181Sgd78059 if (chipid.vendor != dmfep->chipid.vendor) 25275181Sgd78059 return (DDI_FAILURE); 25285181Sgd78059 if (chipid.device != dmfep->chipid.device) 25295181Sgd78059 return (DDI_FAILURE); 25305181Sgd78059 if (chipid.revision != dmfep->chipid.revision) 25315181Sgd78059 return (DDI_FAILURE); 25325181Sgd78059 2533*9860Sgdamore@opensolaris.org mutex_enter(dmfep->oplock); 2534*9860Sgdamore@opensolaris.org mutex_enter(dmfep->txlock); 2535*9860Sgdamore@opensolaris.org dmfep->suspended = B_FALSE; 2536*9860Sgdamore@opensolaris.org mutex_exit(dmfep->txlock); 2537*9860Sgdamore@opensolaris.org 25385181Sgd78059 /* 25395181Sgd78059 * All OK, reinitialise h/w & kick off MAC scheduling 25405181Sgd78059 */ 2541*9860Sgdamore@opensolaris.org if (dmfep->mac_state == DMFE_MAC_STARTED) { 2542*9860Sgdamore@opensolaris.org dmfe_restart(dmfep); 2543*9860Sgdamore@opensolaris.org restart = B_TRUE; 2544*9860Sgdamore@opensolaris.org } 25455181Sgd78059 mutex_exit(dmfep->oplock); 2546*9860Sgdamore@opensolaris.org 2547*9860Sgdamore@opensolaris.org if (restart) { 2548*9860Sgdamore@opensolaris.org mii_resume(dmfep->mii); 2549*9860Sgdamore@opensolaris.org mac_tx_update(dmfep->mh); 2550*9860Sgdamore@opensolaris.org } 25515181Sgd78059 return (DDI_SUCCESS); 25525181Sgd78059 } 25535181Sgd78059 25545181Sgd78059 /* 25555181Sgd78059 * attach(9E) -- Attach a device to the system 25565181Sgd78059 * 25575181Sgd78059 * Called once for each board successfully probed. 25585181Sgd78059 */ 25595181Sgd78059 static int 25605181Sgd78059 dmfe_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) 25615181Sgd78059 { 25625181Sgd78059 mac_register_t *macp; 25635181Sgd78059 dmfe_t *dmfep; /* Our private data */ 25645181Sgd78059 uint32_t csr6; 25655181Sgd78059 int instance; 25665181Sgd78059 int err; 25675181Sgd78059 25685181Sgd78059 instance = ddi_get_instance(devinfo); 25695181Sgd78059 25705181Sgd78059 switch (cmd) { 25715181Sgd78059 default: 25725181Sgd78059 return (DDI_FAILURE); 25735181Sgd78059 25745181Sgd78059 case DDI_RESUME: 25755181Sgd78059 return (dmfe_resume(devinfo)); 25765181Sgd78059 25775181Sgd78059 case DDI_ATTACH: 25785181Sgd78059 break; 25795181Sgd78059 } 25805181Sgd78059 25815181Sgd78059 dmfep = kmem_zalloc(sizeof (*dmfep), KM_SLEEP); 25825181Sgd78059 ddi_set_driver_private(devinfo, dmfep); 25835181Sgd78059 dmfep->devinfo = devinfo; 25845181Sgd78059 dmfep->dmfe_guard = DMFE_GUARD; 25855181Sgd78059 25865181Sgd78059 /* 25875181Sgd78059 * Initialize more fields in DMFE private data 25885181Sgd78059 * Determine the local MAC address 25895181Sgd78059 */ 25905181Sgd78059 #if DMFEDEBUG 25915181Sgd78059 dmfep->debug = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 0, 25925181Sgd78059 debug_propname, dmfe_debug); 25935181Sgd78059 #endif /* DMFEDEBUG */ 25945181Sgd78059 dmfep->cycid = NULL; 25955181Sgd78059 (void) snprintf(dmfep->ifname, sizeof (dmfep->ifname), "dmfe%d", 25965181Sgd78059 instance); 25975181Sgd78059 25985181Sgd78059 /* 25995181Sgd78059 * Check for custom "opmode-reg-value" property; 26005181Sgd78059 * if none, use the defaults below for CSR6 ... 26015181Sgd78059 */ 26025181Sgd78059 csr6 = TX_THRESHOLD_HI | STORE_AND_FORWARD | EXT_MII_IF | OPN_25_MB1; 26035181Sgd78059 dmfep->opmode = ddi_prop_get_int(DDI_DEV_T_ANY, devinfo, 26045181Sgd78059 DDI_PROP_DONTPASS, opmode_propname, csr6); 26055181Sgd78059 26065181Sgd78059 /* 26075181Sgd78059 * Read chip ID & set up config space command register(s) 26085181Sgd78059 */ 26095181Sgd78059 if (dmfe_config_init(dmfep, &dmfep->chipid) != DDI_SUCCESS) { 26105181Sgd78059 dmfe_error(dmfep, "dmfe_config_init() failed"); 26115181Sgd78059 goto attach_fail; 26125181Sgd78059 } 26135181Sgd78059 26145181Sgd78059 /* 26155181Sgd78059 * Map operating registers 26165181Sgd78059 */ 26175181Sgd78059 err = ddi_regs_map_setup(devinfo, DMFE_PCI_RNUMBER, 26185181Sgd78059 &dmfep->io_reg, 0, 0, &dmfe_reg_accattr, &dmfep->io_handle); 26195181Sgd78059 if (err != DDI_SUCCESS) { 26205181Sgd78059 dmfe_error(dmfep, "ddi_regs_map_setup() failed"); 26215181Sgd78059 goto attach_fail; 26225181Sgd78059 } 26235181Sgd78059 26245181Sgd78059 /* 26255181Sgd78059 * Get our MAC address. 26265181Sgd78059 */ 26275181Sgd78059 dmfe_find_mac_address(dmfep); 26285181Sgd78059 26295181Sgd78059 /* 26305181Sgd78059 * Allocate the TX and RX descriptors/buffers. 26315181Sgd78059 */ 26325181Sgd78059 dmfep->tx.n_desc = dmfe_tx_desc; 26335181Sgd78059 dmfep->rx.n_desc = dmfe_rx_desc; 26345181Sgd78059 err = dmfe_alloc_bufs(dmfep); 26355181Sgd78059 if (err != DDI_SUCCESS) { 26365181Sgd78059 goto attach_fail; 26375181Sgd78059 } 26385181Sgd78059 26395181Sgd78059 /* 26405181Sgd78059 * Add the softint handler 26415181Sgd78059 */ 26425181Sgd78059 if (ddi_add_softintr(devinfo, DDI_SOFTINT_LOW, &dmfep->factotum_id, 26435181Sgd78059 NULL, NULL, dmfe_factotum, (caddr_t)dmfep) != DDI_SUCCESS) { 26445181Sgd78059 dmfe_error(dmfep, "ddi_add_softintr() failed"); 26455181Sgd78059 goto attach_fail; 26465181Sgd78059 } 26475181Sgd78059 dmfep->progress |= PROGRESS_SOFTINT; 26485181Sgd78059 26495181Sgd78059 /* 26505181Sgd78059 * Add the h/w interrupt handler & initialise mutexen 26515181Sgd78059 */ 2652*9860Sgdamore@opensolaris.org if (ddi_get_iblock_cookie(devinfo, 0, &dmfep->iblk) != DDI_SUCCESS) { 2653*9860Sgdamore@opensolaris.org dmfe_error(dmfep, "ddi_get_iblock_cookie() failed"); 2654*9860Sgdamore@opensolaris.org goto attach_fail; 2655*9860Sgdamore@opensolaris.org } 2656*9860Sgdamore@opensolaris.org 2657*9860Sgdamore@opensolaris.org mutex_init(dmfep->milock, NULL, MUTEX_DRIVER, NULL); 2658*9860Sgdamore@opensolaris.org mutex_init(dmfep->oplock, NULL, MUTEX_DRIVER, dmfep->iblk); 2659*9860Sgdamore@opensolaris.org mutex_init(dmfep->rxlock, NULL, MUTEX_DRIVER, dmfep->iblk); 2660*9860Sgdamore@opensolaris.org mutex_init(dmfep->txlock, NULL, MUTEX_DRIVER, dmfep->iblk); 2661*9860Sgdamore@opensolaris.org dmfep->progress |= PROGRESS_MUTEX; 2662*9860Sgdamore@opensolaris.org 2663*9860Sgdamore@opensolaris.org if (ddi_add_intr(devinfo, 0, NULL, NULL, 26645181Sgd78059 dmfe_interrupt, (caddr_t)dmfep) != DDI_SUCCESS) { 26655181Sgd78059 dmfe_error(dmfep, "ddi_add_intr() failed"); 26665181Sgd78059 goto attach_fail; 26675181Sgd78059 } 26685181Sgd78059 dmfep->progress |= PROGRESS_HWINT; 26695181Sgd78059 26705181Sgd78059 /* 26715181Sgd78059 * Create & initialise named kstats 26725181Sgd78059 */ 26735181Sgd78059 dmfe_init_kstats(dmfep, instance); 26745181Sgd78059 26755181Sgd78059 /* 26765181Sgd78059 * Reset & initialise the chip and the ring buffers 26775181Sgd78059 * Initialise the (internal) PHY 26785181Sgd78059 */ 26795181Sgd78059 mutex_enter(dmfep->oplock); 26805181Sgd78059 mutex_enter(dmfep->rxlock); 26815181Sgd78059 mutex_enter(dmfep->txlock); 26825181Sgd78059 26835181Sgd78059 dmfe_reset(dmfep); 26845181Sgd78059 26855181Sgd78059 /* 26865181Sgd78059 * Prepare the setup packet 26875181Sgd78059 */ 26885181Sgd78059 bzero(dmfep->tx_desc.setup_va, SETUPBUF_SIZE); 26895181Sgd78059 bzero(dmfep->mcast_refs, MCASTBUF_SIZE); 26905181Sgd78059 dmfep->addr_set = B_FALSE; 26915181Sgd78059 dmfep->opmode &= ~(PROMISC_MODE | PASS_MULTICAST); 26925181Sgd78059 dmfep->mac_state = DMFE_MAC_RESET; 26935181Sgd78059 26945181Sgd78059 mutex_exit(dmfep->txlock); 26955181Sgd78059 mutex_exit(dmfep->rxlock); 26965181Sgd78059 mutex_exit(dmfep->oplock); 26975181Sgd78059 26985181Sgd78059 if (dmfe_init_phy(dmfep) != B_TRUE) 26995181Sgd78059 goto attach_fail; 27005181Sgd78059 27015181Sgd78059 /* 27025181Sgd78059 * Send a reasonable setup frame. This configures our starting 27035181Sgd78059 * address and the broadcast address. 27045181Sgd78059 */ 27055181Sgd78059 (void) dmfe_m_unicst(dmfep, dmfep->curr_addr); 27065181Sgd78059 27075181Sgd78059 /* 27085181Sgd78059 * Initialize pointers to device specific functions which 27095181Sgd78059 * will be used by the generic layer. 27105181Sgd78059 */ 27115181Sgd78059 if ((macp = mac_alloc(MAC_VERSION)) == NULL) 27125181Sgd78059 goto attach_fail; 27135181Sgd78059 macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 27145181Sgd78059 macp->m_driver = dmfep; 27155181Sgd78059 macp->m_dip = devinfo; 27165181Sgd78059 macp->m_src_addr = dmfep->curr_addr; 27175181Sgd78059 macp->m_callbacks = &dmfe_m_callbacks; 27185181Sgd78059 macp->m_min_sdu = 0; 27195181Sgd78059 macp->m_max_sdu = ETHERMTU; 27205895Syz147064 macp->m_margin = VLAN_TAGSZ; 27215181Sgd78059 27225181Sgd78059 /* 27235181Sgd78059 * Finally, we're ready to register ourselves with the MAC layer 27245181Sgd78059 * interface; if this succeeds, we're all ready to start() 27255181Sgd78059 */ 27265181Sgd78059 err = mac_register(macp, &dmfep->mh); 27275181Sgd78059 mac_free(macp); 27285181Sgd78059 if (err != 0) 27295181Sgd78059 goto attach_fail; 27305181Sgd78059 ASSERT(dmfep->dmfe_guard == DMFE_GUARD); 27315181Sgd78059 27325181Sgd78059 /* 27335181Sgd78059 * Install the cyclic callback that we use to check for link 27345181Sgd78059 * status, transmit stall, etc. The cyclic callback (dmfe_cyclic()) 27355181Sgd78059 * is invoked in kernel context then. 27365181Sgd78059 */ 27375181Sgd78059 ASSERT(dmfep->cycid == NULL); 27385181Sgd78059 dmfep->cycid = ddi_periodic_add(dmfe_cyclic, dmfep, 27395181Sgd78059 dmfe_tick_us * 1000, DDI_IPL_0); 27405181Sgd78059 return (DDI_SUCCESS); 27415181Sgd78059 27425181Sgd78059 attach_fail: 27435181Sgd78059 dmfe_unattach(dmfep); 27445181Sgd78059 return (DDI_FAILURE); 27455181Sgd78059 } 27465181Sgd78059 27475181Sgd78059 /* 27485181Sgd78059 * dmfe_suspend() -- suspend transmit/receive for powerdown 27495181Sgd78059 */ 27505181Sgd78059 static int 27515181Sgd78059 dmfe_suspend(dmfe_t *dmfep) 27525181Sgd78059 { 27535181Sgd78059 /* 27545181Sgd78059 * Just stop processing ... 27555181Sgd78059 */ 2756*9860Sgdamore@opensolaris.org mii_suspend(dmfep->mii); 27575181Sgd78059 mutex_enter(dmfep->oplock); 27585181Sgd78059 dmfe_stop(dmfep); 2759*9860Sgdamore@opensolaris.org 2760*9860Sgdamore@opensolaris.org mutex_enter(dmfep->txlock); 2761*9860Sgdamore@opensolaris.org dmfep->suspended = B_TRUE; 2762*9860Sgdamore@opensolaris.org mutex_exit(dmfep->txlock); 27635181Sgd78059 mutex_exit(dmfep->oplock); 27645181Sgd78059 27655181Sgd78059 return (DDI_SUCCESS); 27665181Sgd78059 } 27675181Sgd78059 27685181Sgd78059 /* 27695181Sgd78059 * detach(9E) -- Detach a device from the system 27705181Sgd78059 */ 27715181Sgd78059 static int 27725181Sgd78059 dmfe_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd) 27735181Sgd78059 { 27745181Sgd78059 dmfe_t *dmfep; 27755181Sgd78059 27765181Sgd78059 dmfep = ddi_get_driver_private(devinfo); 27775181Sgd78059 27785181Sgd78059 switch (cmd) { 27795181Sgd78059 default: 27805181Sgd78059 return (DDI_FAILURE); 27815181Sgd78059 27825181Sgd78059 case DDI_SUSPEND: 27835181Sgd78059 return (dmfe_suspend(dmfep)); 27845181Sgd78059 27855181Sgd78059 case DDI_DETACH: 27865181Sgd78059 break; 27875181Sgd78059 } 27885181Sgd78059 27895181Sgd78059 /* 27905181Sgd78059 * Unregister from the MAC subsystem. This can fail, in 27915181Sgd78059 * particular if there are DLPI style-2 streams still open - 27925181Sgd78059 * in which case we just return failure without shutting 27935181Sgd78059 * down chip operations. 27945181Sgd78059 */ 27955181Sgd78059 if (mac_unregister(dmfep->mh) != DDI_SUCCESS) 27965181Sgd78059 return (DDI_FAILURE); 27975181Sgd78059 27985181Sgd78059 /* 27995181Sgd78059 * All activity stopped, so we can clean up & exit 28005181Sgd78059 */ 28015181Sgd78059 dmfe_unattach(dmfep); 28025181Sgd78059 return (DDI_SUCCESS); 28035181Sgd78059 } 28045181Sgd78059 28055181Sgd78059 28065181Sgd78059 /* 28075181Sgd78059 * ========== Module Loading Data & Entry Points ========== 28085181Sgd78059 */ 28095181Sgd78059 28105181Sgd78059 DDI_DEFINE_STREAM_OPS(dmfe_dev_ops, nulldev, nulldev, dmfe_attach, dmfe_detach, 28117656SSherry.Moore@Sun.COM nodev, NULL, D_MP, NULL, ddi_quiesce_not_supported); 28125181Sgd78059 28135181Sgd78059 static struct modldrv dmfe_modldrv = { 28145181Sgd78059 &mod_driverops, /* Type of module. This one is a driver */ 28155181Sgd78059 dmfe_ident, /* short description */ 28165181Sgd78059 &dmfe_dev_ops /* driver specific ops */ 28175181Sgd78059 }; 28185181Sgd78059 28195181Sgd78059 static struct modlinkage modlinkage = { 28205181Sgd78059 MODREV_1, (void *)&dmfe_modldrv, NULL 28215181Sgd78059 }; 28225181Sgd78059 28235181Sgd78059 int 28245181Sgd78059 _info(struct modinfo *modinfop) 28255181Sgd78059 { 28265181Sgd78059 return (mod_info(&modlinkage, modinfop)); 28275181Sgd78059 } 28285181Sgd78059 28295181Sgd78059 int 28305181Sgd78059 _init(void) 28315181Sgd78059 { 28325181Sgd78059 uint32_t tmp100; 28335181Sgd78059 uint32_t tmp10; 28345181Sgd78059 int i; 28355181Sgd78059 int status; 28365181Sgd78059 28375181Sgd78059 /* Calculate global timing parameters */ 28385181Sgd78059 tmp100 = (dmfe_tx100_stall_us+dmfe_tick_us-1)/dmfe_tick_us; 28395181Sgd78059 tmp10 = (dmfe_tx10_stall_us+dmfe_tick_us-1)/dmfe_tick_us; 28405181Sgd78059 28415181Sgd78059 for (i = 0; i <= TX_PROCESS_MAX_STATE; ++i) { 28425181Sgd78059 switch (i) { 28435181Sgd78059 case TX_PROCESS_STATE(TX_PROCESS_FETCH_DATA): 28445181Sgd78059 case TX_PROCESS_STATE(TX_PROCESS_WAIT_END): 28455181Sgd78059 /* 28465181Sgd78059 * The chip doesn't spontaneously recover from 28475181Sgd78059 * a stall in these states, so we reset early 28485181Sgd78059 */ 28495181Sgd78059 stall_100_tix[i] = tmp100; 28505181Sgd78059 stall_10_tix[i] = tmp10; 28515181Sgd78059 break; 28525181Sgd78059 28535181Sgd78059 case TX_PROCESS_STATE(TX_PROCESS_SUSPEND): 28545181Sgd78059 default: 28555181Sgd78059 /* 28565181Sgd78059 * The chip has been seen to spontaneously recover 28575181Sgd78059 * after an apparent stall in the SUSPEND state, 28585181Sgd78059 * so we'll allow it rather longer to do so. As 28595181Sgd78059 * stalls in other states have not been observed, 28605181Sgd78059 * we'll use long timeouts for them too ... 28615181Sgd78059 */ 28625181Sgd78059 stall_100_tix[i] = tmp100 * 20; 28635181Sgd78059 stall_10_tix[i] = tmp10 * 20; 28645181Sgd78059 break; 28655181Sgd78059 } 28665181Sgd78059 } 28675181Sgd78059 28685181Sgd78059 mac_init_ops(&dmfe_dev_ops, "dmfe"); 28695181Sgd78059 status = mod_install(&modlinkage); 28705181Sgd78059 if (status == DDI_SUCCESS) 28715181Sgd78059 dmfe_log_init(); 28725181Sgd78059 28735181Sgd78059 return (status); 28745181Sgd78059 } 28755181Sgd78059 28765181Sgd78059 int 28775181Sgd78059 _fini(void) 28785181Sgd78059 { 28795181Sgd78059 int status; 28805181Sgd78059 28815181Sgd78059 status = mod_remove(&modlinkage); 28825181Sgd78059 if (status == DDI_SUCCESS) { 28835181Sgd78059 mac_fini_ops(&dmfe_dev_ops); 28845181Sgd78059 dmfe_log_fini(); 28855181Sgd78059 } 28865181Sgd78059 28875181Sgd78059 return (status); 28885181Sgd78059 } 2889