11256Syl150051 /* 21256Syl150051 * CDDL HEADER START 31256Syl150051 * 41256Syl150051 * The contents of this file are subject to the terms of the 51256Syl150051 * Common Development and Distribution License (the "License"). 61256Syl150051 * You may not use this file except in compliance with the License. 71256Syl150051 * 81256Syl150051 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91256Syl150051 * or http://www.opensolaris.org/os/licensing. 101256Syl150051 * See the License for the specific language governing permissions 111256Syl150051 * and limitations under the License. 121256Syl150051 * 131256Syl150051 * When distributing Covered Code, include this CDDL HEADER in each 141256Syl150051 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151256Syl150051 * If applicable, add the following below this CDDL HEADER, with the 161256Syl150051 * fields enclosed by brackets "[]" replaced with your own identifying 171256Syl150051 * information: Portions Copyright [yyyy] [name of copyright owner] 181256Syl150051 * 191256Syl150051 * CDDL HEADER END 201256Syl150051 */ 211256Syl150051 221256Syl150051 /* 235895Syz147064 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 241256Syl150051 * Use is subject to license terms. 251256Syl150051 */ 261256Syl150051 271256Syl150051 #pragma ident "%Z%%M% %I% %E% SMI" 281256Syl150051 291256Syl150051 /* 301256Syl150051 * Copyright (c) 2002-2005 Neterion, Inc. 311256Syl150051 * All right Reserved. 321256Syl150051 * 331256Syl150051 * FileName : xgell.c 341256Syl150051 * 351256Syl150051 * Description: Xge Link Layer data path implementation 361256Syl150051 * 371256Syl150051 */ 381256Syl150051 391256Syl150051 #include "xgell.h" 401256Syl150051 411256Syl150051 #include <netinet/ip.h> 421256Syl150051 #include <netinet/tcp.h> 433115Syl150051 #include <netinet/udp.h> 441256Syl150051 452311Sseb #define XGELL_MAX_FRAME_SIZE(hldev) ((hldev)->config.mtu + \ 461256Syl150051 sizeof (struct ether_vlan_header)) 471256Syl150051 481256Syl150051 #define HEADROOM 2 /* for DIX-only packets */ 491256Syl150051 501256Syl150051 void header_free_func(void *arg) { } 511256Syl150051 frtn_t header_frtn = {header_free_func, NULL}; 521256Syl150051 531256Syl150051 /* DMA attributes used for Tx side */ 541256Syl150051 static struct ddi_dma_attr tx_dma_attr = { 551256Syl150051 DMA_ATTR_V0, /* dma_attr_version */ 561256Syl150051 0x0ULL, /* dma_attr_addr_lo */ 571256Syl150051 0xFFFFFFFFFFFFFFFFULL, /* dma_attr_addr_hi */ 58*6937Sxw161283 0xFFFFFFFFFFFFFFFFULL, /* dma_attr_count_max */ 59*6937Sxw161283 #if defined(__sparc) 60*6937Sxw161283 0x2000, /* dma_attr_align */ 61*6937Sxw161283 #else 62*6937Sxw161283 0x1000, /* dma_attr_align */ 63*6937Sxw161283 #endif 64*6937Sxw161283 0xFC00FC, /* dma_attr_burstsizes */ 65*6937Sxw161283 0x1, /* dma_attr_minxfer */ 66*6937Sxw161283 0xFFFFFFFFFFFFFFFFULL, /* dma_attr_maxxfer */ 671256Syl150051 0xFFFFFFFFFFFFFFFFULL, /* dma_attr_seg */ 683115Syl150051 18, /* dma_attr_sgllen */ 69*6937Sxw161283 (unsigned int)1, /* dma_attr_granular */ 701256Syl150051 0 /* dma_attr_flags */ 711256Syl150051 }; 721256Syl150051 731256Syl150051 /* 741256Syl150051 * DMA attributes used when using ddi_dma_mem_alloc to 751256Syl150051 * allocat HAL descriptors and Rx buffers during replenish 761256Syl150051 */ 771256Syl150051 static struct ddi_dma_attr hal_dma_attr = { 781256Syl150051 DMA_ATTR_V0, /* dma_attr_version */ 791256Syl150051 0x0ULL, /* dma_attr_addr_lo */ 801256Syl150051 0xFFFFFFFFFFFFFFFFULL, /* dma_attr_addr_hi */ 81*6937Sxw161283 0xFFFFFFFFFFFFFFFFULL, /* dma_attr_count_max */ 82*6937Sxw161283 #if defined(__sparc) 83*6937Sxw161283 0x2000, /* dma_attr_align */ 84*6937Sxw161283 #else 85*6937Sxw161283 0x1000, /* dma_attr_align */ 86*6937Sxw161283 #endif 87*6937Sxw161283 0xFC00FC, /* dma_attr_burstsizes */ 88*6937Sxw161283 0x1, /* dma_attr_minxfer */ 89*6937Sxw161283 0xFFFFFFFFFFFFFFFFULL, /* dma_attr_maxxfer */ 901256Syl150051 0xFFFFFFFFFFFFFFFFULL, /* dma_attr_seg */ 911256Syl150051 1, /* dma_attr_sgllen */ 92*6937Sxw161283 (unsigned int)1, /* dma_attr_sgllen */ 93*6937Sxw161283 DDI_DMA_RELAXED_ORDERING /* dma_attr_flags */ 941256Syl150051 }; 951256Syl150051 961256Syl150051 struct ddi_dma_attr *p_hal_dma_attr = &hal_dma_attr; 971256Syl150051 982311Sseb static int xgell_m_stat(void *, uint_t, uint64_t *); 992311Sseb static int xgell_m_start(void *); 1002311Sseb static void xgell_m_stop(void *); 1012311Sseb static int xgell_m_promisc(void *, boolean_t); 1022311Sseb static int xgell_m_multicst(void *, boolean_t, const uint8_t *); 1032311Sseb static int xgell_m_unicst(void *, const uint8_t *); 1042311Sseb static void xgell_m_ioctl(void *, queue_t *, mblk_t *); 1052311Sseb static mblk_t *xgell_m_tx(void *, mblk_t *); 1062311Sseb static boolean_t xgell_m_getcapab(void *, mac_capab_t, void *); 1072311Sseb 1082311Sseb #define XGELL_M_CALLBACK_FLAGS (MC_IOCTL | MC_GETCAPAB) 1092311Sseb 1102311Sseb static mac_callbacks_t xgell_m_callbacks = { 1112311Sseb XGELL_M_CALLBACK_FLAGS, 1122311Sseb xgell_m_stat, 1132311Sseb xgell_m_start, 1142311Sseb xgell_m_stop, 1152311Sseb xgell_m_promisc, 1162311Sseb xgell_m_multicst, 1172311Sseb xgell_m_unicst, 1182311Sseb xgell_m_tx, 1192311Sseb NULL, 1202311Sseb xgell_m_ioctl, 1212311Sseb xgell_m_getcapab 1222311Sseb }; 1232311Sseb 1241256Syl150051 /* 1251256Syl150051 * xge_device_poll 1261256Syl150051 * 1271256Syl150051 * Cyclic should call me every 1s. xge_callback_event_queued should call me 1281256Syl150051 * when HAL hope event was rescheduled. 1291256Syl150051 */ 1301256Syl150051 /*ARGSUSED*/ 1311256Syl150051 void 1321256Syl150051 xge_device_poll(void *data) 1331256Syl150051 { 1341256Syl150051 xgelldev_t *lldev = xge_hal_device_private(data); 1351256Syl150051 1361256Syl150051 mutex_enter(&lldev->genlock); 1371256Syl150051 if (lldev->is_initialized) { 1381256Syl150051 xge_hal_device_poll(data); 1391256Syl150051 lldev->timeout_id = timeout(xge_device_poll, data, 1401256Syl150051 XGE_DEV_POLL_TICKS); 1413115Syl150051 } else if (lldev->in_reset == 1) { 1423115Syl150051 lldev->timeout_id = timeout(xge_device_poll, data, 1433115Syl150051 XGE_DEV_POLL_TICKS); 1443115Syl150051 } else { 1453115Syl150051 lldev->timeout_id = 0; 1461256Syl150051 } 1471256Syl150051 mutex_exit(&lldev->genlock); 1481256Syl150051 } 1491256Syl150051 1501256Syl150051 /* 1511256Syl150051 * xge_device_poll_now 1521256Syl150051 * 1531256Syl150051 * Will call xge_device_poll() immediately 1541256Syl150051 */ 1551256Syl150051 void 1561256Syl150051 xge_device_poll_now(void *data) 1571256Syl150051 { 1581256Syl150051 xgelldev_t *lldev = xge_hal_device_private(data); 1591256Syl150051 1601256Syl150051 mutex_enter(&lldev->genlock); 1613115Syl150051 if (lldev->is_initialized) { 1623115Syl150051 xge_hal_device_poll(data); 1633115Syl150051 } 1641256Syl150051 mutex_exit(&lldev->genlock); 1651256Syl150051 } 1661256Syl150051 1671256Syl150051 /* 1681256Syl150051 * xgell_callback_link_up 1691256Syl150051 * 1701256Syl150051 * This function called by HAL to notify HW link up state change. 1711256Syl150051 */ 1721256Syl150051 void 1731256Syl150051 xgell_callback_link_up(void *userdata) 1741256Syl150051 { 1751256Syl150051 xgelldev_t *lldev = (xgelldev_t *)userdata; 1761256Syl150051 1772311Sseb mac_link_update(lldev->mh, LINK_STATE_UP); 1781256Syl150051 } 1791256Syl150051 1801256Syl150051 /* 1811256Syl150051 * xgell_callback_link_down 1821256Syl150051 * 1831256Syl150051 * This function called by HAL to notify HW link down state change. 1841256Syl150051 */ 1851256Syl150051 void 1861256Syl150051 xgell_callback_link_down(void *userdata) 1871256Syl150051 { 1881256Syl150051 xgelldev_t *lldev = (xgelldev_t *)userdata; 1891256Syl150051 1902311Sseb mac_link_update(lldev->mh, LINK_STATE_DOWN); 1911256Syl150051 } 1921256Syl150051 1931256Syl150051 /* 1941256Syl150051 * xgell_rx_buffer_replenish_all 1951256Syl150051 * 1961256Syl150051 * To replenish all freed dtr(s) with buffers in free pool. It's called by 1971256Syl150051 * xgell_rx_buffer_recycle() or xgell_rx_1b_compl(). 1981256Syl150051 * Must be called with pool_lock held. 1991256Syl150051 */ 2001256Syl150051 static void 201*6937Sxw161283 xgell_rx_buffer_replenish_all(xgell_ring_t *ring) 2021256Syl150051 { 2031256Syl150051 xge_hal_dtr_h dtr; 2041256Syl150051 xgell_rx_buffer_t *rx_buffer; 2051256Syl150051 xgell_rxd_priv_t *rxd_priv; 2061256Syl150051 207*6937Sxw161283 xge_assert(mutex_owned(&ring->bf_pool.pool_lock)); 2083115Syl150051 209*6937Sxw161283 while ((ring->bf_pool.free > 0) && 210*6937Sxw161283 (xge_hal_ring_dtr_reserve(ring->channelh, &dtr) == 2111256Syl150051 XGE_HAL_OK)) { 212*6937Sxw161283 rx_buffer = ring->bf_pool.head; 213*6937Sxw161283 ring->bf_pool.head = rx_buffer->next; 214*6937Sxw161283 ring->bf_pool.free--; 2151256Syl150051 2161256Syl150051 xge_assert(rx_buffer); 2171256Syl150051 xge_assert(rx_buffer->dma_addr); 2181256Syl150051 2191256Syl150051 rxd_priv = (xgell_rxd_priv_t *) 220*6937Sxw161283 xge_hal_ring_dtr_private(ring->channelh, dtr); 2211256Syl150051 xge_hal_ring_dtr_1b_set(dtr, rx_buffer->dma_addr, 222*6937Sxw161283 ring->bf_pool.size); 2231256Syl150051 2241256Syl150051 rxd_priv->rx_buffer = rx_buffer; 225*6937Sxw161283 xge_hal_ring_dtr_post(ring->channelh, dtr); 2261256Syl150051 } 2271256Syl150051 } 2281256Syl150051 2291256Syl150051 /* 2301256Syl150051 * xgell_rx_buffer_release 2311256Syl150051 * 2321256Syl150051 * The only thing done here is to put the buffer back to the pool. 2333115Syl150051 * Calling this function need be protected by mutex, bf_pool.pool_lock. 2341256Syl150051 */ 2351256Syl150051 static void 2361256Syl150051 xgell_rx_buffer_release(xgell_rx_buffer_t *rx_buffer) 2371256Syl150051 { 238*6937Sxw161283 xgell_ring_t *ring = rx_buffer->ring; 2391256Syl150051 240*6937Sxw161283 xge_assert(mutex_owned(&ring->bf_pool.pool_lock)); 2411256Syl150051 2421256Syl150051 /* Put the buffer back to pool */ 243*6937Sxw161283 rx_buffer->next = ring->bf_pool.head; 244*6937Sxw161283 ring->bf_pool.head = rx_buffer; 2451256Syl150051 246*6937Sxw161283 ring->bf_pool.free++; 2471256Syl150051 } 2481256Syl150051 2491256Syl150051 /* 2501256Syl150051 * xgell_rx_buffer_recycle 2511256Syl150051 * 2521256Syl150051 * Called by desballoc() to "free" the resource. 2531256Syl150051 * We will try to replenish all descripters. 2541256Syl150051 */ 255*6937Sxw161283 256*6937Sxw161283 /* 257*6937Sxw161283 * Previously there were much lock contention between xgell_rx_1b_compl() and 258*6937Sxw161283 * xgell_rx_buffer_recycle(), which consumed a lot of CPU resources and had bad 259*6937Sxw161283 * effect on rx performance. A separate recycle list is introduced to overcome 260*6937Sxw161283 * this. The recycle list is used to record the rx buffer that has been recycled 261*6937Sxw161283 * and these buffers will be retuned back to the free list in bulk instead of 262*6937Sxw161283 * one-by-one. 263*6937Sxw161283 */ 264*6937Sxw161283 2651256Syl150051 static void 2661256Syl150051 xgell_rx_buffer_recycle(char *arg) 2671256Syl150051 { 2681256Syl150051 xgell_rx_buffer_t *rx_buffer = (xgell_rx_buffer_t *)arg; 269*6937Sxw161283 xgell_ring_t *ring = rx_buffer->ring; 270*6937Sxw161283 xgelldev_t *lldev = ring->lldev; 271*6937Sxw161283 xgell_rx_buffer_pool_t *bf_pool = &ring->bf_pool; 272*6937Sxw161283 273*6937Sxw161283 mutex_enter(&bf_pool->recycle_lock); 2741256Syl150051 275*6937Sxw161283 rx_buffer->next = bf_pool->recycle_head; 276*6937Sxw161283 bf_pool->recycle_head = rx_buffer; 277*6937Sxw161283 if (bf_pool->recycle_tail == NULL) 278*6937Sxw161283 bf_pool->recycle_tail = rx_buffer; 279*6937Sxw161283 bf_pool->recycle++; 2801256Syl150051 2811256Syl150051 /* 2821256Syl150051 * Before finding a good way to set this hiwat, just always call to 2831256Syl150051 * replenish_all. *TODO* 2841256Syl150051 */ 285*6937Sxw161283 if ((lldev->is_initialized != 0) && 286*6937Sxw161283 (bf_pool->recycle >= XGELL_RX_BUFFER_RECYCLE_CACHE)) { 287*6937Sxw161283 if (mutex_tryenter(&bf_pool->pool_lock)) { 288*6937Sxw161283 bf_pool->recycle_tail->next = bf_pool->head; 289*6937Sxw161283 bf_pool->head = bf_pool->recycle_head; 290*6937Sxw161283 bf_pool->recycle_head = bf_pool->recycle_tail = NULL; 291*6937Sxw161283 bf_pool->post -= bf_pool->recycle; 292*6937Sxw161283 bf_pool->free += bf_pool->recycle; 293*6937Sxw161283 bf_pool->recycle = 0; 294*6937Sxw161283 xgell_rx_buffer_replenish_all(ring); 295*6937Sxw161283 mutex_exit(&bf_pool->pool_lock); 296*6937Sxw161283 } 2971256Syl150051 } 2981256Syl150051 299*6937Sxw161283 mutex_exit(&bf_pool->recycle_lock); 3001256Syl150051 } 3011256Syl150051 3021256Syl150051 /* 3031256Syl150051 * xgell_rx_buffer_alloc 3041256Syl150051 * 3051256Syl150051 * Allocate one rx buffer and return with the pointer to the buffer. 3061256Syl150051 * Return NULL if failed. 3071256Syl150051 */ 3081256Syl150051 static xgell_rx_buffer_t * 309*6937Sxw161283 xgell_rx_buffer_alloc(xgell_ring_t *ring) 3101256Syl150051 { 3111256Syl150051 xge_hal_device_t *hldev; 3121256Syl150051 void *vaddr; 3131256Syl150051 ddi_dma_handle_t dma_handle; 3141256Syl150051 ddi_acc_handle_t dma_acch; 3151256Syl150051 dma_addr_t dma_addr; 3161256Syl150051 uint_t ncookies; 3171256Syl150051 ddi_dma_cookie_t dma_cookie; 3181256Syl150051 size_t real_size; 3191256Syl150051 extern ddi_device_acc_attr_t *p_xge_dev_attr; 3201256Syl150051 xgell_rx_buffer_t *rx_buffer; 321*6937Sxw161283 xgelldev_t *lldev = ring->lldev; 3221256Syl150051 3233115Syl150051 hldev = (xge_hal_device_t *)lldev->devh; 3241256Syl150051 3251256Syl150051 if (ddi_dma_alloc_handle(hldev->pdev, p_hal_dma_attr, DDI_DMA_SLEEP, 3261256Syl150051 0, &dma_handle) != DDI_SUCCESS) { 3271256Syl150051 xge_debug_ll(XGE_ERR, "%s%d: can not allocate DMA handle", 3281256Syl150051 XGELL_IFNAME, lldev->instance); 3291256Syl150051 goto handle_failed; 3301256Syl150051 } 3311256Syl150051 3321256Syl150051 /* reserve some space at the end of the buffer for recycling */ 333*6937Sxw161283 if (ddi_dma_mem_alloc(dma_handle, HEADROOM + ring->bf_pool.size + 3341256Syl150051 sizeof (xgell_rx_buffer_t), p_xge_dev_attr, DDI_DMA_STREAMING, 3351256Syl150051 DDI_DMA_SLEEP, 0, (caddr_t *)&vaddr, &real_size, &dma_acch) != 3361256Syl150051 DDI_SUCCESS) { 3371256Syl150051 xge_debug_ll(XGE_ERR, "%s%d: can not allocate DMA-able memory", 3381256Syl150051 XGELL_IFNAME, lldev->instance); 3391256Syl150051 goto mem_failed; 3401256Syl150051 } 3411256Syl150051 342*6937Sxw161283 if (HEADROOM + ring->bf_pool.size + sizeof (xgell_rx_buffer_t) > 3431256Syl150051 real_size) { 3441256Syl150051 xge_debug_ll(XGE_ERR, "%s%d: can not allocate DMA-able memory", 3451256Syl150051 XGELL_IFNAME, lldev->instance); 3461256Syl150051 goto bind_failed; 3471256Syl150051 } 3481256Syl150051 3491256Syl150051 if (ddi_dma_addr_bind_handle(dma_handle, NULL, (char *)vaddr + HEADROOM, 350*6937Sxw161283 ring->bf_pool.size, DDI_DMA_READ | DDI_DMA_STREAMING, 3511256Syl150051 DDI_DMA_SLEEP, 0, &dma_cookie, &ncookies) != DDI_SUCCESS) { 3521256Syl150051 xge_debug_ll(XGE_ERR, "%s%d: out of mapping for mblk", 3531256Syl150051 XGELL_IFNAME, lldev->instance); 3541256Syl150051 goto bind_failed; 3551256Syl150051 } 3561256Syl150051 357*6937Sxw161283 if (ncookies != 1 || dma_cookie.dmac_size < ring->bf_pool.size) { 3581256Syl150051 xge_debug_ll(XGE_ERR, "%s%d: can not handle partial DMA", 3591256Syl150051 XGELL_IFNAME, lldev->instance); 3601256Syl150051 goto check_failed; 3611256Syl150051 } 3621256Syl150051 3631256Syl150051 dma_addr = dma_cookie.dmac_laddress; 3641256Syl150051 3651256Syl150051 rx_buffer = (xgell_rx_buffer_t *)((char *)vaddr + real_size - 3661256Syl150051 sizeof (xgell_rx_buffer_t)); 3671256Syl150051 rx_buffer->next = NULL; 3681256Syl150051 rx_buffer->vaddr = vaddr; 3691256Syl150051 rx_buffer->dma_addr = dma_addr; 3701256Syl150051 rx_buffer->dma_handle = dma_handle; 3711256Syl150051 rx_buffer->dma_acch = dma_acch; 372*6937Sxw161283 rx_buffer->ring = ring; 3731256Syl150051 rx_buffer->frtn.free_func = xgell_rx_buffer_recycle; 3741256Syl150051 rx_buffer->frtn.free_arg = (void *)rx_buffer; 3751256Syl150051 3761256Syl150051 return (rx_buffer); 3771256Syl150051 3781256Syl150051 check_failed: 3791256Syl150051 (void) ddi_dma_unbind_handle(dma_handle); 3801256Syl150051 bind_failed: 3811256Syl150051 XGE_OS_MEMORY_CHECK_FREE(vaddr, 0); 3821256Syl150051 ddi_dma_mem_free(&dma_acch); 3831256Syl150051 mem_failed: 3841256Syl150051 ddi_dma_free_handle(&dma_handle); 3851256Syl150051 handle_failed: 3861256Syl150051 3871256Syl150051 return (NULL); 3881256Syl150051 } 3891256Syl150051 3901256Syl150051 /* 3911256Syl150051 * xgell_rx_destroy_buffer_pool 3921256Syl150051 * 3931256Syl150051 * Destroy buffer pool. If there is still any buffer hold by upper layer, 3941256Syl150051 * recorded by bf_pool.post, return DDI_FAILURE to reject to be unloaded. 3951256Syl150051 */ 3961256Syl150051 static int 397*6937Sxw161283 xgell_rx_destroy_buffer_pool(xgell_ring_t *ring) 3981256Syl150051 { 3991256Syl150051 xgell_rx_buffer_t *rx_buffer; 4001256Syl150051 ddi_dma_handle_t dma_handle; 4011256Syl150051 ddi_acc_handle_t dma_acch; 402*6937Sxw161283 xgelldev_t *lldev = ring->lldev; 4031256Syl150051 int i; 4041256Syl150051 405*6937Sxw161283 if (ring->bf_pool.recycle > 0) { 406*6937Sxw161283 ring->bf_pool.recycle_tail->next = ring->bf_pool.head; 407*6937Sxw161283 ring->bf_pool.head = ring->bf_pool.recycle_head; 408*6937Sxw161283 ring->bf_pool.recycle_tail = 409*6937Sxw161283 ring->bf_pool.recycle_head = NULL; 410*6937Sxw161283 ring->bf_pool.post -= ring->bf_pool.recycle; 411*6937Sxw161283 ring->bf_pool.free += ring->bf_pool.recycle; 412*6937Sxw161283 ring->bf_pool.recycle = 0; 413*6937Sxw161283 } 414*6937Sxw161283 4151256Syl150051 /* 4161256Syl150051 * If there is any posted buffer, the driver should reject to be 4171256Syl150051 * detached. Need notice upper layer to release them. 4181256Syl150051 */ 419*6937Sxw161283 if (ring->bf_pool.post != 0) { 4201256Syl150051 xge_debug_ll(XGE_ERR, 4211256Syl150051 "%s%d has some buffers not be recycled, try later!", 4221256Syl150051 XGELL_IFNAME, lldev->instance); 4231256Syl150051 return (DDI_FAILURE); 4241256Syl150051 } 4251256Syl150051 4261256Syl150051 /* 4271256Syl150051 * Relase buffers one by one. 4281256Syl150051 */ 429*6937Sxw161283 for (i = ring->bf_pool.total; i > 0; i--) { 430*6937Sxw161283 rx_buffer = ring->bf_pool.head; 4311256Syl150051 xge_assert(rx_buffer != NULL); 4321256Syl150051 433*6937Sxw161283 ring->bf_pool.head = rx_buffer->next; 4341256Syl150051 4351256Syl150051 dma_handle = rx_buffer->dma_handle; 4361256Syl150051 dma_acch = rx_buffer->dma_acch; 4371256Syl150051 4381256Syl150051 if (ddi_dma_unbind_handle(dma_handle) != DDI_SUCCESS) { 439*6937Sxw161283 xge_debug_ll(XGE_ERR, "%s", 440*6937Sxw161283 "failed to unbind DMA handle!"); 441*6937Sxw161283 ring->bf_pool.head = rx_buffer; 4421256Syl150051 return (DDI_FAILURE); 4431256Syl150051 } 4441256Syl150051 ddi_dma_mem_free(&dma_acch); 4451256Syl150051 ddi_dma_free_handle(&dma_handle); 4461256Syl150051 447*6937Sxw161283 ring->bf_pool.total--; 448*6937Sxw161283 ring->bf_pool.free--; 4491256Syl150051 } 4501256Syl150051 451*6937Sxw161283 mutex_destroy(&ring->bf_pool.recycle_lock); 452*6937Sxw161283 mutex_destroy(&ring->bf_pool.pool_lock); 4531256Syl150051 return (DDI_SUCCESS); 4541256Syl150051 } 4551256Syl150051 4561256Syl150051 /* 4571256Syl150051 * xgell_rx_create_buffer_pool 4581256Syl150051 * 4591256Syl150051 * Initialize RX buffer pool for all RX rings. Refer to rx_buffer_pool_t. 4601256Syl150051 */ 4611256Syl150051 static int 462*6937Sxw161283 xgell_rx_create_buffer_pool(xgell_ring_t *ring) 4631256Syl150051 { 4641256Syl150051 xge_hal_device_t *hldev; 4651256Syl150051 xgell_rx_buffer_t *rx_buffer; 466*6937Sxw161283 xgelldev_t *lldev = ring->lldev; 4671256Syl150051 int i; 4681256Syl150051 4692311Sseb hldev = (xge_hal_device_t *)lldev->devh; 4701256Syl150051 471*6937Sxw161283 ring->bf_pool.total = 0; 472*6937Sxw161283 ring->bf_pool.size = XGELL_MAX_FRAME_SIZE(hldev); 473*6937Sxw161283 ring->bf_pool.head = NULL; 474*6937Sxw161283 ring->bf_pool.free = 0; 475*6937Sxw161283 ring->bf_pool.post = 0; 476*6937Sxw161283 ring->bf_pool.post_hiwat = lldev->config.rx_buffer_post_hiwat; 477*6937Sxw161283 ring->bf_pool.recycle = 0; 478*6937Sxw161283 ring->bf_pool.recycle_head = NULL; 479*6937Sxw161283 ring->bf_pool.recycle_tail = NULL; 4801256Syl150051 481*6937Sxw161283 mutex_init(&ring->bf_pool.pool_lock, NULL, MUTEX_DRIVER, 482*6937Sxw161283 DDI_INTR_PRI(hldev->irqh)); 483*6937Sxw161283 mutex_init(&ring->bf_pool.recycle_lock, NULL, MUTEX_DRIVER, 484*6937Sxw161283 DDI_INTR_PRI(hldev->irqh)); 4851256Syl150051 4861256Syl150051 /* 4871256Syl150051 * Allocate buffers one by one. If failed, destroy whole pool by 4881256Syl150051 * call to xgell_rx_destroy_buffer_pool(). 4891256Syl150051 */ 490*6937Sxw161283 4911256Syl150051 for (i = 0; i < lldev->config.rx_buffer_total; i++) { 492*6937Sxw161283 if ((rx_buffer = xgell_rx_buffer_alloc(ring)) == NULL) { 493*6937Sxw161283 (void) xgell_rx_destroy_buffer_pool(ring); 4941256Syl150051 return (DDI_FAILURE); 4951256Syl150051 } 4961256Syl150051 497*6937Sxw161283 rx_buffer->next = ring->bf_pool.head; 498*6937Sxw161283 ring->bf_pool.head = rx_buffer; 4991256Syl150051 500*6937Sxw161283 ring->bf_pool.total++; 501*6937Sxw161283 ring->bf_pool.free++; 5021256Syl150051 } 5031256Syl150051 5041256Syl150051 return (DDI_SUCCESS); 5051256Syl150051 } 5061256Syl150051 5071256Syl150051 /* 5081256Syl150051 * xgell_rx_dtr_replenish 5091256Syl150051 * 5101256Syl150051 * Replenish descriptor with rx_buffer in RX buffer pool. 5111256Syl150051 * The dtr should be post right away. 5121256Syl150051 */ 5131256Syl150051 xge_hal_status_e 5141256Syl150051 xgell_rx_dtr_replenish(xge_hal_channel_h channelh, xge_hal_dtr_h dtr, int index, 5151256Syl150051 void *userdata, xge_hal_channel_reopen_e reopen) 5161256Syl150051 { 5171256Syl150051 xgell_ring_t *ring = userdata; 5181256Syl150051 xgell_rx_buffer_t *rx_buffer; 5191256Syl150051 xgell_rxd_priv_t *rxd_priv; 5201256Syl150051 521*6937Sxw161283 if (ring->bf_pool.head == NULL) { 522*6937Sxw161283 xge_debug_ll(XGE_ERR, "%s", "no more available rx DMA buffer!"); 5231256Syl150051 return (XGE_HAL_FAIL); 5241256Syl150051 } 525*6937Sxw161283 rx_buffer = ring->bf_pool.head; 526*6937Sxw161283 ring->bf_pool.head = rx_buffer->next; 527*6937Sxw161283 ring->bf_pool.free--; 5281256Syl150051 5291256Syl150051 xge_assert(rx_buffer); 5301256Syl150051 xge_assert(rx_buffer->dma_addr); 5311256Syl150051 532*6937Sxw161283 rxd_priv = (xgell_rxd_priv_t *)xge_hal_ring_dtr_private(channelh, dtr); 533*6937Sxw161283 xge_hal_ring_dtr_1b_set(dtr, rx_buffer->dma_addr, ring->bf_pool.size); 5341256Syl150051 5351256Syl150051 rxd_priv->rx_buffer = rx_buffer; 5361256Syl150051 5371256Syl150051 return (XGE_HAL_OK); 5381256Syl150051 } 5391256Syl150051 5401256Syl150051 /* 5411256Syl150051 * xgell_get_ip_offset 5421256Syl150051 * 5431256Syl150051 * Calculate the offset to IP header. 5441256Syl150051 */ 5451256Syl150051 static inline int 5461256Syl150051 xgell_get_ip_offset(xge_hal_dtr_info_t *ext_info) 5471256Syl150051 { 5481256Syl150051 int ip_off; 5491256Syl150051 5501256Syl150051 /* get IP-header offset */ 5511256Syl150051 switch (ext_info->frame) { 5521256Syl150051 case XGE_HAL_FRAME_TYPE_DIX: 5531256Syl150051 ip_off = XGE_HAL_HEADER_ETHERNET_II_802_3_SIZE; 5541256Syl150051 break; 5551256Syl150051 case XGE_HAL_FRAME_TYPE_IPX: 5561256Syl150051 ip_off = (XGE_HAL_HEADER_ETHERNET_II_802_3_SIZE + 5571256Syl150051 XGE_HAL_HEADER_802_2_SIZE + 5581256Syl150051 XGE_HAL_HEADER_SNAP_SIZE); 5591256Syl150051 break; 5601256Syl150051 case XGE_HAL_FRAME_TYPE_LLC: 5611256Syl150051 ip_off = (XGE_HAL_HEADER_ETHERNET_II_802_3_SIZE + 5621256Syl150051 XGE_HAL_HEADER_802_2_SIZE); 5631256Syl150051 break; 5641256Syl150051 case XGE_HAL_FRAME_TYPE_SNAP: 5651256Syl150051 ip_off = (XGE_HAL_HEADER_ETHERNET_II_802_3_SIZE + 5661256Syl150051 XGE_HAL_HEADER_SNAP_SIZE); 5671256Syl150051 break; 5681256Syl150051 default: 5691256Syl150051 ip_off = 0; 5701256Syl150051 break; 5711256Syl150051 } 5721256Syl150051 5731256Syl150051 if ((ext_info->proto & XGE_HAL_FRAME_PROTO_IPV4 || 5741256Syl150051 ext_info->proto & XGE_HAL_FRAME_PROTO_IPV6) && 5751256Syl150051 (ext_info->proto & XGE_HAL_FRAME_PROTO_VLAN_TAGGED)) { 5761256Syl150051 ip_off += XGE_HAL_HEADER_VLAN_SIZE; 5771256Syl150051 } 5781256Syl150051 5791256Syl150051 return (ip_off); 5801256Syl150051 } 5811256Syl150051 5821256Syl150051 /* 5831256Syl150051 * xgell_rx_hcksum_assoc 5841256Syl150051 * 5851256Syl150051 * Judge the packet type and then call to hcksum_assoc() to associate 5861256Syl150051 * h/w checksum information. 5871256Syl150051 */ 5881256Syl150051 static inline void 5891256Syl150051 xgell_rx_hcksum_assoc(mblk_t *mp, char *vaddr, int pkt_length, 5901256Syl150051 xge_hal_dtr_info_t *ext_info) 5911256Syl150051 { 5921256Syl150051 int cksum_flags = 0; 5931256Syl150051 5941256Syl150051 if (!(ext_info->proto & XGE_HAL_FRAME_PROTO_IP_FRAGMENTED)) { 5951256Syl150051 if (ext_info->proto & XGE_HAL_FRAME_PROTO_TCP_OR_UDP) { 5961256Syl150051 if (ext_info->l3_cksum == XGE_HAL_L3_CKSUM_OK) { 5971256Syl150051 cksum_flags |= HCK_IPV4_HDRCKSUM; 5981256Syl150051 } 5991256Syl150051 if (ext_info->l4_cksum == XGE_HAL_L4_CKSUM_OK) { 6001256Syl150051 cksum_flags |= HCK_FULLCKSUM_OK; 6011256Syl150051 } 6021256Syl150051 if (cksum_flags) { 6031256Syl150051 cksum_flags |= HCK_FULLCKSUM; 6041256Syl150051 (void) hcksum_assoc(mp, NULL, NULL, 0, 6051256Syl150051 0, 0, 0, cksum_flags, 0); 6061256Syl150051 } 6071256Syl150051 } 6081256Syl150051 } else if (ext_info->proto & 6091256Syl150051 (XGE_HAL_FRAME_PROTO_IPV4 | XGE_HAL_FRAME_PROTO_IPV6)) { 6101256Syl150051 /* 6111256Syl150051 * Just pass the partial cksum up to IP. 6121256Syl150051 */ 6133115Syl150051 int ip_off = xgell_get_ip_offset(ext_info); 6141256Syl150051 int start, end = pkt_length - ip_off; 6151256Syl150051 6161256Syl150051 if (ext_info->proto & XGE_HAL_FRAME_PROTO_IPV4) { 6171256Syl150051 struct ip *ip = 6181256Syl150051 (struct ip *)(vaddr + ip_off); 6191256Syl150051 start = ip->ip_hl * 4 + ip_off; 6201256Syl150051 } else { 6211256Syl150051 start = ip_off + 40; 6221256Syl150051 } 6231256Syl150051 cksum_flags |= HCK_PARTIALCKSUM; 6241256Syl150051 (void) hcksum_assoc(mp, NULL, NULL, start, 0, 6251256Syl150051 end, ntohs(ext_info->l4_cksum), cksum_flags, 6261256Syl150051 0); 6271256Syl150051 } 6281256Syl150051 } 6291256Syl150051 6301256Syl150051 /* 6311256Syl150051 * xgell_rx_1b_msg_alloc 6321256Syl150051 * 6331256Syl150051 * Allocate message header for data buffer, and decide if copy the packet to 6341256Syl150051 * new data buffer to release big rx_buffer to save memory. 6351256Syl150051 * 6363115Syl150051 * If the pkt_length <= XGELL_RX_DMA_LOWAT, call allocb() to allocate 6371256Syl150051 * new message and copy the payload in. 6381256Syl150051 */ 6391256Syl150051 static mblk_t * 6403115Syl150051 xgell_rx_1b_msg_alloc(xgelldev_t *lldev, xgell_rx_buffer_t *rx_buffer, 6413115Syl150051 int pkt_length, xge_hal_dtr_info_t *ext_info, boolean_t *copyit) 6421256Syl150051 { 6431256Syl150051 mblk_t *mp; 6441256Syl150051 char *vaddr; 6451256Syl150051 6461256Syl150051 vaddr = (char *)rx_buffer->vaddr + HEADROOM; 6471256Syl150051 /* 6481256Syl150051 * Copy packet into new allocated message buffer, if pkt_length 6493115Syl150051 * is less than XGELL_RX_DMA_LOWAT 6501256Syl150051 */ 6513115Syl150051 if (*copyit || pkt_length <= lldev->config.rx_dma_lowat) { 652*6937Sxw161283 if ((mp = allocb(pkt_length + HEADROOM, 0)) == NULL) { 6531256Syl150051 return (NULL); 6541256Syl150051 } 655*6937Sxw161283 mp->b_rptr += HEADROOM; 6561256Syl150051 bcopy(vaddr, mp->b_rptr, pkt_length); 6571256Syl150051 mp->b_wptr = mp->b_rptr + pkt_length; 6581256Syl150051 *copyit = B_TRUE; 6591256Syl150051 return (mp); 6601256Syl150051 } 6611256Syl150051 6621256Syl150051 /* 6631256Syl150051 * Just allocate mblk for current data buffer 6641256Syl150051 */ 6653392Syl150051 if ((mp = (mblk_t *)desballoc((unsigned char *)vaddr, pkt_length, 0, 6661256Syl150051 &rx_buffer->frtn)) == NULL) { 6671256Syl150051 /* Drop it */ 6681256Syl150051 return (NULL); 6691256Syl150051 } 6701256Syl150051 /* 6713392Syl150051 * Adjust the b_rptr/b_wptr in the mblk_t structure. 6721256Syl150051 */ 6733392Syl150051 mp->b_wptr += pkt_length; 6741256Syl150051 6751256Syl150051 return (mp); 6761256Syl150051 } 6771256Syl150051 6781256Syl150051 /* 6791256Syl150051 * xgell_rx_1b_compl 6801256Syl150051 * 6811256Syl150051 * If the interrupt is because of a received frame or if the receive ring 6821256Syl150051 * contains fresh as yet un-processed frames, this function is called. 6831256Syl150051 */ 6841256Syl150051 static xge_hal_status_e 6851256Syl150051 xgell_rx_1b_compl(xge_hal_channel_h channelh, xge_hal_dtr_h dtr, u8 t_code, 6861256Syl150051 void *userdata) 6871256Syl150051 { 688*6937Sxw161283 xgell_ring_t *ring = (xgell_ring_t *)userdata; 689*6937Sxw161283 xgelldev_t *lldev = ring->lldev; 6901256Syl150051 xgell_rx_buffer_t *rx_buffer; 6911256Syl150051 mblk_t *mp_head = NULL; 6921256Syl150051 mblk_t *mp_end = NULL; 6933115Syl150051 int pkt_burst = 0; 6943115Syl150051 695*6937Sxw161283 mutex_enter(&ring->bf_pool.pool_lock); 6961256Syl150051 6971256Syl150051 do { 6981256Syl150051 int pkt_length; 6991256Syl150051 dma_addr_t dma_data; 7001256Syl150051 mblk_t *mp; 7011256Syl150051 boolean_t copyit = B_FALSE; 7021256Syl150051 7031256Syl150051 xgell_rxd_priv_t *rxd_priv = ((xgell_rxd_priv_t *) 7041256Syl150051 xge_hal_ring_dtr_private(channelh, dtr)); 7051256Syl150051 xge_hal_dtr_info_t ext_info; 7061256Syl150051 7071256Syl150051 rx_buffer = rxd_priv->rx_buffer; 7081256Syl150051 7091256Syl150051 xge_hal_ring_dtr_1b_get(channelh, dtr, &dma_data, &pkt_length); 7101256Syl150051 xge_hal_ring_dtr_info_get(channelh, dtr, &ext_info); 7111256Syl150051 7121256Syl150051 xge_assert(dma_data == rx_buffer->dma_addr); 7131256Syl150051 7141256Syl150051 if (t_code != 0) { 7151256Syl150051 xge_debug_ll(XGE_ERR, "%s%d: rx: dtr 0x%"PRIx64 7161256Syl150051 " completed due to error t_code %01x", XGELL_IFNAME, 7171256Syl150051 lldev->instance, (uint64_t)(uintptr_t)dtr, t_code); 7181256Syl150051 7191256Syl150051 (void) xge_hal_device_handle_tcode(channelh, dtr, 7201256Syl150051 t_code); 7211256Syl150051 xge_hal_ring_dtr_free(channelh, dtr); /* drop it */ 7221256Syl150051 xgell_rx_buffer_release(rx_buffer); 7231256Syl150051 continue; 7241256Syl150051 } 7251256Syl150051 7261256Syl150051 /* 7271256Syl150051 * Sync the DMA memory 7281256Syl150051 */ 7293115Syl150051 if (ddi_dma_sync(rx_buffer->dma_handle, 0, pkt_length, 7303115Syl150051 DDI_DMA_SYNC_FORKERNEL) != DDI_SUCCESS) { 7311256Syl150051 xge_debug_ll(XGE_ERR, "%s%d: rx: can not do DMA sync", 7321256Syl150051 XGELL_IFNAME, lldev->instance); 7331256Syl150051 xge_hal_ring_dtr_free(channelh, dtr); /* drop it */ 7341256Syl150051 xgell_rx_buffer_release(rx_buffer); 7351256Syl150051 continue; 7361256Syl150051 } 7371256Syl150051 7381256Syl150051 /* 7391256Syl150051 * Allocate message for the packet. 7401256Syl150051 */ 741*6937Sxw161283 if (ring->bf_pool.post > ring->bf_pool.post_hiwat) { 7421256Syl150051 copyit = B_TRUE; 7431256Syl150051 } else { 7441256Syl150051 copyit = B_FALSE; 7451256Syl150051 } 7461256Syl150051 7473115Syl150051 mp = xgell_rx_1b_msg_alloc(lldev, rx_buffer, pkt_length, 7483115Syl150051 &ext_info, ©it); 7491256Syl150051 7501256Syl150051 xge_hal_ring_dtr_free(channelh, dtr); 7511256Syl150051 7521256Syl150051 /* 7531256Syl150051 * Release the buffer and recycle it later 7541256Syl150051 */ 7551256Syl150051 if ((mp == NULL) || copyit) { 7561256Syl150051 xgell_rx_buffer_release(rx_buffer); 7571256Syl150051 } else { 7581256Syl150051 /* 7591256Syl150051 * Count it since the buffer should be loaned up. 7601256Syl150051 */ 761*6937Sxw161283 ring->bf_pool.post++; 7621256Syl150051 } 7631256Syl150051 if (mp == NULL) { 7641256Syl150051 xge_debug_ll(XGE_ERR, 7653115Syl150051 "%s%d: rx: can not allocate mp mblk", 7663115Syl150051 XGELL_IFNAME, lldev->instance); 7671256Syl150051 continue; 7681256Syl150051 } 7691256Syl150051 7701256Syl150051 /* 7713115Syl150051 * Associate cksum_flags per packet type and h/w 7723115Syl150051 * cksum flags. 7731256Syl150051 */ 7741256Syl150051 xgell_rx_hcksum_assoc(mp, (char *)rx_buffer->vaddr + 7751256Syl150051 HEADROOM, pkt_length, &ext_info); 7761256Syl150051 7771256Syl150051 if (mp_head == NULL) { 7781256Syl150051 mp_head = mp; 7791256Syl150051 mp_end = mp; 7801256Syl150051 } else { 7811256Syl150051 mp_end->b_next = mp; 7821256Syl150051 mp_end = mp; 7831256Syl150051 } 7841256Syl150051 7853115Syl150051 if (++pkt_burst < lldev->config.rx_pkt_burst) 7863115Syl150051 continue; 7873115Syl150051 788*6937Sxw161283 if (ring->bf_pool.post > ring->bf_pool.post_hiwat) { 7893115Syl150051 /* Replenish rx buffers */ 790*6937Sxw161283 xgell_rx_buffer_replenish_all(ring); 7913115Syl150051 } 792*6937Sxw161283 mutex_exit(&ring->bf_pool.pool_lock); 7933115Syl150051 if (mp_head != NULL) { 7943115Syl150051 mac_rx(lldev->mh, ((xgell_ring_t *)userdata)->handle, 7953115Syl150051 mp_head); 7963115Syl150051 } 7973115Syl150051 mp_head = mp_end = NULL; 7983115Syl150051 pkt_burst = 0; 799*6937Sxw161283 mutex_enter(&ring->bf_pool.pool_lock); 8003115Syl150051 8011256Syl150051 } while (xge_hal_ring_dtr_next_completed(channelh, &dtr, &t_code) == 8021256Syl150051 XGE_HAL_OK); 8031256Syl150051 8041256Syl150051 /* 8051256Syl150051 * Always call replenish_all to recycle rx_buffers. 8061256Syl150051 */ 807*6937Sxw161283 xgell_rx_buffer_replenish_all(ring); 808*6937Sxw161283 mutex_exit(&ring->bf_pool.pool_lock); 8091256Syl150051 8103115Syl150051 if (mp_head != NULL) { 8113115Syl150051 mac_rx(lldev->mh, ((xgell_ring_t *)userdata)->handle, mp_head); 8123115Syl150051 } 8133115Syl150051 8141256Syl150051 return (XGE_HAL_OK); 8151256Syl150051 } 8161256Syl150051 8171256Syl150051 /* 8181256Syl150051 * xgell_xmit_compl 8191256Syl150051 * 8201256Syl150051 * If an interrupt was raised to indicate DMA complete of the Tx packet, 8211256Syl150051 * this function is called. It identifies the last TxD whose buffer was 8221256Syl150051 * freed and frees all skbs whose data have already DMA'ed into the NICs 8231256Syl150051 * internal memory. 8241256Syl150051 */ 8251256Syl150051 static xge_hal_status_e 8261256Syl150051 xgell_xmit_compl(xge_hal_channel_h channelh, xge_hal_dtr_h dtr, u8 t_code, 8271256Syl150051 void *userdata) 8281256Syl150051 { 829*6937Sxw161283 xgell_fifo_t *fifo = (xgell_fifo_t *)userdata; 830*6937Sxw161283 xgelldev_t *lldev = fifo->lldev; 8311256Syl150051 8321256Syl150051 do { 8331256Syl150051 xgell_txd_priv_t *txd_priv = ((xgell_txd_priv_t *) 8341256Syl150051 xge_hal_fifo_dtr_private(dtr)); 8351256Syl150051 int i; 8361256Syl150051 8371256Syl150051 if (t_code) { 8381256Syl150051 xge_debug_ll(XGE_TRACE, "%s%d: tx: dtr 0x%"PRIx64 8391256Syl150051 " completed due to error t_code %01x", XGELL_IFNAME, 8401256Syl150051 lldev->instance, (uint64_t)(uintptr_t)dtr, t_code); 8411256Syl150051 8421256Syl150051 (void) xge_hal_device_handle_tcode(channelh, dtr, 8431256Syl150051 t_code); 8441256Syl150051 } 8451256Syl150051 8461256Syl150051 for (i = 0; i < txd_priv->handle_cnt; i++) { 847*6937Sxw161283 if (txd_priv->dma_handles[i] != NULL) { 848*6937Sxw161283 xge_assert(txd_priv->dma_handles[i]); 849*6937Sxw161283 (void) ddi_dma_unbind_handle( 850*6937Sxw161283 txd_priv->dma_handles[i]); 851*6937Sxw161283 ddi_dma_free_handle(&txd_priv->dma_handles[i]); 852*6937Sxw161283 txd_priv->dma_handles[i] = 0; 853*6937Sxw161283 } 8541256Syl150051 } 855*6937Sxw161283 txd_priv->handle_cnt = 0; 8561256Syl150051 8571256Syl150051 xge_hal_fifo_dtr_free(channelh, dtr); 8581256Syl150051 859*6937Sxw161283 if (txd_priv->mblk != NULL) { 860*6937Sxw161283 freemsg(txd_priv->mblk); 861*6937Sxw161283 txd_priv->mblk = NULL; 862*6937Sxw161283 } 863*6937Sxw161283 8641256Syl150051 lldev->resched_avail++; 8651256Syl150051 8661256Syl150051 } while (xge_hal_fifo_dtr_next_completed(channelh, &dtr, &t_code) == 8671256Syl150051 XGE_HAL_OK); 8681256Syl150051 8691256Syl150051 if (lldev->resched_retry && 8701256Syl150051 xge_queue_produce_context(xge_hal_device_queue(lldev->devh), 871*6937Sxw161283 XGELL_EVENT_RESCHED_NEEDED, fifo) == XGE_QUEUE_OK) { 872*6937Sxw161283 xge_debug_ll(XGE_TRACE, "%s%d: IRQ produced event for queue %d", 873*6937Sxw161283 XGELL_IFNAME, lldev->instance, 874*6937Sxw161283 ((xge_hal_channel_t *)channelh)->post_qid); 8751256Syl150051 lldev->resched_send = lldev->resched_avail; 8761256Syl150051 lldev->resched_retry = 0; 8771256Syl150051 } 8781256Syl150051 8791256Syl150051 return (XGE_HAL_OK); 8801256Syl150051 } 8811256Syl150051 8821256Syl150051 /* 8831256Syl150051 * xgell_send 8843115Syl150051 * @hldev: pointer to xge_hal_device_t strucutre 8851256Syl150051 * @mblk: pointer to network buffer, i.e. mblk_t structure 8861256Syl150051 * 8871256Syl150051 * Called by the xgell_m_tx to transmit the packet to the XFRAME firmware. 8881256Syl150051 * A pointer to an M_DATA message that contains the packet is passed to 8891256Syl150051 * this routine. 8901256Syl150051 */ 8911256Syl150051 static boolean_t 8923115Syl150051 xgell_send(xgelldev_t *lldev, mblk_t *mp) 8931256Syl150051 { 8941256Syl150051 mblk_t *bp; 8953115Syl150051 boolean_t retry; 8963115Syl150051 xge_hal_device_t *hldev = lldev->devh; 8971256Syl150051 xge_hal_status_e status; 8981256Syl150051 xge_hal_dtr_h dtr; 8991256Syl150051 xgell_txd_priv_t *txd_priv; 9003115Syl150051 uint32_t hckflags; 9013115Syl150051 uint32_t mss; 9023115Syl150051 int handle_cnt, frag_cnt, ret, i, copied; 9033115Syl150051 boolean_t used_copy; 904*6937Sxw161283 xgell_fifo_t *fifo; 905*6937Sxw161283 xge_hal_channel_h fifo_channel; 9061256Syl150051 9071256Syl150051 _begin: 9083115Syl150051 retry = B_FALSE; 9091256Syl150051 handle_cnt = frag_cnt = 0; 9101256Syl150051 9111256Syl150051 if (!lldev->is_initialized || lldev->in_reset) 9121256Syl150051 return (B_FALSE); 9131256Syl150051 914*6937Sxw161283 fifo = &lldev->fifos[0]; 915*6937Sxw161283 fifo_channel = fifo->channelh; 916*6937Sxw161283 9171256Syl150051 /* 9181256Syl150051 * If the free Tx dtrs count reaches the lower threshold, 9191256Syl150051 * inform the gld to stop sending more packets till the free 9201256Syl150051 * dtrs count exceeds higher threshold. Driver informs the 9211256Syl150051 * gld through gld_sched call, when the free dtrs count exceeds 9221256Syl150051 * the higher threshold. 9231256Syl150051 */ 924*6937Sxw161283 if (xge_hal_channel_dtr_count(fifo_channel) 9251256Syl150051 <= XGELL_TX_LEVEL_LOW) { 926*6937Sxw161283 if (++fifo->level_low > XGELL_TX_LEVEL_CHECK) { 927*6937Sxw161283 xge_debug_ll(XGE_TRACE, "%s%d: queue %d: err on xmit," 928*6937Sxw161283 "free descriptors count at low threshold %d", 929*6937Sxw161283 XGELL_IFNAME, lldev->instance, 930*6937Sxw161283 ((xge_hal_channel_t *)fifo_channel)->post_qid, 931*6937Sxw161283 XGELL_TX_LEVEL_LOW); 932*6937Sxw161283 fifo->level_low = 0; 933*6937Sxw161283 retry = B_TRUE; 934*6937Sxw161283 goto _exit; 935*6937Sxw161283 } 936*6937Sxw161283 } else { 937*6937Sxw161283 fifo->level_low = 0; 9381256Syl150051 } 9391256Syl150051 940*6937Sxw161283 status = xge_hal_fifo_dtr_reserve(fifo_channel, &dtr); 9411256Syl150051 if (status != XGE_HAL_OK) { 9421256Syl150051 switch (status) { 9431256Syl150051 case XGE_HAL_INF_CHANNEL_IS_NOT_READY: 9441256Syl150051 xge_debug_ll(XGE_ERR, 9451256Syl150051 "%s%d: channel %d is not ready.", XGELL_IFNAME, 9461256Syl150051 lldev->instance, 9471256Syl150051 ((xge_hal_channel_t *) 948*6937Sxw161283 fifo_channel)->post_qid); 9493115Syl150051 retry = B_TRUE; 9501256Syl150051 goto _exit; 9511256Syl150051 case XGE_HAL_INF_OUT_OF_DESCRIPTORS: 9521256Syl150051 xge_debug_ll(XGE_TRACE, "%s%d: queue %d: error in xmit," 9531256Syl150051 " out of descriptors.", XGELL_IFNAME, 9541256Syl150051 lldev->instance, 9551256Syl150051 ((xge_hal_channel_t *) 956*6937Sxw161283 fifo_channel)->post_qid); 9573115Syl150051 retry = B_TRUE; 9581256Syl150051 goto _exit; 9591256Syl150051 default: 9601256Syl150051 return (B_FALSE); 9611256Syl150051 } 9621256Syl150051 } 9631256Syl150051 9641256Syl150051 txd_priv = xge_hal_fifo_dtr_private(dtr); 9651256Syl150051 txd_priv->mblk = mp; 9661256Syl150051 9671256Syl150051 /* 9681256Syl150051 * VLAN tag should be passed down along with MAC header, so h/w needn't 9691256Syl150051 * do insertion. 9701256Syl150051 * 9711256Syl150051 * For NIC driver that has to strip and re-insert VLAN tag, the example 9721256Syl150051 * is the other implementation for xge. The driver can simple bcopy() 9731256Syl150051 * ether_vlan_header to overwrite VLAN tag and let h/w insert the tag 9741256Syl150051 * automatically, since it's impossible that GLD sends down mp(s) with 9751256Syl150051 * splited ether_vlan_header. 9761256Syl150051 * 9771256Syl150051 * struct ether_vlan_header *evhp; 9781256Syl150051 * uint16_t tci; 9791256Syl150051 * 9801256Syl150051 * evhp = (struct ether_vlan_header *)mp->b_rptr; 9811256Syl150051 * if (evhp->ether_tpid == htons(VLAN_TPID)) { 9823115Syl150051 * tci = ntohs(evhp->ether_tci); 9833115Syl150051 * (void) bcopy(mp->b_rptr, mp->b_rptr + VLAN_TAGSZ, 9841256Syl150051 * 2 * ETHERADDRL); 9853115Syl150051 * mp->b_rptr += VLAN_TAGSZ; 9861256Syl150051 * 9873115Syl150051 * xge_hal_fifo_dtr_vlan_set(dtr, tci); 9881256Syl150051 * } 9891256Syl150051 */ 9901256Syl150051 9913115Syl150051 copied = 0; 9923115Syl150051 used_copy = B_FALSE; 9931256Syl150051 for (bp = mp; bp != NULL; bp = bp->b_cont) { 9941256Syl150051 int mblen; 9951256Syl150051 uint_t ncookies; 9961256Syl150051 ddi_dma_cookie_t dma_cookie; 9971256Syl150051 ddi_dma_handle_t dma_handle; 9981256Syl150051 9991256Syl150051 /* skip zero-length message blocks */ 10001256Syl150051 mblen = MBLKL(bp); 10011256Syl150051 if (mblen == 0) { 10021256Syl150051 continue; 10031256Syl150051 } 10041256Syl150051 10053115Syl150051 /* 10063115Syl150051 * Check the message length to decide to DMA or bcopy() data 10073115Syl150051 * to tx descriptor(s). 10083115Syl150051 */ 10093115Syl150051 if (mblen < lldev->config.tx_dma_lowat && 10103115Syl150051 (copied + mblen) < lldev->tx_copied_max) { 10113115Syl150051 xge_hal_status_e rc; 1012*6937Sxw161283 rc = xge_hal_fifo_dtr_buffer_append(fifo_channel, 10133115Syl150051 dtr, bp->b_rptr, mblen); 10143115Syl150051 if (rc == XGE_HAL_OK) { 10153115Syl150051 used_copy = B_TRUE; 10163115Syl150051 copied += mblen; 10173115Syl150051 continue; 10183115Syl150051 } else if (used_copy) { 10193115Syl150051 xge_hal_fifo_dtr_buffer_finalize( 1020*6937Sxw161283 fifo_channel, dtr, frag_cnt++); 10213115Syl150051 used_copy = B_FALSE; 10223115Syl150051 } 10233115Syl150051 } else if (used_copy) { 1024*6937Sxw161283 xge_hal_fifo_dtr_buffer_finalize(fifo_channel, 10253115Syl150051 dtr, frag_cnt++); 10263115Syl150051 used_copy = B_FALSE; 10273115Syl150051 } 10283115Syl150051 10292311Sseb ret = ddi_dma_alloc_handle(lldev->dev_info, &tx_dma_attr, 10301256Syl150051 DDI_DMA_DONTWAIT, 0, &dma_handle); 10311256Syl150051 if (ret != DDI_SUCCESS) { 10321256Syl150051 xge_debug_ll(XGE_ERR, 10333115Syl150051 "%s%d: can not allocate dma handle", XGELL_IFNAME, 10343115Syl150051 lldev->instance); 10351256Syl150051 goto _exit_cleanup; 10361256Syl150051 } 10371256Syl150051 10381256Syl150051 ret = ddi_dma_addr_bind_handle(dma_handle, NULL, 10391256Syl150051 (caddr_t)bp->b_rptr, mblen, 10401256Syl150051 DDI_DMA_WRITE | DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 0, 10411256Syl150051 &dma_cookie, &ncookies); 10421256Syl150051 10431256Syl150051 switch (ret) { 10441256Syl150051 case DDI_DMA_MAPPED: 10451256Syl150051 /* everything's fine */ 10461256Syl150051 break; 10471256Syl150051 10481256Syl150051 case DDI_DMA_NORESOURCES: 10491256Syl150051 xge_debug_ll(XGE_ERR, 10501256Syl150051 "%s%d: can not bind dma address", 10511256Syl150051 XGELL_IFNAME, lldev->instance); 10521256Syl150051 ddi_dma_free_handle(&dma_handle); 10531256Syl150051 goto _exit_cleanup; 10541256Syl150051 10551256Syl150051 case DDI_DMA_NOMAPPING: 10561256Syl150051 case DDI_DMA_INUSE: 10571256Syl150051 case DDI_DMA_TOOBIG: 10581256Syl150051 default: 10591256Syl150051 /* drop packet, don't retry */ 10601256Syl150051 xge_debug_ll(XGE_ERR, 10611256Syl150051 "%s%d: can not map message buffer", 10621256Syl150051 XGELL_IFNAME, lldev->instance); 10631256Syl150051 ddi_dma_free_handle(&dma_handle); 10641256Syl150051 goto _exit_cleanup; 10651256Syl150051 } 10661256Syl150051 10673115Syl150051 if (ncookies + frag_cnt > hldev->config.fifo.max_frags) { 10681256Syl150051 xge_debug_ll(XGE_ERR, "%s%d: too many fragments, " 10691256Syl150051 "requested c:%d+f:%d", XGELL_IFNAME, 10701256Syl150051 lldev->instance, ncookies, frag_cnt); 10711256Syl150051 (void) ddi_dma_unbind_handle(dma_handle); 10721256Syl150051 ddi_dma_free_handle(&dma_handle); 10731256Syl150051 goto _exit_cleanup; 10741256Syl150051 } 10751256Syl150051 10761256Syl150051 /* setup the descriptors for this data buffer */ 10771256Syl150051 while (ncookies) { 1078*6937Sxw161283 xge_hal_fifo_dtr_buffer_set(fifo_channel, dtr, 10791256Syl150051 frag_cnt++, dma_cookie.dmac_laddress, 10801256Syl150051 dma_cookie.dmac_size); 10811256Syl150051 if (--ncookies) { 10821256Syl150051 ddi_dma_nextcookie(dma_handle, &dma_cookie); 10831256Syl150051 } 10841256Syl150051 10851256Syl150051 } 10861256Syl150051 10871256Syl150051 txd_priv->dma_handles[handle_cnt++] = dma_handle; 10881256Syl150051 10891256Syl150051 if (bp->b_cont && 10901256Syl150051 (frag_cnt + XGE_HAL_DEFAULT_FIFO_FRAGS_THRESHOLD >= 1091*6937Sxw161283 hldev->config.fifo.max_frags)) { 10921256Syl150051 mblk_t *nmp; 10931256Syl150051 10941256Syl150051 xge_debug_ll(XGE_TRACE, 10951256Syl150051 "too many FRAGs [%d], pull up them", frag_cnt); 10961256Syl150051 10971256Syl150051 if ((nmp = msgpullup(bp->b_cont, -1)) == NULL) { 10981256Syl150051 /* Drop packet, don't retry */ 10991256Syl150051 xge_debug_ll(XGE_ERR, 11001256Syl150051 "%s%d: can not pullup message buffer", 11011256Syl150051 XGELL_IFNAME, lldev->instance); 11021256Syl150051 goto _exit_cleanup; 11031256Syl150051 } 11041256Syl150051 freemsg(bp->b_cont); 11051256Syl150051 bp->b_cont = nmp; 11061256Syl150051 } 11071256Syl150051 } 11081256Syl150051 11093115Syl150051 /* finalize unfinished copies */ 11103115Syl150051 if (used_copy) { 1111*6937Sxw161283 xge_hal_fifo_dtr_buffer_finalize(fifo_channel, dtr, 11123115Syl150051 frag_cnt++); 11133115Syl150051 } 11143115Syl150051 11151256Syl150051 txd_priv->handle_cnt = handle_cnt; 11161256Syl150051 11173115Syl150051 /* 11183115Syl150051 * If LSO is required, just call xge_hal_fifo_dtr_mss_set(dtr, mss) to 11193115Syl150051 * do all necessary work. 11203115Syl150051 */ 11213115Syl150051 hcksum_retrieve(mp, NULL, NULL, NULL, NULL, NULL, &mss, &hckflags); 11223115Syl150051 if ((hckflags & HW_LSO) && (mss != 0)) { 11233115Syl150051 xge_hal_fifo_dtr_mss_set(dtr, mss); 11243115Syl150051 } 11253115Syl150051 11263115Syl150051 if (hckflags & HCK_IPV4_HDRCKSUM) { 11271256Syl150051 xge_hal_fifo_dtr_cksum_set_bits(dtr, 11281256Syl150051 XGE_HAL_TXD_TX_CKO_IPV4_EN); 11291256Syl150051 } 11303115Syl150051 if (hckflags & HCK_FULLCKSUM) { 11311256Syl150051 xge_hal_fifo_dtr_cksum_set_bits(dtr, XGE_HAL_TXD_TX_CKO_TCP_EN | 11321256Syl150051 XGE_HAL_TXD_TX_CKO_UDP_EN); 11331256Syl150051 } 11341256Syl150051 1135*6937Sxw161283 xge_hal_fifo_dtr_post(fifo_channel, dtr); 11361256Syl150051 11371256Syl150051 return (B_TRUE); 11381256Syl150051 11391256Syl150051 _exit_cleanup: 11401256Syl150051 11411256Syl150051 for (i = 0; i < handle_cnt; i++) { 11421256Syl150051 (void) ddi_dma_unbind_handle(txd_priv->dma_handles[i]); 11431256Syl150051 ddi_dma_free_handle(&txd_priv->dma_handles[i]); 11441256Syl150051 txd_priv->dma_handles[i] = 0; 11451256Syl150051 } 11461256Syl150051 1147*6937Sxw161283 xge_hal_fifo_dtr_free(fifo_channel, dtr); 11481256Syl150051 11491256Syl150051 _exit: 11501256Syl150051 if (retry) { 11511256Syl150051 if (lldev->resched_avail != lldev->resched_send && 11521256Syl150051 xge_queue_produce_context(xge_hal_device_queue(lldev->devh), 1153*6937Sxw161283 XGELL_EVENT_RESCHED_NEEDED, fifo) == XGE_QUEUE_OK) { 11541256Syl150051 lldev->resched_send = lldev->resched_avail; 11551256Syl150051 return (B_FALSE); 11561256Syl150051 } else { 11571256Syl150051 lldev->resched_retry = 1; 11581256Syl150051 } 11591256Syl150051 } 11601256Syl150051 1161*6937Sxw161283 if (mp) 1162*6937Sxw161283 freemsg(mp); 11631256Syl150051 return (B_TRUE); 11641256Syl150051 } 11651256Syl150051 11661256Syl150051 /* 11671256Syl150051 * xge_m_tx 11683115Syl150051 * @arg: pointer to the xgelldev_t structure 11691256Syl150051 * @resid: resource id 11701256Syl150051 * @mp: pointer to the message buffer 11711256Syl150051 * 11721256Syl150051 * Called by MAC Layer to send a chain of packets 11731256Syl150051 */ 11741256Syl150051 static mblk_t * 11751256Syl150051 xgell_m_tx(void *arg, mblk_t *mp) 11761256Syl150051 { 11773115Syl150051 xgelldev_t *lldev = arg; 11781256Syl150051 mblk_t *next; 11791256Syl150051 11801256Syl150051 while (mp != NULL) { 11811256Syl150051 next = mp->b_next; 11821256Syl150051 mp->b_next = NULL; 11831256Syl150051 11843115Syl150051 if (!xgell_send(lldev, mp)) { 11851256Syl150051 mp->b_next = next; 11861256Syl150051 break; 11871256Syl150051 } 11881256Syl150051 mp = next; 11891256Syl150051 } 11901256Syl150051 11911256Syl150051 return (mp); 11921256Syl150051 } 11931256Syl150051 11941256Syl150051 /* 11951256Syl150051 * xgell_rx_dtr_term 11961256Syl150051 * 11971256Syl150051 * Function will be called by HAL to terminate all DTRs for 11981256Syl150051 * Ring(s) type of channels. 11991256Syl150051 */ 12001256Syl150051 static void 12011256Syl150051 xgell_rx_dtr_term(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh, 12021256Syl150051 xge_hal_dtr_state_e state, void *userdata, xge_hal_channel_reopen_e reopen) 12031256Syl150051 { 1204*6937Sxw161283 xgell_ring_t *ring = (xgell_ring_t *)userdata; 12051256Syl150051 xgell_rxd_priv_t *rxd_priv = 12061256Syl150051 ((xgell_rxd_priv_t *)xge_hal_ring_dtr_private(channelh, dtrh)); 12071256Syl150051 xgell_rx_buffer_t *rx_buffer = rxd_priv->rx_buffer; 12081256Syl150051 12091256Syl150051 if (state == XGE_HAL_DTR_STATE_POSTED) { 1210*6937Sxw161283 mutex_enter(&ring->bf_pool.pool_lock); 12111256Syl150051 xge_hal_ring_dtr_free(channelh, dtrh); 12121256Syl150051 xgell_rx_buffer_release(rx_buffer); 1213*6937Sxw161283 mutex_exit(&ring->bf_pool.pool_lock); 12141256Syl150051 } 12151256Syl150051 } 12161256Syl150051 12171256Syl150051 /* 12181256Syl150051 * xgell_tx_term 12191256Syl150051 * 12201256Syl150051 * Function will be called by HAL to terminate all DTRs for 12211256Syl150051 * Fifo(s) type of channels. 12221256Syl150051 */ 12231256Syl150051 static void 12241256Syl150051 xgell_tx_term(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh, 12251256Syl150051 xge_hal_dtr_state_e state, void *userdata, xge_hal_channel_reopen_e reopen) 12261256Syl150051 { 12271256Syl150051 xgell_txd_priv_t *txd_priv = 12281256Syl150051 ((xgell_txd_priv_t *)xge_hal_fifo_dtr_private(dtrh)); 12291256Syl150051 mblk_t *mp = txd_priv->mblk; 12301256Syl150051 int i; 12313115Syl150051 12321256Syl150051 /* 12331256Syl150051 * for Tx we must clean up the DTR *only* if it has been 12341256Syl150051 * posted! 12351256Syl150051 */ 12361256Syl150051 if (state != XGE_HAL_DTR_STATE_POSTED) { 12371256Syl150051 return; 12381256Syl150051 } 12391256Syl150051 12401256Syl150051 for (i = 0; i < txd_priv->handle_cnt; i++) { 12411256Syl150051 xge_assert(txd_priv->dma_handles[i]); 12421256Syl150051 (void) ddi_dma_unbind_handle(txd_priv->dma_handles[i]); 12431256Syl150051 ddi_dma_free_handle(&txd_priv->dma_handles[i]); 12441256Syl150051 txd_priv->dma_handles[i] = 0; 12451256Syl150051 } 12461256Syl150051 12471256Syl150051 xge_hal_fifo_dtr_free(channelh, dtrh); 12481256Syl150051 1249*6937Sxw161283 if (mp) { 1250*6937Sxw161283 txd_priv->mblk = NULL; 1251*6937Sxw161283 freemsg(mp); 1252*6937Sxw161283 } 1253*6937Sxw161283 } 1254*6937Sxw161283 1255*6937Sxw161283 /* 1256*6937Sxw161283 * xgell_tx_close 1257*6937Sxw161283 * @lldev: the link layer object 1258*6937Sxw161283 * 1259*6937Sxw161283 * Close all Tx channels 1260*6937Sxw161283 */ 1261*6937Sxw161283 static void 1262*6937Sxw161283 xgell_tx_close(xgelldev_t *lldev) 1263*6937Sxw161283 { 1264*6937Sxw161283 xge_list_t *item, *list; 1265*6937Sxw161283 xge_hal_device_t *hldev = (xge_hal_device_t *)lldev->devh; 1266*6937Sxw161283 1267*6937Sxw161283 list = &hldev->fifo_channels; 1268*6937Sxw161283 while (!xge_list_is_empty(list)) { 1269*6937Sxw161283 item = xge_list_first_get(list); 1270*6937Sxw161283 xge_hal_channel_t *channel = xge_container_of(item, 1271*6937Sxw161283 xge_hal_channel_t, item); 1272*6937Sxw161283 1273*6937Sxw161283 xge_hal_channel_close(channel, XGE_HAL_CHANNEL_OC_NORMAL); 1274*6937Sxw161283 } 12751256Syl150051 } 12761256Syl150051 12771256Syl150051 /* 12781256Syl150051 * xgell_tx_open 12791256Syl150051 * @lldev: the link layer object 12801256Syl150051 * 12811256Syl150051 * Initialize and open all Tx channels; 12821256Syl150051 */ 12831256Syl150051 static boolean_t 12841256Syl150051 xgell_tx_open(xgelldev_t *lldev) 12851256Syl150051 { 12861256Syl150051 xge_hal_status_e status; 12871256Syl150051 u64 adapter_status; 12881256Syl150051 xge_hal_channel_attr_t attr; 1289*6937Sxw161283 xge_list_t *item; 1290*6937Sxw161283 xge_hal_device_t *hldev = (xge_hal_device_t *)lldev->devh; 12911256Syl150051 12921256Syl150051 attr.post_qid = 0; 12931256Syl150051 attr.compl_qid = 0; 12941256Syl150051 attr.callback = xgell_xmit_compl; 12951256Syl150051 attr.per_dtr_space = sizeof (xgell_txd_priv_t); 12961256Syl150051 attr.flags = 0; 12971256Syl150051 attr.type = XGE_HAL_CHANNEL_TYPE_FIFO; 12981256Syl150051 attr.userdata = lldev; 12991256Syl150051 attr.dtr_init = NULL; 13001256Syl150051 attr.dtr_term = xgell_tx_term; 13011256Syl150051 13021256Syl150051 if (xge_hal_device_status(lldev->devh, &adapter_status)) { 13031256Syl150051 xge_debug_ll(XGE_ERR, "%s%d: device is not ready " 13041256Syl150051 "adaper status reads 0x%"PRIx64, XGELL_IFNAME, 13051256Syl150051 lldev->instance, (uint64_t)adapter_status); 13061256Syl150051 return (B_FALSE); 13071256Syl150051 } 13081256Syl150051 1309*6937Sxw161283 /* 1310*6937Sxw161283 * Open only configured channels. HAL structures are static, 1311*6937Sxw161283 * so, no worries here.. 1312*6937Sxw161283 */ 1313*6937Sxw161283 _next_channel: 1314*6937Sxw161283 xge_list_for_each(item, &hldev->free_channels) { 1315*6937Sxw161283 xge_hal_channel_t *channel = xge_container_of(item, 1316*6937Sxw161283 xge_hal_channel_t, item); 1317*6937Sxw161283 xgell_fifo_t *fifo; 1318*6937Sxw161283 1319*6937Sxw161283 /* filter on FIFO channels */ 1320*6937Sxw161283 if (channel->type != XGE_HAL_CHANNEL_TYPE_FIFO) 1321*6937Sxw161283 continue; 1322*6937Sxw161283 1323*6937Sxw161283 fifo = &lldev->fifos[attr.post_qid]; 1324*6937Sxw161283 fifo->lldev = lldev; 1325*6937Sxw161283 attr.userdata = fifo; 1326*6937Sxw161283 1327*6937Sxw161283 status = xge_hal_channel_open(lldev->devh, &attr, 1328*6937Sxw161283 &fifo->channelh, XGE_HAL_CHANNEL_OC_NORMAL); 1329*6937Sxw161283 if (status != XGE_HAL_OK) { 1330*6937Sxw161283 xge_debug_ll(XGE_ERR, "%s%d: cannot open Tx channel " 1331*6937Sxw161283 "got status code %d", XGELL_IFNAME, 1332*6937Sxw161283 lldev->instance, status); 1333*6937Sxw161283 /* unwind */ 1334*6937Sxw161283 xgell_tx_close(lldev); 1335*6937Sxw161283 return (B_FALSE); 1336*6937Sxw161283 } 1337*6937Sxw161283 1338*6937Sxw161283 attr.post_qid++; 1339*6937Sxw161283 1340*6937Sxw161283 /* 1341*6937Sxw161283 * because channel_open() moves xge_list entry 1342*6937Sxw161283 * to the fifos_channels 1343*6937Sxw161283 */ 1344*6937Sxw161283 goto _next_channel; 13451256Syl150051 } 13461256Syl150051 13471256Syl150051 return (B_TRUE); 13481256Syl150051 } 13491256Syl150051 13501256Syl150051 /* 1351*6937Sxw161283 * xgell_rx_close 1352*6937Sxw161283 * @lldev: the link layer object 1353*6937Sxw161283 * 1354*6937Sxw161283 * Close all Rx channels 1355*6937Sxw161283 */ 1356*6937Sxw161283 static void 1357*6937Sxw161283 xgell_rx_close(xgelldev_t *lldev) 1358*6937Sxw161283 { 1359*6937Sxw161283 xge_list_t *item, *list; 1360*6937Sxw161283 xge_hal_device_t *hldev = (xge_hal_device_t *)lldev->devh; 1361*6937Sxw161283 1362*6937Sxw161283 list = &hldev->ring_channels; 1363*6937Sxw161283 while (!xge_list_is_empty(list)) { 1364*6937Sxw161283 item = xge_list_first_get(list); 1365*6937Sxw161283 xge_hal_channel_t *channel = xge_container_of(item, 1366*6937Sxw161283 xge_hal_channel_t, item); 1367*6937Sxw161283 xgell_ring_t *ring = xge_hal_channel_userdata(channel); 1368*6937Sxw161283 1369*6937Sxw161283 xge_hal_channel_close(channel, XGE_HAL_CHANNEL_OC_NORMAL); 1370*6937Sxw161283 1371*6937Sxw161283 /* 1372*6937Sxw161283 * destroy Ring's buffer pool 1373*6937Sxw161283 */ 1374*6937Sxw161283 if (xgell_rx_destroy_buffer_pool(ring) != DDI_SUCCESS) { 1375*6937Sxw161283 xge_debug_ll(XGE_ERR, "unable to destroy Ring%d " 1376*6937Sxw161283 "buffer pool", channel->post_qid); 1377*6937Sxw161283 } 1378*6937Sxw161283 list = &hldev->ring_channels; 1379*6937Sxw161283 } 1380*6937Sxw161283 } 1381*6937Sxw161283 1382*6937Sxw161283 /* 13831256Syl150051 * xgell_rx_open 13841256Syl150051 * @lldev: the link layer object 13851256Syl150051 * 13861256Syl150051 * Initialize and open all Rx channels; 13871256Syl150051 */ 13881256Syl150051 static boolean_t 13891256Syl150051 xgell_rx_open(xgelldev_t *lldev) 13901256Syl150051 { 13911256Syl150051 xge_hal_status_e status; 13921256Syl150051 u64 adapter_status; 13931256Syl150051 xge_hal_channel_attr_t attr; 1394*6937Sxw161283 xge_list_t *item; 1395*6937Sxw161283 xge_hal_device_t *hldev = (xge_hal_device_t *)lldev->devh; 13961256Syl150051 1397*6937Sxw161283 attr.post_qid = 0; 13981256Syl150051 attr.compl_qid = 0; 13991256Syl150051 attr.callback = xgell_rx_1b_compl; 14001256Syl150051 attr.per_dtr_space = sizeof (xgell_rxd_priv_t); 14011256Syl150051 attr.flags = 0; 14021256Syl150051 attr.type = XGE_HAL_CHANNEL_TYPE_RING; 14031256Syl150051 attr.dtr_init = xgell_rx_dtr_replenish; 14041256Syl150051 attr.dtr_term = xgell_rx_dtr_term; 14051256Syl150051 14061256Syl150051 if (xge_hal_device_status(lldev->devh, &adapter_status)) { 14071256Syl150051 xge_debug_ll(XGE_ERR, 14081256Syl150051 "%s%d: device is not ready adaper status reads 0x%"PRIx64, 14091256Syl150051 XGELL_IFNAME, lldev->instance, 14101256Syl150051 (uint64_t)adapter_status); 14111256Syl150051 return (B_FALSE); 14121256Syl150051 } 14131256Syl150051 1414*6937Sxw161283 /* 1415*6937Sxw161283 * Open only configured channels. HAL structures are static, 1416*6937Sxw161283 * so, no worries here.. 1417*6937Sxw161283 */ 1418*6937Sxw161283 _next_channel: 1419*6937Sxw161283 xge_list_for_each(item, &hldev->free_channels) { 1420*6937Sxw161283 xge_hal_channel_t *channel = xge_container_of(item, 1421*6937Sxw161283 xge_hal_channel_t, item); 1422*6937Sxw161283 xgell_ring_t *ring; 1423*6937Sxw161283 1424*6937Sxw161283 /* filter on RING channels */ 1425*6937Sxw161283 if (channel->type != XGE_HAL_CHANNEL_TYPE_RING) 1426*6937Sxw161283 continue; 1427*6937Sxw161283 1428*6937Sxw161283 ring = &lldev->rings[attr.post_qid]; 1429*6937Sxw161283 ring->lldev = lldev; 1430*6937Sxw161283 attr.userdata = ring; 14311256Syl150051 1432*6937Sxw161283 if (xgell_rx_create_buffer_pool(ring) != DDI_SUCCESS) { 1433*6937Sxw161283 xge_debug_ll(XGE_ERR, "unable to create Ring%d " 1434*6937Sxw161283 "buffer pool", attr.post_qid); 1435*6937Sxw161283 /* unwind */ 1436*6937Sxw161283 xgell_rx_close(lldev); 1437*6937Sxw161283 return (B_FALSE); 1438*6937Sxw161283 } 1439*6937Sxw161283 1440*6937Sxw161283 status = xge_hal_channel_open(lldev->devh, &attr, 1441*6937Sxw161283 &ring->channelh, XGE_HAL_CHANNEL_OC_NORMAL); 1442*6937Sxw161283 if (status != XGE_HAL_OK) { 1443*6937Sxw161283 xge_debug_ll(XGE_ERR, "%s%d: cannot open Rx channel " 1444*6937Sxw161283 "got status got status code %d", XGELL_IFNAME, 1445*6937Sxw161283 lldev->instance, status); 1446*6937Sxw161283 /* unwind */ 1447*6937Sxw161283 (void) xgell_rx_destroy_buffer_pool(ring); 1448*6937Sxw161283 xgell_rx_close(lldev); 1449*6937Sxw161283 return (B_FALSE); 1450*6937Sxw161283 } 1451*6937Sxw161283 1452*6937Sxw161283 attr.post_qid++; 1453*6937Sxw161283 1454*6937Sxw161283 /* 1455*6937Sxw161283 * because chhannel_open() moves xge_list entry 1456*6937Sxw161283 * to the rings channels 1457*6937Sxw161283 */ 1458*6937Sxw161283 goto _next_channel; 14591256Syl150051 } 14601256Syl150051 14611256Syl150051 return (B_TRUE); 14621256Syl150051 } 14631256Syl150051 14641256Syl150051 static int 14651256Syl150051 xgell_initiate_start(xgelldev_t *lldev) 14661256Syl150051 { 14671256Syl150051 xge_hal_status_e status; 14681256Syl150051 xge_hal_device_t *hldev = lldev->devh; 14692311Sseb int maxpkt = hldev->config.mtu; 14701256Syl150051 14711256Syl150051 /* check initial mtu before enabling the device */ 14721256Syl150051 status = xge_hal_device_mtu_check(lldev->devh, maxpkt); 14731256Syl150051 if (status != XGE_HAL_OK) { 14741256Syl150051 xge_debug_ll(XGE_ERR, "%s%d: MTU size %d is invalid", 14751256Syl150051 XGELL_IFNAME, lldev->instance, maxpkt); 14761256Syl150051 return (EINVAL); 14771256Syl150051 } 14781256Syl150051 14791256Syl150051 /* set initial mtu before enabling the device */ 14801256Syl150051 status = xge_hal_device_mtu_set(lldev->devh, maxpkt); 14811256Syl150051 if (status != XGE_HAL_OK) { 14821256Syl150051 xge_debug_ll(XGE_ERR, "%s%d: can not set new MTU %d", 14831256Syl150051 XGELL_IFNAME, lldev->instance, maxpkt); 14841256Syl150051 return (EIO); 14851256Syl150051 } 14861256Syl150051 14873115Syl150051 /* tune jumbo/normal frame UFC counters */ 14883115Syl150051 hldev->config.ring.queue[XGELL_RING_MAIN_QID].rti.ufc_b = \ 1489*6937Sxw161283 maxpkt > XGE_HAL_DEFAULT_MTU ? 1490*6937Sxw161283 XGE_HAL_DEFAULT_RX_UFC_B_J : 1491*6937Sxw161283 XGE_HAL_DEFAULT_RX_UFC_B_N; 14923115Syl150051 14933115Syl150051 hldev->config.ring.queue[XGELL_RING_MAIN_QID].rti.ufc_c = \ 1494*6937Sxw161283 maxpkt > XGE_HAL_DEFAULT_MTU ? 1495*6937Sxw161283 XGE_HAL_DEFAULT_RX_UFC_C_J : 1496*6937Sxw161283 XGE_HAL_DEFAULT_RX_UFC_C_N; 14973115Syl150051 14981256Syl150051 /* now, enable the device */ 14991256Syl150051 status = xge_hal_device_enable(lldev->devh); 15001256Syl150051 if (status != XGE_HAL_OK) { 15011256Syl150051 xge_debug_ll(XGE_ERR, "%s%d: can not enable the device", 15021256Syl150051 XGELL_IFNAME, lldev->instance); 15031256Syl150051 return (EIO); 15041256Syl150051 } 15051256Syl150051 15061256Syl150051 if (!xgell_rx_open(lldev)) { 15071256Syl150051 status = xge_hal_device_disable(lldev->devh); 15081256Syl150051 if (status != XGE_HAL_OK) { 15091256Syl150051 u64 adapter_status; 15101256Syl150051 (void) xge_hal_device_status(lldev->devh, 15111256Syl150051 &adapter_status); 15121256Syl150051 xge_debug_ll(XGE_ERR, "%s%d: can not safely disable " 15131256Syl150051 "the device. adaper status 0x%"PRIx64 15141256Syl150051 " returned status %d", 15151256Syl150051 XGELL_IFNAME, lldev->instance, 15161256Syl150051 (uint64_t)adapter_status, status); 15171256Syl150051 } 15181256Syl150051 xge_os_mdelay(1500); 15191256Syl150051 return (ENOMEM); 15201256Syl150051 } 15211256Syl150051 15221256Syl150051 if (!xgell_tx_open(lldev)) { 15231256Syl150051 status = xge_hal_device_disable(lldev->devh); 15241256Syl150051 if (status != XGE_HAL_OK) { 15251256Syl150051 u64 adapter_status; 15261256Syl150051 (void) xge_hal_device_status(lldev->devh, 15271256Syl150051 &adapter_status); 15281256Syl150051 xge_debug_ll(XGE_ERR, "%s%d: can not safely disable " 15291256Syl150051 "the device. adaper status 0x%"PRIx64 15301256Syl150051 " returned status %d", 15311256Syl150051 XGELL_IFNAME, lldev->instance, 15321256Syl150051 (uint64_t)adapter_status, status); 15331256Syl150051 } 15341256Syl150051 xge_os_mdelay(1500); 1535*6937Sxw161283 xgell_rx_close(lldev); 1536*6937Sxw161283 15371256Syl150051 return (ENOMEM); 15381256Syl150051 } 15391256Syl150051 15401256Syl150051 /* time to enable interrupts */ 1541*6937Sxw161283 (void) xge_enable_intrs(lldev); 15421256Syl150051 xge_hal_device_intr_enable(lldev->devh); 15431256Syl150051 15441256Syl150051 lldev->is_initialized = 1; 15451256Syl150051 15461256Syl150051 return (0); 15471256Syl150051 } 15481256Syl150051 15491256Syl150051 static void 15501256Syl150051 xgell_initiate_stop(xgelldev_t *lldev) 15511256Syl150051 { 15521256Syl150051 xge_hal_status_e status; 15531256Syl150051 15541256Syl150051 lldev->is_initialized = 0; 15551256Syl150051 15561256Syl150051 status = xge_hal_device_disable(lldev->devh); 15571256Syl150051 if (status != XGE_HAL_OK) { 15581256Syl150051 u64 adapter_status; 15591256Syl150051 (void) xge_hal_device_status(lldev->devh, &adapter_status); 15601256Syl150051 xge_debug_ll(XGE_ERR, "%s%d: can not safely disable " 15611256Syl150051 "the device. adaper status 0x%"PRIx64" returned status %d", 15621256Syl150051 XGELL_IFNAME, lldev->instance, 15631256Syl150051 (uint64_t)adapter_status, status); 15641256Syl150051 } 15651256Syl150051 xge_hal_device_intr_disable(lldev->devh); 1566*6937Sxw161283 /* disable OS ISR's */ 1567*6937Sxw161283 xge_disable_intrs(lldev); 15681256Syl150051 15691256Syl150051 xge_debug_ll(XGE_TRACE, "%s", 15701256Syl150051 "waiting for device irq to become quiescent..."); 15711256Syl150051 xge_os_mdelay(1500); 15721256Syl150051 15731256Syl150051 xge_queue_flush(xge_hal_device_queue(lldev->devh)); 15741256Syl150051 1575*6937Sxw161283 xgell_rx_close(lldev); 1576*6937Sxw161283 xgell_tx_close(lldev); 15771256Syl150051 } 15781256Syl150051 15791256Syl150051 /* 15801256Syl150051 * xgell_m_start 15811256Syl150051 * @arg: pointer to device private strucutre(hldev) 15821256Syl150051 * 15831256Syl150051 * This function is called by MAC Layer to enable the XFRAME 15841256Syl150051 * firmware to generate interrupts and also prepare the 15851256Syl150051 * driver to call mac_rx for delivering receive packets 15861256Syl150051 * to MAC Layer. 15871256Syl150051 */ 15881256Syl150051 static int 15891256Syl150051 xgell_m_start(void *arg) 15901256Syl150051 { 15913115Syl150051 xgelldev_t *lldev = arg; 15923115Syl150051 xge_hal_device_t *hldev = lldev->devh; 15931256Syl150051 int ret; 15941256Syl150051 15951256Syl150051 xge_debug_ll(XGE_TRACE, "%s%d: M_START", XGELL_IFNAME, 15961256Syl150051 lldev->instance); 15971256Syl150051 15981256Syl150051 mutex_enter(&lldev->genlock); 15991256Syl150051 16001256Syl150051 if (lldev->is_initialized) { 16011256Syl150051 xge_debug_ll(XGE_ERR, "%s%d: device is already initialized", 16021256Syl150051 XGELL_IFNAME, lldev->instance); 16031256Syl150051 mutex_exit(&lldev->genlock); 16041256Syl150051 return (EINVAL); 16051256Syl150051 } 16061256Syl150051 16071256Syl150051 hldev->terminating = 0; 16081256Syl150051 if (ret = xgell_initiate_start(lldev)) { 16091256Syl150051 mutex_exit(&lldev->genlock); 16101256Syl150051 return (ret); 16111256Syl150051 } 16121256Syl150051 16131256Syl150051 lldev->timeout_id = timeout(xge_device_poll, hldev, XGE_DEV_POLL_TICKS); 16141256Syl150051 16151256Syl150051 mutex_exit(&lldev->genlock); 16161256Syl150051 16171256Syl150051 return (0); 16181256Syl150051 } 16191256Syl150051 16201256Syl150051 /* 16211256Syl150051 * xgell_m_stop 16221256Syl150051 * @arg: pointer to device private data (hldev) 16231256Syl150051 * 16241256Syl150051 * This function is called by the MAC Layer to disable 16251256Syl150051 * the XFRAME firmware for generating any interrupts and 16261256Syl150051 * also stop the driver from calling mac_rx() for 16271256Syl150051 * delivering data packets to the MAC Layer. 16281256Syl150051 */ 16291256Syl150051 static void 16301256Syl150051 xgell_m_stop(void *arg) 16311256Syl150051 { 16323115Syl150051 xgelldev_t *lldev = arg; 16333115Syl150051 xge_hal_device_t *hldev = lldev->devh; 16341256Syl150051 16351256Syl150051 xge_debug_ll(XGE_TRACE, "%s", "MAC_STOP"); 16361256Syl150051 16371256Syl150051 mutex_enter(&lldev->genlock); 16381256Syl150051 if (!lldev->is_initialized) { 16391256Syl150051 xge_debug_ll(XGE_ERR, "%s", "device is not initialized..."); 16401256Syl150051 mutex_exit(&lldev->genlock); 16411256Syl150051 return; 16421256Syl150051 } 16431256Syl150051 16441256Syl150051 xge_hal_device_terminating(hldev); 16451256Syl150051 xgell_initiate_stop(lldev); 16461256Syl150051 16471256Syl150051 /* reset device */ 16481256Syl150051 (void) xge_hal_device_reset(lldev->devh); 16491256Syl150051 16501256Syl150051 mutex_exit(&lldev->genlock); 16511256Syl150051 16523115Syl150051 if (lldev->timeout_id != 0) { 16533115Syl150051 (void) untimeout(lldev->timeout_id); 16543115Syl150051 } 16551256Syl150051 16561256Syl150051 xge_debug_ll(XGE_TRACE, "%s", "returning back to MAC Layer..."); 16571256Syl150051 } 16581256Syl150051 16591256Syl150051 /* 16601256Syl150051 * xgell_onerr_reset 16611256Syl150051 * @lldev: pointer to xgelldev_t structure 16621256Syl150051 * 16631256Syl150051 * This function is called by HAL Event framework to reset the HW 16641256Syl150051 * This function is must be called with genlock taken. 16651256Syl150051 */ 16661256Syl150051 int 16671256Syl150051 xgell_onerr_reset(xgelldev_t *lldev) 16681256Syl150051 { 16691256Syl150051 int rc = 0; 16701256Syl150051 16711256Syl150051 if (!lldev->is_initialized) { 16721256Syl150051 xge_debug_ll(XGE_ERR, "%s%d: can not reset", 16731256Syl150051 XGELL_IFNAME, lldev->instance); 16741256Syl150051 return (rc); 16751256Syl150051 } 16761256Syl150051 16771256Syl150051 lldev->in_reset = 1; 16781256Syl150051 xgell_initiate_stop(lldev); 16791256Syl150051 16801256Syl150051 /* reset device */ 16811256Syl150051 (void) xge_hal_device_reset(lldev->devh); 16821256Syl150051 16831256Syl150051 rc = xgell_initiate_start(lldev); 16841256Syl150051 lldev->in_reset = 0; 16851256Syl150051 16861256Syl150051 return (rc); 16871256Syl150051 } 16881256Syl150051 16891256Syl150051 16901256Syl150051 /* 16911256Syl150051 * xgell_m_unicst 16921256Syl150051 * @arg: pointer to device private strucutre(hldev) 16931256Syl150051 * @mac_addr: 16941256Syl150051 * 16951256Syl150051 * This function is called by MAC Layer to set the physical address 16961256Syl150051 * of the XFRAME firmware. 16971256Syl150051 */ 16981256Syl150051 static int 16991256Syl150051 xgell_m_unicst(void *arg, const uint8_t *macaddr) 17001256Syl150051 { 17011256Syl150051 xge_hal_status_e status; 17023115Syl150051 xgelldev_t *lldev = (xgelldev_t *)arg; 17033115Syl150051 xge_hal_device_t *hldev = lldev->devh; 17041256Syl150051 xge_debug_ll(XGE_TRACE, "%s", "MAC_UNICST"); 17051256Syl150051 17061256Syl150051 xge_debug_ll(XGE_TRACE, "%s", "M_UNICAST"); 17071256Syl150051 17081256Syl150051 mutex_enter(&lldev->genlock); 17091256Syl150051 17101256Syl150051 xge_debug_ll(XGE_TRACE, 17111256Syl150051 "setting macaddr: 0x%02x-%02x-%02x-%02x-%02x-%02x", 17121256Syl150051 macaddr[0], macaddr[1], macaddr[2], 17131256Syl150051 macaddr[3], macaddr[4], macaddr[5]); 17141256Syl150051 17151256Syl150051 status = xge_hal_device_macaddr_set(hldev, 0, (uchar_t *)macaddr); 17161256Syl150051 if (status != XGE_HAL_OK) { 17171256Syl150051 xge_debug_ll(XGE_ERR, "%s%d: can not set mac address", 17181256Syl150051 XGELL_IFNAME, lldev->instance); 17191256Syl150051 mutex_exit(&lldev->genlock); 17201256Syl150051 return (EIO); 17211256Syl150051 } 17221256Syl150051 17231256Syl150051 mutex_exit(&lldev->genlock); 17241256Syl150051 17251256Syl150051 return (0); 17261256Syl150051 } 17271256Syl150051 17281256Syl150051 17291256Syl150051 /* 17301256Syl150051 * xgell_m_multicst 17311256Syl150051 * @arg: pointer to device private strucutre(hldev) 17321256Syl150051 * @add: 17331256Syl150051 * @mc_addr: 17341256Syl150051 * 17351256Syl150051 * This function is called by MAC Layer to enable or 17361256Syl150051 * disable device-level reception of specific multicast addresses. 17371256Syl150051 */ 17381256Syl150051 static int 17391256Syl150051 xgell_m_multicst(void *arg, boolean_t add, const uint8_t *mc_addr) 17401256Syl150051 { 17411256Syl150051 xge_hal_status_e status; 17423115Syl150051 xgelldev_t *lldev = (xgelldev_t *)arg; 17433115Syl150051 xge_hal_device_t *hldev = lldev->devh; 17441256Syl150051 17451256Syl150051 xge_debug_ll(XGE_TRACE, "M_MULTICAST add %d", add); 17461256Syl150051 17471256Syl150051 mutex_enter(&lldev->genlock); 17481256Syl150051 17491256Syl150051 if (!lldev->is_initialized) { 17501256Syl150051 xge_debug_ll(XGE_ERR, "%s%d: can not set multicast", 17511256Syl150051 XGELL_IFNAME, lldev->instance); 17521256Syl150051 mutex_exit(&lldev->genlock); 17531256Syl150051 return (EIO); 17541256Syl150051 } 17551256Syl150051 17561256Syl150051 /* FIXME: missing HAL functionality: enable_one() */ 17571256Syl150051 17581256Syl150051 status = (add) ? 17591256Syl150051 xge_hal_device_mcast_enable(hldev) : 17601256Syl150051 xge_hal_device_mcast_disable(hldev); 17611256Syl150051 17621256Syl150051 if (status != XGE_HAL_OK) { 17631256Syl150051 xge_debug_ll(XGE_ERR, "failed to %s multicast, status %d", 17641256Syl150051 add ? "enable" : "disable", status); 17651256Syl150051 mutex_exit(&lldev->genlock); 17661256Syl150051 return (EIO); 17671256Syl150051 } 17681256Syl150051 17691256Syl150051 mutex_exit(&lldev->genlock); 17701256Syl150051 17711256Syl150051 return (0); 17721256Syl150051 } 17731256Syl150051 17741256Syl150051 17751256Syl150051 /* 17761256Syl150051 * xgell_m_promisc 17771256Syl150051 * @arg: pointer to device private strucutre(hldev) 17781256Syl150051 * @on: 17791256Syl150051 * 17801256Syl150051 * This function is called by MAC Layer to enable or 17811256Syl150051 * disable the reception of all the packets on the medium 17821256Syl150051 */ 17831256Syl150051 static int 17841256Syl150051 xgell_m_promisc(void *arg, boolean_t on) 17851256Syl150051 { 17863115Syl150051 xgelldev_t *lldev = (xgelldev_t *)arg; 17873115Syl150051 xge_hal_device_t *hldev = lldev->devh; 17881256Syl150051 17891256Syl150051 mutex_enter(&lldev->genlock); 17901256Syl150051 17911256Syl150051 xge_debug_ll(XGE_TRACE, "%s", "MAC_PROMISC_SET"); 17921256Syl150051 17931256Syl150051 if (!lldev->is_initialized) { 17941256Syl150051 xge_debug_ll(XGE_ERR, "%s%d: can not set promiscuous", 17951256Syl150051 XGELL_IFNAME, lldev->instance); 17961256Syl150051 mutex_exit(&lldev->genlock); 17971256Syl150051 return (EIO); 17981256Syl150051 } 17991256Syl150051 18001256Syl150051 if (on) { 18011256Syl150051 xge_hal_device_promisc_enable(hldev); 18021256Syl150051 } else { 18031256Syl150051 xge_hal_device_promisc_disable(hldev); 18041256Syl150051 } 18051256Syl150051 18061256Syl150051 mutex_exit(&lldev->genlock); 18071256Syl150051 18081256Syl150051 return (0); 18091256Syl150051 } 18101256Syl150051 18111256Syl150051 /* 18122311Sseb * xgell_m_stat 18131256Syl150051 * @arg: pointer to device private strucutre(hldev) 18141256Syl150051 * 18152311Sseb * This function is called by MAC Layer to get network statistics 18161256Syl150051 * from the driver. 18171256Syl150051 */ 18182311Sseb static int 18192311Sseb xgell_m_stat(void *arg, uint_t stat, uint64_t *val) 18201256Syl150051 { 18211256Syl150051 xge_hal_stats_hw_info_t *hw_info; 18223115Syl150051 xgelldev_t *lldev = (xgelldev_t *)arg; 18233115Syl150051 xge_hal_device_t *hldev = lldev->devh; 18241256Syl150051 18251256Syl150051 xge_debug_ll(XGE_TRACE, "%s", "MAC_STATS_GET"); 18261256Syl150051 1827*6937Sxw161283 mutex_enter(&lldev->genlock); 18281256Syl150051 18291256Syl150051 if (!lldev->is_initialized) { 18301256Syl150051 mutex_exit(&lldev->genlock); 18312311Sseb return (EAGAIN); 18321256Syl150051 } 18331256Syl150051 18341256Syl150051 if (xge_hal_stats_hw(hldev, &hw_info) != XGE_HAL_OK) { 18351256Syl150051 mutex_exit(&lldev->genlock); 18362311Sseb return (EAGAIN); 18371256Syl150051 } 18381256Syl150051 18391256Syl150051 switch (stat) { 18401256Syl150051 case MAC_STAT_IFSPEED: 18412311Sseb *val = 10000000000ull; /* 10G */ 18421256Syl150051 break; 18431256Syl150051 18441256Syl150051 case MAC_STAT_MULTIRCV: 18453115Syl150051 *val = ((u64) hw_info->rmac_vld_mcst_frms_oflow << 32) | 18463115Syl150051 hw_info->rmac_vld_mcst_frms; 18471256Syl150051 break; 18481256Syl150051 18491256Syl150051 case MAC_STAT_BRDCSTRCV: 18503115Syl150051 *val = ((u64) hw_info->rmac_vld_bcst_frms_oflow << 32) | 18513115Syl150051 hw_info->rmac_vld_bcst_frms; 18521256Syl150051 break; 18531256Syl150051 18541256Syl150051 case MAC_STAT_MULTIXMT: 18553115Syl150051 *val = ((u64) hw_info->tmac_mcst_frms_oflow << 32) | 18563115Syl150051 hw_info->tmac_mcst_frms; 18571256Syl150051 break; 18581256Syl150051 18591256Syl150051 case MAC_STAT_BRDCSTXMT: 18603115Syl150051 *val = ((u64) hw_info->tmac_bcst_frms_oflow << 32) | 18613115Syl150051 hw_info->tmac_bcst_frms; 18621256Syl150051 break; 18631256Syl150051 18641256Syl150051 case MAC_STAT_RBYTES: 18653115Syl150051 *val = ((u64) hw_info->rmac_ttl_octets_oflow << 32) | 18663115Syl150051 hw_info->rmac_ttl_octets; 18671256Syl150051 break; 18681256Syl150051 18691256Syl150051 case MAC_STAT_NORCVBUF: 18702311Sseb *val = hw_info->rmac_drop_frms; 18711256Syl150051 break; 18721256Syl150051 18731256Syl150051 case MAC_STAT_IERRORS: 18743115Syl150051 *val = ((u64) hw_info->rmac_discarded_frms_oflow << 32) | 18753115Syl150051 hw_info->rmac_discarded_frms; 18761256Syl150051 break; 18771256Syl150051 18781256Syl150051 case MAC_STAT_OBYTES: 18793115Syl150051 *val = ((u64) hw_info->tmac_ttl_octets_oflow << 32) | 18803115Syl150051 hw_info->tmac_ttl_octets; 18811256Syl150051 break; 18821256Syl150051 18831256Syl150051 case MAC_STAT_NOXMTBUF: 18842311Sseb *val = hw_info->tmac_drop_frms; 18851256Syl150051 break; 18861256Syl150051 18871256Syl150051 case MAC_STAT_OERRORS: 18883115Syl150051 *val = ((u64) hw_info->tmac_any_err_frms_oflow << 32) | 18893115Syl150051 hw_info->tmac_any_err_frms; 18901256Syl150051 break; 18911256Syl150051 18921256Syl150051 case MAC_STAT_IPACKETS: 18933115Syl150051 *val = ((u64) hw_info->rmac_vld_frms_oflow << 32) | 18943115Syl150051 hw_info->rmac_vld_frms; 18951256Syl150051 break; 18961256Syl150051 18971256Syl150051 case MAC_STAT_OPACKETS: 18983115Syl150051 *val = ((u64) hw_info->tmac_frms_oflow << 32) | 18993115Syl150051 hw_info->tmac_frms; 19002311Sseb break; 19012311Sseb 19022311Sseb case ETHER_STAT_FCS_ERRORS: 19032311Sseb *val = hw_info->rmac_fcs_err_frms; 19041256Syl150051 break; 19051256Syl150051 19062311Sseb case ETHER_STAT_TOOLONG_ERRORS: 19072311Sseb *val = hw_info->rmac_long_frms; 19081256Syl150051 break; 19091256Syl150051 19102311Sseb case ETHER_STAT_LINK_DUPLEX: 19112311Sseb *val = LINK_DUPLEX_FULL; 19121256Syl150051 break; 19131256Syl150051 19141256Syl150051 default: 19152311Sseb mutex_exit(&lldev->genlock); 19162311Sseb return (ENOTSUP); 19171256Syl150051 } 19181256Syl150051 19191256Syl150051 mutex_exit(&lldev->genlock); 19201256Syl150051 19212311Sseb return (0); 19221256Syl150051 } 19231256Syl150051 19241256Syl150051 /* 19251256Syl150051 * xgell_device_alloc - Allocate new LL device 19261256Syl150051 */ 19271256Syl150051 int 19281256Syl150051 xgell_device_alloc(xge_hal_device_h devh, 19291256Syl150051 dev_info_t *dev_info, xgelldev_t **lldev_out) 19301256Syl150051 { 19311256Syl150051 xgelldev_t *lldev; 19321256Syl150051 xge_hal_device_t *hldev = (xge_hal_device_t *)devh; 19331256Syl150051 int instance = ddi_get_instance(dev_info); 19341256Syl150051 19351256Syl150051 *lldev_out = NULL; 19361256Syl150051 19371256Syl150051 xge_debug_ll(XGE_TRACE, "trying to register etherenet device %s%d...", 19381256Syl150051 XGELL_IFNAME, instance); 19391256Syl150051 19401256Syl150051 lldev = kmem_zalloc(sizeof (xgelldev_t), KM_SLEEP); 19411256Syl150051 19421256Syl150051 lldev->devh = hldev; 19431256Syl150051 lldev->instance = instance; 19441256Syl150051 lldev->dev_info = dev_info; 19451256Syl150051 19461256Syl150051 *lldev_out = lldev; 19471256Syl150051 19481256Syl150051 ddi_set_driver_private(dev_info, (caddr_t)hldev); 19491256Syl150051 19501256Syl150051 return (DDI_SUCCESS); 19511256Syl150051 } 19521256Syl150051 19531256Syl150051 /* 19541256Syl150051 * xgell_device_free 19551256Syl150051 */ 19561256Syl150051 void 19571256Syl150051 xgell_device_free(xgelldev_t *lldev) 19581256Syl150051 { 19591256Syl150051 xge_debug_ll(XGE_TRACE, "freeing device %s%d", 19601256Syl150051 XGELL_IFNAME, lldev->instance); 19611256Syl150051 19621256Syl150051 kmem_free(lldev, sizeof (xgelldev_t)); 19631256Syl150051 } 19641256Syl150051 19651256Syl150051 /* 19661256Syl150051 * xgell_ioctl 19671256Syl150051 */ 19681256Syl150051 static void 19691256Syl150051 xgell_m_ioctl(void *arg, queue_t *wq, mblk_t *mp) 19701256Syl150051 { 19713115Syl150051 xgelldev_t *lldev = arg; 19721256Syl150051 struct iocblk *iocp; 19731256Syl150051 int err = 0; 19741256Syl150051 int cmd; 19751256Syl150051 int need_privilege = 1; 19761256Syl150051 int ret = 0; 19771256Syl150051 19781256Syl150051 19791256Syl150051 iocp = (struct iocblk *)mp->b_rptr; 19801256Syl150051 iocp->ioc_error = 0; 19811256Syl150051 cmd = iocp->ioc_cmd; 19821256Syl150051 xge_debug_ll(XGE_TRACE, "MAC_IOCTL cmd 0x%x", cmd); 19831256Syl150051 switch (cmd) { 19841256Syl150051 case ND_GET: 19851256Syl150051 need_privilege = 0; 19861256Syl150051 /* FALLTHRU */ 19871256Syl150051 case ND_SET: 19881256Syl150051 break; 19891256Syl150051 default: 19901256Syl150051 xge_debug_ll(XGE_TRACE, "unknown cmd 0x%x", cmd); 19911256Syl150051 miocnak(wq, mp, 0, EINVAL); 19921256Syl150051 return; 19931256Syl150051 } 19941256Syl150051 19951256Syl150051 if (need_privilege) { 19961256Syl150051 err = secpolicy_net_config(iocp->ioc_cr, B_FALSE); 19971256Syl150051 if (err != 0) { 19981256Syl150051 xge_debug_ll(XGE_ERR, 19991256Syl150051 "drv_priv(): rejected cmd 0x%x, err %d", 20001256Syl150051 cmd, err); 20011256Syl150051 miocnak(wq, mp, 0, err); 20021256Syl150051 return; 20031256Syl150051 } 20041256Syl150051 } 20051256Syl150051 20061256Syl150051 switch (cmd) { 20071256Syl150051 case ND_GET: 20081256Syl150051 /* 20091256Syl150051 * If nd_getset() returns B_FALSE, the command was 20101256Syl150051 * not valid (e.g. unknown name), so we just tell the 20111256Syl150051 * top-level ioctl code to send a NAK (with code EINVAL). 20121256Syl150051 * 20131256Syl150051 * Otherwise, nd_getset() will have built the reply to 20141256Syl150051 * be sent (but not actually sent it), so we tell the 20151256Syl150051 * caller to send the prepared reply. 20161256Syl150051 */ 20171256Syl150051 ret = nd_getset(wq, lldev->ndp, mp); 2018*6937Sxw161283 xge_debug_ll(XGE_TRACE, "%s", "got ndd get ioctl"); 20191256Syl150051 break; 20201256Syl150051 20211256Syl150051 case ND_SET: 20221256Syl150051 ret = nd_getset(wq, lldev->ndp, mp); 2023*6937Sxw161283 xge_debug_ll(XGE_TRACE, "%s", "got ndd set ioctl"); 20241256Syl150051 break; 20251256Syl150051 20261256Syl150051 default: 20271256Syl150051 break; 20281256Syl150051 } 20291256Syl150051 20301256Syl150051 if (ret == B_FALSE) { 20311256Syl150051 xge_debug_ll(XGE_ERR, 20321256Syl150051 "nd_getset(): rejected cmd 0x%x, err %d", 20331256Syl150051 cmd, err); 20341256Syl150051 miocnak(wq, mp, 0, EINVAL); 20351256Syl150051 } else { 20361256Syl150051 mp->b_datap->db_type = iocp->ioc_error == 0 ? 20371256Syl150051 M_IOCACK : M_IOCNAK; 20381256Syl150051 qreply(wq, mp); 20391256Syl150051 } 20401256Syl150051 } 20411256Syl150051 20422311Sseb /* ARGSUSED */ 20432311Sseb static boolean_t 20442311Sseb xgell_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) 20451256Syl150051 { 20463115Syl150051 xgelldev_t *lldev = arg; 20473115Syl150051 20482311Sseb switch (cap) { 20492311Sseb case MAC_CAPAB_HCKSUM: { 20502311Sseb uint32_t *hcksum_txflags = cap_data; 20512311Sseb *hcksum_txflags = HCKSUM_INET_FULL_V4 | HCKSUM_INET_FULL_V6 | 20522311Sseb HCKSUM_IPHDRCKSUM; 20532311Sseb break; 20542311Sseb } 20553115Syl150051 case MAC_CAPAB_LSO: { 20563115Syl150051 mac_capab_lso_t *cap_lso = cap_data; 20573115Syl150051 20583115Syl150051 if (lldev->config.lso_enable) { 20593115Syl150051 cap_lso->lso_flags = LSO_TX_BASIC_TCP_IPV4; 20603115Syl150051 cap_lso->lso_basic_tcp_ipv4.lso_max = XGELL_LSO_MAXLEN; 20613115Syl150051 break; 20623115Syl150051 } else { 20633115Syl150051 return (B_FALSE); 20643115Syl150051 } 20653115Syl150051 } 20662311Sseb default: 20672311Sseb return (B_FALSE); 20682311Sseb } 20692311Sseb return (B_TRUE); 20701256Syl150051 } 20711256Syl150051 20721256Syl150051 static int 20731256Syl150051 xgell_stats_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp) 20741256Syl150051 { 20751256Syl150051 xgelldev_t *lldev = (xgelldev_t *)cp; 20761256Syl150051 xge_hal_status_e status; 20771256Syl150051 int count = 0, retsize; 20781256Syl150051 char *buf; 20791256Syl150051 20801256Syl150051 buf = kmem_alloc(XGELL_STATS_BUFSIZE, KM_SLEEP); 20811256Syl150051 if (buf == NULL) { 20821256Syl150051 return (ENOSPC); 20831256Syl150051 } 20841256Syl150051 20851256Syl150051 status = xge_hal_aux_stats_tmac_read(lldev->devh, XGELL_STATS_BUFSIZE, 20861256Syl150051 buf, &retsize); 20871256Syl150051 if (status != XGE_HAL_OK) { 20881256Syl150051 kmem_free(buf, XGELL_STATS_BUFSIZE); 20891256Syl150051 xge_debug_ll(XGE_ERR, "tmac_read(): status %d", status); 20901256Syl150051 return (EINVAL); 20911256Syl150051 } 20921256Syl150051 count += retsize; 20931256Syl150051 20941256Syl150051 status = xge_hal_aux_stats_rmac_read(lldev->devh, 20951256Syl150051 XGELL_STATS_BUFSIZE - count, 20961256Syl150051 buf+count, &retsize); 20971256Syl150051 if (status != XGE_HAL_OK) { 20981256Syl150051 kmem_free(buf, XGELL_STATS_BUFSIZE); 20991256Syl150051 xge_debug_ll(XGE_ERR, "rmac_read(): status %d", status); 21001256Syl150051 return (EINVAL); 21011256Syl150051 } 21021256Syl150051 count += retsize; 21031256Syl150051 21041256Syl150051 status = xge_hal_aux_stats_pci_read(lldev->devh, 21051256Syl150051 XGELL_STATS_BUFSIZE - count, buf + count, &retsize); 21061256Syl150051 if (status != XGE_HAL_OK) { 21071256Syl150051 kmem_free(buf, XGELL_STATS_BUFSIZE); 21081256Syl150051 xge_debug_ll(XGE_ERR, "pci_read(): status %d", status); 21091256Syl150051 return (EINVAL); 21101256Syl150051 } 21111256Syl150051 count += retsize; 21121256Syl150051 21131256Syl150051 status = xge_hal_aux_stats_sw_dev_read(lldev->devh, 21141256Syl150051 XGELL_STATS_BUFSIZE - count, buf + count, &retsize); 21151256Syl150051 if (status != XGE_HAL_OK) { 21161256Syl150051 kmem_free(buf, XGELL_STATS_BUFSIZE); 21171256Syl150051 xge_debug_ll(XGE_ERR, "sw_dev_read(): status %d", status); 21181256Syl150051 return (EINVAL); 21191256Syl150051 } 21201256Syl150051 count += retsize; 21211256Syl150051 21221256Syl150051 status = xge_hal_aux_stats_hal_read(lldev->devh, 21231256Syl150051 XGELL_STATS_BUFSIZE - count, buf + count, &retsize); 21241256Syl150051 if (status != XGE_HAL_OK) { 21251256Syl150051 kmem_free(buf, XGELL_STATS_BUFSIZE); 21261256Syl150051 xge_debug_ll(XGE_ERR, "pci_read(): status %d", status); 21271256Syl150051 return (EINVAL); 21281256Syl150051 } 21291256Syl150051 count += retsize; 21301256Syl150051 21311256Syl150051 *(buf + count - 1) = '\0'; /* remove last '\n' */ 21321256Syl150051 (void) mi_mpprintf(mp, "%s", buf); 21331256Syl150051 kmem_free(buf, XGELL_STATS_BUFSIZE); 21341256Syl150051 21351256Syl150051 return (0); 21361256Syl150051 } 21371256Syl150051 21381256Syl150051 static int 21391256Syl150051 xgell_pciconf_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp) 21401256Syl150051 { 21411256Syl150051 xgelldev_t *lldev = (xgelldev_t *)cp; 21421256Syl150051 xge_hal_status_e status; 21431256Syl150051 int retsize; 21441256Syl150051 char *buf; 21451256Syl150051 21461256Syl150051 buf = kmem_alloc(XGELL_PCICONF_BUFSIZE, KM_SLEEP); 21471256Syl150051 if (buf == NULL) { 21481256Syl150051 return (ENOSPC); 21491256Syl150051 } 21501256Syl150051 status = xge_hal_aux_pci_config_read(lldev->devh, XGELL_PCICONF_BUFSIZE, 21511256Syl150051 buf, &retsize); 21521256Syl150051 if (status != XGE_HAL_OK) { 21531256Syl150051 kmem_free(buf, XGELL_PCICONF_BUFSIZE); 21541256Syl150051 xge_debug_ll(XGE_ERR, "pci_config_read(): status %d", status); 21551256Syl150051 return (EINVAL); 21561256Syl150051 } 21571256Syl150051 *(buf + retsize - 1) = '\0'; /* remove last '\n' */ 21581256Syl150051 (void) mi_mpprintf(mp, "%s", buf); 21591256Syl150051 kmem_free(buf, XGELL_PCICONF_BUFSIZE); 21601256Syl150051 21611256Syl150051 return (0); 21621256Syl150051 } 21631256Syl150051 21641256Syl150051 static int 21651256Syl150051 xgell_about_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp) 21661256Syl150051 { 21671256Syl150051 xgelldev_t *lldev = (xgelldev_t *)cp; 21681256Syl150051 xge_hal_status_e status; 21691256Syl150051 int retsize; 21701256Syl150051 char *buf; 21711256Syl150051 21721256Syl150051 buf = kmem_alloc(XGELL_ABOUT_BUFSIZE, KM_SLEEP); 21731256Syl150051 if (buf == NULL) { 21741256Syl150051 return (ENOSPC); 21751256Syl150051 } 21761256Syl150051 status = xge_hal_aux_about_read(lldev->devh, XGELL_ABOUT_BUFSIZE, 21771256Syl150051 buf, &retsize); 21781256Syl150051 if (status != XGE_HAL_OK) { 21791256Syl150051 kmem_free(buf, XGELL_ABOUT_BUFSIZE); 21801256Syl150051 xge_debug_ll(XGE_ERR, "about_read(): status %d", status); 21811256Syl150051 return (EINVAL); 21821256Syl150051 } 21831256Syl150051 *(buf + retsize - 1) = '\0'; /* remove last '\n' */ 21841256Syl150051 (void) mi_mpprintf(mp, "%s", buf); 21851256Syl150051 kmem_free(buf, XGELL_ABOUT_BUFSIZE); 21861256Syl150051 21871256Syl150051 return (0); 21881256Syl150051 } 21891256Syl150051 21901256Syl150051 static unsigned long bar0_offset = 0x110; /* adapter_control */ 21911256Syl150051 21921256Syl150051 static int 21931256Syl150051 xgell_bar0_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp) 21941256Syl150051 { 21951256Syl150051 xgelldev_t *lldev = (xgelldev_t *)cp; 21961256Syl150051 xge_hal_status_e status; 21971256Syl150051 int retsize; 21981256Syl150051 char *buf; 21991256Syl150051 22001256Syl150051 buf = kmem_alloc(XGELL_IOCTL_BUFSIZE, KM_SLEEP); 22011256Syl150051 if (buf == NULL) { 22021256Syl150051 return (ENOSPC); 22031256Syl150051 } 22041256Syl150051 status = xge_hal_aux_bar0_read(lldev->devh, bar0_offset, 22051256Syl150051 XGELL_IOCTL_BUFSIZE, buf, &retsize); 22061256Syl150051 if (status != XGE_HAL_OK) { 22071256Syl150051 kmem_free(buf, XGELL_IOCTL_BUFSIZE); 22081256Syl150051 xge_debug_ll(XGE_ERR, "bar0_read(): status %d", status); 22091256Syl150051 return (EINVAL); 22101256Syl150051 } 22111256Syl150051 *(buf + retsize - 1) = '\0'; /* remove last '\n' */ 22121256Syl150051 (void) mi_mpprintf(mp, "%s", buf); 22131256Syl150051 kmem_free(buf, XGELL_IOCTL_BUFSIZE); 22141256Syl150051 22151256Syl150051 return (0); 22161256Syl150051 } 22171256Syl150051 22181256Syl150051 static int 22191256Syl150051 xgell_bar0_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp, cred_t *credp) 22201256Syl150051 { 22211256Syl150051 unsigned long old_offset = bar0_offset; 22221256Syl150051 char *end; 22231256Syl150051 22241256Syl150051 if (value && *value == '0' && 22251256Syl150051 (*(value + 1) == 'x' || *(value + 1) == 'X')) { 22261256Syl150051 value += 2; 22271256Syl150051 } 22281256Syl150051 22291256Syl150051 bar0_offset = mi_strtol(value, &end, 16); 22301256Syl150051 if (end == value) { 22311256Syl150051 bar0_offset = old_offset; 22321256Syl150051 return (EINVAL); 22331256Syl150051 } 22341256Syl150051 22351256Syl150051 xge_debug_ll(XGE_TRACE, "bar0: new value %s:%lX", value, bar0_offset); 22361256Syl150051 22371256Syl150051 return (0); 22381256Syl150051 } 22391256Syl150051 22401256Syl150051 static int 22411256Syl150051 xgell_debug_level_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp) 22421256Syl150051 { 22431256Syl150051 char *buf; 22441256Syl150051 22451256Syl150051 buf = kmem_alloc(XGELL_IOCTL_BUFSIZE, KM_SLEEP); 22461256Syl150051 if (buf == NULL) { 22471256Syl150051 return (ENOSPC); 22481256Syl150051 } 22491256Syl150051 (void) mi_mpprintf(mp, "debug_level %d", xge_hal_driver_debug_level()); 22501256Syl150051 kmem_free(buf, XGELL_IOCTL_BUFSIZE); 22511256Syl150051 22521256Syl150051 return (0); 22531256Syl150051 } 22541256Syl150051 22551256Syl150051 static int 22561256Syl150051 xgell_debug_level_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp, 22571256Syl150051 cred_t *credp) 22581256Syl150051 { 22591256Syl150051 int level; 22601256Syl150051 char *end; 22611256Syl150051 22621256Syl150051 level = mi_strtol(value, &end, 10); 22631256Syl150051 if (level < XGE_NONE || level > XGE_ERR || end == value) { 22641256Syl150051 return (EINVAL); 22651256Syl150051 } 22661256Syl150051 22671256Syl150051 xge_hal_driver_debug_level_set(level); 22681256Syl150051 22691256Syl150051 return (0); 22701256Syl150051 } 22711256Syl150051 22721256Syl150051 static int 22731256Syl150051 xgell_debug_module_mask_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp) 22741256Syl150051 { 22751256Syl150051 char *buf; 22761256Syl150051 22771256Syl150051 buf = kmem_alloc(XGELL_IOCTL_BUFSIZE, KM_SLEEP); 22781256Syl150051 if (buf == NULL) { 22791256Syl150051 return (ENOSPC); 22801256Syl150051 } 22811256Syl150051 (void) mi_mpprintf(mp, "debug_module_mask 0x%08x", 22821256Syl150051 xge_hal_driver_debug_module_mask()); 22831256Syl150051 kmem_free(buf, XGELL_IOCTL_BUFSIZE); 22841256Syl150051 22851256Syl150051 return (0); 22861256Syl150051 } 22871256Syl150051 22881256Syl150051 static int 22891256Syl150051 xgell_debug_module_mask_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp, 22901256Syl150051 cred_t *credp) 22911256Syl150051 { 22921256Syl150051 u32 mask; 22931256Syl150051 char *end; 22941256Syl150051 22951256Syl150051 if (value && *value == '0' && 22961256Syl150051 (*(value + 1) == 'x' || *(value + 1) == 'X')) { 22971256Syl150051 value += 2; 22981256Syl150051 } 22991256Syl150051 23001256Syl150051 mask = mi_strtol(value, &end, 16); 23011256Syl150051 if (end == value) { 23021256Syl150051 return (EINVAL); 23031256Syl150051 } 23041256Syl150051 23051256Syl150051 xge_hal_driver_debug_module_mask_set(mask); 23061256Syl150051 23071256Syl150051 return (0); 23081256Syl150051 } 23091256Syl150051 23101256Syl150051 static int 23111256Syl150051 xgell_devconfig_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp) 23121256Syl150051 { 23131256Syl150051 xgelldev_t *lldev = (xgelldev_t *)(void *)cp; 23141256Syl150051 xge_hal_status_e status; 23151256Syl150051 int retsize; 23161256Syl150051 char *buf; 23171256Syl150051 23181256Syl150051 buf = kmem_alloc(XGELL_DEVCONF_BUFSIZE, KM_SLEEP); 23191256Syl150051 if (buf == NULL) { 23201256Syl150051 return (ENOSPC); 23211256Syl150051 } 23221256Syl150051 status = xge_hal_aux_device_config_read(lldev->devh, 2323*6937Sxw161283 XGELL_DEVCONF_BUFSIZE, 2324*6937Sxw161283 buf, &retsize); 23251256Syl150051 if (status != XGE_HAL_OK) { 23261256Syl150051 kmem_free(buf, XGELL_DEVCONF_BUFSIZE); 23271256Syl150051 xge_debug_ll(XGE_ERR, "device_config_read(): status %d", 23281256Syl150051 status); 23291256Syl150051 return (EINVAL); 23301256Syl150051 } 23311256Syl150051 *(buf + retsize - 1) = '\0'; /* remove last '\n' */ 23321256Syl150051 (void) mi_mpprintf(mp, "%s", buf); 23331256Syl150051 kmem_free(buf, XGELL_DEVCONF_BUFSIZE); 23341256Syl150051 23351256Syl150051 return (0); 23361256Syl150051 } 23371256Syl150051 23381256Syl150051 /* 23391256Syl150051 * xgell_device_register 23401256Syl150051 * @devh: pointer on HAL device 23411256Syl150051 * @config: pointer on this network device configuration 23421256Syl150051 * @ll_out: output pointer. Will be assigned to valid LL device. 23431256Syl150051 * 23441256Syl150051 * This function will allocate and register network device 23451256Syl150051 */ 23461256Syl150051 int 23471256Syl150051 xgell_device_register(xgelldev_t *lldev, xgell_config_t *config) 23481256Syl150051 { 23493115Syl150051 mac_register_t *macp = NULL; 23501256Syl150051 xge_hal_device_t *hldev = (xge_hal_device_t *)lldev->devh; 23511256Syl150051 23521256Syl150051 if (nd_load(&lldev->ndp, "pciconf", xgell_pciconf_get, NULL, 23532311Sseb (caddr_t)lldev) == B_FALSE) 23542311Sseb goto xgell_ndd_fail; 23551256Syl150051 23561256Syl150051 if (nd_load(&lldev->ndp, "about", xgell_about_get, NULL, 23572311Sseb (caddr_t)lldev) == B_FALSE) 23582311Sseb goto xgell_ndd_fail; 23591256Syl150051 23601256Syl150051 if (nd_load(&lldev->ndp, "stats", xgell_stats_get, NULL, 23612311Sseb (caddr_t)lldev) == B_FALSE) 23622311Sseb goto xgell_ndd_fail; 23631256Syl150051 23641256Syl150051 if (nd_load(&lldev->ndp, "bar0", xgell_bar0_get, xgell_bar0_set, 23652311Sseb (caddr_t)lldev) == B_FALSE) 23662311Sseb goto xgell_ndd_fail; 23671256Syl150051 23681256Syl150051 if (nd_load(&lldev->ndp, "debug_level", xgell_debug_level_get, 23692311Sseb xgell_debug_level_set, (caddr_t)lldev) == B_FALSE) 23702311Sseb goto xgell_ndd_fail; 23711256Syl150051 23721256Syl150051 if (nd_load(&lldev->ndp, "debug_module_mask", 23731256Syl150051 xgell_debug_module_mask_get, xgell_debug_module_mask_set, 23742311Sseb (caddr_t)lldev) == B_FALSE) 23752311Sseb goto xgell_ndd_fail; 23761256Syl150051 23771256Syl150051 if (nd_load(&lldev->ndp, "devconfig", xgell_devconfig_get, NULL, 23782311Sseb (caddr_t)lldev) == B_FALSE) 23792311Sseb goto xgell_ndd_fail; 23801256Syl150051 23811256Syl150051 bcopy(config, &lldev->config, sizeof (xgell_config_t)); 23821256Syl150051 2383*6937Sxw161283 mutex_init(&lldev->genlock, NULL, MUTEX_DRIVER, 2384*6937Sxw161283 DDI_INTR_PRI(hldev->irqh)); 23851256Syl150051 23862311Sseb if ((macp = mac_alloc(MAC_VERSION)) == NULL) 23872311Sseb goto xgell_register_fail; 23882311Sseb macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 23893115Syl150051 macp->m_driver = lldev; 23902311Sseb macp->m_dip = lldev->dev_info; 23912311Sseb macp->m_src_addr = hldev->macaddr[0]; 23922311Sseb macp->m_callbacks = &xgell_m_callbacks; 23932311Sseb macp->m_min_sdu = 0; 23942311Sseb macp->m_max_sdu = hldev->config.mtu; 23955895Syz147064 macp->m_margin = VLAN_TAGSZ; 23961256Syl150051 /* 23971256Syl150051 * Finally, we're ready to register ourselves with the Nemo 23981256Syl150051 * interface; if this succeeds, we're all ready to start() 23991256Syl150051 */ 24003115Syl150051 24013115Syl150051 if (mac_register(macp, &lldev->mh) != 0) 24022311Sseb goto xgell_register_fail; 24031256Syl150051 24043392Syl150051 /* Always free the macp after register */ 24053392Syl150051 if (macp != NULL) 24063392Syl150051 mac_free(macp); 24073392Syl150051 24083115Syl150051 /* Calculate tx_copied_max here ??? */ 24093115Syl150051 lldev->tx_copied_max = hldev->config.fifo.max_frags * 2410*6937Sxw161283 hldev->config.fifo.alignment_size * 2411*6937Sxw161283 hldev->config.fifo.max_aligned_frags; 24123115Syl150051 24131256Syl150051 xge_debug_ll(XGE_TRACE, "etherenet device %s%d registered", 24141256Syl150051 XGELL_IFNAME, lldev->instance); 24151256Syl150051 24161256Syl150051 return (DDI_SUCCESS); 24172311Sseb 24182311Sseb xgell_ndd_fail: 24192311Sseb nd_free(&lldev->ndp); 24202311Sseb xge_debug_ll(XGE_ERR, "%s", "unable to load ndd parameter"); 24212311Sseb return (DDI_FAILURE); 24222311Sseb 24232311Sseb xgell_register_fail: 24243115Syl150051 if (macp != NULL) 24253115Syl150051 mac_free(macp); 24262311Sseb nd_free(&lldev->ndp); 24272311Sseb mutex_destroy(&lldev->genlock); 24282311Sseb xge_debug_ll(XGE_ERR, "%s", "unable to register networking device"); 24292311Sseb return (DDI_FAILURE); 24301256Syl150051 } 24311256Syl150051 24321256Syl150051 /* 24331256Syl150051 * xgell_device_unregister 24341256Syl150051 * @devh: pointer on HAL device 24351256Syl150051 * @lldev: pointer to valid LL device. 24361256Syl150051 * 24371256Syl150051 * This function will unregister and free network device 24381256Syl150051 */ 24391256Syl150051 int 24401256Syl150051 xgell_device_unregister(xgelldev_t *lldev) 24411256Syl150051 { 24422311Sseb if (mac_unregister(lldev->mh) != 0) { 24431256Syl150051 xge_debug_ll(XGE_ERR, "unable to unregister device %s%d", 24441256Syl150051 XGELL_IFNAME, lldev->instance); 24451256Syl150051 return (DDI_FAILURE); 24461256Syl150051 } 24471256Syl150051 24481256Syl150051 mutex_destroy(&lldev->genlock); 24491256Syl150051 24501256Syl150051 nd_free(&lldev->ndp); 24511256Syl150051 24521256Syl150051 xge_debug_ll(XGE_TRACE, "etherenet device %s%d unregistered", 24531256Syl150051 XGELL_IFNAME, lldev->instance); 24541256Syl150051 24551256Syl150051 return (DDI_SUCCESS); 24561256Syl150051 } 2457