1015a6ef6SSaurabh Misra /* 2015a6ef6SSaurabh Misra * CDDL HEADER START 3015a6ef6SSaurabh Misra * 4015a6ef6SSaurabh Misra * The contents of this file are subject to the terms of the 5015a6ef6SSaurabh Misra * Common Development and Distribution License (the "License"). 6015a6ef6SSaurabh Misra * You may not use this file except in compliance with the License. 7015a6ef6SSaurabh Misra * 8015a6ef6SSaurabh Misra * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9015a6ef6SSaurabh Misra * or http://www.opensolaris.org/os/licensing. 10015a6ef6SSaurabh Misra * See the License for the specific language governing permissions 11015a6ef6SSaurabh Misra * and limitations under the License. 12015a6ef6SSaurabh Misra * 13015a6ef6SSaurabh Misra * When distributing Covered Code, include this CDDL HEADER in each 14015a6ef6SSaurabh Misra * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15015a6ef6SSaurabh Misra * If applicable, add the following below this CDDL HEADER, with the 16015a6ef6SSaurabh Misra * fields enclosed by brackets "[]" replaced with your own identifying 17015a6ef6SSaurabh Misra * information: Portions Copyright [yyyy] [name of copyright owner] 18015a6ef6SSaurabh Misra * 19015a6ef6SSaurabh Misra * CDDL HEADER END 20015a6ef6SSaurabh Misra */ 21015a6ef6SSaurabh Misra 22015a6ef6SSaurabh Misra /* 23015a6ef6SSaurabh Misra * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24015a6ef6SSaurabh Misra * Use is subject to license terms. 25015a6ef6SSaurabh Misra */ 26015a6ef6SSaurabh Misra 27015a6ef6SSaurabh Misra #include <sys/types.h> 28015a6ef6SSaurabh Misra #include <sys/stream.h> 29015a6ef6SSaurabh Misra #include <sys/strsun.h> 30015a6ef6SSaurabh Misra #include <sys/stat.h> 31015a6ef6SSaurabh Misra #include <sys/modctl.h> 32015a6ef6SSaurabh Misra #include <sys/ethernet.h> 33015a6ef6SSaurabh Misra #include <sys/debug.h> 34015a6ef6SSaurabh Misra #include <sys/conf.h> 35015a6ef6SSaurabh Misra #include <sys/mii.h> 36015a6ef6SSaurabh Misra #include <sys/miiregs.h> 37015a6ef6SSaurabh Misra #include <sys/sysmacros.h> 38015a6ef6SSaurabh Misra #include <sys/dditypes.h> 39015a6ef6SSaurabh Misra #include <sys/ddi.h> 40015a6ef6SSaurabh Misra #include <sys/sunddi.h> 41015a6ef6SSaurabh Misra #include <sys/byteorder.h> 42015a6ef6SSaurabh Misra #include <sys/note.h> 43015a6ef6SSaurabh Misra #include <sys/vlan.h> 44015a6ef6SSaurabh Misra #include <sys/stream.h> 45015a6ef6SSaurabh Misra 46015a6ef6SSaurabh Misra #include "atge.h" 47015a6ef6SSaurabh Misra #include "atge_l1e_reg.h" 48015a6ef6SSaurabh Misra #include "atge_cmn_reg.h" 49015a6ef6SSaurabh Misra 50015a6ef6SSaurabh Misra /* 51015a6ef6SSaurabh Misra * L1E specfic functions. 52015a6ef6SSaurabh Misra */ 53015a6ef6SSaurabh Misra void atge_l1e_device_reset(atge_t *); 54015a6ef6SSaurabh Misra void atge_l1e_stop_rx_mac(atge_t *); 55015a6ef6SSaurabh Misra void atge_l1e_stop_tx_mac(atge_t *); 56015a6ef6SSaurabh Misra 57015a6ef6SSaurabh Misra static ddi_dma_attr_t atge_l1e_dma_attr_tx_desc = { 58015a6ef6SSaurabh Misra DMA_ATTR_V0, /* dma_attr_version */ 59015a6ef6SSaurabh Misra 0, /* dma_attr_addr_lo */ 60015a6ef6SSaurabh Misra 0x0000ffffffffull, /* dma_attr_addr_hi */ 61015a6ef6SSaurabh Misra 0x0000ffffffffull, /* dma_attr_count_max */ 62015a6ef6SSaurabh Misra L1E_TX_RING_ALIGN, /* dma_attr_align */ 63015a6ef6SSaurabh Misra 0x0000fffc, /* dma_attr_burstsizes */ 64015a6ef6SSaurabh Misra 1, /* dma_attr_minxfer */ 65015a6ef6SSaurabh Misra 0x0000ffffffffull, /* dma_attr_maxxfer */ 66015a6ef6SSaurabh Misra 0x0000ffffffffull, /* dma_attr_seg */ 67015a6ef6SSaurabh Misra 1, /* dma_attr_sgllen */ 68015a6ef6SSaurabh Misra 1, /* dma_attr_granular */ 69015a6ef6SSaurabh Misra 0 /* dma_attr_flags */ 70015a6ef6SSaurabh Misra }; 71015a6ef6SSaurabh Misra 72015a6ef6SSaurabh Misra static ddi_dma_attr_t atge_l1e_dma_attr_rx_desc = { 73015a6ef6SSaurabh Misra DMA_ATTR_V0, /* dma_attr_version */ 74015a6ef6SSaurabh Misra 0, /* dma_attr_addr_lo */ 75015a6ef6SSaurabh Misra 0x0000ffffffffull, /* dma_attr_addr_hi */ 76015a6ef6SSaurabh Misra 0x0000ffffffffull, /* dma_attr_count_max */ 77015a6ef6SSaurabh Misra L1E_RX_PAGE_ALIGN, /* dma_attr_align */ 78015a6ef6SSaurabh Misra 0x0000fffc, /* dma_attr_burstsizes */ 79015a6ef6SSaurabh Misra 1, /* dma_attr_minxfer */ 80015a6ef6SSaurabh Misra 0x0000ffffffffull, /* dma_attr_maxxfer */ 81015a6ef6SSaurabh Misra 0x0000ffffffffull, /* dma_attr_seg */ 82015a6ef6SSaurabh Misra 1, /* dma_attr_sgllen */ 83015a6ef6SSaurabh Misra 1, /* dma_attr_granular */ 84015a6ef6SSaurabh Misra 0 /* dma_attr_flags */ 85015a6ef6SSaurabh Misra }; 86015a6ef6SSaurabh Misra 87015a6ef6SSaurabh Misra static ddi_dma_attr_t atge_l1e_dma_attr_cmb = { 88015a6ef6SSaurabh Misra DMA_ATTR_V0, /* dma_attr_version */ 89015a6ef6SSaurabh Misra 0, /* dma_attr_addr_lo */ 90015a6ef6SSaurabh Misra 0x0000ffffffffull, /* dma_attr_addr_hi */ 91015a6ef6SSaurabh Misra 0x0000ffffffffull, /* dma_attr_count_max */ 92015a6ef6SSaurabh Misra L1E_CMB_ALIGN, /* dma_attr_align */ 93015a6ef6SSaurabh Misra 0x0000fffc, /* dma_attr_burstsizes */ 94015a6ef6SSaurabh Misra 1, /* dma_attr_minxfer */ 95015a6ef6SSaurabh Misra 0x0000ffffffffull, /* dma_attr_maxxfer */ 96015a6ef6SSaurabh Misra 0x0000ffffffffull, /* dma_attr_seg */ 97015a6ef6SSaurabh Misra 1, /* dma_attr_sgllen */ 98015a6ef6SSaurabh Misra 1, /* dma_attr_granular */ 99015a6ef6SSaurabh Misra 0 /* dma_attr_flags */ 100015a6ef6SSaurabh Misra }; 101015a6ef6SSaurabh Misra 102015a6ef6SSaurabh Misra void atge_l1e_rx_next_pkt(atge_t *, uint32_t); 103015a6ef6SSaurabh Misra 104015a6ef6SSaurabh Misra void 105015a6ef6SSaurabh Misra atge_rx_desc_free(atge_t *atgep) 106015a6ef6SSaurabh Misra { 107015a6ef6SSaurabh Misra atge_l1e_data_t *l1e; 108015a6ef6SSaurabh Misra atge_dma_t *dma; 109015a6ef6SSaurabh Misra int pages; 110015a6ef6SSaurabh Misra 111015a6ef6SSaurabh Misra l1e = (atge_l1e_data_t *)atgep->atge_private_data; 112015a6ef6SSaurabh Misra if (l1e == NULL) 113015a6ef6SSaurabh Misra return; 114015a6ef6SSaurabh Misra 115015a6ef6SSaurabh Misra if (l1e->atge_l1e_rx_page == NULL) 116015a6ef6SSaurabh Misra return; 117015a6ef6SSaurabh Misra 118015a6ef6SSaurabh Misra for (pages = 0; pages < L1E_RX_PAGES; pages++) { 119015a6ef6SSaurabh Misra dma = l1e->atge_l1e_rx_page[pages]; 120015a6ef6SSaurabh Misra if (dma != NULL) { 121015a6ef6SSaurabh Misra (void) ddi_dma_unbind_handle(dma->hdl); 122015a6ef6SSaurabh Misra ddi_dma_mem_free(&dma->acchdl); 123015a6ef6SSaurabh Misra ddi_dma_free_handle(&dma->hdl); 124015a6ef6SSaurabh Misra kmem_free(dma, sizeof (atge_dma_t)); 125015a6ef6SSaurabh Misra } 126015a6ef6SSaurabh Misra } 127015a6ef6SSaurabh Misra 128015a6ef6SSaurabh Misra kmem_free(l1e->atge_l1e_rx_page, L1E_RX_PAGES * sizeof (atge_dma_t *)); 129015a6ef6SSaurabh Misra l1e->atge_l1e_rx_page = NULL; 130015a6ef6SSaurabh Misra } 131015a6ef6SSaurabh Misra 132015a6ef6SSaurabh Misra int 133015a6ef6SSaurabh Misra atge_l1e_alloc_dma(atge_t *atgep) 134015a6ef6SSaurabh Misra { 135015a6ef6SSaurabh Misra atge_dma_t *dma; 136015a6ef6SSaurabh Misra atge_l1e_data_t *l1e; 137015a6ef6SSaurabh Misra int err; 138015a6ef6SSaurabh Misra int pages; 139015a6ef6SSaurabh Misra int guard_size; 140015a6ef6SSaurabh Misra 141015a6ef6SSaurabh Misra l1e = kmem_zalloc(sizeof (atge_l1e_data_t), KM_SLEEP); 142015a6ef6SSaurabh Misra atgep->atge_private_data = l1e; 143015a6ef6SSaurabh Misra 144015a6ef6SSaurabh Misra /* 145015a6ef6SSaurabh Misra * Allocate TX ring descriptor. 146015a6ef6SSaurabh Misra */ 147015a6ef6SSaurabh Misra atgep->atge_tx_buf_len = atgep->atge_mtu + 148015a6ef6SSaurabh Misra sizeof (struct ether_header) + VLAN_TAGSZ + ETHERFCSL; 149015a6ef6SSaurabh Misra atgep->atge_tx_ring = kmem_alloc(sizeof (atge_ring_t), KM_SLEEP); 150015a6ef6SSaurabh Misra atgep->atge_tx_ring->r_atge = atgep; 151015a6ef6SSaurabh Misra atgep->atge_tx_ring->r_desc_ring = NULL; 152015a6ef6SSaurabh Misra dma = atge_alloc_a_dma_blk(atgep, &atge_l1e_dma_attr_tx_desc, 153*0eb090a7SSaurabh Misra ATGE_TX_RING_SZ, DDI_DMA_RDWR); 154015a6ef6SSaurabh Misra if (dma == NULL) { 155015a6ef6SSaurabh Misra ATGE_DB(("%s :%s failed", 156015a6ef6SSaurabh Misra atgep->atge_name, __func__)); 157*0eb090a7SSaurabh Misra return (DDI_FAILURE); 158015a6ef6SSaurabh Misra } 159015a6ef6SSaurabh Misra atgep->atge_tx_ring->r_desc_ring = dma; 160015a6ef6SSaurabh Misra 161015a6ef6SSaurabh Misra /* 162015a6ef6SSaurabh Misra * Allocate DMA buffers for TX ring. 163015a6ef6SSaurabh Misra */ 164*0eb090a7SSaurabh Misra err = atge_alloc_buffers(atgep->atge_tx_ring, ATGE_TX_RING_CNT, 165015a6ef6SSaurabh Misra atgep->atge_tx_buf_len, DDI_DMA_WRITE); 166*0eb090a7SSaurabh Misra if (err != DDI_SUCCESS) { 167015a6ef6SSaurabh Misra ATGE_DB(("%s :%s() TX buffers failed", 168015a6ef6SSaurabh Misra atgep->atge_name, __func__)); 169015a6ef6SSaurabh Misra return (err); 170015a6ef6SSaurabh Misra } 171015a6ef6SSaurabh Misra 172015a6ef6SSaurabh Misra /* 173015a6ef6SSaurabh Misra * Allocate RX pages. 174015a6ef6SSaurabh Misra */ 175015a6ef6SSaurabh Misra atgep->atge_rx_buf_len = atgep->atge_mtu + 176015a6ef6SSaurabh Misra sizeof (struct ether_header) + VLAN_TAGSZ + ETHERFCSL; 177015a6ef6SSaurabh Misra 178015a6ef6SSaurabh Misra if (atgep->atge_flags & ATGE_FLAG_JUMBO) 179015a6ef6SSaurabh Misra guard_size = L1E_JUMBO_FRAMELEN; 180015a6ef6SSaurabh Misra else 181015a6ef6SSaurabh Misra guard_size = L1E_MAX_FRAMELEN; 182015a6ef6SSaurabh Misra 183015a6ef6SSaurabh Misra l1e->atge_l1e_pagesize = ROUNDUP(guard_size + L1E_RX_PAGE_SZ, 184015a6ef6SSaurabh Misra L1E_RX_PAGE_ALIGN); 185015a6ef6SSaurabh Misra l1e->atge_l1e_rx_page = 186015a6ef6SSaurabh Misra kmem_zalloc(L1E_RX_PAGES * sizeof (atge_dma_t *), KM_SLEEP); 187015a6ef6SSaurabh Misra 188015a6ef6SSaurabh Misra ATGE_DB(("%s: %s() atge_l1e_pagesize : %d, L1E_RX_PAGE_SZ : %d", 189015a6ef6SSaurabh Misra atgep->atge_name, __func__, l1e->atge_l1e_pagesize, 190015a6ef6SSaurabh Misra L1E_RX_PAGE_SZ)); 191015a6ef6SSaurabh Misra 192*0eb090a7SSaurabh Misra err = DDI_SUCCESS; 193015a6ef6SSaurabh Misra for (pages = 0; pages < L1E_RX_PAGES; pages++) { 194015a6ef6SSaurabh Misra dma = atge_alloc_a_dma_blk(atgep, &atge_l1e_dma_attr_rx_desc, 195015a6ef6SSaurabh Misra l1e->atge_l1e_pagesize, DDI_DMA_READ); 196015a6ef6SSaurabh Misra 197015a6ef6SSaurabh Misra if (dma == NULL) { 198*0eb090a7SSaurabh Misra err = DDI_FAILURE; 199015a6ef6SSaurabh Misra break; 200015a6ef6SSaurabh Misra } 201015a6ef6SSaurabh Misra 202015a6ef6SSaurabh Misra l1e->atge_l1e_rx_page[pages] = dma; 203015a6ef6SSaurabh Misra } 204015a6ef6SSaurabh Misra 205*0eb090a7SSaurabh Misra if (err == DDI_FAILURE) { 206015a6ef6SSaurabh Misra ATGE_DB(("%s :%s RX pages failed", 207015a6ef6SSaurabh Misra atgep->atge_name, __func__)); 208*0eb090a7SSaurabh Misra return (DDI_FAILURE); 209015a6ef6SSaurabh Misra } 210015a6ef6SSaurabh Misra 211015a6ef6SSaurabh Misra /* 212015a6ef6SSaurabh Misra * Allocate CMB used for fetching interrupt status data. 213015a6ef6SSaurabh Misra */ 214015a6ef6SSaurabh Misra ATGE_DB(("%s: %s() L1E_RX_CMB_SZ : %x", atgep->atge_name, 215015a6ef6SSaurabh Misra __func__, L1E_RX_CMB_SZ)); 216015a6ef6SSaurabh Misra 217*0eb090a7SSaurabh Misra err = DDI_SUCCESS; 218015a6ef6SSaurabh Misra dma = atge_alloc_a_dma_blk(atgep, &atge_l1e_dma_attr_cmb, 219015a6ef6SSaurabh Misra L1E_RX_CMB_SZ * L1E_RX_PAGES, DDI_DMA_RDWR); 220015a6ef6SSaurabh Misra if (dma == NULL) { 221015a6ef6SSaurabh Misra ATGE_DB(("%s :%s() RX CMB failed", 222015a6ef6SSaurabh Misra atgep->atge_name, __func__)); 223*0eb090a7SSaurabh Misra return (DDI_FAILURE); 224015a6ef6SSaurabh Misra } 225015a6ef6SSaurabh Misra l1e->atge_l1e_rx_cmb = dma; 226015a6ef6SSaurabh Misra 227*0eb090a7SSaurabh Misra if (err == DDI_FAILURE) { 228015a6ef6SSaurabh Misra ATGE_DB(("%s :%s() RX CMB failed", 229015a6ef6SSaurabh Misra atgep->atge_name, __func__)); 230*0eb090a7SSaurabh Misra return (DDI_FAILURE); 231015a6ef6SSaurabh Misra } 232015a6ef6SSaurabh Misra 233015a6ef6SSaurabh Misra atgep->atge_hw_stats = kmem_zalloc(sizeof (atge_l1e_smb_t), KM_SLEEP); 234015a6ef6SSaurabh Misra 235*0eb090a7SSaurabh Misra return (DDI_SUCCESS); 236015a6ef6SSaurabh Misra } 237015a6ef6SSaurabh Misra 238015a6ef6SSaurabh Misra void 239015a6ef6SSaurabh Misra atge_l1e_free_dma(atge_t *atgep) 240015a6ef6SSaurabh Misra { 241015a6ef6SSaurabh Misra atge_l1e_data_t *l1e; 242015a6ef6SSaurabh Misra 243015a6ef6SSaurabh Misra /* 244015a6ef6SSaurabh Misra * Free TX ring. 245015a6ef6SSaurabh Misra */ 246015a6ef6SSaurabh Misra if (atgep->atge_tx_ring != NULL) { 247*0eb090a7SSaurabh Misra atge_free_buffers(atgep->atge_tx_ring, ATGE_TX_RING_CNT); 248015a6ef6SSaurabh Misra 249015a6ef6SSaurabh Misra if (atgep->atge_tx_ring->r_desc_ring != NULL) { 250015a6ef6SSaurabh Misra atge_free_a_dma_blk(atgep->atge_tx_ring->r_desc_ring); 251015a6ef6SSaurabh Misra } 252015a6ef6SSaurabh Misra 253015a6ef6SSaurabh Misra kmem_free(atgep->atge_tx_ring, sizeof (atge_ring_t)); 254015a6ef6SSaurabh Misra atgep->atge_tx_ring = NULL; 255015a6ef6SSaurabh Misra } 256015a6ef6SSaurabh Misra 257015a6ef6SSaurabh Misra l1e = atgep->atge_private_data; 258015a6ef6SSaurabh Misra if (l1e == NULL) 259015a6ef6SSaurabh Misra return; 260015a6ef6SSaurabh Misra 261015a6ef6SSaurabh Misra /* 262015a6ef6SSaurabh Misra * Free RX CMB. 263015a6ef6SSaurabh Misra */ 264015a6ef6SSaurabh Misra if (l1e->atge_l1e_rx_cmb != NULL) { 265015a6ef6SSaurabh Misra atge_free_a_dma_blk(l1e->atge_l1e_rx_cmb); 266015a6ef6SSaurabh Misra l1e->atge_l1e_rx_cmb = NULL; 267015a6ef6SSaurabh Misra } 268015a6ef6SSaurabh Misra 269015a6ef6SSaurabh Misra /* 270015a6ef6SSaurabh Misra * Free RX buffers and RX ring. 271015a6ef6SSaurabh Misra */ 272015a6ef6SSaurabh Misra atge_rx_desc_free(atgep); 273015a6ef6SSaurabh Misra 274015a6ef6SSaurabh Misra /* 275015a6ef6SSaurabh Misra * Free the memory allocated for gathering hw stats. 276015a6ef6SSaurabh Misra */ 277015a6ef6SSaurabh Misra if (atgep->atge_hw_stats != NULL) { 278015a6ef6SSaurabh Misra kmem_free(atgep->atge_hw_stats, sizeof (atge_l1e_smb_t)); 279015a6ef6SSaurabh Misra atgep->atge_hw_stats = NULL; 280015a6ef6SSaurabh Misra } 281015a6ef6SSaurabh Misra } 282015a6ef6SSaurabh Misra 283015a6ef6SSaurabh Misra void 284015a6ef6SSaurabh Misra atge_l1e_init_rx_pages(atge_t *atgep) 285015a6ef6SSaurabh Misra { 286015a6ef6SSaurabh Misra atge_l1e_data_t *l1e; 287015a6ef6SSaurabh Misra atge_dma_t *dma; 288015a6ef6SSaurabh Misra int pages; 289015a6ef6SSaurabh Misra 290015a6ef6SSaurabh Misra ASSERT(atgep != NULL); 291015a6ef6SSaurabh Misra l1e = atgep->atge_private_data; 292015a6ef6SSaurabh Misra 293015a6ef6SSaurabh Misra ASSERT(l1e != NULL); 294015a6ef6SSaurabh Misra 295015a6ef6SSaurabh Misra l1e->atge_l1e_proc_max = L1E_RX_PAGE_SZ / ETHERMIN; 296015a6ef6SSaurabh Misra l1e->atge_l1e_rx_curp = 0; 297015a6ef6SSaurabh Misra l1e->atge_l1e_rx_seqno = 0; 298015a6ef6SSaurabh Misra 299015a6ef6SSaurabh Misra for (pages = 0; pages < L1E_RX_PAGES; pages++) { 300015a6ef6SSaurabh Misra l1e->atge_l1e_rx_page_cons = 0; 301015a6ef6SSaurabh Misra l1e->atge_l1e_rx_page_prods[pages] = 0; 302015a6ef6SSaurabh Misra 303015a6ef6SSaurabh Misra 304015a6ef6SSaurabh Misra dma = l1e->atge_l1e_rx_page[pages]; 305015a6ef6SSaurabh Misra ASSERT(dma != NULL); 306015a6ef6SSaurabh Misra bzero(dma->addr, l1e->atge_l1e_pagesize); 307015a6ef6SSaurabh Misra DMA_SYNC(dma, 0, l1e->atge_l1e_pagesize, DDI_DMA_SYNC_FORDEV); 308015a6ef6SSaurabh Misra } 309015a6ef6SSaurabh Misra 310015a6ef6SSaurabh Misra dma = l1e->atge_l1e_rx_cmb; 311015a6ef6SSaurabh Misra ASSERT(dma != NULL); 312015a6ef6SSaurabh Misra bzero(dma->addr, L1E_RX_CMB_SZ * L1E_RX_PAGES); 313015a6ef6SSaurabh Misra DMA_SYNC(dma, 0, L1E_RX_CMB_SZ * L1E_RX_PAGES, DDI_DMA_SYNC_FORDEV); 314015a6ef6SSaurabh Misra } 315015a6ef6SSaurabh Misra 316015a6ef6SSaurabh Misra void 317015a6ef6SSaurabh Misra atge_l1e_init_tx_ring(atge_t *atgep) 318015a6ef6SSaurabh Misra { 319015a6ef6SSaurabh Misra ASSERT(atgep != NULL); 320015a6ef6SSaurabh Misra ASSERT(atgep->atge_tx_ring != NULL); 321015a6ef6SSaurabh Misra ASSERT(atgep->atge_tx_ring->r_desc_ring != NULL); 322015a6ef6SSaurabh Misra 323015a6ef6SSaurabh Misra atgep->atge_tx_ring->r_producer = 0; 324015a6ef6SSaurabh Misra atgep->atge_tx_ring->r_consumer = 0; 325*0eb090a7SSaurabh Misra atgep->atge_tx_ring->r_avail_desc = ATGE_TX_RING_CNT; 326015a6ef6SSaurabh Misra 327*0eb090a7SSaurabh Misra bzero(atgep->atge_tx_ring->r_desc_ring->addr, ATGE_TX_RING_SZ); 328015a6ef6SSaurabh Misra 329*0eb090a7SSaurabh Misra DMA_SYNC(atgep->atge_tx_ring->r_desc_ring, 0, ATGE_TX_RING_SZ, 330015a6ef6SSaurabh Misra DDI_DMA_SYNC_FORDEV); 331015a6ef6SSaurabh Misra } 332015a6ef6SSaurabh Misra 333015a6ef6SSaurabh Misra void 334015a6ef6SSaurabh Misra atge_l1e_program_dma(atge_t *atgep) 335015a6ef6SSaurabh Misra { 336015a6ef6SSaurabh Misra atge_l1e_data_t *l1e; 337015a6ef6SSaurabh Misra uint64_t paddr; 338015a6ef6SSaurabh Misra uint32_t reg; 339015a6ef6SSaurabh Misra 340015a6ef6SSaurabh Misra l1e = (atge_l1e_data_t *)atgep->atge_private_data; 341015a6ef6SSaurabh Misra 342015a6ef6SSaurabh Misra /* 343015a6ef6SSaurabh Misra * Clear WOL status and disable all WOL feature as WOL 344015a6ef6SSaurabh Misra * would interfere Rx operation under normal environments. 345015a6ef6SSaurabh Misra */ 346015a6ef6SSaurabh Misra (void) INL(atgep, ATGE_WOL_CFG); 347015a6ef6SSaurabh Misra OUTL(atgep, ATGE_WOL_CFG, 0); 348015a6ef6SSaurabh Misra 349015a6ef6SSaurabh Misra /* 350015a6ef6SSaurabh Misra * Set Tx descriptor/RXF0/CMB base addresses. They share 351015a6ef6SSaurabh Misra * the same high address part of DMAable region. 352015a6ef6SSaurabh Misra */ 353015a6ef6SSaurabh Misra paddr = atgep->atge_tx_ring->r_desc_ring->cookie.dmac_laddress; 354015a6ef6SSaurabh Misra OUTL(atgep, ATGE_DESC_ADDR_HI, ATGE_ADDR_HI(paddr)); 355015a6ef6SSaurabh Misra OUTL(atgep, ATGE_DESC_TPD_ADDR_LO, ATGE_ADDR_LO(paddr)); 356015a6ef6SSaurabh Misra OUTL(atgep, ATGE_DESC_TPD_CNT, 357*0eb090a7SSaurabh Misra (ATGE_TX_RING_CNT << DESC_TPD_CNT_SHIFT) & DESC_TPD_CNT_MASK); 358015a6ef6SSaurabh Misra 359015a6ef6SSaurabh Misra /* Set Rx page base address, note we use single queue. */ 360015a6ef6SSaurabh Misra paddr = l1e->atge_l1e_rx_page[0]->cookie.dmac_laddress; 361015a6ef6SSaurabh Misra OUTL(atgep, L1E_RXF0_PAGE0_ADDR_LO, ATGE_ADDR_LO(paddr)); 362015a6ef6SSaurabh Misra paddr = l1e->atge_l1e_rx_page[1]->cookie.dmac_laddress; 363015a6ef6SSaurabh Misra OUTL(atgep, L1E_RXF0_PAGE1_ADDR_LO, ATGE_ADDR_LO(paddr)); 364015a6ef6SSaurabh Misra 365015a6ef6SSaurabh Misra /* Set Tx/Rx CMB addresses. */ 366015a6ef6SSaurabh Misra paddr = l1e->atge_l1e_rx_cmb->cookie.dmac_laddress; 367015a6ef6SSaurabh Misra OUTL(atgep, L1E_RXF0_CMB0_ADDR_LO, ATGE_ADDR_LO(paddr)); 368015a6ef6SSaurabh Misra paddr = l1e->atge_l1e_rx_cmb->cookie.dmac_laddress + sizeof (uint32_t); 369015a6ef6SSaurabh Misra OUTL(atgep, L1E_RXF0_CMB1_ADDR_LO, ATGE_ADDR_LO(paddr)); 370015a6ef6SSaurabh Misra 371015a6ef6SSaurabh Misra /* Mark RXF0 valid. */ 372015a6ef6SSaurabh Misra OUTB(atgep, L1E_RXF0_PAGE0, RXF_VALID); /* 0 */ 373015a6ef6SSaurabh Misra OUTB(atgep, L1E_RXF0_PAGE1, RXF_VALID); /* 1 */ 374015a6ef6SSaurabh Misra OUTB(atgep, L1E_RXF0_PAGE0 + 2, 0); 375015a6ef6SSaurabh Misra OUTB(atgep, L1E_RXF0_PAGE0 + 3, 0); 376015a6ef6SSaurabh Misra OUTB(atgep, L1E_RXF0_PAGE0 + 4, 0); 377015a6ef6SSaurabh Misra OUTB(atgep, L1E_RXF0_PAGE0 + 5, 0); 378015a6ef6SSaurabh Misra OUTB(atgep, L1E_RXF0_PAGE0 + 6, 0); 379015a6ef6SSaurabh Misra OUTB(atgep, L1E_RXF0_PAGE0 + 6, 0); 380015a6ef6SSaurabh Misra 381015a6ef6SSaurabh Misra /* Set Rx page size, excluding guard frame size. */ 382015a6ef6SSaurabh Misra OUTL(atgep, L1E_RXF_PAGE_SIZE, L1E_RX_PAGE_SZ); 383015a6ef6SSaurabh Misra 384015a6ef6SSaurabh Misra /* Tell hardware that we're ready to load DMA blocks. */ 385015a6ef6SSaurabh Misra OUTL(atgep, ATGE_DMA_BLOCK, DMA_BLOCK_LOAD); 386015a6ef6SSaurabh Misra 387015a6ef6SSaurabh Misra /* Set Rx/Tx interrupt trigger threshold. */ 388015a6ef6SSaurabh Misra OUTL(atgep, L1E_INT_TRIG_THRESH, (1 << INT_TRIG_RX_THRESH_SHIFT) | 389015a6ef6SSaurabh Misra (4 << INT_TRIG_TX_THRESH_SHIFT)); 390015a6ef6SSaurabh Misra 391015a6ef6SSaurabh Misra /* 392015a6ef6SSaurabh Misra * Set interrupt trigger timer, its purpose and relation 393015a6ef6SSaurabh Misra * with interrupt moderation mechanism is not clear yet. 394015a6ef6SSaurabh Misra */ 395015a6ef6SSaurabh Misra OUTL(atgep, L1E_INT_TRIG_TIMER, 396015a6ef6SSaurabh Misra ((ATGE_USECS(10) << INT_TRIG_RX_TIMER_SHIFT) | 397015a6ef6SSaurabh Misra (ATGE_USECS(1000) << INT_TRIG_TX_TIMER_SHIFT))); 398015a6ef6SSaurabh Misra 399015a6ef6SSaurabh Misra reg = ATGE_USECS(ATGE_IM_RX_TIMER_DEFAULT) << IM_TIMER_RX_SHIFT; 400015a6ef6SSaurabh Misra reg |= ATGE_USECS(ATGE_IM_TX_TIMER_DEFAULT) << IM_TIMER_TX_SHIFT; 401015a6ef6SSaurabh Misra OUTL(atgep, ATGE_IM_TIMER, reg); 402015a6ef6SSaurabh Misra 403015a6ef6SSaurabh Misra reg = INL(atgep, ATGE_MASTER_CFG); 404015a6ef6SSaurabh Misra reg &= ~(MASTER_CHIP_REV_MASK | MASTER_CHIP_ID_MASK); 405015a6ef6SSaurabh Misra reg &= ~(MASTER_IM_RX_TIMER_ENB | MASTER_IM_TX_TIMER_ENB); 406015a6ef6SSaurabh Misra reg |= MASTER_IM_RX_TIMER_ENB; 407015a6ef6SSaurabh Misra reg |= MASTER_IM_TX_TIMER_ENB; 408015a6ef6SSaurabh Misra OUTL(atgep, ATGE_MASTER_CFG, reg); 409015a6ef6SSaurabh Misra 410015a6ef6SSaurabh Misra OUTW(atgep, RX_COALSC_PKT_1e, 0); 411015a6ef6SSaurabh Misra OUTW(atgep, RX_COALSC_TO_1e, 0); 412015a6ef6SSaurabh Misra OUTW(atgep, TX_COALSC_PKT_1e, 1); 413015a6ef6SSaurabh Misra OUTW(atgep, TX_COALSC_TO_1e, 4000/2); /* 4mS */ 414015a6ef6SSaurabh Misra } 415015a6ef6SSaurabh Misra 416015a6ef6SSaurabh Misra mblk_t * 417015a6ef6SSaurabh Misra atge_l1e_receive(atge_t *atgep) 418015a6ef6SSaurabh Misra { 419015a6ef6SSaurabh Misra atge_l1e_data_t *l1e; 420015a6ef6SSaurabh Misra atge_dma_t *dma_rx_page; 421015a6ef6SSaurabh Misra atge_dma_t *dma_rx_cmb; 422015a6ef6SSaurabh Misra uint32_t *ptr; 423015a6ef6SSaurabh Misra uint32_t cons, current_page; 424015a6ef6SSaurabh Misra uchar_t *pageaddr, *bufp; 425015a6ef6SSaurabh Misra rx_rs_t *rs; 426015a6ef6SSaurabh Misra int prog; 427015a6ef6SSaurabh Misra uint32_t seqno, len, flags; 428015a6ef6SSaurabh Misra mblk_t *mp = NULL, *rx_head, *rx_tail; 429015a6ef6SSaurabh Misra static uint32_t gen = 0; 430015a6ef6SSaurabh Misra 431015a6ef6SSaurabh Misra l1e = atgep->atge_private_data; 432015a6ef6SSaurabh Misra 433015a6ef6SSaurabh Misra ASSERT(MUTEX_HELD(&atgep->atge_intr_lock)); 434015a6ef6SSaurabh Misra ASSERT(l1e != NULL); 435015a6ef6SSaurabh Misra 436015a6ef6SSaurabh Misra rx_tail = NULL; 437015a6ef6SSaurabh Misra rx_head = NULL; 438015a6ef6SSaurabh Misra 439015a6ef6SSaurabh Misra current_page = l1e->atge_l1e_rx_curp; 440015a6ef6SSaurabh Misra 441015a6ef6SSaurabh Misra /* Sync CMB first */ 442015a6ef6SSaurabh Misra dma_rx_cmb = l1e->atge_l1e_rx_cmb; 443015a6ef6SSaurabh Misra DMA_SYNC(dma_rx_cmb, 0, L1E_RX_CMB_SZ * L1E_RX_PAGES, 444015a6ef6SSaurabh Misra DDI_DMA_SYNC_FORKERNEL); 445015a6ef6SSaurabh Misra 446015a6ef6SSaurabh Misra dma_rx_page = l1e->atge_l1e_rx_page[current_page]; 447015a6ef6SSaurabh Misra 448015a6ef6SSaurabh Misra /* 449015a6ef6SSaurabh Misra * Get the producer offset from CMB. 450015a6ef6SSaurabh Misra */ 451015a6ef6SSaurabh Misra ptr = (void *)dma_rx_cmb->addr; 452015a6ef6SSaurabh Misra 453015a6ef6SSaurabh Misra l1e->atge_l1e_rx_page_prods[current_page] = 454015a6ef6SSaurabh Misra ATGE_GET32(dma_rx_cmb, ptr + current_page); 455015a6ef6SSaurabh Misra 456015a6ef6SSaurabh Misra /* Sync current RX Page as well */ 457015a6ef6SSaurabh Misra DMA_SYNC(dma_rx_page, l1e->atge_l1e_rx_page_cons, 458015a6ef6SSaurabh Misra l1e->atge_l1e_rx_page_prods[current_page], DDI_DMA_SYNC_FORKERNEL); 459015a6ef6SSaurabh Misra 460015a6ef6SSaurabh Misra ATGE_DB(("%s: %s() prod : %d, cons : %d, curr page : %d, gen : (%d)" 461015a6ef6SSaurabh Misra " cmb[0,1] : %d, %d", 462015a6ef6SSaurabh Misra atgep->atge_name, __func__, 463015a6ef6SSaurabh Misra l1e->atge_l1e_rx_page_prods[current_page], 464015a6ef6SSaurabh Misra l1e->atge_l1e_rx_page_cons, l1e->atge_l1e_rx_curp, gen, 465015a6ef6SSaurabh Misra ATGE_GET32(dma_rx_cmb, ptr), ATGE_GET32(dma_rx_cmb, ptr + 1))); 466015a6ef6SSaurabh Misra 467015a6ef6SSaurabh Misra for (prog = 0; prog <= l1e->atge_l1e_proc_max; prog++) { 468015a6ef6SSaurabh Misra cons = l1e->atge_l1e_rx_page_cons; 469015a6ef6SSaurabh Misra if (cons >= l1e->atge_l1e_rx_page_prods[l1e->atge_l1e_rx_curp]) 470015a6ef6SSaurabh Misra break; 471015a6ef6SSaurabh Misra 472015a6ef6SSaurabh Misra dma_rx_page = l1e->atge_l1e_rx_page[l1e->atge_l1e_rx_curp]; 473015a6ef6SSaurabh Misra pageaddr = (uchar_t *)dma_rx_page->addr; 474015a6ef6SSaurabh Misra pageaddr = pageaddr + cons; 475015a6ef6SSaurabh Misra rs = (rx_rs_t *)pageaddr; 476015a6ef6SSaurabh Misra 477015a6ef6SSaurabh Misra seqno = ATGE_GET32(dma_rx_page, &(rs->seqno)); 478015a6ef6SSaurabh Misra seqno = L1E_RX_SEQNO(seqno); 479015a6ef6SSaurabh Misra 480015a6ef6SSaurabh Misra len = ATGE_GET32(dma_rx_page, &(rs->length)); 481015a6ef6SSaurabh Misra len = L1E_RX_BYTES(len); 482015a6ef6SSaurabh Misra 483015a6ef6SSaurabh Misra flags = ATGE_GET32(dma_rx_page, &(rs->flags)); 484015a6ef6SSaurabh Misra 485015a6ef6SSaurabh Misra if (seqno != l1e->atge_l1e_rx_seqno) { 486015a6ef6SSaurabh Misra /* 487015a6ef6SSaurabh Misra * We have not seen this happening but we 488015a6ef6SSaurabh Misra * must restart the chip if that happens. 489015a6ef6SSaurabh Misra */ 490015a6ef6SSaurabh Misra ATGE_DB(("%s: %s() MISS-MATCH in seqno :%d," 491015a6ef6SSaurabh Misra " atge_l1e_rx_seqno : %d, length : %d, flags : %x", 492015a6ef6SSaurabh Misra atgep->atge_name, __func__, seqno, 493015a6ef6SSaurabh Misra l1e->atge_l1e_rx_seqno, len, flags)); 494015a6ef6SSaurabh Misra 495015a6ef6SSaurabh Misra mutex_enter(&atgep->atge_tx_lock); 496015a6ef6SSaurabh Misra atge_device_restart(atgep); 497015a6ef6SSaurabh Misra mutex_exit(&atgep->atge_tx_lock); 498015a6ef6SSaurabh Misra 499015a6ef6SSaurabh Misra /* 500015a6ef6SSaurabh Misra * Return all the pkts received before restarting 501015a6ef6SSaurabh Misra * the chip. 502015a6ef6SSaurabh Misra */ 503015a6ef6SSaurabh Misra return (rx_head); 504015a6ef6SSaurabh Misra } else { 505015a6ef6SSaurabh Misra l1e->atge_l1e_rx_seqno++; 506015a6ef6SSaurabh Misra } 507015a6ef6SSaurabh Misra 508015a6ef6SSaurabh Misra /* 509015a6ef6SSaurabh Misra * We will pass the pkt to upper layer provided it's clear 510015a6ef6SSaurabh Misra * from any error. 511015a6ef6SSaurabh Misra */ 512015a6ef6SSaurabh Misra if ((flags & L1E_RD_ERROR) != 0) { 513015a6ef6SSaurabh Misra if ((flags & (L1E_RD_CRC | L1E_RD_CODE | 514015a6ef6SSaurabh Misra L1E_RD_DRIBBLE | L1E_RD_RUNT | L1E_RD_OFLOW | 515015a6ef6SSaurabh Misra L1E_RD_TRUNC)) != 0) { 516015a6ef6SSaurabh Misra ATGE_DB(("%s: %s() ERRORED PKT : %x", 517015a6ef6SSaurabh Misra atgep->atge_name, __func__, flags)); 518015a6ef6SSaurabh Misra atge_l1e_rx_next_pkt(atgep, len); 519015a6ef6SSaurabh Misra atgep->atge_errrcv++; 520015a6ef6SSaurabh Misra continue; 521015a6ef6SSaurabh Misra } 522015a6ef6SSaurabh Misra } 523015a6ef6SSaurabh Misra 524015a6ef6SSaurabh Misra /* 525015a6ef6SSaurabh Misra * So we have received a frame/pkt. 526015a6ef6SSaurabh Misra */ 527015a6ef6SSaurabh Misra if (len == 0 || len > atgep->atge_rx_buf_len) { 528015a6ef6SSaurabh Misra ATGE_DB(("%s: %s() PKT len > error : %d", 529015a6ef6SSaurabh Misra atgep->atge_name, __func__, len)); 530015a6ef6SSaurabh Misra atge_l1e_rx_next_pkt(atgep, len); 531015a6ef6SSaurabh Misra continue; 532015a6ef6SSaurabh Misra } 533015a6ef6SSaurabh Misra 534015a6ef6SSaurabh Misra mp = allocb(len + VLAN_TAGSZ, BPRI_MED); 535015a6ef6SSaurabh Misra if (mp != NULL) { 536015a6ef6SSaurabh Misra mp->b_rptr += VLAN_TAGSZ; 537015a6ef6SSaurabh Misra bufp = mp->b_rptr; 538015a6ef6SSaurabh Misra mp->b_wptr = bufp + len; 539015a6ef6SSaurabh Misra mp->b_next = NULL; 540015a6ef6SSaurabh Misra 541015a6ef6SSaurabh Misra bcopy(pageaddr + sizeof (rx_rs_t), bufp, len); 542015a6ef6SSaurabh Misra 543015a6ef6SSaurabh Misra if (rx_tail == NULL) 544015a6ef6SSaurabh Misra rx_head = rx_tail = mp; 545015a6ef6SSaurabh Misra else { 546015a6ef6SSaurabh Misra rx_tail->b_next = mp; 547015a6ef6SSaurabh Misra rx_tail = mp; 548015a6ef6SSaurabh Misra } 549015a6ef6SSaurabh Misra 550015a6ef6SSaurabh Misra atgep->atge_ipackets++; 551015a6ef6SSaurabh Misra atgep->atge_rbytes += len; 552015a6ef6SSaurabh Misra } else { 553015a6ef6SSaurabh Misra ATGE_DB(("%s: %s() PKT mp == NULL len : %d", 554015a6ef6SSaurabh Misra atgep->atge_name, __func__, len)); 555015a6ef6SSaurabh Misra 556015a6ef6SSaurabh Misra if (len > atgep->atge_rx_buf_len) { 557015a6ef6SSaurabh Misra atgep->atge_toolong_errors++; 558015a6ef6SSaurabh Misra } else if (mp == NULL) { 559015a6ef6SSaurabh Misra atgep->atge_norcvbuf++; 560015a6ef6SSaurabh Misra } 561015a6ef6SSaurabh Misra } 562015a6ef6SSaurabh Misra 563015a6ef6SSaurabh Misra atge_l1e_rx_next_pkt(atgep, len); 564015a6ef6SSaurabh Misra 565015a6ef6SSaurabh Misra ATGE_DB(("%s: %s() seqno :%d, atge_l1e_rx_seqno :" 566015a6ef6SSaurabh Misra " %d, length : %d," 567015a6ef6SSaurabh Misra " flags : %x, cons : %d, prod : %d", 568015a6ef6SSaurabh Misra atgep->atge_name, __func__, seqno, 569015a6ef6SSaurabh Misra l1e->atge_l1e_rx_seqno, len, flags, 570015a6ef6SSaurabh Misra l1e->atge_l1e_rx_page_cons, 571015a6ef6SSaurabh Misra l1e->atge_l1e_rx_page_prods[l1e->atge_l1e_rx_curp])); 572015a6ef6SSaurabh Misra } 573015a6ef6SSaurabh Misra 574015a6ef6SSaurabh Misra ATGE_DB(("%s: %s() receive completed (gen : %d) : cons : %d," 575015a6ef6SSaurabh Misra " prod :%d, L1E_RX_PAGE_SZ : %d (prog:%d)", 576015a6ef6SSaurabh Misra atgep->atge_name, __func__, gen, 577015a6ef6SSaurabh Misra l1e->atge_l1e_rx_page_cons, 578015a6ef6SSaurabh Misra l1e->atge_l1e_rx_page_prods[l1e->atge_l1e_rx_curp], 579015a6ef6SSaurabh Misra L1E_RX_PAGE_SZ, prog)); 580015a6ef6SSaurabh Misra 581015a6ef6SSaurabh Misra gen++; 582015a6ef6SSaurabh Misra return (rx_head); 583015a6ef6SSaurabh Misra } 584015a6ef6SSaurabh Misra 585015a6ef6SSaurabh Misra void 586015a6ef6SSaurabh Misra atge_l1e_rx_next_pkt(atge_t *atgep, uint32_t len) 587015a6ef6SSaurabh Misra { 588015a6ef6SSaurabh Misra atge_l1e_data_t *l1e = atgep->atge_private_data; 589015a6ef6SSaurabh Misra atge_dma_t *dma_rx_page; 590015a6ef6SSaurabh Misra atge_dma_t *dma_rx_cmb; 591015a6ef6SSaurabh Misra int curr = l1e->atge_l1e_rx_curp; 592015a6ef6SSaurabh Misra uint32_t *p; 593015a6ef6SSaurabh Misra 594015a6ef6SSaurabh Misra /* 595015a6ef6SSaurabh Misra * Update consumer position. 596015a6ef6SSaurabh Misra */ 597015a6ef6SSaurabh Misra l1e->atge_l1e_rx_page_cons += 598015a6ef6SSaurabh Misra ROUNDUP(len + sizeof (rx_rs_t), L1E_RX_PAGE_ALIGN); 599015a6ef6SSaurabh Misra 600015a6ef6SSaurabh Misra /* 601015a6ef6SSaurabh Misra * If we need to flip to the other page. Note that we use only two 602015a6ef6SSaurabh Misra * pages. 603015a6ef6SSaurabh Misra */ 604015a6ef6SSaurabh Misra if (l1e->atge_l1e_rx_page_cons >= L1E_RX_PAGE_SZ) { 605015a6ef6SSaurabh Misra ATGE_DB(("%s: %s() cons : %d, prod :%d, L1E_RX_PAGE_SZ : %d", 606015a6ef6SSaurabh Misra atgep->atge_name, __func__, l1e->atge_l1e_rx_page_cons, 607015a6ef6SSaurabh Misra l1e->atge_l1e_rx_page_prods[curr], L1E_RX_PAGE_SZ)); 608015a6ef6SSaurabh Misra 609015a6ef6SSaurabh Misra /* 610015a6ef6SSaurabh Misra * Clear the producer. 611015a6ef6SSaurabh Misra */ 612015a6ef6SSaurabh Misra dma_rx_cmb = l1e->atge_l1e_rx_cmb; 613015a6ef6SSaurabh Misra p = (void *)dma_rx_cmb->addr; 614015a6ef6SSaurabh Misra p = p + curr; 615015a6ef6SSaurabh Misra *p = 0; 616015a6ef6SSaurabh Misra DMA_SYNC(dma_rx_cmb, curr * L1E_RX_CMB_SZ, 617015a6ef6SSaurabh Misra L1E_RX_CMB_SZ, DDI_DMA_SYNC_FORDEV); 618015a6ef6SSaurabh Misra 619015a6ef6SSaurabh Misra /* 620015a6ef6SSaurabh Misra * Notify the NIC that the current RX page is available again. 621015a6ef6SSaurabh Misra */ 622015a6ef6SSaurabh Misra OUTB(atgep, L1E_RXF0_PAGE0 + curr, RXF_VALID); 623015a6ef6SSaurabh Misra 624015a6ef6SSaurabh Misra /* 625015a6ef6SSaurabh Misra * End of Rx page reached, let hardware reuse this page. 626015a6ef6SSaurabh Misra */ 627015a6ef6SSaurabh Misra l1e->atge_l1e_rx_page_cons = 0; 628015a6ef6SSaurabh Misra l1e->atge_l1e_rx_page_prods[curr] = 0; 629015a6ef6SSaurabh Misra 630015a6ef6SSaurabh Misra /* 631015a6ef6SSaurabh Misra * Switch to alternate Rx page. 632015a6ef6SSaurabh Misra */ 633015a6ef6SSaurabh Misra curr ^= 1; 634015a6ef6SSaurabh Misra l1e->atge_l1e_rx_curp = curr; 635015a6ef6SSaurabh Misra 636015a6ef6SSaurabh Misra /* 637015a6ef6SSaurabh Misra * Page flipped, sync CMB and then Rx page. 638015a6ef6SSaurabh Misra */ 639015a6ef6SSaurabh Misra DMA_SYNC(dma_rx_cmb, 0, L1E_RX_PAGES * L1E_RX_CMB_SZ, 640015a6ef6SSaurabh Misra DDI_DMA_SYNC_FORKERNEL); 641015a6ef6SSaurabh Misra p = (void *)dma_rx_cmb->addr; 642015a6ef6SSaurabh Misra l1e->atge_l1e_rx_page_prods[curr] = 643015a6ef6SSaurabh Misra ATGE_GET32(dma_rx_cmb, p + curr); 644015a6ef6SSaurabh Misra 645015a6ef6SSaurabh Misra dma_rx_page = l1e->atge_l1e_rx_page[curr]; 646015a6ef6SSaurabh Misra DMA_SYNC(dma_rx_page, 0, l1e->atge_l1e_rx_page_prods[curr], 647015a6ef6SSaurabh Misra DDI_DMA_SYNC_FORKERNEL); 648015a6ef6SSaurabh Misra 649015a6ef6SSaurabh Misra ATGE_DB(("%s: %s() PAGE FLIPPED -> %d, producer[0,1]: %d, %d", 650015a6ef6SSaurabh Misra atgep->atge_name, __func__, curr, 651015a6ef6SSaurabh Misra ATGE_GET32(dma_rx_cmb, p), ATGE_GET32(dma_rx_cmb, p + 1))); 652015a6ef6SSaurabh Misra } 653015a6ef6SSaurabh Misra } 654015a6ef6SSaurabh Misra 655015a6ef6SSaurabh Misra void 656*0eb090a7SSaurabh Misra atge_l1e_send_packet(atge_ring_t *r) 657015a6ef6SSaurabh Misra { 658015a6ef6SSaurabh Misra /* 659015a6ef6SSaurabh Misra * Ask chip to send the packet now. 660015a6ef6SSaurabh Misra */ 661015a6ef6SSaurabh Misra OUTL(r->r_atge, ATGE_MBOX, r->r_producer); 662015a6ef6SSaurabh Misra } 663015a6ef6SSaurabh Misra 664015a6ef6SSaurabh Misra void 665015a6ef6SSaurabh Misra atge_l1e_clear_stats(atge_t *atgep) 666015a6ef6SSaurabh Misra { 667015a6ef6SSaurabh Misra atge_l1e_smb_t smb; 668015a6ef6SSaurabh Misra uint32_t *reg; 669015a6ef6SSaurabh Misra int i; 670015a6ef6SSaurabh Misra 671015a6ef6SSaurabh Misra /* 672015a6ef6SSaurabh Misra * Clear RX stats first. 673015a6ef6SSaurabh Misra */ 674015a6ef6SSaurabh Misra i = 0; 675015a6ef6SSaurabh Misra reg = &smb.rx_frames; 676015a6ef6SSaurabh Misra while (reg++ <= &smb.rx_pkts_filtered) { 677015a6ef6SSaurabh Misra (void) INL(atgep, L1E_RX_MIB_BASE + i); 678015a6ef6SSaurabh Misra i += sizeof (uint32_t); 679015a6ef6SSaurabh Misra } 680015a6ef6SSaurabh Misra 681015a6ef6SSaurabh Misra /* 682015a6ef6SSaurabh Misra * Clear TX stats. 683015a6ef6SSaurabh Misra */ 684015a6ef6SSaurabh Misra i = 0; 685015a6ef6SSaurabh Misra reg = &smb.tx_frames; 686015a6ef6SSaurabh Misra while (reg++ <= &smb.tx_mcast_bytes) { 687015a6ef6SSaurabh Misra (void) INL(atgep, L1E_TX_MIB_BASE + i); 688015a6ef6SSaurabh Misra i += sizeof (uint32_t); 689015a6ef6SSaurabh Misra } 690015a6ef6SSaurabh Misra } 691015a6ef6SSaurabh Misra 692015a6ef6SSaurabh Misra void 693015a6ef6SSaurabh Misra atge_l1e_gather_stats(atge_t *atgep) 694015a6ef6SSaurabh Misra { 695015a6ef6SSaurabh Misra atge_l1e_smb_t *stat; 696015a6ef6SSaurabh Misra atge_l1e_smb_t *smb; 697015a6ef6SSaurabh Misra atge_l1e_smb_t local_smb; 698015a6ef6SSaurabh Misra uint32_t *reg; 699015a6ef6SSaurabh Misra int i; 700015a6ef6SSaurabh Misra 701015a6ef6SSaurabh Misra ASSERT(atgep != NULL); 702015a6ef6SSaurabh Misra 703015a6ef6SSaurabh Misra stat = (atge_l1e_smb_t *)atgep->atge_hw_stats; 704015a6ef6SSaurabh Misra 705015a6ef6SSaurabh Misra bzero(&local_smb, sizeof (atge_l1e_smb_t)); 706015a6ef6SSaurabh Misra smb = &local_smb; 707015a6ef6SSaurabh Misra 708015a6ef6SSaurabh Misra /* Read Rx statistics. */ 709015a6ef6SSaurabh Misra i = 0; 710015a6ef6SSaurabh Misra reg = &smb->rx_frames; 711015a6ef6SSaurabh Misra while (reg++ <= &smb->rx_pkts_filtered) { 712015a6ef6SSaurabh Misra *reg = INL(atgep, L1E_RX_MIB_BASE + i); 713015a6ef6SSaurabh Misra i += sizeof (uint32_t); 714015a6ef6SSaurabh Misra } 715015a6ef6SSaurabh Misra 716015a6ef6SSaurabh Misra /* Read Tx statistics. */ 717015a6ef6SSaurabh Misra i = 0; 718015a6ef6SSaurabh Misra reg = &smb->tx_frames; 719015a6ef6SSaurabh Misra while (reg++ <= &smb->tx_mcast_bytes) { 720015a6ef6SSaurabh Misra *reg = INL(atgep, L1E_TX_MIB_BASE + i); 721015a6ef6SSaurabh Misra i += sizeof (uint32_t); 722015a6ef6SSaurabh Misra } 723015a6ef6SSaurabh Misra 724015a6ef6SSaurabh Misra /* 725015a6ef6SSaurabh Misra * SMB is cleared everytime we read; hence we always do '+='. 726015a6ef6SSaurabh Misra */ 727015a6ef6SSaurabh Misra 728015a6ef6SSaurabh Misra /* Rx stats. */ 729015a6ef6SSaurabh Misra stat->rx_frames += smb->rx_frames; 730015a6ef6SSaurabh Misra stat->rx_bcast_frames += smb->rx_bcast_frames; 731015a6ef6SSaurabh Misra stat->rx_mcast_frames += smb->rx_mcast_frames; 732015a6ef6SSaurabh Misra stat->rx_pause_frames += smb->rx_pause_frames; 733015a6ef6SSaurabh Misra stat->rx_control_frames += smb->rx_control_frames; 734015a6ef6SSaurabh Misra stat->rx_crcerrs += smb->rx_crcerrs; 735015a6ef6SSaurabh Misra stat->rx_lenerrs += smb->rx_lenerrs; 736015a6ef6SSaurabh Misra stat->rx_bytes += smb->rx_bytes; 737015a6ef6SSaurabh Misra stat->rx_runts += smb->rx_runts; 738015a6ef6SSaurabh Misra stat->rx_fragments += smb->rx_fragments; 739015a6ef6SSaurabh Misra stat->rx_pkts_64 += smb->rx_pkts_64; 740015a6ef6SSaurabh Misra stat->rx_pkts_65_127 += smb->rx_pkts_65_127; 741015a6ef6SSaurabh Misra stat->rx_pkts_128_255 += smb->rx_pkts_128_255; 742015a6ef6SSaurabh Misra stat->rx_pkts_256_511 += smb->rx_pkts_256_511; 743015a6ef6SSaurabh Misra stat->rx_pkts_512_1023 += smb->rx_pkts_512_1023; 744015a6ef6SSaurabh Misra stat->rx_pkts_1024_1518 += smb->rx_pkts_1024_1518; 745015a6ef6SSaurabh Misra stat->rx_pkts_1519_max += smb->rx_pkts_1519_max; 746015a6ef6SSaurabh Misra stat->rx_pkts_truncated += smb->rx_pkts_truncated; 747015a6ef6SSaurabh Misra stat->rx_fifo_oflows += smb->rx_fifo_oflows; 748015a6ef6SSaurabh Misra stat->rx_rrs_errs += smb->rx_rrs_errs; 749015a6ef6SSaurabh Misra stat->rx_alignerrs += smb->rx_alignerrs; 750015a6ef6SSaurabh Misra stat->rx_bcast_bytes += smb->rx_bcast_bytes; 751015a6ef6SSaurabh Misra stat->rx_mcast_bytes += smb->rx_mcast_bytes; 752015a6ef6SSaurabh Misra stat->rx_pkts_filtered += smb->rx_pkts_filtered; 753015a6ef6SSaurabh Misra 754015a6ef6SSaurabh Misra /* Tx stats. */ 755015a6ef6SSaurabh Misra stat->tx_frames += smb->tx_frames; 756015a6ef6SSaurabh Misra stat->tx_bcast_frames += smb->tx_bcast_frames; 757015a6ef6SSaurabh Misra stat->tx_mcast_frames += smb->tx_mcast_frames; 758015a6ef6SSaurabh Misra stat->tx_pause_frames += smb->tx_pause_frames; 759015a6ef6SSaurabh Misra stat->tx_excess_defer += smb->tx_excess_defer; 760015a6ef6SSaurabh Misra stat->tx_control_frames += smb->tx_control_frames; 761015a6ef6SSaurabh Misra stat->tx_deferred += smb->tx_deferred; 762015a6ef6SSaurabh Misra stat->tx_bytes += smb->tx_bytes; 763015a6ef6SSaurabh Misra stat->tx_pkts_64 += smb->tx_pkts_64; 764015a6ef6SSaurabh Misra stat->tx_pkts_65_127 += smb->tx_pkts_65_127; 765015a6ef6SSaurabh Misra stat->tx_pkts_128_255 += smb->tx_pkts_128_255; 766015a6ef6SSaurabh Misra stat->tx_pkts_256_511 += smb->tx_pkts_256_511; 767015a6ef6SSaurabh Misra stat->tx_pkts_512_1023 += smb->tx_pkts_512_1023; 768015a6ef6SSaurabh Misra stat->tx_pkts_1024_1518 += smb->tx_pkts_1024_1518; 769015a6ef6SSaurabh Misra stat->tx_pkts_1519_max += smb->tx_pkts_1519_max; 770015a6ef6SSaurabh Misra stat->tx_single_colls += smb->tx_single_colls; 771015a6ef6SSaurabh Misra stat->tx_multi_colls += smb->tx_multi_colls; 772015a6ef6SSaurabh Misra stat->tx_late_colls += smb->tx_late_colls; 773015a6ef6SSaurabh Misra stat->tx_excess_colls += smb->tx_excess_colls; 774015a6ef6SSaurabh Misra stat->tx_abort += smb->tx_abort; 775015a6ef6SSaurabh Misra stat->tx_underrun += smb->tx_underrun; 776015a6ef6SSaurabh Misra stat->tx_desc_underrun += smb->tx_desc_underrun; 777015a6ef6SSaurabh Misra stat->tx_lenerrs += smb->tx_lenerrs; 778015a6ef6SSaurabh Misra stat->tx_pkts_truncated += smb->tx_pkts_truncated; 779015a6ef6SSaurabh Misra stat->tx_bcast_bytes += smb->tx_bcast_bytes; 780015a6ef6SSaurabh Misra stat->tx_mcast_bytes += smb->tx_mcast_bytes; 781015a6ef6SSaurabh Misra 782015a6ef6SSaurabh Misra /* 783015a6ef6SSaurabh Misra * Update global counters in atge_t. 784015a6ef6SSaurabh Misra */ 785015a6ef6SSaurabh Misra atgep->atge_brdcstrcv += smb->rx_bcast_frames; 786015a6ef6SSaurabh Misra atgep->atge_multircv += smb->rx_mcast_frames; 787015a6ef6SSaurabh Misra atgep->atge_multixmt += smb->tx_mcast_frames; 788015a6ef6SSaurabh Misra atgep->atge_brdcstxmt += smb->tx_bcast_frames; 789015a6ef6SSaurabh Misra 790015a6ef6SSaurabh Misra atgep->atge_align_errors += smb->rx_alignerrs; 791015a6ef6SSaurabh Misra atgep->atge_fcs_errors += smb->rx_crcerrs; 792015a6ef6SSaurabh Misra atgep->atge_sqe_errors += smb->rx_rrs_errs; 793015a6ef6SSaurabh Misra atgep->atge_defer_xmts += smb->tx_deferred; 794015a6ef6SSaurabh Misra atgep->atge_first_collisions += smb->tx_single_colls; 795015a6ef6SSaurabh Misra atgep->atge_multi_collisions += smb->tx_multi_colls * 2; 796015a6ef6SSaurabh Misra atgep->atge_tx_late_collisions += smb->tx_late_colls; 797015a6ef6SSaurabh Misra atgep->atge_ex_collisions += smb->tx_excess_colls; 798015a6ef6SSaurabh Misra atgep->atge_macxmt_errors += smb->tx_abort; 799015a6ef6SSaurabh Misra atgep->atge_toolong_errors += smb->rx_lenerrs; 800015a6ef6SSaurabh Misra atgep->atge_overflow += smb->rx_fifo_oflows; 801015a6ef6SSaurabh Misra atgep->atge_underflow += (smb->tx_underrun + smb->tx_desc_underrun); 802015a6ef6SSaurabh Misra atgep->atge_runt += smb->rx_runts; 803015a6ef6SSaurabh Misra 804015a6ef6SSaurabh Misra 805015a6ef6SSaurabh Misra atgep->atge_collisions += smb->tx_single_colls + 806015a6ef6SSaurabh Misra smb->tx_multi_colls * 2 + smb->tx_late_colls + 807015a6ef6SSaurabh Misra smb->tx_abort * HDPX_CFG_RETRY_DEFAULT; 808015a6ef6SSaurabh Misra 809015a6ef6SSaurabh Misra /* 810015a6ef6SSaurabh Misra * tx_pkts_truncated counter looks suspicious. It constantly 811015a6ef6SSaurabh Misra * increments with no sign of Tx errors. Hence we don't factor it. 812015a6ef6SSaurabh Misra */ 813015a6ef6SSaurabh Misra atgep->atge_macxmt_errors += smb->tx_abort + smb->tx_late_colls + 814015a6ef6SSaurabh Misra smb->tx_underrun; 815015a6ef6SSaurabh Misra 816015a6ef6SSaurabh Misra atgep->atge_macrcv_errors += smb->rx_crcerrs + smb->rx_lenerrs + 817015a6ef6SSaurabh Misra smb->rx_runts + smb->rx_pkts_truncated + 818015a6ef6SSaurabh Misra smb->rx_fifo_oflows + smb->rx_rrs_errs + 819015a6ef6SSaurabh Misra smb->rx_alignerrs; 820015a6ef6SSaurabh Misra } 821015a6ef6SSaurabh Misra 822015a6ef6SSaurabh Misra void 823015a6ef6SSaurabh Misra atge_l1e_stop_mac(atge_t *atgep) 824015a6ef6SSaurabh Misra { 825015a6ef6SSaurabh Misra uint32_t reg; 826015a6ef6SSaurabh Misra 827015a6ef6SSaurabh Misra reg = INL(atgep, ATGE_MAC_CFG); 828015a6ef6SSaurabh Misra ATGE_DB(("%s: %s() reg : %x", atgep->atge_name, __func__, reg)); 829015a6ef6SSaurabh Misra 830015a6ef6SSaurabh Misra if ((reg & (ATGE_CFG_TX_ENB | ATGE_CFG_RX_ENB)) != 0) { 831015a6ef6SSaurabh Misra reg &= ~ATGE_CFG_TX_ENB | ATGE_CFG_RX_ENB; 832015a6ef6SSaurabh Misra OUTL(atgep, ATGE_MAC_CFG, reg); 833015a6ef6SSaurabh Misra ATGE_DB(("%s: %s() mac stopped", atgep->atge_name, __func__)); 834015a6ef6SSaurabh Misra } 835015a6ef6SSaurabh Misra } 836*0eb090a7SSaurabh Misra 837*0eb090a7SSaurabh Misra /* 838*0eb090a7SSaurabh Misra * The interrupt handler for L1E/L2E 839*0eb090a7SSaurabh Misra */ 840*0eb090a7SSaurabh Misra /*ARGSUSED*/ 841*0eb090a7SSaurabh Misra uint_t 842*0eb090a7SSaurabh Misra atge_l1e_interrupt(caddr_t arg1, caddr_t arg2) 843*0eb090a7SSaurabh Misra { 844*0eb090a7SSaurabh Misra atge_t *atgep = (void *)arg1; 845*0eb090a7SSaurabh Misra mblk_t *rx_head = NULL; 846*0eb090a7SSaurabh Misra uint32_t status; 847*0eb090a7SSaurabh Misra int resched = 0; 848*0eb090a7SSaurabh Misra 849*0eb090a7SSaurabh Misra ASSERT(atgep != NULL); 850*0eb090a7SSaurabh Misra 851*0eb090a7SSaurabh Misra mutex_enter(&atgep->atge_intr_lock); 852*0eb090a7SSaurabh Misra 853*0eb090a7SSaurabh Misra if (atgep->atge_chip_state & ATGE_CHIP_SUSPENDED) { 854*0eb090a7SSaurabh Misra mutex_exit(&atgep->atge_intr_lock); 855*0eb090a7SSaurabh Misra return (DDI_INTR_UNCLAIMED); 856*0eb090a7SSaurabh Misra } 857*0eb090a7SSaurabh Misra 858*0eb090a7SSaurabh Misra status = INL(atgep, ATGE_INTR_STATUS); 859*0eb090a7SSaurabh Misra if (status == 0 || (status & atgep->atge_intrs) == 0) { 860*0eb090a7SSaurabh Misra mutex_exit(&atgep->atge_intr_lock); 861*0eb090a7SSaurabh Misra 862*0eb090a7SSaurabh Misra if (atgep->atge_flags & ATGE_FIXED_TYPE) 863*0eb090a7SSaurabh Misra return (DDI_INTR_UNCLAIMED); 864*0eb090a7SSaurabh Misra 865*0eb090a7SSaurabh Misra return (DDI_INTR_CLAIMED); 866*0eb090a7SSaurabh Misra } 867*0eb090a7SSaurabh Misra 868*0eb090a7SSaurabh Misra ATGE_DB(("%s: %s() entry status : %x", 869*0eb090a7SSaurabh Misra atgep->atge_name, __func__, status)); 870*0eb090a7SSaurabh Misra 871*0eb090a7SSaurabh Misra 872*0eb090a7SSaurabh Misra /* 873*0eb090a7SSaurabh Misra * Disable interrupts. 874*0eb090a7SSaurabh Misra */ 875*0eb090a7SSaurabh Misra OUTL(atgep, ATGE_INTR_STATUS, status | INTR_DIS_INT); 876*0eb090a7SSaurabh Misra FLUSH(atgep, ATGE_INTR_STATUS); 877*0eb090a7SSaurabh Misra 878*0eb090a7SSaurabh Misra /* 879*0eb090a7SSaurabh Misra * Check if chip is running, only then do the work. 880*0eb090a7SSaurabh Misra */ 881*0eb090a7SSaurabh Misra if (atgep->atge_chip_state & ATGE_CHIP_RUNNING) { 882*0eb090a7SSaurabh Misra if (status & INTR_SMB) { 883*0eb090a7SSaurabh Misra atge_l1e_gather_stats(atgep); 884*0eb090a7SSaurabh Misra } 885*0eb090a7SSaurabh Misra 886*0eb090a7SSaurabh Misra /* 887*0eb090a7SSaurabh Misra * Check for errors. 888*0eb090a7SSaurabh Misra */ 889*0eb090a7SSaurabh Misra if (status & L1E_INTR_ERRORS) { 890*0eb090a7SSaurabh Misra atge_error(atgep->atge_dip, 891*0eb090a7SSaurabh Misra "L1E chip found an error intr status : %x", 892*0eb090a7SSaurabh Misra status); 893*0eb090a7SSaurabh Misra 894*0eb090a7SSaurabh Misra if (status & 895*0eb090a7SSaurabh Misra (INTR_DMA_RD_TO_RST | INTR_DMA_WR_TO_RST)) { 896*0eb090a7SSaurabh Misra atge_error(atgep->atge_dip, "DMA transfer err"); 897*0eb090a7SSaurabh Misra 898*0eb090a7SSaurabh Misra atge_device_stop(atgep); 899*0eb090a7SSaurabh Misra goto done; 900*0eb090a7SSaurabh Misra } 901*0eb090a7SSaurabh Misra 902*0eb090a7SSaurabh Misra if (status & INTR_TX_FIFO_UNDERRUN) { 903*0eb090a7SSaurabh Misra atge_error(atgep->atge_dip, "TX FIFO underrun"); 904*0eb090a7SSaurabh Misra } 905*0eb090a7SSaurabh Misra } 906*0eb090a7SSaurabh Misra 907*0eb090a7SSaurabh Misra rx_head = atge_l1e_receive(atgep); 908*0eb090a7SSaurabh Misra 909*0eb090a7SSaurabh Misra if (status & INTR_TX_PKT) { 910*0eb090a7SSaurabh Misra int cons; 911*0eb090a7SSaurabh Misra 912*0eb090a7SSaurabh Misra mutex_enter(&atgep->atge_tx_lock); 913*0eb090a7SSaurabh Misra cons = INW(atgep, L1E_TPD_CONS_IDX); 914*0eb090a7SSaurabh Misra atge_tx_reclaim(atgep, cons); 915*0eb090a7SSaurabh Misra if (atgep->atge_tx_resched) { 916*0eb090a7SSaurabh Misra atgep->atge_tx_resched = 0; 917*0eb090a7SSaurabh Misra resched = 1; 918*0eb090a7SSaurabh Misra } 919*0eb090a7SSaurabh Misra 920*0eb090a7SSaurabh Misra mutex_exit(&atgep->atge_tx_lock); 921*0eb090a7SSaurabh Misra } 922*0eb090a7SSaurabh Misra } 923*0eb090a7SSaurabh Misra 924*0eb090a7SSaurabh Misra /* 925*0eb090a7SSaurabh Misra * Enable interrupts. 926*0eb090a7SSaurabh Misra */ 927*0eb090a7SSaurabh Misra OUTL(atgep, ATGE_INTR_STATUS, 0); 928*0eb090a7SSaurabh Misra 929*0eb090a7SSaurabh Misra done: 930*0eb090a7SSaurabh Misra 931*0eb090a7SSaurabh Misra mutex_exit(&atgep->atge_intr_lock); 932*0eb090a7SSaurabh Misra 933*0eb090a7SSaurabh Misra if (status & INTR_GPHY) { 934*0eb090a7SSaurabh Misra /* 935*0eb090a7SSaurabh Misra * Ack interrupts from PHY 936*0eb090a7SSaurabh Misra */ 937*0eb090a7SSaurabh Misra (void) atge_mii_read(atgep, 938*0eb090a7SSaurabh Misra atgep->atge_phyaddr, ATGE_ISR_ACK_GPHY); 939*0eb090a7SSaurabh Misra 940*0eb090a7SSaurabh Misra mii_check(atgep->atge_mii); 941*0eb090a7SSaurabh Misra } 942*0eb090a7SSaurabh Misra 943*0eb090a7SSaurabh Misra /* 944*0eb090a7SSaurabh Misra * Pass the list of packets received from chip to MAC layer. 945*0eb090a7SSaurabh Misra */ 946*0eb090a7SSaurabh Misra if (rx_head) { 947*0eb090a7SSaurabh Misra mac_rx(atgep->atge_mh, 0, rx_head); 948*0eb090a7SSaurabh Misra } 949*0eb090a7SSaurabh Misra 950*0eb090a7SSaurabh Misra /* 951*0eb090a7SSaurabh Misra * Let MAC start sending pkts if the downstream was asked to pause. 952*0eb090a7SSaurabh Misra */ 953*0eb090a7SSaurabh Misra if (resched) 954*0eb090a7SSaurabh Misra mac_tx_update(atgep->atge_mh); 955*0eb090a7SSaurabh Misra 956*0eb090a7SSaurabh Misra return (DDI_INTR_CLAIMED); 957*0eb090a7SSaurabh Misra } 958