1a23fd118Syl150051 /* 2a23fd118Syl150051 * CDDL HEADER START 3a23fd118Syl150051 * 4a23fd118Syl150051 * The contents of this file are subject to the terms of the 5a23fd118Syl150051 * Common Development and Distribution License (the "License"). 6a23fd118Syl150051 * You may not use this file except in compliance with the License. 7a23fd118Syl150051 * 8a23fd118Syl150051 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9a23fd118Syl150051 * or http://www.opensolaris.org/os/licensing. 10a23fd118Syl150051 * See the License for the specific language governing permissions 11a23fd118Syl150051 * and limitations under the License. 12a23fd118Syl150051 * 13a23fd118Syl150051 * When distributing Covered Code, include this CDDL HEADER in each 14a23fd118Syl150051 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15a23fd118Syl150051 * If applicable, add the following below this CDDL HEADER, with the 16a23fd118Syl150051 * fields enclosed by brackets "[]" replaced with your own identifying 17a23fd118Syl150051 * information: Portions Copyright [yyyy] [name of copyright owner] 18a23fd118Syl150051 * 19a23fd118Syl150051 * CDDL HEADER END 20a23fd118Syl150051 */ 21a23fd118Syl150051 22a23fd118Syl150051 /* 230dc2366fSVenugopal Iyer * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24a23fd118Syl150051 * Use is subject to license terms. 25a23fd118Syl150051 */ 26a23fd118Syl150051 27a23fd118Syl150051 /* 28f30c160eSRoamer * Copyright (c) 2002-2009 Neterion, Inc. 29a23fd118Syl150051 * All right Reserved. 30a23fd118Syl150051 * 31a23fd118Syl150051 * FileName : xgell.c 32a23fd118Syl150051 * 33a23fd118Syl150051 * Description: Xge Link Layer data path implementation 34a23fd118Syl150051 * 35a23fd118Syl150051 */ 36a23fd118Syl150051 37a23fd118Syl150051 #include "xgell.h" 38a23fd118Syl150051 39a23fd118Syl150051 #include <netinet/ip.h> 40a23fd118Syl150051 #include <netinet/tcp.h> 418347601bSyl150051 #include <netinet/udp.h> 42a23fd118Syl150051 43ba2e4443Sseb #define XGELL_MAX_FRAME_SIZE(hldev) ((hldev)->config.mtu + \ 44a23fd118Syl150051 sizeof (struct ether_vlan_header)) 45a23fd118Syl150051 46a23fd118Syl150051 #define HEADROOM 2 /* for DIX-only packets */ 47a23fd118Syl150051 48a23fd118Syl150051 void header_free_func(void *arg) { } 49a23fd118Syl150051 frtn_t header_frtn = {header_free_func, NULL}; 50a23fd118Syl150051 51a23fd118Syl150051 /* DMA attributes used for Tx side */ 52a23fd118Syl150051 static struct ddi_dma_attr tx_dma_attr = { 53a23fd118Syl150051 DMA_ATTR_V0, /* dma_attr_version */ 54a23fd118Syl150051 0x0ULL, /* dma_attr_addr_lo */ 55a23fd118Syl150051 0xFFFFFFFFFFFFFFFFULL, /* dma_attr_addr_hi */ 567eced415Sxw161283 0xFFFFFFFFFFFFFFFFULL, /* dma_attr_count_max */ 577eced415Sxw161283 #if defined(__sparc) 587eced415Sxw161283 0x2000, /* dma_attr_align */ 597eced415Sxw161283 #else 607eced415Sxw161283 0x1000, /* dma_attr_align */ 617eced415Sxw161283 #endif 627eced415Sxw161283 0xFC00FC, /* dma_attr_burstsizes */ 637eced415Sxw161283 0x1, /* dma_attr_minxfer */ 647eced415Sxw161283 0xFFFFFFFFFFFFFFFFULL, /* dma_attr_maxxfer */ 65a23fd118Syl150051 0xFFFFFFFFFFFFFFFFULL, /* dma_attr_seg */ 668347601bSyl150051 18, /* dma_attr_sgllen */ 677eced415Sxw161283 (unsigned int)1, /* dma_attr_granular */ 68a23fd118Syl150051 0 /* dma_attr_flags */ 69a23fd118Syl150051 }; 70a23fd118Syl150051 71a23fd118Syl150051 /* 72a23fd118Syl150051 * DMA attributes used when using ddi_dma_mem_alloc to 73a23fd118Syl150051 * allocat HAL descriptors and Rx buffers during replenish 74a23fd118Syl150051 */ 75a23fd118Syl150051 static struct ddi_dma_attr hal_dma_attr = { 76a23fd118Syl150051 DMA_ATTR_V0, /* dma_attr_version */ 77a23fd118Syl150051 0x0ULL, /* dma_attr_addr_lo */ 78a23fd118Syl150051 0xFFFFFFFFFFFFFFFFULL, /* dma_attr_addr_hi */ 797eced415Sxw161283 0xFFFFFFFFFFFFFFFFULL, /* dma_attr_count_max */ 807eced415Sxw161283 #if defined(__sparc) 817eced415Sxw161283 0x2000, /* dma_attr_align */ 827eced415Sxw161283 #else 837eced415Sxw161283 0x1000, /* dma_attr_align */ 847eced415Sxw161283 #endif 857eced415Sxw161283 0xFC00FC, /* dma_attr_burstsizes */ 867eced415Sxw161283 0x1, /* dma_attr_minxfer */ 877eced415Sxw161283 0xFFFFFFFFFFFFFFFFULL, /* dma_attr_maxxfer */ 88a23fd118Syl150051 0xFFFFFFFFFFFFFFFFULL, /* dma_attr_seg */ 89a23fd118Syl150051 1, /* dma_attr_sgllen */ 907eced415Sxw161283 (unsigned int)1, /* dma_attr_sgllen */ 917eced415Sxw161283 DDI_DMA_RELAXED_ORDERING /* dma_attr_flags */ 92a23fd118Syl150051 }; 93a23fd118Syl150051 94a23fd118Syl150051 struct ddi_dma_attr *p_hal_dma_attr = &hal_dma_attr; 95a23fd118Syl150051 96ba2e4443Sseb static int xgell_m_stat(void *, uint_t, uint64_t *); 97ba2e4443Sseb static int xgell_m_start(void *); 98ba2e4443Sseb static void xgell_m_stop(void *); 99ba2e4443Sseb static int xgell_m_promisc(void *, boolean_t); 100ba2e4443Sseb static int xgell_m_multicst(void *, boolean_t, const uint8_t *); 101ba2e4443Sseb static void xgell_m_ioctl(void *, queue_t *, mblk_t *); 102ba2e4443Sseb static boolean_t xgell_m_getcapab(void *, mac_capab_t, void *); 103ba2e4443Sseb 104ba2e4443Sseb #define XGELL_M_CALLBACK_FLAGS (MC_IOCTL | MC_GETCAPAB) 105ba2e4443Sseb 106ba2e4443Sseb static mac_callbacks_t xgell_m_callbacks = { 107ba2e4443Sseb XGELL_M_CALLBACK_FLAGS, 108ba2e4443Sseb xgell_m_stat, 109ba2e4443Sseb xgell_m_start, 110ba2e4443Sseb xgell_m_stop, 111ba2e4443Sseb xgell_m_promisc, 112ba2e4443Sseb xgell_m_multicst, 113da14cebeSEric Cheng NULL, 114ba2e4443Sseb NULL, 1150dc2366fSVenugopal Iyer NULL, 116ba2e4443Sseb xgell_m_ioctl, 117ba2e4443Sseb xgell_m_getcapab 118ba2e4443Sseb }; 119ba2e4443Sseb 120a23fd118Syl150051 /* 121a23fd118Syl150051 * xge_device_poll 122a23fd118Syl150051 * 123da14cebeSEric Cheng * Timeout should call me every 1s. xge_callback_event_queued should call me 124a23fd118Syl150051 * when HAL hope event was rescheduled. 125a23fd118Syl150051 */ 126a23fd118Syl150051 /*ARGSUSED*/ 127a23fd118Syl150051 void 128a23fd118Syl150051 xge_device_poll(void *data) 129a23fd118Syl150051 { 130a23fd118Syl150051 xgelldev_t *lldev = xge_hal_device_private(data); 131a23fd118Syl150051 132a23fd118Syl150051 mutex_enter(&lldev->genlock); 133a23fd118Syl150051 if (lldev->is_initialized) { 134a23fd118Syl150051 xge_hal_device_poll(data); 135a23fd118Syl150051 lldev->timeout_id = timeout(xge_device_poll, data, 136a23fd118Syl150051 XGE_DEV_POLL_TICKS); 1378347601bSyl150051 } else if (lldev->in_reset == 1) { 1388347601bSyl150051 lldev->timeout_id = timeout(xge_device_poll, data, 1398347601bSyl150051 XGE_DEV_POLL_TICKS); 1408347601bSyl150051 } else { 1418347601bSyl150051 lldev->timeout_id = 0; 142a23fd118Syl150051 } 143a23fd118Syl150051 mutex_exit(&lldev->genlock); 144a23fd118Syl150051 } 145a23fd118Syl150051 146a23fd118Syl150051 /* 147a23fd118Syl150051 * xge_device_poll_now 148a23fd118Syl150051 * 149a23fd118Syl150051 * Will call xge_device_poll() immediately 150a23fd118Syl150051 */ 151a23fd118Syl150051 void 152a23fd118Syl150051 xge_device_poll_now(void *data) 153a23fd118Syl150051 { 154a23fd118Syl150051 xgelldev_t *lldev = xge_hal_device_private(data); 155a23fd118Syl150051 156a23fd118Syl150051 mutex_enter(&lldev->genlock); 1578347601bSyl150051 if (lldev->is_initialized) { 1588347601bSyl150051 xge_hal_device_poll(data); 1598347601bSyl150051 } 160a23fd118Syl150051 mutex_exit(&lldev->genlock); 161a23fd118Syl150051 } 162a23fd118Syl150051 163a23fd118Syl150051 /* 164a23fd118Syl150051 * xgell_callback_link_up 165a23fd118Syl150051 * 166a23fd118Syl150051 * This function called by HAL to notify HW link up state change. 167a23fd118Syl150051 */ 168a23fd118Syl150051 void 169a23fd118Syl150051 xgell_callback_link_up(void *userdata) 170a23fd118Syl150051 { 171a23fd118Syl150051 xgelldev_t *lldev = (xgelldev_t *)userdata; 172a23fd118Syl150051 173ba2e4443Sseb mac_link_update(lldev->mh, LINK_STATE_UP); 174a23fd118Syl150051 } 175a23fd118Syl150051 176a23fd118Syl150051 /* 177a23fd118Syl150051 * xgell_callback_link_down 178a23fd118Syl150051 * 179a23fd118Syl150051 * This function called by HAL to notify HW link down state change. 180a23fd118Syl150051 */ 181a23fd118Syl150051 void 182a23fd118Syl150051 xgell_callback_link_down(void *userdata) 183a23fd118Syl150051 { 184a23fd118Syl150051 xgelldev_t *lldev = (xgelldev_t *)userdata; 185a23fd118Syl150051 186ba2e4443Sseb mac_link_update(lldev->mh, LINK_STATE_DOWN); 187a23fd118Syl150051 } 188a23fd118Syl150051 189a23fd118Syl150051 /* 190a23fd118Syl150051 * xgell_rx_buffer_replenish_all 191a23fd118Syl150051 * 192a23fd118Syl150051 * To replenish all freed dtr(s) with buffers in free pool. It's called by 193da14cebeSEric Cheng * xgell_rx_buffer_recycle() or xgell_rx_1b_callback(). 194a23fd118Syl150051 * Must be called with pool_lock held. 195a23fd118Syl150051 */ 196a23fd118Syl150051 static void 197da14cebeSEric Cheng xgell_rx_buffer_replenish_all(xgell_rx_ring_t *ring) 198a23fd118Syl150051 { 199da14cebeSEric Cheng xgell_rx_buffer_pool_t *bf_pool = &ring->bf_pool; 200a23fd118Syl150051 xge_hal_dtr_h dtr; 201a23fd118Syl150051 xgell_rx_buffer_t *rx_buffer; 202a23fd118Syl150051 xgell_rxd_priv_t *rxd_priv; 203a23fd118Syl150051 204da14cebeSEric Cheng xge_assert(mutex_owned(&bf_pool->pool_lock)); 2058347601bSyl150051 206da14cebeSEric Cheng while ((bf_pool->free > 0) && 207da14cebeSEric Cheng (xge_hal_ring_dtr_reserve(ring->channelh, &dtr) == XGE_HAL_OK)) { 208da14cebeSEric Cheng xge_assert(bf_pool->head); 209a23fd118Syl150051 210da14cebeSEric Cheng rx_buffer = bf_pool->head; 211da14cebeSEric Cheng 212da14cebeSEric Cheng bf_pool->head = rx_buffer->next; 213da14cebeSEric Cheng bf_pool->free--; 214da14cebeSEric Cheng 215a23fd118Syl150051 xge_assert(rx_buffer->dma_addr); 216a23fd118Syl150051 217a23fd118Syl150051 rxd_priv = (xgell_rxd_priv_t *) 2187eced415Sxw161283 xge_hal_ring_dtr_private(ring->channelh, dtr); 219a23fd118Syl150051 xge_hal_ring_dtr_1b_set(dtr, rx_buffer->dma_addr, 220da14cebeSEric Cheng bf_pool->size); 221a23fd118Syl150051 222a23fd118Syl150051 rxd_priv->rx_buffer = rx_buffer; 2237eced415Sxw161283 xge_hal_ring_dtr_post(ring->channelh, dtr); 224a23fd118Syl150051 } 225a23fd118Syl150051 } 226a23fd118Syl150051 227a23fd118Syl150051 /* 228a23fd118Syl150051 * xgell_rx_buffer_release 229a23fd118Syl150051 * 230a23fd118Syl150051 * The only thing done here is to put the buffer back to the pool. 2318347601bSyl150051 * Calling this function need be protected by mutex, bf_pool.pool_lock. 232a23fd118Syl150051 */ 233a23fd118Syl150051 static void 234a23fd118Syl150051 xgell_rx_buffer_release(xgell_rx_buffer_t *rx_buffer) 235a23fd118Syl150051 { 236da14cebeSEric Cheng xgell_rx_ring_t *ring = rx_buffer->ring; 237da14cebeSEric Cheng xgell_rx_buffer_pool_t *bf_pool = &ring->bf_pool; 238a23fd118Syl150051 239da14cebeSEric Cheng xge_assert(mutex_owned(&bf_pool->pool_lock)); 240a23fd118Syl150051 241a23fd118Syl150051 /* Put the buffer back to pool */ 242da14cebeSEric Cheng rx_buffer->next = bf_pool->head; 243da14cebeSEric Cheng bf_pool->head = rx_buffer; 244a23fd118Syl150051 245da14cebeSEric Cheng bf_pool->free++; 246a23fd118Syl150051 } 247a23fd118Syl150051 248a23fd118Syl150051 /* 249a23fd118Syl150051 * xgell_rx_buffer_recycle 250a23fd118Syl150051 * 251a23fd118Syl150051 * Called by desballoc() to "free" the resource. 252a23fd118Syl150051 * We will try to replenish all descripters. 253a23fd118Syl150051 */ 2547eced415Sxw161283 2557eced415Sxw161283 /* 2567eced415Sxw161283 * Previously there were much lock contention between xgell_rx_1b_compl() and 2577eced415Sxw161283 * xgell_rx_buffer_recycle(), which consumed a lot of CPU resources and had bad 2587eced415Sxw161283 * effect on rx performance. A separate recycle list is introduced to overcome 2597eced415Sxw161283 * this. The recycle list is used to record the rx buffer that has been recycled 2607eced415Sxw161283 * and these buffers will be retuned back to the free list in bulk instead of 2617eced415Sxw161283 * one-by-one. 2627eced415Sxw161283 */ 2637eced415Sxw161283 264a23fd118Syl150051 static void 265a23fd118Syl150051 xgell_rx_buffer_recycle(char *arg) 266a23fd118Syl150051 { 267a23fd118Syl150051 xgell_rx_buffer_t *rx_buffer = (xgell_rx_buffer_t *)arg; 268da14cebeSEric Cheng xgell_rx_ring_t *ring = rx_buffer->ring; 2697eced415Sxw161283 xgelldev_t *lldev = ring->lldev; 2707eced415Sxw161283 xgell_rx_buffer_pool_t *bf_pool = &ring->bf_pool; 271a23fd118Syl150051 2727eced415Sxw161283 mutex_enter(&bf_pool->recycle_lock); 2738347601bSyl150051 2747eced415Sxw161283 rx_buffer->next = bf_pool->recycle_head; 2757eced415Sxw161283 bf_pool->recycle_head = rx_buffer; 2767eced415Sxw161283 if (bf_pool->recycle_tail == NULL) 2777eced415Sxw161283 bf_pool->recycle_tail = rx_buffer; 2787eced415Sxw161283 bf_pool->recycle++; 279a23fd118Syl150051 280a23fd118Syl150051 /* 281a23fd118Syl150051 * Before finding a good way to set this hiwat, just always call to 282a23fd118Syl150051 * replenish_all. *TODO* 283a23fd118Syl150051 */ 284da14cebeSEric Cheng if ((lldev->is_initialized != 0) && (ring->live) && 2857eced415Sxw161283 (bf_pool->recycle >= XGELL_RX_BUFFER_RECYCLE_CACHE)) { 286da14cebeSEric Cheng mutex_enter(&bf_pool->pool_lock); 2877eced415Sxw161283 bf_pool->recycle_tail->next = bf_pool->head; 2887eced415Sxw161283 bf_pool->head = bf_pool->recycle_head; 2897eced415Sxw161283 bf_pool->recycle_head = bf_pool->recycle_tail = NULL; 2907eced415Sxw161283 bf_pool->post -= bf_pool->recycle; 2917eced415Sxw161283 bf_pool->free += bf_pool->recycle; 2927eced415Sxw161283 bf_pool->recycle = 0; 2937eced415Sxw161283 xgell_rx_buffer_replenish_all(ring); 2947eced415Sxw161283 mutex_exit(&bf_pool->pool_lock); 2957eced415Sxw161283 } 296a23fd118Syl150051 2977eced415Sxw161283 mutex_exit(&bf_pool->recycle_lock); 298a23fd118Syl150051 } 299a23fd118Syl150051 300a23fd118Syl150051 /* 301a23fd118Syl150051 * xgell_rx_buffer_alloc 302a23fd118Syl150051 * 303a23fd118Syl150051 * Allocate one rx buffer and return with the pointer to the buffer. 304a23fd118Syl150051 * Return NULL if failed. 305a23fd118Syl150051 */ 306a23fd118Syl150051 static xgell_rx_buffer_t * 307da14cebeSEric Cheng xgell_rx_buffer_alloc(xgell_rx_ring_t *ring) 308a23fd118Syl150051 { 309da14cebeSEric Cheng xgelldev_t *lldev = ring->lldev; 310da14cebeSEric Cheng xgell_rx_buffer_pool_t *bf_pool = &ring->bf_pool; 311a23fd118Syl150051 xge_hal_device_t *hldev; 312a23fd118Syl150051 void *vaddr; 313a23fd118Syl150051 ddi_dma_handle_t dma_handle; 314a23fd118Syl150051 ddi_acc_handle_t dma_acch; 315a23fd118Syl150051 dma_addr_t dma_addr; 316a23fd118Syl150051 uint_t ncookies; 317a23fd118Syl150051 ddi_dma_cookie_t dma_cookie; 318a23fd118Syl150051 size_t real_size; 319a23fd118Syl150051 extern ddi_device_acc_attr_t *p_xge_dev_attr; 320a23fd118Syl150051 xgell_rx_buffer_t *rx_buffer; 321a23fd118Syl150051 3228347601bSyl150051 hldev = (xge_hal_device_t *)lldev->devh; 323a23fd118Syl150051 324a23fd118Syl150051 if (ddi_dma_alloc_handle(hldev->pdev, p_hal_dma_attr, DDI_DMA_SLEEP, 325a23fd118Syl150051 0, &dma_handle) != DDI_SUCCESS) { 326a23fd118Syl150051 xge_debug_ll(XGE_ERR, "%s%d: can not allocate DMA handle", 327a23fd118Syl150051 XGELL_IFNAME, lldev->instance); 328a23fd118Syl150051 goto handle_failed; 329a23fd118Syl150051 } 330a23fd118Syl150051 331a23fd118Syl150051 /* reserve some space at the end of the buffer for recycling */ 332da14cebeSEric Cheng if (ddi_dma_mem_alloc(dma_handle, HEADROOM + bf_pool->size + 333a23fd118Syl150051 sizeof (xgell_rx_buffer_t), p_xge_dev_attr, DDI_DMA_STREAMING, 334a23fd118Syl150051 DDI_DMA_SLEEP, 0, (caddr_t *)&vaddr, &real_size, &dma_acch) != 335a23fd118Syl150051 DDI_SUCCESS) { 336a23fd118Syl150051 xge_debug_ll(XGE_ERR, "%s%d: can not allocate DMA-able memory", 337a23fd118Syl150051 XGELL_IFNAME, lldev->instance); 338a23fd118Syl150051 goto mem_failed; 339a23fd118Syl150051 } 340a23fd118Syl150051 341da14cebeSEric Cheng if (HEADROOM + bf_pool->size + sizeof (xgell_rx_buffer_t) > 342a23fd118Syl150051 real_size) { 343a23fd118Syl150051 xge_debug_ll(XGE_ERR, "%s%d: can not allocate DMA-able memory", 344a23fd118Syl150051 XGELL_IFNAME, lldev->instance); 345a23fd118Syl150051 goto bind_failed; 346a23fd118Syl150051 } 347a23fd118Syl150051 348a23fd118Syl150051 if (ddi_dma_addr_bind_handle(dma_handle, NULL, (char *)vaddr + HEADROOM, 349da14cebeSEric Cheng bf_pool->size, DDI_DMA_READ | DDI_DMA_STREAMING, 350a23fd118Syl150051 DDI_DMA_SLEEP, 0, &dma_cookie, &ncookies) != DDI_SUCCESS) { 351a23fd118Syl150051 xge_debug_ll(XGE_ERR, "%s%d: out of mapping for mblk", 352a23fd118Syl150051 XGELL_IFNAME, lldev->instance); 353a23fd118Syl150051 goto bind_failed; 354a23fd118Syl150051 } 355a23fd118Syl150051 356da14cebeSEric Cheng if (ncookies != 1 || dma_cookie.dmac_size < bf_pool->size) { 357a23fd118Syl150051 xge_debug_ll(XGE_ERR, "%s%d: can not handle partial DMA", 358a23fd118Syl150051 XGELL_IFNAME, lldev->instance); 359a23fd118Syl150051 goto check_failed; 360a23fd118Syl150051 } 361a23fd118Syl150051 362a23fd118Syl150051 dma_addr = dma_cookie.dmac_laddress; 363a23fd118Syl150051 364a23fd118Syl150051 rx_buffer = (xgell_rx_buffer_t *)((char *)vaddr + real_size - 365a23fd118Syl150051 sizeof (xgell_rx_buffer_t)); 366a23fd118Syl150051 rx_buffer->next = NULL; 367a23fd118Syl150051 rx_buffer->vaddr = vaddr; 368a23fd118Syl150051 rx_buffer->dma_addr = dma_addr; 369a23fd118Syl150051 rx_buffer->dma_handle = dma_handle; 370a23fd118Syl150051 rx_buffer->dma_acch = dma_acch; 3717eced415Sxw161283 rx_buffer->ring = ring; 372a23fd118Syl150051 rx_buffer->frtn.free_func = xgell_rx_buffer_recycle; 373a23fd118Syl150051 rx_buffer->frtn.free_arg = (void *)rx_buffer; 374a23fd118Syl150051 375a23fd118Syl150051 return (rx_buffer); 376a23fd118Syl150051 377a23fd118Syl150051 check_failed: 378a23fd118Syl150051 (void) ddi_dma_unbind_handle(dma_handle); 379a23fd118Syl150051 bind_failed: 380a23fd118Syl150051 XGE_OS_MEMORY_CHECK_FREE(vaddr, 0); 381a23fd118Syl150051 ddi_dma_mem_free(&dma_acch); 382a23fd118Syl150051 mem_failed: 383a23fd118Syl150051 ddi_dma_free_handle(&dma_handle); 384a23fd118Syl150051 handle_failed: 385a23fd118Syl150051 386a23fd118Syl150051 return (NULL); 387a23fd118Syl150051 } 388a23fd118Syl150051 389a23fd118Syl150051 /* 390a23fd118Syl150051 * xgell_rx_destroy_buffer_pool 391a23fd118Syl150051 * 392a23fd118Syl150051 * Destroy buffer pool. If there is still any buffer hold by upper layer, 393a23fd118Syl150051 * recorded by bf_pool.post, return DDI_FAILURE to reject to be unloaded. 394a23fd118Syl150051 */ 395da14cebeSEric Cheng static boolean_t 396da14cebeSEric Cheng xgell_rx_destroy_buffer_pool(xgell_rx_ring_t *ring) 397a23fd118Syl150051 { 398da14cebeSEric Cheng xgelldev_t *lldev = ring->lldev; 399da14cebeSEric Cheng xgell_rx_buffer_pool_t *bf_pool = &ring->bf_pool; 400a23fd118Syl150051 xgell_rx_buffer_t *rx_buffer; 401a23fd118Syl150051 ddi_dma_handle_t dma_handle; 402a23fd118Syl150051 ddi_acc_handle_t dma_acch; 403a23fd118Syl150051 int i; 404a23fd118Syl150051 405da14cebeSEric Cheng /* 406da14cebeSEric Cheng * If the pool has been destroied, just return B_TRUE 407da14cebeSEric Cheng */ 408da14cebeSEric Cheng if (!bf_pool->live) 409da14cebeSEric Cheng return (B_TRUE); 410da14cebeSEric Cheng 411da14cebeSEric Cheng mutex_enter(&bf_pool->recycle_lock); 412da14cebeSEric Cheng if (bf_pool->recycle > 0) { 413da14cebeSEric Cheng mutex_enter(&bf_pool->pool_lock); 414da14cebeSEric Cheng bf_pool->recycle_tail->next = bf_pool->head; 415da14cebeSEric Cheng bf_pool->head = bf_pool->recycle_head; 416da14cebeSEric Cheng bf_pool->recycle_tail = bf_pool->recycle_head = NULL; 417da14cebeSEric Cheng bf_pool->post -= bf_pool->recycle; 418da14cebeSEric Cheng bf_pool->free += bf_pool->recycle; 419da14cebeSEric Cheng bf_pool->recycle = 0; 420da14cebeSEric Cheng mutex_exit(&bf_pool->pool_lock); 4217eced415Sxw161283 } 422da14cebeSEric Cheng mutex_exit(&bf_pool->recycle_lock); 4237eced415Sxw161283 424a23fd118Syl150051 /* 425a23fd118Syl150051 * If there is any posted buffer, the driver should reject to be 426a23fd118Syl150051 * detached. Need notice upper layer to release them. 427a23fd118Syl150051 */ 428da14cebeSEric Cheng if (bf_pool->post != 0) { 429a23fd118Syl150051 xge_debug_ll(XGE_ERR, 430a23fd118Syl150051 "%s%d has some buffers not be recycled, try later!", 431a23fd118Syl150051 XGELL_IFNAME, lldev->instance); 432da14cebeSEric Cheng return (B_FALSE); 433a23fd118Syl150051 } 434a23fd118Syl150051 435a23fd118Syl150051 /* 436da14cebeSEric Cheng * Release buffers one by one. 437a23fd118Syl150051 */ 438da14cebeSEric Cheng for (i = bf_pool->total; i > 0; i--) { 439da14cebeSEric Cheng rx_buffer = bf_pool->head; 440a23fd118Syl150051 xge_assert(rx_buffer != NULL); 441a23fd118Syl150051 442da14cebeSEric Cheng bf_pool->head = rx_buffer->next; 443a23fd118Syl150051 444a23fd118Syl150051 dma_handle = rx_buffer->dma_handle; 445a23fd118Syl150051 dma_acch = rx_buffer->dma_acch; 446a23fd118Syl150051 447a23fd118Syl150051 if (ddi_dma_unbind_handle(dma_handle) != DDI_SUCCESS) { 448da14cebeSEric Cheng xge_debug_ll(XGE_ERR, "failed to unbind DMA handle!"); 449da14cebeSEric Cheng bf_pool->head = rx_buffer; 450da14cebeSEric Cheng return (B_FALSE); 451a23fd118Syl150051 } 452a23fd118Syl150051 ddi_dma_mem_free(&dma_acch); 453a23fd118Syl150051 ddi_dma_free_handle(&dma_handle); 454a23fd118Syl150051 455da14cebeSEric Cheng bf_pool->total--; 456da14cebeSEric Cheng bf_pool->free--; 457a23fd118Syl150051 } 458a23fd118Syl150051 459da14cebeSEric Cheng xge_assert(!mutex_owned(&bf_pool->pool_lock)); 460da14cebeSEric Cheng 461da14cebeSEric Cheng mutex_destroy(&bf_pool->recycle_lock); 462da14cebeSEric Cheng mutex_destroy(&bf_pool->pool_lock); 463da14cebeSEric Cheng bf_pool->live = B_FALSE; 464da14cebeSEric Cheng 465da14cebeSEric Cheng return (B_TRUE); 466a23fd118Syl150051 } 467a23fd118Syl150051 468a23fd118Syl150051 /* 469a23fd118Syl150051 * xgell_rx_create_buffer_pool 470a23fd118Syl150051 * 471a23fd118Syl150051 * Initialize RX buffer pool for all RX rings. Refer to rx_buffer_pool_t. 472a23fd118Syl150051 */ 473da14cebeSEric Cheng static boolean_t 474da14cebeSEric Cheng xgell_rx_create_buffer_pool(xgell_rx_ring_t *ring) 475a23fd118Syl150051 { 476da14cebeSEric Cheng xgelldev_t *lldev = ring->lldev; 477da14cebeSEric Cheng xgell_rx_buffer_pool_t *bf_pool = &ring->bf_pool; 478a23fd118Syl150051 xge_hal_device_t *hldev; 479a23fd118Syl150051 xgell_rx_buffer_t *rx_buffer; 480a23fd118Syl150051 int i; 481a23fd118Syl150051 482da14cebeSEric Cheng if (bf_pool->live) 483da14cebeSEric Cheng return (B_TRUE); 484da14cebeSEric Cheng 485ba2e4443Sseb hldev = (xge_hal_device_t *)lldev->devh; 486a23fd118Syl150051 487da14cebeSEric Cheng bf_pool->total = 0; 488da14cebeSEric Cheng bf_pool->size = XGELL_MAX_FRAME_SIZE(hldev); 489da14cebeSEric Cheng bf_pool->head = NULL; 490da14cebeSEric Cheng bf_pool->free = 0; 491da14cebeSEric Cheng bf_pool->post = 0; 492da14cebeSEric Cheng bf_pool->post_hiwat = lldev->config.rx_buffer_post_hiwat; 493da14cebeSEric Cheng bf_pool->recycle = 0; 494da14cebeSEric Cheng bf_pool->recycle_head = NULL; 495da14cebeSEric Cheng bf_pool->recycle_tail = NULL; 496da14cebeSEric Cheng bf_pool->live = B_TRUE; 497a23fd118Syl150051 498da14cebeSEric Cheng mutex_init(&bf_pool->pool_lock, NULL, MUTEX_DRIVER, 4997eced415Sxw161283 DDI_INTR_PRI(hldev->irqh)); 500da14cebeSEric Cheng mutex_init(&bf_pool->recycle_lock, NULL, MUTEX_DRIVER, 5017eced415Sxw161283 DDI_INTR_PRI(hldev->irqh)); 502a23fd118Syl150051 503a23fd118Syl150051 /* 504a23fd118Syl150051 * Allocate buffers one by one. If failed, destroy whole pool by 505a23fd118Syl150051 * call to xgell_rx_destroy_buffer_pool(). 506a23fd118Syl150051 */ 5077eced415Sxw161283 508a23fd118Syl150051 for (i = 0; i < lldev->config.rx_buffer_total; i++) { 5097eced415Sxw161283 if ((rx_buffer = xgell_rx_buffer_alloc(ring)) == NULL) { 5107eced415Sxw161283 (void) xgell_rx_destroy_buffer_pool(ring); 511da14cebeSEric Cheng return (B_FALSE); 512a23fd118Syl150051 } 513a23fd118Syl150051 514da14cebeSEric Cheng rx_buffer->next = bf_pool->head; 515da14cebeSEric Cheng bf_pool->head = rx_buffer; 516a23fd118Syl150051 517da14cebeSEric Cheng bf_pool->total++; 518da14cebeSEric Cheng bf_pool->free++; 519a23fd118Syl150051 } 520a23fd118Syl150051 521da14cebeSEric Cheng return (B_TRUE); 522a23fd118Syl150051 } 523a23fd118Syl150051 524a23fd118Syl150051 /* 525a23fd118Syl150051 * xgell_rx_dtr_replenish 526a23fd118Syl150051 * 527a23fd118Syl150051 * Replenish descriptor with rx_buffer in RX buffer pool. 528a23fd118Syl150051 * The dtr should be post right away. 529a23fd118Syl150051 */ 530a23fd118Syl150051 xge_hal_status_e 531a23fd118Syl150051 xgell_rx_dtr_replenish(xge_hal_channel_h channelh, xge_hal_dtr_h dtr, int index, 532a23fd118Syl150051 void *userdata, xge_hal_channel_reopen_e reopen) 533a23fd118Syl150051 { 534da14cebeSEric Cheng xgell_rx_ring_t *ring = userdata; 535da14cebeSEric Cheng xgell_rx_buffer_pool_t *bf_pool = &ring->bf_pool; 536a23fd118Syl150051 xgell_rx_buffer_t *rx_buffer; 537a23fd118Syl150051 xgell_rxd_priv_t *rxd_priv; 538a23fd118Syl150051 539da14cebeSEric Cheng mutex_enter(&bf_pool->pool_lock); 540da14cebeSEric Cheng if (bf_pool->head == NULL) { 541da14cebeSEric Cheng xge_debug_ll(XGE_ERR, "no more available rx DMA buffer!"); 542a23fd118Syl150051 return (XGE_HAL_FAIL); 543a23fd118Syl150051 } 544da14cebeSEric Cheng rx_buffer = bf_pool->head; 545a23fd118Syl150051 xge_assert(rx_buffer); 546a23fd118Syl150051 xge_assert(rx_buffer->dma_addr); 547a23fd118Syl150051 548da14cebeSEric Cheng bf_pool->head = rx_buffer->next; 549da14cebeSEric Cheng bf_pool->free--; 550da14cebeSEric Cheng mutex_exit(&bf_pool->pool_lock); 551da14cebeSEric Cheng 5527eced415Sxw161283 rxd_priv = (xgell_rxd_priv_t *)xge_hal_ring_dtr_private(channelh, dtr); 553da14cebeSEric Cheng xge_hal_ring_dtr_1b_set(dtr, rx_buffer->dma_addr, bf_pool->size); 554a23fd118Syl150051 555a23fd118Syl150051 rxd_priv->rx_buffer = rx_buffer; 556a23fd118Syl150051 557a23fd118Syl150051 return (XGE_HAL_OK); 558a23fd118Syl150051 } 559a23fd118Syl150051 560a23fd118Syl150051 /* 561a23fd118Syl150051 * xgell_get_ip_offset 562a23fd118Syl150051 * 563a23fd118Syl150051 * Calculate the offset to IP header. 564a23fd118Syl150051 */ 565a23fd118Syl150051 static inline int 566a23fd118Syl150051 xgell_get_ip_offset(xge_hal_dtr_info_t *ext_info) 567a23fd118Syl150051 { 568a23fd118Syl150051 int ip_off; 569a23fd118Syl150051 570a23fd118Syl150051 /* get IP-header offset */ 571a23fd118Syl150051 switch (ext_info->frame) { 572a23fd118Syl150051 case XGE_HAL_FRAME_TYPE_DIX: 573a23fd118Syl150051 ip_off = XGE_HAL_HEADER_ETHERNET_II_802_3_SIZE; 574a23fd118Syl150051 break; 575a23fd118Syl150051 case XGE_HAL_FRAME_TYPE_IPX: 576a23fd118Syl150051 ip_off = (XGE_HAL_HEADER_ETHERNET_II_802_3_SIZE + 577a23fd118Syl150051 XGE_HAL_HEADER_802_2_SIZE + 578a23fd118Syl150051 XGE_HAL_HEADER_SNAP_SIZE); 579a23fd118Syl150051 break; 580a23fd118Syl150051 case XGE_HAL_FRAME_TYPE_LLC: 581a23fd118Syl150051 ip_off = (XGE_HAL_HEADER_ETHERNET_II_802_3_SIZE + 582a23fd118Syl150051 XGE_HAL_HEADER_802_2_SIZE); 583a23fd118Syl150051 break; 584a23fd118Syl150051 case XGE_HAL_FRAME_TYPE_SNAP: 585a23fd118Syl150051 ip_off = (XGE_HAL_HEADER_ETHERNET_II_802_3_SIZE + 586a23fd118Syl150051 XGE_HAL_HEADER_SNAP_SIZE); 587a23fd118Syl150051 break; 588a23fd118Syl150051 default: 589a23fd118Syl150051 ip_off = 0; 590a23fd118Syl150051 break; 591a23fd118Syl150051 } 592a23fd118Syl150051 593a23fd118Syl150051 if ((ext_info->proto & XGE_HAL_FRAME_PROTO_IPV4 || 594a23fd118Syl150051 ext_info->proto & XGE_HAL_FRAME_PROTO_IPV6) && 595a23fd118Syl150051 (ext_info->proto & XGE_HAL_FRAME_PROTO_VLAN_TAGGED)) { 596a23fd118Syl150051 ip_off += XGE_HAL_HEADER_VLAN_SIZE; 597a23fd118Syl150051 } 598a23fd118Syl150051 599a23fd118Syl150051 return (ip_off); 600a23fd118Syl150051 } 601a23fd118Syl150051 602a23fd118Syl150051 /* 603a23fd118Syl150051 * xgell_rx_hcksum_assoc 604a23fd118Syl150051 * 605a23fd118Syl150051 * Judge the packet type and then call to hcksum_assoc() to associate 606a23fd118Syl150051 * h/w checksum information. 607a23fd118Syl150051 */ 608a23fd118Syl150051 static inline void 609a23fd118Syl150051 xgell_rx_hcksum_assoc(mblk_t *mp, char *vaddr, int pkt_length, 610a23fd118Syl150051 xge_hal_dtr_info_t *ext_info) 611a23fd118Syl150051 { 612a23fd118Syl150051 int cksum_flags = 0; 613a23fd118Syl150051 614a23fd118Syl150051 if (!(ext_info->proto & XGE_HAL_FRAME_PROTO_IP_FRAGMENTED)) { 615a23fd118Syl150051 if (ext_info->proto & XGE_HAL_FRAME_PROTO_TCP_OR_UDP) { 616a23fd118Syl150051 if (ext_info->l3_cksum == XGE_HAL_L3_CKSUM_OK) { 6170dc2366fSVenugopal Iyer cksum_flags |= HCK_IPV4_HDRCKSUM_OK; 618a23fd118Syl150051 } 619a23fd118Syl150051 if (ext_info->l4_cksum == XGE_HAL_L4_CKSUM_OK) { 620a23fd118Syl150051 cksum_flags |= HCK_FULLCKSUM_OK; 621a23fd118Syl150051 } 6220dc2366fSVenugopal Iyer if (cksum_flags != 0) { 6230dc2366fSVenugopal Iyer mac_hcksum_set(mp, 0, 0, 0, 0, cksum_flags); 624a23fd118Syl150051 } 625a23fd118Syl150051 } 626a23fd118Syl150051 } else if (ext_info->proto & 627a23fd118Syl150051 (XGE_HAL_FRAME_PROTO_IPV4 | XGE_HAL_FRAME_PROTO_IPV6)) { 628a23fd118Syl150051 /* 629a23fd118Syl150051 * Just pass the partial cksum up to IP. 630a23fd118Syl150051 */ 6318347601bSyl150051 int ip_off = xgell_get_ip_offset(ext_info); 632a23fd118Syl150051 int start, end = pkt_length - ip_off; 633a23fd118Syl150051 634a23fd118Syl150051 if (ext_info->proto & XGE_HAL_FRAME_PROTO_IPV4) { 635a23fd118Syl150051 struct ip *ip = 636a23fd118Syl150051 (struct ip *)(vaddr + ip_off); 637f30c160eSRoamer start = ip->ip_hl * 4; 638a23fd118Syl150051 } else { 639f30c160eSRoamer start = 40; 640a23fd118Syl150051 } 641a23fd118Syl150051 cksum_flags |= HCK_PARTIALCKSUM; 6420dc2366fSVenugopal Iyer mac_hcksum_set(mp, start, 0, end, 6430dc2366fSVenugopal Iyer ntohs(ext_info->l4_cksum), cksum_flags); 644a23fd118Syl150051 } 645a23fd118Syl150051 } 646a23fd118Syl150051 647a23fd118Syl150051 /* 648a23fd118Syl150051 * xgell_rx_1b_msg_alloc 649a23fd118Syl150051 * 650a23fd118Syl150051 * Allocate message header for data buffer, and decide if copy the packet to 651a23fd118Syl150051 * new data buffer to release big rx_buffer to save memory. 652a23fd118Syl150051 * 6538347601bSyl150051 * If the pkt_length <= XGELL_RX_DMA_LOWAT, call allocb() to allocate 654a23fd118Syl150051 * new message and copy the payload in. 655a23fd118Syl150051 */ 656a23fd118Syl150051 static mblk_t * 657da14cebeSEric Cheng xgell_rx_1b_msg_alloc(xgell_rx_ring_t *ring, xgell_rx_buffer_t *rx_buffer, 6588347601bSyl150051 int pkt_length, xge_hal_dtr_info_t *ext_info, boolean_t *copyit) 659a23fd118Syl150051 { 660da14cebeSEric Cheng xgelldev_t *lldev = ring->lldev; 661a23fd118Syl150051 mblk_t *mp; 662a23fd118Syl150051 char *vaddr; 663a23fd118Syl150051 664a23fd118Syl150051 vaddr = (char *)rx_buffer->vaddr + HEADROOM; 665a23fd118Syl150051 /* 666a23fd118Syl150051 * Copy packet into new allocated message buffer, if pkt_length 6678347601bSyl150051 * is less than XGELL_RX_DMA_LOWAT 668a23fd118Syl150051 */ 6698347601bSyl150051 if (*copyit || pkt_length <= lldev->config.rx_dma_lowat) { 6707eced415Sxw161283 if ((mp = allocb(pkt_length + HEADROOM, 0)) == NULL) { 671a23fd118Syl150051 return (NULL); 672a23fd118Syl150051 } 6737eced415Sxw161283 mp->b_rptr += HEADROOM; 674a23fd118Syl150051 bcopy(vaddr, mp->b_rptr, pkt_length); 675a23fd118Syl150051 mp->b_wptr = mp->b_rptr + pkt_length; 676a23fd118Syl150051 *copyit = B_TRUE; 677a23fd118Syl150051 return (mp); 678a23fd118Syl150051 } 679a23fd118Syl150051 680a23fd118Syl150051 /* 681a23fd118Syl150051 * Just allocate mblk for current data buffer 682a23fd118Syl150051 */ 6833c785c4cSyl150051 if ((mp = (mblk_t *)desballoc((unsigned char *)vaddr, pkt_length, 0, 684a23fd118Syl150051 &rx_buffer->frtn)) == NULL) { 685a23fd118Syl150051 /* Drop it */ 686a23fd118Syl150051 return (NULL); 687a23fd118Syl150051 } 688a23fd118Syl150051 /* 6893c785c4cSyl150051 * Adjust the b_rptr/b_wptr in the mblk_t structure. 690a23fd118Syl150051 */ 6913c785c4cSyl150051 mp->b_wptr += pkt_length; 692a23fd118Syl150051 693a23fd118Syl150051 return (mp); 694a23fd118Syl150051 } 695a23fd118Syl150051 696a23fd118Syl150051 /* 697da14cebeSEric Cheng * xgell_rx_1b_callback 698a23fd118Syl150051 * 699a23fd118Syl150051 * If the interrupt is because of a received frame or if the receive ring 700a23fd118Syl150051 * contains fresh as yet un-processed frames, this function is called. 701a23fd118Syl150051 */ 702a23fd118Syl150051 static xge_hal_status_e 703da14cebeSEric Cheng xgell_rx_1b_callback(xge_hal_channel_h channelh, xge_hal_dtr_h dtr, u8 t_code, 704a23fd118Syl150051 void *userdata) 705a23fd118Syl150051 { 706da14cebeSEric Cheng xgell_rx_ring_t *ring = (xgell_rx_ring_t *)userdata; 7077eced415Sxw161283 xgelldev_t *lldev = ring->lldev; 708a23fd118Syl150051 xgell_rx_buffer_t *rx_buffer; 709a23fd118Syl150051 mblk_t *mp_head = NULL; 710a23fd118Syl150051 mblk_t *mp_end = NULL; 7118347601bSyl150051 int pkt_burst = 0; 7128347601bSyl150051 713da14cebeSEric Cheng xge_debug_ll(XGE_TRACE, "xgell_rx_1b_callback on ring %d", ring->index); 714a23fd118Syl150051 715da14cebeSEric Cheng mutex_enter(&ring->bf_pool.pool_lock); 716a23fd118Syl150051 do { 717a23fd118Syl150051 int pkt_length; 718a23fd118Syl150051 dma_addr_t dma_data; 719a23fd118Syl150051 mblk_t *mp; 720a23fd118Syl150051 boolean_t copyit = B_FALSE; 721a23fd118Syl150051 722a23fd118Syl150051 xgell_rxd_priv_t *rxd_priv = ((xgell_rxd_priv_t *) 723a23fd118Syl150051 xge_hal_ring_dtr_private(channelh, dtr)); 724a23fd118Syl150051 xge_hal_dtr_info_t ext_info; 725a23fd118Syl150051 726a23fd118Syl150051 rx_buffer = rxd_priv->rx_buffer; 727a23fd118Syl150051 728a23fd118Syl150051 xge_hal_ring_dtr_1b_get(channelh, dtr, &dma_data, &pkt_length); 729a23fd118Syl150051 xge_hal_ring_dtr_info_get(channelh, dtr, &ext_info); 730a23fd118Syl150051 731a23fd118Syl150051 xge_assert(dma_data == rx_buffer->dma_addr); 732a23fd118Syl150051 733a23fd118Syl150051 if (t_code != 0) { 734a23fd118Syl150051 xge_debug_ll(XGE_ERR, "%s%d: rx: dtr 0x%"PRIx64 735a23fd118Syl150051 " completed due to error t_code %01x", XGELL_IFNAME, 736a23fd118Syl150051 lldev->instance, (uint64_t)(uintptr_t)dtr, t_code); 737a23fd118Syl150051 738a23fd118Syl150051 (void) xge_hal_device_handle_tcode(channelh, dtr, 739a23fd118Syl150051 t_code); 740a23fd118Syl150051 xge_hal_ring_dtr_free(channelh, dtr); /* drop it */ 741a23fd118Syl150051 xgell_rx_buffer_release(rx_buffer); 742a23fd118Syl150051 continue; 743a23fd118Syl150051 } 744a23fd118Syl150051 745a23fd118Syl150051 /* 746a23fd118Syl150051 * Sync the DMA memory 747a23fd118Syl150051 */ 7488347601bSyl150051 if (ddi_dma_sync(rx_buffer->dma_handle, 0, pkt_length, 7498347601bSyl150051 DDI_DMA_SYNC_FORKERNEL) != DDI_SUCCESS) { 750a23fd118Syl150051 xge_debug_ll(XGE_ERR, "%s%d: rx: can not do DMA sync", 751a23fd118Syl150051 XGELL_IFNAME, lldev->instance); 752a23fd118Syl150051 xge_hal_ring_dtr_free(channelh, dtr); /* drop it */ 753a23fd118Syl150051 xgell_rx_buffer_release(rx_buffer); 754a23fd118Syl150051 continue; 755a23fd118Syl150051 } 756a23fd118Syl150051 757a23fd118Syl150051 /* 758a23fd118Syl150051 * Allocate message for the packet. 759a23fd118Syl150051 */ 7607eced415Sxw161283 if (ring->bf_pool.post > ring->bf_pool.post_hiwat) { 761a23fd118Syl150051 copyit = B_TRUE; 762a23fd118Syl150051 } else { 763a23fd118Syl150051 copyit = B_FALSE; 764a23fd118Syl150051 } 765a23fd118Syl150051 766da14cebeSEric Cheng mp = xgell_rx_1b_msg_alloc(ring, rx_buffer, pkt_length, 7678347601bSyl150051 &ext_info, ©it); 768a23fd118Syl150051 769a23fd118Syl150051 xge_hal_ring_dtr_free(channelh, dtr); 770a23fd118Syl150051 771a23fd118Syl150051 /* 772a23fd118Syl150051 * Release the buffer and recycle it later 773a23fd118Syl150051 */ 774a23fd118Syl150051 if ((mp == NULL) || copyit) { 775a23fd118Syl150051 xgell_rx_buffer_release(rx_buffer); 776a23fd118Syl150051 } else { 777a23fd118Syl150051 /* 778a23fd118Syl150051 * Count it since the buffer should be loaned up. 779a23fd118Syl150051 */ 7807eced415Sxw161283 ring->bf_pool.post++; 781a23fd118Syl150051 } 782a23fd118Syl150051 if (mp == NULL) { 783a23fd118Syl150051 xge_debug_ll(XGE_ERR, 7848347601bSyl150051 "%s%d: rx: can not allocate mp mblk", 7858347601bSyl150051 XGELL_IFNAME, lldev->instance); 786a23fd118Syl150051 continue; 787a23fd118Syl150051 } 788a23fd118Syl150051 789a23fd118Syl150051 /* 7908347601bSyl150051 * Associate cksum_flags per packet type and h/w 7918347601bSyl150051 * cksum flags. 792a23fd118Syl150051 */ 793da14cebeSEric Cheng xgell_rx_hcksum_assoc(mp, (char *)rx_buffer->vaddr + HEADROOM, 794da14cebeSEric Cheng pkt_length, &ext_info); 795da14cebeSEric Cheng 7960dc2366fSVenugopal Iyer ring->rx_pkts++; 7970dc2366fSVenugopal Iyer ring->rx_bytes += pkt_length; 798a23fd118Syl150051 799a23fd118Syl150051 if (mp_head == NULL) { 800a23fd118Syl150051 mp_head = mp; 801a23fd118Syl150051 mp_end = mp; 802a23fd118Syl150051 } else { 803a23fd118Syl150051 mp_end->b_next = mp; 804a23fd118Syl150051 mp_end = mp; 805a23fd118Syl150051 } 806a23fd118Syl150051 807da14cebeSEric Cheng /* 808da14cebeSEric Cheng * Inlined implemented polling function. 809da14cebeSEric Cheng */ 810da14cebeSEric Cheng if ((ring->poll_mp == NULL) && (ring->poll_bytes > 0)) { 811da14cebeSEric Cheng ring->poll_mp = mp_head; 812da14cebeSEric Cheng } 813da14cebeSEric Cheng if (ring->poll_mp != NULL) { 814da14cebeSEric Cheng if ((ring->poll_bytes -= pkt_length) <= 0) { 815da14cebeSEric Cheng /* have polled enough packets. */ 816da14cebeSEric Cheng break; 817da14cebeSEric Cheng } else { 818da14cebeSEric Cheng /* continue polling packets. */ 819da14cebeSEric Cheng continue; 820da14cebeSEric Cheng } 821da14cebeSEric Cheng } 822da14cebeSEric Cheng 823da14cebeSEric Cheng /* 824da14cebeSEric Cheng * We're not in polling mode, so try to chain more messages 825da14cebeSEric Cheng * or send the chain up according to pkt_burst. 826da14cebeSEric Cheng */ 8278347601bSyl150051 if (++pkt_burst < lldev->config.rx_pkt_burst) 8288347601bSyl150051 continue; 8298347601bSyl150051 8307eced415Sxw161283 if (ring->bf_pool.post > ring->bf_pool.post_hiwat) { 8318347601bSyl150051 /* Replenish rx buffers */ 8327eced415Sxw161283 xgell_rx_buffer_replenish_all(ring); 8338347601bSyl150051 } 8347eced415Sxw161283 mutex_exit(&ring->bf_pool.pool_lock); 8358347601bSyl150051 if (mp_head != NULL) { 836da14cebeSEric Cheng mac_rx_ring(lldev->mh, ring->ring_handle, mp_head, 837da14cebeSEric Cheng ring->ring_gen_num); 8388347601bSyl150051 } 8398347601bSyl150051 mp_head = mp_end = NULL; 8408347601bSyl150051 pkt_burst = 0; 8417eced415Sxw161283 mutex_enter(&ring->bf_pool.pool_lock); 8428347601bSyl150051 843a23fd118Syl150051 } while (xge_hal_ring_dtr_next_completed(channelh, &dtr, &t_code) == 844a23fd118Syl150051 XGE_HAL_OK); 845a23fd118Syl150051 846a23fd118Syl150051 /* 847a23fd118Syl150051 * Always call replenish_all to recycle rx_buffers. 848a23fd118Syl150051 */ 8497eced415Sxw161283 xgell_rx_buffer_replenish_all(ring); 8507eced415Sxw161283 mutex_exit(&ring->bf_pool.pool_lock); 851a23fd118Syl150051 852da14cebeSEric Cheng /* 853da14cebeSEric Cheng * If we're not in polling cycle, call mac_rx(), otherwise 854da14cebeSEric Cheng * just return while leaving packets chained to ring->poll_mp. 855da14cebeSEric Cheng */ 856da14cebeSEric Cheng if ((ring->poll_mp == NULL) && (mp_head != NULL)) { 857da14cebeSEric Cheng mac_rx_ring(lldev->mh, ring->ring_handle, mp_head, 858da14cebeSEric Cheng ring->ring_gen_num); 8598347601bSyl150051 } 8608347601bSyl150051 861a23fd118Syl150051 return (XGE_HAL_OK); 862a23fd118Syl150051 } 863a23fd118Syl150051 864da14cebeSEric Cheng mblk_t * 865da14cebeSEric Cheng xgell_rx_poll(void *arg, int bytes_to_pickup) 866da14cebeSEric Cheng { 867da14cebeSEric Cheng xgell_rx_ring_t *ring = (xgell_rx_ring_t *)arg; 868da14cebeSEric Cheng int got_rx = 0; 869da14cebeSEric Cheng mblk_t *mp; 870da14cebeSEric Cheng 871da14cebeSEric Cheng xge_debug_ll(XGE_TRACE, "xgell_rx_poll on ring %d", ring->index); 872da14cebeSEric Cheng 873da14cebeSEric Cheng ring->poll_mp = NULL; 874da14cebeSEric Cheng ring->poll_bytes = bytes_to_pickup; 875da14cebeSEric Cheng (void) xge_hal_device_poll_rx_channel(ring->channelh, &got_rx); 876da14cebeSEric Cheng 877da14cebeSEric Cheng mp = ring->poll_mp; 878da14cebeSEric Cheng ring->poll_bytes = -1; 879da14cebeSEric Cheng ring->polled_bytes += got_rx; 880da14cebeSEric Cheng ring->poll_mp = NULL; 881da14cebeSEric Cheng 882da14cebeSEric Cheng return (mp); 883da14cebeSEric Cheng } 884da14cebeSEric Cheng 885a23fd118Syl150051 /* 886a23fd118Syl150051 * xgell_xmit_compl 887a23fd118Syl150051 * 888a23fd118Syl150051 * If an interrupt was raised to indicate DMA complete of the Tx packet, 889a23fd118Syl150051 * this function is called. It identifies the last TxD whose buffer was 890a23fd118Syl150051 * freed and frees all skbs whose data have already DMA'ed into the NICs 891a23fd118Syl150051 * internal memory. 892a23fd118Syl150051 */ 893a23fd118Syl150051 static xge_hal_status_e 894a23fd118Syl150051 xgell_xmit_compl(xge_hal_channel_h channelh, xge_hal_dtr_h dtr, u8 t_code, 895a23fd118Syl150051 void *userdata) 896a23fd118Syl150051 { 897da14cebeSEric Cheng xgell_tx_ring_t *ring = userdata; 898da14cebeSEric Cheng xgelldev_t *lldev = ring->lldev; 899a23fd118Syl150051 900a23fd118Syl150051 do { 901a23fd118Syl150051 xgell_txd_priv_t *txd_priv = ((xgell_txd_priv_t *) 902a23fd118Syl150051 xge_hal_fifo_dtr_private(dtr)); 903a23fd118Syl150051 int i; 904a23fd118Syl150051 905a23fd118Syl150051 if (t_code) { 906a23fd118Syl150051 xge_debug_ll(XGE_TRACE, "%s%d: tx: dtr 0x%"PRIx64 907a23fd118Syl150051 " completed due to error t_code %01x", XGELL_IFNAME, 908a23fd118Syl150051 lldev->instance, (uint64_t)(uintptr_t)dtr, t_code); 909a23fd118Syl150051 910a23fd118Syl150051 (void) xge_hal_device_handle_tcode(channelh, dtr, 911a23fd118Syl150051 t_code); 912a23fd118Syl150051 } 913a23fd118Syl150051 914a23fd118Syl150051 for (i = 0; i < txd_priv->handle_cnt; i++) { 9157eced415Sxw161283 if (txd_priv->dma_handles[i] != NULL) { 916a23fd118Syl150051 xge_assert(txd_priv->dma_handles[i]); 9177eced415Sxw161283 (void) ddi_dma_unbind_handle( 9187eced415Sxw161283 txd_priv->dma_handles[i]); 919a23fd118Syl150051 ddi_dma_free_handle(&txd_priv->dma_handles[i]); 920a23fd118Syl150051 txd_priv->dma_handles[i] = 0; 921a23fd118Syl150051 } 9227eced415Sxw161283 } 9237eced415Sxw161283 txd_priv->handle_cnt = 0; 924a23fd118Syl150051 925a23fd118Syl150051 xge_hal_fifo_dtr_free(channelh, dtr); 926a23fd118Syl150051 9277eced415Sxw161283 if (txd_priv->mblk != NULL) { 9287eced415Sxw161283 freemsg(txd_priv->mblk); 9297eced415Sxw161283 txd_priv->mblk = NULL; 9307eced415Sxw161283 } 9317eced415Sxw161283 932a23fd118Syl150051 } while (xge_hal_fifo_dtr_next_completed(channelh, &dtr, &t_code) == 933a23fd118Syl150051 XGE_HAL_OK); 934a23fd118Syl150051 935da14cebeSEric Cheng if (ring->need_resched) 936da14cebeSEric Cheng mac_tx_ring_update(lldev->mh, ring->ring_handle); 937a23fd118Syl150051 938a23fd118Syl150051 return (XGE_HAL_OK); 939a23fd118Syl150051 } 940a23fd118Syl150051 941da14cebeSEric Cheng mblk_t * 942da14cebeSEric Cheng xgell_ring_tx(void *arg, mblk_t *mp) 943a23fd118Syl150051 { 944da14cebeSEric Cheng xgell_tx_ring_t *ring = (xgell_tx_ring_t *)arg; 945a23fd118Syl150051 mblk_t *bp; 946da14cebeSEric Cheng xgelldev_t *lldev = ring->lldev; 9478347601bSyl150051 xge_hal_device_t *hldev = lldev->devh; 948a23fd118Syl150051 xge_hal_status_e status; 949a23fd118Syl150051 xge_hal_dtr_h dtr; 950a23fd118Syl150051 xgell_txd_priv_t *txd_priv; 9518347601bSyl150051 uint32_t hckflags; 952da14cebeSEric Cheng uint32_t lsoflags; 9538347601bSyl150051 uint32_t mss; 9548347601bSyl150051 int handle_cnt, frag_cnt, ret, i, copied; 9558347601bSyl150051 boolean_t used_copy; 9560dc2366fSVenugopal Iyer uint64_t sent_bytes; 957a23fd118Syl150051 958a23fd118Syl150051 _begin: 959a23fd118Syl150051 handle_cnt = frag_cnt = 0; 9600dc2366fSVenugopal Iyer sent_bytes = 0; 961a23fd118Syl150051 962a23fd118Syl150051 if (!lldev->is_initialized || lldev->in_reset) 963da14cebeSEric Cheng return (mp); 9647eced415Sxw161283 965a23fd118Syl150051 /* 966a23fd118Syl150051 * If the free Tx dtrs count reaches the lower threshold, 967a23fd118Syl150051 * inform the gld to stop sending more packets till the free 968a23fd118Syl150051 * dtrs count exceeds higher threshold. Driver informs the 969a23fd118Syl150051 * gld through gld_sched call, when the free dtrs count exceeds 970a23fd118Syl150051 * the higher threshold. 971a23fd118Syl150051 */ 972da14cebeSEric Cheng if (xge_hal_channel_dtr_count(ring->channelh) 973a23fd118Syl150051 <= XGELL_TX_LEVEL_LOW) { 974a23fd118Syl150051 xge_debug_ll(XGE_TRACE, "%s%d: queue %d: err on xmit," 975a23fd118Syl150051 "free descriptors count at low threshold %d", 976a23fd118Syl150051 XGELL_IFNAME, lldev->instance, 977da14cebeSEric Cheng ((xge_hal_channel_t *)ring->channelh)->post_qid, 978a23fd118Syl150051 XGELL_TX_LEVEL_LOW); 979a23fd118Syl150051 goto _exit; 980a23fd118Syl150051 } 981a23fd118Syl150051 982da14cebeSEric Cheng status = xge_hal_fifo_dtr_reserve(ring->channelh, &dtr); 983a23fd118Syl150051 if (status != XGE_HAL_OK) { 984a23fd118Syl150051 switch (status) { 985a23fd118Syl150051 case XGE_HAL_INF_CHANNEL_IS_NOT_READY: 986a23fd118Syl150051 xge_debug_ll(XGE_ERR, 987a23fd118Syl150051 "%s%d: channel %d is not ready.", XGELL_IFNAME, 988a23fd118Syl150051 lldev->instance, 989a23fd118Syl150051 ((xge_hal_channel_t *) 990da14cebeSEric Cheng ring->channelh)->post_qid); 991a23fd118Syl150051 goto _exit; 992a23fd118Syl150051 case XGE_HAL_INF_OUT_OF_DESCRIPTORS: 993a23fd118Syl150051 xge_debug_ll(XGE_TRACE, "%s%d: queue %d: error in xmit," 994a23fd118Syl150051 " out of descriptors.", XGELL_IFNAME, 995a23fd118Syl150051 lldev->instance, 996a23fd118Syl150051 ((xge_hal_channel_t *) 997da14cebeSEric Cheng ring->channelh)->post_qid); 998a23fd118Syl150051 goto _exit; 999a23fd118Syl150051 default: 1000da14cebeSEric Cheng return (mp); 1001a23fd118Syl150051 } 1002a23fd118Syl150051 } 1003a23fd118Syl150051 1004a23fd118Syl150051 txd_priv = xge_hal_fifo_dtr_private(dtr); 1005a23fd118Syl150051 txd_priv->mblk = mp; 1006a23fd118Syl150051 1007a23fd118Syl150051 /* 1008a23fd118Syl150051 * VLAN tag should be passed down along with MAC header, so h/w needn't 1009a23fd118Syl150051 * do insertion. 1010a23fd118Syl150051 * 1011a23fd118Syl150051 * For NIC driver that has to strip and re-insert VLAN tag, the example 1012a23fd118Syl150051 * is the other implementation for xge. The driver can simple bcopy() 1013a23fd118Syl150051 * ether_vlan_header to overwrite VLAN tag and let h/w insert the tag 1014a23fd118Syl150051 * automatically, since it's impossible that GLD sends down mp(s) with 1015a23fd118Syl150051 * splited ether_vlan_header. 1016a23fd118Syl150051 * 1017a23fd118Syl150051 * struct ether_vlan_header *evhp; 1018a23fd118Syl150051 * uint16_t tci; 1019a23fd118Syl150051 * 1020a23fd118Syl150051 * evhp = (struct ether_vlan_header *)mp->b_rptr; 1021a23fd118Syl150051 * if (evhp->ether_tpid == htons(VLAN_TPID)) { 1022a23fd118Syl150051 * tci = ntohs(evhp->ether_tci); 1023a23fd118Syl150051 * (void) bcopy(mp->b_rptr, mp->b_rptr + VLAN_TAGSZ, 1024a23fd118Syl150051 * 2 * ETHERADDRL); 1025a23fd118Syl150051 * mp->b_rptr += VLAN_TAGSZ; 1026a23fd118Syl150051 * 1027a23fd118Syl150051 * xge_hal_fifo_dtr_vlan_set(dtr, tci); 1028a23fd118Syl150051 * } 1029a23fd118Syl150051 */ 1030a23fd118Syl150051 10318347601bSyl150051 copied = 0; 10328347601bSyl150051 used_copy = B_FALSE; 1033a23fd118Syl150051 for (bp = mp; bp != NULL; bp = bp->b_cont) { 1034a23fd118Syl150051 int mblen; 1035a23fd118Syl150051 uint_t ncookies; 1036a23fd118Syl150051 ddi_dma_cookie_t dma_cookie; 1037a23fd118Syl150051 ddi_dma_handle_t dma_handle; 1038a23fd118Syl150051 1039a23fd118Syl150051 /* skip zero-length message blocks */ 1040a23fd118Syl150051 mblen = MBLKL(bp); 1041a23fd118Syl150051 if (mblen == 0) { 1042a23fd118Syl150051 continue; 1043a23fd118Syl150051 } 1044a23fd118Syl150051 10450dc2366fSVenugopal Iyer sent_bytes += mblen; 1046da14cebeSEric Cheng 10478347601bSyl150051 /* 10488347601bSyl150051 * Check the message length to decide to DMA or bcopy() data 10498347601bSyl150051 * to tx descriptor(s). 10508347601bSyl150051 */ 10518347601bSyl150051 if (mblen < lldev->config.tx_dma_lowat && 10528347601bSyl150051 (copied + mblen) < lldev->tx_copied_max) { 10538347601bSyl150051 xge_hal_status_e rc; 1054da14cebeSEric Cheng rc = xge_hal_fifo_dtr_buffer_append(ring->channelh, 10558347601bSyl150051 dtr, bp->b_rptr, mblen); 10568347601bSyl150051 if (rc == XGE_HAL_OK) { 10578347601bSyl150051 used_copy = B_TRUE; 10588347601bSyl150051 copied += mblen; 10598347601bSyl150051 continue; 10608347601bSyl150051 } else if (used_copy) { 10618347601bSyl150051 xge_hal_fifo_dtr_buffer_finalize( 1062da14cebeSEric Cheng ring->channelh, dtr, frag_cnt++); 10638347601bSyl150051 used_copy = B_FALSE; 10648347601bSyl150051 } 10658347601bSyl150051 } else if (used_copy) { 1066da14cebeSEric Cheng xge_hal_fifo_dtr_buffer_finalize(ring->channelh, 10678347601bSyl150051 dtr, frag_cnt++); 10688347601bSyl150051 used_copy = B_FALSE; 10698347601bSyl150051 } 10708347601bSyl150051 1071ba2e4443Sseb ret = ddi_dma_alloc_handle(lldev->dev_info, &tx_dma_attr, 1072a23fd118Syl150051 DDI_DMA_DONTWAIT, 0, &dma_handle); 1073a23fd118Syl150051 if (ret != DDI_SUCCESS) { 1074a23fd118Syl150051 xge_debug_ll(XGE_ERR, 10758347601bSyl150051 "%s%d: can not allocate dma handle", XGELL_IFNAME, 10768347601bSyl150051 lldev->instance); 1077a23fd118Syl150051 goto _exit_cleanup; 1078a23fd118Syl150051 } 1079a23fd118Syl150051 1080a23fd118Syl150051 ret = ddi_dma_addr_bind_handle(dma_handle, NULL, 1081a23fd118Syl150051 (caddr_t)bp->b_rptr, mblen, 1082a23fd118Syl150051 DDI_DMA_WRITE | DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 0, 1083a23fd118Syl150051 &dma_cookie, &ncookies); 1084a23fd118Syl150051 1085a23fd118Syl150051 switch (ret) { 1086a23fd118Syl150051 case DDI_DMA_MAPPED: 1087a23fd118Syl150051 /* everything's fine */ 1088a23fd118Syl150051 break; 1089a23fd118Syl150051 1090a23fd118Syl150051 case DDI_DMA_NORESOURCES: 1091a23fd118Syl150051 xge_debug_ll(XGE_ERR, 1092a23fd118Syl150051 "%s%d: can not bind dma address", 1093a23fd118Syl150051 XGELL_IFNAME, lldev->instance); 1094a23fd118Syl150051 ddi_dma_free_handle(&dma_handle); 1095a23fd118Syl150051 goto _exit_cleanup; 1096a23fd118Syl150051 1097a23fd118Syl150051 case DDI_DMA_NOMAPPING: 1098a23fd118Syl150051 case DDI_DMA_INUSE: 1099a23fd118Syl150051 case DDI_DMA_TOOBIG: 1100a23fd118Syl150051 default: 1101a23fd118Syl150051 /* drop packet, don't retry */ 1102a23fd118Syl150051 xge_debug_ll(XGE_ERR, 1103a23fd118Syl150051 "%s%d: can not map message buffer", 1104a23fd118Syl150051 XGELL_IFNAME, lldev->instance); 1105a23fd118Syl150051 ddi_dma_free_handle(&dma_handle); 1106a23fd118Syl150051 goto _exit_cleanup; 1107a23fd118Syl150051 } 1108a23fd118Syl150051 11098347601bSyl150051 if (ncookies + frag_cnt > hldev->config.fifo.max_frags) { 1110a23fd118Syl150051 xge_debug_ll(XGE_ERR, "%s%d: too many fragments, " 1111a23fd118Syl150051 "requested c:%d+f:%d", XGELL_IFNAME, 1112a23fd118Syl150051 lldev->instance, ncookies, frag_cnt); 1113a23fd118Syl150051 (void) ddi_dma_unbind_handle(dma_handle); 1114a23fd118Syl150051 ddi_dma_free_handle(&dma_handle); 1115a23fd118Syl150051 goto _exit_cleanup; 1116a23fd118Syl150051 } 1117a23fd118Syl150051 1118a23fd118Syl150051 /* setup the descriptors for this data buffer */ 1119a23fd118Syl150051 while (ncookies) { 1120da14cebeSEric Cheng xge_hal_fifo_dtr_buffer_set(ring->channelh, dtr, 1121a23fd118Syl150051 frag_cnt++, dma_cookie.dmac_laddress, 1122a23fd118Syl150051 dma_cookie.dmac_size); 1123a23fd118Syl150051 if (--ncookies) { 1124a23fd118Syl150051 ddi_dma_nextcookie(dma_handle, &dma_cookie); 1125a23fd118Syl150051 } 1126a23fd118Syl150051 1127a23fd118Syl150051 } 1128a23fd118Syl150051 1129a23fd118Syl150051 txd_priv->dma_handles[handle_cnt++] = dma_handle; 1130a23fd118Syl150051 1131a23fd118Syl150051 if (bp->b_cont && 1132a23fd118Syl150051 (frag_cnt + XGE_HAL_DEFAULT_FIFO_FRAGS_THRESHOLD >= 11338347601bSyl150051 hldev->config.fifo.max_frags)) { 1134a23fd118Syl150051 mblk_t *nmp; 1135a23fd118Syl150051 1136a23fd118Syl150051 xge_debug_ll(XGE_TRACE, 1137a23fd118Syl150051 "too many FRAGs [%d], pull up them", frag_cnt); 1138a23fd118Syl150051 1139a23fd118Syl150051 if ((nmp = msgpullup(bp->b_cont, -1)) == NULL) { 1140a23fd118Syl150051 /* Drop packet, don't retry */ 1141a23fd118Syl150051 xge_debug_ll(XGE_ERR, 1142a23fd118Syl150051 "%s%d: can not pullup message buffer", 1143a23fd118Syl150051 XGELL_IFNAME, lldev->instance); 1144a23fd118Syl150051 goto _exit_cleanup; 1145a23fd118Syl150051 } 1146a23fd118Syl150051 freemsg(bp->b_cont); 1147a23fd118Syl150051 bp->b_cont = nmp; 1148a23fd118Syl150051 } 1149a23fd118Syl150051 } 1150a23fd118Syl150051 11518347601bSyl150051 /* finalize unfinished copies */ 11528347601bSyl150051 if (used_copy) { 1153da14cebeSEric Cheng xge_hal_fifo_dtr_buffer_finalize(ring->channelh, dtr, 11548347601bSyl150051 frag_cnt++); 11558347601bSyl150051 } 1156a23fd118Syl150051 11578347601bSyl150051 txd_priv->handle_cnt = handle_cnt; 11588347601bSyl150051 11598347601bSyl150051 /* 11608347601bSyl150051 * If LSO is required, just call xge_hal_fifo_dtr_mss_set(dtr, mss) to 11618347601bSyl150051 * do all necessary work. 11628347601bSyl150051 */ 11630dc2366fSVenugopal Iyer mac_lso_get(mp, &mss, &lsoflags); 1164da14cebeSEric Cheng 1165da14cebeSEric Cheng if (lsoflags & HW_LSO) { 1166da14cebeSEric Cheng xge_assert((mss != 0) && (mss <= XGE_HAL_DEFAULT_MTU)); 11678347601bSyl150051 xge_hal_fifo_dtr_mss_set(dtr, mss); 11688347601bSyl150051 } 11698347601bSyl150051 11700dc2366fSVenugopal Iyer mac_hcksum_get(mp, NULL, NULL, NULL, NULL, &hckflags); 11718347601bSyl150051 if (hckflags & HCK_IPV4_HDRCKSUM) { 1172a23fd118Syl150051 xge_hal_fifo_dtr_cksum_set_bits(dtr, 1173a23fd118Syl150051 XGE_HAL_TXD_TX_CKO_IPV4_EN); 1174a23fd118Syl150051 } 11758347601bSyl150051 if (hckflags & HCK_FULLCKSUM) { 1176a23fd118Syl150051 xge_hal_fifo_dtr_cksum_set_bits(dtr, XGE_HAL_TXD_TX_CKO_TCP_EN | 1177a23fd118Syl150051 XGE_HAL_TXD_TX_CKO_UDP_EN); 1178a23fd118Syl150051 } 1179a23fd118Syl150051 1180da14cebeSEric Cheng xge_hal_fifo_dtr_post(ring->channelh, dtr); 1181a23fd118Syl150051 11820dc2366fSVenugopal Iyer /* Update per-ring tx statistics */ 1183*1a5e258fSJosef 'Jeff' Sipek atomic_inc_64(&ring->tx_pkts); 11840dc2366fSVenugopal Iyer atomic_add_64(&ring->tx_bytes, sent_bytes); 11850dc2366fSVenugopal Iyer 1186da14cebeSEric Cheng return (NULL); 1187a23fd118Syl150051 1188a23fd118Syl150051 _exit_cleanup: 1189da14cebeSEric Cheng /* 1190da14cebeSEric Cheng * Could not successfully transmit but have changed the message, 1191da14cebeSEric Cheng * so just free it and return NULL 1192da14cebeSEric Cheng */ 1193a23fd118Syl150051 for (i = 0; i < handle_cnt; i++) { 1194a23fd118Syl150051 (void) ddi_dma_unbind_handle(txd_priv->dma_handles[i]); 1195a23fd118Syl150051 ddi_dma_free_handle(&txd_priv->dma_handles[i]); 1196a23fd118Syl150051 txd_priv->dma_handles[i] = 0; 1197a23fd118Syl150051 } 1198a23fd118Syl150051 1199da14cebeSEric Cheng xge_hal_fifo_dtr_free(ring->channelh, dtr); 1200da14cebeSEric Cheng 1201da14cebeSEric Cheng freemsg(mp); 1202da14cebeSEric Cheng return (NULL); 1203a23fd118Syl150051 1204a23fd118Syl150051 _exit: 1205da14cebeSEric Cheng ring->need_resched = B_TRUE; 1206da14cebeSEric Cheng return (mp); 1207a23fd118Syl150051 } 1208a23fd118Syl150051 1209a23fd118Syl150051 /* 1210da14cebeSEric Cheng * xgell_ring_macaddr_init 1211a23fd118Syl150051 */ 1212da14cebeSEric Cheng static void 1213da14cebeSEric Cheng xgell_rx_ring_maddr_init(xgell_rx_ring_t *ring) 1214a23fd118Syl150051 { 1215da14cebeSEric Cheng int i; 1216da14cebeSEric Cheng xgelldev_t *lldev = ring->lldev; 1217da14cebeSEric Cheng xge_hal_device_t *hldev = lldev->devh; 1218da14cebeSEric Cheng int slot_start; 1219a23fd118Syl150051 1220da14cebeSEric Cheng xge_debug_ll(XGE_TRACE, "%s", "xgell_rx_ring_maddr_init"); 1221a23fd118Syl150051 1222da14cebeSEric Cheng ring->mmac.naddr = XGE_RX_MULTI_MAC_ADDRESSES_MAX; 1223da14cebeSEric Cheng ring->mmac.naddrfree = ring->mmac.naddr; 1224da14cebeSEric Cheng 1225da14cebeSEric Cheng /* 1226da14cebeSEric Cheng * For the default rx ring, the first MAC address is the factory one. 1227da14cebeSEric Cheng * This will be set by the framework, so need to clear it for now. 1228da14cebeSEric Cheng */ 1229da14cebeSEric Cheng (void) xge_hal_device_macaddr_clear(hldev, 0); 1230da14cebeSEric Cheng 1231da14cebeSEric Cheng /* 1232da14cebeSEric Cheng * Read the MAC address Configuration Memory from HAL. 1233da14cebeSEric Cheng * The first slot will hold a factory MAC address, contents in other 1234da14cebeSEric Cheng * slots will be FF:FF:FF:FF:FF:FF. 1235da14cebeSEric Cheng */ 1236da14cebeSEric Cheng slot_start = ring->index * 32; 1237da14cebeSEric Cheng for (i = 0; i < ring->mmac.naddr; i++) { 1238da14cebeSEric Cheng (void) xge_hal_device_macaddr_get(hldev, slot_start + i, 1239da14cebeSEric Cheng ring->mmac.mac_addr + i); 1240da14cebeSEric Cheng ring->mmac.mac_addr_set[i] = B_FALSE; 1241da14cebeSEric Cheng } 1242da14cebeSEric Cheng } 1243da14cebeSEric Cheng 1244da14cebeSEric Cheng static int xgell_maddr_set(xgelldev_t *, int, uint8_t *); 1245da14cebeSEric Cheng 1246da14cebeSEric Cheng static int 1247da14cebeSEric Cheng xgell_addmac(void *arg, const uint8_t *mac_addr) 1248da14cebeSEric Cheng { 1249da14cebeSEric Cheng xgell_rx_ring_t *ring = arg; 1250da14cebeSEric Cheng xgelldev_t *lldev = ring->lldev; 1251da14cebeSEric Cheng xge_hal_device_t *hldev = lldev->devh; 1252da14cebeSEric Cheng int slot; 1253da14cebeSEric Cheng int slot_start; 1254da14cebeSEric Cheng 1255da14cebeSEric Cheng xge_debug_ll(XGE_TRACE, "%s", "xgell_addmac"); 1256da14cebeSEric Cheng 1257da14cebeSEric Cheng mutex_enter(&lldev->genlock); 1258da14cebeSEric Cheng 1259da14cebeSEric Cheng if (ring->mmac.naddrfree == 0) { 1260da14cebeSEric Cheng mutex_exit(&lldev->genlock); 1261da14cebeSEric Cheng return (ENOSPC); 1262da14cebeSEric Cheng } 1263da14cebeSEric Cheng 1264da14cebeSEric Cheng /* First slot is for factory MAC address */ 1265da14cebeSEric Cheng for (slot = 0; slot < ring->mmac.naddr; slot++) { 1266da14cebeSEric Cheng if (ring->mmac.mac_addr_set[slot] == B_FALSE) { 1267a23fd118Syl150051 break; 1268a23fd118Syl150051 } 1269a23fd118Syl150051 } 1270a23fd118Syl150051 1271da14cebeSEric Cheng ASSERT(slot < ring->mmac.naddr); 1272da14cebeSEric Cheng 1273da14cebeSEric Cheng slot_start = ring->index * 32; 1274da14cebeSEric Cheng 1275da14cebeSEric Cheng if (xgell_maddr_set(lldev, slot_start + slot, (uint8_t *)mac_addr) != 1276da14cebeSEric Cheng 0) { 1277da14cebeSEric Cheng mutex_exit(&lldev->genlock); 1278da14cebeSEric Cheng return (EIO); 1279da14cebeSEric Cheng } 1280da14cebeSEric Cheng 1281da14cebeSEric Cheng /* Simply enable RTS for the whole section. */ 1282da14cebeSEric Cheng (void) xge_hal_device_rts_section_enable(hldev, slot_start + slot); 1283da14cebeSEric Cheng 1284da14cebeSEric Cheng /* 1285da14cebeSEric Cheng * Read back the MAC address from HAL to keep the array up to date. 1286da14cebeSEric Cheng */ 1287da14cebeSEric Cheng if (xge_hal_device_macaddr_get(hldev, slot_start + slot, 1288da14cebeSEric Cheng ring->mmac.mac_addr + slot) != XGE_HAL_OK) { 1289da14cebeSEric Cheng (void) xge_hal_device_macaddr_clear(hldev, slot_start + slot); 1290da14cebeSEric Cheng return (EIO); 1291da14cebeSEric Cheng } 1292da14cebeSEric Cheng 1293da14cebeSEric Cheng ring->mmac.mac_addr_set[slot] = B_TRUE; 1294da14cebeSEric Cheng ring->mmac.naddrfree--; 1295da14cebeSEric Cheng 1296da14cebeSEric Cheng mutex_exit(&lldev->genlock); 1297da14cebeSEric Cheng 1298da14cebeSEric Cheng return (0); 1299da14cebeSEric Cheng } 1300da14cebeSEric Cheng 1301da14cebeSEric Cheng static int 1302da14cebeSEric Cheng xgell_remmac(void *arg, const uint8_t *mac_addr) 1303da14cebeSEric Cheng { 1304da14cebeSEric Cheng xgell_rx_ring_t *ring = arg; 1305da14cebeSEric Cheng xgelldev_t *lldev = ring->lldev; 1306da14cebeSEric Cheng xge_hal_device_t *hldev = lldev->devh; 1307da14cebeSEric Cheng xge_hal_status_e status; 1308da14cebeSEric Cheng int slot; 1309da14cebeSEric Cheng int slot_start; 1310da14cebeSEric Cheng 1311da14cebeSEric Cheng xge_debug_ll(XGE_TRACE, "%s", "xgell_remmac"); 1312da14cebeSEric Cheng 1313da14cebeSEric Cheng slot = xge_hal_device_macaddr_find(hldev, (uint8_t *)mac_addr); 1314da14cebeSEric Cheng if (slot == -1) 1315da14cebeSEric Cheng return (EINVAL); 1316da14cebeSEric Cheng 1317da14cebeSEric Cheng slot_start = ring->index * 32; 1318da14cebeSEric Cheng 1319da14cebeSEric Cheng /* 1320da14cebeSEric Cheng * Adjust slot to the offset in the MAC array of this ring (group). 1321da14cebeSEric Cheng */ 1322da14cebeSEric Cheng slot -= slot_start; 1323da14cebeSEric Cheng 1324da14cebeSEric Cheng /* 1325da14cebeSEric Cheng * Only can remove a pre-set MAC address for this ring (group). 1326da14cebeSEric Cheng */ 1327da14cebeSEric Cheng if (slot < 0 || slot >= ring->mmac.naddr) 1328da14cebeSEric Cheng return (EINVAL); 1329da14cebeSEric Cheng 1330da14cebeSEric Cheng 1331da14cebeSEric Cheng xge_assert(ring->mmac.mac_addr_set[slot]); 1332da14cebeSEric Cheng 1333da14cebeSEric Cheng mutex_enter(&lldev->genlock); 1334da14cebeSEric Cheng if (!ring->mmac.mac_addr_set[slot]) { 1335da14cebeSEric Cheng mutex_exit(&lldev->genlock); 1336da14cebeSEric Cheng /* 1337da14cebeSEric Cheng * The result will be unexpected when reach here. WARNING! 1338da14cebeSEric Cheng */ 1339da14cebeSEric Cheng xge_debug_ll(XGE_ERR, 1340da14cebeSEric Cheng "%s%d: caller is trying to remove an unset MAC address", 1341da14cebeSEric Cheng XGELL_IFNAME, lldev->instance); 1342da14cebeSEric Cheng return (ENXIO); 1343da14cebeSEric Cheng } 1344da14cebeSEric Cheng 1345da14cebeSEric Cheng status = xge_hal_device_macaddr_clear(hldev, slot_start + slot); 1346da14cebeSEric Cheng if (status != XGE_HAL_OK) { 1347da14cebeSEric Cheng mutex_exit(&lldev->genlock); 1348da14cebeSEric Cheng return (EIO); 1349da14cebeSEric Cheng } 1350da14cebeSEric Cheng 1351da14cebeSEric Cheng ring->mmac.mac_addr_set[slot] = B_FALSE; 1352da14cebeSEric Cheng ring->mmac.naddrfree++; 1353da14cebeSEric Cheng 1354da14cebeSEric Cheng /* 1355da14cebeSEric Cheng * TODO: Disable MAC RTS if all addresses have been cleared. 1356da14cebeSEric Cheng */ 1357da14cebeSEric Cheng 1358da14cebeSEric Cheng /* 1359da14cebeSEric Cheng * Read back the MAC address from HAL to keep the array up to date. 1360da14cebeSEric Cheng */ 1361da14cebeSEric Cheng (void) xge_hal_device_macaddr_get(hldev, slot_start + slot, 1362da14cebeSEric Cheng ring->mmac.mac_addr + slot); 1363da14cebeSEric Cheng mutex_exit(&lldev->genlock); 1364da14cebeSEric Cheng 1365da14cebeSEric Cheng return (0); 1366da14cebeSEric Cheng } 1367da14cebeSEric Cheng 1368da14cebeSEric Cheng /* 1369da14cebeSEric Cheng * Temporarily calling hal function. 1370da14cebeSEric Cheng * 1371da14cebeSEric Cheng * With MSI-X implementation, no lock is needed, so that the interrupt 1372da14cebeSEric Cheng * handling could be faster. 1373da14cebeSEric Cheng */ 1374da14cebeSEric Cheng int 1375da14cebeSEric Cheng xgell_rx_ring_intr_enable(mac_intr_handle_t ih) 1376da14cebeSEric Cheng { 1377da14cebeSEric Cheng xgell_rx_ring_t *ring = (xgell_rx_ring_t *)ih; 1378da14cebeSEric Cheng 1379da14cebeSEric Cheng mutex_enter(&ring->ring_lock); 1380da14cebeSEric Cheng xge_hal_device_rx_channel_disable_polling(ring->channelh); 1381da14cebeSEric Cheng mutex_exit(&ring->ring_lock); 1382da14cebeSEric Cheng 1383da14cebeSEric Cheng return (0); 1384da14cebeSEric Cheng } 1385da14cebeSEric Cheng 1386da14cebeSEric Cheng int 1387da14cebeSEric Cheng xgell_rx_ring_intr_disable(mac_intr_handle_t ih) 1388da14cebeSEric Cheng { 1389da14cebeSEric Cheng xgell_rx_ring_t *ring = (xgell_rx_ring_t *)ih; 1390da14cebeSEric Cheng 1391da14cebeSEric Cheng mutex_enter(&ring->ring_lock); 1392da14cebeSEric Cheng xge_hal_device_rx_channel_enable_polling(ring->channelh); 1393da14cebeSEric Cheng mutex_exit(&ring->ring_lock); 1394da14cebeSEric Cheng 1395da14cebeSEric Cheng return (0); 1396da14cebeSEric Cheng } 1397da14cebeSEric Cheng 1398da14cebeSEric Cheng static int 1399da14cebeSEric Cheng xgell_rx_ring_start(mac_ring_driver_t rh, uint64_t mr_gen_num) 1400da14cebeSEric Cheng { 1401da14cebeSEric Cheng xgell_rx_ring_t *rx_ring = (xgell_rx_ring_t *)rh; 1402da14cebeSEric Cheng 1403da14cebeSEric Cheng rx_ring->ring_gen_num = mr_gen_num; 1404da14cebeSEric Cheng 1405da14cebeSEric Cheng return (0); 1406da14cebeSEric Cheng } 1407da14cebeSEric Cheng 1408da14cebeSEric Cheng /*ARGSUSED*/ 1409da14cebeSEric Cheng static void 1410da14cebeSEric Cheng xgell_rx_ring_stop(mac_ring_driver_t rh) 1411da14cebeSEric Cheng { 1412da14cebeSEric Cheng } 1413da14cebeSEric Cheng 1414da14cebeSEric Cheng /*ARGSUSED*/ 1415da14cebeSEric Cheng static int 1416da14cebeSEric Cheng xgell_tx_ring_start(mac_ring_driver_t rh, uint64_t useless) 1417da14cebeSEric Cheng { 1418da14cebeSEric Cheng return (0); 1419da14cebeSEric Cheng } 1420da14cebeSEric Cheng 1421da14cebeSEric Cheng /*ARGSUSED*/ 1422da14cebeSEric Cheng static void 1423da14cebeSEric Cheng xgell_tx_ring_stop(mac_ring_driver_t rh) 1424da14cebeSEric Cheng { 1425da14cebeSEric Cheng } 1426da14cebeSEric Cheng 1427da14cebeSEric Cheng /* 1428da14cebeSEric Cheng * Callback funtion for MAC layer to register all rings. 1429da14cebeSEric Cheng * 1430da14cebeSEric Cheng * Xframe hardware doesn't support grouping explicitly, so the driver needs 1431da14cebeSEric Cheng * to pretend having resource groups. We may also optionally group all 8 rx 1432da14cebeSEric Cheng * rings into a single group for increased scalability on CMT architectures, 1433da14cebeSEric Cheng * or group one rx ring per group for maximum virtualization. 1434da14cebeSEric Cheng * 1435da14cebeSEric Cheng * TX grouping is actually done by framework, so, just register all TX 1436da14cebeSEric Cheng * resources without grouping them. 1437da14cebeSEric Cheng */ 1438da14cebeSEric Cheng void 1439da14cebeSEric Cheng xgell_fill_ring(void *arg, mac_ring_type_t rtype, const int rg_index, 1440da14cebeSEric Cheng const int index, mac_ring_info_t *infop, mac_ring_handle_t rh) 1441da14cebeSEric Cheng { 1442da14cebeSEric Cheng xgelldev_t *lldev = (xgelldev_t *)arg; 1443da14cebeSEric Cheng mac_intr_t *mintr; 1444da14cebeSEric Cheng 1445da14cebeSEric Cheng switch (rtype) { 1446da14cebeSEric Cheng case MAC_RING_TYPE_RX: { 1447da14cebeSEric Cheng xgell_rx_ring_t *rx_ring; 1448da14cebeSEric Cheng 1449da14cebeSEric Cheng xge_assert(index < lldev->init_rx_rings); 1450da14cebeSEric Cheng xge_assert(rg_index < lldev->init_rx_groups); 1451da14cebeSEric Cheng 1452da14cebeSEric Cheng /* 1453da14cebeSEric Cheng * Performance vs. Virtualization 1454da14cebeSEric Cheng */ 1455da14cebeSEric Cheng if (lldev->init_rx_rings == lldev->init_rx_groups) 1456da14cebeSEric Cheng rx_ring = lldev->rx_ring + rg_index; 1457da14cebeSEric Cheng else 1458da14cebeSEric Cheng rx_ring = lldev->rx_ring + index; 1459da14cebeSEric Cheng 1460da14cebeSEric Cheng rx_ring->ring_handle = rh; 1461da14cebeSEric Cheng 1462da14cebeSEric Cheng infop->mri_driver = (mac_ring_driver_t)rx_ring; 1463da14cebeSEric Cheng infop->mri_start = xgell_rx_ring_start; 1464da14cebeSEric Cheng infop->mri_stop = xgell_rx_ring_stop; 1465da14cebeSEric Cheng infop->mri_poll = xgell_rx_poll; 14660dc2366fSVenugopal Iyer infop->mri_stat = xgell_rx_ring_stat; 1467da14cebeSEric Cheng 1468da14cebeSEric Cheng mintr = &infop->mri_intr; 1469da14cebeSEric Cheng mintr->mi_handle = (mac_intr_handle_t)rx_ring; 1470da14cebeSEric Cheng mintr->mi_enable = xgell_rx_ring_intr_enable; 1471da14cebeSEric Cheng mintr->mi_disable = xgell_rx_ring_intr_disable; 1472da14cebeSEric Cheng 1473da14cebeSEric Cheng break; 1474da14cebeSEric Cheng } 1475da14cebeSEric Cheng case MAC_RING_TYPE_TX: { 1476da14cebeSEric Cheng xgell_tx_ring_t *tx_ring; 1477da14cebeSEric Cheng 1478da14cebeSEric Cheng xge_assert(rg_index == -1); 1479da14cebeSEric Cheng 1480da14cebeSEric Cheng xge_assert((index >= 0) && (index < lldev->init_tx_rings)); 1481da14cebeSEric Cheng 1482da14cebeSEric Cheng tx_ring = lldev->tx_ring + index; 1483da14cebeSEric Cheng tx_ring->ring_handle = rh; 1484da14cebeSEric Cheng 1485da14cebeSEric Cheng infop->mri_driver = (mac_ring_driver_t)tx_ring; 1486da14cebeSEric Cheng infop->mri_start = xgell_tx_ring_start; 1487da14cebeSEric Cheng infop->mri_stop = xgell_tx_ring_stop; 1488da14cebeSEric Cheng infop->mri_tx = xgell_ring_tx; 14890dc2366fSVenugopal Iyer infop->mri_stat = xgell_tx_ring_stat; 1490da14cebeSEric Cheng 1491da14cebeSEric Cheng break; 1492da14cebeSEric Cheng } 1493da14cebeSEric Cheng default: 1494da14cebeSEric Cheng break; 1495da14cebeSEric Cheng } 1496da14cebeSEric Cheng } 1497da14cebeSEric Cheng 1498da14cebeSEric Cheng void 1499da14cebeSEric Cheng xgell_fill_group(void *arg, mac_ring_type_t rtype, const int index, 1500da14cebeSEric Cheng mac_group_info_t *infop, mac_group_handle_t gh) 1501da14cebeSEric Cheng { 1502da14cebeSEric Cheng xgelldev_t *lldev = (xgelldev_t *)arg; 1503da14cebeSEric Cheng 1504da14cebeSEric Cheng switch (rtype) { 1505da14cebeSEric Cheng case MAC_RING_TYPE_RX: { 1506da14cebeSEric Cheng xgell_rx_ring_t *rx_ring; 1507da14cebeSEric Cheng 1508da14cebeSEric Cheng xge_assert(index < lldev->init_rx_groups); 1509da14cebeSEric Cheng 1510da14cebeSEric Cheng rx_ring = lldev->rx_ring + index; 1511da14cebeSEric Cheng 1512da14cebeSEric Cheng rx_ring->group_handle = gh; 1513da14cebeSEric Cheng 1514da14cebeSEric Cheng infop->mgi_driver = (mac_group_driver_t)rx_ring; 1515da14cebeSEric Cheng infop->mgi_start = NULL; 1516da14cebeSEric Cheng infop->mgi_stop = NULL; 1517da14cebeSEric Cheng infop->mgi_addmac = xgell_addmac; 1518da14cebeSEric Cheng infop->mgi_remmac = xgell_remmac; 1519da14cebeSEric Cheng infop->mgi_count = lldev->init_rx_rings / lldev->init_rx_groups; 1520da14cebeSEric Cheng 1521da14cebeSEric Cheng break; 1522da14cebeSEric Cheng } 1523da14cebeSEric Cheng case MAC_RING_TYPE_TX: 1524da14cebeSEric Cheng xge_assert(0); 1525da14cebeSEric Cheng break; 1526da14cebeSEric Cheng default: 1527da14cebeSEric Cheng break; 1528da14cebeSEric Cheng } 1529da14cebeSEric Cheng } 1530da14cebeSEric Cheng 1531da14cebeSEric Cheng /* 1532da14cebeSEric Cheng * xgell_macaddr_set 1533da14cebeSEric Cheng */ 1534da14cebeSEric Cheng static int 1535da14cebeSEric Cheng xgell_maddr_set(xgelldev_t *lldev, int index, uint8_t *macaddr) 1536da14cebeSEric Cheng { 1537da14cebeSEric Cheng xge_hal_device_t *hldev = lldev->devh; 1538da14cebeSEric Cheng xge_hal_status_e status; 1539da14cebeSEric Cheng 1540da14cebeSEric Cheng xge_debug_ll(XGE_TRACE, "%s", "xgell_maddr_set"); 1541da14cebeSEric Cheng 1542da14cebeSEric Cheng xge_debug_ll(XGE_TRACE, 1543da14cebeSEric Cheng "setting macaddr: 0x%02x-%02x-%02x-%02x-%02x-%02x", 1544da14cebeSEric Cheng macaddr[0], macaddr[1], macaddr[2], 1545da14cebeSEric Cheng macaddr[3], macaddr[4], macaddr[5]); 1546da14cebeSEric Cheng 1547da14cebeSEric Cheng status = xge_hal_device_macaddr_set(hldev, index, (uchar_t *)macaddr); 1548da14cebeSEric Cheng 1549da14cebeSEric Cheng if (status != XGE_HAL_OK) { 1550da14cebeSEric Cheng xge_debug_ll(XGE_ERR, "%s%d: can not set mac address", 1551da14cebeSEric Cheng XGELL_IFNAME, lldev->instance); 1552da14cebeSEric Cheng return (EIO); 1553da14cebeSEric Cheng } 1554da14cebeSEric Cheng 1555da14cebeSEric Cheng return (0); 1556a23fd118Syl150051 } 1557a23fd118Syl150051 1558a23fd118Syl150051 /* 1559a23fd118Syl150051 * xgell_rx_dtr_term 1560a23fd118Syl150051 * 1561a23fd118Syl150051 * Function will be called by HAL to terminate all DTRs for 1562a23fd118Syl150051 * Ring(s) type of channels. 1563a23fd118Syl150051 */ 1564a23fd118Syl150051 static void 1565a23fd118Syl150051 xgell_rx_dtr_term(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh, 1566a23fd118Syl150051 xge_hal_dtr_state_e state, void *userdata, xge_hal_channel_reopen_e reopen) 1567a23fd118Syl150051 { 1568a23fd118Syl150051 xgell_rxd_priv_t *rxd_priv = 1569a23fd118Syl150051 ((xgell_rxd_priv_t *)xge_hal_ring_dtr_private(channelh, dtrh)); 1570a23fd118Syl150051 xgell_rx_buffer_t *rx_buffer = rxd_priv->rx_buffer; 1571a23fd118Syl150051 1572a23fd118Syl150051 if (state == XGE_HAL_DTR_STATE_POSTED) { 1573da14cebeSEric Cheng xgell_rx_ring_t *ring = rx_buffer->ring; 1574da14cebeSEric Cheng 15757eced415Sxw161283 mutex_enter(&ring->bf_pool.pool_lock); 1576a23fd118Syl150051 xge_hal_ring_dtr_free(channelh, dtrh); 1577a23fd118Syl150051 xgell_rx_buffer_release(rx_buffer); 15787eced415Sxw161283 mutex_exit(&ring->bf_pool.pool_lock); 1579a23fd118Syl150051 } 1580a23fd118Syl150051 } 1581a23fd118Syl150051 1582a23fd118Syl150051 /* 1583da14cebeSEric Cheng * To open a rx ring. 1584da14cebeSEric Cheng */ 1585da14cebeSEric Cheng static boolean_t 1586da14cebeSEric Cheng xgell_rx_ring_open(xgell_rx_ring_t *rx_ring) 1587da14cebeSEric Cheng { 1588da14cebeSEric Cheng xge_hal_status_e status; 1589da14cebeSEric Cheng xge_hal_channel_attr_t attr; 1590da14cebeSEric Cheng xgelldev_t *lldev = rx_ring->lldev; 1591da14cebeSEric Cheng xge_hal_device_t *hldev = lldev->devh; 1592da14cebeSEric Cheng 1593da14cebeSEric Cheng if (rx_ring->live) 1594da14cebeSEric Cheng return (B_TRUE); 1595da14cebeSEric Cheng 1596da14cebeSEric Cheng /* Create the buffer pool first */ 1597da14cebeSEric Cheng if (!xgell_rx_create_buffer_pool(rx_ring)) { 1598da14cebeSEric Cheng xge_debug_ll(XGE_ERR, "can not create buffer pool for ring: %d", 1599da14cebeSEric Cheng rx_ring->index); 1600da14cebeSEric Cheng return (B_FALSE); 1601da14cebeSEric Cheng } 1602da14cebeSEric Cheng 1603da14cebeSEric Cheng /* Default ring initialization */ 1604da14cebeSEric Cheng attr.post_qid = rx_ring->index; 1605da14cebeSEric Cheng attr.compl_qid = 0; 1606da14cebeSEric Cheng attr.callback = xgell_rx_1b_callback; 1607da14cebeSEric Cheng attr.per_dtr_space = sizeof (xgell_rxd_priv_t); 1608da14cebeSEric Cheng attr.flags = 0; 1609da14cebeSEric Cheng attr.type = XGE_HAL_CHANNEL_TYPE_RING; 1610da14cebeSEric Cheng attr.dtr_init = xgell_rx_dtr_replenish; 1611da14cebeSEric Cheng attr.dtr_term = xgell_rx_dtr_term; 1612da14cebeSEric Cheng attr.userdata = rx_ring; 1613da14cebeSEric Cheng 1614da14cebeSEric Cheng status = xge_hal_channel_open(lldev->devh, &attr, &rx_ring->channelh, 1615da14cebeSEric Cheng XGE_HAL_CHANNEL_OC_NORMAL); 1616da14cebeSEric Cheng if (status != XGE_HAL_OK) { 1617da14cebeSEric Cheng xge_debug_ll(XGE_ERR, "%s%d: cannot open Rx channel got status " 1618da14cebeSEric Cheng " code %d", XGELL_IFNAME, lldev->instance, status); 1619da14cebeSEric Cheng (void) xgell_rx_destroy_buffer_pool(rx_ring); 1620da14cebeSEric Cheng return (B_FALSE); 1621da14cebeSEric Cheng } 1622da14cebeSEric Cheng 1623da14cebeSEric Cheng xgell_rx_ring_maddr_init(rx_ring); 1624da14cebeSEric Cheng 1625da14cebeSEric Cheng mutex_init(&rx_ring->ring_lock, NULL, MUTEX_DRIVER, 1626da14cebeSEric Cheng DDI_INTR_PRI(hldev->irqh)); 1627da14cebeSEric Cheng 1628da14cebeSEric Cheng rx_ring->poll_bytes = -1; 1629da14cebeSEric Cheng rx_ring->polled_bytes = 0; 1630da14cebeSEric Cheng rx_ring->poll_mp = NULL; 1631da14cebeSEric Cheng rx_ring->live = B_TRUE; 1632da14cebeSEric Cheng 1633da14cebeSEric Cheng xge_debug_ll(XGE_TRACE, "RX ring [%d] is opened successfully", 1634da14cebeSEric Cheng rx_ring->index); 1635da14cebeSEric Cheng 1636da14cebeSEric Cheng return (B_TRUE); 1637da14cebeSEric Cheng } 1638da14cebeSEric Cheng 1639da14cebeSEric Cheng static void 1640da14cebeSEric Cheng xgell_rx_ring_close(xgell_rx_ring_t *rx_ring) 1641da14cebeSEric Cheng { 1642da14cebeSEric Cheng if (!rx_ring->live) 1643da14cebeSEric Cheng return; 1644da14cebeSEric Cheng xge_hal_channel_close(rx_ring->channelh, XGE_HAL_CHANNEL_OC_NORMAL); 1645da14cebeSEric Cheng rx_ring->channelh = NULL; 1646da14cebeSEric Cheng /* This may not clean up all used buffers, driver will handle it */ 1647da14cebeSEric Cheng if (xgell_rx_destroy_buffer_pool(rx_ring)) 1648da14cebeSEric Cheng rx_ring->live = B_FALSE; 1649da14cebeSEric Cheng 1650da14cebeSEric Cheng mutex_destroy(&rx_ring->ring_lock); 1651da14cebeSEric Cheng } 1652da14cebeSEric Cheng 1653da14cebeSEric Cheng /* 1654da14cebeSEric Cheng * xgell_rx_open 1655da14cebeSEric Cheng * @lldev: the link layer object 1656da14cebeSEric Cheng * 1657da14cebeSEric Cheng * Initialize and open all RX channels. 1658da14cebeSEric Cheng */ 1659da14cebeSEric Cheng static boolean_t 1660da14cebeSEric Cheng xgell_rx_open(xgelldev_t *lldev) 1661da14cebeSEric Cheng { 1662da14cebeSEric Cheng xgell_rx_ring_t *rx_ring; 1663da14cebeSEric Cheng int i; 1664da14cebeSEric Cheng 1665da14cebeSEric Cheng if (lldev->live_rx_rings != 0) 1666da14cebeSEric Cheng return (B_TRUE); 1667da14cebeSEric Cheng 1668da14cebeSEric Cheng lldev->live_rx_rings = 0; 1669da14cebeSEric Cheng 1670da14cebeSEric Cheng /* 1671da14cebeSEric Cheng * Initialize all rings 1672da14cebeSEric Cheng */ 1673da14cebeSEric Cheng for (i = 0; i < lldev->init_rx_rings; i++) { 1674da14cebeSEric Cheng rx_ring = &lldev->rx_ring[i]; 1675da14cebeSEric Cheng rx_ring->index = i; 1676da14cebeSEric Cheng rx_ring->lldev = lldev; 1677da14cebeSEric Cheng rx_ring->live = B_FALSE; 1678da14cebeSEric Cheng 1679da14cebeSEric Cheng if (!xgell_rx_ring_open(rx_ring)) 1680da14cebeSEric Cheng return (B_FALSE); 1681da14cebeSEric Cheng 1682da14cebeSEric Cheng lldev->live_rx_rings++; 1683da14cebeSEric Cheng } 1684da14cebeSEric Cheng 1685da14cebeSEric Cheng return (B_TRUE); 1686da14cebeSEric Cheng } 1687da14cebeSEric Cheng 1688da14cebeSEric Cheng static void 1689da14cebeSEric Cheng xgell_rx_close(xgelldev_t *lldev) 1690da14cebeSEric Cheng { 1691da14cebeSEric Cheng xgell_rx_ring_t *rx_ring; 1692da14cebeSEric Cheng int i; 1693da14cebeSEric Cheng 1694da14cebeSEric Cheng if (lldev->live_rx_rings == 0) 1695da14cebeSEric Cheng return; 1696da14cebeSEric Cheng 1697da14cebeSEric Cheng /* 1698da14cebeSEric Cheng * Close all rx rings 1699da14cebeSEric Cheng */ 1700da14cebeSEric Cheng for (i = 0; i < lldev->init_rx_rings; i++) { 1701da14cebeSEric Cheng rx_ring = &lldev->rx_ring[i]; 1702da14cebeSEric Cheng 1703da14cebeSEric Cheng if (rx_ring->live) { 1704da14cebeSEric Cheng xgell_rx_ring_close(rx_ring); 1705da14cebeSEric Cheng lldev->live_rx_rings--; 1706da14cebeSEric Cheng } 1707da14cebeSEric Cheng } 1708da14cebeSEric Cheng 1709da14cebeSEric Cheng xge_assert(lldev->live_rx_rings == 0); 1710da14cebeSEric Cheng } 1711da14cebeSEric Cheng 1712da14cebeSEric Cheng /* 1713a23fd118Syl150051 * xgell_tx_term 1714a23fd118Syl150051 * 1715a23fd118Syl150051 * Function will be called by HAL to terminate all DTRs for 1716a23fd118Syl150051 * Fifo(s) type of channels. 1717a23fd118Syl150051 */ 1718a23fd118Syl150051 static void 1719a23fd118Syl150051 xgell_tx_term(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh, 1720a23fd118Syl150051 xge_hal_dtr_state_e state, void *userdata, xge_hal_channel_reopen_e reopen) 1721a23fd118Syl150051 { 1722a23fd118Syl150051 xgell_txd_priv_t *txd_priv = 1723a23fd118Syl150051 ((xgell_txd_priv_t *)xge_hal_fifo_dtr_private(dtrh)); 1724a23fd118Syl150051 mblk_t *mp = txd_priv->mblk; 1725a23fd118Syl150051 int i; 17268347601bSyl150051 1727a23fd118Syl150051 /* 1728a23fd118Syl150051 * for Tx we must clean up the DTR *only* if it has been 1729a23fd118Syl150051 * posted! 1730a23fd118Syl150051 */ 1731a23fd118Syl150051 if (state != XGE_HAL_DTR_STATE_POSTED) { 1732a23fd118Syl150051 return; 1733a23fd118Syl150051 } 1734a23fd118Syl150051 1735a23fd118Syl150051 for (i = 0; i < txd_priv->handle_cnt; i++) { 1736a23fd118Syl150051 xge_assert(txd_priv->dma_handles[i]); 1737a23fd118Syl150051 (void) ddi_dma_unbind_handle(txd_priv->dma_handles[i]); 1738a23fd118Syl150051 ddi_dma_free_handle(&txd_priv->dma_handles[i]); 1739a23fd118Syl150051 txd_priv->dma_handles[i] = 0; 1740a23fd118Syl150051 } 1741a23fd118Syl150051 1742a23fd118Syl150051 xge_hal_fifo_dtr_free(channelh, dtrh); 1743a23fd118Syl150051 17447eced415Sxw161283 if (mp) { 17457eced415Sxw161283 txd_priv->mblk = NULL; 1746a23fd118Syl150051 freemsg(mp); 1747a23fd118Syl150051 } 17487eced415Sxw161283 } 17497eced415Sxw161283 1750da14cebeSEric Cheng static boolean_t 1751da14cebeSEric Cheng xgell_tx_ring_open(xgell_tx_ring_t *tx_ring) 17527eced415Sxw161283 { 1753da14cebeSEric Cheng xge_hal_status_e status; 1754da14cebeSEric Cheng xge_hal_channel_attr_t attr; 1755da14cebeSEric Cheng xgelldev_t *lldev = tx_ring->lldev; 17567eced415Sxw161283 1757da14cebeSEric Cheng if (tx_ring->live) 1758da14cebeSEric Cheng return (B_TRUE); 17597eced415Sxw161283 1760da14cebeSEric Cheng attr.post_qid = tx_ring->index; 1761da14cebeSEric Cheng attr.compl_qid = 0; 1762da14cebeSEric Cheng attr.callback = xgell_xmit_compl; 1763da14cebeSEric Cheng attr.per_dtr_space = sizeof (xgell_txd_priv_t); 1764da14cebeSEric Cheng attr.flags = 0; 1765da14cebeSEric Cheng attr.type = XGE_HAL_CHANNEL_TYPE_FIFO; 1766da14cebeSEric Cheng attr.dtr_init = NULL; 1767da14cebeSEric Cheng attr.dtr_term = xgell_tx_term; 1768da14cebeSEric Cheng attr.userdata = tx_ring; 1769da14cebeSEric Cheng 1770da14cebeSEric Cheng status = xge_hal_channel_open(lldev->devh, &attr, &tx_ring->channelh, 1771da14cebeSEric Cheng XGE_HAL_CHANNEL_OC_NORMAL); 1772da14cebeSEric Cheng if (status != XGE_HAL_OK) { 1773da14cebeSEric Cheng xge_debug_ll(XGE_ERR, "%s%d: cannot open Tx channel got status " 1774da14cebeSEric Cheng "code %d", XGELL_IFNAME, lldev->instance, status); 1775da14cebeSEric Cheng return (B_FALSE); 17767eced415Sxw161283 } 1777da14cebeSEric Cheng 1778da14cebeSEric Cheng tx_ring->live = B_TRUE; 1779da14cebeSEric Cheng 1780da14cebeSEric Cheng return (B_TRUE); 1781da14cebeSEric Cheng } 1782da14cebeSEric Cheng 1783da14cebeSEric Cheng static void 1784da14cebeSEric Cheng xgell_tx_ring_close(xgell_tx_ring_t *tx_ring) 1785da14cebeSEric Cheng { 1786da14cebeSEric Cheng if (!tx_ring->live) 1787da14cebeSEric Cheng return; 1788da14cebeSEric Cheng xge_hal_channel_close(tx_ring->channelh, XGE_HAL_CHANNEL_OC_NORMAL); 1789da14cebeSEric Cheng tx_ring->live = B_FALSE; 17907eced415Sxw161283 } 1791a23fd118Syl150051 1792a23fd118Syl150051 /* 1793a23fd118Syl150051 * xgell_tx_open 1794a23fd118Syl150051 * @lldev: the link layer object 1795a23fd118Syl150051 * 1796da14cebeSEric Cheng * Initialize and open all TX channels. 1797a23fd118Syl150051 */ 1798a23fd118Syl150051 static boolean_t 1799a23fd118Syl150051 xgell_tx_open(xgelldev_t *lldev) 1800a23fd118Syl150051 { 1801da14cebeSEric Cheng xgell_tx_ring_t *tx_ring; 1802da14cebeSEric Cheng int i; 1803a23fd118Syl150051 1804da14cebeSEric Cheng if (lldev->live_tx_rings != 0) 1805da14cebeSEric Cheng return (B_TRUE); 1806a23fd118Syl150051 1807da14cebeSEric Cheng lldev->live_tx_rings = 0; 1808a23fd118Syl150051 18097eced415Sxw161283 /* 1810da14cebeSEric Cheng * Enable rings by reserve sequence to match the h/w sequences. 18117eced415Sxw161283 */ 1812da14cebeSEric Cheng for (i = 0; i < lldev->init_tx_rings; i++) { 1813da14cebeSEric Cheng tx_ring = &lldev->tx_ring[i]; 1814da14cebeSEric Cheng tx_ring->index = i; 1815da14cebeSEric Cheng tx_ring->lldev = lldev; 1816da14cebeSEric Cheng tx_ring->live = B_FALSE; 18177eced415Sxw161283 1818da14cebeSEric Cheng if (!xgell_tx_ring_open(tx_ring)) 1819a23fd118Syl150051 return (B_FALSE); 1820a23fd118Syl150051 1821da14cebeSEric Cheng lldev->live_tx_rings++; 18227eced415Sxw161283 } 18237eced415Sxw161283 1824a23fd118Syl150051 return (B_TRUE); 1825a23fd118Syl150051 } 1826a23fd118Syl150051 18277eced415Sxw161283 static void 1828da14cebeSEric Cheng xgell_tx_close(xgelldev_t *lldev) 18297eced415Sxw161283 { 1830da14cebeSEric Cheng xgell_tx_ring_t *tx_ring; 1831da14cebeSEric Cheng int i; 18327eced415Sxw161283 1833da14cebeSEric Cheng if (lldev->live_tx_rings == 0) 1834da14cebeSEric Cheng return; 18357eced415Sxw161283 18367eced415Sxw161283 /* 1837da14cebeSEric Cheng * Enable rings by reserve sequence to match the h/w sequences. 18387eced415Sxw161283 */ 1839da14cebeSEric Cheng for (i = 0; i < lldev->init_tx_rings; i++) { 1840da14cebeSEric Cheng tx_ring = &lldev->tx_ring[i]; 1841da14cebeSEric Cheng if (tx_ring->live) { 1842da14cebeSEric Cheng xgell_tx_ring_close(tx_ring); 1843da14cebeSEric Cheng lldev->live_tx_rings--; 18447eced415Sxw161283 } 18457eced415Sxw161283 } 1846a23fd118Syl150051 } 1847a23fd118Syl150051 1848a23fd118Syl150051 static int 1849a23fd118Syl150051 xgell_initiate_start(xgelldev_t *lldev) 1850a23fd118Syl150051 { 1851a23fd118Syl150051 xge_hal_status_e status; 1852a23fd118Syl150051 xge_hal_device_t *hldev = lldev->devh; 1853ba2e4443Sseb int maxpkt = hldev->config.mtu; 1854a23fd118Syl150051 1855a23fd118Syl150051 /* check initial mtu before enabling the device */ 1856a23fd118Syl150051 status = xge_hal_device_mtu_check(lldev->devh, maxpkt); 1857a23fd118Syl150051 if (status != XGE_HAL_OK) { 1858a23fd118Syl150051 xge_debug_ll(XGE_ERR, "%s%d: MTU size %d is invalid", 1859a23fd118Syl150051 XGELL_IFNAME, lldev->instance, maxpkt); 1860a23fd118Syl150051 return (EINVAL); 1861a23fd118Syl150051 } 1862a23fd118Syl150051 1863a23fd118Syl150051 /* set initial mtu before enabling the device */ 1864a23fd118Syl150051 status = xge_hal_device_mtu_set(lldev->devh, maxpkt); 1865a23fd118Syl150051 if (status != XGE_HAL_OK) { 1866a23fd118Syl150051 xge_debug_ll(XGE_ERR, "%s%d: can not set new MTU %d", 1867a23fd118Syl150051 XGELL_IFNAME, lldev->instance, maxpkt); 1868a23fd118Syl150051 return (EIO); 1869a23fd118Syl150051 } 1870a23fd118Syl150051 18718347601bSyl150051 /* tune jumbo/normal frame UFC counters */ 1872da14cebeSEric Cheng hldev->config.ring.queue[XGELL_RX_RING_MAIN].rti.ufc_b = 1873da14cebeSEric Cheng (maxpkt > XGE_HAL_DEFAULT_MTU) ? 18748347601bSyl150051 XGE_HAL_DEFAULT_RX_UFC_B_J : 18758347601bSyl150051 XGE_HAL_DEFAULT_RX_UFC_B_N; 18768347601bSyl150051 1877da14cebeSEric Cheng hldev->config.ring.queue[XGELL_RX_RING_MAIN].rti.ufc_c = 1878da14cebeSEric Cheng (maxpkt > XGE_HAL_DEFAULT_MTU) ? 18798347601bSyl150051 XGE_HAL_DEFAULT_RX_UFC_C_J : 18808347601bSyl150051 XGE_HAL_DEFAULT_RX_UFC_C_N; 18818347601bSyl150051 1882a23fd118Syl150051 /* now, enable the device */ 1883a23fd118Syl150051 status = xge_hal_device_enable(lldev->devh); 1884a23fd118Syl150051 if (status != XGE_HAL_OK) { 1885a23fd118Syl150051 xge_debug_ll(XGE_ERR, "%s%d: can not enable the device", 1886a23fd118Syl150051 XGELL_IFNAME, lldev->instance); 1887a23fd118Syl150051 return (EIO); 1888a23fd118Syl150051 } 1889a23fd118Syl150051 1890a23fd118Syl150051 if (!xgell_rx_open(lldev)) { 1891a23fd118Syl150051 status = xge_hal_device_disable(lldev->devh); 1892a23fd118Syl150051 if (status != XGE_HAL_OK) { 1893a23fd118Syl150051 u64 adapter_status; 1894a23fd118Syl150051 (void) xge_hal_device_status(lldev->devh, 1895a23fd118Syl150051 &adapter_status); 1896a23fd118Syl150051 xge_debug_ll(XGE_ERR, "%s%d: can not safely disable " 1897a23fd118Syl150051 "the device. adaper status 0x%"PRIx64 1898a23fd118Syl150051 " returned status %d", 1899a23fd118Syl150051 XGELL_IFNAME, lldev->instance, 1900a23fd118Syl150051 (uint64_t)adapter_status, status); 1901a23fd118Syl150051 } 1902da14cebeSEric Cheng xgell_rx_close(lldev); 1903a23fd118Syl150051 xge_os_mdelay(1500); 1904a23fd118Syl150051 return (ENOMEM); 1905a23fd118Syl150051 } 1906a23fd118Syl150051 1907a23fd118Syl150051 if (!xgell_tx_open(lldev)) { 1908a23fd118Syl150051 status = xge_hal_device_disable(lldev->devh); 1909a23fd118Syl150051 if (status != XGE_HAL_OK) { 1910a23fd118Syl150051 u64 adapter_status; 1911a23fd118Syl150051 (void) xge_hal_device_status(lldev->devh, 1912a23fd118Syl150051 &adapter_status); 1913a23fd118Syl150051 xge_debug_ll(XGE_ERR, "%s%d: can not safely disable " 1914a23fd118Syl150051 "the device. adaper status 0x%"PRIx64 1915a23fd118Syl150051 " returned status %d", 1916a23fd118Syl150051 XGELL_IFNAME, lldev->instance, 1917a23fd118Syl150051 (uint64_t)adapter_status, status); 1918a23fd118Syl150051 } 1919da14cebeSEric Cheng xgell_tx_close(lldev); 19207eced415Sxw161283 xgell_rx_close(lldev); 1921da14cebeSEric Cheng xge_os_mdelay(1500); 1922a23fd118Syl150051 return (ENOMEM); 1923a23fd118Syl150051 } 1924a23fd118Syl150051 1925a23fd118Syl150051 /* time to enable interrupts */ 19267eced415Sxw161283 (void) xge_enable_intrs(lldev); 1927a23fd118Syl150051 xge_hal_device_intr_enable(lldev->devh); 1928a23fd118Syl150051 1929a23fd118Syl150051 lldev->is_initialized = 1; 1930a23fd118Syl150051 1931a23fd118Syl150051 return (0); 1932a23fd118Syl150051 } 1933a23fd118Syl150051 1934a23fd118Syl150051 static void 1935a23fd118Syl150051 xgell_initiate_stop(xgelldev_t *lldev) 1936a23fd118Syl150051 { 1937a23fd118Syl150051 xge_hal_status_e status; 1938a23fd118Syl150051 1939a23fd118Syl150051 lldev->is_initialized = 0; 1940a23fd118Syl150051 1941a23fd118Syl150051 status = xge_hal_device_disable(lldev->devh); 1942a23fd118Syl150051 if (status != XGE_HAL_OK) { 1943a23fd118Syl150051 u64 adapter_status; 1944a23fd118Syl150051 (void) xge_hal_device_status(lldev->devh, &adapter_status); 1945a23fd118Syl150051 xge_debug_ll(XGE_ERR, "%s%d: can not safely disable " 1946a23fd118Syl150051 "the device. adaper status 0x%"PRIx64" returned status %d", 1947a23fd118Syl150051 XGELL_IFNAME, lldev->instance, 1948a23fd118Syl150051 (uint64_t)adapter_status, status); 1949a23fd118Syl150051 } 1950a23fd118Syl150051 xge_hal_device_intr_disable(lldev->devh); 19517eced415Sxw161283 /* disable OS ISR's */ 19527eced415Sxw161283 xge_disable_intrs(lldev); 1953a23fd118Syl150051 1954a23fd118Syl150051 xge_debug_ll(XGE_TRACE, "%s", 1955a23fd118Syl150051 "waiting for device irq to become quiescent..."); 1956a23fd118Syl150051 xge_os_mdelay(1500); 1957a23fd118Syl150051 1958a23fd118Syl150051 xge_queue_flush(xge_hal_device_queue(lldev->devh)); 1959a23fd118Syl150051 19607eced415Sxw161283 xgell_rx_close(lldev); 19617eced415Sxw161283 xgell_tx_close(lldev); 1962a23fd118Syl150051 } 1963a23fd118Syl150051 1964a23fd118Syl150051 /* 1965a23fd118Syl150051 * xgell_m_start 1966a23fd118Syl150051 * @arg: pointer to device private strucutre(hldev) 1967a23fd118Syl150051 * 1968a23fd118Syl150051 * This function is called by MAC Layer to enable the XFRAME 1969a23fd118Syl150051 * firmware to generate interrupts and also prepare the 1970a23fd118Syl150051 * driver to call mac_rx for delivering receive packets 1971a23fd118Syl150051 * to MAC Layer. 1972a23fd118Syl150051 */ 1973a23fd118Syl150051 static int 1974a23fd118Syl150051 xgell_m_start(void *arg) 1975a23fd118Syl150051 { 19768347601bSyl150051 xgelldev_t *lldev = arg; 19778347601bSyl150051 xge_hal_device_t *hldev = lldev->devh; 1978a23fd118Syl150051 int ret; 1979a23fd118Syl150051 1980a23fd118Syl150051 xge_debug_ll(XGE_TRACE, "%s%d: M_START", XGELL_IFNAME, 1981a23fd118Syl150051 lldev->instance); 1982a23fd118Syl150051 1983a23fd118Syl150051 mutex_enter(&lldev->genlock); 1984a23fd118Syl150051 1985a23fd118Syl150051 if (lldev->is_initialized) { 1986a23fd118Syl150051 xge_debug_ll(XGE_ERR, "%s%d: device is already initialized", 1987a23fd118Syl150051 XGELL_IFNAME, lldev->instance); 1988a23fd118Syl150051 mutex_exit(&lldev->genlock); 1989a23fd118Syl150051 return (EINVAL); 1990a23fd118Syl150051 } 1991a23fd118Syl150051 1992a23fd118Syl150051 hldev->terminating = 0; 1993a23fd118Syl150051 if (ret = xgell_initiate_start(lldev)) { 1994a23fd118Syl150051 mutex_exit(&lldev->genlock); 1995a23fd118Syl150051 return (ret); 1996a23fd118Syl150051 } 1997a23fd118Syl150051 1998a23fd118Syl150051 lldev->timeout_id = timeout(xge_device_poll, hldev, XGE_DEV_POLL_TICKS); 1999a23fd118Syl150051 2000a23fd118Syl150051 mutex_exit(&lldev->genlock); 2001a23fd118Syl150051 2002a23fd118Syl150051 return (0); 2003a23fd118Syl150051 } 2004a23fd118Syl150051 2005a23fd118Syl150051 /* 2006a23fd118Syl150051 * xgell_m_stop 2007a23fd118Syl150051 * @arg: pointer to device private data (hldev) 2008a23fd118Syl150051 * 2009a23fd118Syl150051 * This function is called by the MAC Layer to disable 2010a23fd118Syl150051 * the XFRAME firmware for generating any interrupts and 2011a23fd118Syl150051 * also stop the driver from calling mac_rx() for 2012a23fd118Syl150051 * delivering data packets to the MAC Layer. 2013a23fd118Syl150051 */ 2014a23fd118Syl150051 static void 2015a23fd118Syl150051 xgell_m_stop(void *arg) 2016a23fd118Syl150051 { 20178347601bSyl150051 xgelldev_t *lldev = arg; 20188347601bSyl150051 xge_hal_device_t *hldev = lldev->devh; 2019a23fd118Syl150051 2020a23fd118Syl150051 xge_debug_ll(XGE_TRACE, "%s", "MAC_STOP"); 2021a23fd118Syl150051 2022a23fd118Syl150051 mutex_enter(&lldev->genlock); 2023a23fd118Syl150051 if (!lldev->is_initialized) { 2024a23fd118Syl150051 xge_debug_ll(XGE_ERR, "%s", "device is not initialized..."); 2025a23fd118Syl150051 mutex_exit(&lldev->genlock); 2026a23fd118Syl150051 return; 2027a23fd118Syl150051 } 2028a23fd118Syl150051 2029a23fd118Syl150051 xge_hal_device_terminating(hldev); 2030a23fd118Syl150051 xgell_initiate_stop(lldev); 2031a23fd118Syl150051 2032a23fd118Syl150051 /* reset device */ 2033a23fd118Syl150051 (void) xge_hal_device_reset(lldev->devh); 2034a23fd118Syl150051 2035a23fd118Syl150051 mutex_exit(&lldev->genlock); 2036a23fd118Syl150051 20378347601bSyl150051 if (lldev->timeout_id != 0) { 2038a23fd118Syl150051 (void) untimeout(lldev->timeout_id); 20398347601bSyl150051 } 2040a23fd118Syl150051 2041a23fd118Syl150051 xge_debug_ll(XGE_TRACE, "%s", "returning back to MAC Layer..."); 2042a23fd118Syl150051 } 2043a23fd118Syl150051 2044a23fd118Syl150051 /* 2045a23fd118Syl150051 * xgell_onerr_reset 2046a23fd118Syl150051 * @lldev: pointer to xgelldev_t structure 2047a23fd118Syl150051 * 2048a23fd118Syl150051 * This function is called by HAL Event framework to reset the HW 2049a23fd118Syl150051 * This function is must be called with genlock taken. 2050a23fd118Syl150051 */ 2051a23fd118Syl150051 int 2052a23fd118Syl150051 xgell_onerr_reset(xgelldev_t *lldev) 2053a23fd118Syl150051 { 2054a23fd118Syl150051 int rc = 0; 2055a23fd118Syl150051 2056a23fd118Syl150051 if (!lldev->is_initialized) { 2057a23fd118Syl150051 xge_debug_ll(XGE_ERR, "%s%d: can not reset", 2058a23fd118Syl150051 XGELL_IFNAME, lldev->instance); 2059a23fd118Syl150051 return (rc); 2060a23fd118Syl150051 } 2061a23fd118Syl150051 2062a23fd118Syl150051 lldev->in_reset = 1; 2063a23fd118Syl150051 xgell_initiate_stop(lldev); 2064a23fd118Syl150051 2065a23fd118Syl150051 /* reset device */ 2066a23fd118Syl150051 (void) xge_hal_device_reset(lldev->devh); 2067a23fd118Syl150051 2068a23fd118Syl150051 rc = xgell_initiate_start(lldev); 2069a23fd118Syl150051 lldev->in_reset = 0; 2070a23fd118Syl150051 2071a23fd118Syl150051 return (rc); 2072a23fd118Syl150051 } 2073a23fd118Syl150051 2074a23fd118Syl150051 /* 2075a23fd118Syl150051 * xgell_m_multicst 2076a23fd118Syl150051 * @arg: pointer to device private strucutre(hldev) 2077a23fd118Syl150051 * @add: 2078a23fd118Syl150051 * @mc_addr: 2079a23fd118Syl150051 * 2080a23fd118Syl150051 * This function is called by MAC Layer to enable or 2081a23fd118Syl150051 * disable device-level reception of specific multicast addresses. 2082a23fd118Syl150051 */ 2083a23fd118Syl150051 static int 2084a23fd118Syl150051 xgell_m_multicst(void *arg, boolean_t add, const uint8_t *mc_addr) 2085a23fd118Syl150051 { 2086a23fd118Syl150051 xge_hal_status_e status; 20878347601bSyl150051 xgelldev_t *lldev = (xgelldev_t *)arg; 20888347601bSyl150051 xge_hal_device_t *hldev = lldev->devh; 2089a23fd118Syl150051 2090a23fd118Syl150051 xge_debug_ll(XGE_TRACE, "M_MULTICAST add %d", add); 2091a23fd118Syl150051 2092a23fd118Syl150051 mutex_enter(&lldev->genlock); 2093a23fd118Syl150051 2094a23fd118Syl150051 if (!lldev->is_initialized) { 2095a23fd118Syl150051 xge_debug_ll(XGE_ERR, "%s%d: can not set multicast", 2096a23fd118Syl150051 XGELL_IFNAME, lldev->instance); 2097a23fd118Syl150051 mutex_exit(&lldev->genlock); 2098a23fd118Syl150051 return (EIO); 2099a23fd118Syl150051 } 2100a23fd118Syl150051 2101a23fd118Syl150051 /* FIXME: missing HAL functionality: enable_one() */ 2102a23fd118Syl150051 2103a23fd118Syl150051 status = (add) ? 2104a23fd118Syl150051 xge_hal_device_mcast_enable(hldev) : 2105a23fd118Syl150051 xge_hal_device_mcast_disable(hldev); 2106a23fd118Syl150051 2107a23fd118Syl150051 if (status != XGE_HAL_OK) { 2108a23fd118Syl150051 xge_debug_ll(XGE_ERR, "failed to %s multicast, status %d", 2109a23fd118Syl150051 add ? "enable" : "disable", status); 2110a23fd118Syl150051 mutex_exit(&lldev->genlock); 2111a23fd118Syl150051 return (EIO); 2112a23fd118Syl150051 } 2113a23fd118Syl150051 2114a23fd118Syl150051 mutex_exit(&lldev->genlock); 2115a23fd118Syl150051 2116a23fd118Syl150051 return (0); 2117a23fd118Syl150051 } 2118a23fd118Syl150051 2119a23fd118Syl150051 2120a23fd118Syl150051 /* 2121a23fd118Syl150051 * xgell_m_promisc 2122a23fd118Syl150051 * @arg: pointer to device private strucutre(hldev) 2123a23fd118Syl150051 * @on: 2124a23fd118Syl150051 * 2125a23fd118Syl150051 * This function is called by MAC Layer to enable or 2126a23fd118Syl150051 * disable the reception of all the packets on the medium 2127a23fd118Syl150051 */ 2128a23fd118Syl150051 static int 2129a23fd118Syl150051 xgell_m_promisc(void *arg, boolean_t on) 2130a23fd118Syl150051 { 21318347601bSyl150051 xgelldev_t *lldev = (xgelldev_t *)arg; 21328347601bSyl150051 xge_hal_device_t *hldev = lldev->devh; 2133a23fd118Syl150051 2134a23fd118Syl150051 mutex_enter(&lldev->genlock); 2135a23fd118Syl150051 2136a23fd118Syl150051 xge_debug_ll(XGE_TRACE, "%s", "MAC_PROMISC_SET"); 2137a23fd118Syl150051 2138a23fd118Syl150051 if (!lldev->is_initialized) { 2139a23fd118Syl150051 xge_debug_ll(XGE_ERR, "%s%d: can not set promiscuous", 2140a23fd118Syl150051 XGELL_IFNAME, lldev->instance); 2141a23fd118Syl150051 mutex_exit(&lldev->genlock); 2142a23fd118Syl150051 return (EIO); 2143a23fd118Syl150051 } 2144a23fd118Syl150051 2145a23fd118Syl150051 if (on) { 2146a23fd118Syl150051 xge_hal_device_promisc_enable(hldev); 2147a23fd118Syl150051 } else { 2148a23fd118Syl150051 xge_hal_device_promisc_disable(hldev); 2149a23fd118Syl150051 } 2150a23fd118Syl150051 2151a23fd118Syl150051 mutex_exit(&lldev->genlock); 2152a23fd118Syl150051 2153a23fd118Syl150051 return (0); 2154a23fd118Syl150051 } 2155a23fd118Syl150051 2156a23fd118Syl150051 /* 2157ba2e4443Sseb * xgell_m_stat 2158a23fd118Syl150051 * @arg: pointer to device private strucutre(hldev) 2159a23fd118Syl150051 * 2160a23fd118Syl150051 * This function is called by MAC Layer to get network statistics 2161a23fd118Syl150051 * from the driver. 2162a23fd118Syl150051 */ 2163ba2e4443Sseb static int 2164ba2e4443Sseb xgell_m_stat(void *arg, uint_t stat, uint64_t *val) 2165a23fd118Syl150051 { 2166a23fd118Syl150051 xge_hal_stats_hw_info_t *hw_info; 21678347601bSyl150051 xgelldev_t *lldev = (xgelldev_t *)arg; 21688347601bSyl150051 xge_hal_device_t *hldev = lldev->devh; 2169a23fd118Syl150051 2170a23fd118Syl150051 xge_debug_ll(XGE_TRACE, "%s", "MAC_STATS_GET"); 2171a23fd118Syl150051 21727eced415Sxw161283 mutex_enter(&lldev->genlock); 2173a23fd118Syl150051 2174a23fd118Syl150051 if (!lldev->is_initialized) { 2175a23fd118Syl150051 mutex_exit(&lldev->genlock); 2176ba2e4443Sseb return (EAGAIN); 2177a23fd118Syl150051 } 2178a23fd118Syl150051 2179a23fd118Syl150051 if (xge_hal_stats_hw(hldev, &hw_info) != XGE_HAL_OK) { 2180a23fd118Syl150051 mutex_exit(&lldev->genlock); 2181ba2e4443Sseb return (EAGAIN); 2182a23fd118Syl150051 } 2183a23fd118Syl150051 2184a23fd118Syl150051 switch (stat) { 2185a23fd118Syl150051 case MAC_STAT_IFSPEED: 2186ba2e4443Sseb *val = 10000000000ull; /* 10G */ 2187a23fd118Syl150051 break; 2188a23fd118Syl150051 2189a23fd118Syl150051 case MAC_STAT_MULTIRCV: 21908347601bSyl150051 *val = ((u64) hw_info->rmac_vld_mcst_frms_oflow << 32) | 21918347601bSyl150051 hw_info->rmac_vld_mcst_frms; 2192a23fd118Syl150051 break; 2193a23fd118Syl150051 2194a23fd118Syl150051 case MAC_STAT_BRDCSTRCV: 21958347601bSyl150051 *val = ((u64) hw_info->rmac_vld_bcst_frms_oflow << 32) | 21968347601bSyl150051 hw_info->rmac_vld_bcst_frms; 2197a23fd118Syl150051 break; 2198a23fd118Syl150051 2199a23fd118Syl150051 case MAC_STAT_MULTIXMT: 22008347601bSyl150051 *val = ((u64) hw_info->tmac_mcst_frms_oflow << 32) | 22018347601bSyl150051 hw_info->tmac_mcst_frms; 2202a23fd118Syl150051 break; 2203a23fd118Syl150051 2204a23fd118Syl150051 case MAC_STAT_BRDCSTXMT: 22058347601bSyl150051 *val = ((u64) hw_info->tmac_bcst_frms_oflow << 32) | 22068347601bSyl150051 hw_info->tmac_bcst_frms; 2207a23fd118Syl150051 break; 2208a23fd118Syl150051 2209a23fd118Syl150051 case MAC_STAT_RBYTES: 22108347601bSyl150051 *val = ((u64) hw_info->rmac_ttl_octets_oflow << 32) | 22118347601bSyl150051 hw_info->rmac_ttl_octets; 2212a23fd118Syl150051 break; 2213a23fd118Syl150051 2214a23fd118Syl150051 case MAC_STAT_NORCVBUF: 2215ba2e4443Sseb *val = hw_info->rmac_drop_frms; 2216a23fd118Syl150051 break; 2217a23fd118Syl150051 2218a23fd118Syl150051 case MAC_STAT_IERRORS: 22198347601bSyl150051 *val = ((u64) hw_info->rmac_discarded_frms_oflow << 32) | 22208347601bSyl150051 hw_info->rmac_discarded_frms; 2221a23fd118Syl150051 break; 2222a23fd118Syl150051 2223a23fd118Syl150051 case MAC_STAT_OBYTES: 22248347601bSyl150051 *val = ((u64) hw_info->tmac_ttl_octets_oflow << 32) | 22258347601bSyl150051 hw_info->tmac_ttl_octets; 2226a23fd118Syl150051 break; 2227a23fd118Syl150051 2228a23fd118Syl150051 case MAC_STAT_NOXMTBUF: 2229ba2e4443Sseb *val = hw_info->tmac_drop_frms; 2230a23fd118Syl150051 break; 2231a23fd118Syl150051 2232a23fd118Syl150051 case MAC_STAT_OERRORS: 22338347601bSyl150051 *val = ((u64) hw_info->tmac_any_err_frms_oflow << 32) | 22348347601bSyl150051 hw_info->tmac_any_err_frms; 2235a23fd118Syl150051 break; 2236a23fd118Syl150051 2237a23fd118Syl150051 case MAC_STAT_IPACKETS: 22388347601bSyl150051 *val = ((u64) hw_info->rmac_vld_frms_oflow << 32) | 22398347601bSyl150051 hw_info->rmac_vld_frms; 2240a23fd118Syl150051 break; 2241a23fd118Syl150051 2242a23fd118Syl150051 case MAC_STAT_OPACKETS: 22438347601bSyl150051 *val = ((u64) hw_info->tmac_frms_oflow << 32) | 22448347601bSyl150051 hw_info->tmac_frms; 2245a23fd118Syl150051 break; 2246a23fd118Syl150051 2247ba2e4443Sseb case ETHER_STAT_FCS_ERRORS: 2248ba2e4443Sseb *val = hw_info->rmac_fcs_err_frms; 2249a23fd118Syl150051 break; 2250a23fd118Syl150051 2251ba2e4443Sseb case ETHER_STAT_TOOLONG_ERRORS: 2252ba2e4443Sseb *val = hw_info->rmac_long_frms; 2253ba2e4443Sseb break; 2254ba2e4443Sseb 2255ba2e4443Sseb case ETHER_STAT_LINK_DUPLEX: 2256ba2e4443Sseb *val = LINK_DUPLEX_FULL; 2257a23fd118Syl150051 break; 2258a23fd118Syl150051 2259a23fd118Syl150051 default: 2260ba2e4443Sseb mutex_exit(&lldev->genlock); 2261ba2e4443Sseb return (ENOTSUP); 2262a23fd118Syl150051 } 2263a23fd118Syl150051 2264a23fd118Syl150051 mutex_exit(&lldev->genlock); 2265a23fd118Syl150051 2266ba2e4443Sseb return (0); 2267a23fd118Syl150051 } 2268a23fd118Syl150051 2269a23fd118Syl150051 /* 22700dc2366fSVenugopal Iyer * Retrieve a value for one of the statistics for a particular rx ring 22710dc2366fSVenugopal Iyer */ 22720dc2366fSVenugopal Iyer int 22730dc2366fSVenugopal Iyer xgell_rx_ring_stat(mac_ring_driver_t rh, uint_t stat, uint64_t *val) 22740dc2366fSVenugopal Iyer { 22750dc2366fSVenugopal Iyer xgell_rx_ring_t *rx_ring = (xgell_rx_ring_t *)rh; 22760dc2366fSVenugopal Iyer 22770dc2366fSVenugopal Iyer switch (stat) { 22780dc2366fSVenugopal Iyer case MAC_STAT_RBYTES: 22790dc2366fSVenugopal Iyer *val = rx_ring->rx_bytes; 22800dc2366fSVenugopal Iyer break; 22810dc2366fSVenugopal Iyer 22820dc2366fSVenugopal Iyer case MAC_STAT_IPACKETS: 22830dc2366fSVenugopal Iyer *val = rx_ring->rx_pkts; 22840dc2366fSVenugopal Iyer break; 22850dc2366fSVenugopal Iyer 22860dc2366fSVenugopal Iyer default: 22870dc2366fSVenugopal Iyer *val = 0; 22880dc2366fSVenugopal Iyer return (ENOTSUP); 22890dc2366fSVenugopal Iyer } 22900dc2366fSVenugopal Iyer 22910dc2366fSVenugopal Iyer return (0); 22920dc2366fSVenugopal Iyer } 22930dc2366fSVenugopal Iyer 22940dc2366fSVenugopal Iyer /* 22950dc2366fSVenugopal Iyer * Retrieve a value for one of the statistics for a particular tx ring 22960dc2366fSVenugopal Iyer */ 22970dc2366fSVenugopal Iyer int 22980dc2366fSVenugopal Iyer xgell_tx_ring_stat(mac_ring_driver_t rh, uint_t stat, uint64_t *val) 22990dc2366fSVenugopal Iyer { 23000dc2366fSVenugopal Iyer xgell_tx_ring_t *tx_ring = (xgell_tx_ring_t *)rh; 23010dc2366fSVenugopal Iyer 23020dc2366fSVenugopal Iyer switch (stat) { 23030dc2366fSVenugopal Iyer case MAC_STAT_OBYTES: 23040dc2366fSVenugopal Iyer *val = tx_ring->tx_bytes; 23050dc2366fSVenugopal Iyer break; 23060dc2366fSVenugopal Iyer 23070dc2366fSVenugopal Iyer case MAC_STAT_OPACKETS: 23080dc2366fSVenugopal Iyer *val = tx_ring->tx_pkts; 23090dc2366fSVenugopal Iyer break; 23100dc2366fSVenugopal Iyer 23110dc2366fSVenugopal Iyer default: 23120dc2366fSVenugopal Iyer *val = 0; 23130dc2366fSVenugopal Iyer return (ENOTSUP); 23140dc2366fSVenugopal Iyer } 23150dc2366fSVenugopal Iyer 23160dc2366fSVenugopal Iyer return (0); 23170dc2366fSVenugopal Iyer } 23180dc2366fSVenugopal Iyer 23190dc2366fSVenugopal Iyer /* 2320a23fd118Syl150051 * xgell_device_alloc - Allocate new LL device 2321a23fd118Syl150051 */ 2322a23fd118Syl150051 int 2323a23fd118Syl150051 xgell_device_alloc(xge_hal_device_h devh, 2324a23fd118Syl150051 dev_info_t *dev_info, xgelldev_t **lldev_out) 2325a23fd118Syl150051 { 2326a23fd118Syl150051 xgelldev_t *lldev; 2327a23fd118Syl150051 xge_hal_device_t *hldev = (xge_hal_device_t *)devh; 2328a23fd118Syl150051 int instance = ddi_get_instance(dev_info); 2329a23fd118Syl150051 2330a23fd118Syl150051 *lldev_out = NULL; 2331a23fd118Syl150051 2332a23fd118Syl150051 xge_debug_ll(XGE_TRACE, "trying to register etherenet device %s%d...", 2333a23fd118Syl150051 XGELL_IFNAME, instance); 2334a23fd118Syl150051 2335a23fd118Syl150051 lldev = kmem_zalloc(sizeof (xgelldev_t), KM_SLEEP); 2336a23fd118Syl150051 2337a23fd118Syl150051 lldev->devh = hldev; 2338a23fd118Syl150051 lldev->instance = instance; 2339a23fd118Syl150051 lldev->dev_info = dev_info; 2340a23fd118Syl150051 2341a23fd118Syl150051 *lldev_out = lldev; 2342a23fd118Syl150051 2343a23fd118Syl150051 ddi_set_driver_private(dev_info, (caddr_t)hldev); 2344a23fd118Syl150051 2345a23fd118Syl150051 return (DDI_SUCCESS); 2346a23fd118Syl150051 } 2347a23fd118Syl150051 2348a23fd118Syl150051 /* 2349a23fd118Syl150051 * xgell_device_free 2350a23fd118Syl150051 */ 2351a23fd118Syl150051 void 2352a23fd118Syl150051 xgell_device_free(xgelldev_t *lldev) 2353a23fd118Syl150051 { 2354a23fd118Syl150051 xge_debug_ll(XGE_TRACE, "freeing device %s%d", 2355a23fd118Syl150051 XGELL_IFNAME, lldev->instance); 2356a23fd118Syl150051 2357a23fd118Syl150051 kmem_free(lldev, sizeof (xgelldev_t)); 2358a23fd118Syl150051 } 2359a23fd118Syl150051 2360a23fd118Syl150051 /* 2361a23fd118Syl150051 * xgell_ioctl 2362a23fd118Syl150051 */ 2363a23fd118Syl150051 static void 2364a23fd118Syl150051 xgell_m_ioctl(void *arg, queue_t *wq, mblk_t *mp) 2365a23fd118Syl150051 { 23668347601bSyl150051 xgelldev_t *lldev = arg; 2367a23fd118Syl150051 struct iocblk *iocp; 2368a23fd118Syl150051 int err = 0; 2369a23fd118Syl150051 int cmd; 2370a23fd118Syl150051 int need_privilege = 1; 2371a23fd118Syl150051 int ret = 0; 2372a23fd118Syl150051 2373a23fd118Syl150051 2374a23fd118Syl150051 iocp = (struct iocblk *)mp->b_rptr; 2375a23fd118Syl150051 iocp->ioc_error = 0; 2376a23fd118Syl150051 cmd = iocp->ioc_cmd; 2377a23fd118Syl150051 xge_debug_ll(XGE_TRACE, "MAC_IOCTL cmd 0x%x", cmd); 2378a23fd118Syl150051 switch (cmd) { 2379a23fd118Syl150051 case ND_GET: 2380a23fd118Syl150051 need_privilege = 0; 2381a23fd118Syl150051 /* FALLTHRU */ 2382a23fd118Syl150051 case ND_SET: 2383a23fd118Syl150051 break; 2384a23fd118Syl150051 default: 2385a23fd118Syl150051 xge_debug_ll(XGE_TRACE, "unknown cmd 0x%x", cmd); 2386a23fd118Syl150051 miocnak(wq, mp, 0, EINVAL); 2387a23fd118Syl150051 return; 2388a23fd118Syl150051 } 2389a23fd118Syl150051 2390a23fd118Syl150051 if (need_privilege) { 2391a23fd118Syl150051 err = secpolicy_net_config(iocp->ioc_cr, B_FALSE); 2392a23fd118Syl150051 if (err != 0) { 2393a23fd118Syl150051 xge_debug_ll(XGE_ERR, 2394a23fd118Syl150051 "drv_priv(): rejected cmd 0x%x, err %d", 2395a23fd118Syl150051 cmd, err); 2396a23fd118Syl150051 miocnak(wq, mp, 0, err); 2397a23fd118Syl150051 return; 2398a23fd118Syl150051 } 2399a23fd118Syl150051 } 2400a23fd118Syl150051 2401a23fd118Syl150051 switch (cmd) { 2402a23fd118Syl150051 case ND_GET: 2403a23fd118Syl150051 /* 2404a23fd118Syl150051 * If nd_getset() returns B_FALSE, the command was 2405a23fd118Syl150051 * not valid (e.g. unknown name), so we just tell the 2406a23fd118Syl150051 * top-level ioctl code to send a NAK (with code EINVAL). 2407a23fd118Syl150051 * 2408a23fd118Syl150051 * Otherwise, nd_getset() will have built the reply to 2409a23fd118Syl150051 * be sent (but not actually sent it), so we tell the 2410a23fd118Syl150051 * caller to send the prepared reply. 2411a23fd118Syl150051 */ 2412a23fd118Syl150051 ret = nd_getset(wq, lldev->ndp, mp); 24137eced415Sxw161283 xge_debug_ll(XGE_TRACE, "%s", "got ndd get ioctl"); 2414a23fd118Syl150051 break; 2415a23fd118Syl150051 2416a23fd118Syl150051 case ND_SET: 2417a23fd118Syl150051 ret = nd_getset(wq, lldev->ndp, mp); 24187eced415Sxw161283 xge_debug_ll(XGE_TRACE, "%s", "got ndd set ioctl"); 2419a23fd118Syl150051 break; 2420a23fd118Syl150051 2421a23fd118Syl150051 default: 2422a23fd118Syl150051 break; 2423a23fd118Syl150051 } 2424a23fd118Syl150051 2425a23fd118Syl150051 if (ret == B_FALSE) { 2426a23fd118Syl150051 xge_debug_ll(XGE_ERR, 2427a23fd118Syl150051 "nd_getset(): rejected cmd 0x%x, err %d", 2428a23fd118Syl150051 cmd, err); 2429a23fd118Syl150051 miocnak(wq, mp, 0, EINVAL); 2430a23fd118Syl150051 } else { 2431a23fd118Syl150051 mp->b_datap->db_type = iocp->ioc_error == 0 ? 2432a23fd118Syl150051 M_IOCACK : M_IOCNAK; 2433a23fd118Syl150051 qreply(wq, mp); 2434a23fd118Syl150051 } 2435a23fd118Syl150051 } 2436a23fd118Syl150051 2437da14cebeSEric Cheng 2438ba2e4443Sseb static boolean_t 2439ba2e4443Sseb xgell_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) 2440a23fd118Syl150051 { 24418347601bSyl150051 xgelldev_t *lldev = arg; 24428347601bSyl150051 2443da14cebeSEric Cheng xge_debug_ll(XGE_TRACE, "xgell_m_getcapab: %x", cap); 2444da14cebeSEric Cheng 2445ba2e4443Sseb switch (cap) { 2446ba2e4443Sseb case MAC_CAPAB_HCKSUM: { 2447ba2e4443Sseb uint32_t *hcksum_txflags = cap_data; 2448ba2e4443Sseb *hcksum_txflags = HCKSUM_INET_FULL_V4 | HCKSUM_INET_FULL_V6 | 2449ba2e4443Sseb HCKSUM_IPHDRCKSUM; 2450ba2e4443Sseb break; 2451a23fd118Syl150051 } 24528347601bSyl150051 case MAC_CAPAB_LSO: { 24538347601bSyl150051 mac_capab_lso_t *cap_lso = cap_data; 24548347601bSyl150051 24558347601bSyl150051 if (lldev->config.lso_enable) { 24568347601bSyl150051 cap_lso->lso_flags = LSO_TX_BASIC_TCP_IPV4; 24578347601bSyl150051 cap_lso->lso_basic_tcp_ipv4.lso_max = XGELL_LSO_MAXLEN; 24588347601bSyl150051 break; 24598347601bSyl150051 } else { 24608347601bSyl150051 return (B_FALSE); 24618347601bSyl150051 } 24628347601bSyl150051 } 2463da14cebeSEric Cheng case MAC_CAPAB_RINGS: { 2464da14cebeSEric Cheng mac_capab_rings_t *cap_rings = cap_data; 2465da14cebeSEric Cheng 2466da14cebeSEric Cheng switch (cap_rings->mr_type) { 2467da14cebeSEric Cheng case MAC_RING_TYPE_RX: 2468da14cebeSEric Cheng cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC; 2469da14cebeSEric Cheng cap_rings->mr_rnum = lldev->init_rx_rings; 2470da14cebeSEric Cheng cap_rings->mr_gnum = lldev->init_rx_groups; 2471da14cebeSEric Cheng cap_rings->mr_rget = xgell_fill_ring; 2472da14cebeSEric Cheng cap_rings->mr_gget = xgell_fill_group; 2473da14cebeSEric Cheng break; 2474da14cebeSEric Cheng case MAC_RING_TYPE_TX: 2475da14cebeSEric Cheng cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC; 2476da14cebeSEric Cheng cap_rings->mr_rnum = lldev->init_tx_rings; 2477da14cebeSEric Cheng cap_rings->mr_gnum = 0; 2478da14cebeSEric Cheng cap_rings->mr_rget = xgell_fill_ring; 2479da14cebeSEric Cheng cap_rings->mr_gget = NULL; 2480da14cebeSEric Cheng break; 2481da14cebeSEric Cheng default: 2482da14cebeSEric Cheng break; 2483da14cebeSEric Cheng } 2484da14cebeSEric Cheng break; 2485da14cebeSEric Cheng } 2486ba2e4443Sseb default: 2487ba2e4443Sseb return (B_FALSE); 2488ba2e4443Sseb } 2489ba2e4443Sseb return (B_TRUE); 2490a23fd118Syl150051 } 2491a23fd118Syl150051 2492a23fd118Syl150051 static int 2493a23fd118Syl150051 xgell_stats_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp) 2494a23fd118Syl150051 { 2495a23fd118Syl150051 xgelldev_t *lldev = (xgelldev_t *)cp; 2496a23fd118Syl150051 xge_hal_status_e status; 2497a23fd118Syl150051 int count = 0, retsize; 2498a23fd118Syl150051 char *buf; 2499a23fd118Syl150051 2500a23fd118Syl150051 buf = kmem_alloc(XGELL_STATS_BUFSIZE, KM_SLEEP); 2501a23fd118Syl150051 if (buf == NULL) { 2502a23fd118Syl150051 return (ENOSPC); 2503a23fd118Syl150051 } 2504a23fd118Syl150051 2505a23fd118Syl150051 status = xge_hal_aux_stats_tmac_read(lldev->devh, XGELL_STATS_BUFSIZE, 2506a23fd118Syl150051 buf, &retsize); 2507a23fd118Syl150051 if (status != XGE_HAL_OK) { 2508a23fd118Syl150051 kmem_free(buf, XGELL_STATS_BUFSIZE); 2509a23fd118Syl150051 xge_debug_ll(XGE_ERR, "tmac_read(): status %d", status); 2510a23fd118Syl150051 return (EINVAL); 2511a23fd118Syl150051 } 2512a23fd118Syl150051 count += retsize; 2513a23fd118Syl150051 2514a23fd118Syl150051 status = xge_hal_aux_stats_rmac_read(lldev->devh, 2515a23fd118Syl150051 XGELL_STATS_BUFSIZE - count, 2516a23fd118Syl150051 buf+count, &retsize); 2517a23fd118Syl150051 if (status != XGE_HAL_OK) { 2518a23fd118Syl150051 kmem_free(buf, XGELL_STATS_BUFSIZE); 2519a23fd118Syl150051 xge_debug_ll(XGE_ERR, "rmac_read(): status %d", status); 2520a23fd118Syl150051 return (EINVAL); 2521a23fd118Syl150051 } 2522a23fd118Syl150051 count += retsize; 2523a23fd118Syl150051 2524a23fd118Syl150051 status = xge_hal_aux_stats_pci_read(lldev->devh, 2525a23fd118Syl150051 XGELL_STATS_BUFSIZE - count, buf + count, &retsize); 2526a23fd118Syl150051 if (status != XGE_HAL_OK) { 2527a23fd118Syl150051 kmem_free(buf, XGELL_STATS_BUFSIZE); 2528a23fd118Syl150051 xge_debug_ll(XGE_ERR, "pci_read(): status %d", status); 2529a23fd118Syl150051 return (EINVAL); 2530a23fd118Syl150051 } 2531a23fd118Syl150051 count += retsize; 2532a23fd118Syl150051 2533a23fd118Syl150051 status = xge_hal_aux_stats_sw_dev_read(lldev->devh, 2534a23fd118Syl150051 XGELL_STATS_BUFSIZE - count, buf + count, &retsize); 2535a23fd118Syl150051 if (status != XGE_HAL_OK) { 2536a23fd118Syl150051 kmem_free(buf, XGELL_STATS_BUFSIZE); 2537a23fd118Syl150051 xge_debug_ll(XGE_ERR, "sw_dev_read(): status %d", status); 2538a23fd118Syl150051 return (EINVAL); 2539a23fd118Syl150051 } 2540a23fd118Syl150051 count += retsize; 2541a23fd118Syl150051 2542a23fd118Syl150051 status = xge_hal_aux_stats_hal_read(lldev->devh, 2543a23fd118Syl150051 XGELL_STATS_BUFSIZE - count, buf + count, &retsize); 2544a23fd118Syl150051 if (status != XGE_HAL_OK) { 2545a23fd118Syl150051 kmem_free(buf, XGELL_STATS_BUFSIZE); 2546a23fd118Syl150051 xge_debug_ll(XGE_ERR, "pci_read(): status %d", status); 2547a23fd118Syl150051 return (EINVAL); 2548a23fd118Syl150051 } 2549a23fd118Syl150051 count += retsize; 2550a23fd118Syl150051 2551a23fd118Syl150051 *(buf + count - 1) = '\0'; /* remove last '\n' */ 2552a23fd118Syl150051 (void) mi_mpprintf(mp, "%s", buf); 2553a23fd118Syl150051 kmem_free(buf, XGELL_STATS_BUFSIZE); 2554a23fd118Syl150051 2555a23fd118Syl150051 return (0); 2556a23fd118Syl150051 } 2557a23fd118Syl150051 2558a23fd118Syl150051 static int 2559a23fd118Syl150051 xgell_pciconf_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp) 2560a23fd118Syl150051 { 2561a23fd118Syl150051 xgelldev_t *lldev = (xgelldev_t *)cp; 2562a23fd118Syl150051 xge_hal_status_e status; 2563a23fd118Syl150051 int retsize; 2564a23fd118Syl150051 char *buf; 2565a23fd118Syl150051 2566a23fd118Syl150051 buf = kmem_alloc(XGELL_PCICONF_BUFSIZE, KM_SLEEP); 2567a23fd118Syl150051 if (buf == NULL) { 2568a23fd118Syl150051 return (ENOSPC); 2569a23fd118Syl150051 } 2570a23fd118Syl150051 status = xge_hal_aux_pci_config_read(lldev->devh, XGELL_PCICONF_BUFSIZE, 2571a23fd118Syl150051 buf, &retsize); 2572a23fd118Syl150051 if (status != XGE_HAL_OK) { 2573a23fd118Syl150051 kmem_free(buf, XGELL_PCICONF_BUFSIZE); 2574a23fd118Syl150051 xge_debug_ll(XGE_ERR, "pci_config_read(): status %d", status); 2575a23fd118Syl150051 return (EINVAL); 2576a23fd118Syl150051 } 2577a23fd118Syl150051 *(buf + retsize - 1) = '\0'; /* remove last '\n' */ 2578a23fd118Syl150051 (void) mi_mpprintf(mp, "%s", buf); 2579a23fd118Syl150051 kmem_free(buf, XGELL_PCICONF_BUFSIZE); 2580a23fd118Syl150051 2581a23fd118Syl150051 return (0); 2582a23fd118Syl150051 } 2583a23fd118Syl150051 2584a23fd118Syl150051 static int 2585a23fd118Syl150051 xgell_about_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp) 2586a23fd118Syl150051 { 2587a23fd118Syl150051 xgelldev_t *lldev = (xgelldev_t *)cp; 2588a23fd118Syl150051 xge_hal_status_e status; 2589a23fd118Syl150051 int retsize; 2590a23fd118Syl150051 char *buf; 2591a23fd118Syl150051 2592a23fd118Syl150051 buf = kmem_alloc(XGELL_ABOUT_BUFSIZE, KM_SLEEP); 2593a23fd118Syl150051 if (buf == NULL) { 2594a23fd118Syl150051 return (ENOSPC); 2595a23fd118Syl150051 } 2596a23fd118Syl150051 status = xge_hal_aux_about_read(lldev->devh, XGELL_ABOUT_BUFSIZE, 2597a23fd118Syl150051 buf, &retsize); 2598a23fd118Syl150051 if (status != XGE_HAL_OK) { 2599a23fd118Syl150051 kmem_free(buf, XGELL_ABOUT_BUFSIZE); 2600a23fd118Syl150051 xge_debug_ll(XGE_ERR, "about_read(): status %d", status); 2601a23fd118Syl150051 return (EINVAL); 2602a23fd118Syl150051 } 2603a23fd118Syl150051 *(buf + retsize - 1) = '\0'; /* remove last '\n' */ 2604a23fd118Syl150051 (void) mi_mpprintf(mp, "%s", buf); 2605a23fd118Syl150051 kmem_free(buf, XGELL_ABOUT_BUFSIZE); 2606a23fd118Syl150051 2607a23fd118Syl150051 return (0); 2608a23fd118Syl150051 } 2609a23fd118Syl150051 2610a23fd118Syl150051 static unsigned long bar0_offset = 0x110; /* adapter_control */ 2611a23fd118Syl150051 2612a23fd118Syl150051 static int 2613a23fd118Syl150051 xgell_bar0_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp) 2614a23fd118Syl150051 { 2615a23fd118Syl150051 xgelldev_t *lldev = (xgelldev_t *)cp; 2616a23fd118Syl150051 xge_hal_status_e status; 2617a23fd118Syl150051 int retsize; 2618a23fd118Syl150051 char *buf; 2619a23fd118Syl150051 2620a23fd118Syl150051 buf = kmem_alloc(XGELL_IOCTL_BUFSIZE, KM_SLEEP); 2621a23fd118Syl150051 if (buf == NULL) { 2622a23fd118Syl150051 return (ENOSPC); 2623a23fd118Syl150051 } 2624a23fd118Syl150051 status = xge_hal_aux_bar0_read(lldev->devh, bar0_offset, 2625a23fd118Syl150051 XGELL_IOCTL_BUFSIZE, buf, &retsize); 2626a23fd118Syl150051 if (status != XGE_HAL_OK) { 2627a23fd118Syl150051 kmem_free(buf, XGELL_IOCTL_BUFSIZE); 2628a23fd118Syl150051 xge_debug_ll(XGE_ERR, "bar0_read(): status %d", status); 2629a23fd118Syl150051 return (EINVAL); 2630a23fd118Syl150051 } 2631a23fd118Syl150051 *(buf + retsize - 1) = '\0'; /* remove last '\n' */ 2632a23fd118Syl150051 (void) mi_mpprintf(mp, "%s", buf); 2633a23fd118Syl150051 kmem_free(buf, XGELL_IOCTL_BUFSIZE); 2634a23fd118Syl150051 2635a23fd118Syl150051 return (0); 2636a23fd118Syl150051 } 2637a23fd118Syl150051 2638a23fd118Syl150051 static int 2639a23fd118Syl150051 xgell_bar0_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp, cred_t *credp) 2640a23fd118Syl150051 { 2641a23fd118Syl150051 unsigned long old_offset = bar0_offset; 2642a23fd118Syl150051 char *end; 2643a23fd118Syl150051 2644a23fd118Syl150051 if (value && *value == '0' && 2645a23fd118Syl150051 (*(value + 1) == 'x' || *(value + 1) == 'X')) { 2646a23fd118Syl150051 value += 2; 2647a23fd118Syl150051 } 2648a23fd118Syl150051 2649a23fd118Syl150051 bar0_offset = mi_strtol(value, &end, 16); 2650a23fd118Syl150051 if (end == value) { 2651a23fd118Syl150051 bar0_offset = old_offset; 2652a23fd118Syl150051 return (EINVAL); 2653a23fd118Syl150051 } 2654a23fd118Syl150051 2655a23fd118Syl150051 xge_debug_ll(XGE_TRACE, "bar0: new value %s:%lX", value, bar0_offset); 2656a23fd118Syl150051 2657a23fd118Syl150051 return (0); 2658a23fd118Syl150051 } 2659a23fd118Syl150051 2660a23fd118Syl150051 static int 2661a23fd118Syl150051 xgell_debug_level_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp) 2662a23fd118Syl150051 { 2663a23fd118Syl150051 char *buf; 2664a23fd118Syl150051 2665a23fd118Syl150051 buf = kmem_alloc(XGELL_IOCTL_BUFSIZE, KM_SLEEP); 2666a23fd118Syl150051 if (buf == NULL) { 2667a23fd118Syl150051 return (ENOSPC); 2668a23fd118Syl150051 } 2669a23fd118Syl150051 (void) mi_mpprintf(mp, "debug_level %d", xge_hal_driver_debug_level()); 2670a23fd118Syl150051 kmem_free(buf, XGELL_IOCTL_BUFSIZE); 2671a23fd118Syl150051 2672a23fd118Syl150051 return (0); 2673a23fd118Syl150051 } 2674a23fd118Syl150051 2675a23fd118Syl150051 static int 2676a23fd118Syl150051 xgell_debug_level_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp, 2677a23fd118Syl150051 cred_t *credp) 2678a23fd118Syl150051 { 2679a23fd118Syl150051 int level; 2680a23fd118Syl150051 char *end; 2681a23fd118Syl150051 2682a23fd118Syl150051 level = mi_strtol(value, &end, 10); 2683a23fd118Syl150051 if (level < XGE_NONE || level > XGE_ERR || end == value) { 2684a23fd118Syl150051 return (EINVAL); 2685a23fd118Syl150051 } 2686a23fd118Syl150051 2687a23fd118Syl150051 xge_hal_driver_debug_level_set(level); 2688a23fd118Syl150051 2689a23fd118Syl150051 return (0); 2690a23fd118Syl150051 } 2691a23fd118Syl150051 2692a23fd118Syl150051 static int 2693a23fd118Syl150051 xgell_debug_module_mask_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp) 2694a23fd118Syl150051 { 2695a23fd118Syl150051 char *buf; 2696a23fd118Syl150051 2697a23fd118Syl150051 buf = kmem_alloc(XGELL_IOCTL_BUFSIZE, KM_SLEEP); 2698a23fd118Syl150051 if (buf == NULL) { 2699a23fd118Syl150051 return (ENOSPC); 2700a23fd118Syl150051 } 2701a23fd118Syl150051 (void) mi_mpprintf(mp, "debug_module_mask 0x%08x", 2702a23fd118Syl150051 xge_hal_driver_debug_module_mask()); 2703a23fd118Syl150051 kmem_free(buf, XGELL_IOCTL_BUFSIZE); 2704a23fd118Syl150051 2705a23fd118Syl150051 return (0); 2706a23fd118Syl150051 } 2707a23fd118Syl150051 2708a23fd118Syl150051 static int 2709a23fd118Syl150051 xgell_debug_module_mask_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp, 2710a23fd118Syl150051 cred_t *credp) 2711a23fd118Syl150051 { 2712a23fd118Syl150051 u32 mask; 2713a23fd118Syl150051 char *end; 2714a23fd118Syl150051 2715a23fd118Syl150051 if (value && *value == '0' && 2716a23fd118Syl150051 (*(value + 1) == 'x' || *(value + 1) == 'X')) { 2717a23fd118Syl150051 value += 2; 2718a23fd118Syl150051 } 2719a23fd118Syl150051 2720a23fd118Syl150051 mask = mi_strtol(value, &end, 16); 2721a23fd118Syl150051 if (end == value) { 2722a23fd118Syl150051 return (EINVAL); 2723a23fd118Syl150051 } 2724a23fd118Syl150051 2725a23fd118Syl150051 xge_hal_driver_debug_module_mask_set(mask); 2726a23fd118Syl150051 2727a23fd118Syl150051 return (0); 2728a23fd118Syl150051 } 2729a23fd118Syl150051 2730a23fd118Syl150051 static int 2731a23fd118Syl150051 xgell_devconfig_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp) 2732a23fd118Syl150051 { 2733a23fd118Syl150051 xgelldev_t *lldev = (xgelldev_t *)(void *)cp; 2734a23fd118Syl150051 xge_hal_status_e status; 2735a23fd118Syl150051 int retsize; 2736a23fd118Syl150051 char *buf; 2737a23fd118Syl150051 2738a23fd118Syl150051 buf = kmem_alloc(XGELL_DEVCONF_BUFSIZE, KM_SLEEP); 2739a23fd118Syl150051 if (buf == NULL) { 2740a23fd118Syl150051 return (ENOSPC); 2741a23fd118Syl150051 } 2742a23fd118Syl150051 status = xge_hal_aux_device_config_read(lldev->devh, 2743da14cebeSEric Cheng XGELL_DEVCONF_BUFSIZE, buf, &retsize); 2744a23fd118Syl150051 if (status != XGE_HAL_OK) { 2745a23fd118Syl150051 kmem_free(buf, XGELL_DEVCONF_BUFSIZE); 2746a23fd118Syl150051 xge_debug_ll(XGE_ERR, "device_config_read(): status %d", 2747a23fd118Syl150051 status); 2748a23fd118Syl150051 return (EINVAL); 2749a23fd118Syl150051 } 2750a23fd118Syl150051 *(buf + retsize - 1) = '\0'; /* remove last '\n' */ 2751a23fd118Syl150051 (void) mi_mpprintf(mp, "%s", buf); 2752a23fd118Syl150051 kmem_free(buf, XGELL_DEVCONF_BUFSIZE); 2753a23fd118Syl150051 2754a23fd118Syl150051 return (0); 2755a23fd118Syl150051 } 2756a23fd118Syl150051 2757a23fd118Syl150051 /* 2758a23fd118Syl150051 * xgell_device_register 2759a23fd118Syl150051 * @devh: pointer on HAL device 2760a23fd118Syl150051 * @config: pointer on this network device configuration 2761a23fd118Syl150051 * @ll_out: output pointer. Will be assigned to valid LL device. 2762a23fd118Syl150051 * 2763a23fd118Syl150051 * This function will allocate and register network device 2764a23fd118Syl150051 */ 2765a23fd118Syl150051 int 2766a23fd118Syl150051 xgell_device_register(xgelldev_t *lldev, xgell_config_t *config) 2767a23fd118Syl150051 { 27688347601bSyl150051 mac_register_t *macp = NULL; 2769a23fd118Syl150051 xge_hal_device_t *hldev = (xge_hal_device_t *)lldev->devh; 2770a23fd118Syl150051 2771da14cebeSEric Cheng /* 2772da14cebeSEric Cheng * Initialize some NDD interface for internal debug. 2773da14cebeSEric Cheng */ 2774a23fd118Syl150051 if (nd_load(&lldev->ndp, "pciconf", xgell_pciconf_get, NULL, 2775ba2e4443Sseb (caddr_t)lldev) == B_FALSE) 2776ba2e4443Sseb goto xgell_ndd_fail; 2777a23fd118Syl150051 2778a23fd118Syl150051 if (nd_load(&lldev->ndp, "about", xgell_about_get, NULL, 2779ba2e4443Sseb (caddr_t)lldev) == B_FALSE) 2780ba2e4443Sseb goto xgell_ndd_fail; 2781a23fd118Syl150051 2782a23fd118Syl150051 if (nd_load(&lldev->ndp, "stats", xgell_stats_get, NULL, 2783ba2e4443Sseb (caddr_t)lldev) == B_FALSE) 2784ba2e4443Sseb goto xgell_ndd_fail; 2785a23fd118Syl150051 2786a23fd118Syl150051 if (nd_load(&lldev->ndp, "bar0", xgell_bar0_get, xgell_bar0_set, 2787ba2e4443Sseb (caddr_t)lldev) == B_FALSE) 2788ba2e4443Sseb goto xgell_ndd_fail; 2789a23fd118Syl150051 2790a23fd118Syl150051 if (nd_load(&lldev->ndp, "debug_level", xgell_debug_level_get, 2791ba2e4443Sseb xgell_debug_level_set, (caddr_t)lldev) == B_FALSE) 2792ba2e4443Sseb goto xgell_ndd_fail; 2793a23fd118Syl150051 2794a23fd118Syl150051 if (nd_load(&lldev->ndp, "debug_module_mask", 2795a23fd118Syl150051 xgell_debug_module_mask_get, xgell_debug_module_mask_set, 2796ba2e4443Sseb (caddr_t)lldev) == B_FALSE) 2797ba2e4443Sseb goto xgell_ndd_fail; 2798a23fd118Syl150051 2799a23fd118Syl150051 if (nd_load(&lldev->ndp, "devconfig", xgell_devconfig_get, NULL, 2800ba2e4443Sseb (caddr_t)lldev) == B_FALSE) 2801ba2e4443Sseb goto xgell_ndd_fail; 2802a23fd118Syl150051 2803a23fd118Syl150051 bcopy(config, &lldev->config, sizeof (xgell_config_t)); 2804a23fd118Syl150051 28057eced415Sxw161283 mutex_init(&lldev->genlock, NULL, MUTEX_DRIVER, 28067eced415Sxw161283 DDI_INTR_PRI(hldev->irqh)); 2807a23fd118Syl150051 2808ba2e4443Sseb if ((macp = mac_alloc(MAC_VERSION)) == NULL) 2809ba2e4443Sseb goto xgell_register_fail; 2810ba2e4443Sseb macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 28118347601bSyl150051 macp->m_driver = lldev; 2812ba2e4443Sseb macp->m_dip = lldev->dev_info; 2813ba2e4443Sseb macp->m_src_addr = hldev->macaddr[0]; 2814ba2e4443Sseb macp->m_callbacks = &xgell_m_callbacks; 2815ba2e4443Sseb macp->m_min_sdu = 0; 2816ba2e4443Sseb macp->m_max_sdu = hldev->config.mtu; 2817d62bc4baSyz147064 macp->m_margin = VLAN_TAGSZ; 2818da14cebeSEric Cheng macp->m_v12n = MAC_VIRT_LEVEL1; 28198347601bSyl150051 2820da14cebeSEric Cheng /* 2821da14cebeSEric Cheng * MAC Registration. 2822da14cebeSEric Cheng */ 28238347601bSyl150051 if (mac_register(macp, &lldev->mh) != 0) 2824ba2e4443Sseb goto xgell_register_fail; 2825a23fd118Syl150051 28263c785c4cSyl150051 /* Always free the macp after register */ 28273c785c4cSyl150051 if (macp != NULL) 28283c785c4cSyl150051 mac_free(macp); 28293c785c4cSyl150051 28308347601bSyl150051 /* Calculate tx_copied_max here ??? */ 28318347601bSyl150051 lldev->tx_copied_max = hldev->config.fifo.max_frags * 28328347601bSyl150051 hldev->config.fifo.alignment_size * 28338347601bSyl150051 hldev->config.fifo.max_aligned_frags; 28348347601bSyl150051 2835a23fd118Syl150051 xge_debug_ll(XGE_TRACE, "etherenet device %s%d registered", 2836a23fd118Syl150051 XGELL_IFNAME, lldev->instance); 2837a23fd118Syl150051 2838a23fd118Syl150051 return (DDI_SUCCESS); 2839ba2e4443Sseb 2840ba2e4443Sseb xgell_ndd_fail: 2841ba2e4443Sseb nd_free(&lldev->ndp); 2842ba2e4443Sseb xge_debug_ll(XGE_ERR, "%s", "unable to load ndd parameter"); 2843ba2e4443Sseb return (DDI_FAILURE); 2844ba2e4443Sseb 2845ba2e4443Sseb xgell_register_fail: 28468347601bSyl150051 if (macp != NULL) 28478347601bSyl150051 mac_free(macp); 2848ba2e4443Sseb nd_free(&lldev->ndp); 2849ba2e4443Sseb mutex_destroy(&lldev->genlock); 2850ba2e4443Sseb xge_debug_ll(XGE_ERR, "%s", "unable to register networking device"); 2851ba2e4443Sseb return (DDI_FAILURE); 2852a23fd118Syl150051 } 2853a23fd118Syl150051 2854a23fd118Syl150051 /* 2855a23fd118Syl150051 * xgell_device_unregister 2856a23fd118Syl150051 * @devh: pointer on HAL device 2857a23fd118Syl150051 * @lldev: pointer to valid LL device. 2858a23fd118Syl150051 * 2859a23fd118Syl150051 * This function will unregister and free network device 2860a23fd118Syl150051 */ 2861a23fd118Syl150051 int 2862a23fd118Syl150051 xgell_device_unregister(xgelldev_t *lldev) 2863a23fd118Syl150051 { 2864ba2e4443Sseb if (mac_unregister(lldev->mh) != 0) { 2865a23fd118Syl150051 xge_debug_ll(XGE_ERR, "unable to unregister device %s%d", 2866a23fd118Syl150051 XGELL_IFNAME, lldev->instance); 2867a23fd118Syl150051 return (DDI_FAILURE); 2868a23fd118Syl150051 } 2869a23fd118Syl150051 2870a23fd118Syl150051 mutex_destroy(&lldev->genlock); 2871a23fd118Syl150051 2872a23fd118Syl150051 nd_free(&lldev->ndp); 2873a23fd118Syl150051 2874a23fd118Syl150051 xge_debug_ll(XGE_TRACE, "etherenet device %s%d unregistered", 2875a23fd118Syl150051 XGELL_IFNAME, lldev->instance); 2876a23fd118Syl150051 2877a23fd118Syl150051 return (DDI_SUCCESS); 2878a23fd118Syl150051 } 2879