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 /*
23*11878SVenu.Iyer@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
241256Syl150051 * Use is subject to license terms.
251256Syl150051 */
261256Syl150051
271256Syl150051 /*
2811145SRoamer@Sun.COM * Copyright (c) 2002-2009 Neterion, Inc.
291256Syl150051 * All right Reserved.
301256Syl150051 *
311256Syl150051 * FileName : xgell.c
321256Syl150051 *
331256Syl150051 * Description: Xge Link Layer data path implementation
341256Syl150051 *
351256Syl150051 */
361256Syl150051
371256Syl150051 #include "xgell.h"
381256Syl150051
391256Syl150051 #include <netinet/ip.h>
401256Syl150051 #include <netinet/tcp.h>
413115Syl150051 #include <netinet/udp.h>
421256Syl150051
432311Sseb #define XGELL_MAX_FRAME_SIZE(hldev) ((hldev)->config.mtu + \
441256Syl150051 sizeof (struct ether_vlan_header))
451256Syl150051
461256Syl150051 #define HEADROOM 2 /* for DIX-only packets */
471256Syl150051
header_free_func(void * arg)481256Syl150051 void header_free_func(void *arg) { }
491256Syl150051 frtn_t header_frtn = {header_free_func, NULL};
501256Syl150051
511256Syl150051 /* DMA attributes used for Tx side */
521256Syl150051 static struct ddi_dma_attr tx_dma_attr = {
531256Syl150051 DMA_ATTR_V0, /* dma_attr_version */
541256Syl150051 0x0ULL, /* dma_attr_addr_lo */
551256Syl150051 0xFFFFFFFFFFFFFFFFULL, /* dma_attr_addr_hi */
566937Sxw161283 0xFFFFFFFFFFFFFFFFULL, /* dma_attr_count_max */
576937Sxw161283 #if defined(__sparc)
586937Sxw161283 0x2000, /* dma_attr_align */
596937Sxw161283 #else
606937Sxw161283 0x1000, /* dma_attr_align */
616937Sxw161283 #endif
626937Sxw161283 0xFC00FC, /* dma_attr_burstsizes */
636937Sxw161283 0x1, /* dma_attr_minxfer */
646937Sxw161283 0xFFFFFFFFFFFFFFFFULL, /* dma_attr_maxxfer */
651256Syl150051 0xFFFFFFFFFFFFFFFFULL, /* dma_attr_seg */
663115Syl150051 18, /* dma_attr_sgllen */
676937Sxw161283 (unsigned int)1, /* dma_attr_granular */
681256Syl150051 0 /* dma_attr_flags */
691256Syl150051 };
701256Syl150051
711256Syl150051 /*
721256Syl150051 * DMA attributes used when using ddi_dma_mem_alloc to
731256Syl150051 * allocat HAL descriptors and Rx buffers during replenish
741256Syl150051 */
751256Syl150051 static struct ddi_dma_attr hal_dma_attr = {
761256Syl150051 DMA_ATTR_V0, /* dma_attr_version */
771256Syl150051 0x0ULL, /* dma_attr_addr_lo */
781256Syl150051 0xFFFFFFFFFFFFFFFFULL, /* dma_attr_addr_hi */
796937Sxw161283 0xFFFFFFFFFFFFFFFFULL, /* dma_attr_count_max */
806937Sxw161283 #if defined(__sparc)
816937Sxw161283 0x2000, /* dma_attr_align */
826937Sxw161283 #else
836937Sxw161283 0x1000, /* dma_attr_align */
846937Sxw161283 #endif
856937Sxw161283 0xFC00FC, /* dma_attr_burstsizes */
866937Sxw161283 0x1, /* dma_attr_minxfer */
876937Sxw161283 0xFFFFFFFFFFFFFFFFULL, /* dma_attr_maxxfer */
881256Syl150051 0xFFFFFFFFFFFFFFFFULL, /* dma_attr_seg */
891256Syl150051 1, /* dma_attr_sgllen */
906937Sxw161283 (unsigned int)1, /* dma_attr_sgllen */
916937Sxw161283 DDI_DMA_RELAXED_ORDERING /* dma_attr_flags */
921256Syl150051 };
931256Syl150051
941256Syl150051 struct ddi_dma_attr *p_hal_dma_attr = &hal_dma_attr;
951256Syl150051
962311Sseb static int xgell_m_stat(void *, uint_t, uint64_t *);
972311Sseb static int xgell_m_start(void *);
982311Sseb static void xgell_m_stop(void *);
992311Sseb static int xgell_m_promisc(void *, boolean_t);
1002311Sseb static int xgell_m_multicst(void *, boolean_t, const uint8_t *);
1012311Sseb static void xgell_m_ioctl(void *, queue_t *, mblk_t *);
1022311Sseb static boolean_t xgell_m_getcapab(void *, mac_capab_t, void *);
1032311Sseb
1042311Sseb #define XGELL_M_CALLBACK_FLAGS (MC_IOCTL | MC_GETCAPAB)
1052311Sseb
1062311Sseb static mac_callbacks_t xgell_m_callbacks = {
1072311Sseb XGELL_M_CALLBACK_FLAGS,
1082311Sseb xgell_m_stat,
1092311Sseb xgell_m_start,
1102311Sseb xgell_m_stop,
1112311Sseb xgell_m_promisc,
1122311Sseb xgell_m_multicst,
1138275SEric Cheng NULL,
1142311Sseb NULL,
115*11878SVenu.Iyer@Sun.COM NULL,
1162311Sseb xgell_m_ioctl,
1172311Sseb xgell_m_getcapab
1182311Sseb };
1192311Sseb
1201256Syl150051 /*
1211256Syl150051 * xge_device_poll
1221256Syl150051 *
1238275SEric Cheng * Timeout should call me every 1s. xge_callback_event_queued should call me
1241256Syl150051 * when HAL hope event was rescheduled.
1251256Syl150051 */
1261256Syl150051 /*ARGSUSED*/
1271256Syl150051 void
xge_device_poll(void * data)1281256Syl150051 xge_device_poll(void *data)
1291256Syl150051 {
1301256Syl150051 xgelldev_t *lldev = xge_hal_device_private(data);
1311256Syl150051
1321256Syl150051 mutex_enter(&lldev->genlock);
1331256Syl150051 if (lldev->is_initialized) {
1341256Syl150051 xge_hal_device_poll(data);
1351256Syl150051 lldev->timeout_id = timeout(xge_device_poll, data,
1361256Syl150051 XGE_DEV_POLL_TICKS);
1373115Syl150051 } else if (lldev->in_reset == 1) {
1383115Syl150051 lldev->timeout_id = timeout(xge_device_poll, data,
1393115Syl150051 XGE_DEV_POLL_TICKS);
1403115Syl150051 } else {
1413115Syl150051 lldev->timeout_id = 0;
1421256Syl150051 }
1431256Syl150051 mutex_exit(&lldev->genlock);
1441256Syl150051 }
1451256Syl150051
1461256Syl150051 /*
1471256Syl150051 * xge_device_poll_now
1481256Syl150051 *
1491256Syl150051 * Will call xge_device_poll() immediately
1501256Syl150051 */
1511256Syl150051 void
xge_device_poll_now(void * data)1521256Syl150051 xge_device_poll_now(void *data)
1531256Syl150051 {
1541256Syl150051 xgelldev_t *lldev = xge_hal_device_private(data);
1551256Syl150051
1561256Syl150051 mutex_enter(&lldev->genlock);
1573115Syl150051 if (lldev->is_initialized) {
1583115Syl150051 xge_hal_device_poll(data);
1593115Syl150051 }
1601256Syl150051 mutex_exit(&lldev->genlock);
1611256Syl150051 }
1621256Syl150051
1631256Syl150051 /*
1641256Syl150051 * xgell_callback_link_up
1651256Syl150051 *
1661256Syl150051 * This function called by HAL to notify HW link up state change.
1671256Syl150051 */
1681256Syl150051 void
xgell_callback_link_up(void * userdata)1691256Syl150051 xgell_callback_link_up(void *userdata)
1701256Syl150051 {
1711256Syl150051 xgelldev_t *lldev = (xgelldev_t *)userdata;
1721256Syl150051
1732311Sseb mac_link_update(lldev->mh, LINK_STATE_UP);
1741256Syl150051 }
1751256Syl150051
1761256Syl150051 /*
1771256Syl150051 * xgell_callback_link_down
1781256Syl150051 *
1791256Syl150051 * This function called by HAL to notify HW link down state change.
1801256Syl150051 */
1811256Syl150051 void
xgell_callback_link_down(void * userdata)1821256Syl150051 xgell_callback_link_down(void *userdata)
1831256Syl150051 {
1841256Syl150051 xgelldev_t *lldev = (xgelldev_t *)userdata;
1851256Syl150051
1862311Sseb mac_link_update(lldev->mh, LINK_STATE_DOWN);
1871256Syl150051 }
1881256Syl150051
1891256Syl150051 /*
1901256Syl150051 * xgell_rx_buffer_replenish_all
1911256Syl150051 *
1921256Syl150051 * To replenish all freed dtr(s) with buffers in free pool. It's called by
1938275SEric Cheng * xgell_rx_buffer_recycle() or xgell_rx_1b_callback().
1941256Syl150051 * Must be called with pool_lock held.
1951256Syl150051 */
1961256Syl150051 static void
xgell_rx_buffer_replenish_all(xgell_rx_ring_t * ring)1978275SEric Cheng xgell_rx_buffer_replenish_all(xgell_rx_ring_t *ring)
1981256Syl150051 {
1998275SEric Cheng xgell_rx_buffer_pool_t *bf_pool = &ring->bf_pool;
2001256Syl150051 xge_hal_dtr_h dtr;
2011256Syl150051 xgell_rx_buffer_t *rx_buffer;
2021256Syl150051 xgell_rxd_priv_t *rxd_priv;
2031256Syl150051
2048275SEric Cheng xge_assert(mutex_owned(&bf_pool->pool_lock));
2058275SEric Cheng
2068275SEric Cheng while ((bf_pool->free > 0) &&
2078275SEric Cheng (xge_hal_ring_dtr_reserve(ring->channelh, &dtr) == XGE_HAL_OK)) {
2088275SEric Cheng xge_assert(bf_pool->head);
2098275SEric Cheng
2108275SEric Cheng rx_buffer = bf_pool->head;
2118275SEric Cheng
2128275SEric Cheng bf_pool->head = rx_buffer->next;
2138275SEric Cheng bf_pool->free--;
2148275SEric Cheng
2151256Syl150051 xge_assert(rx_buffer->dma_addr);
2161256Syl150051
2171256Syl150051 rxd_priv = (xgell_rxd_priv_t *)
2186937Sxw161283 xge_hal_ring_dtr_private(ring->channelh, dtr);
2191256Syl150051 xge_hal_ring_dtr_1b_set(dtr, rx_buffer->dma_addr,
2208275SEric Cheng bf_pool->size);
2211256Syl150051
2221256Syl150051 rxd_priv->rx_buffer = rx_buffer;
2236937Sxw161283 xge_hal_ring_dtr_post(ring->channelh, dtr);
2241256Syl150051 }
2251256Syl150051 }
2261256Syl150051
2271256Syl150051 /*
2281256Syl150051 * xgell_rx_buffer_release
2291256Syl150051 *
2301256Syl150051 * The only thing done here is to put the buffer back to the pool.
2313115Syl150051 * Calling this function need be protected by mutex, bf_pool.pool_lock.
2321256Syl150051 */
2331256Syl150051 static void
xgell_rx_buffer_release(xgell_rx_buffer_t * rx_buffer)2341256Syl150051 xgell_rx_buffer_release(xgell_rx_buffer_t *rx_buffer)
2351256Syl150051 {
2368275SEric Cheng xgell_rx_ring_t *ring = rx_buffer->ring;
2378275SEric Cheng xgell_rx_buffer_pool_t *bf_pool = &ring->bf_pool;
2388275SEric Cheng
2398275SEric Cheng xge_assert(mutex_owned(&bf_pool->pool_lock));
2401256Syl150051
2411256Syl150051 /* Put the buffer back to pool */
2428275SEric Cheng rx_buffer->next = bf_pool->head;
2438275SEric Cheng bf_pool->head = rx_buffer;
2448275SEric Cheng
2458275SEric Cheng bf_pool->free++;
2461256Syl150051 }
2471256Syl150051
2481256Syl150051 /*
2491256Syl150051 * xgell_rx_buffer_recycle
2501256Syl150051 *
2511256Syl150051 * Called by desballoc() to "free" the resource.
2521256Syl150051 * We will try to replenish all descripters.
2531256Syl150051 */
2546937Sxw161283
2556937Sxw161283 /*
2566937Sxw161283 * Previously there were much lock contention between xgell_rx_1b_compl() and
2576937Sxw161283 * xgell_rx_buffer_recycle(), which consumed a lot of CPU resources and had bad
2586937Sxw161283 * effect on rx performance. A separate recycle list is introduced to overcome
2596937Sxw161283 * this. The recycle list is used to record the rx buffer that has been recycled
2606937Sxw161283 * and these buffers will be retuned back to the free list in bulk instead of
2616937Sxw161283 * one-by-one.
2626937Sxw161283 */
2636937Sxw161283
2641256Syl150051 static void
xgell_rx_buffer_recycle(char * arg)2651256Syl150051 xgell_rx_buffer_recycle(char *arg)
2661256Syl150051 {
2671256Syl150051 xgell_rx_buffer_t *rx_buffer = (xgell_rx_buffer_t *)arg;
2688275SEric Cheng xgell_rx_ring_t *ring = rx_buffer->ring;
2696937Sxw161283 xgelldev_t *lldev = ring->lldev;
2706937Sxw161283 xgell_rx_buffer_pool_t *bf_pool = &ring->bf_pool;
2716937Sxw161283
2726937Sxw161283 mutex_enter(&bf_pool->recycle_lock);
2731256Syl150051
2746937Sxw161283 rx_buffer->next = bf_pool->recycle_head;
2756937Sxw161283 bf_pool->recycle_head = rx_buffer;
2766937Sxw161283 if (bf_pool->recycle_tail == NULL)
2776937Sxw161283 bf_pool->recycle_tail = rx_buffer;
2786937Sxw161283 bf_pool->recycle++;
2791256Syl150051
2801256Syl150051 /*
2811256Syl150051 * Before finding a good way to set this hiwat, just always call to
2821256Syl150051 * replenish_all. *TODO*
2831256Syl150051 */
2848275SEric Cheng if ((lldev->is_initialized != 0) && (ring->live) &&
2856937Sxw161283 (bf_pool->recycle >= XGELL_RX_BUFFER_RECYCLE_CACHE)) {
2868275SEric Cheng mutex_enter(&bf_pool->pool_lock);
2878275SEric Cheng bf_pool->recycle_tail->next = bf_pool->head;
2888275SEric Cheng bf_pool->head = bf_pool->recycle_head;
2898275SEric Cheng bf_pool->recycle_head = bf_pool->recycle_tail = NULL;
2908275SEric Cheng bf_pool->post -= bf_pool->recycle;
2918275SEric Cheng bf_pool->free += bf_pool->recycle;
2928275SEric Cheng bf_pool->recycle = 0;
2938275SEric Cheng xgell_rx_buffer_replenish_all(ring);
2948275SEric Cheng mutex_exit(&bf_pool->pool_lock);
2951256Syl150051 }
2961256Syl150051
2976937Sxw161283 mutex_exit(&bf_pool->recycle_lock);
2981256Syl150051 }
2991256Syl150051
3001256Syl150051 /*
3011256Syl150051 * xgell_rx_buffer_alloc
3021256Syl150051 *
3031256Syl150051 * Allocate one rx buffer and return with the pointer to the buffer.
3041256Syl150051 * Return NULL if failed.
3051256Syl150051 */
3061256Syl150051 static xgell_rx_buffer_t *
xgell_rx_buffer_alloc(xgell_rx_ring_t * ring)3078275SEric Cheng xgell_rx_buffer_alloc(xgell_rx_ring_t *ring)
3081256Syl150051 {
3098275SEric Cheng xgelldev_t *lldev = ring->lldev;
3108275SEric Cheng xgell_rx_buffer_pool_t *bf_pool = &ring->bf_pool;
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;
3211256Syl150051
3223115Syl150051 hldev = (xge_hal_device_t *)lldev->devh;
3231256Syl150051
3241256Syl150051 if (ddi_dma_alloc_handle(hldev->pdev, p_hal_dma_attr, DDI_DMA_SLEEP,
3251256Syl150051 0, &dma_handle) != DDI_SUCCESS) {
3261256Syl150051 xge_debug_ll(XGE_ERR, "%s%d: can not allocate DMA handle",
3271256Syl150051 XGELL_IFNAME, lldev->instance);
3281256Syl150051 goto handle_failed;
3291256Syl150051 }
3301256Syl150051
3311256Syl150051 /* reserve some space at the end of the buffer for recycling */
3328275SEric Cheng if (ddi_dma_mem_alloc(dma_handle, HEADROOM + bf_pool->size +
3331256Syl150051 sizeof (xgell_rx_buffer_t), p_xge_dev_attr, DDI_DMA_STREAMING,
3341256Syl150051 DDI_DMA_SLEEP, 0, (caddr_t *)&vaddr, &real_size, &dma_acch) !=
3351256Syl150051 DDI_SUCCESS) {
3361256Syl150051 xge_debug_ll(XGE_ERR, "%s%d: can not allocate DMA-able memory",
3371256Syl150051 XGELL_IFNAME, lldev->instance);
3381256Syl150051 goto mem_failed;
3391256Syl150051 }
3401256Syl150051
3418275SEric Cheng if (HEADROOM + bf_pool->size + sizeof (xgell_rx_buffer_t) >
3421256Syl150051 real_size) {
3431256Syl150051 xge_debug_ll(XGE_ERR, "%s%d: can not allocate DMA-able memory",
3441256Syl150051 XGELL_IFNAME, lldev->instance);
3451256Syl150051 goto bind_failed;
3461256Syl150051 }
3471256Syl150051
3481256Syl150051 if (ddi_dma_addr_bind_handle(dma_handle, NULL, (char *)vaddr + HEADROOM,
3498275SEric Cheng bf_pool->size, DDI_DMA_READ | DDI_DMA_STREAMING,
3501256Syl150051 DDI_DMA_SLEEP, 0, &dma_cookie, &ncookies) != DDI_SUCCESS) {
3511256Syl150051 xge_debug_ll(XGE_ERR, "%s%d: out of mapping for mblk",
3521256Syl150051 XGELL_IFNAME, lldev->instance);
3531256Syl150051 goto bind_failed;
3541256Syl150051 }
3551256Syl150051
3568275SEric Cheng if (ncookies != 1 || dma_cookie.dmac_size < bf_pool->size) {
3571256Syl150051 xge_debug_ll(XGE_ERR, "%s%d: can not handle partial DMA",
3581256Syl150051 XGELL_IFNAME, lldev->instance);
3591256Syl150051 goto check_failed;
3601256Syl150051 }
3611256Syl150051
3621256Syl150051 dma_addr = dma_cookie.dmac_laddress;
3631256Syl150051
3641256Syl150051 rx_buffer = (xgell_rx_buffer_t *)((char *)vaddr + real_size -
3651256Syl150051 sizeof (xgell_rx_buffer_t));
3661256Syl150051 rx_buffer->next = NULL;
3671256Syl150051 rx_buffer->vaddr = vaddr;
3681256Syl150051 rx_buffer->dma_addr = dma_addr;
3691256Syl150051 rx_buffer->dma_handle = dma_handle;
3701256Syl150051 rx_buffer->dma_acch = dma_acch;
3716937Sxw161283 rx_buffer->ring = ring;
3721256Syl150051 rx_buffer->frtn.free_func = xgell_rx_buffer_recycle;
3731256Syl150051 rx_buffer->frtn.free_arg = (void *)rx_buffer;
3741256Syl150051
3751256Syl150051 return (rx_buffer);
3761256Syl150051
3771256Syl150051 check_failed:
3781256Syl150051 (void) ddi_dma_unbind_handle(dma_handle);
3791256Syl150051 bind_failed:
3801256Syl150051 XGE_OS_MEMORY_CHECK_FREE(vaddr, 0);
3811256Syl150051 ddi_dma_mem_free(&dma_acch);
3821256Syl150051 mem_failed:
3831256Syl150051 ddi_dma_free_handle(&dma_handle);
3841256Syl150051 handle_failed:
3851256Syl150051
3861256Syl150051 return (NULL);
3871256Syl150051 }
3881256Syl150051
3891256Syl150051 /*
3901256Syl150051 * xgell_rx_destroy_buffer_pool
3911256Syl150051 *
3921256Syl150051 * Destroy buffer pool. If there is still any buffer hold by upper layer,
3931256Syl150051 * recorded by bf_pool.post, return DDI_FAILURE to reject to be unloaded.
3941256Syl150051 */
3958275SEric Cheng static boolean_t
xgell_rx_destroy_buffer_pool(xgell_rx_ring_t * ring)3968275SEric Cheng xgell_rx_destroy_buffer_pool(xgell_rx_ring_t *ring)
3971256Syl150051 {
3988275SEric Cheng xgelldev_t *lldev = ring->lldev;
3998275SEric Cheng xgell_rx_buffer_pool_t *bf_pool = &ring->bf_pool;
4001256Syl150051 xgell_rx_buffer_t *rx_buffer;
4011256Syl150051 ddi_dma_handle_t dma_handle;
4021256Syl150051 ddi_acc_handle_t dma_acch;
4031256Syl150051 int i;
4041256Syl150051
4058275SEric Cheng /*
4068275SEric Cheng * If the pool has been destroied, just return B_TRUE
4078275SEric Cheng */
4088275SEric Cheng if (!bf_pool->live)
4098275SEric Cheng return (B_TRUE);
4108275SEric Cheng
4118275SEric Cheng mutex_enter(&bf_pool->recycle_lock);
4128275SEric Cheng if (bf_pool->recycle > 0) {
4138275SEric Cheng mutex_enter(&bf_pool->pool_lock);
4148275SEric Cheng bf_pool->recycle_tail->next = bf_pool->head;
4158275SEric Cheng bf_pool->head = bf_pool->recycle_head;
4168275SEric Cheng bf_pool->recycle_tail = bf_pool->recycle_head = NULL;
4178275SEric Cheng bf_pool->post -= bf_pool->recycle;
4188275SEric Cheng bf_pool->free += bf_pool->recycle;
4198275SEric Cheng bf_pool->recycle = 0;
4208275SEric Cheng mutex_exit(&bf_pool->pool_lock);
4216937Sxw161283 }
4228275SEric Cheng mutex_exit(&bf_pool->recycle_lock);
4236937Sxw161283
4241256Syl150051 /*
4251256Syl150051 * If there is any posted buffer, the driver should reject to be
4261256Syl150051 * detached. Need notice upper layer to release them.
4271256Syl150051 */
4288275SEric Cheng if (bf_pool->post != 0) {
4291256Syl150051 xge_debug_ll(XGE_ERR,
4301256Syl150051 "%s%d has some buffers not be recycled, try later!",
4311256Syl150051 XGELL_IFNAME, lldev->instance);
4328275SEric Cheng return (B_FALSE);
4331256Syl150051 }
4341256Syl150051
4351256Syl150051 /*
4368275SEric Cheng * Release buffers one by one.
4371256Syl150051 */
4388275SEric Cheng for (i = bf_pool->total; i > 0; i--) {
4398275SEric Cheng rx_buffer = bf_pool->head;
4401256Syl150051 xge_assert(rx_buffer != NULL);
4411256Syl150051
4428275SEric Cheng bf_pool->head = rx_buffer->next;
4431256Syl150051
4441256Syl150051 dma_handle = rx_buffer->dma_handle;
4451256Syl150051 dma_acch = rx_buffer->dma_acch;
4461256Syl150051
4471256Syl150051 if (ddi_dma_unbind_handle(dma_handle) != DDI_SUCCESS) {
4488275SEric Cheng xge_debug_ll(XGE_ERR, "failed to unbind DMA handle!");
4498275SEric Cheng bf_pool->head = rx_buffer;
4508275SEric Cheng return (B_FALSE);
4511256Syl150051 }
4521256Syl150051 ddi_dma_mem_free(&dma_acch);
4531256Syl150051 ddi_dma_free_handle(&dma_handle);
4541256Syl150051
4558275SEric Cheng bf_pool->total--;
4568275SEric Cheng bf_pool->free--;
4571256Syl150051 }
4581256Syl150051
4598275SEric Cheng xge_assert(!mutex_owned(&bf_pool->pool_lock));
4608275SEric Cheng
4618275SEric Cheng mutex_destroy(&bf_pool->recycle_lock);
4628275SEric Cheng mutex_destroy(&bf_pool->pool_lock);
4638275SEric Cheng bf_pool->live = B_FALSE;
4648275SEric Cheng
4658275SEric Cheng return (B_TRUE);
4661256Syl150051 }
4671256Syl150051
4681256Syl150051 /*
4691256Syl150051 * xgell_rx_create_buffer_pool
4701256Syl150051 *
4711256Syl150051 * Initialize RX buffer pool for all RX rings. Refer to rx_buffer_pool_t.
4721256Syl150051 */
4738275SEric Cheng static boolean_t
xgell_rx_create_buffer_pool(xgell_rx_ring_t * ring)4748275SEric Cheng xgell_rx_create_buffer_pool(xgell_rx_ring_t *ring)
4751256Syl150051 {
4768275SEric Cheng xgelldev_t *lldev = ring->lldev;
4778275SEric Cheng xgell_rx_buffer_pool_t *bf_pool = &ring->bf_pool;
4781256Syl150051 xge_hal_device_t *hldev;
4791256Syl150051 xgell_rx_buffer_t *rx_buffer;
4801256Syl150051 int i;
4811256Syl150051
4828275SEric Cheng if (bf_pool->live)
4838275SEric Cheng return (B_TRUE);
4848275SEric Cheng
4852311Sseb hldev = (xge_hal_device_t *)lldev->devh;
4861256Syl150051
4878275SEric Cheng bf_pool->total = 0;
4888275SEric Cheng bf_pool->size = XGELL_MAX_FRAME_SIZE(hldev);
4898275SEric Cheng bf_pool->head = NULL;
4908275SEric Cheng bf_pool->free = 0;
4918275SEric Cheng bf_pool->post = 0;
4928275SEric Cheng bf_pool->post_hiwat = lldev->config.rx_buffer_post_hiwat;
4938275SEric Cheng bf_pool->recycle = 0;
4948275SEric Cheng bf_pool->recycle_head = NULL;
4958275SEric Cheng bf_pool->recycle_tail = NULL;
4968275SEric Cheng bf_pool->live = B_TRUE;
4978275SEric Cheng
4988275SEric Cheng mutex_init(&bf_pool->pool_lock, NULL, MUTEX_DRIVER,
4996937Sxw161283 DDI_INTR_PRI(hldev->irqh));
5008275SEric Cheng mutex_init(&bf_pool->recycle_lock, NULL, MUTEX_DRIVER,
5016937Sxw161283 DDI_INTR_PRI(hldev->irqh));
5021256Syl150051
5031256Syl150051 /*
5041256Syl150051 * Allocate buffers one by one. If failed, destroy whole pool by
5051256Syl150051 * call to xgell_rx_destroy_buffer_pool().
5061256Syl150051 */
5076937Sxw161283
5081256Syl150051 for (i = 0; i < lldev->config.rx_buffer_total; i++) {
5096937Sxw161283 if ((rx_buffer = xgell_rx_buffer_alloc(ring)) == NULL) {
5106937Sxw161283 (void) xgell_rx_destroy_buffer_pool(ring);
5118275SEric Cheng return (B_FALSE);
5121256Syl150051 }
5131256Syl150051
5148275SEric Cheng rx_buffer->next = bf_pool->head;
5158275SEric Cheng bf_pool->head = rx_buffer;
5168275SEric Cheng
5178275SEric Cheng bf_pool->total++;
5188275SEric Cheng bf_pool->free++;
5191256Syl150051 }
5201256Syl150051
5218275SEric Cheng return (B_TRUE);
5221256Syl150051 }
5231256Syl150051
5241256Syl150051 /*
5251256Syl150051 * xgell_rx_dtr_replenish
5261256Syl150051 *
5271256Syl150051 * Replenish descriptor with rx_buffer in RX buffer pool.
5281256Syl150051 * The dtr should be post right away.
5291256Syl150051 */
5301256Syl150051 xge_hal_status_e
xgell_rx_dtr_replenish(xge_hal_channel_h channelh,xge_hal_dtr_h dtr,int index,void * userdata,xge_hal_channel_reopen_e reopen)5311256Syl150051 xgell_rx_dtr_replenish(xge_hal_channel_h channelh, xge_hal_dtr_h dtr, int index,
5321256Syl150051 void *userdata, xge_hal_channel_reopen_e reopen)
5331256Syl150051 {
5348275SEric Cheng xgell_rx_ring_t *ring = userdata;
5358275SEric Cheng xgell_rx_buffer_pool_t *bf_pool = &ring->bf_pool;
5361256Syl150051 xgell_rx_buffer_t *rx_buffer;
5371256Syl150051 xgell_rxd_priv_t *rxd_priv;
5381256Syl150051
5398275SEric Cheng mutex_enter(&bf_pool->pool_lock);
5408275SEric Cheng if (bf_pool->head == NULL) {
5418275SEric Cheng xge_debug_ll(XGE_ERR, "no more available rx DMA buffer!");
5421256Syl150051 return (XGE_HAL_FAIL);
5431256Syl150051 }
5448275SEric Cheng rx_buffer = bf_pool->head;
5451256Syl150051 xge_assert(rx_buffer);
5461256Syl150051 xge_assert(rx_buffer->dma_addr);
5471256Syl150051
5488275SEric Cheng bf_pool->head = rx_buffer->next;
5498275SEric Cheng bf_pool->free--;
5508275SEric Cheng mutex_exit(&bf_pool->pool_lock);
5518275SEric Cheng
5526937Sxw161283 rxd_priv = (xgell_rxd_priv_t *)xge_hal_ring_dtr_private(channelh, dtr);
5538275SEric Cheng xge_hal_ring_dtr_1b_set(dtr, rx_buffer->dma_addr, bf_pool->size);
5541256Syl150051
5551256Syl150051 rxd_priv->rx_buffer = rx_buffer;
5561256Syl150051
5571256Syl150051 return (XGE_HAL_OK);
5581256Syl150051 }
5591256Syl150051
5601256Syl150051 /*
5611256Syl150051 * xgell_get_ip_offset
5621256Syl150051 *
5631256Syl150051 * Calculate the offset to IP header.
5641256Syl150051 */
5651256Syl150051 static inline int
xgell_get_ip_offset(xge_hal_dtr_info_t * ext_info)5661256Syl150051 xgell_get_ip_offset(xge_hal_dtr_info_t *ext_info)
5671256Syl150051 {
5681256Syl150051 int ip_off;
5691256Syl150051
5701256Syl150051 /* get IP-header offset */
5711256Syl150051 switch (ext_info->frame) {
5721256Syl150051 case XGE_HAL_FRAME_TYPE_DIX:
5731256Syl150051 ip_off = XGE_HAL_HEADER_ETHERNET_II_802_3_SIZE;
5741256Syl150051 break;
5751256Syl150051 case XGE_HAL_FRAME_TYPE_IPX:
5761256Syl150051 ip_off = (XGE_HAL_HEADER_ETHERNET_II_802_3_SIZE +
5771256Syl150051 XGE_HAL_HEADER_802_2_SIZE +
5781256Syl150051 XGE_HAL_HEADER_SNAP_SIZE);
5791256Syl150051 break;
5801256Syl150051 case XGE_HAL_FRAME_TYPE_LLC:
5811256Syl150051 ip_off = (XGE_HAL_HEADER_ETHERNET_II_802_3_SIZE +
5821256Syl150051 XGE_HAL_HEADER_802_2_SIZE);
5831256Syl150051 break;
5841256Syl150051 case XGE_HAL_FRAME_TYPE_SNAP:
5851256Syl150051 ip_off = (XGE_HAL_HEADER_ETHERNET_II_802_3_SIZE +
5861256Syl150051 XGE_HAL_HEADER_SNAP_SIZE);
5871256Syl150051 break;
5881256Syl150051 default:
5891256Syl150051 ip_off = 0;
5901256Syl150051 break;
5911256Syl150051 }
5921256Syl150051
5931256Syl150051 if ((ext_info->proto & XGE_HAL_FRAME_PROTO_IPV4 ||
5941256Syl150051 ext_info->proto & XGE_HAL_FRAME_PROTO_IPV6) &&
5951256Syl150051 (ext_info->proto & XGE_HAL_FRAME_PROTO_VLAN_TAGGED)) {
5961256Syl150051 ip_off += XGE_HAL_HEADER_VLAN_SIZE;
5971256Syl150051 }
5981256Syl150051
5991256Syl150051 return (ip_off);
6001256Syl150051 }
6011256Syl150051
6021256Syl150051 /*
6031256Syl150051 * xgell_rx_hcksum_assoc
6041256Syl150051 *
6051256Syl150051 * Judge the packet type and then call to hcksum_assoc() to associate
6061256Syl150051 * h/w checksum information.
6071256Syl150051 */
6081256Syl150051 static inline void
xgell_rx_hcksum_assoc(mblk_t * mp,char * vaddr,int pkt_length,xge_hal_dtr_info_t * ext_info)6091256Syl150051 xgell_rx_hcksum_assoc(mblk_t *mp, char *vaddr, int pkt_length,
6101256Syl150051 xge_hal_dtr_info_t *ext_info)
6111256Syl150051 {
6121256Syl150051 int cksum_flags = 0;
6131256Syl150051
6141256Syl150051 if (!(ext_info->proto & XGE_HAL_FRAME_PROTO_IP_FRAGMENTED)) {
6151256Syl150051 if (ext_info->proto & XGE_HAL_FRAME_PROTO_TCP_OR_UDP) {
6161256Syl150051 if (ext_info->l3_cksum == XGE_HAL_L3_CKSUM_OK) {
617*11878SVenu.Iyer@Sun.COM cksum_flags |= HCK_IPV4_HDRCKSUM_OK;
6181256Syl150051 }
6191256Syl150051 if (ext_info->l4_cksum == XGE_HAL_L4_CKSUM_OK) {
6201256Syl150051 cksum_flags |= HCK_FULLCKSUM_OK;
6211256Syl150051 }
622*11878SVenu.Iyer@Sun.COM if (cksum_flags != 0) {
623*11878SVenu.Iyer@Sun.COM mac_hcksum_set(mp, 0, 0, 0, 0, cksum_flags);
6241256Syl150051 }
6251256Syl150051 }
6261256Syl150051 } else if (ext_info->proto &
6271256Syl150051 (XGE_HAL_FRAME_PROTO_IPV4 | XGE_HAL_FRAME_PROTO_IPV6)) {
6281256Syl150051 /*
6291256Syl150051 * Just pass the partial cksum up to IP.
6301256Syl150051 */
6313115Syl150051 int ip_off = xgell_get_ip_offset(ext_info);
6321256Syl150051 int start, end = pkt_length - ip_off;
6331256Syl150051
6341256Syl150051 if (ext_info->proto & XGE_HAL_FRAME_PROTO_IPV4) {
6351256Syl150051 struct ip *ip =
6361256Syl150051 (struct ip *)(vaddr + ip_off);
63711145SRoamer@Sun.COM start = ip->ip_hl * 4;
6381256Syl150051 } else {
63911145SRoamer@Sun.COM start = 40;
6401256Syl150051 }
6411256Syl150051 cksum_flags |= HCK_PARTIALCKSUM;
642*11878SVenu.Iyer@Sun.COM mac_hcksum_set(mp, start, 0, end,
643*11878SVenu.Iyer@Sun.COM ntohs(ext_info->l4_cksum), cksum_flags);
6441256Syl150051 }
6451256Syl150051 }
6461256Syl150051
6471256Syl150051 /*
6481256Syl150051 * xgell_rx_1b_msg_alloc
6491256Syl150051 *
6501256Syl150051 * Allocate message header for data buffer, and decide if copy the packet to
6511256Syl150051 * new data buffer to release big rx_buffer to save memory.
6521256Syl150051 *
6533115Syl150051 * If the pkt_length <= XGELL_RX_DMA_LOWAT, call allocb() to allocate
6541256Syl150051 * new message and copy the payload in.
6551256Syl150051 */
6561256Syl150051 static mblk_t *
xgell_rx_1b_msg_alloc(xgell_rx_ring_t * ring,xgell_rx_buffer_t * rx_buffer,int pkt_length,xge_hal_dtr_info_t * ext_info,boolean_t * copyit)6578275SEric Cheng xgell_rx_1b_msg_alloc(xgell_rx_ring_t *ring, xgell_rx_buffer_t *rx_buffer,
6583115Syl150051 int pkt_length, xge_hal_dtr_info_t *ext_info, boolean_t *copyit)
6591256Syl150051 {
6608275SEric Cheng xgelldev_t *lldev = ring->lldev;
6611256Syl150051 mblk_t *mp;
6621256Syl150051 char *vaddr;
6631256Syl150051
6641256Syl150051 vaddr = (char *)rx_buffer->vaddr + HEADROOM;
6651256Syl150051 /*
6661256Syl150051 * Copy packet into new allocated message buffer, if pkt_length
6673115Syl150051 * is less than XGELL_RX_DMA_LOWAT
6681256Syl150051 */
6693115Syl150051 if (*copyit || pkt_length <= lldev->config.rx_dma_lowat) {
6706937Sxw161283 if ((mp = allocb(pkt_length + HEADROOM, 0)) == NULL) {
6711256Syl150051 return (NULL);
6721256Syl150051 }
6736937Sxw161283 mp->b_rptr += HEADROOM;
6741256Syl150051 bcopy(vaddr, mp->b_rptr, pkt_length);
6751256Syl150051 mp->b_wptr = mp->b_rptr + pkt_length;
6761256Syl150051 *copyit = B_TRUE;
6771256Syl150051 return (mp);
6781256Syl150051 }
6791256Syl150051
6801256Syl150051 /*
6811256Syl150051 * Just allocate mblk for current data buffer
6821256Syl150051 */
6833392Syl150051 if ((mp = (mblk_t *)desballoc((unsigned char *)vaddr, pkt_length, 0,
6841256Syl150051 &rx_buffer->frtn)) == NULL) {
6851256Syl150051 /* Drop it */
6861256Syl150051 return (NULL);
6871256Syl150051 }
6881256Syl150051 /*
6893392Syl150051 * Adjust the b_rptr/b_wptr in the mblk_t structure.
6901256Syl150051 */
6913392Syl150051 mp->b_wptr += pkt_length;
6921256Syl150051
6931256Syl150051 return (mp);
6941256Syl150051 }
6951256Syl150051
6961256Syl150051 /*
6978275SEric Cheng * xgell_rx_1b_callback
6981256Syl150051 *
6991256Syl150051 * If the interrupt is because of a received frame or if the receive ring
7001256Syl150051 * contains fresh as yet un-processed frames, this function is called.
7011256Syl150051 */
7021256Syl150051 static xge_hal_status_e
xgell_rx_1b_callback(xge_hal_channel_h channelh,xge_hal_dtr_h dtr,u8 t_code,void * userdata)7038275SEric Cheng xgell_rx_1b_callback(xge_hal_channel_h channelh, xge_hal_dtr_h dtr, u8 t_code,
7041256Syl150051 void *userdata)
7051256Syl150051 {
7068275SEric Cheng xgell_rx_ring_t *ring = (xgell_rx_ring_t *)userdata;
7076937Sxw161283 xgelldev_t *lldev = ring->lldev;
7081256Syl150051 xgell_rx_buffer_t *rx_buffer;
7091256Syl150051 mblk_t *mp_head = NULL;
7101256Syl150051 mblk_t *mp_end = NULL;
7113115Syl150051 int pkt_burst = 0;
7123115Syl150051
7138275SEric Cheng xge_debug_ll(XGE_TRACE, "xgell_rx_1b_callback on ring %d", ring->index);
7148275SEric Cheng
7156937Sxw161283 mutex_enter(&ring->bf_pool.pool_lock);
7161256Syl150051 do {
7171256Syl150051 int pkt_length;
7181256Syl150051 dma_addr_t dma_data;
7191256Syl150051 mblk_t *mp;
7201256Syl150051 boolean_t copyit = B_FALSE;
7211256Syl150051
7221256Syl150051 xgell_rxd_priv_t *rxd_priv = ((xgell_rxd_priv_t *)
7231256Syl150051 xge_hal_ring_dtr_private(channelh, dtr));
7241256Syl150051 xge_hal_dtr_info_t ext_info;
7251256Syl150051
7261256Syl150051 rx_buffer = rxd_priv->rx_buffer;
7271256Syl150051
7281256Syl150051 xge_hal_ring_dtr_1b_get(channelh, dtr, &dma_data, &pkt_length);
7291256Syl150051 xge_hal_ring_dtr_info_get(channelh, dtr, &ext_info);
7301256Syl150051
7311256Syl150051 xge_assert(dma_data == rx_buffer->dma_addr);
7321256Syl150051
7331256Syl150051 if (t_code != 0) {
7341256Syl150051 xge_debug_ll(XGE_ERR, "%s%d: rx: dtr 0x%"PRIx64
7351256Syl150051 " completed due to error t_code %01x", XGELL_IFNAME,
7361256Syl150051 lldev->instance, (uint64_t)(uintptr_t)dtr, t_code);
7371256Syl150051
7381256Syl150051 (void) xge_hal_device_handle_tcode(channelh, dtr,
7391256Syl150051 t_code);
7401256Syl150051 xge_hal_ring_dtr_free(channelh, dtr); /* drop it */
7411256Syl150051 xgell_rx_buffer_release(rx_buffer);
7421256Syl150051 continue;
7431256Syl150051 }
7441256Syl150051
7451256Syl150051 /*
7461256Syl150051 * Sync the DMA memory
7471256Syl150051 */
7483115Syl150051 if (ddi_dma_sync(rx_buffer->dma_handle, 0, pkt_length,
7493115Syl150051 DDI_DMA_SYNC_FORKERNEL) != DDI_SUCCESS) {
7501256Syl150051 xge_debug_ll(XGE_ERR, "%s%d: rx: can not do DMA sync",
7511256Syl150051 XGELL_IFNAME, lldev->instance);
7521256Syl150051 xge_hal_ring_dtr_free(channelh, dtr); /* drop it */
7531256Syl150051 xgell_rx_buffer_release(rx_buffer);
7541256Syl150051 continue;
7551256Syl150051 }
7561256Syl150051
7571256Syl150051 /*
7581256Syl150051 * Allocate message for the packet.
7591256Syl150051 */
7606937Sxw161283 if (ring->bf_pool.post > ring->bf_pool.post_hiwat) {
7611256Syl150051 copyit = B_TRUE;
7621256Syl150051 } else {
7631256Syl150051 copyit = B_FALSE;
7641256Syl150051 }
7651256Syl150051
7668275SEric Cheng mp = xgell_rx_1b_msg_alloc(ring, rx_buffer, pkt_length,
7673115Syl150051 &ext_info, ©it);
7681256Syl150051
7691256Syl150051 xge_hal_ring_dtr_free(channelh, dtr);
7701256Syl150051
7711256Syl150051 /*
7721256Syl150051 * Release the buffer and recycle it later
7731256Syl150051 */
7741256Syl150051 if ((mp == NULL) || copyit) {
7751256Syl150051 xgell_rx_buffer_release(rx_buffer);
7761256Syl150051 } else {
7771256Syl150051 /*
7781256Syl150051 * Count it since the buffer should be loaned up.
7791256Syl150051 */
7806937Sxw161283 ring->bf_pool.post++;
7811256Syl150051 }
7821256Syl150051 if (mp == NULL) {
7831256Syl150051 xge_debug_ll(XGE_ERR,
7843115Syl150051 "%s%d: rx: can not allocate mp mblk",
7853115Syl150051 XGELL_IFNAME, lldev->instance);
7861256Syl150051 continue;
7871256Syl150051 }
7881256Syl150051
7891256Syl150051 /*
7903115Syl150051 * Associate cksum_flags per packet type and h/w
7913115Syl150051 * cksum flags.
7921256Syl150051 */
7938275SEric Cheng xgell_rx_hcksum_assoc(mp, (char *)rx_buffer->vaddr + HEADROOM,
7948275SEric Cheng pkt_length, &ext_info);
7958275SEric Cheng
796*11878SVenu.Iyer@Sun.COM ring->rx_pkts++;
797*11878SVenu.Iyer@Sun.COM ring->rx_bytes += pkt_length;
7981256Syl150051
7991256Syl150051 if (mp_head == NULL) {
8001256Syl150051 mp_head = mp;
8011256Syl150051 mp_end = mp;
8021256Syl150051 } else {
8031256Syl150051 mp_end->b_next = mp;
8041256Syl150051 mp_end = mp;
8051256Syl150051 }
8061256Syl150051
8078275SEric Cheng /*
8088275SEric Cheng * Inlined implemented polling function.
8098275SEric Cheng */
8108275SEric Cheng if ((ring->poll_mp == NULL) && (ring->poll_bytes > 0)) {
8118275SEric Cheng ring->poll_mp = mp_head;
8128275SEric Cheng }
8138275SEric Cheng if (ring->poll_mp != NULL) {
8148275SEric Cheng if ((ring->poll_bytes -= pkt_length) <= 0) {
8158275SEric Cheng /* have polled enough packets. */
8168275SEric Cheng break;
8178275SEric Cheng } else {
8188275SEric Cheng /* continue polling packets. */
8198275SEric Cheng continue;
8208275SEric Cheng }
8218275SEric Cheng }
8228275SEric Cheng
8238275SEric Cheng /*
8248275SEric Cheng * We're not in polling mode, so try to chain more messages
8258275SEric Cheng * or send the chain up according to pkt_burst.
8268275SEric Cheng */
8273115Syl150051 if (++pkt_burst < lldev->config.rx_pkt_burst)
8283115Syl150051 continue;
8293115Syl150051
8306937Sxw161283 if (ring->bf_pool.post > ring->bf_pool.post_hiwat) {
8313115Syl150051 /* Replenish rx buffers */
8326937Sxw161283 xgell_rx_buffer_replenish_all(ring);
8333115Syl150051 }
8346937Sxw161283 mutex_exit(&ring->bf_pool.pool_lock);
8353115Syl150051 if (mp_head != NULL) {
8368275SEric Cheng mac_rx_ring(lldev->mh, ring->ring_handle, mp_head,
8378275SEric Cheng ring->ring_gen_num);
8383115Syl150051 }
8393115Syl150051 mp_head = mp_end = NULL;
8403115Syl150051 pkt_burst = 0;
8416937Sxw161283 mutex_enter(&ring->bf_pool.pool_lock);
8423115Syl150051
8431256Syl150051 } while (xge_hal_ring_dtr_next_completed(channelh, &dtr, &t_code) ==
8441256Syl150051 XGE_HAL_OK);
8451256Syl150051
8461256Syl150051 /*
8471256Syl150051 * Always call replenish_all to recycle rx_buffers.
8481256Syl150051 */
8496937Sxw161283 xgell_rx_buffer_replenish_all(ring);
8506937Sxw161283 mutex_exit(&ring->bf_pool.pool_lock);
8511256Syl150051
8528275SEric Cheng /*
8538275SEric Cheng * If we're not in polling cycle, call mac_rx(), otherwise
8548275SEric Cheng * just return while leaving packets chained to ring->poll_mp.
8558275SEric Cheng */
8568275SEric Cheng if ((ring->poll_mp == NULL) && (mp_head != NULL)) {
8578275SEric Cheng mac_rx_ring(lldev->mh, ring->ring_handle, mp_head,
8588275SEric Cheng ring->ring_gen_num);
8593115Syl150051 }
8603115Syl150051
8611256Syl150051 return (XGE_HAL_OK);
8621256Syl150051 }
8631256Syl150051
8648275SEric Cheng mblk_t *
xgell_rx_poll(void * arg,int bytes_to_pickup)8658275SEric Cheng xgell_rx_poll(void *arg, int bytes_to_pickup)
8668275SEric Cheng {
8678275SEric Cheng xgell_rx_ring_t *ring = (xgell_rx_ring_t *)arg;
8688275SEric Cheng int got_rx = 0;
8698275SEric Cheng mblk_t *mp;
8708275SEric Cheng
8718275SEric Cheng xge_debug_ll(XGE_TRACE, "xgell_rx_poll on ring %d", ring->index);
8728275SEric Cheng
8738275SEric Cheng ring->poll_mp = NULL;
8748275SEric Cheng ring->poll_bytes = bytes_to_pickup;
8758275SEric Cheng (void) xge_hal_device_poll_rx_channel(ring->channelh, &got_rx);
8768275SEric Cheng
8778275SEric Cheng mp = ring->poll_mp;
8788275SEric Cheng ring->poll_bytes = -1;
8798275SEric Cheng ring->polled_bytes += got_rx;
8808275SEric Cheng ring->poll_mp = NULL;
8818275SEric Cheng
8828275SEric Cheng return (mp);
8838275SEric Cheng }
8848275SEric Cheng
8851256Syl150051 /*
8861256Syl150051 * xgell_xmit_compl
8871256Syl150051 *
8881256Syl150051 * If an interrupt was raised to indicate DMA complete of the Tx packet,
8891256Syl150051 * this function is called. It identifies the last TxD whose buffer was
8901256Syl150051 * freed and frees all skbs whose data have already DMA'ed into the NICs
8911256Syl150051 * internal memory.
8921256Syl150051 */
8931256Syl150051 static xge_hal_status_e
xgell_xmit_compl(xge_hal_channel_h channelh,xge_hal_dtr_h dtr,u8 t_code,void * userdata)8941256Syl150051 xgell_xmit_compl(xge_hal_channel_h channelh, xge_hal_dtr_h dtr, u8 t_code,
8951256Syl150051 void *userdata)
8961256Syl150051 {
8978275SEric Cheng xgell_tx_ring_t *ring = userdata;
8988275SEric Cheng xgelldev_t *lldev = ring->lldev;
8991256Syl150051
9001256Syl150051 do {
9011256Syl150051 xgell_txd_priv_t *txd_priv = ((xgell_txd_priv_t *)
9021256Syl150051 xge_hal_fifo_dtr_private(dtr));
9031256Syl150051 int i;
9041256Syl150051
9051256Syl150051 if (t_code) {
9061256Syl150051 xge_debug_ll(XGE_TRACE, "%s%d: tx: dtr 0x%"PRIx64
9071256Syl150051 " completed due to error t_code %01x", XGELL_IFNAME,
9081256Syl150051 lldev->instance, (uint64_t)(uintptr_t)dtr, t_code);
9091256Syl150051
9101256Syl150051 (void) xge_hal_device_handle_tcode(channelh, dtr,
9111256Syl150051 t_code);
9121256Syl150051 }
9131256Syl150051
9141256Syl150051 for (i = 0; i < txd_priv->handle_cnt; i++) {
9156937Sxw161283 if (txd_priv->dma_handles[i] != NULL) {
9166937Sxw161283 xge_assert(txd_priv->dma_handles[i]);
9176937Sxw161283 (void) ddi_dma_unbind_handle(
9186937Sxw161283 txd_priv->dma_handles[i]);
9196937Sxw161283 ddi_dma_free_handle(&txd_priv->dma_handles[i]);
9206937Sxw161283 txd_priv->dma_handles[i] = 0;
9216937Sxw161283 }
9221256Syl150051 }
9236937Sxw161283 txd_priv->handle_cnt = 0;
9241256Syl150051
9251256Syl150051 xge_hal_fifo_dtr_free(channelh, dtr);
9261256Syl150051
9276937Sxw161283 if (txd_priv->mblk != NULL) {
9286937Sxw161283 freemsg(txd_priv->mblk);
9296937Sxw161283 txd_priv->mblk = NULL;
9306937Sxw161283 }
9316937Sxw161283
9321256Syl150051 } while (xge_hal_fifo_dtr_next_completed(channelh, &dtr, &t_code) ==
9331256Syl150051 XGE_HAL_OK);
9341256Syl150051
9358275SEric Cheng if (ring->need_resched)
9368275SEric Cheng mac_tx_ring_update(lldev->mh, ring->ring_handle);
9371256Syl150051
9381256Syl150051 return (XGE_HAL_OK);
9391256Syl150051 }
9401256Syl150051
9418275SEric Cheng mblk_t *
xgell_ring_tx(void * arg,mblk_t * mp)9428275SEric Cheng xgell_ring_tx(void *arg, mblk_t *mp)
9431256Syl150051 {
9448275SEric Cheng xgell_tx_ring_t *ring = (xgell_tx_ring_t *)arg;
9451256Syl150051 mblk_t *bp;
9468275SEric Cheng xgelldev_t *lldev = ring->lldev;
9473115Syl150051 xge_hal_device_t *hldev = lldev->devh;
9481256Syl150051 xge_hal_status_e status;
9491256Syl150051 xge_hal_dtr_h dtr;
9501256Syl150051 xgell_txd_priv_t *txd_priv;
9513115Syl150051 uint32_t hckflags;
9528275SEric Cheng uint32_t lsoflags;
9533115Syl150051 uint32_t mss;
9543115Syl150051 int handle_cnt, frag_cnt, ret, i, copied;
9553115Syl150051 boolean_t used_copy;
956*11878SVenu.Iyer@Sun.COM uint64_t sent_bytes;
9571256Syl150051
9581256Syl150051 _begin:
9591256Syl150051 handle_cnt = frag_cnt = 0;
960*11878SVenu.Iyer@Sun.COM sent_bytes = 0;
9611256Syl150051
9621256Syl150051 if (!lldev->is_initialized || lldev->in_reset)
9638275SEric Cheng return (mp);
9646937Sxw161283
9651256Syl150051 /*
9661256Syl150051 * If the free Tx dtrs count reaches the lower threshold,
9671256Syl150051 * inform the gld to stop sending more packets till the free
9681256Syl150051 * dtrs count exceeds higher threshold. Driver informs the
9691256Syl150051 * gld through gld_sched call, when the free dtrs count exceeds
9701256Syl150051 * the higher threshold.
9711256Syl150051 */
9728275SEric Cheng if (xge_hal_channel_dtr_count(ring->channelh)
9731256Syl150051 <= XGELL_TX_LEVEL_LOW) {
9748275SEric Cheng xge_debug_ll(XGE_TRACE, "%s%d: queue %d: err on xmit,"
9758275SEric Cheng "free descriptors count at low threshold %d",
9768275SEric Cheng XGELL_IFNAME, lldev->instance,
9778275SEric Cheng ((xge_hal_channel_t *)ring->channelh)->post_qid,
9788275SEric Cheng XGELL_TX_LEVEL_LOW);
9798275SEric Cheng goto _exit;
9801256Syl150051 }
9811256Syl150051
9828275SEric Cheng status = xge_hal_fifo_dtr_reserve(ring->channelh, &dtr);
9831256Syl150051 if (status != XGE_HAL_OK) {
9841256Syl150051 switch (status) {
9851256Syl150051 case XGE_HAL_INF_CHANNEL_IS_NOT_READY:
9861256Syl150051 xge_debug_ll(XGE_ERR,
9871256Syl150051 "%s%d: channel %d is not ready.", XGELL_IFNAME,
9881256Syl150051 lldev->instance,
9891256Syl150051 ((xge_hal_channel_t *)
9908275SEric Cheng ring->channelh)->post_qid);
9911256Syl150051 goto _exit;
9921256Syl150051 case XGE_HAL_INF_OUT_OF_DESCRIPTORS:
9931256Syl150051 xge_debug_ll(XGE_TRACE, "%s%d: queue %d: error in xmit,"
9941256Syl150051 " out of descriptors.", XGELL_IFNAME,
9951256Syl150051 lldev->instance,
9961256Syl150051 ((xge_hal_channel_t *)
9978275SEric Cheng ring->channelh)->post_qid);
9981256Syl150051 goto _exit;
9991256Syl150051 default:
10008275SEric Cheng return (mp);
10011256Syl150051 }
10021256Syl150051 }
10031256Syl150051
10041256Syl150051 txd_priv = xge_hal_fifo_dtr_private(dtr);
10051256Syl150051 txd_priv->mblk = mp;
10061256Syl150051
10071256Syl150051 /*
10081256Syl150051 * VLAN tag should be passed down along with MAC header, so h/w needn't
10091256Syl150051 * do insertion.
10101256Syl150051 *
10111256Syl150051 * For NIC driver that has to strip and re-insert VLAN tag, the example
10121256Syl150051 * is the other implementation for xge. The driver can simple bcopy()
10131256Syl150051 * ether_vlan_header to overwrite VLAN tag and let h/w insert the tag
10141256Syl150051 * automatically, since it's impossible that GLD sends down mp(s) with
10151256Syl150051 * splited ether_vlan_header.
10161256Syl150051 *
10171256Syl150051 * struct ether_vlan_header *evhp;
10181256Syl150051 * uint16_t tci;
10191256Syl150051 *
10201256Syl150051 * evhp = (struct ether_vlan_header *)mp->b_rptr;
10211256Syl150051 * if (evhp->ether_tpid == htons(VLAN_TPID)) {
10223115Syl150051 * tci = ntohs(evhp->ether_tci);
10233115Syl150051 * (void) bcopy(mp->b_rptr, mp->b_rptr + VLAN_TAGSZ,
10241256Syl150051 * 2 * ETHERADDRL);
10253115Syl150051 * mp->b_rptr += VLAN_TAGSZ;
10261256Syl150051 *
10273115Syl150051 * xge_hal_fifo_dtr_vlan_set(dtr, tci);
10281256Syl150051 * }
10291256Syl150051 */
10301256Syl150051
10313115Syl150051 copied = 0;
10323115Syl150051 used_copy = B_FALSE;
10331256Syl150051 for (bp = mp; bp != NULL; bp = bp->b_cont) {
10341256Syl150051 int mblen;
10351256Syl150051 uint_t ncookies;
10361256Syl150051 ddi_dma_cookie_t dma_cookie;
10371256Syl150051 ddi_dma_handle_t dma_handle;
10381256Syl150051
10391256Syl150051 /* skip zero-length message blocks */
10401256Syl150051 mblen = MBLKL(bp);
10411256Syl150051 if (mblen == 0) {
10421256Syl150051 continue;
10431256Syl150051 }
10441256Syl150051
1045*11878SVenu.Iyer@Sun.COM sent_bytes += mblen;
10468275SEric Cheng
10473115Syl150051 /*
10483115Syl150051 * Check the message length to decide to DMA or bcopy() data
10493115Syl150051 * to tx descriptor(s).
10503115Syl150051 */
10513115Syl150051 if (mblen < lldev->config.tx_dma_lowat &&
10523115Syl150051 (copied + mblen) < lldev->tx_copied_max) {
10533115Syl150051 xge_hal_status_e rc;
10548275SEric Cheng rc = xge_hal_fifo_dtr_buffer_append(ring->channelh,
10553115Syl150051 dtr, bp->b_rptr, mblen);
10563115Syl150051 if (rc == XGE_HAL_OK) {
10573115Syl150051 used_copy = B_TRUE;
10583115Syl150051 copied += mblen;
10593115Syl150051 continue;
10603115Syl150051 } else if (used_copy) {
10613115Syl150051 xge_hal_fifo_dtr_buffer_finalize(
10628275SEric Cheng ring->channelh, dtr, frag_cnt++);
10633115Syl150051 used_copy = B_FALSE;
10643115Syl150051 }
10653115Syl150051 } else if (used_copy) {
10668275SEric Cheng xge_hal_fifo_dtr_buffer_finalize(ring->channelh,
10673115Syl150051 dtr, frag_cnt++);
10683115Syl150051 used_copy = B_FALSE;
10693115Syl150051 }
10703115Syl150051
10712311Sseb ret = ddi_dma_alloc_handle(lldev->dev_info, &tx_dma_attr,
10721256Syl150051 DDI_DMA_DONTWAIT, 0, &dma_handle);
10731256Syl150051 if (ret != DDI_SUCCESS) {
10741256Syl150051 xge_debug_ll(XGE_ERR,
10753115Syl150051 "%s%d: can not allocate dma handle", XGELL_IFNAME,
10763115Syl150051 lldev->instance);
10771256Syl150051 goto _exit_cleanup;
10781256Syl150051 }
10791256Syl150051
10801256Syl150051 ret = ddi_dma_addr_bind_handle(dma_handle, NULL,
10811256Syl150051 (caddr_t)bp->b_rptr, mblen,
10821256Syl150051 DDI_DMA_WRITE | DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 0,
10831256Syl150051 &dma_cookie, &ncookies);
10841256Syl150051
10851256Syl150051 switch (ret) {
10861256Syl150051 case DDI_DMA_MAPPED:
10871256Syl150051 /* everything's fine */
10881256Syl150051 break;
10891256Syl150051
10901256Syl150051 case DDI_DMA_NORESOURCES:
10911256Syl150051 xge_debug_ll(XGE_ERR,
10921256Syl150051 "%s%d: can not bind dma address",
10931256Syl150051 XGELL_IFNAME, lldev->instance);
10941256Syl150051 ddi_dma_free_handle(&dma_handle);
10951256Syl150051 goto _exit_cleanup;
10961256Syl150051
10971256Syl150051 case DDI_DMA_NOMAPPING:
10981256Syl150051 case DDI_DMA_INUSE:
10991256Syl150051 case DDI_DMA_TOOBIG:
11001256Syl150051 default:
11011256Syl150051 /* drop packet, don't retry */
11021256Syl150051 xge_debug_ll(XGE_ERR,
11031256Syl150051 "%s%d: can not map message buffer",
11041256Syl150051 XGELL_IFNAME, lldev->instance);
11051256Syl150051 ddi_dma_free_handle(&dma_handle);
11061256Syl150051 goto _exit_cleanup;
11071256Syl150051 }
11081256Syl150051
11093115Syl150051 if (ncookies + frag_cnt > hldev->config.fifo.max_frags) {
11101256Syl150051 xge_debug_ll(XGE_ERR, "%s%d: too many fragments, "
11111256Syl150051 "requested c:%d+f:%d", XGELL_IFNAME,
11121256Syl150051 lldev->instance, ncookies, frag_cnt);
11131256Syl150051 (void) ddi_dma_unbind_handle(dma_handle);
11141256Syl150051 ddi_dma_free_handle(&dma_handle);
11151256Syl150051 goto _exit_cleanup;
11161256Syl150051 }
11171256Syl150051
11181256Syl150051 /* setup the descriptors for this data buffer */
11191256Syl150051 while (ncookies) {
11208275SEric Cheng xge_hal_fifo_dtr_buffer_set(ring->channelh, dtr,
11211256Syl150051 frag_cnt++, dma_cookie.dmac_laddress,
11221256Syl150051 dma_cookie.dmac_size);
11231256Syl150051 if (--ncookies) {
11241256Syl150051 ddi_dma_nextcookie(dma_handle, &dma_cookie);
11251256Syl150051 }
11261256Syl150051
11271256Syl150051 }
11281256Syl150051
11291256Syl150051 txd_priv->dma_handles[handle_cnt++] = dma_handle;
11301256Syl150051
11311256Syl150051 if (bp->b_cont &&
11321256Syl150051 (frag_cnt + XGE_HAL_DEFAULT_FIFO_FRAGS_THRESHOLD >=
11336937Sxw161283 hldev->config.fifo.max_frags)) {
11341256Syl150051 mblk_t *nmp;
11351256Syl150051
11361256Syl150051 xge_debug_ll(XGE_TRACE,
11371256Syl150051 "too many FRAGs [%d], pull up them", frag_cnt);
11381256Syl150051
11391256Syl150051 if ((nmp = msgpullup(bp->b_cont, -1)) == NULL) {
11401256Syl150051 /* Drop packet, don't retry */
11411256Syl150051 xge_debug_ll(XGE_ERR,
11421256Syl150051 "%s%d: can not pullup message buffer",
11431256Syl150051 XGELL_IFNAME, lldev->instance);
11441256Syl150051 goto _exit_cleanup;
11451256Syl150051 }
11461256Syl150051 freemsg(bp->b_cont);
11471256Syl150051 bp->b_cont = nmp;
11481256Syl150051 }
11491256Syl150051 }
11501256Syl150051
11513115Syl150051 /* finalize unfinished copies */
11523115Syl150051 if (used_copy) {
11538275SEric Cheng xge_hal_fifo_dtr_buffer_finalize(ring->channelh, dtr,
11543115Syl150051 frag_cnt++);
11553115Syl150051 }
11563115Syl150051
11571256Syl150051 txd_priv->handle_cnt = handle_cnt;
11581256Syl150051
11593115Syl150051 /*
11603115Syl150051 * If LSO is required, just call xge_hal_fifo_dtr_mss_set(dtr, mss) to
11613115Syl150051 * do all necessary work.
11623115Syl150051 */
1163*11878SVenu.Iyer@Sun.COM mac_lso_get(mp, &mss, &lsoflags);
11648275SEric Cheng
11658275SEric Cheng if (lsoflags & HW_LSO) {
11668275SEric Cheng xge_assert((mss != 0) && (mss <= XGE_HAL_DEFAULT_MTU));
11673115Syl150051 xge_hal_fifo_dtr_mss_set(dtr, mss);
11683115Syl150051 }
11693115Syl150051
1170*11878SVenu.Iyer@Sun.COM mac_hcksum_get(mp, NULL, NULL, NULL, NULL, &hckflags);
11713115Syl150051 if (hckflags & HCK_IPV4_HDRCKSUM) {
11721256Syl150051 xge_hal_fifo_dtr_cksum_set_bits(dtr,
11731256Syl150051 XGE_HAL_TXD_TX_CKO_IPV4_EN);
11741256Syl150051 }
11753115Syl150051 if (hckflags & HCK_FULLCKSUM) {
11761256Syl150051 xge_hal_fifo_dtr_cksum_set_bits(dtr, XGE_HAL_TXD_TX_CKO_TCP_EN |
11771256Syl150051 XGE_HAL_TXD_TX_CKO_UDP_EN);
11781256Syl150051 }
11791256Syl150051
11808275SEric Cheng xge_hal_fifo_dtr_post(ring->channelh, dtr);
11818275SEric Cheng
1182*11878SVenu.Iyer@Sun.COM /* Update per-ring tx statistics */
1183*11878SVenu.Iyer@Sun.COM atomic_add_64(&ring->tx_pkts, 1);
1184*11878SVenu.Iyer@Sun.COM atomic_add_64(&ring->tx_bytes, sent_bytes);
1185*11878SVenu.Iyer@Sun.COM
11868275SEric Cheng return (NULL);
11871256Syl150051
11881256Syl150051 _exit_cleanup:
11898275SEric Cheng /*
11908275SEric Cheng * Could not successfully transmit but have changed the message,
11918275SEric Cheng * so just free it and return NULL
11928275SEric Cheng */
11931256Syl150051 for (i = 0; i < handle_cnt; i++) {
11941256Syl150051 (void) ddi_dma_unbind_handle(txd_priv->dma_handles[i]);
11951256Syl150051 ddi_dma_free_handle(&txd_priv->dma_handles[i]);
11961256Syl150051 txd_priv->dma_handles[i] = 0;
11971256Syl150051 }
11981256Syl150051
11998275SEric Cheng xge_hal_fifo_dtr_free(ring->channelh, dtr);
12008275SEric Cheng
12018275SEric Cheng freemsg(mp);
12028275SEric Cheng return (NULL);
12031256Syl150051
12041256Syl150051 _exit:
12058275SEric Cheng ring->need_resched = B_TRUE;
12068275SEric Cheng return (mp);
12078275SEric Cheng }
12088275SEric Cheng
12098275SEric Cheng /*
12108275SEric Cheng * xgell_ring_macaddr_init
12118275SEric Cheng */
12128275SEric Cheng static void
xgell_rx_ring_maddr_init(xgell_rx_ring_t * ring)12138275SEric Cheng xgell_rx_ring_maddr_init(xgell_rx_ring_t *ring)
12148275SEric Cheng {
12158275SEric Cheng int i;
12168275SEric Cheng xgelldev_t *lldev = ring->lldev;
12178275SEric Cheng xge_hal_device_t *hldev = lldev->devh;
12188275SEric Cheng int slot_start;
12198275SEric Cheng
12208275SEric Cheng xge_debug_ll(XGE_TRACE, "%s", "xgell_rx_ring_maddr_init");
12218275SEric Cheng
12228275SEric Cheng ring->mmac.naddr = XGE_RX_MULTI_MAC_ADDRESSES_MAX;
12238275SEric Cheng ring->mmac.naddrfree = ring->mmac.naddr;
12248275SEric Cheng
12258275SEric Cheng /*
12268275SEric Cheng * For the default rx ring, the first MAC address is the factory one.
12278275SEric Cheng * This will be set by the framework, so need to clear it for now.
12288275SEric Cheng */
12298275SEric Cheng (void) xge_hal_device_macaddr_clear(hldev, 0);
12308275SEric Cheng
12318275SEric Cheng /*
12328275SEric Cheng * Read the MAC address Configuration Memory from HAL.
12338275SEric Cheng * The first slot will hold a factory MAC address, contents in other
12348275SEric Cheng * slots will be FF:FF:FF:FF:FF:FF.
12358275SEric Cheng */
12368275SEric Cheng slot_start = ring->index * 32;
12378275SEric Cheng for (i = 0; i < ring->mmac.naddr; i++) {
12388275SEric Cheng (void) xge_hal_device_macaddr_get(hldev, slot_start + i,
12398275SEric Cheng ring->mmac.mac_addr + i);
12408275SEric Cheng ring->mmac.mac_addr_set[i] = B_FALSE;
12418275SEric Cheng }
12428275SEric Cheng }
12438275SEric Cheng
12448275SEric Cheng static int xgell_maddr_set(xgelldev_t *, int, uint8_t *);
12458275SEric Cheng
12468275SEric Cheng static int
xgell_addmac(void * arg,const uint8_t * mac_addr)12478275SEric Cheng xgell_addmac(void *arg, const uint8_t *mac_addr)
12488275SEric Cheng {
12498275SEric Cheng xgell_rx_ring_t *ring = arg;
12508275SEric Cheng xgelldev_t *lldev = ring->lldev;
12518275SEric Cheng xge_hal_device_t *hldev = lldev->devh;
12528275SEric Cheng int slot;
12538275SEric Cheng int slot_start;
12548275SEric Cheng
12558275SEric Cheng xge_debug_ll(XGE_TRACE, "%s", "xgell_addmac");
12568275SEric Cheng
12578275SEric Cheng mutex_enter(&lldev->genlock);
12588275SEric Cheng
12598275SEric Cheng if (ring->mmac.naddrfree == 0) {
12608275SEric Cheng mutex_exit(&lldev->genlock);
12618275SEric Cheng return (ENOSPC);
12628275SEric Cheng }
12638275SEric Cheng
12648275SEric Cheng /* First slot is for factory MAC address */
12658275SEric Cheng for (slot = 0; slot < ring->mmac.naddr; slot++) {
12668275SEric Cheng if (ring->mmac.mac_addr_set[slot] == B_FALSE) {
12678275SEric Cheng break;
12681256Syl150051 }
12691256Syl150051 }
12701256Syl150051
12718275SEric Cheng ASSERT(slot < ring->mmac.naddr);
12728275SEric Cheng
12738275SEric Cheng slot_start = ring->index * 32;
12748275SEric Cheng
12758275SEric Cheng if (xgell_maddr_set(lldev, slot_start + slot, (uint8_t *)mac_addr) !=
12768275SEric Cheng 0) {
12778275SEric Cheng mutex_exit(&lldev->genlock);
12788275SEric Cheng return (EIO);
12798275SEric Cheng }
12808275SEric Cheng
12818275SEric Cheng /* Simply enable RTS for the whole section. */
12828275SEric Cheng (void) xge_hal_device_rts_section_enable(hldev, slot_start + slot);
12838275SEric Cheng
12848275SEric Cheng /*
12858275SEric Cheng * Read back the MAC address from HAL to keep the array up to date.
12868275SEric Cheng */
12878275SEric Cheng if (xge_hal_device_macaddr_get(hldev, slot_start + slot,
12888275SEric Cheng ring->mmac.mac_addr + slot) != XGE_HAL_OK) {
12898275SEric Cheng (void) xge_hal_device_macaddr_clear(hldev, slot_start + slot);
12908275SEric Cheng return (EIO);
12918275SEric Cheng }
12928275SEric Cheng
12938275SEric Cheng ring->mmac.mac_addr_set[slot] = B_TRUE;
12948275SEric Cheng ring->mmac.naddrfree--;
12958275SEric Cheng
12968275SEric Cheng mutex_exit(&lldev->genlock);
12978275SEric Cheng
12988275SEric Cheng return (0);
12998275SEric Cheng }
13008275SEric Cheng
13018275SEric Cheng static int
xgell_remmac(void * arg,const uint8_t * mac_addr)13028275SEric Cheng xgell_remmac(void *arg, const uint8_t *mac_addr)
13038275SEric Cheng {
13048275SEric Cheng xgell_rx_ring_t *ring = arg;
13058275SEric Cheng xgelldev_t *lldev = ring->lldev;
13068275SEric Cheng xge_hal_device_t *hldev = lldev->devh;
13078275SEric Cheng xge_hal_status_e status;
13088275SEric Cheng int slot;
13098275SEric Cheng int slot_start;
13108275SEric Cheng
13118275SEric Cheng xge_debug_ll(XGE_TRACE, "%s", "xgell_remmac");
13128275SEric Cheng
13138275SEric Cheng slot = xge_hal_device_macaddr_find(hldev, (uint8_t *)mac_addr);
13148275SEric Cheng if (slot == -1)
13158275SEric Cheng return (EINVAL);
13168275SEric Cheng
13178275SEric Cheng slot_start = ring->index * 32;
13188275SEric Cheng
13198275SEric Cheng /*
13208275SEric Cheng * Adjust slot to the offset in the MAC array of this ring (group).
13218275SEric Cheng */
13228275SEric Cheng slot -= slot_start;
13238275SEric Cheng
13248275SEric Cheng /*
13258275SEric Cheng * Only can remove a pre-set MAC address for this ring (group).
13268275SEric Cheng */
13278275SEric Cheng if (slot < 0 || slot >= ring->mmac.naddr)
13288275SEric Cheng return (EINVAL);
13298275SEric Cheng
13308275SEric Cheng
13318275SEric Cheng xge_assert(ring->mmac.mac_addr_set[slot]);
13328275SEric Cheng
13338275SEric Cheng mutex_enter(&lldev->genlock);
13348275SEric Cheng if (!ring->mmac.mac_addr_set[slot]) {
13358275SEric Cheng mutex_exit(&lldev->genlock);
13368275SEric Cheng /*
13378275SEric Cheng * The result will be unexpected when reach here. WARNING!
13388275SEric Cheng */
13398275SEric Cheng xge_debug_ll(XGE_ERR,
13408275SEric Cheng "%s%d: caller is trying to remove an unset MAC address",
13418275SEric Cheng XGELL_IFNAME, lldev->instance);
13428275SEric Cheng return (ENXIO);
13438275SEric Cheng }
13448275SEric Cheng
13458275SEric Cheng status = xge_hal_device_macaddr_clear(hldev, slot_start + slot);
13468275SEric Cheng if (status != XGE_HAL_OK) {
13478275SEric Cheng mutex_exit(&lldev->genlock);
13488275SEric Cheng return (EIO);
13498275SEric Cheng }
13508275SEric Cheng
13518275SEric Cheng ring->mmac.mac_addr_set[slot] = B_FALSE;
13528275SEric Cheng ring->mmac.naddrfree++;
13538275SEric Cheng
13548275SEric Cheng /*
13558275SEric Cheng * TODO: Disable MAC RTS if all addresses have been cleared.
13568275SEric Cheng */
13578275SEric Cheng
13588275SEric Cheng /*
13598275SEric Cheng * Read back the MAC address from HAL to keep the array up to date.
13608275SEric Cheng */
13618275SEric Cheng (void) xge_hal_device_macaddr_get(hldev, slot_start + slot,
13628275SEric Cheng ring->mmac.mac_addr + slot);
13638275SEric Cheng mutex_exit(&lldev->genlock);
13648275SEric Cheng
13658275SEric Cheng return (0);
13661256Syl150051 }
13671256Syl150051
13681256Syl150051 /*
13698275SEric Cheng * Temporarily calling hal function.
13701256Syl150051 *
13718275SEric Cheng * With MSI-X implementation, no lock is needed, so that the interrupt
13728275SEric Cheng * handling could be faster.
13731256Syl150051 */
13748275SEric Cheng int
xgell_rx_ring_intr_enable(mac_intr_handle_t ih)13758275SEric Cheng xgell_rx_ring_intr_enable(mac_intr_handle_t ih)
13768275SEric Cheng {
13778275SEric Cheng xgell_rx_ring_t *ring = (xgell_rx_ring_t *)ih;
13788275SEric Cheng
13798275SEric Cheng mutex_enter(&ring->ring_lock);
13808275SEric Cheng xge_hal_device_rx_channel_disable_polling(ring->channelh);
13818275SEric Cheng mutex_exit(&ring->ring_lock);
13828275SEric Cheng
13838275SEric Cheng return (0);
13848275SEric Cheng }
13858275SEric Cheng
13868275SEric Cheng int
xgell_rx_ring_intr_disable(mac_intr_handle_t ih)13878275SEric Cheng xgell_rx_ring_intr_disable(mac_intr_handle_t ih)
13888275SEric Cheng {
13898275SEric Cheng xgell_rx_ring_t *ring = (xgell_rx_ring_t *)ih;
13908275SEric Cheng
13918275SEric Cheng mutex_enter(&ring->ring_lock);
13928275SEric Cheng xge_hal_device_rx_channel_enable_polling(ring->channelh);
13938275SEric Cheng mutex_exit(&ring->ring_lock);
13948275SEric Cheng
13958275SEric Cheng return (0);
13968275SEric Cheng }
13978275SEric Cheng
13988275SEric Cheng static int
xgell_rx_ring_start(mac_ring_driver_t rh,uint64_t mr_gen_num)13998275SEric Cheng xgell_rx_ring_start(mac_ring_driver_t rh, uint64_t mr_gen_num)
14008275SEric Cheng {
14018275SEric Cheng xgell_rx_ring_t *rx_ring = (xgell_rx_ring_t *)rh;
14028275SEric Cheng
14038275SEric Cheng rx_ring->ring_gen_num = mr_gen_num;
14048275SEric Cheng
14058275SEric Cheng return (0);
14068275SEric Cheng }
14078275SEric Cheng
14088275SEric Cheng /*ARGSUSED*/
14098275SEric Cheng static void
xgell_rx_ring_stop(mac_ring_driver_t rh)14108275SEric Cheng xgell_rx_ring_stop(mac_ring_driver_t rh)
14118275SEric Cheng {
14128275SEric Cheng }
14138275SEric Cheng
14148275SEric Cheng /*ARGSUSED*/
14158275SEric Cheng static int
xgell_tx_ring_start(mac_ring_driver_t rh,uint64_t useless)14168275SEric Cheng xgell_tx_ring_start(mac_ring_driver_t rh, uint64_t useless)
14178275SEric Cheng {
14188275SEric Cheng return (0);
14198275SEric Cheng }
14208275SEric Cheng
14218275SEric Cheng /*ARGSUSED*/
14228275SEric Cheng static void
xgell_tx_ring_stop(mac_ring_driver_t rh)14238275SEric Cheng xgell_tx_ring_stop(mac_ring_driver_t rh)
14248275SEric Cheng {
14258275SEric Cheng }
14268275SEric Cheng
14278275SEric Cheng /*
14288275SEric Cheng * Callback funtion for MAC layer to register all rings.
14298275SEric Cheng *
14308275SEric Cheng * Xframe hardware doesn't support grouping explicitly, so the driver needs
14318275SEric Cheng * to pretend having resource groups. We may also optionally group all 8 rx
14328275SEric Cheng * rings into a single group for increased scalability on CMT architectures,
14338275SEric Cheng * or group one rx ring per group for maximum virtualization.
14348275SEric Cheng *
14358275SEric Cheng * TX grouping is actually done by framework, so, just register all TX
14368275SEric Cheng * resources without grouping them.
14378275SEric Cheng */
14388275SEric Cheng void
xgell_fill_ring(void * arg,mac_ring_type_t rtype,const int rg_index,const int index,mac_ring_info_t * infop,mac_ring_handle_t rh)14398275SEric Cheng xgell_fill_ring(void *arg, mac_ring_type_t rtype, const int rg_index,
14408275SEric Cheng const int index, mac_ring_info_t *infop, mac_ring_handle_t rh)
14411256Syl150051 {
14428275SEric Cheng xgelldev_t *lldev = (xgelldev_t *)arg;
14438275SEric Cheng mac_intr_t *mintr;
14448275SEric Cheng
14458275SEric Cheng switch (rtype) {
14468275SEric Cheng case MAC_RING_TYPE_RX: {
14478275SEric Cheng xgell_rx_ring_t *rx_ring;
14488275SEric Cheng
14498275SEric Cheng xge_assert(index < lldev->init_rx_rings);
14508275SEric Cheng xge_assert(rg_index < lldev->init_rx_groups);
14518275SEric Cheng
14528275SEric Cheng /*
14538275SEric Cheng * Performance vs. Virtualization
14548275SEric Cheng */
14558275SEric Cheng if (lldev->init_rx_rings == lldev->init_rx_groups)
14568275SEric Cheng rx_ring = lldev->rx_ring + rg_index;
14578275SEric Cheng else
14588275SEric Cheng rx_ring = lldev->rx_ring + index;
14598275SEric Cheng
14608275SEric Cheng rx_ring->ring_handle = rh;
14618275SEric Cheng
14628275SEric Cheng infop->mri_driver = (mac_ring_driver_t)rx_ring;
14638275SEric Cheng infop->mri_start = xgell_rx_ring_start;
14648275SEric Cheng infop->mri_stop = xgell_rx_ring_stop;
14658275SEric Cheng infop->mri_poll = xgell_rx_poll;
1466*11878SVenu.Iyer@Sun.COM infop->mri_stat = xgell_rx_ring_stat;
14678275SEric Cheng
14688275SEric Cheng mintr = &infop->mri_intr;
14698275SEric Cheng mintr->mi_handle = (mac_intr_handle_t)rx_ring;
14708275SEric Cheng mintr->mi_enable = xgell_rx_ring_intr_enable;
14718275SEric Cheng mintr->mi_disable = xgell_rx_ring_intr_disable;
14728275SEric Cheng
14738275SEric Cheng break;
14748275SEric Cheng }
14758275SEric Cheng case MAC_RING_TYPE_TX: {
14768275SEric Cheng xgell_tx_ring_t *tx_ring;
14778275SEric Cheng
14788275SEric Cheng xge_assert(rg_index == -1);
14798275SEric Cheng
14808275SEric Cheng xge_assert((index >= 0) && (index < lldev->init_tx_rings));
14818275SEric Cheng
14828275SEric Cheng tx_ring = lldev->tx_ring + index;
14838275SEric Cheng tx_ring->ring_handle = rh;
14848275SEric Cheng
14858275SEric Cheng infop->mri_driver = (mac_ring_driver_t)tx_ring;
14868275SEric Cheng infop->mri_start = xgell_tx_ring_start;
14878275SEric Cheng infop->mri_stop = xgell_tx_ring_stop;
14888275SEric Cheng infop->mri_tx = xgell_ring_tx;
1489*11878SVenu.Iyer@Sun.COM infop->mri_stat = xgell_tx_ring_stat;
14908275SEric Cheng
14918275SEric Cheng break;
14928275SEric Cheng }
14938275SEric Cheng default:
14948275SEric Cheng break;
14951256Syl150051 }
14968275SEric Cheng }
14978275SEric Cheng
14988275SEric Cheng void
xgell_fill_group(void * arg,mac_ring_type_t rtype,const int index,mac_group_info_t * infop,mac_group_handle_t gh)14998275SEric Cheng xgell_fill_group(void *arg, mac_ring_type_t rtype, const int index,
15008275SEric Cheng mac_group_info_t *infop, mac_group_handle_t gh)
15018275SEric Cheng {
15028275SEric Cheng xgelldev_t *lldev = (xgelldev_t *)arg;
15038275SEric Cheng
15048275SEric Cheng switch (rtype) {
15058275SEric Cheng case MAC_RING_TYPE_RX: {
15068275SEric Cheng xgell_rx_ring_t *rx_ring;
15078275SEric Cheng
15088275SEric Cheng xge_assert(index < lldev->init_rx_groups);
15098275SEric Cheng
15108275SEric Cheng rx_ring = lldev->rx_ring + index;
15118275SEric Cheng
15128275SEric Cheng rx_ring->group_handle = gh;
15138275SEric Cheng
15148275SEric Cheng infop->mgi_driver = (mac_group_driver_t)rx_ring;
15158275SEric Cheng infop->mgi_start = NULL;
15168275SEric Cheng infop->mgi_stop = NULL;
15178275SEric Cheng infop->mgi_addmac = xgell_addmac;
15188275SEric Cheng infop->mgi_remmac = xgell_remmac;
15198275SEric Cheng infop->mgi_count = lldev->init_rx_rings / lldev->init_rx_groups;
15208275SEric Cheng
15218275SEric Cheng break;
15228275SEric Cheng }
15238275SEric Cheng case MAC_RING_TYPE_TX:
15248275SEric Cheng xge_assert(0);
15258275SEric Cheng break;
15268275SEric Cheng default:
15278275SEric Cheng break;
15288275SEric Cheng }
15298275SEric Cheng }
15308275SEric Cheng
15318275SEric Cheng /*
15328275SEric Cheng * xgell_macaddr_set
15338275SEric Cheng */
15348275SEric Cheng static int
xgell_maddr_set(xgelldev_t * lldev,int index,uint8_t * macaddr)15358275SEric Cheng xgell_maddr_set(xgelldev_t *lldev, int index, uint8_t *macaddr)
15368275SEric Cheng {
15378275SEric Cheng xge_hal_device_t *hldev = lldev->devh;
15388275SEric Cheng xge_hal_status_e status;
15398275SEric Cheng
15408275SEric Cheng xge_debug_ll(XGE_TRACE, "%s", "xgell_maddr_set");
15418275SEric Cheng
15428275SEric Cheng xge_debug_ll(XGE_TRACE,
15438275SEric Cheng "setting macaddr: 0x%02x-%02x-%02x-%02x-%02x-%02x",
15448275SEric Cheng macaddr[0], macaddr[1], macaddr[2],
15458275SEric Cheng macaddr[3], macaddr[4], macaddr[5]);
15468275SEric Cheng
15478275SEric Cheng status = xge_hal_device_macaddr_set(hldev, index, (uchar_t *)macaddr);
15488275SEric Cheng
15498275SEric Cheng if (status != XGE_HAL_OK) {
15508275SEric Cheng xge_debug_ll(XGE_ERR, "%s%d: can not set mac address",
15518275SEric Cheng XGELL_IFNAME, lldev->instance);
15528275SEric Cheng return (EIO);
15538275SEric Cheng }
15548275SEric Cheng
15558275SEric Cheng return (0);
15561256Syl150051 }
15571256Syl150051
15581256Syl150051 /*
15591256Syl150051 * xgell_rx_dtr_term
15601256Syl150051 *
15611256Syl150051 * Function will be called by HAL to terminate all DTRs for
15621256Syl150051 * Ring(s) type of channels.
15631256Syl150051 */
15641256Syl150051 static void
xgell_rx_dtr_term(xge_hal_channel_h channelh,xge_hal_dtr_h dtrh,xge_hal_dtr_state_e state,void * userdata,xge_hal_channel_reopen_e reopen)15651256Syl150051 xgell_rx_dtr_term(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh,
15661256Syl150051 xge_hal_dtr_state_e state, void *userdata, xge_hal_channel_reopen_e reopen)
15671256Syl150051 {
15681256Syl150051 xgell_rxd_priv_t *rxd_priv =
15691256Syl150051 ((xgell_rxd_priv_t *)xge_hal_ring_dtr_private(channelh, dtrh));
15701256Syl150051 xgell_rx_buffer_t *rx_buffer = rxd_priv->rx_buffer;
15711256Syl150051
15721256Syl150051 if (state == XGE_HAL_DTR_STATE_POSTED) {
15738275SEric Cheng xgell_rx_ring_t *ring = rx_buffer->ring;
15748275SEric Cheng
15756937Sxw161283 mutex_enter(&ring->bf_pool.pool_lock);
15761256Syl150051 xge_hal_ring_dtr_free(channelh, dtrh);
15771256Syl150051 xgell_rx_buffer_release(rx_buffer);
15786937Sxw161283 mutex_exit(&ring->bf_pool.pool_lock);
15791256Syl150051 }
15801256Syl150051 }
15811256Syl150051
15821256Syl150051 /*
15838275SEric Cheng * To open a rx ring.
15848275SEric Cheng */
15858275SEric Cheng static boolean_t
xgell_rx_ring_open(xgell_rx_ring_t * rx_ring)15868275SEric Cheng xgell_rx_ring_open(xgell_rx_ring_t *rx_ring)
15878275SEric Cheng {
15888275SEric Cheng xge_hal_status_e status;
15898275SEric Cheng xge_hal_channel_attr_t attr;
15908275SEric Cheng xgelldev_t *lldev = rx_ring->lldev;
15918275SEric Cheng xge_hal_device_t *hldev = lldev->devh;
15928275SEric Cheng
15938275SEric Cheng if (rx_ring->live)
15948275SEric Cheng return (B_TRUE);
15958275SEric Cheng
15968275SEric Cheng /* Create the buffer pool first */
15978275SEric Cheng if (!xgell_rx_create_buffer_pool(rx_ring)) {
15988275SEric Cheng xge_debug_ll(XGE_ERR, "can not create buffer pool for ring: %d",
15998275SEric Cheng rx_ring->index);
16008275SEric Cheng return (B_FALSE);
16018275SEric Cheng }
16028275SEric Cheng
16038275SEric Cheng /* Default ring initialization */
16048275SEric Cheng attr.post_qid = rx_ring->index;
16058275SEric Cheng attr.compl_qid = 0;
16068275SEric Cheng attr.callback = xgell_rx_1b_callback;
16078275SEric Cheng attr.per_dtr_space = sizeof (xgell_rxd_priv_t);
16088275SEric Cheng attr.flags = 0;
16098275SEric Cheng attr.type = XGE_HAL_CHANNEL_TYPE_RING;
16108275SEric Cheng attr.dtr_init = xgell_rx_dtr_replenish;
16118275SEric Cheng attr.dtr_term = xgell_rx_dtr_term;
16128275SEric Cheng attr.userdata = rx_ring;
16138275SEric Cheng
16148275SEric Cheng status = xge_hal_channel_open(lldev->devh, &attr, &rx_ring->channelh,
16158275SEric Cheng XGE_HAL_CHANNEL_OC_NORMAL);
16168275SEric Cheng if (status != XGE_HAL_OK) {
16178275SEric Cheng xge_debug_ll(XGE_ERR, "%s%d: cannot open Rx channel got status "
16188275SEric Cheng " code %d", XGELL_IFNAME, lldev->instance, status);
16198275SEric Cheng (void) xgell_rx_destroy_buffer_pool(rx_ring);
16208275SEric Cheng return (B_FALSE);
16218275SEric Cheng }
16228275SEric Cheng
16238275SEric Cheng xgell_rx_ring_maddr_init(rx_ring);
16248275SEric Cheng
16258275SEric Cheng mutex_init(&rx_ring->ring_lock, NULL, MUTEX_DRIVER,
16268275SEric Cheng DDI_INTR_PRI(hldev->irqh));
16278275SEric Cheng
16288275SEric Cheng rx_ring->poll_bytes = -1;
16298275SEric Cheng rx_ring->polled_bytes = 0;
16308275SEric Cheng rx_ring->poll_mp = NULL;
16318275SEric Cheng rx_ring->live = B_TRUE;
16328275SEric Cheng
16338275SEric Cheng xge_debug_ll(XGE_TRACE, "RX ring [%d] is opened successfully",
16348275SEric Cheng rx_ring->index);
16358275SEric Cheng
16368275SEric Cheng return (B_TRUE);
16378275SEric Cheng }
16388275SEric Cheng
16398275SEric Cheng static void
xgell_rx_ring_close(xgell_rx_ring_t * rx_ring)16408275SEric Cheng xgell_rx_ring_close(xgell_rx_ring_t *rx_ring)
16418275SEric Cheng {
16428275SEric Cheng if (!rx_ring->live)
16438275SEric Cheng return;
16448275SEric Cheng xge_hal_channel_close(rx_ring->channelh, XGE_HAL_CHANNEL_OC_NORMAL);
16458275SEric Cheng rx_ring->channelh = NULL;
16468275SEric Cheng /* This may not clean up all used buffers, driver will handle it */
16478275SEric Cheng if (xgell_rx_destroy_buffer_pool(rx_ring))
16488275SEric Cheng rx_ring->live = B_FALSE;
16498275SEric Cheng
16508275SEric Cheng mutex_destroy(&rx_ring->ring_lock);
16518275SEric Cheng }
16528275SEric Cheng
16538275SEric Cheng /*
16548275SEric Cheng * xgell_rx_open
16558275SEric Cheng * @lldev: the link layer object
16568275SEric Cheng *
16578275SEric Cheng * Initialize and open all RX channels.
16588275SEric Cheng */
16598275SEric Cheng static boolean_t
xgell_rx_open(xgelldev_t * lldev)16608275SEric Cheng xgell_rx_open(xgelldev_t *lldev)
16618275SEric Cheng {
16628275SEric Cheng xgell_rx_ring_t *rx_ring;
16638275SEric Cheng int i;
16648275SEric Cheng
16658275SEric Cheng if (lldev->live_rx_rings != 0)
16668275SEric Cheng return (B_TRUE);
16678275SEric Cheng
16688275SEric Cheng lldev->live_rx_rings = 0;
16698275SEric Cheng
16708275SEric Cheng /*
16718275SEric Cheng * Initialize all rings
16728275SEric Cheng */
16738275SEric Cheng for (i = 0; i < lldev->init_rx_rings; i++) {
16748275SEric Cheng rx_ring = &lldev->rx_ring[i];
16758275SEric Cheng rx_ring->index = i;
16768275SEric Cheng rx_ring->lldev = lldev;
16778275SEric Cheng rx_ring->live = B_FALSE;
16788275SEric Cheng
16798275SEric Cheng if (!xgell_rx_ring_open(rx_ring))
16808275SEric Cheng return (B_FALSE);
16818275SEric Cheng
16828275SEric Cheng lldev->live_rx_rings++;
16838275SEric Cheng }
16848275SEric Cheng
16858275SEric Cheng return (B_TRUE);
16868275SEric Cheng }
16878275SEric Cheng
16888275SEric Cheng static void
xgell_rx_close(xgelldev_t * lldev)16898275SEric Cheng xgell_rx_close(xgelldev_t *lldev)
16908275SEric Cheng {
16918275SEric Cheng xgell_rx_ring_t *rx_ring;
16928275SEric Cheng int i;
16938275SEric Cheng
16948275SEric Cheng if (lldev->live_rx_rings == 0)
16958275SEric Cheng return;
16968275SEric Cheng
16978275SEric Cheng /*
16988275SEric Cheng * Close all rx rings
16998275SEric Cheng */
17008275SEric Cheng for (i = 0; i < lldev->init_rx_rings; i++) {
17018275SEric Cheng rx_ring = &lldev->rx_ring[i];
17028275SEric Cheng
17038275SEric Cheng if (rx_ring->live) {
17048275SEric Cheng xgell_rx_ring_close(rx_ring);
17058275SEric Cheng lldev->live_rx_rings--;
17068275SEric Cheng }
17078275SEric Cheng }
17088275SEric Cheng
17098275SEric Cheng xge_assert(lldev->live_rx_rings == 0);
17108275SEric Cheng }
17118275SEric Cheng
17128275SEric Cheng /*
17131256Syl150051 * xgell_tx_term
17141256Syl150051 *
17151256Syl150051 * Function will be called by HAL to terminate all DTRs for
17161256Syl150051 * Fifo(s) type of channels.
17171256Syl150051 */
17181256Syl150051 static void
xgell_tx_term(xge_hal_channel_h channelh,xge_hal_dtr_h dtrh,xge_hal_dtr_state_e state,void * userdata,xge_hal_channel_reopen_e reopen)17191256Syl150051 xgell_tx_term(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh,
17201256Syl150051 xge_hal_dtr_state_e state, void *userdata, xge_hal_channel_reopen_e reopen)
17211256Syl150051 {
17221256Syl150051 xgell_txd_priv_t *txd_priv =
17231256Syl150051 ((xgell_txd_priv_t *)xge_hal_fifo_dtr_private(dtrh));
17241256Syl150051 mblk_t *mp = txd_priv->mblk;
17251256Syl150051 int i;
17263115Syl150051
17271256Syl150051 /*
17281256Syl150051 * for Tx we must clean up the DTR *only* if it has been
17291256Syl150051 * posted!
17301256Syl150051 */
17311256Syl150051 if (state != XGE_HAL_DTR_STATE_POSTED) {
17321256Syl150051 return;
17331256Syl150051 }
17341256Syl150051
17351256Syl150051 for (i = 0; i < txd_priv->handle_cnt; i++) {
17361256Syl150051 xge_assert(txd_priv->dma_handles[i]);
17371256Syl150051 (void) ddi_dma_unbind_handle(txd_priv->dma_handles[i]);
17381256Syl150051 ddi_dma_free_handle(&txd_priv->dma_handles[i]);
17391256Syl150051 txd_priv->dma_handles[i] = 0;
17401256Syl150051 }
17411256Syl150051
17421256Syl150051 xge_hal_fifo_dtr_free(channelh, dtrh);
17431256Syl150051
17446937Sxw161283 if (mp) {
17456937Sxw161283 txd_priv->mblk = NULL;
17466937Sxw161283 freemsg(mp);
17476937Sxw161283 }
17486937Sxw161283 }
17496937Sxw161283
17508275SEric Cheng static boolean_t
xgell_tx_ring_open(xgell_tx_ring_t * tx_ring)17518275SEric Cheng xgell_tx_ring_open(xgell_tx_ring_t *tx_ring)
17526937Sxw161283 {
17538275SEric Cheng xge_hal_status_e status;
17548275SEric Cheng xge_hal_channel_attr_t attr;
17558275SEric Cheng xgelldev_t *lldev = tx_ring->lldev;
17568275SEric Cheng
17578275SEric Cheng if (tx_ring->live)
17588275SEric Cheng return (B_TRUE);
17598275SEric Cheng
17608275SEric Cheng attr.post_qid = tx_ring->index;
17618275SEric Cheng attr.compl_qid = 0;
17628275SEric Cheng attr.callback = xgell_xmit_compl;
17638275SEric Cheng attr.per_dtr_space = sizeof (xgell_txd_priv_t);
17648275SEric Cheng attr.flags = 0;
17658275SEric Cheng attr.type = XGE_HAL_CHANNEL_TYPE_FIFO;
17668275SEric Cheng attr.dtr_init = NULL;
17678275SEric Cheng attr.dtr_term = xgell_tx_term;
17688275SEric Cheng attr.userdata = tx_ring;
17698275SEric Cheng
17708275SEric Cheng status = xge_hal_channel_open(lldev->devh, &attr, &tx_ring->channelh,
17718275SEric Cheng XGE_HAL_CHANNEL_OC_NORMAL);
17728275SEric Cheng if (status != XGE_HAL_OK) {
17738275SEric Cheng xge_debug_ll(XGE_ERR, "%s%d: cannot open Tx channel got status "
17748275SEric Cheng "code %d", XGELL_IFNAME, lldev->instance, status);
17758275SEric Cheng return (B_FALSE);
17766937Sxw161283 }
17778275SEric Cheng
17788275SEric Cheng tx_ring->live = B_TRUE;
17798275SEric Cheng
17808275SEric Cheng return (B_TRUE);
17818275SEric Cheng }
17828275SEric Cheng
17838275SEric Cheng static void
xgell_tx_ring_close(xgell_tx_ring_t * tx_ring)17848275SEric Cheng xgell_tx_ring_close(xgell_tx_ring_t *tx_ring)
17858275SEric Cheng {
17868275SEric Cheng if (!tx_ring->live)
17878275SEric Cheng return;
17888275SEric Cheng xge_hal_channel_close(tx_ring->channelh, XGE_HAL_CHANNEL_OC_NORMAL);
17898275SEric Cheng tx_ring->live = B_FALSE;
17901256Syl150051 }
17911256Syl150051
17921256Syl150051 /*
17931256Syl150051 * xgell_tx_open
17941256Syl150051 * @lldev: the link layer object
17951256Syl150051 *
17968275SEric Cheng * Initialize and open all TX channels.
17971256Syl150051 */
17981256Syl150051 static boolean_t
xgell_tx_open(xgelldev_t * lldev)17991256Syl150051 xgell_tx_open(xgelldev_t *lldev)
18001256Syl150051 {
18018275SEric Cheng xgell_tx_ring_t *tx_ring;
18028275SEric Cheng int i;
18038275SEric Cheng
18048275SEric Cheng if (lldev->live_tx_rings != 0)
18058275SEric Cheng return (B_TRUE);
18068275SEric Cheng
18078275SEric Cheng lldev->live_tx_rings = 0;
18081256Syl150051
18096937Sxw161283 /*
18108275SEric Cheng * Enable rings by reserve sequence to match the h/w sequences.
18116937Sxw161283 */
18128275SEric Cheng for (i = 0; i < lldev->init_tx_rings; i++) {
18138275SEric Cheng tx_ring = &lldev->tx_ring[i];
18148275SEric Cheng tx_ring->index = i;
18158275SEric Cheng tx_ring->lldev = lldev;
18168275SEric Cheng tx_ring->live = B_FALSE;
18178275SEric Cheng
18188275SEric Cheng if (!xgell_tx_ring_open(tx_ring))
18196937Sxw161283 return (B_FALSE);
18208275SEric Cheng
18218275SEric Cheng lldev->live_tx_rings++;
18221256Syl150051 }
18231256Syl150051
18241256Syl150051 return (B_TRUE);
18251256Syl150051 }
18261256Syl150051
18276937Sxw161283 static void
xgell_tx_close(xgelldev_t * lldev)18288275SEric Cheng xgell_tx_close(xgelldev_t *lldev)
18296937Sxw161283 {
18308275SEric Cheng xgell_tx_ring_t *tx_ring;
18318275SEric Cheng int i;
18328275SEric Cheng
18338275SEric Cheng if (lldev->live_tx_rings == 0)
18348275SEric Cheng return;
18351256Syl150051
18366937Sxw161283 /*
18378275SEric Cheng * Enable rings by reserve sequence to match the h/w sequences.
18386937Sxw161283 */
18398275SEric Cheng for (i = 0; i < lldev->init_tx_rings; i++) {
18408275SEric Cheng tx_ring = &lldev->tx_ring[i];
18418275SEric Cheng if (tx_ring->live) {
18428275SEric Cheng xgell_tx_ring_close(tx_ring);
18438275SEric Cheng lldev->live_tx_rings--;
18446937Sxw161283 }
18451256Syl150051 }
18461256Syl150051 }
18471256Syl150051
18481256Syl150051 static int
xgell_initiate_start(xgelldev_t * lldev)18491256Syl150051 xgell_initiate_start(xgelldev_t *lldev)
18501256Syl150051 {
18511256Syl150051 xge_hal_status_e status;
18521256Syl150051 xge_hal_device_t *hldev = lldev->devh;
18532311Sseb int maxpkt = hldev->config.mtu;
18541256Syl150051
18551256Syl150051 /* check initial mtu before enabling the device */
18561256Syl150051 status = xge_hal_device_mtu_check(lldev->devh, maxpkt);
18571256Syl150051 if (status != XGE_HAL_OK) {
18581256Syl150051 xge_debug_ll(XGE_ERR, "%s%d: MTU size %d is invalid",
18591256Syl150051 XGELL_IFNAME, lldev->instance, maxpkt);
18601256Syl150051 return (EINVAL);
18611256Syl150051 }
18621256Syl150051
18631256Syl150051 /* set initial mtu before enabling the device */
18641256Syl150051 status = xge_hal_device_mtu_set(lldev->devh, maxpkt);
18651256Syl150051 if (status != XGE_HAL_OK) {
18661256Syl150051 xge_debug_ll(XGE_ERR, "%s%d: can not set new MTU %d",
18671256Syl150051 XGELL_IFNAME, lldev->instance, maxpkt);
18681256Syl150051 return (EIO);
18691256Syl150051 }
18701256Syl150051
18713115Syl150051 /* tune jumbo/normal frame UFC counters */
18728275SEric Cheng hldev->config.ring.queue[XGELL_RX_RING_MAIN].rti.ufc_b =
18738275SEric Cheng (maxpkt > XGE_HAL_DEFAULT_MTU) ?
18746937Sxw161283 XGE_HAL_DEFAULT_RX_UFC_B_J :
18756937Sxw161283 XGE_HAL_DEFAULT_RX_UFC_B_N;
18763115Syl150051
18778275SEric Cheng hldev->config.ring.queue[XGELL_RX_RING_MAIN].rti.ufc_c =
18788275SEric Cheng (maxpkt > XGE_HAL_DEFAULT_MTU) ?
18796937Sxw161283 XGE_HAL_DEFAULT_RX_UFC_C_J :
18806937Sxw161283 XGE_HAL_DEFAULT_RX_UFC_C_N;
18813115Syl150051
18821256Syl150051 /* now, enable the device */
18831256Syl150051 status = xge_hal_device_enable(lldev->devh);
18841256Syl150051 if (status != XGE_HAL_OK) {
18851256Syl150051 xge_debug_ll(XGE_ERR, "%s%d: can not enable the device",
18861256Syl150051 XGELL_IFNAME, lldev->instance);
18871256Syl150051 return (EIO);
18881256Syl150051 }
18891256Syl150051
18901256Syl150051 if (!xgell_rx_open(lldev)) {
18911256Syl150051 status = xge_hal_device_disable(lldev->devh);
18921256Syl150051 if (status != XGE_HAL_OK) {
18931256Syl150051 u64 adapter_status;
18941256Syl150051 (void) xge_hal_device_status(lldev->devh,
18951256Syl150051 &adapter_status);
18961256Syl150051 xge_debug_ll(XGE_ERR, "%s%d: can not safely disable "
18971256Syl150051 "the device. adaper status 0x%"PRIx64
18981256Syl150051 " returned status %d",
18991256Syl150051 XGELL_IFNAME, lldev->instance,
19001256Syl150051 (uint64_t)adapter_status, status);
19011256Syl150051 }
19028275SEric Cheng xgell_rx_close(lldev);
19031256Syl150051 xge_os_mdelay(1500);
19041256Syl150051 return (ENOMEM);
19051256Syl150051 }
19061256Syl150051
19071256Syl150051 if (!xgell_tx_open(lldev)) {
19081256Syl150051 status = xge_hal_device_disable(lldev->devh);
19091256Syl150051 if (status != XGE_HAL_OK) {
19101256Syl150051 u64 adapter_status;
19111256Syl150051 (void) xge_hal_device_status(lldev->devh,
19121256Syl150051 &adapter_status);
19131256Syl150051 xge_debug_ll(XGE_ERR, "%s%d: can not safely disable "
19141256Syl150051 "the device. adaper status 0x%"PRIx64
19151256Syl150051 " returned status %d",
19161256Syl150051 XGELL_IFNAME, lldev->instance,
19171256Syl150051 (uint64_t)adapter_status, status);
19181256Syl150051 }
19198275SEric Cheng xgell_tx_close(lldev);
19206937Sxw161283 xgell_rx_close(lldev);
19218275SEric Cheng xge_os_mdelay(1500);
19221256Syl150051 return (ENOMEM);
19231256Syl150051 }
19241256Syl150051
19251256Syl150051 /* time to enable interrupts */
19266937Sxw161283 (void) xge_enable_intrs(lldev);
19271256Syl150051 xge_hal_device_intr_enable(lldev->devh);
19281256Syl150051
19291256Syl150051 lldev->is_initialized = 1;
19301256Syl150051
19311256Syl150051 return (0);
19321256Syl150051 }
19331256Syl150051
19341256Syl150051 static void
xgell_initiate_stop(xgelldev_t * lldev)19351256Syl150051 xgell_initiate_stop(xgelldev_t *lldev)
19361256Syl150051 {
19371256Syl150051 xge_hal_status_e status;
19381256Syl150051
19391256Syl150051 lldev->is_initialized = 0;
19401256Syl150051
19411256Syl150051 status = xge_hal_device_disable(lldev->devh);
19421256Syl150051 if (status != XGE_HAL_OK) {
19431256Syl150051 u64 adapter_status;
19441256Syl150051 (void) xge_hal_device_status(lldev->devh, &adapter_status);
19451256Syl150051 xge_debug_ll(XGE_ERR, "%s%d: can not safely disable "
19461256Syl150051 "the device. adaper status 0x%"PRIx64" returned status %d",
19471256Syl150051 XGELL_IFNAME, lldev->instance,
19481256Syl150051 (uint64_t)adapter_status, status);
19491256Syl150051 }
19501256Syl150051 xge_hal_device_intr_disable(lldev->devh);
19516937Sxw161283 /* disable OS ISR's */
19526937Sxw161283 xge_disable_intrs(lldev);
19531256Syl150051
19541256Syl150051 xge_debug_ll(XGE_TRACE, "%s",
19551256Syl150051 "waiting for device irq to become quiescent...");
19561256Syl150051 xge_os_mdelay(1500);
19571256Syl150051
19581256Syl150051 xge_queue_flush(xge_hal_device_queue(lldev->devh));
19591256Syl150051
19606937Sxw161283 xgell_rx_close(lldev);
19616937Sxw161283 xgell_tx_close(lldev);
19621256Syl150051 }
19631256Syl150051
19641256Syl150051 /*
19651256Syl150051 * xgell_m_start
19661256Syl150051 * @arg: pointer to device private strucutre(hldev)
19671256Syl150051 *
19681256Syl150051 * This function is called by MAC Layer to enable the XFRAME
19691256Syl150051 * firmware to generate interrupts and also prepare the
19701256Syl150051 * driver to call mac_rx for delivering receive packets
19711256Syl150051 * to MAC Layer.
19721256Syl150051 */
19731256Syl150051 static int
xgell_m_start(void * arg)19741256Syl150051 xgell_m_start(void *arg)
19751256Syl150051 {
19763115Syl150051 xgelldev_t *lldev = arg;
19773115Syl150051 xge_hal_device_t *hldev = lldev->devh;
19781256Syl150051 int ret;
19791256Syl150051
19801256Syl150051 xge_debug_ll(XGE_TRACE, "%s%d: M_START", XGELL_IFNAME,
19811256Syl150051 lldev->instance);
19821256Syl150051
19831256Syl150051 mutex_enter(&lldev->genlock);
19841256Syl150051
19851256Syl150051 if (lldev->is_initialized) {
19861256Syl150051 xge_debug_ll(XGE_ERR, "%s%d: device is already initialized",
19871256Syl150051 XGELL_IFNAME, lldev->instance);
19881256Syl150051 mutex_exit(&lldev->genlock);
19891256Syl150051 return (EINVAL);
19901256Syl150051 }
19911256Syl150051
19921256Syl150051 hldev->terminating = 0;
19931256Syl150051 if (ret = xgell_initiate_start(lldev)) {
19941256Syl150051 mutex_exit(&lldev->genlock);
19951256Syl150051 return (ret);
19961256Syl150051 }
19971256Syl150051
19981256Syl150051 lldev->timeout_id = timeout(xge_device_poll, hldev, XGE_DEV_POLL_TICKS);
19991256Syl150051
20001256Syl150051 mutex_exit(&lldev->genlock);
20011256Syl150051
20021256Syl150051 return (0);
20031256Syl150051 }
20041256Syl150051
20051256Syl150051 /*
20061256Syl150051 * xgell_m_stop
20071256Syl150051 * @arg: pointer to device private data (hldev)
20081256Syl150051 *
20091256Syl150051 * This function is called by the MAC Layer to disable
20101256Syl150051 * the XFRAME firmware for generating any interrupts and
20111256Syl150051 * also stop the driver from calling mac_rx() for
20121256Syl150051 * delivering data packets to the MAC Layer.
20131256Syl150051 */
20141256Syl150051 static void
xgell_m_stop(void * arg)20151256Syl150051 xgell_m_stop(void *arg)
20161256Syl150051 {
20173115Syl150051 xgelldev_t *lldev = arg;
20183115Syl150051 xge_hal_device_t *hldev = lldev->devh;
20191256Syl150051
20201256Syl150051 xge_debug_ll(XGE_TRACE, "%s", "MAC_STOP");
20211256Syl150051
20221256Syl150051 mutex_enter(&lldev->genlock);
20231256Syl150051 if (!lldev->is_initialized) {
20241256Syl150051 xge_debug_ll(XGE_ERR, "%s", "device is not initialized...");
20251256Syl150051 mutex_exit(&lldev->genlock);
20261256Syl150051 return;
20271256Syl150051 }
20281256Syl150051
20291256Syl150051 xge_hal_device_terminating(hldev);
20301256Syl150051 xgell_initiate_stop(lldev);
20311256Syl150051
20321256Syl150051 /* reset device */
20331256Syl150051 (void) xge_hal_device_reset(lldev->devh);
20341256Syl150051
20351256Syl150051 mutex_exit(&lldev->genlock);
20361256Syl150051
20373115Syl150051 if (lldev->timeout_id != 0) {
20383115Syl150051 (void) untimeout(lldev->timeout_id);
20393115Syl150051 }
20401256Syl150051
20411256Syl150051 xge_debug_ll(XGE_TRACE, "%s", "returning back to MAC Layer...");
20421256Syl150051 }
20431256Syl150051
20441256Syl150051 /*
20451256Syl150051 * xgell_onerr_reset
20461256Syl150051 * @lldev: pointer to xgelldev_t structure
20471256Syl150051 *
20481256Syl150051 * This function is called by HAL Event framework to reset the HW
20491256Syl150051 * This function is must be called with genlock taken.
20501256Syl150051 */
20511256Syl150051 int
xgell_onerr_reset(xgelldev_t * lldev)20521256Syl150051 xgell_onerr_reset(xgelldev_t *lldev)
20531256Syl150051 {
20541256Syl150051 int rc = 0;
20551256Syl150051
20561256Syl150051 if (!lldev->is_initialized) {
20571256Syl150051 xge_debug_ll(XGE_ERR, "%s%d: can not reset",
20581256Syl150051 XGELL_IFNAME, lldev->instance);
20591256Syl150051 return (rc);
20601256Syl150051 }
20611256Syl150051
20621256Syl150051 lldev->in_reset = 1;
20631256Syl150051 xgell_initiate_stop(lldev);
20641256Syl150051
20651256Syl150051 /* reset device */
20661256Syl150051 (void) xge_hal_device_reset(lldev->devh);
20671256Syl150051
20681256Syl150051 rc = xgell_initiate_start(lldev);
20691256Syl150051 lldev->in_reset = 0;
20701256Syl150051
20711256Syl150051 return (rc);
20721256Syl150051 }
20731256Syl150051
20741256Syl150051 /*
20751256Syl150051 * xgell_m_multicst
20761256Syl150051 * @arg: pointer to device private strucutre(hldev)
20771256Syl150051 * @add:
20781256Syl150051 * @mc_addr:
20791256Syl150051 *
20801256Syl150051 * This function is called by MAC Layer to enable or
20811256Syl150051 * disable device-level reception of specific multicast addresses.
20821256Syl150051 */
20831256Syl150051 static int
xgell_m_multicst(void * arg,boolean_t add,const uint8_t * mc_addr)20841256Syl150051 xgell_m_multicst(void *arg, boolean_t add, const uint8_t *mc_addr)
20851256Syl150051 {
20861256Syl150051 xge_hal_status_e status;
20873115Syl150051 xgelldev_t *lldev = (xgelldev_t *)arg;
20883115Syl150051 xge_hal_device_t *hldev = lldev->devh;
20891256Syl150051
20901256Syl150051 xge_debug_ll(XGE_TRACE, "M_MULTICAST add %d", add);
20911256Syl150051
20921256Syl150051 mutex_enter(&lldev->genlock);
20931256Syl150051
20941256Syl150051 if (!lldev->is_initialized) {
20951256Syl150051 xge_debug_ll(XGE_ERR, "%s%d: can not set multicast",
20961256Syl150051 XGELL_IFNAME, lldev->instance);
20971256Syl150051 mutex_exit(&lldev->genlock);
20981256Syl150051 return (EIO);
20991256Syl150051 }
21001256Syl150051
21011256Syl150051 /* FIXME: missing HAL functionality: enable_one() */
21021256Syl150051
21031256Syl150051 status = (add) ?
21041256Syl150051 xge_hal_device_mcast_enable(hldev) :
21051256Syl150051 xge_hal_device_mcast_disable(hldev);
21061256Syl150051
21071256Syl150051 if (status != XGE_HAL_OK) {
21081256Syl150051 xge_debug_ll(XGE_ERR, "failed to %s multicast, status %d",
21091256Syl150051 add ? "enable" : "disable", status);
21101256Syl150051 mutex_exit(&lldev->genlock);
21111256Syl150051 return (EIO);
21121256Syl150051 }
21131256Syl150051
21141256Syl150051 mutex_exit(&lldev->genlock);
21151256Syl150051
21161256Syl150051 return (0);
21171256Syl150051 }
21181256Syl150051
21191256Syl150051
21201256Syl150051 /*
21211256Syl150051 * xgell_m_promisc
21221256Syl150051 * @arg: pointer to device private strucutre(hldev)
21231256Syl150051 * @on:
21241256Syl150051 *
21251256Syl150051 * This function is called by MAC Layer to enable or
21261256Syl150051 * disable the reception of all the packets on the medium
21271256Syl150051 */
21281256Syl150051 static int
xgell_m_promisc(void * arg,boolean_t on)21291256Syl150051 xgell_m_promisc(void *arg, boolean_t on)
21301256Syl150051 {
21313115Syl150051 xgelldev_t *lldev = (xgelldev_t *)arg;
21323115Syl150051 xge_hal_device_t *hldev = lldev->devh;
21331256Syl150051
21341256Syl150051 mutex_enter(&lldev->genlock);
21351256Syl150051
21361256Syl150051 xge_debug_ll(XGE_TRACE, "%s", "MAC_PROMISC_SET");
21371256Syl150051
21381256Syl150051 if (!lldev->is_initialized) {
21391256Syl150051 xge_debug_ll(XGE_ERR, "%s%d: can not set promiscuous",
21401256Syl150051 XGELL_IFNAME, lldev->instance);
21411256Syl150051 mutex_exit(&lldev->genlock);
21421256Syl150051 return (EIO);
21431256Syl150051 }
21441256Syl150051
21451256Syl150051 if (on) {
21461256Syl150051 xge_hal_device_promisc_enable(hldev);
21471256Syl150051 } else {
21481256Syl150051 xge_hal_device_promisc_disable(hldev);
21491256Syl150051 }
21501256Syl150051
21511256Syl150051 mutex_exit(&lldev->genlock);
21521256Syl150051
21531256Syl150051 return (0);
21541256Syl150051 }
21551256Syl150051
21561256Syl150051 /*
21572311Sseb * xgell_m_stat
21581256Syl150051 * @arg: pointer to device private strucutre(hldev)
21591256Syl150051 *
21602311Sseb * This function is called by MAC Layer to get network statistics
21611256Syl150051 * from the driver.
21621256Syl150051 */
21632311Sseb static int
xgell_m_stat(void * arg,uint_t stat,uint64_t * val)21642311Sseb xgell_m_stat(void *arg, uint_t stat, uint64_t *val)
21651256Syl150051 {
21661256Syl150051 xge_hal_stats_hw_info_t *hw_info;
21673115Syl150051 xgelldev_t *lldev = (xgelldev_t *)arg;
21683115Syl150051 xge_hal_device_t *hldev = lldev->devh;
21691256Syl150051
21701256Syl150051 xge_debug_ll(XGE_TRACE, "%s", "MAC_STATS_GET");
21711256Syl150051
21726937Sxw161283 mutex_enter(&lldev->genlock);
21731256Syl150051
21741256Syl150051 if (!lldev->is_initialized) {
21751256Syl150051 mutex_exit(&lldev->genlock);
21762311Sseb return (EAGAIN);
21771256Syl150051 }
21781256Syl150051
21791256Syl150051 if (xge_hal_stats_hw(hldev, &hw_info) != XGE_HAL_OK) {
21801256Syl150051 mutex_exit(&lldev->genlock);
21812311Sseb return (EAGAIN);
21821256Syl150051 }
21831256Syl150051
21841256Syl150051 switch (stat) {
21851256Syl150051 case MAC_STAT_IFSPEED:
21862311Sseb *val = 10000000000ull; /* 10G */
21871256Syl150051 break;
21881256Syl150051
21891256Syl150051 case MAC_STAT_MULTIRCV:
21903115Syl150051 *val = ((u64) hw_info->rmac_vld_mcst_frms_oflow << 32) |
21913115Syl150051 hw_info->rmac_vld_mcst_frms;
21921256Syl150051 break;
21931256Syl150051
21941256Syl150051 case MAC_STAT_BRDCSTRCV:
21953115Syl150051 *val = ((u64) hw_info->rmac_vld_bcst_frms_oflow << 32) |
21963115Syl150051 hw_info->rmac_vld_bcst_frms;
21971256Syl150051 break;
21981256Syl150051
21991256Syl150051 case MAC_STAT_MULTIXMT:
22003115Syl150051 *val = ((u64) hw_info->tmac_mcst_frms_oflow << 32) |
22013115Syl150051 hw_info->tmac_mcst_frms;
22021256Syl150051 break;
22031256Syl150051
22041256Syl150051 case MAC_STAT_BRDCSTXMT:
22053115Syl150051 *val = ((u64) hw_info->tmac_bcst_frms_oflow << 32) |
22063115Syl150051 hw_info->tmac_bcst_frms;
22071256Syl150051 break;
22081256Syl150051
22091256Syl150051 case MAC_STAT_RBYTES:
22103115Syl150051 *val = ((u64) hw_info->rmac_ttl_octets_oflow << 32) |
22113115Syl150051 hw_info->rmac_ttl_octets;
22121256Syl150051 break;
22131256Syl150051
22141256Syl150051 case MAC_STAT_NORCVBUF:
22152311Sseb *val = hw_info->rmac_drop_frms;
22161256Syl150051 break;
22171256Syl150051
22181256Syl150051 case MAC_STAT_IERRORS:
22193115Syl150051 *val = ((u64) hw_info->rmac_discarded_frms_oflow << 32) |
22203115Syl150051 hw_info->rmac_discarded_frms;
22211256Syl150051 break;
22221256Syl150051
22231256Syl150051 case MAC_STAT_OBYTES:
22243115Syl150051 *val = ((u64) hw_info->tmac_ttl_octets_oflow << 32) |
22253115Syl150051 hw_info->tmac_ttl_octets;
22261256Syl150051 break;
22271256Syl150051
22281256Syl150051 case MAC_STAT_NOXMTBUF:
22292311Sseb *val = hw_info->tmac_drop_frms;
22301256Syl150051 break;
22311256Syl150051
22321256Syl150051 case MAC_STAT_OERRORS:
22333115Syl150051 *val = ((u64) hw_info->tmac_any_err_frms_oflow << 32) |
22343115Syl150051 hw_info->tmac_any_err_frms;
22351256Syl150051 break;
22361256Syl150051
22371256Syl150051 case MAC_STAT_IPACKETS:
22383115Syl150051 *val = ((u64) hw_info->rmac_vld_frms_oflow << 32) |
22393115Syl150051 hw_info->rmac_vld_frms;
22401256Syl150051 break;
22411256Syl150051
22421256Syl150051 case MAC_STAT_OPACKETS:
22433115Syl150051 *val = ((u64) hw_info->tmac_frms_oflow << 32) |
22443115Syl150051 hw_info->tmac_frms;
22452311Sseb break;
22462311Sseb
22472311Sseb case ETHER_STAT_FCS_ERRORS:
22482311Sseb *val = hw_info->rmac_fcs_err_frms;
22491256Syl150051 break;
22501256Syl150051
22512311Sseb case ETHER_STAT_TOOLONG_ERRORS:
22522311Sseb *val = hw_info->rmac_long_frms;
22531256Syl150051 break;
22541256Syl150051
22552311Sseb case ETHER_STAT_LINK_DUPLEX:
22562311Sseb *val = LINK_DUPLEX_FULL;
22571256Syl150051 break;
22581256Syl150051
22591256Syl150051 default:
22602311Sseb mutex_exit(&lldev->genlock);
22612311Sseb return (ENOTSUP);
22621256Syl150051 }
22631256Syl150051
22641256Syl150051 mutex_exit(&lldev->genlock);
22651256Syl150051
22662311Sseb return (0);
22671256Syl150051 }
22681256Syl150051
22691256Syl150051 /*
2270*11878SVenu.Iyer@Sun.COM * Retrieve a value for one of the statistics for a particular rx ring
2271*11878SVenu.Iyer@Sun.COM */
2272*11878SVenu.Iyer@Sun.COM int
xgell_rx_ring_stat(mac_ring_driver_t rh,uint_t stat,uint64_t * val)2273*11878SVenu.Iyer@Sun.COM xgell_rx_ring_stat(mac_ring_driver_t rh, uint_t stat, uint64_t *val)
2274*11878SVenu.Iyer@Sun.COM {
2275*11878SVenu.Iyer@Sun.COM xgell_rx_ring_t *rx_ring = (xgell_rx_ring_t *)rh;
2276*11878SVenu.Iyer@Sun.COM
2277*11878SVenu.Iyer@Sun.COM switch (stat) {
2278*11878SVenu.Iyer@Sun.COM case MAC_STAT_RBYTES:
2279*11878SVenu.Iyer@Sun.COM *val = rx_ring->rx_bytes;
2280*11878SVenu.Iyer@Sun.COM break;
2281*11878SVenu.Iyer@Sun.COM
2282*11878SVenu.Iyer@Sun.COM case MAC_STAT_IPACKETS:
2283*11878SVenu.Iyer@Sun.COM *val = rx_ring->rx_pkts;
2284*11878SVenu.Iyer@Sun.COM break;
2285*11878SVenu.Iyer@Sun.COM
2286*11878SVenu.Iyer@Sun.COM default:
2287*11878SVenu.Iyer@Sun.COM *val = 0;
2288*11878SVenu.Iyer@Sun.COM return (ENOTSUP);
2289*11878SVenu.Iyer@Sun.COM }
2290*11878SVenu.Iyer@Sun.COM
2291*11878SVenu.Iyer@Sun.COM return (0);
2292*11878SVenu.Iyer@Sun.COM }
2293*11878SVenu.Iyer@Sun.COM
2294*11878SVenu.Iyer@Sun.COM /*
2295*11878SVenu.Iyer@Sun.COM * Retrieve a value for one of the statistics for a particular tx ring
2296*11878SVenu.Iyer@Sun.COM */
2297*11878SVenu.Iyer@Sun.COM int
xgell_tx_ring_stat(mac_ring_driver_t rh,uint_t stat,uint64_t * val)2298*11878SVenu.Iyer@Sun.COM xgell_tx_ring_stat(mac_ring_driver_t rh, uint_t stat, uint64_t *val)
2299*11878SVenu.Iyer@Sun.COM {
2300*11878SVenu.Iyer@Sun.COM xgell_tx_ring_t *tx_ring = (xgell_tx_ring_t *)rh;
2301*11878SVenu.Iyer@Sun.COM
2302*11878SVenu.Iyer@Sun.COM switch (stat) {
2303*11878SVenu.Iyer@Sun.COM case MAC_STAT_OBYTES:
2304*11878SVenu.Iyer@Sun.COM *val = tx_ring->tx_bytes;
2305*11878SVenu.Iyer@Sun.COM break;
2306*11878SVenu.Iyer@Sun.COM
2307*11878SVenu.Iyer@Sun.COM case MAC_STAT_OPACKETS:
2308*11878SVenu.Iyer@Sun.COM *val = tx_ring->tx_pkts;
2309*11878SVenu.Iyer@Sun.COM break;
2310*11878SVenu.Iyer@Sun.COM
2311*11878SVenu.Iyer@Sun.COM default:
2312*11878SVenu.Iyer@Sun.COM *val = 0;
2313*11878SVenu.Iyer@Sun.COM return (ENOTSUP);
2314*11878SVenu.Iyer@Sun.COM }
2315*11878SVenu.Iyer@Sun.COM
2316*11878SVenu.Iyer@Sun.COM return (0);
2317*11878SVenu.Iyer@Sun.COM }
2318*11878SVenu.Iyer@Sun.COM
2319*11878SVenu.Iyer@Sun.COM /*
23201256Syl150051 * xgell_device_alloc - Allocate new LL device
23211256Syl150051 */
23221256Syl150051 int
xgell_device_alloc(xge_hal_device_h devh,dev_info_t * dev_info,xgelldev_t ** lldev_out)23231256Syl150051 xgell_device_alloc(xge_hal_device_h devh,
23241256Syl150051 dev_info_t *dev_info, xgelldev_t **lldev_out)
23251256Syl150051 {
23261256Syl150051 xgelldev_t *lldev;
23271256Syl150051 xge_hal_device_t *hldev = (xge_hal_device_t *)devh;
23281256Syl150051 int instance = ddi_get_instance(dev_info);
23291256Syl150051
23301256Syl150051 *lldev_out = NULL;
23311256Syl150051
23321256Syl150051 xge_debug_ll(XGE_TRACE, "trying to register etherenet device %s%d...",
23331256Syl150051 XGELL_IFNAME, instance);
23341256Syl150051
23351256Syl150051 lldev = kmem_zalloc(sizeof (xgelldev_t), KM_SLEEP);
23361256Syl150051
23371256Syl150051 lldev->devh = hldev;
23381256Syl150051 lldev->instance = instance;
23391256Syl150051 lldev->dev_info = dev_info;
23401256Syl150051
23411256Syl150051 *lldev_out = lldev;
23421256Syl150051
23431256Syl150051 ddi_set_driver_private(dev_info, (caddr_t)hldev);
23441256Syl150051
23451256Syl150051 return (DDI_SUCCESS);
23461256Syl150051 }
23471256Syl150051
23481256Syl150051 /*
23491256Syl150051 * xgell_device_free
23501256Syl150051 */
23511256Syl150051 void
xgell_device_free(xgelldev_t * lldev)23521256Syl150051 xgell_device_free(xgelldev_t *lldev)
23531256Syl150051 {
23541256Syl150051 xge_debug_ll(XGE_TRACE, "freeing device %s%d",
23551256Syl150051 XGELL_IFNAME, lldev->instance);
23561256Syl150051
23571256Syl150051 kmem_free(lldev, sizeof (xgelldev_t));
23581256Syl150051 }
23591256Syl150051
23601256Syl150051 /*
23611256Syl150051 * xgell_ioctl
23621256Syl150051 */
23631256Syl150051 static void
xgell_m_ioctl(void * arg,queue_t * wq,mblk_t * mp)23641256Syl150051 xgell_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
23651256Syl150051 {
23663115Syl150051 xgelldev_t *lldev = arg;
23671256Syl150051 struct iocblk *iocp;
23681256Syl150051 int err = 0;
23691256Syl150051 int cmd;
23701256Syl150051 int need_privilege = 1;
23711256Syl150051 int ret = 0;
23721256Syl150051
23731256Syl150051
23741256Syl150051 iocp = (struct iocblk *)mp->b_rptr;
23751256Syl150051 iocp->ioc_error = 0;
23761256Syl150051 cmd = iocp->ioc_cmd;
23771256Syl150051 xge_debug_ll(XGE_TRACE, "MAC_IOCTL cmd 0x%x", cmd);
23781256Syl150051 switch (cmd) {
23791256Syl150051 case ND_GET:
23801256Syl150051 need_privilege = 0;
23811256Syl150051 /* FALLTHRU */
23821256Syl150051 case ND_SET:
23831256Syl150051 break;
23841256Syl150051 default:
23851256Syl150051 xge_debug_ll(XGE_TRACE, "unknown cmd 0x%x", cmd);
23861256Syl150051 miocnak(wq, mp, 0, EINVAL);
23871256Syl150051 return;
23881256Syl150051 }
23891256Syl150051
23901256Syl150051 if (need_privilege) {
23911256Syl150051 err = secpolicy_net_config(iocp->ioc_cr, B_FALSE);
23921256Syl150051 if (err != 0) {
23931256Syl150051 xge_debug_ll(XGE_ERR,
23941256Syl150051 "drv_priv(): rejected cmd 0x%x, err %d",
23951256Syl150051 cmd, err);
23961256Syl150051 miocnak(wq, mp, 0, err);
23971256Syl150051 return;
23981256Syl150051 }
23991256Syl150051 }
24001256Syl150051
24011256Syl150051 switch (cmd) {
24021256Syl150051 case ND_GET:
24031256Syl150051 /*
24041256Syl150051 * If nd_getset() returns B_FALSE, the command was
24051256Syl150051 * not valid (e.g. unknown name), so we just tell the
24061256Syl150051 * top-level ioctl code to send a NAK (with code EINVAL).
24071256Syl150051 *
24081256Syl150051 * Otherwise, nd_getset() will have built the reply to
24091256Syl150051 * be sent (but not actually sent it), so we tell the
24101256Syl150051 * caller to send the prepared reply.
24111256Syl150051 */
24121256Syl150051 ret = nd_getset(wq, lldev->ndp, mp);
24136937Sxw161283 xge_debug_ll(XGE_TRACE, "%s", "got ndd get ioctl");
24141256Syl150051 break;
24151256Syl150051
24161256Syl150051 case ND_SET:
24171256Syl150051 ret = nd_getset(wq, lldev->ndp, mp);
24186937Sxw161283 xge_debug_ll(XGE_TRACE, "%s", "got ndd set ioctl");
24191256Syl150051 break;
24201256Syl150051
24211256Syl150051 default:
24221256Syl150051 break;
24231256Syl150051 }
24241256Syl150051
24251256Syl150051 if (ret == B_FALSE) {
24261256Syl150051 xge_debug_ll(XGE_ERR,
24271256Syl150051 "nd_getset(): rejected cmd 0x%x, err %d",
24281256Syl150051 cmd, err);
24291256Syl150051 miocnak(wq, mp, 0, EINVAL);
24301256Syl150051 } else {
24311256Syl150051 mp->b_datap->db_type = iocp->ioc_error == 0 ?
24321256Syl150051 M_IOCACK : M_IOCNAK;
24331256Syl150051 qreply(wq, mp);
24341256Syl150051 }
24351256Syl150051 }
24361256Syl150051
24378275SEric Cheng
24382311Sseb static boolean_t
xgell_m_getcapab(void * arg,mac_capab_t cap,void * cap_data)24392311Sseb xgell_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
24401256Syl150051 {
24413115Syl150051 xgelldev_t *lldev = arg;
24423115Syl150051
24438275SEric Cheng xge_debug_ll(XGE_TRACE, "xgell_m_getcapab: %x", cap);
24448275SEric Cheng
24452311Sseb switch (cap) {
24462311Sseb case MAC_CAPAB_HCKSUM: {
24472311Sseb uint32_t *hcksum_txflags = cap_data;
24482311Sseb *hcksum_txflags = HCKSUM_INET_FULL_V4 | HCKSUM_INET_FULL_V6 |
24492311Sseb HCKSUM_IPHDRCKSUM;
24502311Sseb break;
24512311Sseb }
24523115Syl150051 case MAC_CAPAB_LSO: {
24533115Syl150051 mac_capab_lso_t *cap_lso = cap_data;
24543115Syl150051
24553115Syl150051 if (lldev->config.lso_enable) {
24563115Syl150051 cap_lso->lso_flags = LSO_TX_BASIC_TCP_IPV4;
24573115Syl150051 cap_lso->lso_basic_tcp_ipv4.lso_max = XGELL_LSO_MAXLEN;
24583115Syl150051 break;
24593115Syl150051 } else {
24603115Syl150051 return (B_FALSE);
24613115Syl150051 }
24623115Syl150051 }
24638275SEric Cheng case MAC_CAPAB_RINGS: {
24648275SEric Cheng mac_capab_rings_t *cap_rings = cap_data;
24658275SEric Cheng
24668275SEric Cheng switch (cap_rings->mr_type) {
24678275SEric Cheng case MAC_RING_TYPE_RX:
24688275SEric Cheng cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
24698275SEric Cheng cap_rings->mr_rnum = lldev->init_rx_rings;
24708275SEric Cheng cap_rings->mr_gnum = lldev->init_rx_groups;
24718275SEric Cheng cap_rings->mr_rget = xgell_fill_ring;
24728275SEric Cheng cap_rings->mr_gget = xgell_fill_group;
24738275SEric Cheng break;
24748275SEric Cheng case MAC_RING_TYPE_TX:
24758275SEric Cheng cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
24768275SEric Cheng cap_rings->mr_rnum = lldev->init_tx_rings;
24778275SEric Cheng cap_rings->mr_gnum = 0;
24788275SEric Cheng cap_rings->mr_rget = xgell_fill_ring;
24798275SEric Cheng cap_rings->mr_gget = NULL;
24808275SEric Cheng break;
24818275SEric Cheng default:
24828275SEric Cheng break;
24838275SEric Cheng }
24848275SEric Cheng break;
24858275SEric Cheng }
24862311Sseb default:
24872311Sseb return (B_FALSE);
24882311Sseb }
24892311Sseb return (B_TRUE);
24901256Syl150051 }
24911256Syl150051
24921256Syl150051 static int
xgell_stats_get(queue_t * q,mblk_t * mp,caddr_t cp,cred_t * credp)24931256Syl150051 xgell_stats_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp)
24941256Syl150051 {
24951256Syl150051 xgelldev_t *lldev = (xgelldev_t *)cp;
24961256Syl150051 xge_hal_status_e status;
24971256Syl150051 int count = 0, retsize;
24981256Syl150051 char *buf;
24991256Syl150051
25001256Syl150051 buf = kmem_alloc(XGELL_STATS_BUFSIZE, KM_SLEEP);
25011256Syl150051 if (buf == NULL) {
25021256Syl150051 return (ENOSPC);
25031256Syl150051 }
25041256Syl150051
25051256Syl150051 status = xge_hal_aux_stats_tmac_read(lldev->devh, XGELL_STATS_BUFSIZE,
25061256Syl150051 buf, &retsize);
25071256Syl150051 if (status != XGE_HAL_OK) {
25081256Syl150051 kmem_free(buf, XGELL_STATS_BUFSIZE);
25091256Syl150051 xge_debug_ll(XGE_ERR, "tmac_read(): status %d", status);
25101256Syl150051 return (EINVAL);
25111256Syl150051 }
25121256Syl150051 count += retsize;
25131256Syl150051
25141256Syl150051 status = xge_hal_aux_stats_rmac_read(lldev->devh,
25151256Syl150051 XGELL_STATS_BUFSIZE - count,
25161256Syl150051 buf+count, &retsize);
25171256Syl150051 if (status != XGE_HAL_OK) {
25181256Syl150051 kmem_free(buf, XGELL_STATS_BUFSIZE);
25191256Syl150051 xge_debug_ll(XGE_ERR, "rmac_read(): status %d", status);
25201256Syl150051 return (EINVAL);
25211256Syl150051 }
25221256Syl150051 count += retsize;
25231256Syl150051
25241256Syl150051 status = xge_hal_aux_stats_pci_read(lldev->devh,
25251256Syl150051 XGELL_STATS_BUFSIZE - count, buf + count, &retsize);
25261256Syl150051 if (status != XGE_HAL_OK) {
25271256Syl150051 kmem_free(buf, XGELL_STATS_BUFSIZE);
25281256Syl150051 xge_debug_ll(XGE_ERR, "pci_read(): status %d", status);
25291256Syl150051 return (EINVAL);
25301256Syl150051 }
25311256Syl150051 count += retsize;
25321256Syl150051
25331256Syl150051 status = xge_hal_aux_stats_sw_dev_read(lldev->devh,
25341256Syl150051 XGELL_STATS_BUFSIZE - count, buf + count, &retsize);
25351256Syl150051 if (status != XGE_HAL_OK) {
25361256Syl150051 kmem_free(buf, XGELL_STATS_BUFSIZE);
25371256Syl150051 xge_debug_ll(XGE_ERR, "sw_dev_read(): status %d", status);
25381256Syl150051 return (EINVAL);
25391256Syl150051 }
25401256Syl150051 count += retsize;
25411256Syl150051
25421256Syl150051 status = xge_hal_aux_stats_hal_read(lldev->devh,
25431256Syl150051 XGELL_STATS_BUFSIZE - count, buf + count, &retsize);
25441256Syl150051 if (status != XGE_HAL_OK) {
25451256Syl150051 kmem_free(buf, XGELL_STATS_BUFSIZE);
25461256Syl150051 xge_debug_ll(XGE_ERR, "pci_read(): status %d", status);
25471256Syl150051 return (EINVAL);
25481256Syl150051 }
25491256Syl150051 count += retsize;
25501256Syl150051
25511256Syl150051 *(buf + count - 1) = '\0'; /* remove last '\n' */
25521256Syl150051 (void) mi_mpprintf(mp, "%s", buf);
25531256Syl150051 kmem_free(buf, XGELL_STATS_BUFSIZE);
25541256Syl150051
25551256Syl150051 return (0);
25561256Syl150051 }
25571256Syl150051
25581256Syl150051 static int
xgell_pciconf_get(queue_t * q,mblk_t * mp,caddr_t cp,cred_t * credp)25591256Syl150051 xgell_pciconf_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp)
25601256Syl150051 {
25611256Syl150051 xgelldev_t *lldev = (xgelldev_t *)cp;
25621256Syl150051 xge_hal_status_e status;
25631256Syl150051 int retsize;
25641256Syl150051 char *buf;
25651256Syl150051
25661256Syl150051 buf = kmem_alloc(XGELL_PCICONF_BUFSIZE, KM_SLEEP);
25671256Syl150051 if (buf == NULL) {
25681256Syl150051 return (ENOSPC);
25691256Syl150051 }
25701256Syl150051 status = xge_hal_aux_pci_config_read(lldev->devh, XGELL_PCICONF_BUFSIZE,
25711256Syl150051 buf, &retsize);
25721256Syl150051 if (status != XGE_HAL_OK) {
25731256Syl150051 kmem_free(buf, XGELL_PCICONF_BUFSIZE);
25741256Syl150051 xge_debug_ll(XGE_ERR, "pci_config_read(): status %d", status);
25751256Syl150051 return (EINVAL);
25761256Syl150051 }
25771256Syl150051 *(buf + retsize - 1) = '\0'; /* remove last '\n' */
25781256Syl150051 (void) mi_mpprintf(mp, "%s", buf);
25791256Syl150051 kmem_free(buf, XGELL_PCICONF_BUFSIZE);
25801256Syl150051
25811256Syl150051 return (0);
25821256Syl150051 }
25831256Syl150051
25841256Syl150051 static int
xgell_about_get(queue_t * q,mblk_t * mp,caddr_t cp,cred_t * credp)25851256Syl150051 xgell_about_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp)
25861256Syl150051 {
25871256Syl150051 xgelldev_t *lldev = (xgelldev_t *)cp;
25881256Syl150051 xge_hal_status_e status;
25891256Syl150051 int retsize;
25901256Syl150051 char *buf;
25911256Syl150051
25921256Syl150051 buf = kmem_alloc(XGELL_ABOUT_BUFSIZE, KM_SLEEP);
25931256Syl150051 if (buf == NULL) {
25941256Syl150051 return (ENOSPC);
25951256Syl150051 }
25961256Syl150051 status = xge_hal_aux_about_read(lldev->devh, XGELL_ABOUT_BUFSIZE,
25971256Syl150051 buf, &retsize);
25981256Syl150051 if (status != XGE_HAL_OK) {
25991256Syl150051 kmem_free(buf, XGELL_ABOUT_BUFSIZE);
26001256Syl150051 xge_debug_ll(XGE_ERR, "about_read(): status %d", status);
26011256Syl150051 return (EINVAL);
26021256Syl150051 }
26031256Syl150051 *(buf + retsize - 1) = '\0'; /* remove last '\n' */
26041256Syl150051 (void) mi_mpprintf(mp, "%s", buf);
26051256Syl150051 kmem_free(buf, XGELL_ABOUT_BUFSIZE);
26061256Syl150051
26071256Syl150051 return (0);
26081256Syl150051 }
26091256Syl150051
26101256Syl150051 static unsigned long bar0_offset = 0x110; /* adapter_control */
26111256Syl150051
26121256Syl150051 static int
xgell_bar0_get(queue_t * q,mblk_t * mp,caddr_t cp,cred_t * credp)26131256Syl150051 xgell_bar0_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp)
26141256Syl150051 {
26151256Syl150051 xgelldev_t *lldev = (xgelldev_t *)cp;
26161256Syl150051 xge_hal_status_e status;
26171256Syl150051 int retsize;
26181256Syl150051 char *buf;
26191256Syl150051
26201256Syl150051 buf = kmem_alloc(XGELL_IOCTL_BUFSIZE, KM_SLEEP);
26211256Syl150051 if (buf == NULL) {
26221256Syl150051 return (ENOSPC);
26231256Syl150051 }
26241256Syl150051 status = xge_hal_aux_bar0_read(lldev->devh, bar0_offset,
26251256Syl150051 XGELL_IOCTL_BUFSIZE, buf, &retsize);
26261256Syl150051 if (status != XGE_HAL_OK) {
26271256Syl150051 kmem_free(buf, XGELL_IOCTL_BUFSIZE);
26281256Syl150051 xge_debug_ll(XGE_ERR, "bar0_read(): status %d", status);
26291256Syl150051 return (EINVAL);
26301256Syl150051 }
26311256Syl150051 *(buf + retsize - 1) = '\0'; /* remove last '\n' */
26321256Syl150051 (void) mi_mpprintf(mp, "%s", buf);
26331256Syl150051 kmem_free(buf, XGELL_IOCTL_BUFSIZE);
26341256Syl150051
26351256Syl150051 return (0);
26361256Syl150051 }
26371256Syl150051
26381256Syl150051 static int
xgell_bar0_set(queue_t * q,mblk_t * mp,char * value,caddr_t cp,cred_t * credp)26391256Syl150051 xgell_bar0_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp, cred_t *credp)
26401256Syl150051 {
26411256Syl150051 unsigned long old_offset = bar0_offset;
26421256Syl150051 char *end;
26431256Syl150051
26441256Syl150051 if (value && *value == '0' &&
26451256Syl150051 (*(value + 1) == 'x' || *(value + 1) == 'X')) {
26461256Syl150051 value += 2;
26471256Syl150051 }
26481256Syl150051
26491256Syl150051 bar0_offset = mi_strtol(value, &end, 16);
26501256Syl150051 if (end == value) {
26511256Syl150051 bar0_offset = old_offset;
26521256Syl150051 return (EINVAL);
26531256Syl150051 }
26541256Syl150051
26551256Syl150051 xge_debug_ll(XGE_TRACE, "bar0: new value %s:%lX", value, bar0_offset);
26561256Syl150051
26571256Syl150051 return (0);
26581256Syl150051 }
26591256Syl150051
26601256Syl150051 static int
xgell_debug_level_get(queue_t * q,mblk_t * mp,caddr_t cp,cred_t * credp)26611256Syl150051 xgell_debug_level_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp)
26621256Syl150051 {
26631256Syl150051 char *buf;
26641256Syl150051
26651256Syl150051 buf = kmem_alloc(XGELL_IOCTL_BUFSIZE, KM_SLEEP);
26661256Syl150051 if (buf == NULL) {
26671256Syl150051 return (ENOSPC);
26681256Syl150051 }
26691256Syl150051 (void) mi_mpprintf(mp, "debug_level %d", xge_hal_driver_debug_level());
26701256Syl150051 kmem_free(buf, XGELL_IOCTL_BUFSIZE);
26711256Syl150051
26721256Syl150051 return (0);
26731256Syl150051 }
26741256Syl150051
26751256Syl150051 static int
xgell_debug_level_set(queue_t * q,mblk_t * mp,char * value,caddr_t cp,cred_t * credp)26761256Syl150051 xgell_debug_level_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp,
26771256Syl150051 cred_t *credp)
26781256Syl150051 {
26791256Syl150051 int level;
26801256Syl150051 char *end;
26811256Syl150051
26821256Syl150051 level = mi_strtol(value, &end, 10);
26831256Syl150051 if (level < XGE_NONE || level > XGE_ERR || end == value) {
26841256Syl150051 return (EINVAL);
26851256Syl150051 }
26861256Syl150051
26871256Syl150051 xge_hal_driver_debug_level_set(level);
26881256Syl150051
26891256Syl150051 return (0);
26901256Syl150051 }
26911256Syl150051
26921256Syl150051 static int
xgell_debug_module_mask_get(queue_t * q,mblk_t * mp,caddr_t cp,cred_t * credp)26931256Syl150051 xgell_debug_module_mask_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp)
26941256Syl150051 {
26951256Syl150051 char *buf;
26961256Syl150051
26971256Syl150051 buf = kmem_alloc(XGELL_IOCTL_BUFSIZE, KM_SLEEP);
26981256Syl150051 if (buf == NULL) {
26991256Syl150051 return (ENOSPC);
27001256Syl150051 }
27011256Syl150051 (void) mi_mpprintf(mp, "debug_module_mask 0x%08x",
27021256Syl150051 xge_hal_driver_debug_module_mask());
27031256Syl150051 kmem_free(buf, XGELL_IOCTL_BUFSIZE);
27041256Syl150051
27051256Syl150051 return (0);
27061256Syl150051 }
27071256Syl150051
27081256Syl150051 static int
xgell_debug_module_mask_set(queue_t * q,mblk_t * mp,char * value,caddr_t cp,cred_t * credp)27091256Syl150051 xgell_debug_module_mask_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp,
27101256Syl150051 cred_t *credp)
27111256Syl150051 {
27121256Syl150051 u32 mask;
27131256Syl150051 char *end;
27141256Syl150051
27151256Syl150051 if (value && *value == '0' &&
27161256Syl150051 (*(value + 1) == 'x' || *(value + 1) == 'X')) {
27171256Syl150051 value += 2;
27181256Syl150051 }
27191256Syl150051
27201256Syl150051 mask = mi_strtol(value, &end, 16);
27211256Syl150051 if (end == value) {
27221256Syl150051 return (EINVAL);
27231256Syl150051 }
27241256Syl150051
27251256Syl150051 xge_hal_driver_debug_module_mask_set(mask);
27261256Syl150051
27271256Syl150051 return (0);
27281256Syl150051 }
27291256Syl150051
27301256Syl150051 static int
xgell_devconfig_get(queue_t * q,mblk_t * mp,caddr_t cp,cred_t * credp)27311256Syl150051 xgell_devconfig_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp)
27321256Syl150051 {
27331256Syl150051 xgelldev_t *lldev = (xgelldev_t *)(void *)cp;
27341256Syl150051 xge_hal_status_e status;
27351256Syl150051 int retsize;
27361256Syl150051 char *buf;
27371256Syl150051
27381256Syl150051 buf = kmem_alloc(XGELL_DEVCONF_BUFSIZE, KM_SLEEP);
27391256Syl150051 if (buf == NULL) {
27401256Syl150051 return (ENOSPC);
27411256Syl150051 }
27421256Syl150051 status = xge_hal_aux_device_config_read(lldev->devh,
27438275SEric Cheng XGELL_DEVCONF_BUFSIZE, buf, &retsize);
27441256Syl150051 if (status != XGE_HAL_OK) {
27451256Syl150051 kmem_free(buf, XGELL_DEVCONF_BUFSIZE);
27461256Syl150051 xge_debug_ll(XGE_ERR, "device_config_read(): status %d",
27471256Syl150051 status);
27481256Syl150051 return (EINVAL);
27491256Syl150051 }
27501256Syl150051 *(buf + retsize - 1) = '\0'; /* remove last '\n' */
27511256Syl150051 (void) mi_mpprintf(mp, "%s", buf);
27521256Syl150051 kmem_free(buf, XGELL_DEVCONF_BUFSIZE);
27531256Syl150051
27541256Syl150051 return (0);
27551256Syl150051 }
27561256Syl150051
27571256Syl150051 /*
27581256Syl150051 * xgell_device_register
27591256Syl150051 * @devh: pointer on HAL device
27601256Syl150051 * @config: pointer on this network device configuration
27611256Syl150051 * @ll_out: output pointer. Will be assigned to valid LL device.
27621256Syl150051 *
27631256Syl150051 * This function will allocate and register network device
27641256Syl150051 */
27651256Syl150051 int
xgell_device_register(xgelldev_t * lldev,xgell_config_t * config)27661256Syl150051 xgell_device_register(xgelldev_t *lldev, xgell_config_t *config)
27671256Syl150051 {
27683115Syl150051 mac_register_t *macp = NULL;
27691256Syl150051 xge_hal_device_t *hldev = (xge_hal_device_t *)lldev->devh;
27701256Syl150051
27718275SEric Cheng /*
27728275SEric Cheng * Initialize some NDD interface for internal debug.
27738275SEric Cheng */
27741256Syl150051 if (nd_load(&lldev->ndp, "pciconf", xgell_pciconf_get, NULL,
27752311Sseb (caddr_t)lldev) == B_FALSE)
27762311Sseb goto xgell_ndd_fail;
27771256Syl150051
27781256Syl150051 if (nd_load(&lldev->ndp, "about", xgell_about_get, NULL,
27792311Sseb (caddr_t)lldev) == B_FALSE)
27802311Sseb goto xgell_ndd_fail;
27811256Syl150051
27821256Syl150051 if (nd_load(&lldev->ndp, "stats", xgell_stats_get, NULL,
27832311Sseb (caddr_t)lldev) == B_FALSE)
27842311Sseb goto xgell_ndd_fail;
27851256Syl150051
27861256Syl150051 if (nd_load(&lldev->ndp, "bar0", xgell_bar0_get, xgell_bar0_set,
27872311Sseb (caddr_t)lldev) == B_FALSE)
27882311Sseb goto xgell_ndd_fail;
27891256Syl150051
27901256Syl150051 if (nd_load(&lldev->ndp, "debug_level", xgell_debug_level_get,
27912311Sseb xgell_debug_level_set, (caddr_t)lldev) == B_FALSE)
27922311Sseb goto xgell_ndd_fail;
27931256Syl150051
27941256Syl150051 if (nd_load(&lldev->ndp, "debug_module_mask",
27951256Syl150051 xgell_debug_module_mask_get, xgell_debug_module_mask_set,
27962311Sseb (caddr_t)lldev) == B_FALSE)
27972311Sseb goto xgell_ndd_fail;
27981256Syl150051
27991256Syl150051 if (nd_load(&lldev->ndp, "devconfig", xgell_devconfig_get, NULL,
28002311Sseb (caddr_t)lldev) == B_FALSE)
28012311Sseb goto xgell_ndd_fail;
28021256Syl150051
28031256Syl150051 bcopy(config, &lldev->config, sizeof (xgell_config_t));
28041256Syl150051
28056937Sxw161283 mutex_init(&lldev->genlock, NULL, MUTEX_DRIVER,
28066937Sxw161283 DDI_INTR_PRI(hldev->irqh));
28071256Syl150051
28082311Sseb if ((macp = mac_alloc(MAC_VERSION)) == NULL)
28092311Sseb goto xgell_register_fail;
28102311Sseb macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
28113115Syl150051 macp->m_driver = lldev;
28122311Sseb macp->m_dip = lldev->dev_info;
28132311Sseb macp->m_src_addr = hldev->macaddr[0];
28142311Sseb macp->m_callbacks = &xgell_m_callbacks;
28152311Sseb macp->m_min_sdu = 0;
28162311Sseb macp->m_max_sdu = hldev->config.mtu;
28175895Syz147064 macp->m_margin = VLAN_TAGSZ;
28188275SEric Cheng macp->m_v12n = MAC_VIRT_LEVEL1;
28198275SEric Cheng
28201256Syl150051 /*
28218275SEric Cheng * MAC Registration.
28221256Syl150051 */
28233115Syl150051 if (mac_register(macp, &lldev->mh) != 0)
28242311Sseb goto xgell_register_fail;
28251256Syl150051
28263392Syl150051 /* Always free the macp after register */
28273392Syl150051 if (macp != NULL)
28283392Syl150051 mac_free(macp);
28293392Syl150051
28303115Syl150051 /* Calculate tx_copied_max here ??? */
28313115Syl150051 lldev->tx_copied_max = hldev->config.fifo.max_frags *
28326937Sxw161283 hldev->config.fifo.alignment_size *
28336937Sxw161283 hldev->config.fifo.max_aligned_frags;
28343115Syl150051
28351256Syl150051 xge_debug_ll(XGE_TRACE, "etherenet device %s%d registered",
28361256Syl150051 XGELL_IFNAME, lldev->instance);
28371256Syl150051
28381256Syl150051 return (DDI_SUCCESS);
28392311Sseb
28402311Sseb xgell_ndd_fail:
28412311Sseb nd_free(&lldev->ndp);
28422311Sseb xge_debug_ll(XGE_ERR, "%s", "unable to load ndd parameter");
28432311Sseb return (DDI_FAILURE);
28442311Sseb
28452311Sseb xgell_register_fail:
28463115Syl150051 if (macp != NULL)
28473115Syl150051 mac_free(macp);
28482311Sseb nd_free(&lldev->ndp);
28492311Sseb mutex_destroy(&lldev->genlock);
28502311Sseb xge_debug_ll(XGE_ERR, "%s", "unable to register networking device");
28512311Sseb return (DDI_FAILURE);
28521256Syl150051 }
28531256Syl150051
28541256Syl150051 /*
28551256Syl150051 * xgell_device_unregister
28561256Syl150051 * @devh: pointer on HAL device
28571256Syl150051 * @lldev: pointer to valid LL device.
28581256Syl150051 *
28591256Syl150051 * This function will unregister and free network device
28601256Syl150051 */
28611256Syl150051 int
xgell_device_unregister(xgelldev_t * lldev)28621256Syl150051 xgell_device_unregister(xgelldev_t *lldev)
28631256Syl150051 {
28642311Sseb if (mac_unregister(lldev->mh) != 0) {
28651256Syl150051 xge_debug_ll(XGE_ERR, "unable to unregister device %s%d",
28661256Syl150051 XGELL_IFNAME, lldev->instance);
28671256Syl150051 return (DDI_FAILURE);
28681256Syl150051 }
28691256Syl150051
28701256Syl150051 mutex_destroy(&lldev->genlock);
28711256Syl150051
28721256Syl150051 nd_free(&lldev->ndp);
28731256Syl150051
28741256Syl150051 xge_debug_ll(XGE_TRACE, "etherenet device %s%d unregistered",
28751256Syl150051 XGELL_IFNAME, lldev->instance);
28761256Syl150051
28771256Syl150051 return (DDI_SUCCESS);
28781256Syl150051 }
2879