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 /*
236937Sxw161283 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
241256Syl150051 * Use is subject to license terms.
251256Syl150051 */
261256Syl150051
271256Syl150051 /*
281256Syl150051 * Copyright (c) 2002-2005 Neterion, Inc.
291256Syl150051 * All right Reserved.
301256Syl150051 *
311256Syl150051 * FileName : xge.c
321256Syl150051 *
331256Syl150051 * Description: Xge main Solaris specific initialization & routines
341256Syl150051 * for upper layer driver
351256Syl150051 *
361256Syl150051 */
371256Syl150051 #include "xgell.h"
381256Syl150051
391256Syl150051 static int xge_attach(dev_info_t *dev_info, ddi_attach_cmd_t cmd);
401256Syl150051 static int xge_detach(dev_info_t *dev_info, ddi_detach_cmd_t cmd);
417656SSherry.Moore@Sun.COM static int xge_quiesce(dev_info_t *dev_info);
421256Syl150051
431256Syl150051 DDI_DEFINE_STREAM_OPS(xge_ops, nulldev, nulldev, xge_attach, xge_detach,
447656SSherry.Moore@Sun.COM nodev, NULL, D_MP, NULL, xge_quiesce);
451256Syl150051
461256Syl150051 /* Standard Module linkage initialization for a Streams driver */
471256Syl150051 extern struct mod_ops mod_driverops;
481256Syl150051
491256Syl150051 static struct modldrv modldrv = {
501256Syl150051 &mod_driverops, /* Type of module. This one is a driver */
511256Syl150051 XGELL_DESC, /* short description */
521256Syl150051 &xge_ops /* driver specific ops */
531256Syl150051 };
541256Syl150051
551256Syl150051 static struct modlinkage modlinkage = {
561256Syl150051 MODREV_1, {(void *)&modldrv, NULL}
571256Syl150051 };
581256Syl150051
591256Syl150051 /* Xge device attributes */
601256Syl150051 ddi_device_acc_attr_t xge_dev_attr = {
611256Syl150051 DDI_DEVICE_ATTR_V0,
621256Syl150051 DDI_NEVERSWAP_ACC,
631256Syl150051 DDI_STRICTORDER_ACC
641256Syl150051 };
651256Syl150051 ddi_device_acc_attr_t *p_xge_dev_attr = &xge_dev_attr;
661256Syl150051
671256Syl150051 /*
681256Syl150051 * xgell_callback_crit_err
691256Syl150051 *
701256Syl150051 * This function called by HAL on Serious Error event. XGE_HAL_EVENT_SERR.
711256Syl150051 * Upper layer must analyze it based on %type.
721256Syl150051 */
731256Syl150051 static void
xge_callback_crit_err(void * userdata,xge_hal_event_e type,u64 serr_data)741256Syl150051 xge_callback_crit_err(void *userdata, xge_hal_event_e type, u64 serr_data)
751256Syl150051 {
761256Syl150051 (void) xgell_onerr_reset(userdata);
771256Syl150051 }
781256Syl150051
791256Syl150051 /*
806937Sxw161283 * xge_xpak_alarm_log
816937Sxw161283 * This function called by HAL on XPAK alarms. Upper layer must log the msg
826937Sxw161283 * based on the xpak alarm type
836937Sxw161283 */
846937Sxw161283 static void
xge_xpak_alarm_log(void * userdata,xge_hal_xpak_alarm_type_e type)856937Sxw161283 xge_xpak_alarm_log(void *userdata, xge_hal_xpak_alarm_type_e type)
866937Sxw161283 {
876937Sxw161283 switch (type) {
886937Sxw161283 case XGE_HAL_XPAK_ALARM_EXCESS_TEMP:
896937Sxw161283 xge_debug_osdep(XGE_ERR, "%s", "Take Xframe NIC out of "
906937Sxw161283 "service. Excessive temperatures may result in "
916937Sxw161283 "premature transceiver failure \n");
926937Sxw161283
936937Sxw161283 break;
946937Sxw161283 case XGE_HAL_XPAK_ALARM_EXCESS_BIAS_CURRENT:
956937Sxw161283 xge_debug_osdep(XGE_ERR, "%s", "Take Xframe NIC out of "
966937Sxw161283 "service Excessive bias currents may indicate "
976937Sxw161283 "imminent laser diode failure \n");
986937Sxw161283
996937Sxw161283 break;
1006937Sxw161283 case XGE_HAL_XPAK_ALARM_EXCESS_LASER_OUTPUT:
1016937Sxw161283 xge_debug_osdep(XGE_ERR, "%s", "Take Xframe NIC out of "
1026937Sxw161283 "service Excessive laser output power may saturate "
1036937Sxw161283 "far-end receiver\n");
1046937Sxw161283
1056937Sxw161283 break;
1066937Sxw161283 default:
1076937Sxw161283 xge_debug_osdep(XGE_ERR, "%s", "Undefined Xpak Alarm");
1086937Sxw161283 break;
1096937Sxw161283 }
1106937Sxw161283
1116937Sxw161283 }
1126937Sxw161283
1136937Sxw161283 /*
1141256Syl150051 * xge_driver_init_hal
1151256Syl150051 *
1161256Syl150051 * To initialize HAL portion of driver.
1171256Syl150051 */
1181256Syl150051 static xge_hal_status_e
xge_driver_init_hal(void)1191256Syl150051 xge_driver_init_hal(void)
1201256Syl150051 {
1211256Syl150051 static xge_hal_driver_config_t driver_config;
1221256Syl150051 xge_hal_uld_cbs_t uld_callbacks;
1231256Syl150051
1241256Syl150051 driver_config.queue_size_initial = 1;
1251256Syl150051 driver_config.queue_size_max = 4;
1261256Syl150051
1271256Syl150051 uld_callbacks.link_up = xgell_callback_link_up;
1281256Syl150051 uld_callbacks.link_down = xgell_callback_link_down;
1291256Syl150051 uld_callbacks.crit_err = xge_callback_crit_err;
130*8275SEric Cheng uld_callbacks.event = NULL;
131*8275SEric Cheng uld_callbacks.event_queued = NULL;
1321256Syl150051 uld_callbacks.before_device_poll = NULL;
1331256Syl150051 uld_callbacks.after_device_poll = NULL;
1341256Syl150051 uld_callbacks.sched_timer = NULL;
1356937Sxw161283 uld_callbacks.xpak_alarm_log = xge_xpak_alarm_log;
1361256Syl150051
1371256Syl150051 return (xge_hal_driver_initialize(&driver_config, &uld_callbacks));
1381256Syl150051
1391256Syl150051 }
1401256Syl150051
1411256Syl150051 /*
1421256Syl150051 * _init
1431256Syl150051 *
1441256Syl150051 * Solaris standard _init function for a device driver
1451256Syl150051 */
1461256Syl150051 int
_init(void)1471256Syl150051 _init(void)
1481256Syl150051 {
1491256Syl150051 int ret = 0;
1501256Syl150051 xge_hal_status_e status;
1511256Syl150051
1521256Syl150051 status = xge_driver_init_hal();
1531256Syl150051 if (status != XGE_HAL_OK) {
1541256Syl150051 xge_debug_osdep(XGE_ERR, "can't initialize the driver (%d)",
1551256Syl150051 status);
1561256Syl150051 return (EINVAL);
1571256Syl150051 }
1581256Syl150051
1591256Syl150051 xge_hal_driver_debug_module_mask_set(0xffffffff);
1601256Syl150051 xge_hal_driver_debug_level_set(XGE_TRACE);
1611256Syl150051
1621256Syl150051 mac_init_ops(&xge_ops, "xge");
1631256Syl150051 if ((ret = mod_install(&modlinkage)) != 0) {
1641256Syl150051 xge_hal_driver_terminate();
1651256Syl150051 mac_fini_ops(&xge_ops);
1661256Syl150051 xge_debug_osdep(XGE_ERR, "%s",
1671256Syl150051 "Unable to install the driver");
1681256Syl150051 return (ret);
1691256Syl150051 }
1701256Syl150051
1711256Syl150051 return (0);
1721256Syl150051 }
1731256Syl150051
1741256Syl150051 /*
1751256Syl150051 * _fini
1761256Syl150051 *
1771256Syl150051 * Solaris standard _fini function for device driver
1781256Syl150051 */
1791256Syl150051 int
_fini(void)1801256Syl150051 _fini(void)
1811256Syl150051 {
1821256Syl150051 int ret;
1831256Syl150051
1841256Syl150051 ret = mod_remove(&modlinkage);
1851256Syl150051 if (ret == 0) {
1861256Syl150051 xge_hal_driver_terminate();
1871256Syl150051 mac_fini_ops(&xge_ops);
1881256Syl150051 }
1891256Syl150051
1901256Syl150051 return (ret);
1911256Syl150051 }
1921256Syl150051
1931256Syl150051 /*
1941256Syl150051 * _info
1951256Syl150051 *
1961256Syl150051 * Solaris standard _info function for device driver
1971256Syl150051 */
1981256Syl150051 int
_info(struct modinfo * pModinfo)1991256Syl150051 _info(struct modinfo *pModinfo)
2001256Syl150051 {
2011256Syl150051 return (mod_info(&modlinkage, pModinfo));
2021256Syl150051 }
2031256Syl150051
2041256Syl150051 /*
2051256Syl150051 * xge_isr
2061256Syl150051 * @arg: pointer to device private strucutre(hldev)
2071256Syl150051 *
2081256Syl150051 * This is the ISR scheduled by the OS to indicate to the
2091256Syl150051 * driver that the receive/transmit operation is completed.
2101256Syl150051 */
211*8275SEric Cheng /* ARGSUSED */
2121256Syl150051 static uint_t
xge_isr(caddr_t arg0,caddr_t arg1)2136937Sxw161283 xge_isr(caddr_t arg0, caddr_t arg1)
2141256Syl150051 {
2151256Syl150051 xge_hal_status_e status;
2166937Sxw161283 xge_hal_device_t *hldev = (xge_hal_device_t *)arg0;
2171256Syl150051 xgelldev_t *lldev = xge_hal_device_private(hldev);
2181256Syl150051
2191256Syl150051 if (!lldev->is_initialized) {
2206937Sxw161283 return (DDI_INTR_UNCLAIMED);
2211256Syl150051 }
2221256Syl150051
2231256Syl150051 status = xge_hal_device_handle_irq(hldev);
2241256Syl150051
2251256Syl150051 return ((status == XGE_HAL_ERR_WRONG_IRQ) ?
2261256Syl150051 DDI_INTR_UNCLAIMED : DDI_INTR_CLAIMED);
2271256Syl150051 }
2281256Syl150051
2291256Syl150051 /*
2306937Sxw161283 * Interrupt handler for transmit when MSI-X interrupt mechasnism is used
2316937Sxw161283 */
2326937Sxw161283 /* ARGSUSED */
2336937Sxw161283 static uint_t
xge_fifo_msix_isr(caddr_t arg0,caddr_t arg1)2346937Sxw161283 xge_fifo_msix_isr(caddr_t arg0, caddr_t arg1)
2356937Sxw161283 {
2366937Sxw161283 int got_tx;
2376937Sxw161283 xge_hal_channel_t *channel = (xge_hal_channel_t *)arg0;
2386937Sxw161283 xgelldev_t *lldev = xge_hal_device_private(channel->devh);
2396937Sxw161283
2406937Sxw161283 if (!lldev->is_initialized) {
2416937Sxw161283 return (DDI_INTR_UNCLAIMED);
2426937Sxw161283 }
2436937Sxw161283 (void) xge_hal_device_poll_tx_channel(channel, &got_tx);
2446937Sxw161283
2456937Sxw161283 return (DDI_INTR_CLAIMED);
2466937Sxw161283 }
2476937Sxw161283
2486937Sxw161283 /*
2496937Sxw161283 * Interrupt handler for receive when MSI-X interrupt mechasnism is used
2506937Sxw161283 */
2516937Sxw161283 /* ARGSUSED */
2526937Sxw161283 static uint_t
xge_ring_msix_isr(caddr_t arg0,caddr_t arg1)2536937Sxw161283 xge_ring_msix_isr(caddr_t arg0, caddr_t arg1)
2546937Sxw161283 {
2556937Sxw161283 int got_rx;
2566937Sxw161283 xge_hal_channel_t *channel = (xge_hal_channel_t *)arg0;
2576937Sxw161283 xgelldev_t *lldev = xge_hal_device_private(channel->devh);
2586937Sxw161283
2596937Sxw161283 if (!lldev->is_initialized) {
2606937Sxw161283 return (DDI_INTR_UNCLAIMED);
2616937Sxw161283 }
2626937Sxw161283 (void) xge_hal_device_poll_rx_channel(channel, &got_rx);
2636937Sxw161283
2646937Sxw161283 return (DDI_INTR_CLAIMED);
2656937Sxw161283 }
2666937Sxw161283
2676937Sxw161283 /*
2686937Sxw161283 * Configure single ring
2696937Sxw161283 */
2706937Sxw161283 static void
xge_ring_config(dev_info_t * dev_info,xge_hal_device_config_t * device_config,int index)271*8275SEric Cheng xge_ring_config(dev_info_t *dev_info, xge_hal_device_config_t *device_config,
272*8275SEric Cheng int index)
2736937Sxw161283 {
2746937Sxw161283 char msg[MSG_SIZE];
2756937Sxw161283
276*8275SEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_configured", index);
277*8275SEric Cheng device_config->ring.queue[index].configured =
2786937Sxw161283 ddi_prop_get_int(DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS,
279*8275SEric Cheng msg, index < XGELL_RX_RING_NUM_MAX ? 1 : 0);
2806937Sxw161283
2816937Sxw161283 /* no point to configure it further if unconfigured */
282*8275SEric Cheng if (!device_config->ring.queue[index].configured)
2836937Sxw161283 return;
2846937Sxw161283
2856937Sxw161283 #if defined(__sparc)
286*8275SEric Cheng device_config->ring.queue[index].no_snoop_bits = 1;
2876937Sxw161283 #endif
2886937Sxw161283
289*8275SEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_max", index);
290*8275SEric Cheng device_config->ring.queue[index].max =
2916937Sxw161283 ddi_prop_get_int(DDI_DEV_T_ANY,
2926937Sxw161283 dev_info, DDI_PROP_DONTPASS, msg,
2936937Sxw161283 XGE_HAL_DEFAULT_USE_HARDCODE);
2946937Sxw161283
295*8275SEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_initial", index);
296*8275SEric Cheng device_config->ring.queue[index].initial =
2976937Sxw161283 ddi_prop_get_int(DDI_DEV_T_ANY,
2986937Sxw161283 dev_info, DDI_PROP_DONTPASS, msg,
2996937Sxw161283 XGE_HAL_DEFAULT_USE_HARDCODE);
3006937Sxw161283
301*8275SEric Cheng if (device_config->ring.queue[index].initial ==
3026937Sxw161283 XGE_HAL_DEFAULT_USE_HARDCODE) {
303*8275SEric Cheng device_config->ring.queue[index].initial =
304*8275SEric Cheng device_config->ring.queue[index].max =
305*8275SEric Cheng XGE_HAL_DEFAULT_RING_QUEUE_BLOCKS;
3066937Sxw161283 }
3076937Sxw161283
308*8275SEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_buffer_mode", index);
309*8275SEric Cheng device_config->ring.queue[index].buffer_mode =
3106937Sxw161283 ddi_prop_get_int(DDI_DEV_T_ANY,
3116937Sxw161283 dev_info, DDI_PROP_DONTPASS, msg,
3126937Sxw161283 XGE_HAL_RING_QUEUE_BUFFER_MODE_DEFAULT);
3136937Sxw161283
314*8275SEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_dram_size_mb", index);
315*8275SEric Cheng device_config->ring.queue[index].dram_size_mb =
3166937Sxw161283 ddi_prop_get_int(DDI_DEV_T_ANY,
3176937Sxw161283 dev_info, DDI_PROP_DONTPASS, msg,
3186937Sxw161283 XGE_HAL_DEFAULT_USE_HARDCODE);
3196937Sxw161283
3206937Sxw161283 (void) xge_os_snprintf(msg, MSG_SIZE,
321*8275SEric Cheng "ring%d_backoff_interval_us", index);
322*8275SEric Cheng device_config->ring.queue[index].backoff_interval_us =
3236937Sxw161283 ddi_prop_get_int(DDI_DEV_T_ANY,
3246937Sxw161283 dev_info, DDI_PROP_DONTPASS, msg,
3256937Sxw161283 XGE_HAL_DEFAULT_BACKOFF_INTERVAL_US);
3266937Sxw161283
327*8275SEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_max_frm_len", index);
328*8275SEric Cheng device_config->ring.queue[index].max_frm_len =
3296937Sxw161283 ddi_prop_get_int(DDI_DEV_T_ANY,
3306937Sxw161283 dev_info, DDI_PROP_DONTPASS, msg,
3316937Sxw161283 XGE_HAL_RING_USE_MTU);
3326937Sxw161283
3336937Sxw161283
334*8275SEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_priority", index);
335*8275SEric Cheng device_config->ring.queue[index].priority =
3366937Sxw161283 ddi_prop_get_int(DDI_DEV_T_ANY,
3376937Sxw161283 dev_info, DDI_PROP_DONTPASS, msg,
3386937Sxw161283 XGE_HAL_DEFAULT_RING_PRIORITY);
3396937Sxw161283
340*8275SEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_urange_a", index);
341*8275SEric Cheng device_config->ring.queue[index].rti.urange_a =
3426937Sxw161283 ddi_prop_get_int(DDI_DEV_T_ANY,
3436937Sxw161283 dev_info, DDI_PROP_DONTPASS, msg,
3446937Sxw161283 XGE_HAL_DEFAULT_RX_URANGE_A);
3456937Sxw161283
346*8275SEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_ufc_a", index);
347*8275SEric Cheng device_config->ring.queue[index].rti.ufc_a =
3486937Sxw161283 ddi_prop_get_int(DDI_DEV_T_ANY,
3496937Sxw161283 dev_info, DDI_PROP_DONTPASS, msg,
3506937Sxw161283 XGE_HAL_DEFAULT_RX_UFC_A);
3516937Sxw161283
352*8275SEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_urange_b", index);
353*8275SEric Cheng device_config->ring.queue[index].rti.urange_b =
3546937Sxw161283 ddi_prop_get_int(DDI_DEV_T_ANY,
3556937Sxw161283 dev_info, DDI_PROP_DONTPASS, msg,
3566937Sxw161283 XGE_HAL_DEFAULT_RX_URANGE_B);
3576937Sxw161283
358*8275SEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_ufc_b", index);
359*8275SEric Cheng device_config->ring.queue[index].rti.ufc_b =
3606937Sxw161283 ddi_prop_get_int(DDI_DEV_T_ANY,
3616937Sxw161283 dev_info, DDI_PROP_DONTPASS, msg,
3626937Sxw161283 device_config->mtu > XGE_HAL_DEFAULT_MTU ?
3636937Sxw161283 XGE_HAL_DEFAULT_RX_UFC_B_J:
3646937Sxw161283 XGE_HAL_DEFAULT_RX_UFC_B_N);
3656937Sxw161283
366*8275SEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_urange_c", index);
367*8275SEric Cheng device_config->ring.queue[index].rti.urange_c =
3686937Sxw161283 ddi_prop_get_int(DDI_DEV_T_ANY,
3696937Sxw161283 dev_info, DDI_PROP_DONTPASS, msg,
3706937Sxw161283 XGE_HAL_DEFAULT_RX_URANGE_C);
3716937Sxw161283
372*8275SEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_ufc_c", index);
373*8275SEric Cheng device_config->ring.queue[index].rti.ufc_c =
3746937Sxw161283 ddi_prop_get_int(DDI_DEV_T_ANY,
3756937Sxw161283 dev_info, DDI_PROP_DONTPASS, msg,
3766937Sxw161283 device_config->mtu > XGE_HAL_DEFAULT_MTU ?
3776937Sxw161283 XGE_HAL_DEFAULT_RX_UFC_C_J:
3786937Sxw161283 XGE_HAL_DEFAULT_RX_UFC_C_N);
3796937Sxw161283
380*8275SEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_ufc_d", index);
381*8275SEric Cheng device_config->ring.queue[index].rti.ufc_d =
3826937Sxw161283 ddi_prop_get_int(DDI_DEV_T_ANY,
3836937Sxw161283 dev_info, DDI_PROP_DONTPASS, msg,
3846937Sxw161283 XGE_HAL_DEFAULT_RX_UFC_D);
3856937Sxw161283
386*8275SEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_timer_val", index);
387*8275SEric Cheng device_config->ring.queue[index].rti.timer_val_us =
3886937Sxw161283 ddi_prop_get_int(DDI_DEV_T_ANY,
3896937Sxw161283 dev_info, DDI_PROP_DONTPASS, msg,
3906937Sxw161283 XGE_HAL_DEFAULT_RX_TIMER_VAL);
3916937Sxw161283
392*8275SEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_timer_ac_en", index);
393*8275SEric Cheng device_config->ring.queue[index].rti.timer_ac_en =
3946937Sxw161283 ddi_prop_get_int(DDI_DEV_T_ANY,
3956937Sxw161283 dev_info, DDI_PROP_DONTPASS, msg,
3966937Sxw161283 XGE_HAL_DEFAULT_RX_TIMER_AC_EN);
3976937Sxw161283
398*8275SEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "ring%d_indicate_max_pkts",
399*8275SEric Cheng index);
400*8275SEric Cheng device_config->ring.queue[index].indicate_max_pkts =
4016937Sxw161283 ddi_prop_get_int(DDI_DEV_T_ANY,
4026937Sxw161283 dev_info, DDI_PROP_DONTPASS, msg,
4036937Sxw161283 (device_config->bimodal_interrupts ?
4046937Sxw161283 XGE_HAL_DEFAULT_INDICATE_MAX_PKTS_B :
4056937Sxw161283 XGE_HAL_DEFAULT_INDICATE_MAX_PKTS_N));
4066937Sxw161283
407*8275SEric Cheng /*
408*8275SEric Cheng * Enable RTH steering if needed HERE!!!!
409*8275SEric Cheng */
410*8275SEric Cheng if (device_config->rth_en == XGE_HAL_RTH_ENABLE)
411*8275SEric Cheng device_config->ring.queue[index].rth_en = 1;
4126937Sxw161283 }
4136937Sxw161283
4146937Sxw161283 /*
4156937Sxw161283 * Configure single fifo
4166937Sxw161283 */
4176937Sxw161283 static void
xge_fifo_config(dev_info_t * dev_info,xge_hal_device_config_t * device_config,int index)418*8275SEric Cheng xge_fifo_config(dev_info_t *dev_info, xge_hal_device_config_t *device_config,
419*8275SEric Cheng int index)
4206937Sxw161283 {
4216937Sxw161283 char msg[MSG_SIZE];
4226937Sxw161283
423*8275SEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_configured", index);
424*8275SEric Cheng device_config->fifo.queue[index].configured =
4256937Sxw161283 ddi_prop_get_int(DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS,
426*8275SEric Cheng msg, index < XGELL_TX_RING_NUM_MAX ? 1 : 0);
4276937Sxw161283
4286937Sxw161283 /* no point to configure it further */
429*8275SEric Cheng if (!device_config->fifo.queue[index].configured)
4306937Sxw161283 return;
4316937Sxw161283
4326937Sxw161283 #if defined(__sparc)
433*8275SEric Cheng device_config->fifo.queue[index].no_snoop_bits = 1;
4346937Sxw161283 #endif
4356937Sxw161283
436*8275SEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_max", index);
437*8275SEric Cheng device_config->fifo.queue[index].max = ddi_prop_get_int(DDI_DEV_T_ANY,
4386937Sxw161283 dev_info, DDI_PROP_DONTPASS, msg,
4396937Sxw161283 XGE_HAL_DEFAULT_USE_HARDCODE);
4406937Sxw161283
441*8275SEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_initial", index);
442*8275SEric Cheng device_config->fifo.queue[index].initial =
443*8275SEric Cheng ddi_prop_get_int(DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
444*8275SEric Cheng XGE_HAL_DEFAULT_USE_HARDCODE);
445*8275SEric Cheng
446*8275SEric Cheng #if 0
447*8275SEric Cheng if (device_config->fifo.queue[index].initial ==
4486937Sxw161283 XGE_HAL_DEFAULT_USE_HARDCODE) {
4496937Sxw161283 if (device_config->mtu > XGE_HAL_DEFAULT_MTU) {
450*8275SEric Cheng device_config->fifo.queue[index].initial =
451*8275SEric Cheng device_config->fifo.queue[index].max =
4526937Sxw161283 XGE_HAL_DEFAULT_FIFO_QUEUE_LENGTH_J;
4536937Sxw161283 } else {
454*8275SEric Cheng device_config->fifo.queue[index].initial =
455*8275SEric Cheng device_config->fifo.queue[index].max =
4566937Sxw161283 XGE_HAL_DEFAULT_FIFO_QUEUE_LENGTH_N;
4576937Sxw161283 }
4586937Sxw161283 }
459*8275SEric Cheng #else
460*8275SEric Cheng if (device_config->fifo.queue[index].initial ==
461*8275SEric Cheng XGE_HAL_DEFAULT_USE_HARDCODE) {
462*8275SEric Cheng device_config->fifo.queue[index].max =
463*8275SEric Cheng device_config->fifo.queue[index].initial =
464*8275SEric Cheng XGE_HAL_DEFAULT_FIFO_QUEUE_LENGTH_A;
465*8275SEric Cheng }
466*8275SEric Cheng #endif
4676937Sxw161283
468*8275SEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_intr", index);
469*8275SEric Cheng device_config->fifo.queue[index].intr = ddi_prop_get_int(DDI_DEV_T_ANY,
4706937Sxw161283 dev_info, DDI_PROP_DONTPASS, msg,
4716937Sxw161283 XGE_HAL_DEFAULT_FIFO_QUEUE_INTR);
4726937Sxw161283
4736937Sxw161283 /*
4746937Sxw161283 * TTI 0 configuration
4756937Sxw161283 */
476*8275SEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_enable", index);
477*8275SEric Cheng device_config->fifo.queue[index].tti[index].enabled = ddi_prop_get_int(
4786937Sxw161283 DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg, 1);
4796937Sxw161283
480*8275SEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_urange_a", index);
481*8275SEric Cheng device_config->fifo.queue[index].tti[index].urange_a = ddi_prop_get_int(
4826937Sxw161283 DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
4836937Sxw161283 XGE_HAL_DEFAULT_TX_URANGE_A);
4846937Sxw161283
485*8275SEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_ufc_a", index);
486*8275SEric Cheng device_config->fifo.queue[index].tti[index].ufc_a = ddi_prop_get_int(
4876937Sxw161283 DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
4886937Sxw161283 XGE_HAL_DEFAULT_TX_UFC_A);
4896937Sxw161283
490*8275SEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_urange_b", index);
491*8275SEric Cheng device_config->fifo.queue[index].tti[index].urange_b = ddi_prop_get_int(
4926937Sxw161283 DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
4936937Sxw161283 XGE_HAL_DEFAULT_TX_URANGE_B);
4946937Sxw161283
495*8275SEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_ufc_b", index);
496*8275SEric Cheng device_config->fifo.queue[index].tti[index].ufc_b = ddi_prop_get_int(
4976937Sxw161283 DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
4986937Sxw161283 XGE_HAL_DEFAULT_TX_UFC_B);
4996937Sxw161283
500*8275SEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_urange_c", index);
501*8275SEric Cheng device_config->fifo.queue[index].tti[index].urange_c = ddi_prop_get_int(
5026937Sxw161283 DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
5036937Sxw161283 XGE_HAL_DEFAULT_TX_URANGE_C);
5046937Sxw161283
505*8275SEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_ufc_c", index);
506*8275SEric Cheng device_config->fifo.queue[index].tti[index].ufc_c = ddi_prop_get_int(
5076937Sxw161283 DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
5086937Sxw161283 XGE_HAL_DEFAULT_TX_UFC_C);
5096937Sxw161283
510*8275SEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_ufc_d", index);
511*8275SEric Cheng device_config->fifo.queue[index].tti[index].ufc_d = ddi_prop_get_int(
5126937Sxw161283 DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
5136937Sxw161283 XGE_HAL_DEFAULT_TX_UFC_D);
5146937Sxw161283
515*8275SEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_timer_ac_en", index);
516*8275SEric Cheng device_config->fifo.queue[index].tti[index].timer_ac_en =
517*8275SEric Cheng ddi_prop_get_int(DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
5186937Sxw161283 XGE_HAL_DEFAULT_TX_TIMER_AC_EN);
5196937Sxw161283
520*8275SEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_timer_val", index);
521*8275SEric Cheng device_config->fifo.queue[index].tti[index].timer_val_us =
522*8275SEric Cheng ddi_prop_get_int(DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
5236937Sxw161283 XGE_HAL_DEFAULT_TX_TIMER_VAL);
5246937Sxw161283
525*8275SEric Cheng (void) xge_os_snprintf(msg, MSG_SIZE, "fifo%d_tti_timer_ci_en", index);
526*8275SEric Cheng device_config->fifo.queue[index].tti[index].timer_ci_en =
527*8275SEric Cheng ddi_prop_get_int(DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, msg,
5286937Sxw161283 XGE_HAL_DEFAULT_TX_TIMER_CI_EN);
5296937Sxw161283 }
5306937Sxw161283
5316937Sxw161283 /*
5321256Syl150051 * xge_configuration_init
5331256Syl150051 * @device_config: pointer to xge_hal_device_config_t
5341256Syl150051 *
5351256Syl150051 * This function will lookup properties from .conf file to init
5361256Syl150051 * the configuration data structure. If a property is not in .conf
5371256Syl150051 * file, the default value should be set.
5381256Syl150051 */
5391256Syl150051 static void
xge_configuration_init(dev_info_t * dev_info,xge_hal_device_config_t * device_config,xgell_config_t * xgell_config)5401256Syl150051 xge_configuration_init(dev_info_t *dev_info,
541*8275SEric Cheng xge_hal_device_config_t *device_config, xgell_config_t *xgell_config)
5421256Syl150051 {
5436937Sxw161283 int i, rings_configured = 0, fifos_configured = 0;
5446937Sxw161283
5451256Syl150051 /*
546*8275SEric Cheng * Initialize link layer configuration first
547*8275SEric Cheng */
548*8275SEric Cheng xgell_config->rx_dma_lowat = ddi_prop_get_int(DDI_DEV_T_ANY, dev_info,
549*8275SEric Cheng DDI_PROP_DONTPASS, "rx_dma_lowat", XGELL_RX_DMA_LOWAT);
550*8275SEric Cheng xgell_config->rx_pkt_burst = ddi_prop_get_int(DDI_DEV_T_ANY,
551*8275SEric Cheng dev_info, DDI_PROP_DONTPASS, "rx_pkt_burst", XGELL_RX_PKT_BURST);
552*8275SEric Cheng xgell_config->tx_dma_lowat = ddi_prop_get_int(DDI_DEV_T_ANY, dev_info,
553*8275SEric Cheng DDI_PROP_DONTPASS, "tx_dma_lowat", XGELL_TX_DMA_LOWAT);
554*8275SEric Cheng xgell_config->lso_enable = ddi_prop_get_int(DDI_DEV_T_ANY, dev_info,
555*8275SEric Cheng DDI_PROP_DONTPASS, "lso_enable", XGELL_CONF_ENABLE_BY_DEFAULT);
556*8275SEric Cheng xgell_config->msix_enable = ddi_prop_get_int(DDI_DEV_T_ANY, dev_info,
557*8275SEric Cheng DDI_PROP_DONTPASS, "msix_enable", XGELL_CONF_ENABLE_BY_DEFAULT);
558*8275SEric Cheng
559*8275SEric Cheng xgell_config->grouping = ddi_prop_get_int(DDI_DEV_T_ANY, dev_info,
560*8275SEric Cheng DDI_PROP_DONTPASS, "grouping", XGELL_CONF_GROUP_POLICY_DEFAULT);
561*8275SEric Cheng
562*8275SEric Cheng switch (xgell_config->grouping) {
563*8275SEric Cheng case XGELL_CONF_GROUP_POLICY_VIRT:
564*8275SEric Cheng /*
565*8275SEric Cheng * Enable layer 2 steering for better virtualization
566*8275SEric Cheng */
567*8275SEric Cheng device_config->rth_en = XGE_HAL_RTH_DISABLE;
568*8275SEric Cheng device_config->rts_mac_en = XGE_HAL_RTS_MAC_ENABLE;
569*8275SEric Cheng break;
570*8275SEric Cheng case XGELL_CONF_GROUP_POLICY_PERF:
571*8275SEric Cheng /*
572*8275SEric Cheng * Configure layer 4 RTH to hashing inbound traffic
573*8275SEric Cheng */
574*8275SEric Cheng device_config->rth_en = XGE_HAL_RTH_ENABLE;
575*8275SEric Cheng device_config->rth_bucket_size = XGE_HAL_MAX_RTH_BUCKET_SIZE;
576*8275SEric Cheng device_config->rth_spdm_en = XGE_HAL_RTH_SPDM_DISABLE;
577*8275SEric Cheng device_config->rth_spdm_use_l4 = XGE_HAL_RTH_SPDM_USE_L4;
578*8275SEric Cheng
579*8275SEric Cheng device_config->rts_mac_en = XGE_HAL_RTS_MAC_DISABLE;
580*8275SEric Cheng break;
581*8275SEric Cheng case XGELL_CONF_GROUP_POLICY_BASIC:
582*8275SEric Cheng default:
583*8275SEric Cheng /*
584*8275SEric Cheng * Disable both RTS and RTH for single ring configuration
585*8275SEric Cheng */
586*8275SEric Cheng device_config->rth_en = XGE_HAL_RTH_DISABLE;
587*8275SEric Cheng device_config->rts_mac_en = XGE_HAL_RTS_MAC_DISABLE;
588*8275SEric Cheng break;
589*8275SEric Cheng }
590*8275SEric Cheng
591*8275SEric Cheng /*
5921256Syl150051 * Initialize common properties
5931256Syl150051 */
5941256Syl150051 device_config->mtu = ddi_prop_get_int(DDI_DEV_T_ANY,
5951256Syl150051 dev_info, DDI_PROP_DONTPASS, "default_mtu",
5961256Syl150051 XGE_HAL_DEFAULT_INITIAL_MTU);
5971256Syl150051 device_config->isr_polling_cnt = ddi_prop_get_int(DDI_DEV_T_ANY,
5981256Syl150051 dev_info, DDI_PROP_DONTPASS, "isr_polling_cnt",
5991256Syl150051 XGE_HAL_DEFAULT_ISR_POLLING_CNT);
6001256Syl150051 device_config->latency_timer = ddi_prop_get_int(DDI_DEV_T_ANY,
6011256Syl150051 dev_info, DDI_PROP_DONTPASS, "latency_timer",
6021256Syl150051 XGE_HAL_DEFAULT_LATENCY_TIMER);
6031256Syl150051 device_config->max_splits_trans = ddi_prop_get_int(DDI_DEV_T_ANY,
6041256Syl150051 dev_info, DDI_PROP_DONTPASS, "max_splits_trans",
6051256Syl150051 XGE_HAL_DEFAULT_SPLIT_TRANSACTION);
6061256Syl150051 device_config->mmrb_count = ddi_prop_get_int(DDI_DEV_T_ANY,
6071256Syl150051 dev_info, DDI_PROP_DONTPASS, "mmrb_count",
6081256Syl150051 XGE_HAL_DEFAULT_MMRB_COUNT);
6091256Syl150051 device_config->shared_splits = ddi_prop_get_int(DDI_DEV_T_ANY,
6101256Syl150051 dev_info, DDI_PROP_DONTPASS, "shared_splits",
6111256Syl150051 XGE_HAL_DEFAULT_SHARED_SPLITS);
6121256Syl150051 device_config->stats_refresh_time_sec = ddi_prop_get_int(DDI_DEV_T_ANY,
6131256Syl150051 dev_info, DDI_PROP_DONTPASS, "stats_refresh_time",
6141256Syl150051 XGE_HAL_DEFAULT_STATS_REFRESH_TIME);
6151256Syl150051 device_config->device_poll_millis = ddi_prop_get_int(DDI_DEV_T_ANY,
6161256Syl150051 dev_info, DDI_PROP_DONTPASS, "device_poll_millis",
6171256Syl150051 XGE_HAL_DEFAULT_DEVICE_POLL_MILLIS);
6181256Syl150051 device_config->pci_freq_mherz = ddi_prop_get_int(DDI_DEV_T_ANY,
6193115Syl150051 dev_info, DDI_PROP_DONTPASS, "pci_freq_mherz",
6203115Syl150051 XGE_HAL_DEFAULT_USE_HARDCODE);
6211256Syl150051
6221256Syl150051 /*
6231256Syl150051 * Initialize ring properties
6241256Syl150051 */
6251256Syl150051 device_config->ring.memblock_size = ddi_prop_get_int(DDI_DEV_T_ANY,
6261256Syl150051 dev_info, DDI_PROP_DONTPASS, "ring_memblock_size",
6271256Syl150051 XGE_HAL_DEFAULT_RING_MEMBLOCK_SIZE);
6281256Syl150051 device_config->ring.strip_vlan_tag = XGE_HAL_RING_DONOT_STRIP_VLAN_TAG;
6291256Syl150051
6306937Sxw161283 /*
6316937Sxw161283 * Bimodal Interrupts - TTI 56 configuration
6326937Sxw161283 */
6336937Sxw161283 device_config->bimodal_interrupts = ddi_prop_get_int(
6346937Sxw161283 DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, "bimodal_interrupts",
6356937Sxw161283 XGE_HAL_DEFAULT_BIMODAL_INTERRUPTS);
6366937Sxw161283 device_config->bimodal_timer_lo_us = ddi_prop_get_int(
6376937Sxw161283 DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, "bimodal_timer_lo_us",
6386937Sxw161283 XGE_HAL_DEFAULT_BIMODAL_TIMER_LO_US);
6396937Sxw161283 device_config->bimodal_timer_hi_us = ddi_prop_get_int(
6406937Sxw161283 DDI_DEV_T_ANY, dev_info, DDI_PROP_DONTPASS, "bimodal_timer_hi_us",
6416937Sxw161283 XGE_HAL_DEFAULT_BIMODAL_TIMER_HI_US);
6426937Sxw161283
6436937Sxw161283 /*
6446937Sxw161283 * Go through all possibly configured rings. Each ring could be
6456937Sxw161283 * configured individually. To enable/disable specific ring, just
6466937Sxw161283 * set ring->configured = [1|0].
6476937Sxw161283 *
6486937Sxw161283 * By default *all* rings enabled.
6496937Sxw161283 */
6506937Sxw161283 for (i = 0; i < XGE_HAL_MAX_RING_NUM; i++) {
6516937Sxw161283 xge_ring_config(dev_info, device_config, i);
6526937Sxw161283 if (device_config->ring.queue[i].configured)
6536937Sxw161283 rings_configured++;
6541256Syl150051 }
6551256Syl150051
6561256Syl150051 /*
6571256Syl150051 * Initialize mac properties
6581256Syl150051 */
6591256Syl150051 device_config->mac.tmac_util_period = ddi_prop_get_int(DDI_DEV_T_ANY,
6601256Syl150051 dev_info, DDI_PROP_DONTPASS, "mac_tmac_util_period",
6611256Syl150051 XGE_HAL_DEFAULT_TMAC_UTIL_PERIOD);
6621256Syl150051 device_config->mac.rmac_util_period = ddi_prop_get_int(DDI_DEV_T_ANY,
6631256Syl150051 dev_info, DDI_PROP_DONTPASS, "mac_rmac_util_period",
6641256Syl150051 XGE_HAL_DEFAULT_RMAC_UTIL_PERIOD);
6651256Syl150051 device_config->mac.rmac_bcast_en = ddi_prop_get_int(DDI_DEV_T_ANY,
6661256Syl150051 dev_info, DDI_PROP_DONTPASS, "mac_rmac_bcast_en",
6671256Syl150051 1); /* HAL never provide a good named macro */
6683115Syl150051 device_config->mac.rmac_pause_gen_en = ddi_prop_get_int(DDI_DEV_T_ANY,
6693115Syl150051 dev_info, DDI_PROP_DONTPASS, "rmac_pause_gen_en",
6703115Syl150051 XGE_HAL_DEFAULT_RMAC_PAUSE_GEN_DIS);
6713115Syl150051 device_config->mac.rmac_pause_rcv_en = ddi_prop_get_int(DDI_DEV_T_ANY,
6723115Syl150051 dev_info, DDI_PROP_DONTPASS, "rmac_pause_rcv_en",
6733115Syl150051 XGE_HAL_DEFAULT_RMAC_PAUSE_RCV_DIS);
6741256Syl150051 device_config->mac.rmac_pause_time = ddi_prop_get_int(DDI_DEV_T_ANY,
6751256Syl150051 dev_info, DDI_PROP_DONTPASS, "mac_rmac_pause_time",
6761256Syl150051 XGE_HAL_DEFAULT_RMAC_HIGH_PTIME);
6771256Syl150051 device_config->mac.mc_pause_threshold_q0q3 =
6781256Syl150051 ddi_prop_get_int(DDI_DEV_T_ANY,
6796937Sxw161283 dev_info, DDI_PROP_DONTPASS, "mac_mc_pause_threshold_q0q3",
6806937Sxw161283 XGE_HAL_DEFAULT_MC_PAUSE_THRESHOLD_Q0Q3);
6811256Syl150051 device_config->mac.mc_pause_threshold_q4q7 =
6821256Syl150051 ddi_prop_get_int(DDI_DEV_T_ANY,
6836937Sxw161283 dev_info, DDI_PROP_DONTPASS, "mac_mc_pause_threshold_q4q7",
6846937Sxw161283 XGE_HAL_DEFAULT_MC_PAUSE_THRESHOLD_Q4Q7);
6851256Syl150051
6861256Syl150051 /*
6871256Syl150051 * Initialize fifo properties
6881256Syl150051 */
6891256Syl150051 device_config->fifo.max_frags = ddi_prop_get_int(DDI_DEV_T_ANY,
6901256Syl150051 dev_info, DDI_PROP_DONTPASS, "fifo_max_frags",
6911256Syl150051 XGE_HAL_DEFAULT_FIFO_FRAGS);
6921256Syl150051 device_config->fifo.reserve_threshold = ddi_prop_get_int(DDI_DEV_T_ANY,
6931256Syl150051 dev_info, DDI_PROP_DONTPASS, "fifo_reserve_threshold",
6941256Syl150051 XGE_HAL_DEFAULT_FIFO_RESERVE_THRESHOLD);
6951256Syl150051 device_config->fifo.memblock_size = ddi_prop_get_int(DDI_DEV_T_ANY,
6961256Syl150051 dev_info, DDI_PROP_DONTPASS, "fifo_memblock_size",
6971256Syl150051 XGE_HAL_DEFAULT_FIFO_MEMBLOCK_SIZE);
6981256Syl150051 #ifdef XGE_HAL_ALIGN_XMIT
6993115Syl150051 device_config->fifo.alignment_size = ddi_prop_get_int(DDI_DEV_T_ANY,
7003115Syl150051 dev_info, DDI_PROP_DONTPASS, "fifo_copied_frag_size",
7013115Syl150051 XGE_HAL_DEFAULT_FIFO_ALIGNMENT_SIZE);
7023115Syl150051 device_config->fifo.max_aligned_frags = ddi_prop_get_int(DDI_DEV_T_ANY,
7033115Syl150051 dev_info, DDI_PROP_DONTPASS, "fifo_copied_max_frags",
7043115Syl150051 XGE_HAL_DEFAULT_FIFO_MAX_ALIGNED_FRAGS);
7051256Syl150051 #endif
7061256Syl150051
7071256Syl150051 /*
7086937Sxw161283 * Go through all possibly configured fifos. Each fifo could be
7096937Sxw161283 * configured individually. To enable/disable specific fifo, just
7106937Sxw161283 * set fifo->configured = [0|1].
7116937Sxw161283 *
7126937Sxw161283 * By default *all* fifos enabled.
7133115Syl150051 */
7146937Sxw161283 for (i = 0; i < XGE_HAL_MAX_FIFO_NUM; i++) {
7156937Sxw161283 xge_fifo_config(dev_info, device_config, i);
7166937Sxw161283 if (device_config->fifo.queue[i].configured)
7176937Sxw161283 fifos_configured++;
7186937Sxw161283 }
7191256Syl150051
7201256Syl150051 /*
7211256Syl150051 * Initialize errors dumping
7221256Syl150051 */
7231256Syl150051 device_config->dump_on_serr = ddi_prop_get_int(DDI_DEV_T_ANY,
7241256Syl150051 dev_info, DDI_PROP_DONTPASS, "dump_on_serr",
7251256Syl150051 0);
7261256Syl150051 device_config->dump_on_serr = ddi_prop_get_int(DDI_DEV_T_ANY,
7271256Syl150051 dev_info, DDI_PROP_DONTPASS, "dump_on_eccerr",
7281256Syl150051 0);
7291256Syl150051 device_config->dump_on_serr = ddi_prop_get_int(DDI_DEV_T_ANY,
7301256Syl150051 dev_info, DDI_PROP_DONTPASS, "dump_on_parityerr",
7311256Syl150051 0);
7321256Syl150051
7331256Syl150051 /*
7343115Syl150051 * LRO tunables
7353115Syl150051 */
7363115Syl150051 device_config->lro_sg_size = ddi_prop_get_int(DDI_DEV_T_ANY,
7373115Syl150051 dev_info, DDI_PROP_DONTPASS, "lro_sg_size",
7383115Syl150051 XGE_HAL_DEFAULT_LRO_SG_SIZE);
7393115Syl150051 device_config->lro_frm_len = ddi_prop_get_int(DDI_DEV_T_ANY,
7403115Syl150051 dev_info, DDI_PROP_DONTPASS, "lro_frm_len",
7413115Syl150051 XGE_HAL_DEFAULT_LRO_FRM_LEN);
7423115Syl150051
7433115Syl150051 /*
744*8275SEric Cheng * Initialize other link layer configuration first
7451256Syl150051 */
746*8275SEric Cheng xgell_config->rx_buffer_total = ddi_prop_get_int(DDI_DEV_T_ANY,
7471256Syl150051 dev_info, DDI_PROP_DONTPASS, "rx_buffer_total",
748*8275SEric Cheng device_config->ring.queue[XGELL_RX_RING_MAIN].initial *
7496937Sxw161283 XGELL_RX_BUFFER_TOTAL);
750*8275SEric Cheng xgell_config->rx_buffer_total += XGELL_RX_BUFFER_RECYCLE_CACHE;
751*8275SEric Cheng xgell_config->rx_buffer_post_hiwat = ddi_prop_get_int(DDI_DEV_T_ANY,
7521256Syl150051 dev_info, DDI_PROP_DONTPASS, "rx_buffer_post_hiwat",
753*8275SEric Cheng device_config->ring.queue[XGELL_RX_RING_MAIN].initial *
7546937Sxw161283 XGELL_RX_BUFFER_POST_HIWAT);
755*8275SEric Cheng xgell_config->rx_buffer_post_hiwat += XGELL_RX_BUFFER_RECYCLE_CACHE;
7561256Syl150051 }
7571256Syl150051
7586937Sxw161283 /*
7596937Sxw161283 * xge_alloc_intrs:
7606937Sxw161283 *
7616937Sxw161283 * Allocate FIXED or MSIX interrupts.
7626937Sxw161283 */
7636937Sxw161283 static int
xge_alloc_intrs(xgelldev_t * lldev)7646937Sxw161283 xge_alloc_intrs(xgelldev_t *lldev)
7656937Sxw161283 {
7666937Sxw161283 dev_info_t *dip = lldev->dev_info;
7676937Sxw161283 int avail, actual, count = 0;
7686937Sxw161283 int i, intr_behavior, ret;
7696937Sxw161283
7706937Sxw161283 if (lldev->intr_type == DDI_INTR_TYPE_MSIX) {
7716937Sxw161283 intr_behavior = DDI_INTR_ALLOC_STRICT;
7726937Sxw161283 (void) ddi_prop_create(DDI_DEV_T_NONE, dip,
7736937Sxw161283 DDI_PROP_CANSLEEP, "#msix-request", NULL, 0);
7746937Sxw161283 } else {
7756937Sxw161283 intr_behavior = DDI_INTR_ALLOC_NORMAL;
7766937Sxw161283 }
7776937Sxw161283
7786937Sxw161283 /* Get number of interrupts */
7796937Sxw161283 ret = ddi_intr_get_nintrs(dip, lldev->intr_type, &count);
7806937Sxw161283 if ((ret != DDI_SUCCESS) || (count == 0)) {
7816937Sxw161283 xge_debug_osdep(XGE_ERR, "ddi_intr_get_nintrs() failed, "
7826937Sxw161283 "ret: %d, count: %d", ret, count);
7836937Sxw161283
7846937Sxw161283 goto _err_exit0;
7856937Sxw161283 }
7866937Sxw161283
7876937Sxw161283 /* Get number of available interrupts */
7886937Sxw161283 ret = ddi_intr_get_navail(dip, lldev->intr_type, &avail);
7896937Sxw161283 if ((ret != DDI_SUCCESS) || (avail == 0)) {
7906937Sxw161283 xge_debug_osdep(XGE_ERR, "ddi_intr_get_navail() failure, "
7916937Sxw161283 "ret: %d, avail: %d", ret, avail);
7926937Sxw161283
7936937Sxw161283 goto _err_exit0;
7946937Sxw161283 }
7956937Sxw161283
7966937Sxw161283 if (avail < lldev->intr_cnt) {
7976937Sxw161283 xge_debug_osdep(XGE_ERR, "%d interrupts wanted while only "
7986937Sxw161283 "%d available", lldev->intr_cnt, avail);
7996937Sxw161283 goto _err_exit0;
8006937Sxw161283 }
8016937Sxw161283
8026937Sxw161283 /* Allocate an array of interrupt handles */
8036937Sxw161283 lldev->intr_table_size = lldev->intr_cnt * sizeof (ddi_intr_handle_t);
8046937Sxw161283 lldev->intr_table = kmem_alloc(lldev->intr_table_size, KM_SLEEP);
8056937Sxw161283
8066937Sxw161283 /* Call ddi_intr_alloc() */
8076937Sxw161283 ret = ddi_intr_alloc(dip, lldev->intr_table, lldev->intr_type, 0,
8086937Sxw161283 lldev->intr_cnt, &actual, intr_behavior);
8096937Sxw161283 if ((ret != DDI_SUCCESS) || (actual == 0)) {
8106937Sxw161283 xge_debug_osdep(XGE_ERR, "ddi_intr_alloc() failed %d", ret);
8116937Sxw161283 goto _err_exit1;
8126937Sxw161283 }
8136937Sxw161283
8146937Sxw161283 xge_debug_osdep(XGE_TRACE, "%s: Requested: %d, Granted: %d",
8156937Sxw161283 lldev->intr_type == DDI_INTR_TYPE_MSIX ? "MSI-X" :
8166937Sxw161283 "IRQA", count, actual);
8176937Sxw161283
8186937Sxw161283 if (lldev->intr_cnt != actual) {
8196937Sxw161283 xge_debug_osdep(XGE_ERR, "Not enough resources granted");
8206937Sxw161283 goto _err_exit2;
8216937Sxw161283 }
8226937Sxw161283
8236937Sxw161283 /*
8246937Sxw161283 * Get priority for first msi, assume remaining are all the same
8256937Sxw161283 */
8266937Sxw161283 if ((ret = ddi_intr_get_pri(lldev->intr_table[0], &lldev->intr_pri)) !=
8276937Sxw161283 DDI_SUCCESS) {
8286937Sxw161283 xge_debug_osdep(XGE_ERR, "ddi_intr_get_pri() failed %d", ret);
8296937Sxw161283 goto _err_exit2;
8306937Sxw161283 }
8316937Sxw161283
8326937Sxw161283 return (DDI_SUCCESS);
8336937Sxw161283
8346937Sxw161283 _err_exit2:
8356937Sxw161283 /* Free already allocated intr */
8366937Sxw161283 for (i = 0; i < actual; i++) {
8376937Sxw161283 (void) ddi_intr_free(lldev->intr_table[i]);
8386937Sxw161283 }
8396937Sxw161283 _err_exit1:
8406937Sxw161283 kmem_free(lldev->intr_table, lldev->intr_table_size);
841*8275SEric Cheng lldev->intr_table = NULL;
8426937Sxw161283 _err_exit0:
8436937Sxw161283 if (lldev->intr_type == DDI_INTR_TYPE_MSIX)
8446937Sxw161283 (void) ddi_prop_remove(DDI_DEV_T_NONE, dip, "#msix-request");
8456937Sxw161283 return (DDI_FAILURE);
8466937Sxw161283 }
8476937Sxw161283
8486937Sxw161283 /*
8496937Sxw161283 * xge_free_intrs:
8506937Sxw161283 *
8516937Sxw161283 * Free previously allocated interrupts.
8526937Sxw161283 */
8536937Sxw161283 static void
xge_free_intrs(xgelldev_t * lldev)8546937Sxw161283 xge_free_intrs(xgelldev_t *lldev)
8556937Sxw161283 {
8566937Sxw161283 int i;
8576937Sxw161283 dev_info_t *dip = lldev->dev_info;
8586937Sxw161283
8596937Sxw161283 /* Free already allocated intr */
8606937Sxw161283 for (i = 0; i < lldev->intr_cnt; i++) {
8616937Sxw161283 (void) ddi_intr_free(lldev->intr_table[i]);
8626937Sxw161283 }
8636937Sxw161283 kmem_free(lldev->intr_table, lldev->intr_table_size);
864*8275SEric Cheng lldev->intr_table = NULL;
8656937Sxw161283
8666937Sxw161283 if (lldev->intr_type == DDI_INTR_TYPE_MSIX)
8676937Sxw161283 (void) ddi_prop_remove(DDI_DEV_T_NONE, dip, "#msix-request");
8686937Sxw161283 }
8696937Sxw161283
8706937Sxw161283 /*
8716937Sxw161283 * xge_add_intrs:
8726937Sxw161283 *
8736937Sxw161283 * Register FIXED or MSI interrupts.
8746937Sxw161283 */
8756937Sxw161283 int
xge_add_intrs(xgelldev_t * lldev)8766937Sxw161283 xge_add_intrs(xgelldev_t *lldev)
8776937Sxw161283 {
8786937Sxw161283 int i, ret;
8796937Sxw161283 xge_hal_device_t *hldev = lldev->devh;
8806937Sxw161283 xge_hal_device_config_t *hal_conf = &hldev->config;
8816937Sxw161283 xge_hal_ring_config_t *ring_conf = &hal_conf->ring;
8826937Sxw161283 xge_hal_fifo_config_t *fifo_conf = &hal_conf->fifo;
8836937Sxw161283 xge_list_t *item;
8846937Sxw161283 int msix_idx = 1; /* 0 by default is reserved for Alarms. */
885*8275SEric Cheng xge_hal_channel_t *assigned[XGELL_RX_RING_NUM_MAX +
886*8275SEric Cheng XGELL_TX_RING_NUM_MAX + 1];
8876937Sxw161283
888*8275SEric Cheng xge_assert(lldev->intr_table != NULL);
8896937Sxw161283 switch (lldev->intr_type) {
8906937Sxw161283 case DDI_INTR_TYPE_FIXED:
8916937Sxw161283 ret = ddi_intr_add_handler(lldev->intr_table[0],
8926937Sxw161283 (ddi_intr_handler_t *)xge_isr,
8936937Sxw161283 (caddr_t)hldev, 0);
8946937Sxw161283 if (ret != DDI_SUCCESS) {
8956937Sxw161283 xge_debug_osdep(XGE_ERR, "ddi_intr_add_handler(FIXED)"
8966937Sxw161283 "failed %d", ret);
8976937Sxw161283 return (DDI_FAILURE);
8986937Sxw161283 }
8996937Sxw161283 break;
9006937Sxw161283
9016937Sxw161283 case DDI_INTR_TYPE_MSIX:
9026937Sxw161283 i = 0;
9036937Sxw161283 xge_list_for_each(item, &hldev->free_channels) {
9046937Sxw161283 xge_hal_channel_t *channel = xge_container_of(item,
9056937Sxw161283 xge_hal_channel_t, item);
9066937Sxw161283 i = channel->post_qid;
9076937Sxw161283 if (channel->type == XGE_HAL_CHANNEL_TYPE_FIFO) {
9086937Sxw161283 if (fifo_conf->queue[i].configured) {
9096937Sxw161283 assigned[msix_idx] = channel;
9106937Sxw161283 msix_idx++;
9116937Sxw161283 }
9126937Sxw161283 } else {
9136937Sxw161283 if (ring_conf->queue[i].configured) {
9146937Sxw161283 assigned[msix_idx] = channel;
9156937Sxw161283 msix_idx++;
9166937Sxw161283 }
9176937Sxw161283 }
9186937Sxw161283 }
9196937Sxw161283 for (i = 0; i < lldev->intr_cnt; i++) {
9206937Sxw161283 uint_t (*intr)(caddr_t, caddr_t);
9216937Sxw161283 caddr_t intr_arg;
9226937Sxw161283
9236937Sxw161283 /* partition MSIX vectors */
9246937Sxw161283 if (i == 0) {
9256937Sxw161283 intr = xge_isr;
9266937Sxw161283 intr_arg = (caddr_t)hldev;
9276937Sxw161283 xge_debug_osdep(XGE_TRACE,
9286937Sxw161283 "Channel-A: using MSI-X #0");
9296937Sxw161283 } else if (assigned[i] && assigned[i]->type ==
9306937Sxw161283 XGE_HAL_CHANNEL_TYPE_FIFO) {
9316937Sxw161283 intr = xge_fifo_msix_isr;
9326937Sxw161283 intr_arg = (caddr_t)assigned[i];
9336937Sxw161283 xge_debug_osdep(XGE_TRACE, "Channel-Tx%d"
9346937Sxw161283 "using MSI-X #%d",
9356937Sxw161283 assigned[i]->post_qid, i);
9366937Sxw161283 } else if (assigned[i] && assigned[i]->type ==
9376937Sxw161283 XGE_HAL_CHANNEL_TYPE_RING) {
9386937Sxw161283 intr = xge_ring_msix_isr;
9396937Sxw161283 intr_arg = (caddr_t)assigned[i];
9406937Sxw161283 xge_debug_osdep(XGE_TRACE, "Channel-Rx%d: "
9416937Sxw161283 "using MSI-X #%d",
9426937Sxw161283 assigned[i]->post_qid, i);
9436937Sxw161283 }
9446937Sxw161283 ret = ddi_intr_add_handler(lldev->intr_table[i], intr,
9456937Sxw161283 intr_arg, (caddr_t)(uintptr_t)i);
9466937Sxw161283 if (ret != DDI_SUCCESS) {
9476937Sxw161283 int j;
9486937Sxw161283 xge_debug_osdep(XGE_ERR,
9496937Sxw161283 "ddi_intr_add_handler()"
9506937Sxw161283 " failed %d", ret);
9516937Sxw161283 for (j = 0; j < i; j++) {
9526937Sxw161283 (void) ddi_intr_remove_handler(
9536937Sxw161283 lldev->intr_table[j]);
9546937Sxw161283 }
9556937Sxw161283 return (DDI_FAILURE);
9566937Sxw161283 }
9576937Sxw161283 }
9586937Sxw161283
9596937Sxw161283 for (i = 1; i < msix_idx; i++)
9606937Sxw161283 (void) xge_hal_channel_msix_set(assigned[i], i);
9616937Sxw161283 break;
9626937Sxw161283
9636937Sxw161283 default:
9646937Sxw161283 break;
9656937Sxw161283 }
9666937Sxw161283 ret = ddi_intr_get_cap(lldev->intr_table[0], &lldev->intr_cap);
9676937Sxw161283 if (ret != DDI_SUCCESS) {
9686937Sxw161283 xge_debug_osdep(XGE_ERR, "ddi_intr_get_cap() failed %d", ret);
9696937Sxw161283 for (i = 0; i < lldev->intr_cnt; i++) {
9706937Sxw161283 (void) ddi_intr_remove_handler(lldev->intr_table[i]);
9716937Sxw161283 }
9726937Sxw161283 return (DDI_FAILURE);
9736937Sxw161283 }
9746937Sxw161283 return (DDI_SUCCESS);
9756937Sxw161283 }
9766937Sxw161283
9776937Sxw161283
9786937Sxw161283 /*
9796937Sxw161283 * xge_enable_intrs:
9806937Sxw161283 *
9816937Sxw161283 * Enable FIXED or MSI interrupts
9826937Sxw161283 */
9836937Sxw161283 int
xge_enable_intrs(xgelldev_t * lldev)9846937Sxw161283 xge_enable_intrs(xgelldev_t *lldev)
9856937Sxw161283 {
9866937Sxw161283 int ret, i;
9876937Sxw161283
9886937Sxw161283 if (lldev->intr_cap & DDI_INTR_FLAG_BLOCK) {
9896937Sxw161283 /* Call ddi_intr_block_enable() for MSI(X) interrupts */
9906937Sxw161283 if ((ret = ddi_intr_block_enable(lldev->intr_table,
9916937Sxw161283 lldev->intr_cnt)) != DDI_SUCCESS) {
9926937Sxw161283 xge_debug_osdep(XGE_ERR, "ddi_intr_enable() failed, "
9936937Sxw161283 "ret 0x%x", ret);
9946937Sxw161283 return (DDI_FAILURE);
9956937Sxw161283 }
9966937Sxw161283 } else {
9976937Sxw161283 /* Call ddi_intr_enable for MSI(X) or FIXED interrupts */
9986937Sxw161283 for (i = 0; i < lldev->intr_cnt; i++) {
9996937Sxw161283 if ((ret = ddi_intr_enable(lldev->intr_table[i]))
10006937Sxw161283 != DDI_SUCCESS) {
10016937Sxw161283 int j;
10026937Sxw161283
10036937Sxw161283 xge_debug_osdep(XGE_ERR, "ddi_intr_enable() "
10046937Sxw161283 "failed, ret 0x%x", ret);
10056937Sxw161283
10066937Sxw161283 /* unwind */
10076937Sxw161283 for (j = 0; j < i; j++) {
10086937Sxw161283 (void) ddi_intr_disable(
10096937Sxw161283 lldev->intr_table[j]);
10106937Sxw161283 }
10116937Sxw161283
10126937Sxw161283 return (DDI_FAILURE);
10136937Sxw161283 }
10146937Sxw161283 }
10156937Sxw161283 }
10166937Sxw161283
10176937Sxw161283 return (DDI_SUCCESS);
10186937Sxw161283 }
10196937Sxw161283
10206937Sxw161283 /*
10216937Sxw161283 * xge_disable_intrs:
10226937Sxw161283 *
10236937Sxw161283 * Disable FIXED or MSI interrupts
10246937Sxw161283 */
10256937Sxw161283 void
xge_disable_intrs(xgelldev_t * lldev)10266937Sxw161283 xge_disable_intrs(xgelldev_t *lldev)
10276937Sxw161283 {
10286937Sxw161283 int i;
10296937Sxw161283
10306937Sxw161283 if (lldev->intr_cap & DDI_INTR_FLAG_BLOCK) {
10316937Sxw161283 /* Call ddi_intr_block_disable() */
10326937Sxw161283 (void) ddi_intr_block_disable(lldev->intr_table,
10336937Sxw161283 lldev->intr_cnt);
10346937Sxw161283 } else {
10356937Sxw161283 for (i = 0; i < lldev->intr_cnt; i++) {
10366937Sxw161283 (void) ddi_intr_disable(lldev->intr_table[i]);
10376937Sxw161283 }
10386937Sxw161283 }
10396937Sxw161283 }
10406937Sxw161283
10416937Sxw161283 /*
10426937Sxw161283 * xge_rem_intrs:
10436937Sxw161283 *
10446937Sxw161283 * Unregister FIXED or MSI interrupts
10456937Sxw161283 */
10466937Sxw161283 void
xge_rem_intrs(xgelldev_t * lldev)10476937Sxw161283 xge_rem_intrs(xgelldev_t *lldev)
10486937Sxw161283 {
10496937Sxw161283 int i;
10506937Sxw161283
1051*8275SEric Cheng xge_assert(lldev->intr_table != NULL);
1052*8275SEric Cheng
10536937Sxw161283 /* Call ddi_intr_remove_handler() */
10546937Sxw161283 for (i = 0; i < lldev->intr_cnt; i++) {
10556937Sxw161283 (void) ddi_intr_remove_handler(lldev->intr_table[i]);
10566937Sxw161283 }
10576937Sxw161283 }
10586937Sxw161283
10591256Syl150051 /*
10601256Syl150051 * xge_attach
10611256Syl150051 * @dev_info: pointer to dev_info_t structure
10621256Syl150051 * @cmd: attach command to process
10631256Syl150051 *
10641256Syl150051 * This is a solaris standard attach function. This
10651256Syl150051 * function initializes the Xframe identified
10661256Syl150051 * by the dev_info_t structure and setup the driver
10671256Syl150051 * data structures corresponding to the Xframe Card.
10681256Syl150051 * This function also registers the XFRAME device
10691256Syl150051 * instance with the MAC Layer.
10701256Syl150051 * If this function returns success then the OS
10711256Syl150051 * will attach the HBA controller to this
10721256Syl150051 * driver.
10731256Syl150051 */
10741256Syl150051 static int
xge_attach(dev_info_t * dev_info,ddi_attach_cmd_t cmd)10751256Syl150051 xge_attach(dev_info_t *dev_info, ddi_attach_cmd_t cmd)
10761256Syl150051 {
10771256Syl150051 xgelldev_t *ll;
1078*8275SEric Cheng xgell_config_t *xgell_config;
10796937Sxw161283 xge_hal_device_config_t *device_config;
10801256Syl150051 xge_hal_device_t *hldev;
10811256Syl150051 xge_hal_device_attr_t attr;
10821256Syl150051 xge_hal_status_e status;
10836937Sxw161283 int ret, intr_types, i;
10841256Syl150051
10851256Syl150051 xge_debug_osdep(XGE_TRACE, "XGE_ATTACH cmd %d", cmd);
10861256Syl150051
10871256Syl150051 switch (cmd) {
10881256Syl150051 case DDI_ATTACH:
10891256Syl150051 break;
10901256Syl150051
10911256Syl150051 case DDI_RESUME:
10921256Syl150051 case DDI_PM_RESUME:
10931256Syl150051 xge_debug_osdep(XGE_ERR, "%s", "resume unsupported yet");
10941256Syl150051 ret = DDI_FAILURE;
10951256Syl150051 goto _exit0;
10961256Syl150051
10971256Syl150051 default:
10981256Syl150051 xge_debug_osdep(XGE_ERR, "cmd 0x%x unrecognized", cmd);
10991256Syl150051 ret = DDI_FAILURE;
11001256Syl150051 goto _exit0;
11011256Syl150051 }
11021256Syl150051
1103*8275SEric Cheng xgell_config = kmem_zalloc(sizeof (xgell_config_t), KM_SLEEP);
11046937Sxw161283 device_config = kmem_zalloc(sizeof (xge_hal_device_config_t), KM_SLEEP);
11051256Syl150051
1106*8275SEric Cheng /*
1107*8275SEric Cheng * Initialize all configurations
1108*8275SEric Cheng */
1109*8275SEric Cheng xge_configuration_init(dev_info, device_config, xgell_config);
11106937Sxw161283
11116937Sxw161283 /* Determine which types of interrupts supported */
11126937Sxw161283 ret = ddi_intr_get_supported_types(dev_info, &intr_types);
11136937Sxw161283 if ((ret != DDI_SUCCESS) || (!(intr_types & DDI_INTR_TYPE_FIXED))) {
11146937Sxw161283 xge_debug_osdep(XGE_ERR, "%s",
11156937Sxw161283 "fixed type interrupt is not supported");
11166937Sxw161283 goto _exit0a;
11176937Sxw161283 }
11181256Syl150051
11191256Syl150051 /* map BAR0 */
11201256Syl150051 ret = ddi_regs_map_setup(dev_info, 1, (caddr_t *)&attr.bar0,
11211256Syl150051 (offset_t)0, (offset_t)0, &xge_dev_attr, &attr.regh0);
11221256Syl150051 if (ret != DDI_SUCCESS) {
11231256Syl150051 xge_debug_osdep(XGE_ERR, "unable to map bar0: [%d]", ret);
11246937Sxw161283 goto _exit0a;
11251256Syl150051 }
11261256Syl150051
11271256Syl150051 /* map BAR1 */
11281256Syl150051 ret = ddi_regs_map_setup(dev_info, 2, (caddr_t *)&attr.bar1,
11291256Syl150051 (offset_t)0, (offset_t)0, &xge_dev_attr, &attr.regh1);
11301256Syl150051 if (ret != DDI_SUCCESS) {
11311256Syl150051 xge_debug_osdep(XGE_ERR, "unable to map bar1: [%d]", ret);
11321256Syl150051 goto _exit1;
11331256Syl150051 }
11341256Syl150051
11356937Sxw161283 /* map BAR2 MSI(X) */
11366937Sxw161283 ret = ddi_regs_map_setup(dev_info, 2, (caddr_t *)&attr.bar2,
11376937Sxw161283 (offset_t)0, (offset_t)0, &xge_dev_attr, &attr.regh2);
11386937Sxw161283 if (ret != DDI_SUCCESS) {
11396937Sxw161283 xge_debug_osdep(XGE_ERR, "unable to map bar2: [%d]", ret);
11406937Sxw161283 goto _exit1a;
11416937Sxw161283 }
11426937Sxw161283
11431256Syl150051 /* preallocate memory for new HAL device and private LL part */
11441256Syl150051 hldev = kmem_zalloc(sizeof (xge_hal_device_t), KM_SLEEP);
11451256Syl150051
11461256Syl150051 /* Get the PCI Configuartion space handle */
11471256Syl150051 ret = pci_config_setup(dev_info, &attr.cfgh);
11481256Syl150051 if (ret != DDI_SUCCESS) {
11491256Syl150051 xge_debug_osdep(XGE_ERR, "%s", "can not setup config space");
11501256Syl150051 goto _exit2a;
11511256Syl150051 }
11521256Syl150051
11531256Syl150051 attr.pdev = dev_info;
11541256Syl150051
11551256Syl150051 ret = xgell_device_alloc(hldev, dev_info, &ll);
11561256Syl150051 if (ret != DDI_SUCCESS) {
11571256Syl150051 xge_debug_osdep(XGE_ERR,
11581256Syl150051 "%s",
11591256Syl150051 "unable to allocate new LL device");
11601256Syl150051 goto _exit3;
11611256Syl150051 }
11621256Syl150051
1163*8275SEric Cheng /*
1164*8275SEric Cheng * Init multiple rings configuration
1165*8275SEric Cheng */
1166*8275SEric Cheng switch (xgell_config->grouping) {
1167*8275SEric Cheng case XGELL_CONF_GROUP_POLICY_VIRT:
1168*8275SEric Cheng ll->init_rx_rings = XGELL_RX_RING_NUM_MAX; /* 8 */
1169*8275SEric Cheng ll->init_tx_rings = XGELL_TX_RING_NUM_MAX; /* 8 */
1170*8275SEric Cheng ll->init_rx_groups = ll->init_rx_rings;
1171*8275SEric Cheng break;
1172*8275SEric Cheng case XGELL_CONF_GROUP_POLICY_PERF:
1173*8275SEric Cheng ll->init_rx_rings = XGELL_RX_RING_NUM_MAX; /* 8 */
1174*8275SEric Cheng ll->init_tx_rings = XGELL_TX_RING_NUM_MAX; /* 8 */
1175*8275SEric Cheng ll->init_rx_groups = 1;
1176*8275SEric Cheng break;
1177*8275SEric Cheng case XGELL_CONF_GROUP_POLICY_BASIC:
1178*8275SEric Cheng ll->init_rx_rings = XGELL_RX_RING_NUM_MIN; /* 1 */
1179*8275SEric Cheng ll->init_tx_rings = XGELL_TX_RING_NUM_MIN; /* 1 */
1180*8275SEric Cheng ll->init_rx_groups = ll->init_rx_rings;
1181*8275SEric Cheng break;
1182*8275SEric Cheng default:
1183*8275SEric Cheng ASSERT(0);
1184*8275SEric Cheng break;
1185*8275SEric Cheng }
1186*8275SEric Cheng
1187*8275SEric Cheng /*
1188*8275SEric Cheng * Init MSI-X configuration
1189*8275SEric Cheng */
1190*8275SEric Cheng if (xgell_config->msix_enable && intr_types & DDI_INTR_TYPE_MSIX) {
11916937Sxw161283 ll->intr_type = DDI_INTR_TYPE_MSIX;
11926937Sxw161283 ll->intr_cnt = 1;
11936937Sxw161283 for (i = 0; i < XGE_HAL_MAX_FIFO_NUM; i++)
11946937Sxw161283 if (device_config->fifo.queue[i].configured)
11956937Sxw161283 ll->intr_cnt++;
11966937Sxw161283 for (i = 0; i < XGE_HAL_MAX_RING_NUM; i++)
11976937Sxw161283 if (device_config->ring.queue[i].configured)
11986937Sxw161283 ll->intr_cnt++;
11996937Sxw161283 } else {
12006937Sxw161283 ll->intr_type = DDI_INTR_TYPE_FIXED;
12016937Sxw161283 ll->intr_cnt = 1;
12026937Sxw161283 }
12036937Sxw161283
1204*8275SEric Cheng /*
1205*8275SEric Cheng * Allocate interrupt(s)
1206*8275SEric Cheng */
12076937Sxw161283 while ((ret = xge_alloc_intrs(ll)) != DDI_SUCCESS) {
12086937Sxw161283 if (ll->intr_type == DDI_INTR_TYPE_MSIX) {
1209*8275SEric Cheng xgell_config->msix_enable = 0;
12106937Sxw161283 ll->intr_type = DDI_INTR_TYPE_FIXED;
12116937Sxw161283 ll->intr_cnt = 1;
12126937Sxw161283 device_config->intr_mode = XGE_HAL_INTR_MODE_IRQLINE;
12136937Sxw161283 xge_debug_osdep(XGE_TRACE,
12146937Sxw161283 "Unable to allocate MSI-X handlers"
12156937Sxw161283 " - defaulting to IRQA");
12166937Sxw161283 continue;
12176937Sxw161283 }
12181256Syl150051 goto _exit3a;
12191256Syl150051 }
12201256Syl150051
12216937Sxw161283 if (ll->intr_type == DDI_INTR_TYPE_MSIX) {
12226937Sxw161283 device_config->intr_mode = XGE_HAL_INTR_MODE_MSIX;
12236937Sxw161283 device_config->bimodal_interrupts = 0;
12246937Sxw161283 } else {
12256937Sxw161283 device_config->intr_mode = XGE_HAL_INTR_MODE_IRQLINE;
12266937Sxw161283 }
12276937Sxw161283
12286937Sxw161283 attr.irqh = ll->intr_pri;
12296937Sxw161283
12301256Syl150051 /* initialize HW */
12316937Sxw161283 status = xge_hal_device_initialize(hldev, &attr, device_config);
12321256Syl150051 if (status != XGE_HAL_OK) {
12331256Syl150051 switch (status) {
12341256Syl150051 case XGE_HAL_ERR_DRIVER_NOT_INITIALIZED:
12351256Syl150051 xge_debug_osdep(XGE_ERR, "%s",
12361256Syl150051 "driver is not initialized");
12371256Syl150051 ret = DDI_FAILURE;
12381256Syl150051 goto _exit3b;
12391256Syl150051 case XGE_HAL_ERR_DEVICE_IS_NOT_QUIESCENT:
12401256Syl150051 xge_debug_osdep(XGE_ERR, "%s",
12411256Syl150051 "device is not quiescent");
12421256Syl150051 ret = DDI_EBUSY;
12431256Syl150051 goto _exit3b;
12441256Syl150051 case XGE_HAL_ERR_OUT_OF_MEMORY:
12451256Syl150051 xge_debug_osdep(XGE_ERR, "%s",
12461256Syl150051 "unable to allocate memory");
12471256Syl150051 ret = DDI_ENOMEM;
12481256Syl150051 goto _exit3b;
12491256Syl150051 default:
12501256Syl150051 xge_debug_osdep(XGE_ERR,
12511256Syl150051 "can't initialize the device: %d", status);
12521256Syl150051 ret = DDI_FAILURE;
12531256Syl150051 goto _exit3b;
12541256Syl150051 }
12551256Syl150051 }
12561256Syl150051
12576937Sxw161283 /* register interrupt handler for handling xge device interrupts */
12586937Sxw161283 ret = xge_add_intrs(ll);
12596937Sxw161283 if (ret != DDI_SUCCESS)
12606937Sxw161283 goto _exit4;
12616937Sxw161283
12621256Syl150051 /* allocate and register Link Layer */
1263*8275SEric Cheng ret = xgell_device_register(ll, xgell_config);
12641256Syl150051 if (ret != DDI_SUCCESS) {
12656937Sxw161283 goto _exit5;
12661256Syl150051 }
12671256Syl150051
12681256Syl150051 /* store ll as a HAL private part */
12691256Syl150051 xge_hal_device_private_set(hldev, ll);
12701256Syl150051
12716937Sxw161283 kmem_free(device_config, sizeof (xge_hal_device_config_t));
1272*8275SEric Cheng kmem_free(xgell_config, sizeof (xgell_config_t));
12736937Sxw161283
12741256Syl150051 return (DDI_SUCCESS);
12751256Syl150051
12766937Sxw161283 _exit5:
12776937Sxw161283 xge_rem_intrs(ll);
12781256Syl150051 _exit4:
12791256Syl150051 xge_hal_device_terminate(hldev);
12801256Syl150051 _exit3b:
12816937Sxw161283 xge_free_intrs(ll);
12821256Syl150051 _exit3a:
12831256Syl150051 xgell_device_free(ll);
12841256Syl150051 _exit3:
12851256Syl150051 pci_config_teardown(&attr.cfgh);
12861256Syl150051 _exit2a:
12871256Syl150051 kmem_free(hldev, sizeof (xge_hal_device_t));
12881256Syl150051 _exit2:
12896937Sxw161283 ddi_regs_map_free(&attr.regh2);
12906937Sxw161283 _exit1a:
12911256Syl150051 ddi_regs_map_free(&attr.regh1);
12921256Syl150051 _exit1:
12931256Syl150051 ddi_regs_map_free(&attr.regh0);
12946937Sxw161283 _exit0a:
12956937Sxw161283 kmem_free(device_config, sizeof (xge_hal_device_config_t));
1296*8275SEric Cheng kmem_free(xgell_config, sizeof (xgell_config_t));
12971256Syl150051 _exit0:
12981256Syl150051 return (ret);
12991256Syl150051 }
13001256Syl150051
13011256Syl150051 /*
13027656SSherry.Moore@Sun.COM * quiesce(9E) entry point.
13037656SSherry.Moore@Sun.COM *
13047656SSherry.Moore@Sun.COM * This function is called when the system is single-threaded at high
13057656SSherry.Moore@Sun.COM * PIL with preemption disabled. Therefore, this function must not be
13067656SSherry.Moore@Sun.COM * blocked.
13077656SSherry.Moore@Sun.COM *
13087656SSherry.Moore@Sun.COM * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
13097656SSherry.Moore@Sun.COM * DDI_FAILURE indicates an error condition and should almost never happen.
13107656SSherry.Moore@Sun.COM */
13117656SSherry.Moore@Sun.COM static int
xge_quiesce(dev_info_t * dev_info)13127656SSherry.Moore@Sun.COM xge_quiesce(dev_info_t *dev_info)
13137656SSherry.Moore@Sun.COM {
13147656SSherry.Moore@Sun.COM xge_hal_device_t *hldev =
13157656SSherry.Moore@Sun.COM (xge_hal_device_t *)ddi_get_driver_private(dev_info);
13167656SSherry.Moore@Sun.COM
13177656SSherry.Moore@Sun.COM xgelldev_t *lldev = xge_hal_device_private(hldev);
13187656SSherry.Moore@Sun.COM
13197656SSherry.Moore@Sun.COM xge_hal_device_quiesce(hldev, lldev->devh);
13207656SSherry.Moore@Sun.COM
13217656SSherry.Moore@Sun.COM return (DDI_SUCCESS);
13227656SSherry.Moore@Sun.COM }
13237656SSherry.Moore@Sun.COM
13247656SSherry.Moore@Sun.COM /*
13251256Syl150051 * xge_detach
13261256Syl150051 * @dev_info: pointer to dev_info_t structure
13271256Syl150051 * @cmd: attach command to process
13281256Syl150051 *
13291256Syl150051 * This function is called by OS when the system is about
13301256Syl150051 * to shutdown or when the super user tries to unload
13311256Syl150051 * the driver. This function frees all the memory allocated
1332*8275SEric Cheng * during xge_attach() and also unregisters the Xframe
13331256Syl150051 * device instance from the GLD framework.
13341256Syl150051 */
13351256Syl150051 static int
xge_detach(dev_info_t * dev_info,ddi_detach_cmd_t cmd)13361256Syl150051 xge_detach(dev_info_t *dev_info, ddi_detach_cmd_t cmd)
13371256Syl150051 {
13381256Syl150051 xge_hal_device_t *hldev;
13391256Syl150051 xge_hal_device_attr_t *attr;
13401256Syl150051 xgelldev_t *lldev;
13411256Syl150051
13421256Syl150051 xge_debug_osdep(XGE_TRACE, "XGE_DETACH cmd %d", cmd);
13431256Syl150051
13441256Syl150051 hldev = (xge_hal_device_t *)ddi_get_driver_private(dev_info);
13451256Syl150051 attr = xge_hal_device_attr(hldev);
13461256Syl150051 lldev = xge_hal_device_private(hldev);
13471256Syl150051
13481256Syl150051 switch (cmd) {
13491256Syl150051 case DDI_DETACH:
13501256Syl150051 break;
13511256Syl150051
13521256Syl150051 case DDI_PM_SUSPEND:
13531256Syl150051 xge_debug_osdep(XGE_ERR, "%s", "suspend unsupported yet");
13541256Syl150051 return (DDI_FAILURE);
13551256Syl150051
13561256Syl150051 default:
13571256Syl150051 xge_debug_osdep(XGE_ERR, "cmd 0x%x unrecognized", cmd);
13581256Syl150051 return (DDI_FAILURE);
13591256Syl150051 }
13601256Syl150051
13611256Syl150051 if (lldev->is_initialized) {
13621256Syl150051 xge_debug_osdep(XGE_ERR, "%s",
13631256Syl150051 "can not detach: device is not unplumbed");
13641256Syl150051 return (DDI_FAILURE);
13651256Syl150051 }
13661256Syl150051
13671256Syl150051 xge_hal_device_terminating(hldev);
13681256Syl150051 if (xgell_device_unregister(lldev) != DDI_SUCCESS) {
13691256Syl150051 return (DDI_FAILURE);
13701256Syl150051 }
13711256Syl150051 xge_hal_device_terminate(hldev);
13721256Syl150051
13736937Sxw161283 xge_rem_intrs(lldev);
13746937Sxw161283 xge_free_intrs(lldev);
13751256Syl150051 xgell_device_free(lldev);
13761256Syl150051 pci_config_teardown(&attr->cfgh);
13776937Sxw161283 ddi_regs_map_free(&attr->regh2);
13781256Syl150051 ddi_regs_map_free(&attr->regh1);
13791256Syl150051 ddi_regs_map_free(&attr->regh0);
13801256Syl150051 kmem_free(hldev, sizeof (xge_hal_device_t));
13811256Syl150051
13821256Syl150051 return (DDI_SUCCESS);
13831256Syl150051 }
1384