/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 NetXen, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright (c) 2018, Joyent, Inc. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "unm_nic.h" #include "unm_nic_hw.h" #include "unm_brdcfg.h" #include "nic_cmn.h" #include "nic_phan_reg.h" #include "unm_nic_ioctl.h" #include "nx_hw_pci_regs.h" char ident[] = "Netxen nic driver v" UNM_NIC_VERSIONID; char unm_nic_driver_name[] = "ntxn"; int verbmsg = 0; static char txbcopythreshold_propname[] = "tx_bcopy_threshold"; static char rxbcopythreshold_propname[] = "rx_bcopy_threshold"; static char rxringsize_propname[] = "rx_ring_size"; static char jumborxringsize_propname[] = "jumbo_rx_ring_size"; static char txringsize_propname[] = "tx_ring_size"; static char defaultmtu_propname[] = "default_mtu"; static char dmesg_propname[] = "verbose_driver"; #define STRUCT_COPY(a, b) bcopy(&(b), &(a), sizeof (a)) extern int unm_register_mac(unm_adapter *adapter); extern void unm_fini_kstats(unm_adapter* adapter); extern void unm_nic_remove(unm_adapter *adapter); extern int unm_nic_suspend(unm_adapter *); extern uint_t unm_intr(caddr_t, caddr_t); /* Data access requirements. */ static struct ddi_device_acc_attr unm_dev_attr = { DDI_DEVICE_ATTR_V0, DDI_STRUCTURE_LE_ACC, DDI_STRICTORDER_ACC }; static struct ddi_device_acc_attr unm_buf_attr = { DDI_DEVICE_ATTR_V0, DDI_NEVERSWAP_ACC, DDI_STRICTORDER_ACC }; static ddi_dma_attr_t unm_dma_attr_desc = { DMA_ATTR_V0, /* dma_attr_version */ 0, /* dma_attr_addr_lo */ 0xffffffffull, /* dma_attr_addr_hi */ 0x000fffffull, /* dma_attr_count_max */ 4096, /* dma_attr_align */ 0x000fffffull, /* dma_attr_burstsizes */ 4, /* dma_attr_minxfer */ 0x003fffffull, /* dma_attr_maxxfer */ 0xffffffffull, /* dma_attr_seg */ 1, /* dma_attr_sgllen */ 1, /* dma_attr_granular */ 0 /* dma_attr_flags */ }; static ddi_dma_attr_t unm_dma_attr_rxbuf = { DMA_ATTR_V0, /* dma_attr_version */ 0, /* dma_attr_addr_lo */ 0x7ffffffffULL, /* dma_attr_addr_hi */ 0xffffull, /* dma_attr_count_max */ 4096, /* dma_attr_align */ 0xfff8ull, /* dma_attr_burstsizes */ 1, /* dma_attr_minxfer */ 0xffffffffull, /* dma_attr_maxxfer */ 0xffffull, /* dma_attr_seg */ 1, /* dma_attr_sgllen */ 1, /* dma_attr_granular */ 0 /* dma_attr_flags */ }; static ddi_dma_attr_t unm_dma_attr_cmddesc = { DMA_ATTR_V0, /* dma_attr_version */ 0, /* dma_attr_addr_lo */ 0x7ffffffffULL, /* dma_attr_addr_hi */ 0xffffull, /* dma_attr_count_max */ 1, /* dma_attr_align */ 0xfff8ull, /* dma_attr_burstsizes */ 1, /* dma_attr_minxfer */ 0xffff0ull, /* dma_attr_maxxfer */ 0xffffull, /* dma_attr_seg */ 16, /* dma_attr_sgllen */ 1, /* dma_attr_granular */ 0 /* dma_attr_flags */ }; static struct nx_legacy_intr_set legacy_intr[] = NX_LEGACY_INTR_CONFIG; static int check_hw_init(struct unm_adapter_s *adapter) { u32 val; int ret = 0; adapter->unm_nic_hw_read_wx(adapter, UNM_CAM_RAM(0x1fc), &val, 4); if (val == 0x55555555) { /* This is the first boot after power up */ adapter->unm_nic_hw_read_wx(adapter, UNM_ROMUSB_GLB_SW_RESET, &val, 4); if (val != 0x80000f) ret = -1; if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) { /* Start P2 boot loader */ adapter->unm_nic_pci_write_normalize(adapter, UNM_CAM_RAM(0x1fc), UNM_BDINFO_MAGIC); adapter->unm_nic_pci_write_normalize(adapter, UNM_ROMUSB_GLB_PEGTUNE_DONE, 1); } } return (ret); } static int unm_get_flash_block(unm_adapter *adapter, int base, int size, uint32_t *buf) { int i, addr; uint32_t *ptr32; addr = base; ptr32 = buf; for (i = 0; i < size / sizeof (uint32_t); i++) { if (rom_fast_read(adapter, addr, (int *)ptr32) == -1) return (-1); ptr32++; addr += sizeof (uint32_t); } if ((char *)buf + size > (char *)ptr32) { int local; if (rom_fast_read(adapter, addr, &local) == -1) return (-1); (void) memcpy(ptr32, &local, (uintptr_t)((char *)buf + size) - (uintptr_t)(char *)ptr32); } return (0); } static int get_flash_mac_addr(struct unm_adapter_s *adapter, u64 mac[]) { uint32_t *pmac = (uint32_t *)&mac[0]; if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { uint32_t temp, crbaddr; uint16_t *pmac16 = (uint16_t *)pmac; // FOR P3, read from CAM RAM int pci_func = adapter->ahw.pci_func; pmac16 += (4 * pci_func); crbaddr = CRB_MAC_BLOCK_START + (4 * ((pci_func/2) * 3)) + (4 * (pci_func & 1)); adapter->unm_nic_hw_read_wx(adapter, crbaddr, &temp, 4); if (pci_func & 1) { *pmac16++ = (temp >> 16); adapter->unm_nic_hw_read_wx(adapter, crbaddr+4, &temp, 4); *pmac16++ = (temp & 0xffff); *pmac16++ = (temp >> 16); *pmac16 = 0; } else { *pmac16++ = (temp & 0xffff); *pmac16++ = (temp >> 16); adapter->unm_nic_hw_read_wx(adapter, crbaddr+4, &temp, 4); *pmac16++ = (temp & 0xffff); *pmac16 = 0; } return (0); } if (unm_get_flash_block(adapter, USER_START + offsetof(unm_user_info_t, mac_addr), FLASH_NUM_PORTS * sizeof (U64), pmac) == -1) return (-1); if (*mac == ~0ULL) { if (unm_get_flash_block(adapter, USER_START_OLD + offsetof(unm_old_user_info_t, mac_addr), FLASH_NUM_PORTS * sizeof (U64), pmac) == -1) return (-1); if (*mac == ~0ULL) return (-1); } return (0); } static int unm_initialize_dummy_dma(unm_adapter *adapter) { uint32_t hi, lo, temp; ddi_dma_cookie_t cookie; if (unm_pci_alloc_consistent(adapter, UNM_HOST_DUMMY_DMA_SIZE, (caddr_t *)&adapter->dummy_dma.addr, &cookie, &adapter->dummy_dma.dma_handle, &adapter->dummy_dma.acc_handle) != DDI_SUCCESS) { cmn_err(CE_WARN, "%s%d: Unable to alloc dummy dma buf\n", adapter->name, adapter->instance); return (DDI_ENOMEM); } adapter->dummy_dma.phys_addr = cookie.dmac_laddress; hi = (adapter->dummy_dma.phys_addr >> 32) & 0xffffffff; lo = adapter->dummy_dma.phys_addr & 0xffffffff; UNM_READ_LOCK(&adapter->adapter_lock); adapter->unm_nic_hw_write_wx(adapter, CRB_HOST_DUMMY_BUF_ADDR_HI, &hi, 4); adapter->unm_nic_hw_write_wx(adapter, CRB_HOST_DUMMY_BUF_ADDR_LO, &lo, 4); if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { temp = DUMMY_BUF_INIT; adapter->unm_nic_hw_write_wx(adapter, CRB_HOST_DUMMY_BUF, &temp, 4); } UNM_READ_UNLOCK(&adapter->adapter_lock); return (DDI_SUCCESS); } void unm_free_dummy_dma(unm_adapter *adapter) { if (adapter->dummy_dma.addr) { unm_pci_free_consistent(&adapter->dummy_dma.dma_handle, &adapter->dummy_dma.acc_handle); adapter->dummy_dma.addr = NULL; } } static int unm_pci_cfg_init(unm_adapter *adapter) { hardware_context *hwcontext; ddi_acc_handle_t pci_cfg_hdl; int *reg_options; dev_info_t *dip; uint_t noptions; int ret; uint16_t vendor_id, pci_cmd_word; uint8_t base_class, sub_class, prog_class; uint32_t pexsizes; struct nx_legacy_intr_set *legacy_intrp; hwcontext = &adapter->ahw; pci_cfg_hdl = adapter->pci_cfg_handle; dip = adapter->dip; vendor_id = pci_config_get16(pci_cfg_hdl, PCI_CONF_VENID); if (vendor_id != 0x4040) { cmn_err(CE_WARN, "%s%d: vendor id %x not 0x4040\n", adapter->name, adapter->instance, vendor_id); return (DDI_FAILURE); } ret = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 0, "reg", ®_options, &noptions); if (ret != DDI_PROP_SUCCESS) { cmn_err(CE_WARN, "%s%d: Could not determine reg property\n", adapter->name, adapter->instance); return (DDI_FAILURE); } hwcontext->pci_func = (reg_options[0] >> 8) & 0x7; ddi_prop_free(reg_options); base_class = pci_config_get8(pci_cfg_hdl, PCI_CONF_BASCLASS); sub_class = pci_config_get8(pci_cfg_hdl, PCI_CONF_SUBCLASS); prog_class = pci_config_get8(pci_cfg_hdl, PCI_CONF_PROGCLASS); /* * Need this check so that MEZZ card mgmt interface ntxn0 could fail * attach & return and proceed to next interfaces ntxn1 and ntxn2 */ if ((base_class != 0x02) || (sub_class != 0) || (prog_class != 0)) { cmn_err(CE_WARN, "%s%d: Base/sub/prog class problem %d/%d/%d\n", adapter->name, adapter->instance, base_class, sub_class, prog_class); return (DDI_FAILURE); } hwcontext->revision_id = pci_config_get8(pci_cfg_hdl, PCI_CONF_REVID); /* * Refuse to work with dubious P3 cards. */ if ((hwcontext->revision_id >= NX_P3_A0) && (hwcontext->revision_id < NX_P3_B1)) { cmn_err(CE_WARN, "%s%d: NetXen chip revs between 0x%x-0x%x " "is unsupported\n", adapter->name, adapter->instance, NX_P3_A0, NX_P3_B0); return (DDI_FAILURE); } /* * Save error reporting settings; clear [19:16] error status bits. * Set max read request [14:12] to 0 for 128 bytes. Set max payload * size[7:5] to 0 for for 128 bytes. */ if (NX_IS_REVISION_P2(hwcontext->revision_id)) { pexsizes = pci_config_get32(pci_cfg_hdl, 0xd8); pexsizes &= 7; pexsizes |= 0xF0000; pci_config_put32(pci_cfg_hdl, 0xd8, pexsizes); } pci_cmd_word = pci_config_get16(pci_cfg_hdl, PCI_CONF_COMM); pci_cmd_word |= (PCI_COMM_INTX_DISABLE | PCI_COMM_SERR_ENABLE); pci_config_put16(pci_cfg_hdl, PCI_CONF_COMM, pci_cmd_word); if (hwcontext->revision_id >= NX_P3_B0) legacy_intrp = &legacy_intr[hwcontext->pci_func]; else legacy_intrp = &legacy_intr[0]; adapter->legacy_intr.int_vec_bit = legacy_intrp->int_vec_bit; adapter->legacy_intr.tgt_status_reg = legacy_intrp->tgt_status_reg; adapter->legacy_intr.tgt_mask_reg = legacy_intrp->tgt_mask_reg; adapter->legacy_intr.pci_int_reg = legacy_intrp->pci_int_reg; return (DDI_SUCCESS); } static void unm_free_tx_dmahdl(unm_adapter *adapter) { int i; unm_dmah_node_t *nodep; mutex_enter(&adapter->tx_lock); nodep = &adapter->tx_dma_hdls[0]; for (i = 0; i < adapter->MaxTxDescCount + EXTRA_HANDLES; i++) { if (nodep->dmahdl != NULL) { ddi_dma_free_handle(&nodep->dmahdl); nodep->dmahdl = NULL; } nodep->next = NULL; nodep++; } adapter->dmahdl_pool = NULL; adapter->freehdls = 0; mutex_exit(&adapter->tx_lock); } static int unm_alloc_tx_dmahdl(unm_adapter *adapter) { int i; unm_dmah_node_t *nodep = &adapter->tx_dma_hdls[0]; mutex_enter(&adapter->tx_lock); for (i = 0; i < adapter->MaxTxDescCount + EXTRA_HANDLES; i++) { if (ddi_dma_alloc_handle(adapter->dip, &unm_dma_attr_cmddesc, DDI_DMA_DONTWAIT, NULL, &nodep->dmahdl) != DDI_SUCCESS) { mutex_exit(&adapter->tx_lock); goto alloc_hdl_fail; } if (i > 0) nodep->next = nodep - 1; nodep++; } adapter->dmahdl_pool = nodep - 1; adapter->freehdls = i; mutex_exit(&adapter->tx_lock); return (DDI_SUCCESS); alloc_hdl_fail: unm_free_tx_dmahdl(adapter); cmn_err(CE_WARN, "%s%d: Failed transmit ring dma handle allocation\n", adapter->name, adapter->instance); return (DDI_FAILURE); } static void unm_free_dma_mem(dma_area_t *dma_p) { if (dma_p->dma_hdl != NULL) { if (dma_p->ncookies) { (void) ddi_dma_unbind_handle(dma_p->dma_hdl); dma_p->ncookies = 0; } } if (dma_p->acc_hdl != NULL) { ddi_dma_mem_free(&dma_p->acc_hdl); dma_p->acc_hdl = NULL; } if (dma_p->dma_hdl != NULL) { ddi_dma_free_handle(&dma_p->dma_hdl); dma_p->dma_hdl = NULL; } } static int unm_alloc_dma_mem(unm_adapter *adapter, int size, uint_t dma_flag, ddi_dma_attr_t *dma_attr_p, dma_area_t *dma_p) { int ret; caddr_t vaddr; size_t actual_size; ddi_dma_cookie_t cookie; ret = ddi_dma_alloc_handle(adapter->dip, dma_attr_p, DDI_DMA_DONTWAIT, NULL, &dma_p->dma_hdl); if (ret != DDI_SUCCESS) { cmn_err(CE_WARN, "%s%d: Failed ddi_dma_alloc_handle\n", adapter->name, adapter->instance); goto dma_mem_fail; } ret = ddi_dma_mem_alloc(dma_p->dma_hdl, size, &adapter->gc_attr_desc, dma_flag & (DDI_DMA_STREAMING | DDI_DMA_CONSISTENT), DDI_DMA_DONTWAIT, NULL, &vaddr, &actual_size, &dma_p->acc_hdl); if (ret != DDI_SUCCESS) { cmn_err(CE_WARN, "%s%d: ddi_dma_mem_alloc() failed\n", adapter->name, adapter->instance); goto dma_mem_fail; } if (actual_size < size) { cmn_err(CE_WARN, "%s%d: ddi_dma_mem_alloc() allocated small\n", adapter->name, adapter->instance); goto dma_mem_fail; } ret = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL, vaddr, size, dma_flag, DDI_DMA_DONTWAIT, NULL, &cookie, &dma_p->ncookies); if (ret != DDI_DMA_MAPPED || dma_p->ncookies != 1) { cmn_err(CE_WARN, "%s%d: ddi_dma_addr_bind_handle() failed, " "%d, %d\n", adapter->name, adapter->instance, ret, dma_p->ncookies); goto dma_mem_fail; } dma_p->dma_addr = cookie.dmac_laddress; dma_p->vaddr = vaddr; (void) memset(vaddr, 0, size); return (DDI_SUCCESS); dma_mem_fail: unm_free_dma_mem(dma_p); return (DDI_FAILURE); } static void unm_free_tx_buffers(unm_adapter *adapter) { int i; dma_area_t *dma_p; struct unm_cmd_buffer *cmd_buf; unm_dmah_node_t *nodep; cmd_buf = &adapter->cmd_buf_arr[0]; for (i = 0; i < adapter->MaxTxDescCount; i++) { dma_p = &cmd_buf->dma_area; unm_free_dma_mem(dma_p); nodep = cmd_buf->head; while (nodep != NULL) { (void) ddi_dma_unbind_handle(nodep->dmahdl); nodep = nodep->next; } if (cmd_buf->msg != NULL) freemsg(cmd_buf->msg); cmd_buf++; } adapter->freecmds = 0; } static int unm_alloc_tx_buffers(unm_adapter *adapter) { int i, ret, size, allocated = 0; dma_area_t *dma_p; struct unm_cmd_buffer *cmd_buf; cmd_buf = &adapter->cmd_buf_arr[0]; size = adapter->maxmtu; for (i = 0; i < adapter->MaxTxDescCount; i++) { dma_p = &cmd_buf->dma_area; ret = unm_alloc_dma_mem(adapter, size, DDI_DMA_WRITE | DDI_DMA_STREAMING, &unm_dma_attr_rxbuf, dma_p); if (ret != DDI_SUCCESS) goto alloc_tx_buffer_fail; allocated++; cmd_buf++; } adapter->freecmds = adapter->MaxTxDescCount; return (DDI_SUCCESS); alloc_tx_buffer_fail: cmd_buf = &adapter->cmd_buf_arr[0]; for (i = 0; i < allocated; i++) { dma_p = &cmd_buf->dma_area; unm_free_dma_mem(dma_p); cmd_buf++; } cmn_err(CE_WARN, "%s%d: Failed transmit ring memory allocation\n", adapter->name, adapter->instance); return (DDI_FAILURE); } /* * Called by freemsg() to "free" the resource. */ static void unm_rx_buffer_recycle(char *arg) { unm_rx_buffer_t *rx_buffer = (unm_rx_buffer_t *)(uintptr_t)arg; unm_adapter *adapter = rx_buffer->adapter; unm_rcv_desc_ctx_t *rcv_desc = rx_buffer->rcv_desc; rx_buffer->mp = desballoc(rx_buffer->dma_info.vaddr, rcv_desc->dma_size, 0, &rx_buffer->rx_recycle); if (rx_buffer->mp == NULL) adapter->stats.desballocfailed++; mutex_enter(rcv_desc->recycle_lock); rx_buffer->next = rcv_desc->recycle_list; rcv_desc->recycle_list = rx_buffer; rcv_desc->rx_buf_recycle++; mutex_exit(rcv_desc->recycle_lock); } static void unm_destroy_rx_ring(unm_rcv_desc_ctx_t *rcv_desc) { uint32_t i, total_buf; unm_rx_buffer_t *buf_pool; total_buf = rcv_desc->rx_buf_total; buf_pool = rcv_desc->rx_buf_pool; for (i = 0; i < total_buf; i++) { if (buf_pool->mp != NULL) freemsg(buf_pool->mp); unm_free_dma_mem(&buf_pool->dma_info); buf_pool++; } kmem_free(rcv_desc->rx_buf_pool, sizeof (unm_rx_buffer_t) * total_buf); rcv_desc->rx_buf_pool = NULL; rcv_desc->pool_list = NULL; rcv_desc->recycle_list = NULL; rcv_desc->rx_buf_free = 0; mutex_destroy(rcv_desc->pool_lock); mutex_destroy(rcv_desc->recycle_lock); } static int unm_create_rx_ring(unm_adapter *adapter, unm_rcv_desc_ctx_t *rcv_desc) { int i, ret, allocate = 0, sreoff; uint32_t total_buf; dma_area_t *dma_info; unm_rx_buffer_t *rx_buffer; sreoff = adapter->ahw.cut_through ? 0 : IP_ALIGNMENT_BYTES; /* temporarily set the total rx buffers two times of MaxRxDescCount */ total_buf = rcv_desc->rx_buf_total = rcv_desc->MaxRxDescCount * 2; rcv_desc->rx_buf_pool = kmem_zalloc(sizeof (unm_rx_buffer_t) * total_buf, KM_SLEEP); rx_buffer = rcv_desc->rx_buf_pool; for (i = 0; i < total_buf; i++) { dma_info = &rx_buffer->dma_info; ret = unm_alloc_dma_mem(adapter, rcv_desc->buf_size, DDI_DMA_READ | DDI_DMA_STREAMING, &unm_dma_attr_rxbuf, dma_info); if (ret != DDI_SUCCESS) goto alloc_mem_failed; else { allocate++; dma_info->vaddr = (void *) ((char *)dma_info->vaddr + sreoff); dma_info->dma_addr += sreoff; rx_buffer->rx_recycle.free_func = unm_rx_buffer_recycle; rx_buffer->rx_recycle.free_arg = (caddr_t)rx_buffer; rx_buffer->next = NULL; rx_buffer->mp = desballoc(dma_info->vaddr, rcv_desc->dma_size, 0, &rx_buffer->rx_recycle); if (rx_buffer->mp == NULL) adapter->stats.desballocfailed++; rx_buffer->rcv_desc = rcv_desc; rx_buffer->adapter = adapter; rx_buffer++; } } for (i = 0; i < (total_buf - 1); i++) { rcv_desc->rx_buf_pool[i].next = &rcv_desc->rx_buf_pool[i + 1]; } rcv_desc->pool_list = rcv_desc->rx_buf_pool; rcv_desc->recycle_list = NULL; rcv_desc->rx_buf_free = total_buf; mutex_init(rcv_desc->pool_lock, NULL, MUTEX_DRIVER, (DDI_INTR_PRI(adapter->intr_pri))); mutex_init(rcv_desc->recycle_lock, NULL, MUTEX_DRIVER, (DDI_INTR_PRI(adapter->intr_pri))); return (DDI_SUCCESS); alloc_mem_failed: rx_buffer = rcv_desc->rx_buf_pool; for (i = 0; i < allocate; i++, rx_buffer++) { dma_info = &rx_buffer->dma_info; if (rx_buffer->mp != NULL) freemsg(rx_buffer->mp); unm_free_dma_mem(dma_info); } kmem_free(rcv_desc->rx_buf_pool, sizeof (unm_rx_buffer_t) * total_buf); rcv_desc->rx_buf_pool = NULL; cmn_err(CE_WARN, "%s%d: Failed receive ring resource allocation\n", adapter->name, adapter->instance); return (DDI_FAILURE); } static void unm_check_options(unm_adapter *adapter) { int i, ring, tx_desc, rx_desc, rx_jdesc, maxrx; unm_recv_context_t *recv_ctx; unm_rcv_desc_ctx_t *rcv_desc; uint8_t revid = adapter->ahw.revision_id; dev_info_t *dip = adapter->dip; /* * Reduce number of regular rcv desc to half on x86. */ maxrx = MAX_RCV_DESCRIPTORS; #if !defined(_LP64) maxrx /= 2; #endif /* !_LP64 */ verbmsg = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, dmesg_propname, 0); adapter->tx_bcopy_threshold = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, txbcopythreshold_propname, UNM_TX_BCOPY_THRESHOLD); adapter->rx_bcopy_threshold = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, rxbcopythreshold_propname, UNM_RX_BCOPY_THRESHOLD); tx_desc = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, txringsize_propname, MAX_CMD_DESCRIPTORS_HOST); if (tx_desc >= 256 && tx_desc <= MAX_CMD_DESCRIPTORS && ISP2(tx_desc)) { adapter->MaxTxDescCount = tx_desc; } else { cmn_err(CE_WARN, "%s%d: TxRingSize defaulting to %d, since " ".conf value is not 2 power aligned in range 256 - %d\n", adapter->name, adapter->instance, MAX_CMD_DESCRIPTORS_HOST, MAX_CMD_DESCRIPTORS); adapter->MaxTxDescCount = MAX_CMD_DESCRIPTORS_HOST; } rx_desc = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, rxringsize_propname, maxrx); if (rx_desc >= NX_MIN_DRIVER_RDS_SIZE && rx_desc <= NX_MAX_SUPPORTED_RDS_SIZE && ISP2(rx_desc)) { adapter->MaxRxDescCount = rx_desc; } else { cmn_err(CE_WARN, "%s%d: RxRingSize defaulting to %d, since " ".conf value is not 2 power aligned in range %d - %d\n", adapter->name, adapter->instance, MAX_RCV_DESCRIPTORS, NX_MIN_DRIVER_RDS_SIZE, NX_MAX_SUPPORTED_RDS_SIZE); adapter->MaxRxDescCount = MAX_RCV_DESCRIPTORS; } rx_jdesc = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, jumborxringsize_propname, MAX_JUMBO_RCV_DESCRIPTORS); if (rx_jdesc >= NX_MIN_DRIVER_RDS_SIZE && rx_jdesc <= NX_MAX_SUPPORTED_JUMBO_RDS_SIZE && ISP2(rx_jdesc)) { adapter->MaxJumboRxDescCount = rx_jdesc; } else { cmn_err(CE_WARN, "%s%d: JumboRingSize defaulting to %d, since " ".conf value is not 2 power aligned in range %d - %d\n", adapter->name, adapter->instance, MAX_JUMBO_RCV_DESCRIPTORS, NX_MIN_DRIVER_RDS_SIZE, NX_MAX_SUPPORTED_JUMBO_RDS_SIZE); adapter->MaxJumboRxDescCount = MAX_JUMBO_RCV_DESCRIPTORS; } /* * Solaris does not use LRO, but older firmware needs to have a * couple of descriptors for initialization. */ adapter->MaxLroRxDescCount = (adapter->fw_major < 4) ? 2 : 0; adapter->mtu = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, defaultmtu_propname, MTU_SIZE); if (adapter->mtu < MTU_SIZE) { cmn_err(CE_WARN, "Raising mtu to %d\n", MTU_SIZE); adapter->mtu = MTU_SIZE; } adapter->maxmtu = NX_IS_REVISION_P2(revid) ? P2_MAX_MTU : P3_MAX_MTU; if (adapter->mtu > adapter->maxmtu) { cmn_err(CE_WARN, "Lowering mtu to %d\n", adapter->maxmtu); adapter->mtu = adapter->maxmtu; } adapter->maxmtu = adapter->mtu + NX_MAX_ETHERHDR; /* * If we are not expecting to receive jumbo frames, save memory and * do not allocate. */ if (adapter->mtu <= MTU_SIZE) adapter->MaxJumboRxDescCount = NX_MIN_DRIVER_RDS_SIZE; for (i = 0; i < MAX_RCV_CTX; ++i) { recv_ctx = &adapter->recv_ctx[i]; for (ring = 0; ring < adapter->max_rds_rings; ring++) { rcv_desc = &recv_ctx->rcv_desc[ring]; switch (RCV_DESC_TYPE(ring)) { case RCV_DESC_NORMAL: rcv_desc->MaxRxDescCount = adapter->MaxRxDescCount; if (adapter->ahw.cut_through) { rcv_desc->dma_size = NX_CT_DEFAULT_RX_BUF_LEN; rcv_desc->buf_size = rcv_desc->dma_size; } else { rcv_desc->dma_size = NX_RX_NORMAL_BUF_MAX_LEN; rcv_desc->buf_size = rcv_desc->dma_size + IP_ALIGNMENT_BYTES; } break; case RCV_DESC_JUMBO: rcv_desc->MaxRxDescCount = adapter->MaxJumboRxDescCount; if (adapter->ahw.cut_through) { rcv_desc->dma_size = rcv_desc->buf_size = NX_P3_RX_JUMBO_BUF_MAX_LEN; } else { if (NX_IS_REVISION_P2(revid)) rcv_desc->dma_size = NX_P2_RX_JUMBO_BUF_MAX_LEN; else rcv_desc->dma_size = NX_P3_RX_JUMBO_BUF_MAX_LEN; rcv_desc->buf_size = rcv_desc->dma_size + IP_ALIGNMENT_BYTES; } break; case RCV_RING_LRO: rcv_desc->MaxRxDescCount = adapter->MaxLroRxDescCount; rcv_desc->buf_size = MAX_RX_LRO_BUFFER_LENGTH; rcv_desc->dma_size = RX_LRO_DMA_MAP_LEN; break; default: break; } } } } static void vector128M(unm_adapter *aptr) { aptr->unm_nic_pci_change_crbwindow = &unm_nic_pci_change_crbwindow_128M; aptr->unm_crb_writelit_adapter = &unm_crb_writelit_adapter_128M; aptr->unm_nic_hw_write_wx = &unm_nic_hw_write_wx_128M; aptr->unm_nic_hw_read_wx = &unm_nic_hw_read_wx_128M; aptr->unm_nic_hw_write_ioctl = &unm_nic_hw_write_ioctl_128M; aptr->unm_nic_hw_read_ioctl = &unm_nic_hw_read_ioctl_128M; aptr->unm_nic_pci_mem_write = &unm_nic_pci_mem_write_128M; aptr->unm_nic_pci_mem_read = &unm_nic_pci_mem_read_128M; aptr->unm_nic_pci_write_immediate = &unm_nic_pci_write_immediate_128M; aptr->unm_nic_pci_read_immediate = &unm_nic_pci_read_immediate_128M; aptr->unm_nic_pci_write_normalize = &unm_nic_pci_write_normalize_128M; aptr->unm_nic_pci_read_normalize = &unm_nic_pci_read_normalize_128M; aptr->unm_nic_pci_set_window = &unm_nic_pci_set_window_128M; aptr->unm_nic_clear_statistics = &unm_nic_clear_statistics_128M; aptr->unm_nic_fill_statistics = &unm_nic_fill_statistics_128M; } static void vector2M(unm_adapter *aptr) { aptr->unm_nic_pci_change_crbwindow = &unm_nic_pci_change_crbwindow_2M; aptr->unm_crb_writelit_adapter = &unm_crb_writelit_adapter_2M; aptr->unm_nic_hw_write_wx = &unm_nic_hw_write_wx_2M; aptr->unm_nic_hw_read_wx = &unm_nic_hw_read_wx_2M; aptr->unm_nic_hw_write_ioctl = &unm_nic_hw_write_wx_2M; aptr->unm_nic_hw_read_ioctl = &unm_nic_hw_read_wx_2M; aptr->unm_nic_pci_mem_write = &unm_nic_pci_mem_write_2M; aptr->unm_nic_pci_mem_read = &unm_nic_pci_mem_read_2M; aptr->unm_nic_pci_write_immediate = &unm_nic_pci_write_immediate_2M; aptr->unm_nic_pci_read_immediate = &unm_nic_pci_read_immediate_2M; aptr->unm_nic_pci_write_normalize = &unm_nic_pci_write_normalize_2M; aptr->unm_nic_pci_read_normalize = &unm_nic_pci_read_normalize_2M; aptr->unm_nic_pci_set_window = &unm_nic_pci_set_window_2M; aptr->unm_nic_clear_statistics = &unm_nic_clear_statistics_2M; aptr->unm_nic_fill_statistics = &unm_nic_fill_statistics_2M; } static int unm_pci_map_setup(unm_adapter *adapter) { int ret; caddr_t reg_base, db_base; caddr_t mem_ptr0, mem_ptr1 = NULL, mem_ptr2 = NULL; unsigned long pci_len0; unsigned long first_page_group_start, first_page_group_end; off_t regsize, dbsize = UNM_DB_MAPSIZE_BYTES; dev_info_t *dip = adapter->dip; adapter->ahw.qdr_sn_window = adapter->ahw.ddr_mn_window = -1; /* map register space */ ret = ddi_dev_regsize(dip, 1, ®size); if (ret != DDI_SUCCESS) { cmn_err(CE_WARN, "%s%d: failed to read reg size for bar0\n", adapter->name, adapter->instance); return (DDI_FAILURE); } ret = ddi_regs_map_setup(dip, 1, ®_base, 0, regsize, &unm_dev_attr, &adapter->regs_handle); if (ret != DDI_SUCCESS) { cmn_err(CE_WARN, "%s%d: failed to map registers\n", adapter->name, adapter->instance); return (DDI_FAILURE); } mem_ptr0 = reg_base; if (regsize == UNM_PCI_128MB_SIZE) { pci_len0 = FIRST_PAGE_GROUP_SIZE; mem_ptr1 = mem_ptr0 + SECOND_PAGE_GROUP_START; mem_ptr2 = mem_ptr0 + THIRD_PAGE_GROUP_START; first_page_group_start = FIRST_PAGE_GROUP_START; first_page_group_end = FIRST_PAGE_GROUP_END; vector128M(adapter); } else if (regsize == UNM_PCI_32MB_SIZE) { pci_len0 = 0; mem_ptr1 = mem_ptr0; mem_ptr2 = mem_ptr0 + (THIRD_PAGE_GROUP_START - SECOND_PAGE_GROUP_START); first_page_group_start = 0; first_page_group_end = 0; vector128M(adapter); } else if (regsize == UNM_PCI_2MB_SIZE) { pci_len0 = UNM_PCI_2MB_SIZE; first_page_group_start = 0; first_page_group_end = 0; adapter->ahw.ddr_mn_window = adapter->ahw.qdr_sn_window = 0; adapter->ahw.mn_win_crb = 0x100000 + PCIX_MN_WINDOW + (adapter->ahw.pci_func * 0x20); if (adapter->ahw.pci_func < 4) adapter->ahw.ms_win_crb = 0x100000 + PCIX_SN_WINDOW + (adapter->ahw.pci_func * 0x20); else adapter->ahw.ms_win_crb = 0x100000 + PCIX_SN_WINDOW + 0xA0 + ((adapter->ahw.pci_func - 4) * 0x10); vector2M(adapter); } else { cmn_err(CE_WARN, "%s%d: invalid pci regs map size %ld\n", adapter->name, adapter->instance, regsize); ddi_regs_map_free(&adapter->regs_handle); return (DDI_FAILURE); } adapter->ahw.pci_base0 = (unsigned long)mem_ptr0; adapter->ahw.pci_len0 = pci_len0; adapter->ahw.pci_base1 = (unsigned long)mem_ptr1; adapter->ahw.pci_len1 = SECOND_PAGE_GROUP_SIZE; adapter->ahw.pci_base2 = (unsigned long)mem_ptr2; adapter->ahw.pci_len2 = THIRD_PAGE_GROUP_SIZE; adapter->ahw.crb_base = PCI_OFFSET_SECOND_RANGE(adapter, UNM_PCI_CRBSPACE); adapter->ahw.first_page_group_start = first_page_group_start; adapter->ahw.first_page_group_end = first_page_group_end; /* map doorbell */ ret = ddi_regs_map_setup(dip, 2, &db_base, 0, dbsize, &unm_dev_attr, &adapter->db_handle); if (ret != DDI_SUCCESS) { cmn_err(CE_WARN, "%s%d: failed to map doorbell\n", adapter->name, adapter->instance); ddi_regs_map_free(&adapter->regs_handle); return (DDI_FAILURE); } adapter->ahw.db_base = (unsigned long)db_base; adapter->ahw.db_len = dbsize; return (DDI_SUCCESS); } static int unm_initialize_intr(unm_adapter *adapter) { int ret; int type, count, avail, actual; ret = ddi_intr_get_supported_types(adapter->dip, &type); if (ret != DDI_SUCCESS) { cmn_err(CE_WARN, "%s%d: ddi_intr_get_supported_types() " "failed\n", adapter->name, adapter->instance); return (DDI_FAILURE); } type = DDI_INTR_TYPE_MSI; ret = ddi_intr_get_nintrs(adapter->dip, type, &count); if ((ret == DDI_SUCCESS) && (count > 0)) goto found_msi; type = DDI_INTR_TYPE_FIXED; ret = ddi_intr_get_nintrs(adapter->dip, type, &count); if ((ret != DDI_SUCCESS) || (count == 0)) { cmn_err(CE_WARN, "ddi_intr_get_nintrs() failure ret=%d\n", ret); return (DDI_FAILURE); } found_msi: adapter->intr_type = type; adapter->flags &= ~(UNM_NIC_MSI_ENABLED | UNM_NIC_MSIX_ENABLED); if (type == DDI_INTR_TYPE_MSI) adapter->flags |= UNM_NIC_MSI_ENABLED; /* Get number of available interrupts */ ret = ddi_intr_get_navail(adapter->dip, type, &avail); if ((ret != DDI_SUCCESS) || (avail == 0)) { cmn_err(CE_WARN, "ddi_intr_get_navail() failure, ret=%d\n", ret); return (DDI_FAILURE); } ret = ddi_intr_alloc(adapter->dip, &adapter->intr_handle, type, 0, 1, &actual, DDI_INTR_ALLOC_NORMAL); if ((ret != DDI_SUCCESS) || (actual == 0)) { cmn_err(CE_WARN, "ddi_intr_alloc() failure: %d\n", ret); return (DDI_FAILURE); } ret = ddi_intr_get_pri(adapter->intr_handle, &adapter->intr_pri); if (ret != DDI_SUCCESS) { cmn_err(CE_WARN, "ddi_intr_get_pri() failure: %d\n", ret); } /* Call ddi_intr_add_handler() */ ret = ddi_intr_add_handler(adapter->intr_handle, unm_intr, (caddr_t)adapter, NULL); if (ret != DDI_SUCCESS) { cmn_err(CE_WARN, "%s%d: ddi_intr_add_handler() failure\n", adapter->name, adapter->instance); (void) ddi_intr_free(adapter->intr_handle); return (DDI_FAILURE); } /* Add softintr if required */ return (DDI_SUCCESS); } void unm_destroy_intr(unm_adapter *adapter) { /* disable interrupt */ if (adapter->intr_type == DDI_INTR_TYPE_MSI) (void) ddi_intr_block_disable(&adapter->intr_handle, 1); else (void) ddi_intr_disable(adapter->intr_handle); (void) ddi_intr_remove_handler(adapter->intr_handle); (void) ddi_intr_free(adapter->intr_handle); /* Remove the software intr handler */ } static void netxen_set_port_mode(unm_adapter *adapter) { static int wol_port_mode = UNM_PORT_MODE_AUTO_NEG_1G; static int port_mode = UNM_PORT_MODE_AUTO_NEG; int btype = adapter->ahw.boardcfg.board_type, data = 0; if (btype == UNM_BRDTYPE_P3_HMEZ || btype == UNM_BRDTYPE_P3_XG_LOM) { data = port_mode; /* set to port_mode normally */ if ((port_mode != UNM_PORT_MODE_802_3_AP) && (port_mode != UNM_PORT_MODE_XG) && (port_mode != UNM_PORT_MODE_AUTO_NEG_1G) && (port_mode != UNM_PORT_MODE_AUTO_NEG_XG)) data = UNM_PORT_MODE_AUTO_NEG; adapter->unm_nic_hw_write_wx(adapter, UNM_PORT_MODE_ADDR, &data, 4); if ((wol_port_mode != UNM_PORT_MODE_802_3_AP) && (wol_port_mode != UNM_PORT_MODE_XG) && (wol_port_mode != UNM_PORT_MODE_AUTO_NEG_1G) && (wol_port_mode != UNM_PORT_MODE_AUTO_NEG_XG)) wol_port_mode = UNM_PORT_MODE_AUTO_NEG; adapter->unm_nic_hw_write_wx(adapter, UNM_WOL_PORT_MODE, &wol_port_mode, 4); } } static void netxen_pcie_strap_init(unm_adapter *adapter) { ddi_acc_handle_t pcihdl = adapter->pci_cfg_handle; u32 chicken, control, c8c9value = 0xF1000; adapter->unm_nic_hw_read_wx(adapter, UNM_PCIE_REG(PCIE_CHICKEN3), &chicken, 4); chicken &= 0xFCFFFFFF; /* clear chicken3 25:24 */ control = pci_config_get32(pcihdl, 0xD0); if ((control & 0x000F0000) != 0x00020000) /* is it gen1? */ chicken |= 0x01000000; adapter->unm_nic_hw_write_wx(adapter, UNM_PCIE_REG(PCIE_CHICKEN3), &chicken, 4); control = pci_config_get32(pcihdl, 0xC8); control = pci_config_get32(pcihdl, 0xC8); pci_config_put32(pcihdl, 0xC8, c8c9value); } static int netxen_read_mac_addr(unm_adapter *adapter) { u64 mac_addr[8 + 1]; unsigned char *p; int i; if (get_flash_mac_addr(adapter, mac_addr) != 0) return (-1); if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) p = (unsigned char *)&mac_addr[adapter->ahw.pci_func]; else p = (unsigned char *)&mac_addr[adapter->portnum]; for (i = 0; i < 6; i++) adapter->mac_addr[i] = p[5 - i]; if (unm_nic_macaddr_set(adapter, adapter->mac_addr) != 0) return (-1); return (0); } static int unmattach(dev_info_t *dip, ddi_attach_cmd_t cmd) { unm_adapter *adapter; int i, first_driver = 0; int ret, temp; switch (cmd) { case DDI_ATTACH: break; case DDI_RESUME: case DDI_PM_RESUME: default: return (DDI_FAILURE); } adapter = kmem_zalloc(sizeof (unm_adapter), KM_SLEEP); adapter->dip = dip; ddi_set_driver_private(dip, adapter); adapter->instance = ddi_get_instance(dip); adapter->name = ddi_driver_name(dip); ret = pci_config_setup(dip, &adapter->pci_cfg_handle); if (ret != DDI_SUCCESS) { cmn_err(CE_WARN, "%s%d: pci_config_setup failed\n", adapter->name, adapter->instance); goto attach_setup_err; } ret = unm_pci_cfg_init(adapter); if (ret != DDI_SUCCESS) goto attach_err; ret = unm_pci_map_setup(adapter); if (ret != DDI_SUCCESS) goto attach_err; if (unm_initialize_intr(adapter) != DDI_SUCCESS) goto attach_unmap_regs; rw_init(&adapter->adapter_lock, NULL, RW_DRIVER, DDI_INTR_PRI(adapter->intr_pri)); mutex_init(&adapter->tx_lock, NULL, MUTEX_DRIVER, (DDI_INTR_PRI(adapter->intr_pri))); mutex_init(&adapter->lock, NULL, MUTEX_DRIVER, (DDI_INTR_PRI(adapter->intr_pri))); adapter->portnum = (int8_t)adapter->ahw.pci_func; /* * Set the CRB window to invalid. If any register in window 0 is * accessed it should set window to 0 and then reset it to 1. */ adapter->curr_window = 255; adapter->fw_major = adapter->unm_nic_pci_read_normalize(adapter, UNM_FW_VERSION_MAJOR); if (adapter->fw_major < 4) adapter->max_rds_rings = 3; else adapter->max_rds_rings = 2; STRUCT_COPY(adapter->gc_dma_attr_desc, unm_dma_attr_desc); STRUCT_COPY(adapter->gc_attr_desc, unm_buf_attr); ret = unm_nic_get_board_info(adapter); if (ret != DDI_SUCCESS) { cmn_err(CE_WARN, "%s%d: error reading board config\n", adapter->name, adapter->instance); goto attach_destroy_intr; } /* Mezz cards have PCI function 0, 2, 3 enabled */ switch (adapter->ahw.boardcfg.board_type) { case UNM_BRDTYPE_P2_SB31_10G_IMEZ: case UNM_BRDTYPE_P2_SB31_10G_HMEZ: if (adapter->ahw.pci_func >= 2) { adapter->portnum = adapter->ahw.pci_func - 2; } default: break; } if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { temp = UNM_CRB_READ_VAL_ADAPTER(UNM_MIU_MN_CONTROL, adapter); adapter->ahw.cut_through = NX_IS_SYSTEM_CUT_THROUGH(temp); if (adapter->ahw.pci_func == 0) first_driver = 1; } else { if (adapter->portnum == 0) first_driver = 1; } unm_check_options(adapter); if (first_driver) { int first_boot = adapter->unm_nic_pci_read_normalize(adapter, UNM_CAM_RAM(0x1fc)); if (check_hw_init(adapter) != 0) { cmn_err(CE_WARN, "%s%d: Error in HW init sequence\n", adapter->name, adapter->instance); goto attach_destroy_intr; } if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) netxen_set_port_mode(adapter); if (first_boot != 0x55555555) { temp = 0; adapter->unm_nic_hw_write_wx(adapter, CRB_CMDPEG_STATE, &temp, 4); if (pinit_from_rom(adapter, 0) != 0) goto attach_destroy_intr; drv_usecwait(500); ret = load_from_flash(adapter); if (ret != DDI_SUCCESS) goto attach_destroy_intr; } if (ret = unm_initialize_dummy_dma(adapter)) goto attach_destroy_intr; /* * Tell the hardware our version number. */ i = (_UNM_NIC_MAJOR << 16) | ((_UNM_NIC_MINOR << 8)) | (_UNM_NIC_SUBVERSION); adapter->unm_nic_hw_write_wx(adapter, CRB_DRIVER_VERSION, &i, 4); /* Unlock the HW, prompting the boot sequence */ if ((first_boot == 0x55555555) && (NX_IS_REVISION_P2(adapter->ahw.revision_id))) adapter->unm_nic_pci_write_normalize(adapter, UNM_ROMUSB_GLB_PEGTUNE_DONE, 1); /* Handshake with the card before we register the devices. */ if (phantom_init(adapter, 0) != DDI_SUCCESS) goto attach_destroy_intr; } if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) netxen_pcie_strap_init(adapter); /* * See if the firmware gave us a virtual-physical port mapping. */ adapter->physical_port = adapter->portnum; i = adapter->unm_nic_pci_read_normalize(adapter, CRB_V2P(adapter->portnum)); if (i != 0x55555555) adapter->physical_port = (uint16_t)i; adapter->ahw.linkup = 0; if (receive_peg_ready(adapter)) { ret = -EIO; goto free_dummy_dma; } if (netxen_read_mac_addr(adapter)) cmn_err(CE_WARN, "%s%d: Failed to read MAC addr\n", adapter->name, adapter->instance); unm_nic_flash_print(adapter); if (verbmsg != 0) { switch (adapter->ahw.board_type) { case UNM_NIC_GBE: cmn_err(CE_NOTE, "%s: QUAD GbE port %d initialized\n", unm_nic_driver_name, adapter->portnum); break; case UNM_NIC_XGBE: cmn_err(CE_NOTE, "%s: XGbE port %d initialized\n", unm_nic_driver_name, adapter->portnum); break; } } ret = unm_register_mac(adapter); if (ret != DDI_SUCCESS) { cmn_err(CE_NOTE, "%s%d: Mac registration error\n", adapter->name, adapter->instance); goto free_dummy_dma; } return (DDI_SUCCESS); free_dummy_dma: if (first_driver) unm_free_dummy_dma(adapter); attach_destroy_intr: unm_destroy_intr(adapter); attach_unmap_regs: ddi_regs_map_free(&(adapter->regs_handle)); ddi_regs_map_free(&(adapter->db_handle)); attach_err: pci_config_teardown(&adapter->pci_cfg_handle); attach_setup_err: kmem_free(adapter, sizeof (unm_adapter)); return (ret); } static int unmdetach(dev_info_t *dip, ddi_detach_cmd_t cmd) { unm_adapter *adapter = (unm_adapter *)ddi_get_driver_private(dip); if (adapter == NULL) return (DDI_FAILURE); switch (cmd) { case DDI_DETACH: unm_fini_kstats(adapter); adapter->kstats[0] = NULL; if (adapter->pci_cfg_handle != NULL) pci_config_teardown(&adapter->pci_cfg_handle); unm_nd_cleanup(adapter); unm_nic_remove(adapter); return (DDI_SUCCESS); case DDI_SUSPEND: return (unm_nic_suspend(adapter)); default: break; } return (DDI_FAILURE); } int create_rxtx_rings(unm_adapter *adapter) { unm_recv_context_t *recv_ctx; unm_rcv_desc_ctx_t *rcv_desc; int i, ring; adapter->cmd_buf_arr = (struct unm_cmd_buffer *)kmem_zalloc( sizeof (struct unm_cmd_buffer) * adapter->MaxTxDescCount, KM_SLEEP); for (i = 0; i < MAX_RCV_CTX; ++i) { recv_ctx = &adapter->recv_ctx[i]; for (ring = 0; ring < adapter->max_rds_rings; ring++) { rcv_desc = &recv_ctx->rcv_desc[ring]; if (unm_create_rx_ring(adapter, rcv_desc) != DDI_SUCCESS) goto attach_free_cmdbufs; } } if (unm_alloc_tx_dmahdl(adapter) != DDI_SUCCESS) goto attach_free_cmdbufs; if (unm_alloc_tx_buffers(adapter) != DDI_SUCCESS) goto attach_free_tx_dmahdl; return (DDI_SUCCESS); attach_free_tx_buffers: unm_free_tx_buffers(adapter); attach_free_tx_dmahdl: unm_free_tx_dmahdl(adapter); attach_free_cmdbufs: kmem_free(adapter->cmd_buf_arr, sizeof (struct unm_cmd_buffer) * adapter->MaxTxDescCount); for (i = 0; i < MAX_RCV_CTX; ++i) { recv_ctx = &adapter->recv_ctx[i]; for (ring = 0; ring < adapter->max_rds_rings; ring++) { rcv_desc = &recv_ctx->rcv_desc[ring]; if (rcv_desc->rx_buf_pool != NULL) unm_destroy_rx_ring(rcv_desc); } } return (DDI_FAILURE); } void destroy_rxtx_rings(unm_adapter *adapter) { unm_recv_context_t *recv_ctx; unm_rcv_desc_ctx_t *rcv_desc; int ctx, ring; unm_free_tx_buffers(adapter); unm_free_tx_dmahdl(adapter); for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) { recv_ctx = &adapter->recv_ctx[ctx]; for (ring = 0; ring < adapter->max_rds_rings; ring++) { rcv_desc = &recv_ctx->rcv_desc[ring]; if (rcv_desc->rx_buf_pool != NULL) unm_destroy_rx_ring(rcv_desc); } } if (adapter->cmd_buf_arr != NULL) kmem_free(adapter->cmd_buf_arr, sizeof (struct unm_cmd_buffer) * adapter->MaxTxDescCount); } #ifdef SOLARIS11 DDI_DEFINE_STREAM_OPS(unm_ops, nulldev, nulldev, unmattach, unmdetach, nodev, NULL, D_MP, NULL, NULL); #else DDI_DEFINE_STREAM_OPS(unm_ops, nulldev, nulldev, unmattach, unmdetach, nodev, NULL, D_MP, NULL); #endif static struct modldrv modldrv = { &mod_driverops, /* Type of module. This one is a driver */ ident, &unm_ops, /* driver ops */ }; static struct modlinkage modlinkage = { MODREV_1, (&modldrv), NULL }; int _init(void) { int ret; unm_ops.devo_cb_ops->cb_str = NULL; mac_init_ops(&unm_ops, "ntxn"); ret = mod_install(&modlinkage); if (ret != DDI_SUCCESS) { mac_fini_ops(&unm_ops); cmn_err(CE_WARN, "ntxn: mod_install failed\n"); } return (ret); } int _fini(void) { int ret; ret = mod_remove(&modlinkage); if (ret == DDI_SUCCESS) mac_fini_ops(&unm_ops); return (ret); } int _info(struct modinfo *modinfop) { return (mod_info(&modlinkage, modinfop)); }