summaryrefslogtreecommitdiffstats
path: root/sys/dev/nxge/if_nxge.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/nxge/if_nxge.c')
-rw-r--r--sys/dev/nxge/if_nxge.c3415
1 files changed, 3415 insertions, 0 deletions
diff --git a/sys/dev/nxge/if_nxge.c b/sys/dev/nxge/if_nxge.c
new file mode 100644
index 0000000..6687b4b
--- /dev/null
+++ b/sys/dev/nxge/if_nxge.c
@@ -0,0 +1,3415 @@
+/*-
+ * Copyright (c) 2002-2007 Neterion, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * if_nxge.c
+ *
+ * FreeBSD specific initialization & routines
+ */
+
+#include <dev/nxge/if_nxge.h>
+#include <dev/nxge/xge-osdep.h>
+#include <net/if_arp.h>
+#include <sys/types.h>
+#include <net/if.h>
+#include <net/if_vlan_var.h>
+
+int copyright_print = 0;
+int hal_driver_init_count = 0;
+size_t size = sizeof(int);
+
+/******************************************
+ * xge_probe
+ * Parameters: Device structure
+ * Return: BUS_PROBE_DEFAULT/ENXIO/ENOMEM
+ * Description: Probes for Xframe device
+ ******************************************/
+int
+xge_probe(device_t dev)
+{
+ int devid = pci_get_device(dev);
+ int vendorid = pci_get_vendor(dev);
+ int retValue = ENXIO;
+
+ ENTER_FUNCTION
+
+ if(vendorid == XGE_PCI_VENDOR_ID) {
+ if((devid == XGE_PCI_DEVICE_ID_XENA_2) ||
+ (devid == XGE_PCI_DEVICE_ID_HERC_2)) {
+ if(!copyright_print) {
+ PRINT_COPYRIGHT;
+ copyright_print = 1;
+ }
+ device_set_desc_copy(dev,
+ "Neterion Xframe 10 Gigabit Ethernet Adapter");
+ retValue = BUS_PROBE_DEFAULT;
+ }
+ }
+
+ LEAVE_FUNCTION
+ return retValue;
+}
+
+/******************************************
+ * xge_init_params
+ * Parameters: HAL device configuration
+ * structure, device pointer
+ * Return: None
+ * Description: Sets parameter values in
+ * xge_hal_device_config_t structure
+ ******************************************/
+void
+xge_init_params(xge_hal_device_config_t *dconfig, device_t dev)
+{
+ int index, revision;
+ device_t checkdev;
+
+ ENTER_FUNCTION
+
+#define SAVE_PARAM(to, what, value) to.what = value;
+
+#define GET_PARAM(str_kenv, to, param, hardcode) { \
+ static int param##__LINE__; \
+ if(testenv(str_kenv) == 1) { \
+ getenv_int(str_kenv, &param##__LINE__); \
+ } \
+ else { \
+ param##__LINE__ = hardcode; \
+ } \
+ SAVE_PARAM(to, param, param##__LINE__); \
+}
+
+#define GET_PARAM_MAC(str_kenv, param, hardcode) \
+ GET_PARAM(str_kenv, ((*dconfig).mac), param, hardcode);
+
+#define GET_PARAM_FIFO(str_kenv, param, hardcode) \
+ GET_PARAM(str_kenv, ((*dconfig).fifo), param, hardcode);
+
+#define GET_PARAM_FIFO_QUEUE(str_kenv, param, qindex, hardcode) \
+ GET_PARAM(str_kenv, ((*dconfig).fifo.queue[qindex]), param, hardcode);
+
+#define GET_PARAM_FIFO_QUEUE_TTI(str_kenv, param, qindex, tindex, hardcode) \
+ GET_PARAM(str_kenv, ((*dconfig).fifo.queue[qindex].tti[tindex]), \
+ param, hardcode);
+
+#define GET_PARAM_RING(str_kenv, param, hardcode) \
+ GET_PARAM(str_kenv, ((*dconfig).ring), param, hardcode);
+
+#define GET_PARAM_RING_QUEUE(str_kenv, param, qindex, hardcode) \
+ GET_PARAM(str_kenv, ((*dconfig).ring.queue[qindex]), param, hardcode);
+
+#define GET_PARAM_RING_QUEUE_RTI(str_kenv, param, qindex, hardcode) \
+ GET_PARAM(str_kenv, ((*dconfig).ring.queue[qindex].rti), param, \
+ hardcode);
+
+ dconfig->mtu = XGE_DEFAULT_INITIAL_MTU;
+ dconfig->pci_freq_mherz = XGE_DEFAULT_USER_HARDCODED;
+ dconfig->device_poll_millis = XGE_HAL_DEFAULT_DEVICE_POLL_MILLIS;
+ dconfig->link_stability_period = XGE_HAL_DEFAULT_LINK_STABILITY_PERIOD;
+ dconfig->mac.rmac_bcast_en = XGE_DEFAULT_MAC_RMAC_BCAST_EN;
+ dconfig->fifo.alignment_size = XGE_DEFAULT_FIFO_ALIGNMENT_SIZE;
+
+ GET_PARAM("hw.xge.latency_timer", (*dconfig), latency_timer,
+ XGE_DEFAULT_LATENCY_TIMER);
+ GET_PARAM("hw.xge.max_splits_trans", (*dconfig), max_splits_trans,
+ XGE_DEFAULT_MAX_SPLITS_TRANS);
+ GET_PARAM("hw.xge.mmrb_count", (*dconfig), mmrb_count,
+ XGE_DEFAULT_MMRB_COUNT);
+ GET_PARAM("hw.xge.shared_splits", (*dconfig), shared_splits,
+ XGE_DEFAULT_SHARED_SPLITS);
+ GET_PARAM("hw.xge.isr_polling_cnt", (*dconfig), isr_polling_cnt,
+ XGE_DEFAULT_ISR_POLLING_CNT);
+ GET_PARAM("hw.xge.stats_refresh_time_sec", (*dconfig),
+ stats_refresh_time_sec, XGE_DEFAULT_STATS_REFRESH_TIME_SEC);
+
+ GET_PARAM_MAC("hw.xge.mac_tmac_util_period", tmac_util_period,
+ XGE_DEFAULT_MAC_TMAC_UTIL_PERIOD);
+ GET_PARAM_MAC("hw.xge.mac_rmac_util_period", rmac_util_period,
+ XGE_DEFAULT_MAC_RMAC_UTIL_PERIOD);
+ GET_PARAM_MAC("hw.xge.mac_rmac_pause_gen_en", rmac_pause_gen_en,
+ XGE_DEFAULT_MAC_RMAC_PAUSE_GEN_EN);
+ GET_PARAM_MAC("hw.xge.mac_rmac_pause_rcv_en", rmac_pause_rcv_en,
+ XGE_DEFAULT_MAC_RMAC_PAUSE_RCV_EN);
+ GET_PARAM_MAC("hw.xge.mac_rmac_pause_time", rmac_pause_time,
+ XGE_DEFAULT_MAC_RMAC_PAUSE_TIME);
+ GET_PARAM_MAC("hw.xge.mac_mc_pause_threshold_q0q3",
+ mc_pause_threshold_q0q3, XGE_DEFAULT_MAC_MC_PAUSE_THRESHOLD_Q0Q3);
+ GET_PARAM_MAC("hw.xge.mac_mc_pause_threshold_q4q7",
+ mc_pause_threshold_q4q7, XGE_DEFAULT_MAC_MC_PAUSE_THRESHOLD_Q4Q7);
+
+ GET_PARAM_FIFO("hw.xge.fifo_memblock_size", memblock_size,
+ XGE_DEFAULT_FIFO_MEMBLOCK_SIZE);
+ GET_PARAM_FIFO("hw.xge.fifo_reserve_threshold", reserve_threshold,
+ XGE_DEFAULT_FIFO_RESERVE_THRESHOLD);
+ GET_PARAM_FIFO("hw.xge.fifo_max_frags", max_frags,
+ XGE_DEFAULT_FIFO_MAX_FRAGS);
+
+ GET_PARAM_FIFO_QUEUE("hw.xge.fifo_queue_intr", intr, 0,
+ XGE_DEFAULT_FIFO_QUEUE_INTR);
+ GET_PARAM_FIFO_QUEUE("hw.xge.fifo_queue_max", max, 0,
+ XGE_DEFAULT_FIFO_QUEUE_MAX);
+ GET_PARAM_FIFO_QUEUE("hw.xge.fifo_queue_initial", initial, 0,
+ XGE_DEFAULT_FIFO_QUEUE_INITIAL);
+
+ for (index = 0; index < XGE_HAL_MAX_FIFO_TTI_NUM; index++) {
+ dconfig->fifo.queue[0].tti[index].enabled = 1;
+ dconfig->fifo.queue[0].configured = 1;
+
+ GET_PARAM_FIFO_QUEUE_TTI("hw.xge.fifo_queue_tti_urange_a",
+ urange_a, 0, index, XGE_DEFAULT_FIFO_QUEUE_TTI_URANGE_A);
+ GET_PARAM_FIFO_QUEUE_TTI("hw.xge.fifo_queue_tti_urange_b",
+ urange_b, 0, index, XGE_DEFAULT_FIFO_QUEUE_TTI_URANGE_B);
+ GET_PARAM_FIFO_QUEUE_TTI("hw.xge.fifo_queue_tti_urange_c",
+ urange_c, 0, index, XGE_DEFAULT_FIFO_QUEUE_TTI_URANGE_C);
+ GET_PARAM_FIFO_QUEUE_TTI("hw.xge.fifo_queue_tti_ufc_a",
+ ufc_a, 0, index, XGE_DEFAULT_FIFO_QUEUE_TTI_UFC_A);
+ GET_PARAM_FIFO_QUEUE_TTI("hw.xge.fifo_queue_tti_ufc_b",
+ ufc_b, 0, index, XGE_DEFAULT_FIFO_QUEUE_TTI_UFC_B);
+ GET_PARAM_FIFO_QUEUE_TTI("hw.xge.fifo_queue_tti_ufc_c",
+ ufc_c, 0, index, XGE_DEFAULT_FIFO_QUEUE_TTI_UFC_C);
+ GET_PARAM_FIFO_QUEUE_TTI("hw.xge.fifo_queue_tti_ufc_d",
+ ufc_d, 0, index, XGE_DEFAULT_FIFO_QUEUE_TTI_UFC_D);
+ GET_PARAM_FIFO_QUEUE_TTI("hw.xge.fifo_queue_tti_timer_ci_en",
+ timer_ci_en, 0, index, XGE_DEFAULT_FIFO_QUEUE_TTI_TIMER_CI_EN);
+ GET_PARAM_FIFO_QUEUE_TTI("hw.xge.fifo_queue_tti_timer_ac_en",
+ timer_ac_en, 0, index, XGE_DEFAULT_FIFO_QUEUE_TTI_TIMER_AC_EN);
+ GET_PARAM_FIFO_QUEUE_TTI("hw.xge.fifo_queue_tti_timer_val_us",
+ timer_val_us, 0, index,
+ XGE_DEFAULT_FIFO_QUEUE_TTI_TIMER_VAL_US);
+ }
+
+ GET_PARAM_RING("hw.xge.ring_memblock_size", memblock_size,
+ XGE_DEFAULT_RING_MEMBLOCK_SIZE);
+
+ GET_PARAM_RING("hw.xge.ring_strip_vlan_tag", strip_vlan_tag,
+ XGE_DEFAULT_RING_STRIP_VLAN_TAG);
+
+ for (index = 0; index < XGE_HAL_MIN_RING_NUM; index++) {
+ dconfig->ring.queue[index].max_frm_len = XGE_HAL_RING_USE_MTU;
+ dconfig->ring.queue[index].priority = 0;
+ dconfig->ring.queue[index].configured = 1;
+ dconfig->ring.queue[index].buffer_mode =
+ XGE_HAL_RING_QUEUE_BUFFER_MODE_1;
+
+ GET_PARAM_RING_QUEUE("hw.xge.ring_queue_max", max, index,
+ XGE_DEFAULT_RING_QUEUE_MAX);
+ GET_PARAM_RING_QUEUE("hw.xge.ring_queue_initial", initial, index,
+ XGE_DEFAULT_RING_QUEUE_INITIAL);
+ GET_PARAM_RING_QUEUE("hw.xge.ring_queue_dram_size_mb", dram_size_mb,
+ index, XGE_DEFAULT_RING_QUEUE_DRAM_SIZE_MB);
+ GET_PARAM_RING_QUEUE("hw.xge.ring_queue_indicate_max_pkts",
+ indicate_max_pkts, index,
+ XGE_DEFAULT_RING_QUEUE_INDICATE_MAX_PKTS);
+ GET_PARAM_RING_QUEUE("hw.xge.ring_queue_backoff_interval_us",
+ backoff_interval_us, index,
+ XGE_DEFAULT_RING_QUEUE_BACKOFF_INTERVAL_US);
+
+ GET_PARAM_RING_QUEUE_RTI("hw.xge.ring_queue_rti_ufc_a", ufc_a,
+ index, XGE_DEFAULT_RING_QUEUE_RTI_UFC_A);
+ GET_PARAM_RING_QUEUE_RTI("hw.xge.ring_queue_rti_ufc_b", ufc_b,
+ index, XGE_DEFAULT_RING_QUEUE_RTI_UFC_B);
+ GET_PARAM_RING_QUEUE_RTI("hw.xge.ring_queue_rti_ufc_c", ufc_c,
+ index, XGE_DEFAULT_RING_QUEUE_RTI_UFC_C);
+ GET_PARAM_RING_QUEUE_RTI("hw.xge.ring_queue_rti_ufc_d", ufc_d,
+ index, XGE_DEFAULT_RING_QUEUE_RTI_UFC_D);
+ GET_PARAM_RING_QUEUE_RTI("hw.xge.ring_queue_rti_timer_ac_en",
+ timer_ac_en, index, XGE_DEFAULT_RING_QUEUE_RTI_TIMER_AC_EN);
+ GET_PARAM_RING_QUEUE_RTI("hw.xge.ring_queue_rti_timer_val_us",
+ timer_val_us, index, XGE_DEFAULT_RING_QUEUE_RTI_TIMER_VAL_US);
+ GET_PARAM_RING_QUEUE_RTI("hw.xge.ring_queue_rti_urange_a", urange_a,
+ index, XGE_DEFAULT_RING_QUEUE_RTI_URANGE_A);
+ GET_PARAM_RING_QUEUE_RTI("hw.xge.ring_queue_rti_urange_b", urange_b,
+ index, XGE_DEFAULT_RING_QUEUE_RTI_URANGE_B);
+ GET_PARAM_RING_QUEUE_RTI("hw.xge.ring_queue_rti_urange_c", urange_c,
+ index, XGE_DEFAULT_RING_QUEUE_RTI_URANGE_C);
+ }
+
+ if(dconfig->fifo.max_frags > (PAGE_SIZE/32)) {
+ xge_os_printf("fifo_max_frags = %d", dconfig->fifo.max_frags);
+ xge_os_printf("fifo_max_frags should be <= (PAGE_SIZE / 32) = %d",
+ (PAGE_SIZE / 32));
+ xge_os_printf("Using fifo_max_frags = %d", (PAGE_SIZE / 32));
+ dconfig->fifo.max_frags = (PAGE_SIZE / 32);
+ }
+
+ checkdev = pci_find_device(VENDOR_ID_AMD, DEVICE_ID_8131_PCI_BRIDGE);
+ if(checkdev != NULL) {
+ /* Check Revision for 0x12 */
+ revision = pci_read_config(checkdev,
+ xge_offsetof(xge_hal_pci_config_t, revision), 1);
+ if(revision <= 0x12) {
+ /* Set mmrb_count to 1k and max splits = 2 */
+ dconfig->mmrb_count = 1;
+ dconfig->max_splits_trans = XGE_HAL_THREE_SPLIT_TRANSACTION;
+ }
+ }
+
+#ifdef XGE_FEATURE_LRO
+ /* updating the LRO frame's sg size and frame len size. */
+ dconfig->lro_sg_size = 20;
+ dconfig->lro_frm_len = 65536;
+#endif
+
+ LEAVE_FUNCTION
+}
+
+/******************************************
+ * xge_driver_initialize
+ * Parameters: None
+ * Return: 0/1
+ * Description: Defines HAL-ULD callbacks
+ * and initializes the HAL driver
+ ******************************************/
+int
+xge_driver_initialize(void)
+{
+ xge_hal_uld_cbs_t uld_callbacks;
+ xge_hal_driver_config_t driver_config;
+ xge_hal_status_e status = XGE_HAL_OK;
+
+ ENTER_FUNCTION
+
+ /* Initialize HAL driver */
+ if(!hal_driver_init_count) {
+ xge_os_memzero(&uld_callbacks, sizeof(xge_hal_uld_cbs_t));
+
+ /*
+ * Initial and maximum size of the queue used to store the events
+ * like Link up/down (xge_hal_event_e)
+ */
+ driver_config.queue_size_initial = 1;
+ driver_config.queue_size_max = 4;
+
+ uld_callbacks.link_up = xgell_callback_link_up;
+ uld_callbacks.link_down = xgell_callback_link_down;
+ uld_callbacks.crit_err = xgell_callback_crit_err;
+ uld_callbacks.event = xgell_callback_event;
+
+ status = xge_hal_driver_initialize(&driver_config, &uld_callbacks);
+ if(status != XGE_HAL_OK) {
+ xge_os_printf("xgeX: Initialization failed (Status: %d)",
+ status);
+ goto xdi_out;
+ }
+ }
+ hal_driver_init_count = hal_driver_init_count + 1;
+
+ xge_hal_driver_debug_module_mask_set(0xffffffff);
+ xge_hal_driver_debug_level_set(XGE_TRACE);
+
+xdi_out:
+ LEAVE_FUNCTION
+ return status;
+}
+
+/******************************************
+ * Function: xge_media_init
+ * Parameters: Device pointer
+ * Return: None
+ * Description: Initializes, adds and sets
+ * media
+ ******************************************/
+void
+xge_media_init(device_t devc)
+{
+ xgelldev_t *lldev = (xgelldev_t *)device_get_softc(devc);
+
+ ENTER_FUNCTION
+
+ /* Initialize Media */
+ ifmedia_init(&lldev->xge_media, IFM_IMASK, xge_ifmedia_change,
+ xge_ifmedia_status);
+
+ /* Add supported media */
+ ifmedia_add(&lldev->xge_media, IFM_ETHER | IFM_1000_SX | IFM_FDX,
+ 0, NULL);
+ ifmedia_add(&lldev->xge_media, IFM_ETHER | IFM_1000_SX, 0, NULL);
+ ifmedia_add(&lldev->xge_media, IFM_ETHER | IFM_AUTO, 0, NULL);
+ ifmedia_add(&lldev->xge_media, IFM_ETHER | IFM_10G_SR, 0, NULL);
+ ifmedia_add(&lldev->xge_media, IFM_ETHER | IFM_10G_LR, 0, NULL);
+
+ /* Set media */
+ ifmedia_set(&lldev->xge_media, IFM_ETHER | IFM_AUTO);
+
+ LEAVE_FUNCTION
+}
+
+/*
+ * xge_pci_space_save
+ * Save PCI configuration space
+ * @dev Device structure
+ */
+void
+xge_pci_space_save(device_t dev)
+{
+ ENTER_FUNCTION
+
+ struct pci_devinfo *dinfo = NULL;
+
+ dinfo = device_get_ivars(dev);
+ xge_trace(XGE_TRACE, "Saving PCI configuration space");
+ pci_cfg_save(dev, dinfo, 0);
+
+ LEAVE_FUNCTION
+}
+
+/*
+ * xge_pci_space_restore
+ * Restore saved PCI configuration space
+ * @dev Device structure
+ */
+void
+xge_pci_space_restore(device_t dev)
+{
+ ENTER_FUNCTION
+
+ struct pci_devinfo *dinfo = NULL;
+
+ dinfo = device_get_ivars(dev);
+ xge_trace(XGE_TRACE, "Restoring PCI configuration space");
+ pci_cfg_restore(dev, dinfo);
+
+ LEAVE_FUNCTION
+}
+
+/******************************************
+ * xge_attach
+ * Parameters: Per adapter xgelldev_t
+ * structure pointer
+ * Return: None
+ * Description: Connects the driver to the
+ * system if the probe routine returned success
+ ******************************************/
+int
+xge_attach(device_t dev)
+{
+ xge_hal_device_config_t *device_config;
+ xge_hal_ring_config_t *pRingConfig;
+ xge_hal_device_attr_t attr;
+ xgelldev_t *lldev;
+ xge_hal_device_t *hldev;
+ pci_info_t *pci_info;
+ struct ifnet *ifnetp;
+ char *mesg;
+ char *desc;
+ int rid;
+ int rid0;
+ int rid1;
+ int error;
+ u64 val64 = 0;
+ int retValue = 0;
+ int mode = 0;
+ int buffer_index, buffer_length, index;
+
+ ENTER_FUNCTION
+
+ device_config = xge_malloc(sizeof(xge_hal_device_config_t));
+ if(!device_config) {
+ xge_ctrace(XGE_ERR, "Malloc of device config failed");
+ retValue = ENOMEM;
+ goto attach_out_config;
+ }
+
+ lldev = (xgelldev_t *) device_get_softc(dev);
+ if(!lldev) {
+ xge_ctrace(XGE_ERR, "Adapter softc structure allocation failed");
+ retValue = ENOMEM;
+ goto attach_out;
+ }
+ lldev->device = dev;
+
+ /* Initialize mutex */
+ if(mtx_initialized(&lldev->xge_lock) == 0) {
+ mtx_init((&lldev->xge_lock), "xge", MTX_NETWORK_LOCK, MTX_DEF);
+ }
+
+ error = xge_driver_initialize();
+ if(error != XGE_HAL_OK) {
+ xge_ctrace(XGE_ERR, "Initializing driver failed");
+ freeResources(dev, 1);
+ retValue = ENXIO;
+ goto attach_out;
+ }
+
+ /* HAL device */
+ hldev = (xge_hal_device_t *)xge_malloc(sizeof(xge_hal_device_t));
+ if(!hldev) {
+ xge_trace(XGE_ERR, "Allocating memory for xge_hal_device_t failed");
+ freeResources(dev, 2);
+ retValue = ENOMEM;
+ goto attach_out;
+ }
+ lldev->devh = hldev;
+
+ /* Our private structure */
+ pci_info = (pci_info_t*) xge_malloc(sizeof(pci_info_t));
+ if(!pci_info) {
+ xge_trace(XGE_ERR, "Allocating memory for pci_info_t failed");
+ freeResources(dev, 3);
+ retValue = ENOMEM;
+ goto attach_out;
+ }
+ lldev->pdev = pci_info;
+ pci_info->device = dev;
+
+ /* Set bus master */
+ pci_enable_busmaster(dev);
+
+ /* Get virtual address for BAR0 */
+ rid0 = PCIR_BAR(0);
+ pci_info->regmap0 = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid0,
+ RF_ACTIVE);
+ if(pci_info->regmap0 == NULL) {
+ xge_trace(XGE_ERR, "NULL handler for BAR0");
+ freeResources(dev, 4);
+ retValue = ENOMEM;
+ goto attach_out;
+ }
+ attr.bar0 = (char *)pci_info->regmap0;
+
+ pci_info->bar0resource =
+ (busresource_t*) xge_malloc(sizeof(busresource_t));
+ if(pci_info->bar0resource == NULL) {
+ xge_trace(XGE_ERR, "Allocating memory for bar0resources failed");
+ freeResources(dev, 5);
+ retValue = ENOMEM;
+ goto attach_out;
+ }
+ ((struct busresources *)(pci_info->bar0resource))->bus_tag =
+ rman_get_bustag(pci_info->regmap0);
+ ((struct busresources *)(pci_info->bar0resource))->bus_handle =
+ rman_get_bushandle(pci_info->regmap0);
+ ((struct busresources *)(pci_info->bar0resource))->bar_start_addr =
+ pci_info->regmap0;
+
+ /* Get virtual address for BAR1 */
+ rid1 = PCIR_BAR(2);
+ pci_info->regmap1 = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid1,
+ RF_ACTIVE);
+ if(pci_info->regmap1 == NULL) {
+ xge_trace(XGE_ERR, "NULL handler for BAR1");
+ freeResources(dev, 6);
+ retValue = ENOMEM;
+ goto attach_out;
+ }
+ attr.bar1 = (char *)pci_info->regmap1;
+
+ pci_info->bar1resource =
+ (busresource_t*) xge_malloc(sizeof(busresource_t));
+ if(pci_info->bar1resource == NULL) {
+ xge_trace(XGE_ERR, "Allocating memory for bar0resources failed");
+ freeResources(dev, 7);
+ retValue = ENOMEM;
+ goto attach_out;
+ }
+ ((struct busresources *)(pci_info->bar1resource))->bus_tag =
+ rman_get_bustag(pci_info->regmap1);
+ ((struct busresources *)(pci_info->bar1resource))->bus_handle =
+ rman_get_bushandle(pci_info->regmap1);
+ ((struct busresources *)(pci_info->bar1resource))->bar_start_addr =
+ pci_info->regmap1;
+
+ /* Save PCI config space */
+ xge_pci_space_save(dev);
+
+ attr.regh0 = (busresource_t *) pci_info->bar0resource;
+ attr.regh1 = (busresource_t *) pci_info->bar1resource;
+ attr.irqh = lldev->irqhandle;
+ attr.cfgh = pci_info;
+ attr.pdev = pci_info;
+
+ /* Initialize device configuration parameters */
+ xge_init_params(device_config, dev);
+
+ /* Initialize HAL device */
+ error = xge_hal_device_initialize(hldev, &attr, device_config);
+ if(error != XGE_HAL_OK) {
+ switch(error) {
+ case XGE_HAL_ERR_DRIVER_NOT_INITIALIZED:
+ xge_trace(XGE_ERR, "XGE_HAL_ERR_DRIVER_NOT_INITIALIZED");
+ break;
+
+ case XGE_HAL_ERR_OUT_OF_MEMORY:
+ xge_trace(XGE_ERR, "XGE_HAL_ERR_OUT_OF_MEMORY");
+ break;
+
+ case XGE_HAL_ERR_BAD_SUBSYSTEM_ID:
+ xge_trace(XGE_ERR, "XGE_HAL_ERR_BAD_SUBSYSTEM_ID");
+ break;
+
+ case XGE_HAL_ERR_INVALID_MAC_ADDRESS:
+ xge_trace(XGE_ERR, "XGE_HAL_ERR_INVALID_MAC_ADDRESS");
+ break;
+
+ case XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING:
+ xge_trace(XGE_ERR, "XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING");
+ break;
+
+ case XGE_HAL_ERR_SWAPPER_CTRL:
+ xge_trace(XGE_ERR, "XGE_HAL_ERR_SWAPPER_CTRL");
+ break;
+
+ case XGE_HAL_ERR_DEVICE_IS_NOT_QUIESCENT:
+ xge_trace(XGE_ERR, "XGE_HAL_ERR_DEVICE_IS_NOT_QUIESCENT");
+ break;
+ }
+ xge_trace(XGE_ERR, "Initializing HAL device failed (error: %d)\n",
+ error);
+ freeResources(dev, 8);
+ retValue = ENXIO;
+ goto attach_out;
+ }
+
+ desc = (char *) malloc(100, M_DEVBUF, M_NOWAIT);
+ if(desc == NULL) {
+ retValue = ENOMEM;
+ }
+ else {
+ sprintf(desc, "%s (Rev %d) Driver v%s \n%s: Serial Number: %s ",
+ hldev->vpd_data.product_name, hldev->revision, DRIVER_VERSION,
+ device_get_nameunit(dev), hldev->vpd_data.serial_num);
+ printf("%s: Xframe%s %s\n", device_get_nameunit(dev),
+ ((hldev->device_id == XGE_PCI_DEVICE_ID_XENA_2) ? "I": "II"),
+ desc);
+ free(desc, M_DEVBUF);
+
+ }
+
+ if(pci_get_device(dev) == XGE_PCI_DEVICE_ID_HERC_2) {
+ error = xge_hal_mgmt_reg_read(hldev, 0,
+ xge_offsetof(xge_hal_pci_bar0_t, pci_info), &val64);
+ if(error != XGE_HAL_OK) {
+ xge_trace(XGE_ERR, "Error for getting bus speed");
+ }
+ mesg = (char *) xge_malloc(20);
+ if(mesg == NULL) {
+ freeResources(dev, 8);
+ retValue = ENOMEM;
+ goto attach_out;
+ }
+
+ sprintf(mesg, "%s: Device is on %s bit", device_get_nameunit(dev),
+ (val64 & BIT(8)) ? "32":"64");
+
+ mode = (u8)((val64 & vBIT(0xF, 0, 4)) >> 60);
+ switch(mode) {
+ case 0x00: xge_os_printf("%s PCI 33MHz bus", mesg); break;
+ case 0x01: xge_os_printf("%s PCI 66MHz bus", mesg); break;
+ case 0x02: xge_os_printf("%s PCIX(M1) 66MHz bus", mesg); break;
+ case 0x03: xge_os_printf("%s PCIX(M1) 100MHz bus", mesg); break;
+ case 0x04: xge_os_printf("%s PCIX(M1) 133MHz bus", mesg); break;
+ case 0x05: xge_os_printf("%s PCIX(M2) 133MHz bus", mesg); break;
+ case 0x06: xge_os_printf("%s PCIX(M2) 200MHz bus", mesg); break;
+ case 0x07: xge_os_printf("%s PCIX(M2) 266MHz bus", mesg); break;
+ }
+ free(mesg, M_DEVBUF);
+ }
+
+ xge_hal_device_private_set(hldev, lldev);
+
+ error = xge_interface_setup(dev);
+ if(error != 0) {
+ retValue = error;
+ goto attach_out;
+ }
+
+ ifnetp = lldev->ifnetp;
+ ifnetp->if_mtu = device_config->mtu;
+
+ xge_media_init(dev);
+
+ /* Interrupt */
+ rid = 0;
+ lldev->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+ RF_SHAREABLE | RF_ACTIVE);
+ if(lldev->irq == NULL) {
+ xge_trace(XGE_ERR, "NULL handler for IRQ");
+ freeResources(dev, 10);
+ retValue = ENOMEM;
+ goto attach_out;
+ }
+
+ /* Associate interrupt handler with the device */
+ error = bus_setup_intr(dev, lldev->irq, INTR_TYPE_NET | INTR_MPSAFE,
+#if __FreeBSD_version > 700030
+ xge_intr_filter,
+#endif
+ (void *)xge_intr, lldev, &lldev->irqhandle);
+ if(error != 0) {
+ xge_trace(XGE_ERR,
+ "Associating interrupt handler with device failed");
+ freeResources(dev, 11);
+ retValue = ENXIO;
+ goto attach_out;
+ }
+
+ /* Create DMA tags */
+ error = bus_dma_tag_create(
+ bus_get_dma_tag(dev), /* Parent */
+ PAGE_SIZE, /* Alignment */
+ 0, /* Bounds */
+ BUS_SPACE_MAXADDR, /* Low Address */
+ BUS_SPACE_MAXADDR, /* High Address */
+ NULL, /* Filter Function */
+ NULL, /* Filter Function Arguments */
+ MCLBYTES * MAX_SEGS, /* Maximum Size */
+ MAX_SEGS, /* Number of Segments */
+ MCLBYTES, /* Maximum Segment Size */
+ BUS_DMA_ALLOCNOW, /* Flags */
+ NULL, /* Lock Function */
+ NULL, /* Lock Function Arguments */
+ (&lldev->dma_tag_tx)); /* DMA Tag */
+ if(error != 0) {
+ xge_trace(XGE_ERR, "Tx DMA tag creation failed");
+ freeResources(dev, 12);
+ retValue = ENOMEM;
+ goto attach_out;
+ }
+
+ error = bus_dma_tag_create(
+ bus_get_dma_tag(dev), /* Parent */
+ PAGE_SIZE, /* Alignment */
+ 0, /* Bounds */
+ BUS_SPACE_MAXADDR, /* Low Address */
+ BUS_SPACE_MAXADDR, /* High Address */
+ NULL, /* Filter Function */
+ NULL, /* Filter Function Arguments */
+ MJUMPAGESIZE, /* Maximum Size */
+ 1, /* Number of Segments */
+ MJUMPAGESIZE, /* Maximum Segment Size */
+ BUS_DMA_ALLOCNOW, /* Flags */
+ NULL, /* Lock Function */
+ NULL, /* Lock Function Arguments */
+ (&lldev->dma_tag_rx)); /* DMA Tag */
+
+ if(error != 0) {
+ xge_trace(XGE_ERR, "Rx DMA tag creation failed");
+ freeResources(dev, 13);
+ retValue = ENOMEM;
+ goto attach_out;
+ }
+
+ /*Updating lldev->buffer_mode parameter*/
+ pRingConfig = &(hldev->config.ring);
+
+ if((device_config->mtu + XGE_HAL_MAC_HEADER_MAX_SIZE) <= PAGE_SIZE) {
+#if defined(XGE_FEATURE_BUFFER_MODE_3)
+ xge_os_printf("%s: 3 Buffer Mode Enabled",
+ device_get_nameunit(dev));
+ for(index = 0; index < XGE_RING_COUNT; index++) {
+ pRingConfig->queue[index].buffer_mode =
+ XGE_HAL_RING_QUEUE_BUFFER_MODE_3;
+ }
+ pRingConfig->scatter_mode = XGE_HAL_RING_QUEUE_SCATTER_MODE_A;
+ lldev->buffer_mode = XGE_HAL_RING_QUEUE_BUFFER_MODE_3;
+ lldev->rxd_mbuf_len[0] = XGE_HAL_MAC_HEADER_MAX_SIZE;
+ lldev->rxd_mbuf_len[1] = XGE_HAL_TCPIP_HEADER_MAX_SIZE;
+ lldev->rxd_mbuf_len[2] = device_config->mtu;
+ lldev->rxd_mbuf_cnt = 3;
+#else
+#if defined(XGE_FEATURE_BUFFER_MODE_2)
+ xge_os_printf("%s: 2 Buffer Mode Enabled",
+ device_get_nameunit(dev));
+ for(index = 0; index < XGE_RING_COUNT; index++) {
+ pRingConfig->queue[index].buffer_mode =
+ XGE_HAL_RING_QUEUE_BUFFER_MODE_3;
+ }
+ pRingConfig->scatter_mode = XGE_HAL_RING_QUEUE_SCATTER_MODE_B;
+ lldev->buffer_mode = XGE_HAL_RING_QUEUE_BUFFER_MODE_2;
+ lldev->rxd_mbuf_len[0] = XGE_HAL_MAC_HEADER_MAX_SIZE;
+ lldev->rxd_mbuf_len[1] = device_config->mtu;
+ lldev->rxd_mbuf_cnt = 2;
+#else
+ lldev->buffer_mode = XGE_HAL_RING_QUEUE_BUFFER_MODE_1;
+ lldev->rxd_mbuf_len[0] = device_config->mtu;
+ lldev->rxd_mbuf_cnt = 1;
+#endif
+#endif
+ }
+ else {
+ xge_os_printf("%s: 5 Buffer Mode Enabled",
+ device_get_nameunit(dev));
+ xge_os_memzero(lldev->rxd_mbuf_len, sizeof(lldev->rxd_mbuf_len));
+ for(index = 0; index < XGE_RING_COUNT; index++) {
+ pRingConfig->queue[index].buffer_mode =
+ XGE_HAL_RING_QUEUE_BUFFER_MODE_5;
+ }
+ lldev->buffer_mode = XGE_HAL_RING_QUEUE_BUFFER_MODE_5;
+ buffer_length = device_config->mtu;
+ buffer_index = 2;
+ lldev->rxd_mbuf_len[0] = XGE_HAL_MAC_HEADER_MAX_SIZE;
+ lldev->rxd_mbuf_len[1] = XGE_HAL_TCPIP_HEADER_MAX_SIZE;
+
+ while(buffer_length > PAGE_SIZE) {
+ buffer_length -= PAGE_SIZE;
+ lldev->rxd_mbuf_len[buffer_index] = PAGE_SIZE;
+ buffer_index++;
+ }
+
+ BUFALIGN(buffer_length);
+
+ lldev->rxd_mbuf_len[buffer_index] = buffer_length;
+ lldev->rxd_mbuf_cnt = buffer_index;
+ }
+
+#ifdef XGE_FEATURE_LRO
+ xge_os_printf("%s: LRO (Large Receive Offload) Enabled",
+ device_get_nameunit(dev));
+#endif
+
+#ifdef XGE_FEATURE_TSO
+ xge_os_printf("%s: TSO (TCP Segmentation Offload) enabled",
+ device_get_nameunit(dev));
+#endif
+
+attach_out:
+ free(device_config, M_DEVBUF);
+attach_out_config:
+ LEAVE_FUNCTION
+ return retValue;
+}
+
+/******************************************
+ * freeResources
+ * Parameters: Device structure, error (used
+ * to branch freeing)
+ * Return: None
+ * Description: Frees allocated resources
+ ******************************************/
+void
+freeResources(device_t dev, int error)
+{
+ xgelldev_t *lldev;
+ pci_info_t *pci_info;
+ xge_hal_device_t *hldev;
+ int rid, status;
+
+ ENTER_FUNCTION
+
+ /* LL Device */
+ lldev = (xgelldev_t *) device_get_softc(dev);
+ pci_info = lldev->pdev;
+
+ /* HAL Device */
+ hldev = lldev->devh;
+
+ switch(error) {
+ case 0:
+ status = bus_dma_tag_destroy(lldev->dma_tag_rx);
+ if(status) {
+ xge_trace(XGE_ERR, "Rx DMA tag destroy failed");
+ }
+
+ case 13:
+ status = bus_dma_tag_destroy(lldev->dma_tag_tx);
+ if(status) {
+ xge_trace(XGE_ERR, "Tx DMA tag destroy failed");
+ }
+
+ case 12:
+ /* Teardown interrupt handler - device association */
+ bus_teardown_intr(dev, lldev->irq, lldev->irqhandle);
+
+ case 11:
+ /* Release IRQ */
+ bus_release_resource(dev, SYS_RES_IRQ, 0, lldev->irq);
+
+ case 10:
+ /* Media */
+ ifmedia_removeall(&lldev->xge_media);
+
+ /* Detach Ether */
+ ether_ifdetach(lldev->ifnetp);
+ if_free(lldev->ifnetp);
+
+ xge_hal_device_private_set(hldev, NULL);
+ xge_hal_device_disable(hldev);
+
+ case 9:
+ /* HAL Device */
+ xge_hal_device_terminate(hldev);
+
+ case 8:
+ /* Restore PCI configuration space */
+ xge_pci_space_restore(dev);
+
+ /* Free bar1resource */
+ free(pci_info->bar1resource, M_DEVBUF);
+
+ case 7:
+ /* Release BAR1 */
+ rid = PCIR_BAR(2);
+ bus_release_resource(dev, SYS_RES_MEMORY, rid,
+ pci_info->regmap1);
+
+ case 6:
+ /* Free bar0resource */
+ free(pci_info->bar0resource, M_DEVBUF);
+
+ case 5:
+ /* Release BAR0 */
+ rid = PCIR_BAR(0);
+ bus_release_resource(dev, SYS_RES_MEMORY, rid,
+ pci_info->regmap0);
+
+ case 4:
+ /* Disable Bus Master */
+ pci_disable_busmaster(dev);
+
+ /* Free pci_info_t */
+ lldev->pdev = NULL;
+ free(pci_info, M_DEVBUF);
+
+ case 3:
+ /* Free device configuration struct and HAL device */
+ free(hldev, M_DEVBUF);
+
+ case 2:
+ /* Terminate HAL driver */
+ hal_driver_init_count = hal_driver_init_count - 1;
+ if(!hal_driver_init_count) {
+ xge_hal_driver_terminate();
+ }
+
+ case 1:
+ if(mtx_initialized(&lldev->xge_lock) != 0) {
+ mtx_destroy(&lldev->xge_lock);
+ }
+ }
+
+ LEAVE_FUNCTION
+}
+
+/******************************************
+ * xge_detach
+ * Parameters: Device structure
+ * Return: 0
+ * Description: Detaches the driver from the
+ * kernel subsystem.
+ ******************************************/
+int
+xge_detach(device_t dev)
+{
+ xgelldev_t *lldev = (xgelldev_t *)device_get_softc(dev);
+
+ ENTER_FUNCTION
+
+ mtx_lock(&lldev->xge_lock);
+ lldev->in_detach = 1;
+ xge_stop(lldev);
+ mtx_unlock(&lldev->xge_lock);
+
+ freeResources(dev, 0);
+
+ LEAVE_FUNCTION
+
+ return 0;
+}
+
+/******************************************
+ * xge_shutdown
+ * Parameters: Per adapter xgelldev_t
+ * structure pointer
+ * Return: None
+ * Description: Gets called when the system
+ * is about to be shutdown.
+ ******************************************/
+int
+xge_shutdown(device_t dev)
+{
+ xgelldev_t *lldev = (xgelldev_t *) device_get_softc(dev);
+
+ ENTER_FUNCTION
+ mtx_lock(&lldev->xge_lock);
+ xge_stop(lldev);
+ mtx_unlock(&lldev->xge_lock);
+ LEAVE_FUNCTION
+ return 0;
+}
+
+/******************************************
+ * Function: xge_interface_setup
+ * Parameters: Device pointer
+ * Return: 0/ENXIO/ENOMEM
+ * Description: Sets up the interface
+ * through ifnet pointer
+ ******************************************/
+int
+xge_interface_setup(device_t dev)
+{
+ u8 mcaddr[ETHER_ADDR_LEN];
+ xge_hal_status_e status_code;
+ xgelldev_t *lldev = (xgelldev_t *)device_get_softc(dev);
+ struct ifnet *ifnetp;
+ xge_hal_device_t *hldev = lldev->devh;
+ int retValue = 0;
+
+ ENTER_FUNCTION
+
+ /* Get the MAC address of the device */
+ status_code = xge_hal_device_macaddr_get(hldev, 0, &mcaddr);
+ if(status_code != XGE_HAL_OK) {
+ switch(status_code) {
+ case XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING:
+ xge_trace(XGE_ERR,
+ "Failed to retrieve MAC address (timeout)");
+ break;
+
+ case XGE_HAL_ERR_OUT_OF_MAC_ADDRESSES:
+ xge_trace(XGE_ERR, "Invalid MAC address index");
+ break;
+
+ default:
+ xge_trace(XGE_TRACE, "Default Case");
+ break;
+ }
+ freeResources(dev, 9);
+ retValue = ENXIO;
+ goto ifsetup_out;
+ }
+
+ /* Get interface ifnet structure for this Ether device */
+ ifnetp = lldev->ifnetp = if_alloc(IFT_ETHER);
+ if(ifnetp == NULL) {
+ xge_trace(XGE_ERR, "Allocating/getting ifnet structure failed");
+ freeResources(dev, 9);
+ retValue = ENOMEM;
+ goto ifsetup_out;
+ }
+
+ /* Initialize interface ifnet structure */
+ if_initname(ifnetp, device_get_name(dev), device_get_unit(dev));
+ ifnetp->if_mtu = XGE_HAL_DEFAULT_MTU;
+
+ /*
+ * TODO: Can't set more than 2Gbps. -- Higher value results in overflow.
+ * But there is no effect in performance even if you set this to 10 Mbps
+ */
+ ifnetp->if_baudrate = IF_Gbps(2);
+ ifnetp->if_init = xge_init;
+ ifnetp->if_softc = lldev;
+ ifnetp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifnetp->if_ioctl = xge_ioctl;
+ ifnetp->if_start = xge_send;
+
+ /* TODO: Check and assign optimal value */
+ ifnetp->if_snd.ifq_maxlen = IFQ_MAXLEN;
+
+ ifnetp->if_capabilities = IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU |
+ IFCAP_HWCSUM;
+
+ ifnetp->if_capenable = ifnetp->if_capabilities;
+
+#ifdef XGE_FEATURE_TSO
+ ifnetp->if_capabilities |= IFCAP_TSO4;
+ ifnetp->if_capenable |= IFCAP_TSO4;
+#endif
+
+ /* Attach the interface */
+ ether_ifattach(ifnetp, mcaddr);
+
+ifsetup_out:
+ LEAVE_FUNCTION
+
+ return retValue;
+}
+
+/******************************************
+ * xgell_callback_link_up
+ * Parameters: Per adapter xgelldev_t
+ * structure pointer as void *
+ * Return: None
+ * Description: Called by HAL to notify
+ * hardware link up state change
+ ******************************************/
+void
+xgell_callback_link_up(void *userdata)
+{
+ xgelldev_t *lldev = (xgelldev_t *)userdata;
+ struct ifnet *ifnetp = lldev->ifnetp;
+
+ ENTER_FUNCTION
+
+ ifnetp->if_flags &= ~IFF_DRV_OACTIVE;
+ if_link_state_change(ifnetp, LINK_STATE_UP);
+
+ LEAVE_FUNCTION
+}
+
+/******************************************
+ * xgell_callback_link_down
+ * Parameters: Per adapter xgelldev_t
+ * structure pointer as void *
+ * Return: None
+ * Description: Called by HAL to notify
+ * hardware link up state change
+ ******************************************/
+void
+xgell_callback_link_down(void *userdata)
+{
+ xgelldev_t *lldev = (xgelldev_t *)userdata;
+ struct ifnet *ifnetp = lldev->ifnetp;
+
+ ENTER_FUNCTION
+
+ ifnetp->if_flags |= IFF_DRV_OACTIVE;
+ if_link_state_change(ifnetp, LINK_STATE_DOWN);
+
+ LEAVE_FUNCTION
+}
+
+/******************************************
+ * xgell_callback_crit_err
+ * Parameters: Per adapter xgelldev_t
+ * structure pointer as void *, event,
+ * serr_data ->
+ * Return: None
+ * Description: Called by HAL on serious
+ * error event
+ ******************************************/
+void
+xgell_callback_crit_err(void *userdata, xge_hal_event_e type, u64 serr_data)
+{
+ ENTER_FUNCTION
+
+ xge_trace(XGE_ERR, "Critical Error");
+ xgell_reset(userdata);
+
+ LEAVE_FUNCTION
+}
+
+/******************************************
+ * xgell_callback_event
+ * Parameters: Queue item
+ * Return: None
+ * Description: Called by HAL in case of
+ * some unknown to HAL events.
+ ******************************************/
+void
+xgell_callback_event(xge_queue_item_t *item)
+{
+ xgelldev_t *lldev = NULL;
+ xge_hal_device_t *hldev = NULL;
+ struct ifnet *ifnetp = NULL;
+
+ ENTER_FUNCTION
+
+ hldev = item->context;
+ lldev = xge_hal_device_private(hldev);
+ ifnetp = lldev->ifnetp;
+
+ if(item->event_type == XGE_LL_EVENT_TRY_XMIT_AGAIN) {
+ if(lldev->initialized) {
+ if(xge_hal_channel_dtr_count(lldev->fifo_channel_0) > 0) {
+ ifnetp->if_flags &= ~IFF_DRV_OACTIVE;
+ }
+ else {
+ /* try next time */
+ xge_queue_produce_context(
+ xge_hal_device_queue(lldev->devh),
+ XGE_LL_EVENT_TRY_XMIT_AGAIN, lldev->devh);
+ }
+ }
+ }
+ else if(item->event_type == XGE_LL_EVENT_DEVICE_RESETTING) {
+ xgell_reset(item->context);
+ }
+
+ LEAVE_FUNCTION
+}
+
+/******************************************
+ * Function: xge_ifmedia_change
+ * Parameters: Pointer to ifnet structure
+ * Return: 0 for success, EINVAL if media
+ * type is not IFM_ETHER.
+ * Description: Media change driver callback
+ ******************************************/
+int
+xge_ifmedia_change(struct ifnet *ifnetp)
+{
+ xgelldev_t *lldev = ifnetp->if_softc;
+ struct ifmedia *ifmediap = &lldev->xge_media;
+
+ ENTER_FUNCTION
+ LEAVE_FUNCTION
+
+ return (IFM_TYPE(ifmediap->ifm_media) != IFM_ETHER) ? EINVAL:0;
+}
+
+/******************************************
+ * Function: xge_ifmedia_status
+ * Parameters: Pointer to ifnet structure
+ * ifmediareq structure pointer
+ * through which status of media
+ * will be returned.
+ * Return: None
+ * Description: Media status driver callback
+ ******************************************/
+void
+xge_ifmedia_status(struct ifnet *ifnetp, struct ifmediareq *ifmr)
+{
+ xge_hal_status_e status;
+ u64 regvalue;
+ xgelldev_t *lldev = ifnetp->if_softc;
+ xge_hal_device_t *hldev = lldev->devh;
+
+ ENTER_FUNCTION
+
+ ifmr->ifm_status = IFM_AVALID;
+ ifmr->ifm_active = IFM_ETHER;
+
+ status = xge_hal_mgmt_reg_read(hldev, 0,
+ xge_offsetof(xge_hal_pci_bar0_t, adapter_status), &regvalue);
+ if(status != XGE_HAL_OK) {
+ xge_trace(XGE_ERR, "Getting adapter status failed");
+ return;
+ }
+
+ if((regvalue & (XGE_HAL_ADAPTER_STATUS_RMAC_REMOTE_FAULT |
+ XGE_HAL_ADAPTER_STATUS_RMAC_LOCAL_FAULT)) == 0) {
+ ifmr->ifm_status |= IFM_ACTIVE;
+ ifmr->ifm_active |= IFM_10G_SR | IFM_FDX;
+ if_link_state_change(ifnetp, LINK_STATE_UP);
+ }
+ else {
+ if_link_state_change(ifnetp, LINK_STATE_DOWN);
+ }
+
+ LEAVE_FUNCTION
+}
+
+/******************************************
+ * Function: xge_ioctl
+ * Parameters: Pointer to ifnet structure,
+ * command -> indicates requests,
+ * data -> passed values (if any)
+ * Return:
+ * Description: IOCTL entry point. Called
+ * when the user wants to
+ * configure the interface
+ ******************************************/
+int
+xge_ioctl(struct ifnet *ifnetp, unsigned long command, caddr_t data)
+{
+ struct ifmedia *ifmediap;
+ xge_hal_stats_hw_info_t *hw_stats;
+ xge_hal_pci_config_t *pci_conf;
+ xge_hal_device_config_t *device_conf;
+ xge_hal_stats_sw_err_t *tcode;
+ xge_hal_stats_device_info_t *intr;
+ bar0reg_t *reg;
+ xge_hal_status_e status_code;
+ xge_hal_device_t *hldev;
+ void *regInfo;
+ u64 value;
+ u64 offset;
+ char *pAccess;
+ char *version;
+ int retValue = 0, index = 0, buffer_mode = 0;
+ struct ifreq *ifreqp = (struct ifreq *) data;
+ xgelldev_t *lldev = ifnetp->if_softc;
+
+ ifmediap = &lldev->xge_media;
+ hldev = lldev->devh;
+
+ if(lldev->in_detach) {
+ return retValue;
+ }
+
+ switch(command) {
+ /* Set/Get ifnet address */
+ case SIOCSIFADDR:
+ case SIOCGIFADDR:
+ ether_ioctl(ifnetp, command, data);
+ break;
+
+ /* Set ifnet MTU */
+ case SIOCSIFMTU:
+ retValue = changeMtu(lldev, ifreqp->ifr_mtu);
+ break;
+
+ /* Set ifnet flags */
+ case SIOCSIFFLAGS:
+ mtx_lock(&lldev->xge_lock);
+ if(ifnetp->if_flags & IFF_UP) {
+ /* Link status is UP */
+ if(!(ifnetp->if_drv_flags & IFF_DRV_RUNNING)) {
+ xge_init_locked(lldev);
+ }
+ xge_disable_promisc(lldev);
+ xge_enable_promisc(lldev);
+ }
+ else {
+ /* Link status is DOWN */
+ /* If device is in running, make it down */
+ if(ifnetp->if_drv_flags & IFF_DRV_RUNNING) {
+ xge_stop(lldev);
+ }
+ }
+ mtx_unlock(&lldev->xge_lock);
+ break;
+
+ /* Add/delete multicast address */
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ if(ifnetp->if_drv_flags & IFF_DRV_RUNNING) {
+ xge_setmulti(lldev);
+ }
+ break;
+
+ /* Set/Get net media */
+ case SIOCSIFMEDIA:
+ case SIOCGIFMEDIA:
+ retValue = ifmedia_ioctl(ifnetp, ifreqp, ifmediap, command);
+ break;
+
+ /* Set capabilities */
+ case SIOCSIFCAP:
+ mtx_lock(&lldev->xge_lock);
+ int mask = 0;
+ mask = ifreqp->ifr_reqcap ^ ifnetp->if_capenable;
+#if defined(__FreeBSD_version) && (__FreeBSD_version >= 700026)
+ if(mask & IFCAP_TSO4) {
+ if(ifnetp->if_capenable & IFCAP_TSO4) {
+ ifnetp->if_capenable &= ~IFCAP_TSO4;
+ ifnetp->if_hwassist &= ~CSUM_TSO;
+ }
+
+ /*enable tso only if txcsum is enabled*/
+ if(ifnetp->if_capenable & IFCAP_TXCSUM) {
+ ifnetp->if_capenable |= IFCAP_TSO4;
+ ifnetp->if_hwassist |= CSUM_TSO;
+ }
+ }
+#endif
+ mtx_unlock(&lldev->xge_lock);
+ break;
+
+ /* Custom IOCTL 0 :
+ * Used to get Statistics & PCI configuration through application */
+ case SIOCGPRIVATE_0:
+ pAccess = (char*) ifreqp->ifr_data;
+ if(*pAccess == XGE_QUERY_STATS) {
+ mtx_lock(&lldev->xge_lock);
+ status_code = xge_hal_stats_hw(hldev, &hw_stats);
+ if(status_code != XGE_HAL_OK) {
+ xge_trace(XGE_ERR,
+ "Getting statistics failed (Status: %d)",
+ status_code);
+ mtx_unlock(&lldev->xge_lock);
+ retValue = EINVAL;
+ }
+ copyout(hw_stats, ifreqp->ifr_data,
+ sizeof(xge_hal_stats_hw_info_t));
+ mtx_unlock(&lldev->xge_lock);
+ }
+ else if(*pAccess == XGE_QUERY_PCICONF) {
+ pci_conf = xge_malloc(sizeof(xge_hal_pci_config_t));
+ if(pci_conf == NULL) {
+ return(ENOMEM);
+ }
+ mtx_lock(&lldev->xge_lock);
+ status_code = xge_hal_mgmt_pci_config(hldev, pci_conf,
+ sizeof(xge_hal_pci_config_t));
+ if(status_code != XGE_HAL_OK) {
+ xge_trace(XGE_ERR,
+ "Getting PCIconfiguration failed (Status: %d)",
+ status_code);
+ mtx_unlock(&lldev->xge_lock);
+ retValue = EINVAL;
+ }
+ copyout(pci_conf, ifreqp->ifr_data,
+ sizeof(xge_hal_pci_config_t));
+ mtx_unlock(&lldev->xge_lock);
+ free(pci_conf, M_DEVBUF);
+ }
+ else if(*pAccess ==XGE_QUERY_INTRSTATS) {
+ intr = xge_malloc(sizeof(xge_hal_stats_device_info_t));
+ if(intr == NULL) {
+ return(ENOMEM);
+ }
+ mtx_lock(&lldev->xge_lock);
+ status_code =xge_hal_mgmt_device_stats(hldev, intr,
+ sizeof(xge_hal_stats_device_info_t));
+ if(status_code != XGE_HAL_OK) {
+ xge_trace(XGE_ERR,
+ "Getting intr statistics failed (Status: %d)",
+ status_code);
+ mtx_unlock(&lldev->xge_lock);
+ retValue = EINVAL;
+ }
+ copyout(intr, ifreqp->ifr_data,
+ sizeof(xge_hal_stats_device_info_t));
+ mtx_unlock(&lldev->xge_lock);
+ free(intr, M_DEVBUF);
+ }
+ else if(*pAccess == XGE_QUERY_TCODE) {
+ tcode = xge_malloc(sizeof(xge_hal_stats_sw_err_t));
+ if(tcode == NULL) {
+ return(ENOMEM);
+ }
+ mtx_lock(&lldev->xge_lock);
+ status_code =xge_hal_mgmt_sw_stats(hldev, tcode,
+ sizeof(xge_hal_stats_sw_err_t));
+ if(status_code != XGE_HAL_OK) {
+ xge_trace(XGE_ERR,
+ "Getting tcode statistics failed (Status: %d)",
+ status_code);
+ mtx_unlock(&lldev->xge_lock);
+ retValue = EINVAL;
+ }
+ copyout(tcode, ifreqp->ifr_data,
+ sizeof(xge_hal_stats_sw_err_t));
+ mtx_unlock(&lldev->xge_lock);
+ free(tcode, M_DEVBUF);
+ }
+ else if(*pAccess ==XGE_READ_VERSION) {
+ version = xge_malloc(BUFFER_SIZE);
+ if(version == NULL) {
+ return(ENOMEM);
+ }
+ mtx_lock(&lldev->xge_lock);
+ strcpy(version,DRIVER_VERSION);
+ copyout(version, ifreqp->ifr_data, BUFFER_SIZE);
+ mtx_unlock(&lldev->xge_lock);
+ free(version, M_DEVBUF);
+ }
+ else if(*pAccess == XGE_QUERY_DEVCONF) {
+ device_conf = xge_malloc(sizeof(xge_hal_device_config_t));
+ if(device_conf == NULL) {
+ return(ENOMEM);
+ }
+ mtx_lock(&lldev->xge_lock);
+ status_code = xge_hal_mgmt_device_config(hldev, device_conf,
+ sizeof(xge_hal_device_config_t));
+ if(status_code != XGE_HAL_OK) {
+ xge_trace(XGE_ERR,
+ "Getting devconfig failed (Status: %d)",
+ status_code);
+ mtx_unlock(&lldev->xge_lock);
+ retValue = EINVAL;
+ }
+ if(copyout(device_conf, ifreqp->ifr_data,
+ sizeof(xge_hal_device_config_t)) != 0) {
+ xge_trace(XGE_ERR, "Device configuration copyout erro");
+ }
+ mtx_unlock(&lldev->xge_lock);
+ free(device_conf, M_DEVBUF);
+ }
+ else if(*pAccess == XGE_QUERY_BUFFER_MODE) {
+ buffer_mode = lldev->buffer_mode;
+ if(copyout(&buffer_mode, ifreqp->ifr_data,
+ sizeof(int)) != 0) {
+ xge_trace(XGE_ERR, "Error with copyout of buffermode");
+ retValue = EINVAL;
+ }
+ }
+ else if((*pAccess == XGE_SET_BUFFER_MODE_1) ||
+ (*pAccess == XGE_SET_BUFFER_MODE_2) ||
+ (*pAccess == XGE_SET_BUFFER_MODE_3) ||
+ (*pAccess == XGE_SET_BUFFER_MODE_5)) {
+ switch(*pAccess) {
+ case XGE_SET_BUFFER_MODE_1: *pAccess = 'Y'; break;
+ case XGE_SET_BUFFER_MODE_2:
+ case XGE_SET_BUFFER_MODE_3:
+ case XGE_SET_BUFFER_MODE_5: *pAccess = 'N'; break;
+ }
+ if(copyout(pAccess, ifreqp->ifr_data,
+ sizeof(pAccess)) != 0) {
+ xge_trace(XGE_ERR,
+ "Copyout of chgbufmode result failed");
+ }
+ }
+ else {
+ xge_trace(XGE_TRACE, "Nothing is matching");
+ }
+ break;
+
+ /*
+ * Custom IOCTL 1 :
+ * Used to get BAR0 register values through application program
+ */
+ case SIOCGPRIVATE_1:
+ reg = (bar0reg_t *) ifreqp->ifr_data;
+ if(strcmp(reg->option,"-r") == 0) {
+ offset = reg->offset;
+ value = 0x0000;
+ mtx_lock(&lldev->xge_lock);
+ status_code = xge_hal_mgmt_reg_read(hldev, 0, offset,
+ &value );
+ if(status_code == XGE_HAL_OK) {
+ reg->value = value;
+ }
+ else {
+ xge_trace(XGE_ERR, "Getting register value failed");
+ mtx_unlock(&lldev->xge_lock);
+ retValue = EINVAL;
+ break;
+ }
+ copyout(reg, ifreqp->ifr_data, sizeof(bar0reg_t));
+ mtx_unlock(&lldev->xge_lock);
+ }
+ else if(strcmp(reg->option,"-w") == 0) {
+ offset = reg->offset;
+ value = reg->value;
+ mtx_lock(&lldev->xge_lock);
+ status_code = xge_hal_mgmt_reg_write(hldev, 0, offset,
+ value );
+ if(status_code != XGE_HAL_OK) {
+ xge_trace(XGE_ERR, "Getting register value failed");
+ mtx_unlock(&lldev->xge_lock);
+ retValue = EINVAL;
+ break;
+ }
+ value = 0x0000;
+ status_code = xge_hal_mgmt_reg_read(hldev, 0, offset,
+ &value);
+ if(status_code != XGE_HAL_OK) {
+ xge_trace(XGE_ERR, "Getting register value failed");
+ mtx_unlock(&lldev->xge_lock);
+ retValue = EINVAL;
+ break;
+ }
+ if(reg->value != value) {
+ mtx_unlock(&lldev->xge_lock);
+ retValue = EINVAL;
+ break;
+ }
+ mtx_unlock(&lldev->xge_lock);
+ }
+ else
+ {
+ offset = 0x0000;
+ value = 0x0000;
+ regInfo = (void *)ifreqp->ifr_data;
+
+ mtx_lock(&lldev->xge_lock);
+ for(index = 0, offset = 0; offset <= XGE_OFFSET_OF_LAST_REG;
+ index++, offset += 0x0008) {
+ status_code = xge_hal_mgmt_reg_read(hldev, 0, offset,
+ &value);
+ if(status_code == XGE_HAL_OK) {
+ *( ( u64 *)( ( u64 * )regInfo + index ) ) = value;
+ }
+ else {
+ xge_trace(XGE_ERR, "Getting register value failed");
+ mtx_unlock(&lldev->xge_lock);
+ retValue = EINVAL;
+ break;
+ }
+ }
+
+ copyout(regInfo, ifreqp->ifr_data,
+ sizeof(xge_hal_pci_bar0_t));
+ mtx_unlock(&lldev->xge_lock);
+ }
+ break;
+
+ default:
+ retValue = EINVAL;
+ break;
+ }
+ return retValue;
+}
+
+/******************************************
+ * Function: xge_init
+ * Parameters: Pointer to per-device
+ * xgelldev_t structure as void*.
+ * Return: None
+ * Description: Init entry point.
+ ******************************************/
+void
+xge_init(void *plldev)
+{
+ ENTER_FUNCTION
+
+ xgelldev_t *lldev = (xgelldev_t *)plldev;
+
+ mtx_lock(&lldev->xge_lock);
+ xge_init_locked(lldev);
+ mtx_unlock(&lldev->xge_lock);
+
+ LEAVE_FUNCTION
+}
+
+void
+xge_init_locked(void *pdevin)
+{
+ ENTER_FUNCTION
+
+ xgelldev_t *lldev = (xgelldev_t *)pdevin;
+ struct ifnet *ifnetp = lldev->ifnetp;
+ device_t dev = lldev->device;
+
+ mtx_assert((&lldev->xge_lock), MA_OWNED);
+
+ /* If device is in running state, initializing is not required */
+ if(ifnetp->if_drv_flags & IFF_DRV_RUNNING) {
+ return;
+ }
+
+ /* Initializing timer */
+ callout_init(&lldev->timer, CALLOUT_MPSAFE);
+
+ xge_initialize(dev, XGE_HAL_CHANNEL_OC_NORMAL);
+
+ LEAVE_FUNCTION
+}
+
+/******************************************
+ * Function: xge_timer
+ * Parameters: Pointer to per-device
+ * xgelldev_t structure as void*.
+ * Return: None
+ * Description: Polls the changes.
+ ******************************************/
+void
+xge_timer(void *devp)
+{
+ xgelldev_t *lldev = (xgelldev_t *)devp;
+ xge_hal_device_t *hldev = lldev->devh;
+
+ /* Poll for changes */
+ xge_hal_device_poll(hldev);
+
+ /* Reset timer */
+ callout_reset(&lldev->timer, hz, xge_timer, lldev);
+
+ return;
+}
+
+/******************************************
+ * Function: xge_stop
+ * Parameters: Per adapter xgelldev_t
+ * structure pointer
+ * Return: None
+ * Description: Deactivates the interface
+ * (Called on "ifconfig down"
+ ******************************************/
+void
+xge_stop(xgelldev_t *lldev)
+{
+ struct ifnet *ifnetp = lldev->ifnetp;
+ device_t dev = lldev->device;
+
+ ENTER_FUNCTION
+
+ mtx_assert((&lldev->xge_lock), MA_OWNED);
+
+ /* If device is not in "Running" state, return */
+ if (!(ifnetp->if_drv_flags & IFF_DRV_RUNNING)) {
+ goto xfstop_out;
+ }
+
+ xge_terminate(dev, XGE_HAL_CHANNEL_OC_NORMAL);
+
+xfstop_out:
+ LEAVE_FUNCTION
+ return;
+}
+
+/*
+ * xge_intr_filter
+ *
+ * ISR filter function
+ * @handle softc/lldev per device structure
+ */
+int
+xge_intr_filter(void *handle)
+{
+ xgelldev_t *lldev = NULL;
+ xge_hal_device_t *hldev = NULL;
+ xge_hal_pci_bar0_t *bar0 = NULL;
+ device_t dev = NULL;
+ u16 retValue = FILTER_STRAY;
+ u64 val64 = 0;
+
+ lldev = (xgelldev_t *)handle;
+ hldev = lldev->devh;
+ dev = lldev->device;
+ bar0 = (xge_hal_pci_bar0_t *)hldev->bar0;
+
+ val64 = xge_os_pio_mem_read64(lldev->pdev, hldev->regh0,
+ &bar0->general_int_status);
+ retValue = (!val64) ? FILTER_STRAY : FILTER_SCHEDULE_THREAD;
+
+ return retValue;
+}
+
+/******************************************
+ * xge_intr
+ * Parameters: Per adapter xgelldev_t
+ * structure pointer
+ * Return: None
+ * Description: Interrupt service routine
+ ******************************************/
+void
+xge_intr(void *plldev)
+{
+ xge_hal_status_e status;
+ xgelldev_t *lldev = (xgelldev_t *)plldev;
+ xge_hal_device_t *hldev = (xge_hal_device_t *)lldev->devh;
+ struct ifnet *ifnetp = lldev->ifnetp;
+
+ mtx_lock(&lldev->xge_lock);
+ if(ifnetp->if_drv_flags & IFF_DRV_RUNNING) {
+ status = xge_hal_device_handle_irq(hldev);
+
+ if(!(IFQ_DRV_IS_EMPTY(&ifnetp->if_snd))) {
+ xge_send_locked(ifnetp);
+ }
+ }
+ mtx_unlock(&lldev->xge_lock);
+ return;
+}
+
+/********************************************
+ * Function : xgell_rx_open
+ * Parameters: Queue index, channel
+ * open/close/reopen flag
+ * Return: 0 or ENODEV
+ * Description: Initialize and open all Rx
+ * channels.
+ ******************************************/
+int
+xgell_rx_open(int qid, xgelldev_t *lldev, xge_hal_channel_reopen_e rflag)
+{
+ u64 adapter_status = 0x0;
+ int retValue = 0;
+ xge_hal_status_e status_code;
+
+ ENTER_FUNCTION
+
+ xge_hal_channel_attr_t attr = {
+ .post_qid = qid,
+ .compl_qid = 0,
+ .callback = xgell_rx_compl,
+ .per_dtr_space = sizeof(xgell_rx_priv_t),
+ .flags = 0,
+ .type = XGE_HAL_CHANNEL_TYPE_RING,
+ .userdata = lldev,
+ .dtr_init = xgell_rx_initial_replenish,
+ .dtr_term = xgell_rx_term
+ };
+
+ /* If device is not ready, return */
+ if(xge_hal_device_status(lldev->devh, &adapter_status)) {
+ xge_trace(XGE_ERR, "Device is not ready. Adapter status: 0x%llx",
+ (unsigned long long) adapter_status);
+ retValue = -ENODEV;
+ goto rxopen_out;
+ }
+
+ /* Open ring channel */
+ status_code = xge_hal_channel_open(lldev->devh, &attr,
+ &lldev->ring_channel[qid], rflag);
+ if(status_code != XGE_HAL_OK) {
+ xge_trace(XGE_ERR, "Can not open Rx RING channel, Status: %d\n",
+ status_code);
+ retValue = -ENODEV;
+ goto rxopen_out;
+ }
+
+rxopen_out:
+ LEAVE_FUNCTION
+
+ return retValue;
+}
+
+/******************************************
+ * Function: xgell_tx_open
+ * Parameters: Channel
+ * open/close/reopen flag
+ * Return: 0 or ENODEV
+ * Description: Initialize and open all Tx
+ * channels.
+ ******************************************/
+int
+xgell_tx_open(xgelldev_t *lldev, xge_hal_channel_reopen_e tflag)
+{
+ xge_hal_status_e status_code;
+ u64 adapter_status = 0x0;
+ int retValue = 0;
+
+ ENTER_FUNCTION
+
+ xge_hal_channel_attr_t attr = {
+ .post_qid = 0,
+ .compl_qid = 0,
+ .callback = xgell_tx_compl,
+ .per_dtr_space = sizeof(xgell_tx_priv_t),
+ .flags = 0,
+ .type = XGE_HAL_CHANNEL_TYPE_FIFO,
+ .userdata = lldev,
+ .dtr_init = xgell_tx_initial_replenish,
+ .dtr_term = xgell_tx_term
+ };
+
+ /* If device is not ready, return */
+ if(xge_hal_device_status(lldev->devh, &adapter_status)) {
+ xge_trace(XGE_ERR, "Device is not ready. Adapter status: 0x%llx\n",
+ (unsigned long long) adapter_status);
+ retValue = -ENODEV;
+ goto txopen_out;
+ }
+
+ /* Open FIFO channel */
+ status_code = xge_hal_channel_open(lldev->devh, &attr,
+ &lldev->fifo_channel_0, tflag);
+ if(status_code != XGE_HAL_OK) {
+ xge_trace(XGE_ERR, "Can not open Tx FIFO channel, Status: %d\n",
+ status_code);
+ retValue = -ENODEV;
+ goto txopen_out;
+ }
+
+txopen_out:
+ LEAVE_FUNCTION
+
+ return retValue;
+}
+
+/******************************************
+ * Function: xgell_channel_open
+ * Parameters: Per adapter xgelldev_t
+ * structure pointer
+ * Return: None
+ * Description: Opens both Rx and Tx channels.
+ ******************************************/
+int
+xgell_channel_open(xgelldev_t *lldev, xge_hal_channel_reopen_e option)
+{
+ int status = XGE_HAL_OK;
+ int index = 0;
+ int index2 = 0;
+
+ ENTER_FUNCTION
+
+ /* Open ring (Rx) channel */
+ for(index = 0; index < XGE_RING_COUNT; index++) {
+ if((status = xgell_rx_open(index, lldev, option))) {
+ xge_trace(XGE_ERR, "Opening Rx channel failed (Status: %d)\n",
+ status);
+ for(index2 = 0; index2 < index; index2++) {
+ xge_hal_channel_close(lldev->ring_channel[index2], option);
+ }
+ return status;
+ }
+ }
+#ifdef XGE_FEATURE_LRO
+ status = xge_hal_lro_init(1, lldev->devh);
+ if (status != XGE_HAL_OK) {
+ xge_trace(XGE_ERR, "cannot init Rx LRO got status code %d", status);
+ return -ENODEV;
+ }
+#endif
+
+ /* Open FIFO (Tx) channel */
+ if((status = xgell_tx_open(lldev, option))) {
+ xge_trace(XGE_ERR, "Opening Tx channel failed (Status: %d)\n",
+ status);
+ for(index = 0; index < XGE_RING_COUNT; index++) {
+ xge_hal_channel_close(lldev->ring_channel[index], option);
+ }
+ }
+
+ LEAVE_FUNCTION
+ return status;
+}
+
+/******************************************
+ * Function: xgell_channel_close
+ * Parameters: Per adapter xgelldev_t
+ * structure pointer
+ * Return: 0 for success, non-zero for
+ * failure
+ * Description: Closes both Tx and Rx channels
+ ******************************************/
+int
+xgell_channel_close(xgelldev_t *lldev, xge_hal_channel_reopen_e option)
+{
+ int index;
+
+ ENTER_FUNCTION
+
+ DELAY(1000 * 1000);
+
+ /* Close FIFO (Tx) channel */
+ xge_hal_channel_close(lldev->fifo_channel_0, option);
+
+ /* Close Ring (Rx) channel */
+ for(index = 0; index < XGE_RING_COUNT; index++) {
+ xge_hal_channel_close(lldev->ring_channel[index], option);
+ }
+
+ LEAVE_FUNCTION
+
+ return 0;
+}
+
+
+/******************************************
+ * Function: dmamap_cb
+ * Parameters: Parameter passed from dmamap
+ * function, Segment, Number of
+ * segments, error (if any)
+ * Return: None
+ * Description: Callback function used for
+ * DMA mapping
+ ******************************************/
+void
+dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
+{
+ if(!error) {
+ *(bus_addr_t *) arg = segs->ds_addr;
+ }
+}
+
+/******************************************
+ * Function: xgell_reset
+ * Parameters: Per adapter xgelldev_t
+ * structure pointer
+ * Return: HAL status code/EPERM
+ * Description: Resets the device
+ ******************************************/
+void
+xgell_reset(xgelldev_t *lldev)
+{
+ device_t dev = lldev->device;
+
+ ENTER_FUNCTION
+
+ xge_trace(XGE_TRACE, "Reseting the chip");
+
+ mtx_lock(&lldev->xge_lock);
+
+ /* If the device is not initialized, return */
+ if(!lldev->initialized) {
+ goto xreset_out;
+ }
+
+ xge_terminate(dev, XGE_HAL_CHANNEL_OC_NORMAL);
+
+ xge_initialize(dev, XGE_HAL_CHANNEL_OC_NORMAL);
+
+xreset_out:
+ LEAVE_FUNCTION
+ mtx_unlock(&lldev->xge_lock);
+
+ return;
+}
+
+/******************************************
+ * Function: xge_setmulti
+ * Parameters: Per adapter xgelldev_t
+ * structure pointer
+ * Return: None
+ * Description: Set an address as a multicast
+ * address
+ ******************************************/
+void
+xge_setmulti(xgelldev_t *lldev)
+{
+ ENTER_FUNCTION
+ struct ifmultiaddr *ifma;
+ u8 *lladdr;
+ xge_hal_device_t *hldev = (xge_hal_device_t *)lldev->devh;
+ struct ifnet *ifnetp = lldev->ifnetp;
+ int index = 0;
+ int offset = 1;
+ int table_size = 47;
+ xge_hal_status_e status = XGE_HAL_OK;
+ u8 initial_addr[]= {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+ if((ifnetp->if_flags & IFF_MULTICAST) && (!lldev->all_multicast)) {
+ status = xge_hal_device_mcast_enable(hldev);
+ lldev->all_multicast = 1;
+ }
+ else if((ifnetp->if_flags & IFF_MULTICAST) && (lldev->all_multicast)) {
+ status = xge_hal_device_mcast_disable(hldev);
+ lldev->all_multicast = 0;
+ }
+
+ if(status != XGE_HAL_OK) {
+ printf("Failed to %s multicast (status: %d)\n",
+ (ifnetp->if_flags & IFF_ALLMULTI ? "enable" : "disable"),
+ status);
+ }
+
+ /* Updating address list */
+ IF_ADDR_LOCK(ifnetp);
+ index = 0;
+ TAILQ_FOREACH(ifma, &ifnetp->if_multiaddrs, ifma_link) {
+ if(ifma->ifma_addr->sa_family != AF_LINK) {
+ continue;
+ }
+ lladdr = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
+ index += 1;
+ }
+ IF_ADDR_UNLOCK(ifnetp);
+
+ if((!lldev->all_multicast) && (index)) {
+ lldev->macaddr_count = (index + 1);
+ if(lldev->macaddr_count > table_size) {
+ return;
+ }
+
+ /* Clear old addresses */
+ for(index = 0; index < 48; index++) {
+ xge_hal_device_macaddr_set(hldev, (offset + index),
+ initial_addr);
+ }
+ }
+
+ /* Add new addresses */
+ IF_ADDR_LOCK(ifnetp);
+ index = 0;
+ TAILQ_FOREACH(ifma, &ifnetp->if_multiaddrs, ifma_link) {
+ if(ifma->ifma_addr->sa_family != AF_LINK) {
+ continue;
+ }
+ lladdr = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
+ xge_hal_device_macaddr_set(hldev, (offset + index), lladdr);
+ index += 1;
+ }
+ IF_ADDR_UNLOCK(ifnetp);
+
+ LEAVE_FUNCTION
+}
+
+/******************************************
+ * Function: xge_enable_promisc
+ * Parameters: Adapter structure
+ * Return: None
+ * Description: Enables promiscuous mode
+ ******************************************/
+void
+xge_enable_promisc(xgelldev_t *lldev)
+{
+ struct ifnet *ifnetp = lldev->ifnetp;
+ xge_hal_device_t *hldev = lldev->devh;
+ xge_hal_pci_bar0_t *bar0 = NULL;
+ u64 val64 = 0;
+
+ ENTER_FUNCTION
+
+ bar0 = (xge_hal_pci_bar0_t *) hldev->bar0;
+
+ if(ifnetp->if_flags & IFF_PROMISC) {
+ xge_hal_device_promisc_enable(lldev->devh);
+
+ /*
+ * When operating in promiscuous mode, don't strip the VLAN tag
+ */
+ val64 = xge_os_pio_mem_read64(lldev->pdev, hldev->regh0,
+ &bar0->rx_pa_cfg);
+ val64 &= ~XGE_HAL_RX_PA_CFG_STRIP_VLAN_TAG_MODE(1);
+ val64 |= XGE_HAL_RX_PA_CFG_STRIP_VLAN_TAG_MODE(0);
+ xge_os_pio_mem_write64(lldev->pdev, hldev->regh0, val64,
+ &bar0->rx_pa_cfg);
+
+ xge_trace(XGE_TRACE, "Promiscuous mode ON");
+ }
+
+ LEAVE_FUNCTION
+}
+
+/******************************************
+ * Function: xge_disable_promisc
+ * Parameters: Adapter structure
+ * Return: None
+ * Description: Disables promiscuous mode
+ ******************************************/
+void
+xge_disable_promisc(xgelldev_t *lldev)
+{
+ xge_hal_device_t *hldev = lldev->devh;
+ xge_hal_pci_bar0_t *bar0 = NULL;
+ u64 val64 = 0;
+
+ ENTER_FUNCTION
+
+ bar0 = (xge_hal_pci_bar0_t *) hldev->bar0;
+
+ xge_hal_device_promisc_disable(lldev->devh);
+
+ /*
+ * Strip VLAN tag when operating in non-promiscuous mode
+ */
+ val64 = xge_os_pio_mem_read64(lldev->pdev, hldev->regh0,
+ &bar0->rx_pa_cfg);
+ val64 &= ~XGE_HAL_RX_PA_CFG_STRIP_VLAN_TAG_MODE(1);
+ val64 |= XGE_HAL_RX_PA_CFG_STRIP_VLAN_TAG_MODE(1);
+ xge_os_pio_mem_write64(lldev->pdev, hldev->regh0, val64,
+ &bar0->rx_pa_cfg);
+
+ xge_trace(XGE_TRACE, "Promiscuous mode OFF");
+
+ LEAVE_FUNCTION
+}
+
+/******************************************
+ * Function: changeMtu
+ * Parameters: Pointer to per-device
+ * xgelldev_t structure, New
+ * MTU size.
+ * Return: None
+ * Description: Changes MTU size to requested
+ ******************************************/
+int
+changeMtu(xgelldev_t *lldev, int NewMtu)
+{
+ struct ifnet *ifnetp = lldev->ifnetp;
+ xge_hal_device_t *hldev = lldev->devh;
+ int retValue = 0;
+
+ ENTER_FUNCTION
+
+ do {
+ /* Check requested MTU size for boundary */
+ if(xge_hal_device_mtu_check(hldev, NewMtu) != XGE_HAL_OK) {
+ xge_trace(XGE_ERR, "Invalid MTU");
+ retValue = EINVAL;
+ break;
+ }
+
+ if(lldev->initialized != 0) {
+ mtx_lock(&lldev->xge_lock);
+ if_down(ifnetp);
+ xge_stop(lldev);
+ ifnetp->if_mtu = NewMtu;
+ changeBufmode(lldev, NewMtu);
+ xge_init_locked((void *)lldev);
+ if_up(ifnetp);
+ mtx_unlock(&lldev->xge_lock);
+ }
+ else {
+ ifnetp->if_mtu = NewMtu;
+ changeBufmode(lldev, NewMtu);
+ }
+ } while(FALSE);
+
+ LEAVE_FUNCTION
+ return retValue;
+}
+
+/******************************************
+ * Function: changeBufmode
+ * Parameters: Pointer to per-device
+ * xgelldev_t structure, New
+ * MTU size.
+ * Return: None
+ * Description: Updates RingConfiguration structure
+ * depending the NewMtu size.
+ ******************************************/
+int
+changeBufmode (xgelldev_t *lldev, int NewMtu)
+{
+ xge_hal_ring_config_t * pRingConfig;
+ xge_hal_device_t *hldev = lldev->devh;
+ device_t dev = lldev->device;
+ int buffer_length = 0, buffer_index = 0, index;
+
+ pRingConfig = &(hldev->config.ring);
+ xge_os_memzero(lldev->rxd_mbuf_len, sizeof(lldev->rxd_mbuf_len));
+
+ if((NewMtu + XGE_HAL_MAC_HEADER_MAX_SIZE) <= MJUMPAGESIZE) {
+#if defined(XGE_FEATURE_BUFFER_MODE_3)
+ xge_os_printf("%s: 3 Buffer Mode Enabled",
+ device_get_nameunit(dev));
+ for(index = 0; index < XGE_RING_COUNT; index++) {
+ pRingConfig->queue[index].buffer_mode =
+ XGE_HAL_RING_QUEUE_BUFFER_MODE_3;
+ }
+ pRingConfig->scatter_mode = XGE_HAL_RING_QUEUE_SCATTER_MODE_A;
+ lldev->buffer_mode = XGE_HAL_RING_QUEUE_BUFFER_MODE_3;
+ lldev->rxd_mbuf_len[0] = XGE_HAL_MAC_HEADER_MAX_SIZE;
+ lldev->rxd_mbuf_len[1] = XGE_HAL_TCPIP_HEADER_MAX_SIZE;
+ lldev->rxd_mbuf_len[2] = NewMtu;
+ lldev->rxd_mbuf_cnt = 3;
+#else
+#if defined(XGE_FEATURE_BUFFER_MODE_2)
+ xge_os_printf("%s: 2 Buffer Mode Enabled",
+ device_get_nameunit(dev));
+ for(index = 0; index < XGE_RING_COUNT; index++) {
+ pRingConfig->queue[index].buffer_mode =
+ XGE_HAL_RING_QUEUE_BUFFER_MODE_3;
+ }
+ pRingConfig->scatter_mode = XGE_HAL_RING_QUEUE_SCATTER_MODE_B;
+ lldev->buffer_mode = XGE_HAL_RING_QUEUE_BUFFER_MODE_2;
+ lldev->rxd_mbuf_len[0] = XGE_HAL_MAC_HEADER_MAX_SIZE;
+ lldev->rxd_mbuf_len[1] = NewMtu;
+ lldev->rxd_mbuf_cnt = 2;
+#else
+ for(index = 0; index < XGE_RING_COUNT; index++) {
+ pRingConfig->queue[index].buffer_mode =
+ XGE_HAL_RING_QUEUE_BUFFER_MODE_1;
+ }
+ pRingConfig->scatter_mode = XGE_HAL_RING_QUEUE_SCATTER_MODE_A;
+ lldev->buffer_mode = XGE_HAL_RING_QUEUE_BUFFER_MODE_1;
+ lldev->rxd_mbuf_len[0] = NewMtu;
+ lldev->rxd_mbuf_cnt = 1;
+#endif
+#endif
+ }
+ else {
+#if defined(XGE_FEATURE_BUFFER_MODE_3) || defined (XGE_FEATURE_BUFFER_MODE_2)
+ xge_os_printf("2 or 3 Buffer mode is not supported for given MTU");
+ xge_os_printf("So changing buffer mode to 5 buffer mode\n");
+#endif
+ xge_os_printf("%s: 5 Buffer Mode Enabled",
+ device_get_nameunit(dev));
+ for(index = 0; index < XGE_RING_COUNT; index++) {
+ pRingConfig->queue[index].buffer_mode =
+ XGE_HAL_RING_QUEUE_BUFFER_MODE_5;
+ }
+ lldev->buffer_mode = XGE_HAL_RING_QUEUE_BUFFER_MODE_5;
+ buffer_length = NewMtu;
+ buffer_index = 2;
+ lldev->rxd_mbuf_len[0] = XGE_HAL_MAC_HEADER_MAX_SIZE;
+ lldev->rxd_mbuf_len[1] = XGE_HAL_TCPIP_HEADER_MAX_SIZE;
+
+ while(buffer_length > MJUMPAGESIZE) {
+ buffer_length -= MJUMPAGESIZE;
+ lldev->rxd_mbuf_len[buffer_index] = MJUMPAGESIZE;
+ buffer_index++;
+ }
+
+ BUFALIGN(buffer_length);
+
+ lldev->rxd_mbuf_len[buffer_index] = buffer_length;
+ lldev->rxd_mbuf_cnt = buffer_index+1;
+ }
+
+ return XGE_HAL_OK;
+}
+
+/*************************************************************
+ * xge_initialize
+ *
+ * @dev: Device structure
+ * @option: Normal/Reset option for channels
+ *
+ * Called by both init and reset functions to enable device, interrupts, and to
+ * open channels.
+ *
+ **************************************************************/
+void xge_initialize(device_t dev, xge_hal_channel_reopen_e option)
+{
+ ENTER_FUNCTION
+
+ struct ifaddr *ifaddrp;
+ struct sockaddr_dl *sockaddrp;
+ unsigned char *macaddr;
+ xgelldev_t *lldev = (xgelldev_t *) device_get_softc(dev);
+ xge_hal_device_t *hldev = lldev->devh;
+ struct ifnet *ifnetp = lldev->ifnetp;
+ int status = XGE_HAL_OK;
+
+ xge_trace(XGE_TRACE, "Set MTU size");
+ status = xge_hal_device_mtu_set(hldev, ifnetp->if_mtu);
+ if(status != XGE_HAL_OK) {
+ xge_trace(XGE_ERR, "Setting HAL device MTU failed (Status: %d)",
+ status);
+ goto init_sub_out;
+ }
+
+
+ /* Enable HAL device */
+ xge_hal_device_enable(hldev);
+
+ /* Get MAC address and update in HAL */
+ ifaddrp = ifaddr_byindex(ifnetp->if_index);
+ sockaddrp = (struct sockaddr_dl *)ifaddrp->ifa_addr;
+ sockaddrp->sdl_type = IFT_ETHER;
+ sockaddrp->sdl_alen = ifnetp->if_addrlen;
+ macaddr = LLADDR(sockaddrp);
+ xge_trace(XGE_TRACE,
+ "Setting MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ *macaddr, *(macaddr + 1), *(macaddr + 2), *(macaddr + 3),
+ *(macaddr + 4), *(macaddr + 5));
+ status = xge_hal_device_macaddr_set(hldev, 0, macaddr);
+ if(status != XGE_HAL_OK) {
+ xge_trace(XGE_ERR,
+ "Setting MAC address failed (Status: %d)\n", status);
+ }
+
+ /* Opening channels */
+ mtx_unlock(&lldev->xge_lock);
+ status = xgell_channel_open(lldev, option);
+ mtx_lock(&lldev->xge_lock);
+ if(status != 0) {
+ goto init_sub_out;
+ }
+
+ /* Set appropriate flags */
+ ifnetp->if_drv_flags |= IFF_DRV_RUNNING;
+ ifnetp->if_flags &= ~IFF_DRV_OACTIVE;
+
+ /* Checksum capability */
+ ifnetp->if_hwassist = (ifnetp->if_capenable & IFCAP_TXCSUM) ?
+ (CSUM_TCP | CSUM_UDP) : 0;
+
+#ifdef XGE_FEATURE_TSO
+ if(ifnetp->if_capenable & IFCAP_TSO4)
+ ifnetp->if_hwassist |= CSUM_TSO;
+#endif
+
+ /* Enable interrupts */
+ xge_hal_device_intr_enable(hldev);
+
+ callout_reset(&lldev->timer, 10*hz, xge_timer, lldev);
+
+ /* Disable promiscuous mode */
+ xge_trace(XGE_TRACE, "If opted, enable promiscuous mode");
+ xge_enable_promisc(lldev);
+
+ /* Device is initialized */
+ lldev->initialized = 1;
+ xge_os_mdelay(1000);
+
+init_sub_out:
+ LEAVE_FUNCTION
+ return;
+}
+
+/*******************************************************
+ * xge_terminate
+ *
+ * @dev: Device structure
+ * @option: Normal/Reset option for channels
+ *
+ * Called by both stop and reset functions to disable device, interrupts, and to
+ * close channels.
+ ******************************************************/
+void xge_terminate(device_t dev, xge_hal_channel_reopen_e option)
+{
+ ENTER_FUNCTION
+
+ xgelldev_t *lldev = (xgelldev_t *)device_get_softc(dev);
+ xge_hal_device_t *hldev = lldev->devh;
+ struct ifnet *ifnetp = lldev->ifnetp;
+
+ /* Set appropriate flags */
+ ifnetp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
+
+ /* Stop timer */
+ callout_stop(&lldev->timer);
+
+ /* Disable interrupts */
+ xge_hal_device_intr_disable(hldev);
+
+ mtx_unlock(&lldev->xge_lock);
+ xge_queue_flush(xge_hal_device_queue(lldev->devh));
+ mtx_lock(&lldev->xge_lock);
+
+ /* Disable HAL device */
+ if(xge_hal_device_disable(hldev) != XGE_HAL_OK) {
+ xge_trace(XGE_ERR, "Disabling HAL device failed");
+ }
+
+ /* Close Tx and Rx channels */
+ xgell_channel_close(lldev, option);
+
+ /* Reset HAL device */
+ xge_hal_device_reset(hldev);
+
+ xge_os_mdelay(1000);
+ lldev->initialized = 0;
+
+ if_link_state_change(ifnetp, LINK_STATE_DOWN);
+
+ LEAVE_FUNCTION
+}
+
+/******************************************
+ * Function: xgell_set_mbuf_cflags
+ * Parameters: mbuf structure pointer
+ * Return: None
+ * Description: This fuction will set the csum_flag of the mbuf
+ ******************************************/
+void xgell_set_mbuf_cflags(mbuf_t pkt)
+{
+ pkt->m_pkthdr.csum_flags = CSUM_IP_CHECKED;
+ pkt->m_pkthdr.csum_flags |= CSUM_IP_VALID;
+ pkt->m_pkthdr.csum_flags |= (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
+ pkt->m_pkthdr.csum_data = htons(0xffff);
+}
+
+#ifdef XGE_FEATURE_LRO
+/******************************************
+ * Function: xgell_lro_flush_sessions
+ * Parameters: Per adapter xgelldev_t
+ * Return: None
+ * Description: This function will flush the LRO session and send the
+ * accumulated LRO packet to Upper layer.
+ ******************************************/
+void xgell_lro_flush_sessions(xgelldev_t *lldev)
+{
+ lro_t *lro;
+ struct ifnet *ifnetp = lldev->ifnetp;
+ xge_hal_device_t *hldev = (xge_hal_device_t *)lldev->devh;
+
+ while (NULL != (lro = xge_hal_lro_get_next_session(hldev))) {
+ xgell_set_mbuf_cflags(lro->os_buf);
+
+ /* Send it up */
+ mtx_unlock(&lldev->xge_lock);
+ (*ifnetp->if_input)(ifnetp, lro->os_buf);
+ mtx_lock(&lldev->xge_lock);
+
+ xge_hal_lro_close_session(lro);
+ }
+}
+
+/******************************************
+ * Function: xgell_accumulate_large_rx
+ * Parameters: Descriptor info structure, current mbuf structure,
+ * packet length, Per adapter structure, Rx Desc private structure
+ * Return: None
+ * Description: This function will accumulate packets to form the LRO
+ * packets based on various condition.
+ ******************************************/
+void xgell_accumulate_large_rx(xge_hal_dtr_info_t *ext_info,mbuf_t pkt,
+ int pkt_length, xgelldev_t *lldev, xgell_rx_priv_t *rxd_priv)
+{
+ tcplro_t *tcp;
+ lro_t *lro, *lro_end3;
+ xge_hal_status_e status;
+ unsigned char * temp;
+ struct ifnet *ifnetp = lldev->ifnetp;
+
+ status = xge_hal_accumulate_large_rx(pkt->m_data, &tcp, &pkt_length,
+ &lro, ext_info, lldev->devh, &lro_end3);
+ pkt->m_next = NULL;
+ temp = (unsigned char *)tcp;
+
+ if(status == XGE_HAL_INF_LRO_BEGIN) {
+ pkt->m_flags |= M_PKTHDR;
+ pkt->m_pkthdr.rcvif = ifnetp;
+ lro->os_buf = lro->os_buf_end = pkt;
+ }
+ else if(status == XGE_HAL_INF_LRO_CONT) {
+ /*
+ * Current mbuf will be combine to form LRO frame,
+ * So mask the pkthdr of the flag variable for current mbuf
+ */
+ pkt->m_flags = pkt->m_flags & 0xFFFD; //Mask pkthdr
+ pkt->m_data = (u8 *)tcp;
+ pkt->m_len = pkt_length;
+
+ /*
+ * Combine the current mbuf to the LRO frame and update
+ * the LRO's pkthdr len accordingly
+ */
+ lro->os_buf_end->m_next = pkt;
+ lro->os_buf_end = pkt;
+ lro->os_buf->m_pkthdr.len += pkt_length;
+ }
+ else if(status == XGE_HAL_INF_LRO_END_2) {
+ lro->os_buf->m_flags |= M_EOR;
+
+ /* Update the Checksum flags of the LRO frames */
+ xgell_set_mbuf_cflags(lro->os_buf);
+
+ /* Post-Read sync */
+ bus_dmamap_sync(lldev->dma_tag_rx, rxd_priv->dmainfo[0].dma_map,
+ BUS_DMASYNC_POSTREAD);
+
+ /*
+ * Current packet can not be combined with LRO frame.
+ * Flush the previous LRO frames and send the current packet
+ * seperately
+ */
+ mtx_unlock(&lldev->xge_lock);
+ (*ifnetp->if_input)(ifnetp, lro->os_buf);
+ (*ifnetp->if_input)(ifnetp, pkt);
+ mtx_lock(&lldev->xge_lock);
+ xge_hal_lro_close_session(lro);
+ }
+ else if(status == XGE_HAL_INF_LRO_END_1) {
+ pkt->m_flags = pkt->m_flags & 0xFFFD;
+ pkt->m_data = (u8 *)tcp;
+ pkt->m_len = pkt_length;
+ lro->os_buf_end->m_next = pkt;
+ lro->os_buf->m_pkthdr.len += pkt_length;
+ xgell_set_mbuf_cflags(lro->os_buf);
+ lro->os_buf->m_flags |= M_EOR;
+
+ /* Post-Read sync */
+ bus_dmamap_sync(lldev->dma_tag_rx, rxd_priv->dmainfo[0].dma_map,
+ BUS_DMASYNC_POSTREAD);
+
+ /* Send it up */
+ mtx_unlock(&lldev->xge_lock);
+ (*ifnetp->if_input)(ifnetp, lro->os_buf);
+ mtx_lock(&lldev->xge_lock);
+
+ xge_hal_lro_close_session(lro);
+ }
+ else if(status == XGE_HAL_INF_LRO_END_3) {
+ pkt->m_flags |= M_PKTHDR;
+ pkt->m_len = pkt_length;
+ pkt->m_pkthdr.len = pkt_length;
+ lro_end3->os_buf = lro_end3->os_buf_end = pkt;
+ lro->os_buf->m_flags |= M_EOR;
+ xgell_set_mbuf_cflags(lro->os_buf);
+
+ /* Post-Read sync */
+ bus_dmamap_sync(lldev->dma_tag_rx, rxd_priv->dmainfo[0].dma_map,
+ BUS_DMASYNC_POSTREAD);
+
+ /* Send it up */
+ mtx_unlock(&lldev->xge_lock);
+ (*ifnetp->if_input)(ifnetp, lro->os_buf);
+ mtx_lock(&lldev->xge_lock);
+ xge_hal_lro_close_session(lro);
+ }
+ else if((status == XGE_HAL_INF_LRO_UNCAPABLE) ||
+ (status == XGE_HAL_INF_LRO_SESSIONS_XCDED)) {
+ pkt->m_flags |= M_PKTHDR;
+ pkt->m_len = pkt_length;
+ pkt->m_pkthdr.len = pkt_length;
+
+ /* Post-Read sync */
+ bus_dmamap_sync(lldev->dma_tag_rx, rxd_priv->dmainfo[0].dma_map,
+ BUS_DMASYNC_POSTREAD);
+
+ /* Send it up */
+ mtx_unlock(&lldev->xge_lock);
+ (*ifnetp->if_input)(ifnetp, pkt);
+ mtx_lock(&lldev->xge_lock);
+ }
+}
+#endif
+
+/******************************************
+ * Function: xgell_rx_compl
+ * Parameters: Channel handle, descriptor,
+ * transfer code, userdata
+ * (not used)
+ * Return: HAL status code
+ * Description: If the interrupt is because
+ * of a received frame or if
+ * the receive ring contains
+ * fresh as yet un-processed
+ * frames, this function is
+ * called.
+ ******************************************/
+xge_hal_status_e
+xgell_rx_compl(xge_hal_channel_h channelh, xge_hal_dtr_h dtr, u8 t_code,
+ void *userdata)
+{
+ xge_hal_dtr_info_t ext_info;
+ xge_hal_status_e status_code;
+ struct ifnet *ifnetp;
+ device_t dev;
+ int index;
+ mbuf_t mbuf_up = NULL;
+ xgell_rx_priv_t *rxd_priv = NULL, old_rxd_priv;
+ u16 vlan_tag;
+
+// ENTER_FUNCTION
+
+
+ /*get the user data portion*/
+ xgelldev_t *lldev = xge_hal_channel_userdata(channelh);
+ if(!lldev) {
+ xge_ctrace(XGE_TRACE, "xgeX: %s: Failed to get user data",
+ __FUNCTION__);
+ return XGE_HAL_FAIL;
+ }
+ dev = lldev->device;
+
+ mtx_assert((&lldev->xge_lock), MA_OWNED);
+
+ /* get the interface pointer */
+ ifnetp = lldev->ifnetp;
+
+ do {
+ if(!(ifnetp->if_drv_flags & IFF_DRV_RUNNING)) {
+ return XGE_HAL_FAIL;
+ }
+
+ if(t_code) {
+ xge_trace(XGE_TRACE, "Packet dropped because of %d", t_code);
+ xge_hal_device_handle_tcode(channelh, dtr, t_code);
+ xge_hal_ring_dtr_post(channelh,dtr);
+ continue;
+ }
+
+ /* Get the private data for this descriptor*/
+ rxd_priv = (xgell_rx_priv_t *) xge_hal_ring_dtr_private(channelh,
+ dtr);
+ if(!rxd_priv) {
+ xge_trace(XGE_ERR, "Failed to get descriptor private data");
+ return XGE_HAL_FAIL;
+ }
+
+ /* Taking backup of rxd_priv structure details of current packet */
+ xge_os_memcpy(&old_rxd_priv, rxd_priv, sizeof(xgell_rx_priv_t));
+
+ /* Prepare one buffer to send it to upper layer -- since the upper
+ * layer frees the buffer do not use rxd_priv->buffer
+ * Meanwhile prepare a new buffer, do mapping, use it in the
+ * current descriptor and post descriptor back to ring channel */
+ mbuf_up = rxd_priv->bufferArray[0];
+
+ /* Gets details of mbuf i.e., packet length */
+ xge_ring_dtr_get(mbuf_up, channelh, dtr, lldev, rxd_priv);
+
+ status_code =
+ (lldev->buffer_mode == XGE_HAL_RING_QUEUE_BUFFER_MODE_1) ?
+ xgell_get_buf(dtr, rxd_priv, lldev, 0) :
+ xgell_get_buf_3b_5b(dtr, rxd_priv, lldev);
+
+ if(status_code != XGE_HAL_OK) {
+ xge_trace(XGE_ERR, "No memory");
+
+ /*
+ * Do not deliver the received buffer to the stack. Instead,
+ * Re-post the descriptor with the same buffer
+ */
+
+ /* Get back previous rxd_priv structure before posting */
+ xge_os_memcpy(rxd_priv, &old_rxd_priv, sizeof(xgell_rx_priv_t));
+
+ xge_hal_ring_dtr_post(channelh, dtr);
+ continue;
+ }
+
+ /* Get the extended information */
+ xge_hal_ring_dtr_info_get(channelh, dtr, &ext_info);
+
+ if(lldev->buffer_mode == XGE_HAL_RING_QUEUE_BUFFER_MODE_1) {
+ /*
+ * As we have allocated a new mbuf for this descriptor, post
+ * this descriptor with new mbuf back to ring channel
+ */
+ vlan_tag = ext_info.vlan;
+ xge_hal_ring_dtr_post(channelh, dtr);
+ if ((!(ext_info.proto & XGE_HAL_FRAME_PROTO_IP_FRAGMENTED) &&
+ (ext_info.proto & XGE_HAL_FRAME_PROTO_TCP_OR_UDP) &&
+ (ext_info.l3_cksum == XGE_HAL_L3_CKSUM_OK) &&
+ (ext_info.l4_cksum == XGE_HAL_L4_CKSUM_OK))) {
+ /* set Checksum Flag */
+ xgell_set_mbuf_cflags(mbuf_up);
+#ifdef XGE_FEATURE_LRO
+ if(lldev->buffer_mode == XGE_HAL_RING_QUEUE_BUFFER_MODE_1) {
+ xgell_accumulate_large_rx(&ext_info, mbuf_up,
+ mbuf_up->m_len, lldev, rxd_priv);
+ }
+#else
+ /* Post-Read sync for buffers*/
+ bus_dmamap_sync(lldev->dma_tag_rx,
+ rxd_priv->dmainfo[0].dma_map, BUS_DMASYNC_POSTREAD);
+
+ /* Send it up */
+ mtx_unlock(&lldev->xge_lock);
+ (*ifnetp->if_input)(ifnetp, mbuf_up);
+ mtx_lock(&lldev->xge_lock);
+#endif
+ }
+ else {
+ /*
+ * Packet with erroneous checksum , let the upper layer
+ * deal with it
+ */
+
+ /* Post-Read sync for buffers*/
+ bus_dmamap_sync(lldev->dma_tag_rx,
+ rxd_priv->dmainfo[0].dma_map, BUS_DMASYNC_POSTREAD);
+
+#ifdef XGE_FEATURE_LRO
+ xgell_lro_flush_sessions(lldev);
+#endif
+
+ if (vlan_tag) {
+ mbuf_up->m_pkthdr.ether_vtag = vlan_tag;
+ mbuf_up->m_flags |= M_VLANTAG;
+ }
+ /* Send it up */
+ mtx_unlock(&lldev->xge_lock);
+ (*ifnetp->if_input)(ifnetp, mbuf_up);
+ mtx_lock(&lldev->xge_lock);
+ }
+ }
+ else {
+ /*
+ * As we have allocated a new mbuf for this descriptor, post
+ * this descriptor with new mbuf back to ring channel
+ */
+ xge_hal_ring_dtr_post(channelh, dtr);
+ if ((!(ext_info.proto & XGE_HAL_FRAME_PROTO_IP_FRAGMENTED) &&
+ (ext_info.proto & XGE_HAL_FRAME_PROTO_TCP_OR_UDP) &&
+ (ext_info.l3_cksum == XGE_HAL_L3_CKSUM_OK) &&
+ (ext_info.l4_cksum == XGE_HAL_L4_CKSUM_OK))) {
+ /* set Checksum Flag */
+ xgell_set_mbuf_cflags(mbuf_up);
+#ifdef XGE_FEATURE_LRO
+ if(lldev->buffer_mode == XGE_HAL_RING_QUEUE_BUFFER_MODE_1) {
+ xgell_accumulate_large_rx(&ext_info, mbuf_up,
+ mbuf_up->m_len, lldev, rxd_priv);
+ }
+#else
+ /* Post-Read sync for buffers*/
+ for(index = 0; index < lldev->rxd_mbuf_cnt; index++) {
+ /* Post-Read sync */
+ bus_dmamap_sync(lldev->dma_tag_rx,
+ rxd_priv->dmainfo[index].dma_map,
+ BUS_DMASYNC_POSTREAD);
+ }
+
+ /* Send it up */
+ mtx_unlock(&lldev->xge_lock);
+ (*ifnetp->if_input)(ifnetp, mbuf_up);
+ mtx_lock(&lldev->xge_lock);
+#endif
+ }
+ else {
+ /*
+ * Packet with erroneous checksum , let the upper layer
+ * deal with it
+ */
+ for(index = 0; index < lldev->rxd_mbuf_cnt; index++) {
+ /* Post-Read sync */
+ bus_dmamap_sync(lldev->dma_tag_rx,
+ rxd_priv->dmainfo[index].dma_map,
+ BUS_DMASYNC_POSTREAD);
+ }
+
+#ifdef XGE_FEATURE_LRO
+ xgell_lro_flush_sessions(lldev);
+#endif
+ /* Send it up */
+ mtx_unlock(&lldev->xge_lock);
+ (*ifnetp->if_input)(ifnetp, mbuf_up);
+ mtx_lock(&lldev->xge_lock);
+ }
+ }
+ } while(xge_hal_ring_dtr_next_completed(channelh, &dtr, &t_code)
+ == XGE_HAL_OK);
+#ifdef XGE_FEATURE_LRO
+ xgell_lro_flush_sessions(lldev);
+#endif
+
+// LEAVE_FUNCTION
+
+ return XGE_HAL_OK;
+}
+
+/******************************************
+ * Function: xge_ring_dtr_get
+ * Parameters: mbuf pointer, channel handler
+ * descriptot, Per adapter xgelldev_t
+ * structure pointer,
+ * Rx private structure
+ * Return: HAL status code
+ * Description: Updates the mbuf lengths
+ * depending on packet lengths.
+ ******************************************/
+int
+xge_ring_dtr_get(mbuf_t mbuf_up, xge_hal_channel_h channelh, xge_hal_dtr_h dtr,
+ xgelldev_t *lldev, xgell_rx_priv_t *rxd_priv)
+{
+ mbuf_t m;
+ int pkt_length[5]={0,0}, pkt_len=0;
+ dma_addr_t dma_data[5];
+ int index;
+
+ m = mbuf_up;
+ pkt_len = 0;
+
+ if(lldev->buffer_mode != XGE_HAL_RING_QUEUE_BUFFER_MODE_1) {
+ xge_os_memzero(pkt_length, sizeof(pkt_length));
+
+ /*
+ * Retrieve data of interest from the completed descriptor -- This
+ * returns the packet length
+ */
+ if(lldev->buffer_mode == XGE_HAL_RING_QUEUE_BUFFER_MODE_5) {
+ xge_hal_ring_dtr_5b_get(channelh, dtr, dma_data, pkt_length);
+ }
+ else {
+ xge_hal_ring_dtr_3b_get(channelh, dtr, dma_data, pkt_length);
+ }
+
+ for(index = 0; index < lldev->rxd_mbuf_cnt; index++) {
+ m->m_len = pkt_length[index];
+
+ if(index < (lldev->rxd_mbuf_cnt-1)) {
+ m->m_next = rxd_priv->bufferArray[index + 1];
+ m = m->m_next;
+ }
+ else {
+ m->m_next = NULL;
+ }
+ pkt_len+=pkt_length[index];
+ }
+
+ /*
+ * Since 2 buffer mode is an exceptional case where data is in 3rd
+ * buffer but not in 2nd buffer
+ */
+ if(lldev->buffer_mode == XGE_HAL_RING_QUEUE_BUFFER_MODE_2) {
+ m->m_len = pkt_length[2];
+ pkt_len+=pkt_length[2];
+ }
+
+ /*
+ * Update length of newly created buffer to be sent up with packet
+ * length
+ */
+ mbuf_up->m_pkthdr.len = pkt_len;
+ }
+ else {
+ /*
+ * Retrieve data of interest from the completed descriptor -- This
+ * returns the packet length
+ */
+ xge_hal_ring_dtr_1b_get(channelh, dtr,&dma_data[0], &pkt_length[0]);
+
+ /*
+ * Update length of newly created buffer to be sent up with packet
+ * length
+ */
+ mbuf_up->m_len = mbuf_up->m_pkthdr.len = pkt_length[0];
+ }
+
+return XGE_HAL_OK;
+}
+
+
+/******************************************
+ * Function: xge_send
+ * Parameters: Pointer to ifnet structure
+ * Return: None
+ * Description: Transmit entry point
+ ******************************************/
+void
+xge_send(struct ifnet *ifnetp)
+{
+ xgelldev_t *lldev = ifnetp->if_softc;
+
+ mtx_lock(&lldev->xge_lock);
+ xge_send_locked(ifnetp);
+ mtx_unlock(&lldev->xge_lock);
+}
+
+void
+xge_send_locked(struct ifnet *ifnetp)
+{
+ xge_hal_dtr_h dtr;
+ static bus_dma_segment_t segs[MAX_SEGS];
+ xge_hal_status_e status_code;
+ unsigned int max_fragments;
+ xgelldev_t *lldev = ifnetp->if_softc;
+ xge_hal_channel_h channelh = lldev->fifo_channel_0;
+ mbuf_t m_head = NULL;
+ mbuf_t m_buf = NULL;
+ xgell_tx_priv_t *ll_tx_priv = NULL;
+ register unsigned int count = 0;
+ unsigned int nsegs = 0;
+ u16 vlan_tag;
+
+ max_fragments = ((xge_hal_fifo_t *)channelh)->config->max_frags;
+
+ mtx_assert((&lldev->xge_lock), MA_OWNED);
+
+ /* If device is not initialized, return */
+ if((!lldev->initialized) ||
+ (!(ifnetp->if_drv_flags & IFF_DRV_RUNNING))) {
+ xge_trace(XGE_ERR, "Device is not initialized");
+ return;
+ }
+
+ /*
+ * Get the number of free descriptors in the FIFO channel and return if
+ * the count is less than the XGELL_TX_LEVEL_LOW -- the low threshold
+ */
+ count = xge_hal_channel_dtr_count(channelh);
+ if(count <= XGELL_TX_LEVEL_LOW) {
+ ifnetp->if_drv_flags |= IFF_DRV_OACTIVE;
+ xge_trace(XGE_TRACE, "Free descriptor count %d/%d at low threshold",
+ count, XGELL_TX_LEVEL_LOW);
+
+ /* Serialized -- through queue */
+ xge_queue_produce_context(xge_hal_device_queue(lldev->devh),
+ XGE_LL_EVENT_TRY_XMIT_AGAIN, lldev);
+ return;
+ }
+
+ /* This loop will be executed for each packet in the kernel maintained
+ * queue -- each packet can be with fragments as an mbuf chain */
+ while((ifnetp->if_snd.ifq_head) &&
+ (xge_hal_channel_dtr_count(channelh) > XGELL_TX_LEVEL_LOW)) {
+ IF_DEQUEUE(&ifnetp->if_snd, m_head);
+
+ for(count = 0, m_buf = m_head; m_buf != NULL;
+ m_buf = m_buf->m_next) {
+ if(m_buf->m_len) {
+ count += 1;
+ }
+ }
+
+ if(count >= max_fragments) {
+ m_buf = m_defrag(m_head, M_DONTWAIT);
+ if(m_buf != NULL) {
+ m_head = m_buf;
+ }
+ }
+
+ /* Reserve descriptors */
+ status_code = xge_hal_fifo_dtr_reserve(channelh, &dtr);
+ if(status_code) {
+ switch(status_code) {
+ case XGE_HAL_INF_CHANNEL_IS_NOT_READY:
+ xge_trace(XGE_ERR, "Channel is not ready");
+ break;
+
+ case XGE_HAL_INF_OUT_OF_DESCRIPTORS:
+ xge_trace(XGE_ERR, "Out of descriptors");
+ break;
+
+ default:
+ xge_trace(XGE_ERR,
+ "Reserving (Tx) descriptors failed. Status %d",
+ status_code);
+ }
+ goto out2;
+ break;
+ }
+
+ vlan_tag = (m_head->m_flags & M_VLANTAG) ? m_head->m_pkthdr.ether_vtag : 0;
+ xge_hal_fifo_dtr_vlan_set(dtr, vlan_tag);
+
+ /* Update Tx private structure for this descriptor */
+ ll_tx_priv = xge_hal_fifo_dtr_private(dtr);
+ ll_tx_priv->buffer = m_head;
+
+ /*
+ * Do mapping -- Required DMA tag has been created in xge_init
+ * function and DMA maps have already been created in the
+ * xgell_tx_replenish function.
+ * Returns number of segments through nsegs
+ */
+ if(bus_dmamap_load_mbuf_sg(lldev->dma_tag_tx,
+ ll_tx_priv->dma_map, m_head, segs, &nsegs, BUS_DMA_NOWAIT)) {
+ xge_trace(XGE_ERR, "DMA map load with segments failed");
+ goto out2;
+ }
+
+ /* Set descriptor buffer for header and each fragment/segment */
+ count = 0;
+ do {
+ xge_hal_fifo_dtr_buffer_set(channelh, dtr, count,
+ (dma_addr_t)htole64(segs[count].ds_addr),
+ segs[count].ds_len);
+ count = count + 1;
+ } while(count < nsegs);
+
+ /* Pre-write Sync of mapping */
+ bus_dmamap_sync(lldev->dma_tag_tx, ll_tx_priv->dma_map,
+ BUS_DMASYNC_PREWRITE);
+
+#ifdef XGE_FEATURE_TSO
+ if((m_head->m_pkthdr.csum_flags & CSUM_TSO) != 0) {
+ xge_hal_fifo_dtr_mss_set(dtr, m_head->m_pkthdr.tso_segsz);
+ }
+#endif
+ /* Checksum */
+ if(ifnetp->if_hwassist > 0) {
+ xge_hal_fifo_dtr_cksum_set_bits(dtr, XGE_HAL_TXD_TX_CKO_IPV4_EN
+ | XGE_HAL_TXD_TX_CKO_TCP_EN | XGE_HAL_TXD_TX_CKO_UDP_EN);
+ }
+
+ /* Post descriptor to FIFO channel */
+ xge_hal_fifo_dtr_post(channelh, dtr);
+
+ /* Send the same copy of mbuf packet to BPF (Berkely Packet Filter)
+ * listener so that we can use tools like tcpdump */
+ ETHER_BPF_MTAP(ifnetp, m_head);
+ }
+ goto out1;
+out2:
+ /* Prepend the packet back to queue */
+ IF_PREPEND(&ifnetp->if_snd, m_head);
+out1:
+ ifnetp->if_timer = 15;
+}
+
+/******************************************
+ * Function: xgell_get_buf
+ * Parameters: Per adapter xgelldev_t
+ * structure pointer, descriptor,
+ * Rx private structure, rxd_priv buffer
+ * buffer index for mapping
+ * Return: HAL status code
+ * Description: Gets buffer from system mbuf
+ * buffer pool.
+ ******************************************/
+int
+xgell_get_buf(xge_hal_dtr_h dtrh, xgell_rx_priv_t *rxd_priv,
+ xgelldev_t *lldev, int index)
+{
+ register mbuf_t mp = NULL;
+ struct ifnet *ifnetp = lldev->ifnetp;
+ int retValue = XGE_HAL_OK;
+ bus_addr_t paddr;
+ int BUFLEN = 0, CLUSTLEN = 0;
+
+ if(lldev->buffer_mode == XGE_HAL_RING_QUEUE_BUFFER_MODE_1) {
+ CLUSTLEN = MJUMPAGESIZE;
+ BUFLEN = MJUMPAGESIZE;
+ }
+ else {
+ BUFLEN = lldev->rxd_mbuf_len[index];
+ if(BUFLEN < MCLBYTES) {
+ CLUSTLEN = MCLBYTES;
+ }
+ else {
+ CLUSTLEN = MJUMPAGESIZE;
+ }
+ }
+
+ /* Get mbuf with attached cluster */
+ mp = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, CLUSTLEN);
+ if(!mp) {
+ xge_trace(XGE_ERR, "Out of memory to allocate mbuf");
+ retValue = XGE_HAL_FAIL;
+ goto getbuf_out;
+ }
+
+ /* Update mbuf's length, packet length and receive interface */
+ mp->m_len = mp->m_pkthdr.len = BUFLEN;
+ mp->m_pkthdr.rcvif = ifnetp;
+
+ /* Unload DMA map of mbuf in current descriptor */
+ bus_dmamap_unload(lldev->dma_tag_rx, rxd_priv->dmainfo[index].dma_map);
+
+ /* Load DMA map */
+ if(bus_dmamap_load(lldev->dma_tag_rx , rxd_priv->dmainfo[index].dma_map,
+ mtod(mp, void*), mp->m_len, dmamap_cb , &paddr , 0)) {
+ xge_trace(XGE_ERR, "Loading DMA map failed");
+ m_freem(mp);
+ retValue = XGE_HAL_FAIL;
+ goto getbuf_out;
+ }
+
+ /* Update descriptor private data */
+ rxd_priv->bufferArray[index] = mp;
+ rxd_priv->dmainfo[index].dma_phyaddr = htole64(paddr);
+
+ /* Pre-Read/Write sync */
+ bus_dmamap_sync(lldev->dma_tag_rx, rxd_priv->dmainfo[index].dma_map,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ /* Set descriptor buffer */
+ if(lldev->buffer_mode == XGE_HAL_RING_QUEUE_BUFFER_MODE_1) {
+ xge_hal_ring_dtr_1b_set(dtrh, rxd_priv->dmainfo[0].dma_phyaddr,
+ MJUMPAGESIZE);
+ }
+
+getbuf_out:
+ return retValue;
+}
+
+/******************************************
+ * Function: xgell_get_buf_3b_5b
+ * Parameters: Per adapter xgelldev_t
+ * structure pointer, descriptor,
+ * Rx private structure
+ * Return: HAL status code
+ * Description: Gets buffers from system mbuf
+ * buffer pool.
+ ******************************************/
+int
+xgell_get_buf_3b_5b(xge_hal_dtr_h dtrh, xgell_rx_priv_t *rxd_priv,
+ xgelldev_t *lldev)
+{
+ bus_addr_t dma_pointers[5];
+ int dma_sizes[5];
+ int retValue = XGE_HAL_OK, index;
+ int newindex = 0;
+
+ for(index = 0; index < lldev->rxd_mbuf_cnt; index++) {
+ retValue = xgell_get_buf(dtrh, rxd_priv, lldev, index);
+ if(retValue != XGE_HAL_OK) {
+ for(newindex = 0; newindex < index; newindex++) {
+ m_freem(rxd_priv->bufferArray[newindex]);
+ }
+ return retValue;
+ }
+ }
+
+ for(index = 0; index < lldev->buffer_mode; index++) {
+ if(lldev->rxd_mbuf_len[index] != 0) {
+ dma_pointers[index] = rxd_priv->dmainfo[index].dma_phyaddr;
+ dma_sizes[index] = lldev->rxd_mbuf_len[index];
+ }
+ else {
+ dma_pointers[index] = rxd_priv->dmainfo[index-1].dma_phyaddr;
+ dma_sizes[index] = 1;
+ }
+ }
+
+ /* Assigning second buffer to third pointer in 2 buffer mode */
+ if(lldev->buffer_mode == XGE_HAL_RING_QUEUE_BUFFER_MODE_2) {
+ dma_pointers[2] = dma_pointers[1];
+ dma_sizes[2] = dma_sizes[1];
+ dma_sizes[1] = 1;
+ }
+
+ if(lldev->buffer_mode == XGE_HAL_RING_QUEUE_BUFFER_MODE_5) {
+ xge_hal_ring_dtr_5b_set(dtrh, dma_pointers, dma_sizes);
+ }
+ else {
+ xge_hal_ring_dtr_3b_set(dtrh, dma_pointers, dma_sizes);
+ }
+
+ return retValue;
+}
+
+/******************************************
+ * Function: xgell_tx_compl
+ * Parameters: Channel handle, descriptor,
+ * transfer code,
+ * userdata -> per adapter
+ * xgelldev_t structure as void *
+ * Return: HAL status code
+ * Description: If an interrupt was raised
+ * to indicate DMA complete of
+ * the Tx packet, this function
+ * is called. It identifies the
+ * last TxD whose buffer was
+ * freed and frees all skbs
+ * whose data have already DMA'ed
+ * into the NICs internal memory.
+ ******************************************/
+xge_hal_status_e
+xgell_tx_compl(xge_hal_channel_h channelh,
+ xge_hal_dtr_h dtr, u8 t_code, void *userdata)
+{
+ xgell_tx_priv_t *ll_tx_priv;
+ mbuf_t m_buffer;
+ xgelldev_t *lldev = (xgelldev_t *)userdata;
+ struct ifnet *ifnetp = lldev->ifnetp;
+
+ ifnetp->if_timer = 0;
+
+ /* For each completed descriptor: Get private structure, free buffer,
+ * do unmapping, and free descriptor */
+ do {
+ if(t_code) {
+ xge_trace(XGE_TRACE, "t_code %d", t_code);
+ xge_hal_device_handle_tcode(channelh, dtr, t_code);
+ }
+
+ ll_tx_priv = xge_hal_fifo_dtr_private(dtr);
+ m_buffer = ll_tx_priv->buffer;
+ bus_dmamap_unload(lldev->dma_tag_tx, ll_tx_priv->dma_map);
+ m_freem(m_buffer);
+ ll_tx_priv->buffer = NULL;
+ xge_hal_fifo_dtr_free(channelh, dtr);
+ } while(xge_hal_fifo_dtr_next_completed(channelh, &dtr, &t_code)
+ == XGE_HAL_OK);
+ ifnetp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+
+ return XGE_HAL_OK;
+}
+
+/******************************************
+ * Function: xgell_tx_initial_replenish
+ * Parameters: Channel handle, descriptor,
+ * index (not used), userdata
+ * (not used), channel
+ * open/close/reopen option.
+ * Return: HAL status code
+ * Description: Creates DMA maps to be used
+ * for Tx
+ ******************************************/
+xge_hal_status_e
+xgell_tx_initial_replenish(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh,
+ int index, void *userdata, xge_hal_channel_reopen_e reopen)
+{
+ xgell_tx_priv_t *txd_priv = NULL;
+ int retValue = XGE_HAL_OK;
+ device_t dev = NULL;
+
+ /* Get the user data portion from channel handle */
+ xgelldev_t *lldev = xge_hal_channel_userdata(channelh);
+ if(lldev == NULL) {
+ xge_trace(XGE_ERR, "Failed to get user data");
+ retValue = XGE_HAL_FAIL;
+ goto txinit_out;
+ }
+ dev = lldev->device;
+
+ /* Get the private data */
+ txd_priv = (xgell_tx_priv_t *) xge_hal_fifo_dtr_private(dtrh);
+ if(txd_priv == NULL) {
+ xge_trace(XGE_ERR, "Failed to get descriptor private data");
+ retValue = XGE_HAL_FAIL;
+ goto txinit_out;
+ }
+
+ /* Create DMA map for this descriptor */
+ if(bus_dmamap_create(lldev->dma_tag_tx, BUS_DMA_NOWAIT,
+ &txd_priv->dma_map)) {
+ xge_trace(XGE_ERR, "DMA map creation for Tx descriptor failed");
+ retValue = XGE_HAL_FAIL;
+ goto txinit_out;
+ }
+
+txinit_out:
+ return retValue;
+}
+
+/******************************************
+ * Function: xgell_rx_initial_replenish
+ * Parameters: Channel handle, descriptor,
+ * ring index, userdata
+ * (not used), channel
+ * open/close/reopen option.
+ * Return: HAL status code
+ * Description: Replenish descriptor with
+ * rx_buffer in Rx buffer pool.
+ ******************************************/
+xge_hal_status_e
+xgell_rx_initial_replenish(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh,
+ int index, void *userdata, xge_hal_channel_reopen_e reopen)
+{
+ xgell_rx_priv_t *rxd_priv = NULL;
+ int retValue = XGE_HAL_OK;
+ struct ifnet *ifnetp;
+ device_t dev;
+ int index1, index2;
+
+ /* Get the user data portion from channel handle */
+ xgelldev_t *lldev = xge_hal_channel_userdata(channelh);
+ if(lldev == NULL) {
+ xge_ctrace(XGE_ERR, "xgeX: %s: Failed to get user data",
+ __FUNCTION__);
+ retValue = XGE_HAL_FAIL;
+ goto rxinit_out;
+ }
+ dev = lldev->device;
+
+ /* Get the private data */
+ rxd_priv = (xgell_rx_priv_t *) xge_hal_ring_dtr_private(channelh, dtrh);
+ if(rxd_priv == NULL) {
+ xge_trace(XGE_ERR, "Failed to get descriptor private data");
+ retValue = XGE_HAL_FAIL;
+ goto rxinit_out;
+ }
+
+ rxd_priv->bufferArray =
+ malloc(((sizeof(rxd_priv->bufferArray)) * (lldev->rxd_mbuf_cnt)),
+ M_DEVBUF, M_NOWAIT);
+
+ if(rxd_priv->bufferArray == NULL) {
+ xge_trace(XGE_ERR,
+ "Failed to allocate buffers for Rxd private structure");
+ retValue = XGE_HAL_FAIL;
+ goto rxinit_out;
+ }
+
+ ifnetp = lldev->ifnetp;
+
+ if(lldev->buffer_mode == XGE_HAL_RING_QUEUE_BUFFER_MODE_1) {
+ /* Create DMA map for these descriptors*/
+ if(bus_dmamap_create(lldev->dma_tag_rx , BUS_DMA_NOWAIT,
+ &rxd_priv->dmainfo[0].dma_map)) {
+ xge_trace(XGE_ERR,
+ "DMA map creation for Rx descriptor failed");
+ retValue = XGE_HAL_FAIL;
+ goto rxinit_err_out;
+ }
+ /* Get a buffer, attach it to this descriptor */
+ retValue = xgell_get_buf(dtrh, rxd_priv, lldev, 0);
+ }
+ else {
+ for(index1 = 0; index1 < lldev->rxd_mbuf_cnt; index1++) {
+ /* Create DMA map for this descriptor */
+ if(bus_dmamap_create(lldev->dma_tag_rx , BUS_DMA_NOWAIT ,
+ &rxd_priv->dmainfo[index1].dma_map)) {
+ xge_trace(XGE_ERR,
+ "Jumbo DMA map creation for Rx descriptor failed");
+ for(index2 = index1 - 1; index2 >= 0; index2--) {
+ bus_dmamap_destroy(lldev->dma_tag_rx,
+ rxd_priv->dmainfo[index2].dma_map);
+ }
+ retValue = XGE_HAL_FAIL;
+ goto rxinit_err_out;
+ }
+ }
+ retValue = xgell_get_buf_3b_5b(dtrh, rxd_priv, lldev);
+ }
+
+ if(retValue != XGE_HAL_OK) {
+ for(index1 = 0; index1 < lldev->rxd_mbuf_cnt; index1++) {
+ bus_dmamap_destroy(lldev->dma_tag_rx,
+ rxd_priv->dmainfo[index1].dma_map);
+ }
+ goto rxinit_err_out;
+ }
+ else {
+ goto rxinit_out;
+ }
+
+rxinit_err_out:
+ free(rxd_priv->bufferArray,M_DEVBUF);
+rxinit_out:
+ return retValue;
+}
+
+/******************************************
+ * Function: xgell_rx_term
+ * Parameters: Channel handle, descriptor,
+ * descriptor state, userdata
+ * (not used), channel
+ * open/close/reopen option.
+ * Return: None
+ * Description: Called by HAL to terminate
+ * all DTRs for ring channels.
+ ******************************************/
+void
+xgell_rx_term(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh,
+ xge_hal_dtr_state_e state, void *userdata,
+ xge_hal_channel_reopen_e reopen)
+{
+ xgell_rx_priv_t *rxd_priv;
+ xgelldev_t *lldev;
+ struct ifnet *ifnetp;
+ device_t dev;
+ int index;
+
+// ENTER_FUNCTION
+
+ /* Descriptor state is not "Posted" */
+ if(state != XGE_HAL_DTR_STATE_POSTED) {
+ xge_ctrace(XGE_ERR, "xgeX: %s: Descriptor not posted\n",
+ __FUNCTION__);
+ goto rxterm_out;
+ }
+
+ /* Get the user data portion */
+ lldev = xge_hal_channel_userdata(channelh);
+
+ dev = lldev->device;
+ ifnetp = lldev->ifnetp;
+
+ /* Get the private data */
+ rxd_priv = (xgell_rx_priv_t *) xge_hal_ring_dtr_private(channelh, dtrh);
+
+ if(lldev->buffer_mode == XGE_HAL_RING_QUEUE_BUFFER_MODE_1) {
+ /* Post-Read sync */
+ bus_dmamap_sync(lldev->dma_tag_rx, rxd_priv->dmainfo[0].dma_map,
+ BUS_DMASYNC_POSTREAD);
+
+ /* Do unmapping and destory DMA map */
+ bus_dmamap_unload(lldev->dma_tag_rx, rxd_priv->dmainfo[0].dma_map);
+ m_freem(rxd_priv->bufferArray[0]);
+ bus_dmamap_destroy(lldev->dma_tag_rx, rxd_priv->dmainfo[0].dma_map);
+ }
+ else {
+ for(index = 0; index < lldev->rxd_mbuf_cnt; index++) {
+ /* Post-Read sync */
+ bus_dmamap_sync(lldev->dma_tag_rx,
+ rxd_priv->dmainfo[index].dma_map, BUS_DMASYNC_POSTREAD);
+
+ /* Do unmapping and destory DMA map */
+ bus_dmamap_unload(lldev->dma_tag_rx,
+ rxd_priv->dmainfo[index].dma_map);
+
+ bus_dmamap_destroy(lldev->dma_tag_rx,
+ rxd_priv->dmainfo[index].dma_map);
+
+ /* Free the buffer */
+ m_free(rxd_priv->bufferArray[index]);
+ }
+ }
+ free(rxd_priv->bufferArray,M_DEVBUF);
+
+ /* Free the descriptor */
+ xge_hal_ring_dtr_free(channelh, dtrh);
+
+rxterm_out:
+// LEAVE_FUNCTION
+ return;
+}
+
+
+/******************************************
+ * Function: xgell_tx_term
+ * Parameters: Channel handle, descriptor,
+ * descriptor state, userdata
+ * (not used), channel
+ * open/close/reopen option.
+ * Return: None
+ * Description: Called by HAL to terminate
+ * all DTRs for fifo channels.
+ ******************************************/
+void
+xgell_tx_term(xge_hal_channel_h channelh, xge_hal_dtr_h dtr,
+ xge_hal_dtr_state_e state, void *userdata,
+ xge_hal_channel_reopen_e reopen)
+{
+ xgell_tx_priv_t *ll_tx_priv = xge_hal_fifo_dtr_private(dtr);
+ xgelldev_t *lldev = (xgelldev_t *)userdata;
+
+// ENTER_FUNCTION
+
+ /* Destroy DMA map */
+ bus_dmamap_destroy(lldev->dma_tag_tx, ll_tx_priv->dma_map);
+
+// LEAVE_FUNCTION
+}
+
+/******************************************
+ * xge_methods
+ *
+ * FreeBSD device interface entry points
+ ******************************************/
+static device_method_t xge_methods[] = {
+ DEVMETHOD(device_probe, xge_probe),
+ DEVMETHOD(device_attach, xge_attach),
+ DEVMETHOD(device_detach, xge_detach),
+ DEVMETHOD(device_shutdown, xge_shutdown),
+ {0, 0}
+};
+
+static driver_t xge_driver = {
+ "nxge",
+ xge_methods,
+ sizeof(xgelldev_t),
+};
+static devclass_t xge_devclass;
+DRIVER_MODULE(nxge, pci, xge_driver, xge_devclass, 0, 0);
OpenPOWER on IntegriCloud