1a23fd118Syl150051 /* 2a23fd118Syl150051 * CDDL HEADER START 3a23fd118Syl150051 * 4a23fd118Syl150051 * The contents of this file are subject to the terms of the 5a23fd118Syl150051 * Common Development and Distribution License (the "License"). 6a23fd118Syl150051 * You may not use this file except in compliance with the License. 7a23fd118Syl150051 * 8a23fd118Syl150051 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9a23fd118Syl150051 * or http://www.opensolaris.org/os/licensing. 10a23fd118Syl150051 * See the License for the specific language governing permissions 11a23fd118Syl150051 * and limitations under the License. 12a23fd118Syl150051 * 13a23fd118Syl150051 * When distributing Covered Code, include this CDDL HEADER in each 14a23fd118Syl150051 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15a23fd118Syl150051 * If applicable, add the following below this CDDL HEADER, with the 16a23fd118Syl150051 * fields enclosed by brackets "[]" replaced with your own identifying 17a23fd118Syl150051 * information: Portions Copyright [yyyy] [name of copyright owner] 18a23fd118Syl150051 * 19a23fd118Syl150051 * CDDL HEADER END 20a23fd118Syl150051 */ 21a23fd118Syl150051 22a23fd118Syl150051 /* 237eced415Sxw161283 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24a23fd118Syl150051 * Use is subject to license terms. 25a23fd118Syl150051 */ 26a23fd118Syl150051 27a23fd118Syl150051 /* 28a23fd118Syl150051 * Copyright (c) 2002-2005 Neterion, Inc. 29a23fd118Syl150051 * All right Reserved. 30a23fd118Syl150051 * 31a23fd118Syl150051 * FileName : xge.c 32a23fd118Syl150051 * 33a23fd118Syl150051 * Description: Xge main Solaris specific initialization & routines 34a23fd118Syl150051 * for upper layer driver 35a23fd118Syl150051 * 36a23fd118Syl150051 */ 37a23fd118Syl150051 #include "xgell.h" 38a23fd118Syl150051 39a23fd118Syl150051 static int xge_attach(dev_info_t *dev_info, ddi_attach_cmd_t cmd); 40a23fd118Syl150051 static int xge_detach(dev_info_t *dev_info, ddi_detach_cmd_t cmd); 4119397407SSherry Moore static int xge_quiesce(dev_info_t *dev_info); 42a23fd118Syl150051 43a23fd118Syl150051 DDI_DEFINE_STREAM_OPS(xge_ops, nulldev, nulldev, xge_attach, xge_detach, 4419397407SSherry Moore nodev, NULL, D_MP, NULL, xge_quiesce); 45a23fd118Syl150051 46a23fd118Syl150051 /* Standard Module linkage initialization for a Streams driver */ 47a23fd118Syl150051 extern struct mod_ops mod_driverops; 48a23fd118Syl150051 49a23fd118Syl150051 static struct modldrv modldrv = { 50a23fd118Syl150051 &mod_driverops, /* Type of module. This one is a driver */ 51a23fd118Syl150051 XGELL_DESC, /* short description */ 52a23fd118Syl150051 &xge_ops /* driver specific ops */ 53a23fd118Syl150051 }; 54a23fd118Syl150051 55a23fd118Syl150051 static struct modlinkage modlinkage = { 56a23fd118Syl150051 MODREV_1, {(void *)&modldrv, NULL} 57a23fd118Syl150051 }; 58a23fd118Syl150051 59a23fd118Syl150051 /* Xge device attributes */ 60a23fd118Syl150051 ddi_device_acc_attr_t xge_dev_attr = { 61a23fd118Syl150051 DDI_DEVICE_ATTR_V0, 62a23fd118Syl150051 DDI_NEVERSWAP_ACC, 63a23fd118Syl150051 DDI_STRICTORDER_ACC 64a23fd118Syl150051 }; 65a23fd118Syl150051 ddi_device_acc_attr_t *p_xge_dev_attr = &xge_dev_attr; 66a23fd118Syl150051 67a23fd118Syl150051 /* 68a23fd118Syl150051 * xgell_callback_crit_err 69a23fd118Syl150051 * 70a23fd118Syl150051 * This function called by HAL on Serious Error event. XGE_HAL_EVENT_SERR. 71a23fd118Syl150051 * Upper layer must analyze it based on %type. 72a23fd118Syl150051 */ 73a23fd118Syl150051 static void 74a23fd118Syl150051 xge_callback_crit_err(void *userdata, xge_hal_event_e type, u64 serr_data) 75a23fd118Syl150051 { 76a23fd118Syl150051 (void) xgell_onerr_reset(userdata); 77a23fd118Syl150051 } 78a23fd118Syl150051 79a23fd118Syl150051 /* 807eced415Sxw161283 * xge_xpak_alarm_log 817eced415Sxw161283 * This function called by HAL on XPAK alarms. Upper layer must log the msg 827eced415Sxw161283 * based on the xpak alarm type 837eced415Sxw161283 */ 847eced415Sxw161283 static void 857eced415Sxw161283 xge_xpak_alarm_log(void *userdata, xge_hal_xpak_alarm_type_e type) 867eced415Sxw161283 { 877eced415Sxw161283 switch (type) { 887eced415Sxw161283 case XGE_HAL_XPAK_ALARM_EXCESS_TEMP: 897eced415Sxw161283 xge_debug_osdep(XGE_ERR, "%s", "Take Xframe NIC out of " 907eced415Sxw161283 "service. Excessive temperatures may result in " 917eced415Sxw161283 "premature transceiver failure \n"); 927eced415Sxw161283 937eced415Sxw161283 break; 947eced415Sxw161283 case XGE_HAL_XPAK_ALARM_EXCESS_BIAS_CURRENT: 957eced415Sxw161283 xge_debug_osdep(XGE_ERR, "%s", "Take Xframe NIC out of " 967eced415Sxw161283 "service Excessive bias currents may indicate " 977eced415Sxw161283 "imminent laser diode failure \n"); 987eced415Sxw161283 997eced415Sxw161283 break; 1007eced415Sxw161283 case XGE_HAL_XPAK_ALARM_EXCESS_LASER_OUTPUT: 1017eced415Sxw161283 xge_debug_osdep(XGE_ERR, "%s", "Take Xframe NIC out of " 1027eced415Sxw161283 "service Excessive laser output power may saturate " 1037eced415Sxw161283 "far-end receiver\n"); 1047eced415Sxw161283 1057eced415Sxw161283 break; 1067eced415Sxw161283 default: 1077eced415Sxw161283 xge_debug_osdep(XGE_ERR, "%s", "Undefined Xpak Alarm"); 1087eced415Sxw161283 break; 1097eced415Sxw161283 } 1107eced415Sxw161283 1117eced415Sxw161283 } 1127eced415Sxw161283 1137eced415Sxw161283 /* 114a23fd118Syl150051 * xge_driver_init_hal 115a23fd118Syl150051 * 116a23fd118Syl150051 * To initialize HAL portion of driver. 117a23fd118Syl150051 */ 118a23fd118Syl150051 static xge_hal_status_e 119a23fd118Syl150051 xge_driver_init_hal(void) 120a23fd118Syl150051 { 121a23fd118Syl150051 static xge_hal_driver_config_t driver_config; 122a23fd118Syl150051 xge_hal_uld_cbs_t uld_callbacks; 123a23fd118Syl150051 124a23fd118Syl150051 driver_config.queue_size_initial = 1; 125a23fd118Syl150051 driver_config.queue_size_max = 4; 126a23fd118Syl150051 127a23fd118Syl150051 uld_callbacks.link_up = xgell_callback_link_up; 128a23fd118Syl150051 uld_callbacks.link_down = xgell_callback_link_down; 129a23fd118Syl150051 uld_callbacks.crit_err = xge_callback_crit_err; 130*da14cebeSEric Cheng uld_callbacks.event = NULL; 131*da14cebeSEric Cheng uld_callbacks.event_queued = NULL; 132a23fd118Syl150051 uld_callbacks.before_device_poll = NULL; 133a23fd118Syl150051 uld_callbacks.after_device_poll = NULL; 134a23fd118Syl150051 uld_callbacks.sched_timer = NULL; 1357eced415Sxw161283 uld_callbacks.xpak_alarm_log = xge_xpak_alarm_log; 136a23fd118Syl150051 137a23fd118Syl150051 return (xge_hal_driver_initialize(&driver_config, &uld_callbacks)); 138a23fd118Syl150051 139a23fd118Syl150051 } 140a23fd118Syl150051 141a23fd118Syl150051 /* 142a23fd118Syl150051 * _init 143a23fd118Syl150051 * 144a23fd118Syl150051 * Solaris standard _init function for a device driver 145a23fd118Syl150051 */ 146a23fd118Syl150051 int 147a23fd118Syl150051 _init(void) 148a23fd118Syl150051 { 149a23fd118Syl150051 int ret = 0; 150a23fd118Syl150051 xge_hal_status_e status; 151a23fd118Syl150051 152a23fd118Syl150051 status = xge_driver_init_hal(); 153a23fd118Syl150051 if (status != XGE_HAL_OK) { 154a23fd118Syl150051 xge_debug_osdep(XGE_ERR, "can't initialize the driver (%d)", 155a23fd118Syl150051 status); 156a23fd118Syl150051 return (EINVAL); 157a23fd118Syl150051 } 158a23fd118Syl150051 159a23fd118Syl150051 xge_hal_driver_debug_module_mask_set(0xffffffff); 160a23fd118Syl150051 xge_hal_driver_debug_level_set(XGE_TRACE); 161a23fd118Syl150051 162a23fd118Syl150051 mac_init_ops(&xge_ops, "xge"); 163a23fd118Syl150051 if ((ret = mod_install(&modlinkage)) != 0) { 164a23fd118Syl150051 xge_hal_driver_terminate(); 165a23fd118Syl150051 mac_fini_ops(&xge_ops); 166a23fd118Syl150051 xge_debug_osdep(XGE_ERR, "%s", 167a23fd118Syl150051 "Unable to install the driver"); 168a23fd118Syl150051 return (ret); 169a23fd118Syl150051 } 170a23fd118Syl150051 171a23fd118Syl150051 return (0); 172a23fd118Syl150051 } 173a23fd118Syl150051 174a23fd118Syl150051 /* 175a23fd118Syl150051 * _fini 176a23fd118Syl150051 * 177a23fd118Syl150051 * Solaris standard _fini function for device driver 178a23fd118Syl150051 */ 179a23fd118Syl150051 int 180a23fd118Syl150051 _fini(void) 181a23fd118Syl150051 { 182a23fd118Syl150051 int ret; 183a23fd118Syl150051 184a23fd118Syl150051 ret = mod_remove(&modlinkage); 185a23fd118Syl150051 if (ret == 0) { 186a23fd118Syl150051 xge_hal_driver_terminate(); 187a23fd118Syl150051 mac_fini_ops(&xge_ops); 188a23fd118Syl150051 } 189a23fd118Syl150051 190a23fd118Syl150051 return (ret); 191a23fd118Syl150051 } 192a23fd118Syl150051 193a23fd118Syl150051 /* 194a23fd118Syl150051 * _info 195a23fd118Syl150051 * 196a23fd118Syl150051 * Solaris standard _info function for device driver 197a23fd118Syl150051 */ 198a23fd118Syl150051 int 199a23fd118Syl150051 _info(struct modinfo *pModinfo) 200a23fd118Syl150051 { 201a23fd118Syl150051 return (mod_info(&modlinkage, pModinfo)); 202a23fd118Syl150051 } 203a23fd118Syl150051 204a23fd118Syl150051 /* 205a23fd118Syl150051 * xge_isr 206a23fd118Syl150051 * @arg: pointer to device private strucutre(hldev) 207a23fd118Syl150051 * 208a23fd118Syl150051 * This is the ISR scheduled by the OS to indicate to the 209a23fd118Syl150051 * driver that the receive/transmit operation is completed. 210a23fd118Syl150051 */ 211*da14cebeSEric Cheng /* ARGSUSED */ 212a23fd118Syl150051 static uint_t 2137eced415Sxw161283 xge_isr(caddr_t arg0, caddr_t arg1) 214a23fd118Syl150051 { 215a23fd118Syl150051 xge_hal_status_e status; 2167eced415Sxw161283 xge_hal_device_t *hldev = (xge_hal_device_t *)arg0; 217a23fd118Syl150051 xgelldev_t *lldev = xge_hal_device_private(hldev); 218a23fd118Syl150051 219a23fd118Syl150051 if (!lldev->is_initialized) { 2207eced415Sxw161283 return (DDI_INTR_UNCLAIMED); 221a23fd118Syl150051 } 222a23fd118Syl150051 223a23fd118Syl150051 status = xge_hal_device_handle_irq(hldev); 224a23fd118Syl150051 225a23fd118Syl150051 return ((status == XGE_HAL_ERR_WRONG_IRQ) ? 226a23fd118Syl150051 DDI_INTR_UNCLAIMED : DDI_INTR_CLAIMED); 227a23fd118Syl150051 } 228a23fd118Syl150051 229a23fd118Syl150051 /* 2307eced415Sxw161283 * Interrupt handler for transmit when MSI-X interrupt mechasnism is used 2317eced415Sxw161283 */ 2327eced415Sxw161283 /* ARGSUSED */ 2337eced415Sxw161283 static uint_t 2347eced415Sxw161283 xge_fifo_msix_isr(caddr_t arg0, caddr_t arg1) 2357eced415Sxw161283 { 2367eced415Sxw161283 int got_tx; 2377eced415Sxw161283 xge_hal_channel_t *channel = (xge_hal_channel_t *)arg0; 2387eced415Sxw161283 xgelldev_t *lldev = xge_hal_device_private(channel->devh); 2397eced415Sxw161283 2407eced415Sxw161283 if (!lldev->is_initialized) { 2417eced415Sxw161283 return (DDI_INTR_UNCLAIMED); 2427eced415Sxw161283 } 2437eced415Sxw161283 (void) xge_hal_device_poll_tx_channel(channel, &got_tx); 2447eced415Sxw161283 2457eced415Sxw161283 return (DDI_INTR_CLAIMED); 2467eced415Sxw161283 } 2477eced415Sxw161283 2487eced415Sxw161283 /* 2497eced415Sxw161283 * Interrupt handler for receive when MSI-X interrupt mechasnism is used 2507eced415Sxw161283 */ 2517eced415Sxw161283 /* ARGSUSED */ 2527eced415Sxw161283 static uint_t 2537eced415Sxw161283 xge_ring_msix_isr(caddr_t arg0, caddr_t arg1) 2547eced415Sxw161283 { 2557eced415Sxw161283 int got_rx; 2567eced415Sxw161283 xge_hal_channel_t *channel = (xge_hal_channel_t *)arg0; 2577eced415Sxw161283 xgelldev_t *lldev = xge_hal_device_private(channel->devh); 2587eced415Sxw161283 2597eced415Sxw161283 if (!lldev->is_initialized) { 2607eced415Sxw161283 return (DDI_INTR_UNCLAIMED); 2617eced415Sxw161283 } 2627eced415Sxw161283 (void) xge_hal_device_poll_rx_channel(channel, &got_rx); 2637eced415Sxw161283 2647eced415Sxw161283 return (DDI_INTR_CLAIMED); 2657eced415Sxw161283 } 2667eced415Sxw161283 2677eced415Sxw161283 /* 2687eced415Sxw161283 * Configure single ring 2697eced415Sxw161283 */ 2707eced415Sxw161283 static void 271*da14cebeSEric Cheng xge_ring_config(dev_info_t *dev_info, xge_hal_device_config_t *device_config, 272*da14cebeSEric Cheng int index) 2737eced415Sxw161283 { 2747eced415Sxw161283 char msg[MSG_SIZE]; 2757eced415Sxw161283 276*da14cebeSEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_configured", index); 277*da14cebeSEric Cheng device_config->ring.queue[index].configured = 2787eced415Sxw161283 ddi_prop_get_int(DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, 279*da14cebeSEric Cheng msg, index < XGELL_RX_RING_NUM_MAX ? 1 : 0); 2807eced415Sxw161283 2817eced415Sxw161283 /* no point to configure it further if unconfigured */ 282*da14cebeSEric Cheng if (!device_config->ring.queue[index].configured) 2837eced415Sxw161283 return; 2847eced415Sxw161283 2857eced415Sxw161283 #if defined(__sparc) 286*da14cebeSEric Cheng device_config->ring.queue[index].no_snoop_bits = 1; 2877eced415Sxw161283 #endif 2887eced415Sxw161283 289*da14cebeSEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_max", index); 290*da14cebeSEric Cheng device_config->ring.queue[index].max = 2917eced415Sxw161283 ddi_prop_get_int(DDI_DEV_T_ANY, 2927eced415Sxw161283 dev_info, DDI_PROP_DONTPASS, msg, 2937eced415Sxw161283 XGE_HAL_DEFAULT_USE_HARDCODE); 2947eced415Sxw161283 295*da14cebeSEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_initial", index); 296*da14cebeSEric Cheng device_config->ring.queue[index].initial = 2977eced415Sxw161283 ddi_prop_get_int(DDI_DEV_T_ANY, 2987eced415Sxw161283 dev_info, DDI_PROP_DONTPASS, msg, 2997eced415Sxw161283 XGE_HAL_DEFAULT_USE_HARDCODE); 3007eced415Sxw161283 301*da14cebeSEric Cheng if (device_config->ring.queue[index].initial == 3027eced415Sxw161283 XGE_HAL_DEFAULT_USE_HARDCODE) { 303*da14cebeSEric Cheng device_config->ring.queue[index].initial = 304*da14cebeSEric Cheng device_config->ring.queue[index].max = 305*da14cebeSEric Cheng XGE_HAL_DEFAULT_RING_QUEUE_BLOCKS; 3067eced415Sxw161283 } 3077eced415Sxw161283 308*da14cebeSEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_buffer_mode", index); 309*da14cebeSEric Cheng device_config->ring.queue[index].buffer_mode = 3107eced415Sxw161283 ddi_prop_get_int(DDI_DEV_T_ANY, 3117eced415Sxw161283 dev_info, DDI_PROP_DONTPASS, msg, 3127eced415Sxw161283 XGE_HAL_RING_QUEUE_BUFFER_MODE_DEFAULT); 3137eced415Sxw161283 314*da14cebeSEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_dram_size_mb", index); 315*da14cebeSEric Cheng device_config->ring.queue[index].dram_size_mb = 3167eced415Sxw161283 ddi_prop_get_int(DDI_DEV_T_ANY, 3177eced415Sxw161283 dev_info, DDI_PROP_DONTPASS, msg, 3187eced415Sxw161283 XGE_HAL_DEFAULT_USE_HARDCODE); 3197eced415Sxw161283 3207eced415Sxw161283 (void) xge_os_snprintf(msg, MSG_SIZE, 321*da14cebeSEric Cheng "ring%d_backoff_interval_us", index); 322*da14cebeSEric Cheng device_config->ring.queue[index].backoff_interval_us = 3237eced415Sxw161283 ddi_prop_get_int(DDI_DEV_T_ANY, 3247eced415Sxw161283 dev_info, DDI_PROP_DONTPASS, msg, 3257eced415Sxw161283 XGE_HAL_DEFAULT_BACKOFF_INTERVAL_US); 3267eced415Sxw161283 327*da14cebeSEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_max_frm_len", index); 328*da14cebeSEric Cheng device_config->ring.queue[index].max_frm_len = 3297eced415Sxw161283 ddi_prop_get_int(DDI_DEV_T_ANY, 3307eced415Sxw161283 dev_info, DDI_PROP_DONTPASS, msg, 3317eced415Sxw161283 XGE_HAL_RING_USE_MTU); 3327eced415Sxw161283 3337eced415Sxw161283 334*da14cebeSEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_priority", index); 335*da14cebeSEric Cheng device_config->ring.queue[index].priority = 3367eced415Sxw161283 ddi_prop_get_int(DDI_DEV_T_ANY, 3377eced415Sxw161283 dev_info, DDI_PROP_DONTPASS, msg, 3387eced415Sxw161283 XGE_HAL_DEFAULT_RING_PRIORITY); 3397eced415Sxw161283 340*da14cebeSEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_urange_a", index); 341*da14cebeSEric Cheng device_config->ring.queue[index].rti.urange_a = 3427eced415Sxw161283 ddi_prop_get_int(DDI_DEV_T_ANY, 3437eced415Sxw161283 dev_info, DDI_PROP_DONTPASS, msg, 3447eced415Sxw161283 XGE_HAL_DEFAULT_RX_URANGE_A); 3457eced415Sxw161283 346*da14cebeSEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_ufc_a", index); 347*da14cebeSEric Cheng device_config->ring.queue[index].rti.ufc_a = 3487eced415Sxw161283 ddi_prop_get_int(DDI_DEV_T_ANY, 3497eced415Sxw161283 dev_info, DDI_PROP_DONTPASS, msg, 3507eced415Sxw161283 XGE_HAL_DEFAULT_RX_UFC_A); 3517eced415Sxw161283 352*da14cebeSEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_urange_b", index); 353*da14cebeSEric Cheng device_config->ring.queue[index].rti.urange_b = 3547eced415Sxw161283 ddi_prop_get_int(DDI_DEV_T_ANY, 3557eced415Sxw161283 dev_info, DDI_PROP_DONTPASS, msg, 3567eced415Sxw161283 XGE_HAL_DEFAULT_RX_URANGE_B); 3577eced415Sxw161283 358*da14cebeSEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_ufc_b", index); 359*da14cebeSEric Cheng device_config->ring.queue[index].rti.ufc_b = 3607eced415Sxw161283 ddi_prop_get_int(DDI_DEV_T_ANY, 3617eced415Sxw161283 dev_info, DDI_PROP_DONTPASS, msg, 3627eced415Sxw161283 device_config->mtu > XGE_HAL_DEFAULT_MTU ? 3637eced415Sxw161283 XGE_HAL_DEFAULT_RX_UFC_B_J: 3647eced415Sxw161283 XGE_HAL_DEFAULT_RX_UFC_B_N); 3657eced415Sxw161283 366*da14cebeSEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_urange_c", index); 367*da14cebeSEric Cheng device_config->ring.queue[index].rti.urange_c = 3687eced415Sxw161283 ddi_prop_get_int(DDI_DEV_T_ANY, 3697eced415Sxw161283 dev_info, DDI_PROP_DONTPASS, msg, 3707eced415Sxw161283 XGE_HAL_DEFAULT_RX_URANGE_C); 3717eced415Sxw161283 372*da14cebeSEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_ufc_c", index); 373*da14cebeSEric Cheng device_config->ring.queue[index].rti.ufc_c = 3747eced415Sxw161283 ddi_prop_get_int(DDI_DEV_T_ANY, 3757eced415Sxw161283 dev_info, DDI_PROP_DONTPASS, msg, 3767eced415Sxw161283 device_config->mtu > XGE_HAL_DEFAULT_MTU ? 3777eced415Sxw161283 XGE_HAL_DEFAULT_RX_UFC_C_J: 3787eced415Sxw161283 XGE_HAL_DEFAULT_RX_UFC_C_N); 3797eced415Sxw161283 380*da14cebeSEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_ufc_d", index); 381*da14cebeSEric Cheng device_config->ring.queue[index].rti.ufc_d = 3827eced415Sxw161283 ddi_prop_get_int(DDI_DEV_T_ANY, 3837eced415Sxw161283 dev_info, DDI_PROP_DONTPASS, msg, 3847eced415Sxw161283 XGE_HAL_DEFAULT_RX_UFC_D); 3857eced415Sxw161283 386*da14cebeSEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_timer_val", index); 387*da14cebeSEric Cheng device_config->ring.queue[index].rti.timer_val_us = 3887eced415Sxw161283 ddi_prop_get_int(DDI_DEV_T_ANY, 3897eced415Sxw161283 dev_info, DDI_PROP_DONTPASS, msg, 3907eced415Sxw161283 XGE_HAL_DEFAULT_RX_TIMER_VAL); 3917eced415Sxw161283 392*da14cebeSEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_timer_ac_en", index); 393*da14cebeSEric Cheng device_config->ring.queue[index].rti.timer_ac_en = 3947eced415Sxw161283 ddi_prop_get_int(DDI_DEV_T_ANY, 3957eced415Sxw161283 dev_info, DDI_PROP_DONTPASS, msg, 3967eced415Sxw161283 XGE_HAL_DEFAULT_RX_TIMER_AC_EN); 3977eced415Sxw161283 398*da14cebeSEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_indicate_max_pkts", 399*da14cebeSEric Cheng index); 400*da14cebeSEric Cheng device_config->ring.queue[index].indicate_max_pkts = 4017eced415Sxw161283 ddi_prop_get_int(DDI_DEV_T_ANY, 4027eced415Sxw161283 dev_info, DDI_PROP_DONTPASS, msg, 4037eced415Sxw161283 (device_config->bimodal_interrupts ? 4047eced415Sxw161283 XGE_HAL_DEFAULT_INDICATE_MAX_PKTS_B : 4057eced415Sxw161283 XGE_HAL_DEFAULT_INDICATE_MAX_PKTS_N)); 4067eced415Sxw161283 407*da14cebeSEric Cheng /* 408*da14cebeSEric Cheng * Enable RTH steering if needed HERE!!!! 409*da14cebeSEric Cheng */ 410*da14cebeSEric Cheng if (device_config->rth_en == XGE_HAL_RTH_ENABLE) 411*da14cebeSEric Cheng device_config->ring.queue[index].rth_en = 1; 4127eced415Sxw161283 } 4137eced415Sxw161283 4147eced415Sxw161283 /* 4157eced415Sxw161283 * Configure single fifo 4167eced415Sxw161283 */ 4177eced415Sxw161283 static void 418*da14cebeSEric Cheng xge_fifo_config(dev_info_t *dev_info, xge_hal_device_config_t *device_config, 419*da14cebeSEric Cheng int index) 4207eced415Sxw161283 { 4217eced415Sxw161283 char msg[MSG_SIZE]; 4227eced415Sxw161283 423*da14cebeSEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_configured", index); 424*da14cebeSEric Cheng device_config->fifo.queue[index].configured = 4257eced415Sxw161283 ddi_prop_get_int(DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, 426*da14cebeSEric Cheng msg, index < XGELL_TX_RING_NUM_MAX ? 1 : 0); 4277eced415Sxw161283 4287eced415Sxw161283 /* no point to configure it further */ 429*da14cebeSEric Cheng if (!device_config->fifo.queue[index].configured) 4307eced415Sxw161283 return; 4317eced415Sxw161283 4327eced415Sxw161283 #if defined(__sparc) 433*da14cebeSEric Cheng device_config->fifo.queue[index].no_snoop_bits = 1; 4347eced415Sxw161283 #endif 4357eced415Sxw161283 436*da14cebeSEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_max", index); 437*da14cebeSEric Cheng device_config->fifo.queue[index].max = ddi_prop_get_int(DDI_DEV_T_ANY, 4387eced415Sxw161283 dev_info, DDI_PROP_DONTPASS, msg, 4397eced415Sxw161283 XGE_HAL_DEFAULT_USE_HARDCODE); 4407eced415Sxw161283 441*da14cebeSEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_initial", index); 442*da14cebeSEric Cheng device_config->fifo.queue[index].initial = 443*da14cebeSEric Cheng ddi_prop_get_int(DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg, 4447eced415Sxw161283 XGE_HAL_DEFAULT_USE_HARDCODE); 4457eced415Sxw161283 446*da14cebeSEric Cheng #if 0 447*da14cebeSEric Cheng if (device_config->fifo.queue[index].initial == 4487eced415Sxw161283 XGE_HAL_DEFAULT_USE_HARDCODE) { 4497eced415Sxw161283 if (device_config->mtu > XGE_HAL_DEFAULT_MTU) { 450*da14cebeSEric Cheng device_config->fifo.queue[index].initial = 451*da14cebeSEric Cheng device_config->fifo.queue[index].max = 4527eced415Sxw161283 XGE_HAL_DEFAULT_FIFO_QUEUE_LENGTH_J; 4537eced415Sxw161283 } else { 454*da14cebeSEric Cheng device_config->fifo.queue[index].initial = 455*da14cebeSEric Cheng device_config->fifo.queue[index].max = 4567eced415Sxw161283 XGE_HAL_DEFAULT_FIFO_QUEUE_LENGTH_N; 4577eced415Sxw161283 } 4587eced415Sxw161283 } 459*da14cebeSEric Cheng #else 460*da14cebeSEric Cheng if (device_config->fifo.queue[index].initial == 461*da14cebeSEric Cheng XGE_HAL_DEFAULT_USE_HARDCODE) { 462*da14cebeSEric Cheng device_config->fifo.queue[index].max = 463*da14cebeSEric Cheng device_config->fifo.queue[index].initial = 464*da14cebeSEric Cheng XGE_HAL_DEFAULT_FIFO_QUEUE_LENGTH_A; 465*da14cebeSEric Cheng } 466*da14cebeSEric Cheng #endif 4677eced415Sxw161283 468*da14cebeSEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_intr", index); 469*da14cebeSEric Cheng device_config->fifo.queue[index].intr = ddi_prop_get_int(DDI_DEV_T_ANY, 4707eced415Sxw161283 dev_info, DDI_PROP_DONTPASS, msg, 4717eced415Sxw161283 XGE_HAL_DEFAULT_FIFO_QUEUE_INTR); 4727eced415Sxw161283 4737eced415Sxw161283 /* 4747eced415Sxw161283 * TTI 0 configuration 4757eced415Sxw161283 */ 476*da14cebeSEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_enable", index); 477*da14cebeSEric Cheng device_config->fifo.queue[index].tti[index].enabled = ddi_prop_get_int( 4787eced415Sxw161283 DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg, 1); 4797eced415Sxw161283 480*da14cebeSEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_urange_a", index); 481*da14cebeSEric Cheng device_config->fifo.queue[index].tti[index].urange_a = ddi_prop_get_int( 4827eced415Sxw161283 DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg, 4837eced415Sxw161283 XGE_HAL_DEFAULT_TX_URANGE_A); 4847eced415Sxw161283 485*da14cebeSEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_ufc_a", index); 486*da14cebeSEric Cheng device_config->fifo.queue[index].tti[index].ufc_a = ddi_prop_get_int( 4877eced415Sxw161283 DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg, 4887eced415Sxw161283 XGE_HAL_DEFAULT_TX_UFC_A); 4897eced415Sxw161283 490*da14cebeSEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_urange_b", index); 491*da14cebeSEric Cheng device_config->fifo.queue[index].tti[index].urange_b = ddi_prop_get_int( 4927eced415Sxw161283 DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg, 4937eced415Sxw161283 XGE_HAL_DEFAULT_TX_URANGE_B); 4947eced415Sxw161283 495*da14cebeSEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_ufc_b", index); 496*da14cebeSEric Cheng device_config->fifo.queue[index].tti[index].ufc_b = ddi_prop_get_int( 4977eced415Sxw161283 DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg, 4987eced415Sxw161283 XGE_HAL_DEFAULT_TX_UFC_B); 4997eced415Sxw161283 500*da14cebeSEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_urange_c", index); 501*da14cebeSEric Cheng device_config->fifo.queue[index].tti[index].urange_c = ddi_prop_get_int( 5027eced415Sxw161283 DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg, 5037eced415Sxw161283 XGE_HAL_DEFAULT_TX_URANGE_C); 5047eced415Sxw161283 505*da14cebeSEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_ufc_c", index); 506*da14cebeSEric Cheng device_config->fifo.queue[index].tti[index].ufc_c = ddi_prop_get_int( 5077eced415Sxw161283 DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg, 5087eced415Sxw161283 XGE_HAL_DEFAULT_TX_UFC_C); 5097eced415Sxw161283 510*da14cebeSEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_ufc_d", index); 511*da14cebeSEric Cheng device_config->fifo.queue[index].tti[index].ufc_d = ddi_prop_get_int( 5127eced415Sxw161283 DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg, 5137eced415Sxw161283 XGE_HAL_DEFAULT_TX_UFC_D); 5147eced415Sxw161283 515*da14cebeSEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_timer_ac_en", index); 516*da14cebeSEric Cheng device_config->fifo.queue[index].tti[index].timer_ac_en = 517*da14cebeSEric Cheng ddi_prop_get_int(DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg, 5187eced415Sxw161283 XGE_HAL_DEFAULT_TX_TIMER_AC_EN); 5197eced415Sxw161283 520*da14cebeSEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_timer_val", index); 521*da14cebeSEric Cheng device_config->fifo.queue[index].tti[index].timer_val_us = 522*da14cebeSEric Cheng ddi_prop_get_int(DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg, 5237eced415Sxw161283 XGE_HAL_DEFAULT_TX_TIMER_VAL); 5247eced415Sxw161283 525*da14cebeSEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_timer_ci_en", index); 526*da14cebeSEric Cheng device_config->fifo.queue[index].tti[index].timer_ci_en = 527*da14cebeSEric Cheng ddi_prop_get_int(DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg, 5287eced415Sxw161283 XGE_HAL_DEFAULT_TX_TIMER_CI_EN); 5297eced415Sxw161283 } 5307eced415Sxw161283 5317eced415Sxw161283 /* 532a23fd118Syl150051 * xge_configuration_init 533a23fd118Syl150051 * @device_config: pointer to xge_hal_device_config_t 534a23fd118Syl150051 * 535a23fd118Syl150051 * This function will lookup properties from .conf file to init 536a23fd118Syl150051 * the configuration data structure. If a property is not in .conf 537a23fd118Syl150051 * file, the default value should be set. 538a23fd118Syl150051 */ 539a23fd118Syl150051 static void 540a23fd118Syl150051 xge_configuration_init(dev_info_t *dev_info, 541*da14cebeSEric Cheng xge_hal_device_config_t *device_config, xgell_config_t *xgell_config) 542a23fd118Syl150051 { 5437eced415Sxw161283 int i, rings_configured = 0, fifos_configured = 0; 5447eced415Sxw161283 545a23fd118Syl150051 /* 546*da14cebeSEric Cheng * Initialize link layer configuration first 547*da14cebeSEric Cheng */ 548*da14cebeSEric Cheng xgell_config->rx_dma_lowat = ddi_prop_get_int(DDI_DEV_T_ANY, dev_info, 549*da14cebeSEric Cheng DDI_PROP_DONTPASS, "rx_dma_lowat", XGELL_RX_DMA_LOWAT); 550*da14cebeSEric Cheng xgell_config->rx_pkt_burst = ddi_prop_get_int(DDI_DEV_T_ANY, 551*da14cebeSEric Cheng dev_info, DDI_PROP_DONTPASS, "rx_pkt_burst", XGELL_RX_PKT_BURST); 552*da14cebeSEric Cheng xgell_config->tx_dma_lowat = ddi_prop_get_int(DDI_DEV_T_ANY, dev_info, 553*da14cebeSEric Cheng DDI_PROP_DONTPASS, "tx_dma_lowat", XGELL_TX_DMA_LOWAT); 554*da14cebeSEric Cheng xgell_config->lso_enable = ddi_prop_get_int(DDI_DEV_T_ANY, dev_info, 555*da14cebeSEric Cheng DDI_PROP_DONTPASS, "lso_enable", XGELL_CONF_ENABLE_BY_DEFAULT); 556*da14cebeSEric Cheng xgell_config->msix_enable = ddi_prop_get_int(DDI_DEV_T_ANY, dev_info, 557*da14cebeSEric Cheng DDI_PROP_DONTPASS, "msix_enable", XGELL_CONF_ENABLE_BY_DEFAULT); 558*da14cebeSEric Cheng 559*da14cebeSEric Cheng xgell_config->grouping = ddi_prop_get_int(DDI_DEV_T_ANY, dev_info, 560*da14cebeSEric Cheng DDI_PROP_DONTPASS, "grouping", XGELL_CONF_GROUP_POLICY_DEFAULT); 561*da14cebeSEric Cheng 562*da14cebeSEric Cheng switch (xgell_config->grouping) { 563*da14cebeSEric Cheng case XGELL_CONF_GROUP_POLICY_VIRT: 564*da14cebeSEric Cheng /* 565*da14cebeSEric Cheng * Enable layer 2 steering for better virtualization 566*da14cebeSEric Cheng */ 567*da14cebeSEric Cheng device_config->rth_en = XGE_HAL_RTH_DISABLE; 568*da14cebeSEric Cheng device_config->rts_mac_en = XGE_HAL_RTS_MAC_ENABLE; 569*da14cebeSEric Cheng break; 570*da14cebeSEric Cheng case XGELL_CONF_GROUP_POLICY_PERF: 571*da14cebeSEric Cheng /* 572*da14cebeSEric Cheng * Configure layer 4 RTH to hashing inbound traffic 573*da14cebeSEric Cheng */ 574*da14cebeSEric Cheng device_config->rth_en = XGE_HAL_RTH_ENABLE; 575*da14cebeSEric Cheng device_config->rth_bucket_size = XGE_HAL_MAX_RTH_BUCKET_SIZE; 576*da14cebeSEric Cheng device_config->rth_spdm_en = XGE_HAL_RTH_SPDM_DISABLE; 577*da14cebeSEric Cheng device_config->rth_spdm_use_l4 = XGE_HAL_RTH_SPDM_USE_L4; 578*da14cebeSEric Cheng 579*da14cebeSEric Cheng device_config->rts_mac_en = XGE_HAL_RTS_MAC_DISABLE; 580*da14cebeSEric Cheng break; 581*da14cebeSEric Cheng case XGELL_CONF_GROUP_POLICY_BASIC: 582*da14cebeSEric Cheng default: 583*da14cebeSEric Cheng /* 584*da14cebeSEric Cheng * Disable both RTS and RTH for single ring configuration 585*da14cebeSEric Cheng */ 586*da14cebeSEric Cheng device_config->rth_en = XGE_HAL_RTH_DISABLE; 587*da14cebeSEric Cheng device_config->rts_mac_en = XGE_HAL_RTS_MAC_DISABLE; 588*da14cebeSEric Cheng break; 589*da14cebeSEric Cheng } 590*da14cebeSEric Cheng 591*da14cebeSEric Cheng /* 592a23fd118Syl150051 * Initialize common properties 593a23fd118Syl150051 */ 594a23fd118Syl150051 device_config->mtu = ddi_prop_get_int(DDI_DEV_T_ANY, 595a23fd118Syl150051 dev_info, DDI_PROP_DONTPASS, "default_mtu", 596a23fd118Syl150051 XGE_HAL_DEFAULT_INITIAL_MTU); 597a23fd118Syl150051 device_config->isr_polling_cnt = ddi_prop_get_int(DDI_DEV_T_ANY, 598a23fd118Syl150051 dev_info, DDI_PROP_DONTPASS, "isr_polling_cnt", 599a23fd118Syl150051 XGE_HAL_DEFAULT_ISR_POLLING_CNT); 600a23fd118Syl150051 device_config->latency_timer = ddi_prop_get_int(DDI_DEV_T_ANY, 601a23fd118Syl150051 dev_info, DDI_PROP_DONTPASS, "latency_timer", 602a23fd118Syl150051 XGE_HAL_DEFAULT_LATENCY_TIMER); 603a23fd118Syl150051 device_config->max_splits_trans = ddi_prop_get_int(DDI_DEV_T_ANY, 604a23fd118Syl150051 dev_info, DDI_PROP_DONTPASS, "max_splits_trans", 605a23fd118Syl150051 XGE_HAL_DEFAULT_SPLIT_TRANSACTION); 606a23fd118Syl150051 device_config->mmrb_count = ddi_prop_get_int(DDI_DEV_T_ANY, 607a23fd118Syl150051 dev_info, DDI_PROP_DONTPASS, "mmrb_count", 608a23fd118Syl150051 XGE_HAL_DEFAULT_MMRB_COUNT); 609a23fd118Syl150051 device_config->shared_splits = ddi_prop_get_int(DDI_DEV_T_ANY, 610a23fd118Syl150051 dev_info, DDI_PROP_DONTPASS, "shared_splits", 611a23fd118Syl150051 XGE_HAL_DEFAULT_SHARED_SPLITS); 612a23fd118Syl150051 device_config->stats_refresh_time_sec = ddi_prop_get_int(DDI_DEV_T_ANY, 613a23fd118Syl150051 dev_info, DDI_PROP_DONTPASS, "stats_refresh_time", 614a23fd118Syl150051 XGE_HAL_DEFAULT_STATS_REFRESH_TIME); 615a23fd118Syl150051 device_config->device_poll_millis = ddi_prop_get_int(DDI_DEV_T_ANY, 616a23fd118Syl150051 dev_info, DDI_PROP_DONTPASS, "device_poll_millis", 617a23fd118Syl150051 XGE_HAL_DEFAULT_DEVICE_POLL_MILLIS); 618a23fd118Syl150051 device_config->pci_freq_mherz = ddi_prop_get_int(DDI_DEV_T_ANY, 6198347601bSyl150051 dev_info, DDI_PROP_DONTPASS, "pci_freq_mherz", 6208347601bSyl150051 XGE_HAL_DEFAULT_USE_HARDCODE); 621a23fd118Syl150051 622a23fd118Syl150051 /* 623a23fd118Syl150051 * Initialize ring properties 624a23fd118Syl150051 */ 625a23fd118Syl150051 device_config->ring.memblock_size = ddi_prop_get_int(DDI_DEV_T_ANY, 626a23fd118Syl150051 dev_info, DDI_PROP_DONTPASS, "ring_memblock_size", 627a23fd118Syl150051 XGE_HAL_DEFAULT_RING_MEMBLOCK_SIZE); 628a23fd118Syl150051 device_config->ring.strip_vlan_tag = XGE_HAL_RING_DONOT_STRIP_VLAN_TAG; 629a23fd118Syl150051 6307eced415Sxw161283 /* 6317eced415Sxw161283 * Bimodal Interrupts - TTI 56 configuration 6327eced415Sxw161283 */ 6337eced415Sxw161283 device_config->bimodal_interrupts = ddi_prop_get_int( 6347eced415Sxw161283 DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, "bimodal_interrupts", 6357eced415Sxw161283 XGE_HAL_DEFAULT_BIMODAL_INTERRUPTS); 6367eced415Sxw161283 device_config->bimodal_timer_lo_us = ddi_prop_get_int( 6377eced415Sxw161283 DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, "bimodal_timer_lo_us", 6387eced415Sxw161283 XGE_HAL_DEFAULT_BIMODAL_TIMER_LO_US); 6397eced415Sxw161283 device_config->bimodal_timer_hi_us = ddi_prop_get_int( 6407eced415Sxw161283 DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, "bimodal_timer_hi_us", 6417eced415Sxw161283 XGE_HAL_DEFAULT_BIMODAL_TIMER_HI_US); 6427eced415Sxw161283 6437eced415Sxw161283 /* 6447eced415Sxw161283 * Go through all possibly configured rings. Each ring could be 6457eced415Sxw161283 * configured individually. To enable/disable specific ring, just 6467eced415Sxw161283 * set ring->configured = [1|0]. 6477eced415Sxw161283 * 6487eced415Sxw161283 * By default *all* rings enabled. 6497eced415Sxw161283 */ 6507eced415Sxw161283 for (i = 0; i < XGE_HAL_MAX_RING_NUM; i++) { 6517eced415Sxw161283 xge_ring_config(dev_info, device_config, i); 6527eced415Sxw161283 if (device_config->ring.queue[i].configured) 6537eced415Sxw161283 rings_configured++; 654a23fd118Syl150051 } 655a23fd118Syl150051 656a23fd118Syl150051 /* 657a23fd118Syl150051 * Initialize mac properties 658a23fd118Syl150051 */ 659a23fd118Syl150051 device_config->mac.tmac_util_period = ddi_prop_get_int(DDI_DEV_T_ANY, 660a23fd118Syl150051 dev_info, DDI_PROP_DONTPASS, "mac_tmac_util_period", 661a23fd118Syl150051 XGE_HAL_DEFAULT_TMAC_UTIL_PERIOD); 662a23fd118Syl150051 device_config->mac.rmac_util_period = ddi_prop_get_int(DDI_DEV_T_ANY, 663a23fd118Syl150051 dev_info, DDI_PROP_DONTPASS, "mac_rmac_util_period", 664a23fd118Syl150051 XGE_HAL_DEFAULT_RMAC_UTIL_PERIOD); 665a23fd118Syl150051 device_config->mac.rmac_bcast_en = ddi_prop_get_int(DDI_DEV_T_ANY, 666a23fd118Syl150051 dev_info, DDI_PROP_DONTPASS, "mac_rmac_bcast_en", 667a23fd118Syl150051 1); /* HAL never provide a good named macro */ 6688347601bSyl150051 device_config->mac.rmac_pause_gen_en = ddi_prop_get_int(DDI_DEV_T_ANY, 6698347601bSyl150051 dev_info, DDI_PROP_DONTPASS, "rmac_pause_gen_en", 6708347601bSyl150051 XGE_HAL_DEFAULT_RMAC_PAUSE_GEN_DIS); 6718347601bSyl150051 device_config->mac.rmac_pause_rcv_en = ddi_prop_get_int(DDI_DEV_T_ANY, 6728347601bSyl150051 dev_info, DDI_PROP_DONTPASS, "rmac_pause_rcv_en", 6738347601bSyl150051 XGE_HAL_DEFAULT_RMAC_PAUSE_RCV_DIS); 674a23fd118Syl150051 device_config->mac.rmac_pause_time = ddi_prop_get_int(DDI_DEV_T_ANY, 675a23fd118Syl150051 dev_info, DDI_PROP_DONTPASS, "mac_rmac_pause_time", 676a23fd118Syl150051 XGE_HAL_DEFAULT_RMAC_HIGH_PTIME); 677a23fd118Syl150051 device_config->mac.mc_pause_threshold_q0q3 = 678a23fd118Syl150051 ddi_prop_get_int(DDI_DEV_T_ANY, 679a23fd118Syl150051 dev_info, DDI_PROP_DONTPASS, "mac_mc_pause_threshold_q0q3", 680a23fd118Syl150051 XGE_HAL_DEFAULT_MC_PAUSE_THRESHOLD_Q0Q3); 681a23fd118Syl150051 device_config->mac.mc_pause_threshold_q4q7 = 682a23fd118Syl150051 ddi_prop_get_int(DDI_DEV_T_ANY, 683a23fd118Syl150051 dev_info, DDI_PROP_DONTPASS, "mac_mc_pause_threshold_q4q7", 684a23fd118Syl150051 XGE_HAL_DEFAULT_MC_PAUSE_THRESHOLD_Q4Q7); 685a23fd118Syl150051 686a23fd118Syl150051 /* 687a23fd118Syl150051 * Initialize fifo properties 688a23fd118Syl150051 */ 689a23fd118Syl150051 device_config->fifo.max_frags = ddi_prop_get_int(DDI_DEV_T_ANY, 690a23fd118Syl150051 dev_info, DDI_PROP_DONTPASS, "fifo_max_frags", 691a23fd118Syl150051 XGE_HAL_DEFAULT_FIFO_FRAGS); 692a23fd118Syl150051 device_config->fifo.reserve_threshold = ddi_prop_get_int(DDI_DEV_T_ANY, 693a23fd118Syl150051 dev_info, DDI_PROP_DONTPASS, "fifo_reserve_threshold", 694a23fd118Syl150051 XGE_HAL_DEFAULT_FIFO_RESERVE_THRESHOLD); 695a23fd118Syl150051 device_config->fifo.memblock_size = ddi_prop_get_int(DDI_DEV_T_ANY, 696a23fd118Syl150051 dev_info, DDI_PROP_DONTPASS, "fifo_memblock_size", 697a23fd118Syl150051 XGE_HAL_DEFAULT_FIFO_MEMBLOCK_SIZE); 698a23fd118Syl150051 #ifdef XGE_HAL_ALIGN_XMIT 6998347601bSyl150051 device_config->fifo.alignment_size = ddi_prop_get_int(DDI_DEV_T_ANY, 7008347601bSyl150051 dev_info, DDI_PROP_DONTPASS, "fifo_copied_frag_size", 7018347601bSyl150051 XGE_HAL_DEFAULT_FIFO_ALIGNMENT_SIZE); 7028347601bSyl150051 device_config->fifo.max_aligned_frags = ddi_prop_get_int(DDI_DEV_T_ANY, 7038347601bSyl150051 dev_info, DDI_PROP_DONTPASS, "fifo_copied_max_frags", 7048347601bSyl150051 XGE_HAL_DEFAULT_FIFO_MAX_ALIGNED_FRAGS); 705a23fd118Syl150051 #endif 706a23fd118Syl150051 707a23fd118Syl150051 /* 7087eced415Sxw161283 * Go through all possibly configured fifos. Each fifo could be 7097eced415Sxw161283 * configured individually. To enable/disable specific fifo, just 7107eced415Sxw161283 * set fifo->configured = [0|1]. 7117eced415Sxw161283 * 7127eced415Sxw161283 * By default *all* fifos enabled. 713a23fd118Syl150051 */ 7147eced415Sxw161283 for (i = 0; i < XGE_HAL_MAX_FIFO_NUM; i++) { 7157eced415Sxw161283 xge_fifo_config(dev_info, device_config, i); 7167eced415Sxw161283 if (device_config->fifo.queue[i].configured) 7177eced415Sxw161283 fifos_configured++; 7187eced415Sxw161283 } 719a23fd118Syl150051 720a23fd118Syl150051 /* 721a23fd118Syl150051 * Initialize errors dumping 722a23fd118Syl150051 */ 723a23fd118Syl150051 device_config->dump_on_serr = ddi_prop_get_int(DDI_DEV_T_ANY, 724a23fd118Syl150051 dev_info, DDI_PROP_DONTPASS, "dump_on_serr", 725a23fd118Syl150051 0); 726a23fd118Syl150051 device_config->dump_on_serr = ddi_prop_get_int(DDI_DEV_T_ANY, 727a23fd118Syl150051 dev_info, DDI_PROP_DONTPASS, "dump_on_eccerr", 728a23fd118Syl150051 0); 729a23fd118Syl150051 device_config->dump_on_serr = ddi_prop_get_int(DDI_DEV_T_ANY, 730a23fd118Syl150051 dev_info, DDI_PROP_DONTPASS, "dump_on_parityerr", 731a23fd118Syl150051 0); 732a23fd118Syl150051 733a23fd118Syl150051 /* 7348347601bSyl150051 * LRO tunables 7358347601bSyl150051 */ 7368347601bSyl150051 device_config->lro_sg_size = ddi_prop_get_int(DDI_DEV_T_ANY, 7378347601bSyl150051 dev_info, DDI_PROP_DONTPASS, "lro_sg_size", 7388347601bSyl150051 XGE_HAL_DEFAULT_LRO_SG_SIZE); 7398347601bSyl150051 device_config->lro_frm_len = ddi_prop_get_int(DDI_DEV_T_ANY, 7408347601bSyl150051 dev_info, DDI_PROP_DONTPASS, "lro_frm_len", 7418347601bSyl150051 XGE_HAL_DEFAULT_LRO_FRM_LEN); 7428347601bSyl150051 7438347601bSyl150051 /* 744*da14cebeSEric Cheng * Initialize other link layer configuration first 745a23fd118Syl150051 */ 746*da14cebeSEric Cheng xgell_config->rx_buffer_total = ddi_prop_get_int(DDI_DEV_T_ANY, 747a23fd118Syl150051 dev_info, DDI_PROP_DONTPASS, "rx_buffer_total", 748*da14cebeSEric Cheng device_config->ring.queue[XGELL_RX_RING_MAIN].initial * 749a23fd118Syl150051 XGELL_RX_BUFFER_TOTAL); 750*da14cebeSEric Cheng xgell_config->rx_buffer_total += XGELL_RX_BUFFER_RECYCLE_CACHE; 751*da14cebeSEric Cheng xgell_config->rx_buffer_post_hiwat = ddi_prop_get_int(DDI_DEV_T_ANY, 752a23fd118Syl150051 dev_info, DDI_PROP_DONTPASS, "rx_buffer_post_hiwat", 753*da14cebeSEric Cheng device_config->ring.queue[XGELL_RX_RING_MAIN].initial * 754a23fd118Syl150051 XGELL_RX_BUFFER_POST_HIWAT); 755*da14cebeSEric Cheng xgell_config->rx_buffer_post_hiwat += XGELL_RX_BUFFER_RECYCLE_CACHE; 756a23fd118Syl150051 } 757a23fd118Syl150051 7587eced415Sxw161283 /* 7597eced415Sxw161283 * xge_alloc_intrs: 7607eced415Sxw161283 * 7617eced415Sxw161283 * Allocate FIXED or MSIX interrupts. 7627eced415Sxw161283 */ 7637eced415Sxw161283 static int 7647eced415Sxw161283 xge_alloc_intrs(xgelldev_t *lldev) 7657eced415Sxw161283 { 7667eced415Sxw161283 dev_info_t *dip = lldev->dev_info; 7677eced415Sxw161283 int avail, actual, count = 0; 7687eced415Sxw161283 int i, intr_behavior, ret; 7697eced415Sxw161283 7707eced415Sxw161283 if (lldev->intr_type == DDI_INTR_TYPE_MSIX) { 7717eced415Sxw161283 intr_behavior = DDI_INTR_ALLOC_STRICT; 7727eced415Sxw161283 (void) ddi_prop_create(DDI_DEV_T_NONE, dip, 7737eced415Sxw161283 DDI_PROP_CANSLEEP, "#msix-request", NULL, 0); 7747eced415Sxw161283 } else { 7757eced415Sxw161283 intr_behavior = DDI_INTR_ALLOC_NORMAL; 7767eced415Sxw161283 } 7777eced415Sxw161283 7787eced415Sxw161283 /* Get number of interrupts */ 7797eced415Sxw161283 ret = ddi_intr_get_nintrs(dip, lldev->intr_type, &count); 7807eced415Sxw161283 if ((ret != DDI_SUCCESS) || (count == 0)) { 7817eced415Sxw161283 xge_debug_osdep(XGE_ERR, "ddi_intr_get_nintrs() failed, " 7827eced415Sxw161283 "ret: %d, count: %d", ret, count); 7837eced415Sxw161283 7847eced415Sxw161283 goto _err_exit0; 7857eced415Sxw161283 } 7867eced415Sxw161283 7877eced415Sxw161283 /* Get number of available interrupts */ 7887eced415Sxw161283 ret = ddi_intr_get_navail(dip, lldev->intr_type, &avail); 7897eced415Sxw161283 if ((ret != DDI_SUCCESS) || (avail == 0)) { 7907eced415Sxw161283 xge_debug_osdep(XGE_ERR, "ddi_intr_get_navail() failure, " 7917eced415Sxw161283 "ret: %d, avail: %d", ret, avail); 7927eced415Sxw161283 7937eced415Sxw161283 goto _err_exit0; 7947eced415Sxw161283 } 7957eced415Sxw161283 7967eced415Sxw161283 if (avail < lldev->intr_cnt) { 7977eced415Sxw161283 xge_debug_osdep(XGE_ERR, "%d interrupts wanted while only " 7987eced415Sxw161283 "%d available", lldev->intr_cnt, avail); 7997eced415Sxw161283 goto _err_exit0; 8007eced415Sxw161283 } 8017eced415Sxw161283 8027eced415Sxw161283 /* Allocate an array of interrupt handles */ 8037eced415Sxw161283 lldev->intr_table_size = lldev->intr_cnt * sizeof (ddi_intr_handle_t); 8047eced415Sxw161283 lldev->intr_table = kmem_alloc(lldev->intr_table_size, KM_SLEEP); 8057eced415Sxw161283 8067eced415Sxw161283 /* Call ddi_intr_alloc() */ 8077eced415Sxw161283 ret = ddi_intr_alloc(dip, lldev->intr_table, lldev->intr_type, 0, 8087eced415Sxw161283 lldev->intr_cnt, &actual, intr_behavior); 8097eced415Sxw161283 if ((ret != DDI_SUCCESS) || (actual == 0)) { 8107eced415Sxw161283 xge_debug_osdep(XGE_ERR, "ddi_intr_alloc() failed %d", ret); 8117eced415Sxw161283 goto _err_exit1; 8127eced415Sxw161283 } 8137eced415Sxw161283 8147eced415Sxw161283 xge_debug_osdep(XGE_TRACE, "%s: Requested: %d, Granted: %d", 8157eced415Sxw161283 lldev->intr_type == DDI_INTR_TYPE_MSIX ? "MSI-X" : 8167eced415Sxw161283 "IRQA", count, actual); 8177eced415Sxw161283 8187eced415Sxw161283 if (lldev->intr_cnt != actual) { 8197eced415Sxw161283 xge_debug_osdep(XGE_ERR, "Not enough resources granted"); 8207eced415Sxw161283 goto _err_exit2; 8217eced415Sxw161283 } 8227eced415Sxw161283 8237eced415Sxw161283 /* 8247eced415Sxw161283 * Get priority for first msi, assume remaining are all the same 8257eced415Sxw161283 */ 8267eced415Sxw161283 if ((ret = ddi_intr_get_pri(lldev->intr_table[0], &lldev->intr_pri)) != 8277eced415Sxw161283 DDI_SUCCESS) { 8287eced415Sxw161283 xge_debug_osdep(XGE_ERR, "ddi_intr_get_pri() failed %d", ret); 8297eced415Sxw161283 goto _err_exit2; 8307eced415Sxw161283 } 8317eced415Sxw161283 8327eced415Sxw161283 return (DDI_SUCCESS); 8337eced415Sxw161283 8347eced415Sxw161283 _err_exit2: 8357eced415Sxw161283 /* Free already allocated intr */ 8367eced415Sxw161283 for (i = 0; i < actual; i++) { 8377eced415Sxw161283 (void) ddi_intr_free(lldev->intr_table[i]); 8387eced415Sxw161283 } 8397eced415Sxw161283 _err_exit1: 8407eced415Sxw161283 kmem_free(lldev->intr_table, lldev->intr_table_size); 841*da14cebeSEric Cheng lldev->intr_table = NULL; 8427eced415Sxw161283 _err_exit0: 8437eced415Sxw161283 if (lldev->intr_type == DDI_INTR_TYPE_MSIX) 8447eced415Sxw161283 (void) ddi_prop_remove(DDI_DEV_T_NONE, dip, "#msix-request"); 8457eced415Sxw161283 return (DDI_FAILURE); 8467eced415Sxw161283 } 8477eced415Sxw161283 8487eced415Sxw161283 /* 8497eced415Sxw161283 * xge_free_intrs: 8507eced415Sxw161283 * 8517eced415Sxw161283 * Free previously allocated interrupts. 8527eced415Sxw161283 */ 8537eced415Sxw161283 static void 8547eced415Sxw161283 xge_free_intrs(xgelldev_t *lldev) 8557eced415Sxw161283 { 8567eced415Sxw161283 int i; 8577eced415Sxw161283 dev_info_t *dip = lldev->dev_info; 8587eced415Sxw161283 8597eced415Sxw161283 /* Free already allocated intr */ 8607eced415Sxw161283 for (i = 0; i < lldev->intr_cnt; i++) { 8617eced415Sxw161283 (void) ddi_intr_free(lldev->intr_table[i]); 8627eced415Sxw161283 } 8637eced415Sxw161283 kmem_free(lldev->intr_table, lldev->intr_table_size); 864*da14cebeSEric Cheng lldev->intr_table = NULL; 8657eced415Sxw161283 8667eced415Sxw161283 if (lldev->intr_type == DDI_INTR_TYPE_MSIX) 8677eced415Sxw161283 (void) ddi_prop_remove(DDI_DEV_T_NONE, dip, "#msix-request"); 8687eced415Sxw161283 } 8697eced415Sxw161283 8707eced415Sxw161283 /* 8717eced415Sxw161283 * xge_add_intrs: 8727eced415Sxw161283 * 8737eced415Sxw161283 * Register FIXED or MSI interrupts. 8747eced415Sxw161283 */ 8757eced415Sxw161283 int 8767eced415Sxw161283 xge_add_intrs(xgelldev_t *lldev) 8777eced415Sxw161283 { 8787eced415Sxw161283 int i, ret; 8797eced415Sxw161283 xge_hal_device_t *hldev = lldev->devh; 8807eced415Sxw161283 xge_hal_device_config_t *hal_conf = &hldev->config; 8817eced415Sxw161283 xge_hal_ring_config_t *ring_conf = &hal_conf->ring; 8827eced415Sxw161283 xge_hal_fifo_config_t *fifo_conf = &hal_conf->fifo; 8837eced415Sxw161283 xge_list_t *item; 8847eced415Sxw161283 int msix_idx = 1; /* 0 by default is reserved for Alarms. */ 885*da14cebeSEric Cheng xge_hal_channel_t *assigned[XGELL_RX_RING_NUM_MAX + 886*da14cebeSEric Cheng XGELL_TX_RING_NUM_MAX + 1]; 8877eced415Sxw161283 888*da14cebeSEric Cheng xge_assert(lldev->intr_table != NULL); 8897eced415Sxw161283 switch (lldev->intr_type) { 8907eced415Sxw161283 case DDI_INTR_TYPE_FIXED: 8917eced415Sxw161283 ret = ddi_intr_add_handler(lldev->intr_table[0], 8927eced415Sxw161283 (ddi_intr_handler_t *)xge_isr, 8937eced415Sxw161283 (caddr_t)hldev, 0); 8947eced415Sxw161283 if (ret != DDI_SUCCESS) { 8957eced415Sxw161283 xge_debug_osdep(XGE_ERR, "ddi_intr_add_handler(FIXED)" 8967eced415Sxw161283 "failed %d", ret); 8977eced415Sxw161283 return (DDI_FAILURE); 8987eced415Sxw161283 } 8997eced415Sxw161283 break; 9007eced415Sxw161283 9017eced415Sxw161283 case DDI_INTR_TYPE_MSIX: 9027eced415Sxw161283 i = 0; 9037eced415Sxw161283 xge_list_for_each(item, &hldev->free_channels) { 9047eced415Sxw161283 xge_hal_channel_t *channel = xge_container_of(item, 9057eced415Sxw161283 xge_hal_channel_t, item); 9067eced415Sxw161283 i = channel->post_qid; 9077eced415Sxw161283 if (channel->type == XGE_HAL_CHANNEL_TYPE_FIFO) { 9087eced415Sxw161283 if (fifo_conf->queue[i].configured) { 9097eced415Sxw161283 assigned[msix_idx] = channel; 9107eced415Sxw161283 msix_idx++; 9117eced415Sxw161283 } 9127eced415Sxw161283 } else { 9137eced415Sxw161283 if (ring_conf->queue[i].configured) { 9147eced415Sxw161283 assigned[msix_idx] = channel; 9157eced415Sxw161283 msix_idx++; 9167eced415Sxw161283 } 9177eced415Sxw161283 } 9187eced415Sxw161283 } 9197eced415Sxw161283 for (i = 0; i < lldev->intr_cnt; i++) { 9207eced415Sxw161283 uint_t (*intr)(caddr_t, caddr_t); 9217eced415Sxw161283 caddr_t intr_arg; 9227eced415Sxw161283 9237eced415Sxw161283 /* partition MSIX vectors */ 9247eced415Sxw161283 if (i == 0) { 9257eced415Sxw161283 intr = xge_isr; 9267eced415Sxw161283 intr_arg = (caddr_t)hldev; 9277eced415Sxw161283 xge_debug_osdep(XGE_TRACE, 9287eced415Sxw161283 "Channel-A: using MSI-X #0"); 9297eced415Sxw161283 } else if (assigned[i] && assigned[i]->type == 9307eced415Sxw161283 XGE_HAL_CHANNEL_TYPE_FIFO) { 9317eced415Sxw161283 intr = xge_fifo_msix_isr; 9327eced415Sxw161283 intr_arg = (caddr_t)assigned[i]; 9337eced415Sxw161283 xge_debug_osdep(XGE_TRACE, "Channel-Tx%d" 9347eced415Sxw161283 "using MSI-X #%d", 9357eced415Sxw161283 assigned[i]->post_qid, i); 9367eced415Sxw161283 } else if (assigned[i] && assigned[i]->type == 9377eced415Sxw161283 XGE_HAL_CHANNEL_TYPE_RING) { 9387eced415Sxw161283 intr = xge_ring_msix_isr; 9397eced415Sxw161283 intr_arg = (caddr_t)assigned[i]; 9407eced415Sxw161283 xge_debug_osdep(XGE_TRACE, "Channel-Rx%d: " 9417eced415Sxw161283 "using MSI-X #%d", 9427eced415Sxw161283 assigned[i]->post_qid, i); 9437eced415Sxw161283 } 9447eced415Sxw161283 ret = ddi_intr_add_handler(lldev->intr_table[i], intr, 9457eced415Sxw161283 intr_arg, (caddr_t)(uintptr_t)i); 9467eced415Sxw161283 if (ret != DDI_SUCCESS) { 9477eced415Sxw161283 int j; 9487eced415Sxw161283 xge_debug_osdep(XGE_ERR, 9497eced415Sxw161283 "ddi_intr_add_handler()" 9507eced415Sxw161283 " failed %d", ret); 9517eced415Sxw161283 for (j = 0; j < i; j++) { 9527eced415Sxw161283 (void) ddi_intr_remove_handler( 9537eced415Sxw161283 lldev->intr_table[j]); 9547eced415Sxw161283 } 9557eced415Sxw161283 return (DDI_FAILURE); 9567eced415Sxw161283 } 9577eced415Sxw161283 } 9587eced415Sxw161283 9597eced415Sxw161283 for (i = 1; i < msix_idx; i++) 9607eced415Sxw161283 (void) xge_hal_channel_msix_set(assigned[i], i); 9617eced415Sxw161283 break; 9627eced415Sxw161283 9637eced415Sxw161283 default: 9647eced415Sxw161283 break; 9657eced415Sxw161283 } 9667eced415Sxw161283 ret = ddi_intr_get_cap(lldev->intr_table[0], &lldev->intr_cap); 9677eced415Sxw161283 if (ret != DDI_SUCCESS) { 9687eced415Sxw161283 xge_debug_osdep(XGE_ERR, "ddi_intr_get_cap() failed %d", ret); 9697eced415Sxw161283 for (i = 0; i < lldev->intr_cnt; i++) { 9707eced415Sxw161283 (void) ddi_intr_remove_handler(lldev->intr_table[i]); 9717eced415Sxw161283 } 9727eced415Sxw161283 return (DDI_FAILURE); 9737eced415Sxw161283 } 9747eced415Sxw161283 return (DDI_SUCCESS); 9757eced415Sxw161283 } 9767eced415Sxw161283 9777eced415Sxw161283 9787eced415Sxw161283 /* 9797eced415Sxw161283 * xge_enable_intrs: 9807eced415Sxw161283 * 9817eced415Sxw161283 * Enable FIXED or MSI interrupts 9827eced415Sxw161283 */ 9837eced415Sxw161283 int 9847eced415Sxw161283 xge_enable_intrs(xgelldev_t *lldev) 9857eced415Sxw161283 { 9867eced415Sxw161283 int ret, i; 9877eced415Sxw161283 9887eced415Sxw161283 if (lldev->intr_cap & DDI_INTR_FLAG_BLOCK) { 9897eced415Sxw161283 /* Call ddi_intr_block_enable() for MSI(X) interrupts */ 9907eced415Sxw161283 if ((ret = ddi_intr_block_enable(lldev->intr_table, 9917eced415Sxw161283 lldev->intr_cnt)) != DDI_SUCCESS) { 9927eced415Sxw161283 xge_debug_osdep(XGE_ERR, "ddi_intr_enable() failed, " 9937eced415Sxw161283 "ret 0x%x", ret); 9947eced415Sxw161283 return (DDI_FAILURE); 9957eced415Sxw161283 } 9967eced415Sxw161283 } else { 9977eced415Sxw161283 /* Call ddi_intr_enable for MSI(X) or FIXED interrupts */ 9987eced415Sxw161283 for (i = 0; i < lldev->intr_cnt; i++) { 9997eced415Sxw161283 if ((ret = ddi_intr_enable(lldev->intr_table[i])) 10007eced415Sxw161283 != DDI_SUCCESS) { 10017eced415Sxw161283 int j; 10027eced415Sxw161283 10037eced415Sxw161283 xge_debug_osdep(XGE_ERR, "ddi_intr_enable() " 10047eced415Sxw161283 "failed, ret 0x%x", ret); 10057eced415Sxw161283 10067eced415Sxw161283 /* unwind */ 10077eced415Sxw161283 for (j = 0; j < i; j++) { 10087eced415Sxw161283 (void) ddi_intr_disable( 10097eced415Sxw161283 lldev->intr_table[j]); 10107eced415Sxw161283 } 10117eced415Sxw161283 10127eced415Sxw161283 return (DDI_FAILURE); 10137eced415Sxw161283 } 10147eced415Sxw161283 } 10157eced415Sxw161283 } 10167eced415Sxw161283 10177eced415Sxw161283 return (DDI_SUCCESS); 10187eced415Sxw161283 } 10197eced415Sxw161283 10207eced415Sxw161283 /* 10217eced415Sxw161283 * xge_disable_intrs: 10227eced415Sxw161283 * 10237eced415Sxw161283 * Disable FIXED or MSI interrupts 10247eced415Sxw161283 */ 10257eced415Sxw161283 void 10267eced415Sxw161283 xge_disable_intrs(xgelldev_t *lldev) 10277eced415Sxw161283 { 10287eced415Sxw161283 int i; 10297eced415Sxw161283 10307eced415Sxw161283 if (lldev->intr_cap & DDI_INTR_FLAG_BLOCK) { 10317eced415Sxw161283 /* Call ddi_intr_block_disable() */ 10327eced415Sxw161283 (void) ddi_intr_block_disable(lldev->intr_table, 10337eced415Sxw161283 lldev->intr_cnt); 10347eced415Sxw161283 } else { 10357eced415Sxw161283 for (i = 0; i < lldev->intr_cnt; i++) { 10367eced415Sxw161283 (void) ddi_intr_disable(lldev->intr_table[i]); 10377eced415Sxw161283 } 10387eced415Sxw161283 } 10397eced415Sxw161283 } 10407eced415Sxw161283 10417eced415Sxw161283 /* 10427eced415Sxw161283 * xge_rem_intrs: 10437eced415Sxw161283 * 10447eced415Sxw161283 * Unregister FIXED or MSI interrupts 10457eced415Sxw161283 */ 10467eced415Sxw161283 void 10477eced415Sxw161283 xge_rem_intrs(xgelldev_t *lldev) 10487eced415Sxw161283 { 10497eced415Sxw161283 int i; 10507eced415Sxw161283 1051*da14cebeSEric Cheng xge_assert(lldev->intr_table != NULL); 1052*da14cebeSEric Cheng 10537eced415Sxw161283 /* Call ddi_intr_remove_handler() */ 10547eced415Sxw161283 for (i = 0; i < lldev->intr_cnt; i++) { 10557eced415Sxw161283 (void) ddi_intr_remove_handler(lldev->intr_table[i]); 10567eced415Sxw161283 } 10577eced415Sxw161283 } 10587eced415Sxw161283 1059a23fd118Syl150051 /* 1060a23fd118Syl150051 * xge_attach 1061a23fd118Syl150051 * @dev_info: pointer to dev_info_t structure 1062a23fd118Syl150051 * @cmd: attach command to process 1063a23fd118Syl150051 * 1064a23fd118Syl150051 * This is a solaris standard attach function. This 1065a23fd118Syl150051 * function initializes the Xframe identified 1066a23fd118Syl150051 * by the dev_info_t structure and setup the driver 1067a23fd118Syl150051 * data structures corresponding to the Xframe Card. 1068a23fd118Syl150051 * This function also registers the XFRAME device 1069a23fd118Syl150051 * instance with the MAC Layer. 1070a23fd118Syl150051 * If this function returns success then the OS 1071a23fd118Syl150051 * will attach the HBA controller to this 1072a23fd118Syl150051 * driver. 1073a23fd118Syl150051 */ 1074a23fd118Syl150051 static int 1075a23fd118Syl150051 xge_attach(dev_info_t *dev_info, ddi_attach_cmd_t cmd) 1076a23fd118Syl150051 { 1077a23fd118Syl150051 xgelldev_t *ll; 1078*da14cebeSEric Cheng xgell_config_t *xgell_config; 10797eced415Sxw161283 xge_hal_device_config_t *device_config; 1080a23fd118Syl150051 xge_hal_device_t *hldev; 1081a23fd118Syl150051 xge_hal_device_attr_t attr; 1082a23fd118Syl150051 xge_hal_status_e status; 10837eced415Sxw161283 int ret, intr_types, i; 1084a23fd118Syl150051 1085a23fd118Syl150051 xge_debug_osdep(XGE_TRACE, "XGE_ATTACH cmd %d", cmd); 1086a23fd118Syl150051 1087a23fd118Syl150051 switch (cmd) { 1088a23fd118Syl150051 case DDI_ATTACH: 1089a23fd118Syl150051 break; 1090a23fd118Syl150051 1091a23fd118Syl150051 case DDI_RESUME: 1092a23fd118Syl150051 case DDI_PM_RESUME: 1093a23fd118Syl150051 xge_debug_osdep(XGE_ERR, "%s", "resume unsupported yet"); 1094a23fd118Syl150051 ret = DDI_FAILURE; 1095a23fd118Syl150051 goto _exit0; 1096a23fd118Syl150051 1097a23fd118Syl150051 default: 1098a23fd118Syl150051 xge_debug_osdep(XGE_ERR, "cmd 0x%x unrecognized", cmd); 1099a23fd118Syl150051 ret = DDI_FAILURE; 1100a23fd118Syl150051 goto _exit0; 1101a23fd118Syl150051 } 1102a23fd118Syl150051 1103*da14cebeSEric Cheng xgell_config = kmem_zalloc(sizeof (xgell_config_t), KM_SLEEP); 11047eced415Sxw161283 device_config = kmem_zalloc(sizeof (xge_hal_device_config_t), KM_SLEEP); 1105a23fd118Syl150051 1106*da14cebeSEric Cheng /* 1107*da14cebeSEric Cheng * Initialize all configurations 1108*da14cebeSEric Cheng */ 1109*da14cebeSEric Cheng xge_configuration_init(dev_info, device_config, xgell_config); 11107eced415Sxw161283 11117eced415Sxw161283 /* Determine which types of interrupts supported */ 11127eced415Sxw161283 ret = ddi_intr_get_supported_types(dev_info, &intr_types); 11137eced415Sxw161283 if ((ret != DDI_SUCCESS) || (!(intr_types & DDI_INTR_TYPE_FIXED))) { 11147eced415Sxw161283 xge_debug_osdep(XGE_ERR, "%s", 11157eced415Sxw161283 "fixed type interrupt is not supported"); 11167eced415Sxw161283 goto _exit0a; 11177eced415Sxw161283 } 1118a23fd118Syl150051 1119a23fd118Syl150051 /* map BAR0 */ 1120a23fd118Syl150051 ret = ddi_regs_map_setup(dev_info, 1, (caddr_t *)&attr.bar0, 1121a23fd118Syl150051 (offset_t)0, (offset_t)0, &xge_dev_attr, &attr.regh0); 1122a23fd118Syl150051 if (ret != DDI_SUCCESS) { 1123a23fd118Syl150051 xge_debug_osdep(XGE_ERR, "unable to map bar0: [%d]", ret); 11247eced415Sxw161283 goto _exit0a; 1125a23fd118Syl150051 } 1126a23fd118Syl150051 1127a23fd118Syl150051 /* map BAR1 */ 1128a23fd118Syl150051 ret = ddi_regs_map_setup(dev_info, 2, (caddr_t *)&attr.bar1, 1129a23fd118Syl150051 (offset_t)0, (offset_t)0, &xge_dev_attr, &attr.regh1); 1130a23fd118Syl150051 if (ret != DDI_SUCCESS) { 1131a23fd118Syl150051 xge_debug_osdep(XGE_ERR, "unable to map bar1: [%d]", ret); 1132a23fd118Syl150051 goto _exit1; 1133a23fd118Syl150051 } 1134a23fd118Syl150051 11357eced415Sxw161283 /* map BAR2 MSI(X) */ 11367eced415Sxw161283 ret = ddi_regs_map_setup(dev_info, 2, (caddr_t *)&attr.bar2, 11377eced415Sxw161283 (offset_t)0, (offset_t)0, &xge_dev_attr, &attr.regh2); 11387eced415Sxw161283 if (ret != DDI_SUCCESS) { 11397eced415Sxw161283 xge_debug_osdep(XGE_ERR, "unable to map bar2: [%d]", ret); 11407eced415Sxw161283 goto _exit1a; 1141a23fd118Syl150051 } 1142a23fd118Syl150051 11437eced415Sxw161283 /* preallocate memory for new HAL device and private LL part */ 11447eced415Sxw161283 hldev = kmem_zalloc(sizeof (xge_hal_device_t), KM_SLEEP); 1145a23fd118Syl150051 1146a23fd118Syl150051 /* Get the PCI Configuartion space handle */ 1147a23fd118Syl150051 ret = pci_config_setup(dev_info, &attr.cfgh); 1148a23fd118Syl150051 if (ret != DDI_SUCCESS) { 1149a23fd118Syl150051 xge_debug_osdep(XGE_ERR, "%s", "can not setup config space"); 1150a23fd118Syl150051 goto _exit2a; 1151a23fd118Syl150051 } 1152a23fd118Syl150051 1153a23fd118Syl150051 attr.pdev = dev_info; 1154a23fd118Syl150051 1155a23fd118Syl150051 ret = xgell_device_alloc(hldev, dev_info, &ll); 1156a23fd118Syl150051 if (ret != DDI_SUCCESS) { 1157a23fd118Syl150051 xge_debug_osdep(XGE_ERR, 1158a23fd118Syl150051 "%s", 1159a23fd118Syl150051 "unable to allocate new LL device"); 1160a23fd118Syl150051 goto _exit3; 1161a23fd118Syl150051 } 1162a23fd118Syl150051 1163*da14cebeSEric Cheng /* 1164*da14cebeSEric Cheng * Init multiple rings configuration 1165*da14cebeSEric Cheng */ 1166*da14cebeSEric Cheng switch (xgell_config->grouping) { 1167*da14cebeSEric Cheng case XGELL_CONF_GROUP_POLICY_VIRT: 1168*da14cebeSEric Cheng ll->init_rx_rings = XGELL_RX_RING_NUM_MAX; /* 8 */ 1169*da14cebeSEric Cheng ll->init_tx_rings = XGELL_TX_RING_NUM_MAX; /* 8 */ 1170*da14cebeSEric Cheng ll->init_rx_groups = ll->init_rx_rings; 1171*da14cebeSEric Cheng break; 1172*da14cebeSEric Cheng case XGELL_CONF_GROUP_POLICY_PERF: 1173*da14cebeSEric Cheng ll->init_rx_rings = XGELL_RX_RING_NUM_MAX; /* 8 */ 1174*da14cebeSEric Cheng ll->init_tx_rings = XGELL_TX_RING_NUM_MAX; /* 8 */ 1175*da14cebeSEric Cheng ll->init_rx_groups = 1; 1176*da14cebeSEric Cheng break; 1177*da14cebeSEric Cheng case XGELL_CONF_GROUP_POLICY_BASIC: 1178*da14cebeSEric Cheng ll->init_rx_rings = XGELL_RX_RING_NUM_MIN; /* 1 */ 1179*da14cebeSEric Cheng ll->init_tx_rings = XGELL_TX_RING_NUM_MIN; /* 1 */ 1180*da14cebeSEric Cheng ll->init_rx_groups = ll->init_rx_rings; 1181*da14cebeSEric Cheng break; 1182*da14cebeSEric Cheng default: 1183*da14cebeSEric Cheng ASSERT(0); 1184*da14cebeSEric Cheng break; 1185*da14cebeSEric Cheng } 1186*da14cebeSEric Cheng 1187*da14cebeSEric Cheng /* 1188*da14cebeSEric Cheng * Init MSI-X configuration 1189*da14cebeSEric Cheng */ 1190*da14cebeSEric Cheng if (xgell_config->msix_enable && intr_types & DDI_INTR_TYPE_MSIX) { 11917eced415Sxw161283 ll->intr_type = DDI_INTR_TYPE_MSIX; 11927eced415Sxw161283 ll->intr_cnt = 1; 11937eced415Sxw161283 for (i = 0; i < XGE_HAL_MAX_FIFO_NUM; i++) 11947eced415Sxw161283 if (device_config->fifo.queue[i].configured) 11957eced415Sxw161283 ll->intr_cnt++; 11967eced415Sxw161283 for (i = 0; i < XGE_HAL_MAX_RING_NUM; i++) 11977eced415Sxw161283 if (device_config->ring.queue[i].configured) 11987eced415Sxw161283 ll->intr_cnt++; 11997eced415Sxw161283 } else { 12007eced415Sxw161283 ll->intr_type = DDI_INTR_TYPE_FIXED; 12017eced415Sxw161283 ll->intr_cnt = 1; 12027eced415Sxw161283 } 12037eced415Sxw161283 1204*da14cebeSEric Cheng /* 1205*da14cebeSEric Cheng * Allocate interrupt(s) 1206*da14cebeSEric Cheng */ 12077eced415Sxw161283 while ((ret = xge_alloc_intrs(ll)) != DDI_SUCCESS) { 12087eced415Sxw161283 if (ll->intr_type == DDI_INTR_TYPE_MSIX) { 1209*da14cebeSEric Cheng xgell_config->msix_enable = 0; 12107eced415Sxw161283 ll->intr_type = DDI_INTR_TYPE_FIXED; 12117eced415Sxw161283 ll->intr_cnt = 1; 12127eced415Sxw161283 device_config->intr_mode = XGE_HAL_INTR_MODE_IRQLINE; 12137eced415Sxw161283 xge_debug_osdep(XGE_TRACE, 12147eced415Sxw161283 "Unable to allocate MSI-X handlers" 12157eced415Sxw161283 " - defaulting to IRQA"); 12167eced415Sxw161283 continue; 12177eced415Sxw161283 } 1218a23fd118Syl150051 goto _exit3a; 1219a23fd118Syl150051 } 1220a23fd118Syl150051 12217eced415Sxw161283 if (ll->intr_type == DDI_INTR_TYPE_MSIX) { 12227eced415Sxw161283 device_config->intr_mode = XGE_HAL_INTR_MODE_MSIX; 12237eced415Sxw161283 device_config->bimodal_interrupts = 0; 12247eced415Sxw161283 } else { 12257eced415Sxw161283 device_config->intr_mode = XGE_HAL_INTR_MODE_IRQLINE; 12267eced415Sxw161283 } 12277eced415Sxw161283 12287eced415Sxw161283 attr.irqh = ll->intr_pri; 12297eced415Sxw161283 1230a23fd118Syl150051 /* initialize HW */ 12317eced415Sxw161283 status = xge_hal_device_initialize(hldev, &attr, device_config); 1232a23fd118Syl150051 if (status != XGE_HAL_OK) { 1233a23fd118Syl150051 switch (status) { 1234a23fd118Syl150051 case XGE_HAL_ERR_DRIVER_NOT_INITIALIZED: 1235a23fd118Syl150051 xge_debug_osdep(XGE_ERR, "%s", 1236a23fd118Syl150051 "driver is not initialized"); 1237a23fd118Syl150051 ret = DDI_FAILURE; 1238a23fd118Syl150051 goto _exit3b; 1239a23fd118Syl150051 case XGE_HAL_ERR_DEVICE_IS_NOT_QUIESCENT: 1240a23fd118Syl150051 xge_debug_osdep(XGE_ERR, "%s", 1241a23fd118Syl150051 "device is not quiescent"); 1242a23fd118Syl150051 ret = DDI_EBUSY; 1243a23fd118Syl150051 goto _exit3b; 1244a23fd118Syl150051 case XGE_HAL_ERR_OUT_OF_MEMORY: 1245a23fd118Syl150051 xge_debug_osdep(XGE_ERR, "%s", 1246a23fd118Syl150051 "unable to allocate memory"); 1247a23fd118Syl150051 ret = DDI_ENOMEM; 1248a23fd118Syl150051 goto _exit3b; 1249a23fd118Syl150051 default: 1250a23fd118Syl150051 xge_debug_osdep(XGE_ERR, 1251a23fd118Syl150051 "can't initialize the device: %d", status); 1252a23fd118Syl150051 ret = DDI_FAILURE; 1253a23fd118Syl150051 goto _exit3b; 1254a23fd118Syl150051 } 1255a23fd118Syl150051 } 1256a23fd118Syl150051 12577eced415Sxw161283 /* register interrupt handler for handling xge device interrupts */ 12587eced415Sxw161283 ret = xge_add_intrs(ll); 12597eced415Sxw161283 if (ret != DDI_SUCCESS) 12607eced415Sxw161283 goto _exit4; 12617eced415Sxw161283 1262a23fd118Syl150051 /* allocate and register Link Layer */ 1263*da14cebeSEric Cheng ret = xgell_device_register(ll, xgell_config); 1264a23fd118Syl150051 if (ret != DDI_SUCCESS) { 12657eced415Sxw161283 goto _exit5; 1266a23fd118Syl150051 } 1267a23fd118Syl150051 1268a23fd118Syl150051 /* store ll as a HAL private part */ 1269a23fd118Syl150051 xge_hal_device_private_set(hldev, ll); 1270a23fd118Syl150051 12717eced415Sxw161283 kmem_free(device_config, sizeof (xge_hal_device_config_t)); 1272*da14cebeSEric Cheng kmem_free(xgell_config, sizeof (xgell_config_t)); 12737eced415Sxw161283 1274a23fd118Syl150051 return (DDI_SUCCESS); 1275a23fd118Syl150051 12767eced415Sxw161283 _exit5: 12777eced415Sxw161283 xge_rem_intrs(ll); 1278a23fd118Syl150051 _exit4: 1279a23fd118Syl150051 xge_hal_device_terminate(hldev); 1280a23fd118Syl150051 _exit3b: 12817eced415Sxw161283 xge_free_intrs(ll); 1282a23fd118Syl150051 _exit3a: 1283a23fd118Syl150051 xgell_device_free(ll); 1284a23fd118Syl150051 _exit3: 1285a23fd118Syl150051 pci_config_teardown(&attr.cfgh); 1286a23fd118Syl150051 _exit2a: 1287a23fd118Syl150051 kmem_free(hldev, sizeof (xge_hal_device_t)); 1288a23fd118Syl150051 _exit2: 12897eced415Sxw161283 ddi_regs_map_free(&attr.regh2); 12907eced415Sxw161283 _exit1a: 1291a23fd118Syl150051 ddi_regs_map_free(&attr.regh1); 1292a23fd118Syl150051 _exit1: 1293a23fd118Syl150051 ddi_regs_map_free(&attr.regh0); 12947eced415Sxw161283 _exit0a: 12957eced415Sxw161283 kmem_free(device_config, sizeof (xge_hal_device_config_t)); 1296*da14cebeSEric Cheng kmem_free(xgell_config, sizeof (xgell_config_t)); 1297a23fd118Syl150051 _exit0: 1298a23fd118Syl150051 return (ret); 1299a23fd118Syl150051 } 1300a23fd118Syl150051 1301a23fd118Syl150051 /* 130219397407SSherry Moore * quiesce(9E) entry point. 130319397407SSherry Moore * 130419397407SSherry Moore * This function is called when the system is single-threaded at high 130519397407SSherry Moore * PIL with preemption disabled. Therefore, this function must not be 130619397407SSherry Moore * blocked. 130719397407SSherry Moore * 130819397407SSherry Moore * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure. 130919397407SSherry Moore * DDI_FAILURE indicates an error condition and should almost never happen. 131019397407SSherry Moore */ 131119397407SSherry Moore static int 131219397407SSherry Moore xge_quiesce(dev_info_t *dev_info) 131319397407SSherry Moore { 131419397407SSherry Moore xge_hal_device_t *hldev = 131519397407SSherry Moore (xge_hal_device_t *)ddi_get_driver_private(dev_info); 131619397407SSherry Moore 131719397407SSherry Moore xgelldev_t *lldev = xge_hal_device_private(hldev); 131819397407SSherry Moore 131919397407SSherry Moore xge_hal_device_quiesce(hldev, lldev->devh); 132019397407SSherry Moore 132119397407SSherry Moore return (DDI_SUCCESS); 132219397407SSherry Moore } 132319397407SSherry Moore 132419397407SSherry Moore /* 1325a23fd118Syl150051 * xge_detach 1326a23fd118Syl150051 * @dev_info: pointer to dev_info_t structure 1327a23fd118Syl150051 * @cmd: attach command to process 1328a23fd118Syl150051 * 1329a23fd118Syl150051 * This function is called by OS when the system is about 1330a23fd118Syl150051 * to shutdown or when the super user tries to unload 1331a23fd118Syl150051 * the driver. This function frees all the memory allocated 1332*da14cebeSEric Cheng * during xge_attach() and also unregisters the Xframe 1333a23fd118Syl150051 * device instance from the GLD framework. 1334a23fd118Syl150051 */ 1335a23fd118Syl150051 static int 1336a23fd118Syl150051 xge_detach(dev_info_t *dev_info, ddi_detach_cmd_t cmd) 1337a23fd118Syl150051 { 1338a23fd118Syl150051 xge_hal_device_t *hldev; 1339a23fd118Syl150051 xge_hal_device_attr_t *attr; 1340a23fd118Syl150051 xgelldev_t *lldev; 1341a23fd118Syl150051 1342a23fd118Syl150051 xge_debug_osdep(XGE_TRACE, "XGE_DETACH cmd %d", cmd); 1343a23fd118Syl150051 1344a23fd118Syl150051 hldev = (xge_hal_device_t *)ddi_get_driver_private(dev_info); 1345a23fd118Syl150051 attr = xge_hal_device_attr(hldev); 1346a23fd118Syl150051 lldev = xge_hal_device_private(hldev); 1347a23fd118Syl150051 1348a23fd118Syl150051 switch (cmd) { 1349a23fd118Syl150051 case DDI_DETACH: 1350a23fd118Syl150051 break; 1351a23fd118Syl150051 1352a23fd118Syl150051 case DDI_PM_SUSPEND: 1353a23fd118Syl150051 xge_debug_osdep(XGE_ERR, "%s", "suspend unsupported yet"); 1354a23fd118Syl150051 return (DDI_FAILURE); 1355a23fd118Syl150051 1356a23fd118Syl150051 default: 1357a23fd118Syl150051 xge_debug_osdep(XGE_ERR, "cmd 0x%x unrecognized", cmd); 1358a23fd118Syl150051 return (DDI_FAILURE); 1359a23fd118Syl150051 } 1360a23fd118Syl150051 1361a23fd118Syl150051 if (lldev->is_initialized) { 1362a23fd118Syl150051 xge_debug_osdep(XGE_ERR, "%s", 1363a23fd118Syl150051 "can not detach: device is not unplumbed"); 1364a23fd118Syl150051 return (DDI_FAILURE); 1365a23fd118Syl150051 } 1366a23fd118Syl150051 1367a23fd118Syl150051 xge_hal_device_terminating(hldev); 1368a23fd118Syl150051 if (xgell_device_unregister(lldev) != DDI_SUCCESS) { 1369a23fd118Syl150051 return (DDI_FAILURE); 1370a23fd118Syl150051 } 1371a23fd118Syl150051 xge_hal_device_terminate(hldev); 1372a23fd118Syl150051 13737eced415Sxw161283 xge_rem_intrs(lldev); 13747eced415Sxw161283 xge_free_intrs(lldev); 1375a23fd118Syl150051 xgell_device_free(lldev); 1376a23fd118Syl150051 pci_config_teardown(&attr->cfgh); 13777eced415Sxw161283 ddi_regs_map_free(&attr->regh2); 1378a23fd118Syl150051 ddi_regs_map_free(&attr->regh1); 1379a23fd118Syl150051 ddi_regs_map_free(&attr->regh0); 1380a23fd118Syl150051 kmem_free(hldev, sizeof (xge_hal_device_t)); 1381a23fd118Syl150051 1382a23fd118Syl150051 return (DDI_SUCCESS); 1383a23fd118Syl150051 } 1384