nxge_main.c revision 802444998caed0d514e19b9fcf966c62e328e01a
1N/A * The contents of this file are subject to the terms of the 1N/A * Common Development and Distribution License (the "License"). 1N/A * You may not use this file except in compliance with the License. 1N/A * See the License for the specific language governing permissions * and limitations under the License. * When distributing Covered Code, include this CDDL HEADER in each * 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] * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. #
pragma ident "%Z%%M% %I% %E% SMI" * SunOs MT STREAMS NIU/Neptune 10Gb Ethernet Device Driver. * until MSIX supported, assume msi, use 2 for msix * Globals: tunable parameters (/etc/system or adb) * nxge_no_tx_lb : transmit load balancing * nxge_tx_lb_policy: 0 - TCP port (default) * Add tunable to reduce the amount of time spent in the * ISR doing Rx Processing. * Tunables to manage the receive buffer blocks. * nxge_rx_threshold_hi: copy all buffers. * nxge_rx_bcopy_size_type: receive buffer block size type. * nxge_rx_threshold_lo: copy only up to tunable block size type. * Hypervisor N2/NIU services information. * The next declarations are for the GLDv3 interface. * These global variables control the message * This list contains the instance structures for the Neptune * devices present in the system. The lock exists to guarantee * mutually exclusive access to the list. * Count used to maintain the number of buffers being used * by Neptune instances and loaned up to the upper layers. * Device register access attributes for PIO. * Device descriptor access attributes for DMA. * Device buffer access attributes for DMA. 0xffffffffffffffff,
/* high address */ 0xffffffffffffffff,
/* address counter max */ 0x100000,
/* alignment */ 0xfc00fc,
/* dlim_burstsizes */ 0x1,
/* minimum transfer size */ 0xffffffffffffffff,
/* maximum transfer size */ 0xffffffffffffffff,
/* maximum segment size */ (
unsigned int)
1,
/* granularity */ 0xffffffffffffffff,
/* high address */ 0xffffffffffffffff,
/* address counter max */ 0xfc00fc,
/* dlim_burstsizes */ 0x1,
/* minimum transfer size */ 0xffffffffffffffff,
/* maximum transfer size */ 0xffffffffffffffff,
/* maximum segment size */ (
unsigned int)
1,
/* granularity */ 0xffffffffffffffff,
/* high address */ 0xffffffffffffffff,
/* address counter max */ 0xfc00fc,
/* dlim_burstsizes */ 0x1,
/* minimum transfer size */ 0xffffffffffffffff,
/* maximum transfer size */ 0xffffffffffffffff,
/* maximum segment size */ (
unsigned int)
1,
/* granularity */ (
uint_t)
0xffffffff,
/* dlim_addr_hi */ (
uint_t)
0xffffffff,
/* dlim_cntr_max */ (
uint_t)
0xfc00fc,
/* dlim_burstsizes for 32 and 64 bit xfers */ * Try to allocate the largest possible size * so that fewer number of dma chunks would be managed 0x10000,
0x20000,
0x40000,
0x80000,
0x100000,
0x200000,
0x400000,
0x800000,
0x1000000};
* Translate "dev_t" to a pointer to the associated "dev_info_t". * Get the device instance since we'll need to setup * or retrieve a soft state for this instance. "nxge_init_common_dev failed"));
* Neptune has 4 ports, the first 2 ports use XMAC (10G MAC) * internally, the rest 2 ports use BMAC (1G "Big" MAC). * The two types of MACs have different characterizations. * Setup the Ndd parameters for the this instance. * Setup Register Tracing Buffer. " Couldn't determine card type" * Setup the Kstats for the driver. "major: 0x%lx minor: 0x%lx " "NIU Hypervisor service enabled"));
"unable to register to mac layer (%d)",
status));
"<== nxge_detach status = 0x%08X",
status));
"<== nxge_detach (mac_unregister) status = 0x%08X",
status));
* Stop any further interrupts. /* remove soft interrups */ * Stop the device and free resources. * Tear down the ndd parameters setup. * Tear down the kstat setup. * Remove the list of ndd parameters which * were setup during attach. " nxge_unattach: remove all properties"));
* Unmap the register setup. "nxge_map_regs: pathname devname %s",
devname));
/* get function number */ "nxge_map_regs: N2/NIU function number %d",
"Reg property not found"));
"Reg property found: fun # %d",
"nxge_map_regs: pci config size 0x%x",
regsize));
"ddi_map_regs, nxge bus config regs failed"));
"nxge_map_reg: PCI config addr 0x%0llx " * workaround for bit swapping bug in HW * which ends up in no-snoop = yes * resulting, in DMA not synched properly /* workarounds for x86 systems */ "nxge_map_regs: pio size 0x%x",
regsize));
/* set up the device mapped register */ "ddi_map_regs for Neptune global reg failed"));
/* set up the msi/msi-x mapped register */ "nxge_map_regs: msix size 0x%x",
regsize));
"ddi_map_regs for msi reg failed"));
/* set up the vio region mapped register */ "nxge_map_regs: vio size 0x%x",
regsize));
"ddi_map_regs for nxge vio reg failed"));
* Set up the device mapped register (FWARC 2006/556) * (changed back to 1: reg starts at 1!) "nxge_map_regs: dev size 0x%x",
regsize));
"ddi_map_regs for N2/NIU, global reg failed "));
/* set up the vio region mapped register */ "nxge_map_regs: vio (1) size 0x%x",
regsize));
"ddi_map_regs for nxge vio reg failed"));
/* set up the vio region mapped register */ "nxge_map_regs: vio (3) size 0x%x",
regsize));
"ddi_map_regs for nxge vio2 reg failed"));
"==> nxge_unmap_regs: bus"));
"==> nxge_unmap_regs: device registers"));
"==> nxge_unmap_regs: device interrupts"));
"==> nxge_unmap_regs: vio region"));
"==> nxge_unmap_regs: vio2 region"));
* Get the interrupt cookie so the mutexes can be "<== nxge_setup_mutexes: failed 0x%x",
ddi_status));
/* Initialize global mutex */ * Initialize mutex's for this device. * FFLP Mutexes are never used in interrupt context * as fflp operation can take very long time to * complete and hence not suitable to invoke from interrupt "<== nxge_setup_mutexes status = %x",
status));
/* free data structures, based on HW type */ * Initialize and enable TXC registers * (Globally enable TX controller, * enable a port, configure dma channel bitmap, * configure the max burst size). * Initialize and enable TXDMA channels. * Initialize and enable RXDMA channels. * Initialize TCAM and FCRAM (Neptune). * Initialize the MAC block. * Enable hardware interrupts. "<== nxge_init status (failed) = 0x%08x",
status));
"==> nxge_uninit: not initialized"));
* Reset the receive MAC side. /* Disable and soft reset the IPP */ /* Free classification resources */ * Reset the transmit MAC side. for (i = 0; i <
retry; i++) {
/* do the msg processing */ char digits[] =
"0123456789abcdef";
/* Dump the leading bytes */ /* Dump the last MAX_DUMP_SZ/2 bytes */ for (i = 0; i <
size; i++) {
"Neptune PCI regp cfg_ptr 0x%llx", (
char *)
cfg_ptr));
"Neptune PCI cfg_ptr vendor id ptr 0x%llx",
"\tvendorid 0x%x devid 0x%x",
"PCI BAR: base 0x%x base14 0x%x base 18 0x%x " "\nNeptune PCI BAR: base20 0x%x base24 0x%x " "base 28 0x%x bar2c 0x%x\n",
"\nNeptune PCI BAR: base30 0x%x\n",
"first 0x%llx second 0x%llx third 0x%llx " "<== nxge_resume status = 0x%x",
status));
" nxge_setup_dev status " " (xcvr find 0x%08x)",
status));
" nxge_setup_dev status " "(xcvr init 0x%08x)",
status));
"<== nxge_setup_dev port %d status = 0x%08x",
" nxge_setup_system_dma_pages: page %d (ddi_ptob %d) " " default_block_size %d iommu_pagesize %d",
"==> nxge_setup_system_dma_pages: page %d (ddi_ptob %d) " "default_block_size %d page mask %d",
* Get the system DMA burst size. "ddi_dma_alloc_handle: failed " "Binding spare handle to find system" "<== nxge_setup_system_dma_pages status = 0x%08x",
status));
" nxge_alloc_rx_mem_pool st_rdc %d ndmas %d",
st_rdc,
ndmas));
* Allocate memory for each receive DMA channel. * Assume that each DMA channel will be configured with default * rbr block counts are mod of batch count (16). * N2/NIU has limitation on the descriptor sizes (contiguous * memory allocation on data buffers to 4M (contig_mem_alloc) * and little endian for control buffers (must use the ddi/dki mem alloc * Addresses of receive block ring, receive completion ring and the * mailbox must be all cache-aligned (64 bytes). "nxge_port_rbr_size = %d nxge_port_rbr_spare_size = %d " "nxge_port_rcr_size = %d " "rx_cntl_alloc_size = %d",
"==> nxge_alloc_rx_mem_pool: " "==> nxge_alloc_rx_mem_pool: " * Allocate memory for receive buffers and descriptor rings. * Replace allocation functions with interface functions provided * by the partition manager when it is available. * Allocate memory for the receive buffer blocks. for (i = 0; i <
ndmas; i++) {
" nxge_alloc_rx_mem_pool to alloc mem: " " dma %d dma_buf_p %llx &dma_buf_p %llx",
" nxge_alloc_rx_mem_pool DONE alloc mem: " "dma %d dma_buf_p %llx &dma_buf_p %llx", i,
* Allocate memory for descriptor rings and mailbox. for (j = 0; j <
ndmas; j++) {
/* Free control buffers */ "==> nxge_alloc_rx_mem_pool: freeing control bufs (%d)", j));
"==> nxge_alloc_rx_mem_pool: control bufs freed (%d)",
"==> nxge_alloc_rx_mem_pool: control bufs freed (%d)", j));
"==> nxge_alloc_rx_mem_pool: freeing data bufs (%d)", i));
"==> nxge_alloc_rx_mem_pool: data bufs freed (%d)", i));
"<== nxge_alloc_rx_mem_pool:status 0x%08x",
status));
"<== nxge_free_rx_mem_pool " "(null rx buf pool or buf not allocated"));
"<== nxge_free_rx_mem_pool " "(null rx cntl buf pool or cntl buf not allocated"));
for (i = 0; i <
ndmas; i++) {
for (i = 0; i <
ndmas; i++) {
for (i = 0; i <
ndmas; i++) {
" alloc_rx_buf_dma rdc %d asize %x bsize %x bbuf %llx ",
* N2/NIU: data buffers must be contiguous as the driver * needs to call Hypervisor api to set up "alloc_rx_buf_dma rdc %d chunk %d bufp %llx size %x " "i %d nblocks %d alength %d",
" nxge_alloc_rx_buf_dma: Alloc Failed "));
" alloc_rx_buf_dma allocated rdc %d " "chunk %d size %x dvma %x bufp %llx ",
" alloc_rx_buf_dma rdc %d allocated %d chunks",
"<== nxge_alloc_rx_buf_dma status 0x%08x",
status));
"==> nxge_free_rx_buf_dma: # of chunks %d",
num_chunks));
"==> nxge_free_rx_buf_dma: chunk %d dmap 0x%llx",
"<== nxge_alloc_rx_cntl_dma status 0x%08x",
status));
"p_cfgp 0x%016llx start_tdc %d ndmas %d nxgep->max_tdcs %d",
* Allocate memory for each transmit DMA channel. * N2/NIU has limitation on the descriptor sizes (contiguous * memory allocation on data buffers to 4M (contig_mem_alloc) * and little endian for control buffers (must use the ddi/dki mem alloc * function). The transmit ring is limited to 8K (includes the * Assume that each DMA channel will be configured with default * transmit bufer size for copying transmit data. * (For packet payload over this limit, packets will not be * Addresses of transmit descriptor ring and the * mailbox must be all cache-aligned (64 bytes). "==> nxge_alloc_tx_mem_pool: " "==> nxge_alloc_tx_mem_pool: " * Allocate memory for transmit buffers and descriptor rings. * Replace allocation functions with interface functions provided * by the partition manager when it is available. * Allocate memory for the transmit buffer pool. for (i = 0; i <
ndmas; i++) {
* Allocate memory for descriptor rings and mailbox. for (j = 0; j <
ndmas; j++) {
"==> nxge_alloc_tx_mem_pool: start_tdc %d " "ndmas %d poolp->ndmas %d",
/* Free control buffers */ "<== nxge_alloc_tx_mem_pool:status 0x%08x",
status));
* N2/NIU: data buffers must be contiguous as the driver * needs to call Hypervisor api to set up "==> nxge_alloc_tx_buf_dma dmap 0x%016llx num chunks %d",
"<== nxge_alloc_tx_buf_dma status 0x%08x",
status));
"<== nxge_alloc_tx_cntl_dma status 0x%08x",
status));
"<== nxge_free_tx_mem_pool " "(null rx buf pool or buf not allocated"));
"<== nxge_free_tx_mem_pool " "(null tx cntl buf pool or cntl buf not allocated"));
for (i = 0; i <
ndmas; i++) {
for (i = 0; i <
ndmas; i++) {
for (i = 0; i <
ndmas; i++) {
* contig_alloc_type for contiguous memory only allowed "nxge_dma_mem_alloc: alloc type not allows (%d)",
"nxge_dma_mem_alloc:ddi_dma_alloc_handle failed."));
"nxge_dma_mem_alloc:ddi_dma_mem_alloc failed"));
"nxge_dma_mem_alloc:ddi_dma_mem_alloc " "nxge_dma_mem_alloc:di_dma_addr_bind failed " "nxge_dma_mem_alloc:ddi_dma_addr_bind " "nxge_dma_mem_alloc:contig_mem_alloc failed."));
"nxge_dma_mem_alloc:di_dma_addr_bind failed " "==> nxge_dma_mem_alloc: (not mapped)" "free contig kaddrp $%p " "nxge_dma_mem_alloc:di_dma_addr_bind > 1 " "dmac_laddress is NULL $%p size %d " " (status 0x%x ncookies %d.)",
"nxge_dma_mem_alloc: invalid alloc type for !sun4v"));
"dma buffer allocated: dma_p $%p " "return dmac_ladress from cookie $%p cookie dmac_size %d " "dma_p->orig_ioaddr_p $%p " "kaddrp $%p (orig_kaddrp $%p)" * nxge_m_start() -- start transmitting and receiving. * This function is called by the MAC layer when the first * stream is open to prepare the hardware ready for sending * and transmitting packets. "<== nxge_m_start: initialization failed"));
* Start timer to check the system error and tx hangs * nxge_m_stop(): stop transmitting and receiving. "<== nxge_m_unicst: set unitcast failed"));
"==> nxge_m_multicst: add %d",
add));
"<== nxge_m_multicst: add multicast failed"));
"<== nxge_m_multicst: del multicast failed"));
"==> nxge_m_promisc: on %d",
on));
"<== nxge_m_promisc: set promisc failed"));
"<== nxge_m_promisc: on %d",
on));
"<== nxge_m_ioctl: no priv"));
"==> nxge_m_ioctl: cmd 0x%x",
cmd));
* CR 6492541 Check to see if the drv_state has been initialized, * if not * call nxge_init(). * Export our receive resources to the MAC layer. for (i = 0; i <
ndmas; i++) {
"==> nxge_m_resources: vdma %d dma %d " "rcrptr 0x%016llx mac_handle 0x%016llx",
* nxge_altmac_set() -- Set an alternate MAC address * Enable comparison with the alternate MAC address. * While the first alternate addr is enabled by bit 1 of register * BMAC_ALTAD_CMPEN, it is enabled by bit 0 of register * XMAC_ADDR_CMPEN, so slot needs to be converted to addrn * accordingly before calling npi_mac_altaddr_entry. * nxeg_m_mmac_add() - find an unused address slot, set the address * value to the one specified, enable the port to start filtering on * the new MAC address. Returns 0 on success. * Make sure that nxge is initialized, if _start() has * Search for the first available slot. Because naddrfree * is not zero, we are guaranteed to find one. * Slot 0 is for unique (primary) MAC. The first alternate * Each of the first two ports of Neptune has 16 alternate * MAC slots but only the first 7 (of 15) slots have assigned factory * MAC addresses. We first search among the slots without bundled * factory MACs. If we fail to find one in that range, then we * search the slots with bundled factory MACs. A factory MAC * will be wasted while the slot is used with a user MAC address. * But the slot could be used by factory MAC again after calling * nxge_m_mmac_remove and nxge_m_mmac_reserve. * This function reserves an unused slot and programs the slot and the HW * with a factory mac address. * Make sure that nxge is initialized, if _start() has if (
slot == -
1) {
/* -1: Take the first available slot */ * Do not support factory MAC at a slot greater than * num_factory_mmac even when there are available factory * MAC addresses because the alternate MACs are bundled with * slot[1] through slot[num_factory_mmac] /* Verify the address to be reserved */ /* Pass info back to the caller */ * Remove the specified mac address and update the HW not to filter * the mac address anymore. * Make sure that nxge is initialized, if _start() has * Regardless if the MAC we just stopped filtering * is a user addr or a facory addr, we must set * the MMAC_VENDOR_ADDR flag if this slot has an * associated factory MAC to indicate that a factory * Clear mac_pool[slot].addr so that kstat shows 0 * alternate MAC address if the slot is not used. * (But nxge_m_mmac_get returns the factory MAC even * when the slot is not used!) * Modify a mac address added by nxge_m_mmac_add or nxge_m_mmac_reserve(). * Make sure that nxge is initialized, if _start() has * Assume that the MAC passed down from the caller * is not a factory MAC address (The user should * call mmac_remove followed by mmac_reserve if * he wants to use the factory MAC for this slot). * nxge_m_mmac_get() - Get the MAC address and other information * related to the slot. mma_flags should be set to 0 in the call. * Note: although kstat shows MAC address as zero when a slot is * not used, Crossbow expects nxge_m_mmac_get to copy factory MAC * to the caller as long as the slot is not using a user MAC address. * The following table shows the rules, * ------------------------------------------------------------ * (1) Slot uses a user MAC: yes no user MAC * (2) Slot uses a factory MAC: yes yes factory MAC * (3) Slot is not used but is * factory MAC capable: no yes factory MAC * (4) Slot is not used and is * not factory MAC capable: no no 0 * ------------------------------------------------------------ * Make sure that nxge is initialized, if _start() has * There's nothing for us to fill in, simply returning * B_TRUE stating that we support polling is sufficient. * maddr_handle is driver's private data, passed back to * entry point functions as arg. * Module loading and removing entry points. nodev,
/* int (*cb_aread)() */ nodev /* int (*cb_awrite)() */ * Module linkage information for the kernel. "failed to init device soft state"));
"Module removal failed 0x%08x",
/* Get the supported interrupt types */ "ddi_intr_get_supported_types failed: status 0x%08x",
"ddi_intr_get_supported_types: 0x%08x",
intr_types));
* Solaris MSIX is not supported yet. use MSI for now. * 1 - MSI 2 - MSI-X others - FIXED "use fixed (intx emulation) type %08x",
"ddi_intr_get_supported_types: 0x%08x",
intr_types));
"ddi_intr_get_supported_types: MSIX 0x%08x",
"ddi_intr_get_supported_types: MSI 0x%08x",
"ddi_intr_get_supported_types: MSXED0x%08x",
"ddi_intr_get_supported_types: MSI 0x%08x",
"ddi_intr_get_supported_types: MSIX 0x%08x",
"ddi_intr_get_supported_types: MSXED0x%08x",
" nxge_add_intrs_adv failed: status 0x%08x",
"interrupts registered : type %d",
type));
"\nAdded advanced nxge add_intr_adv " "intr type 0x%x\n",
type));
"failed to register interrupts"));
"ddi_add_softintrs failed: status 0x%08x",
"ddi_intr_get_nintrs() failed, status: 0x%x%, " "ddi_intr_get_navail() failed, status: 0x%x%, " "ddi_intr_get_navail() returned: nintrs %d, navail %d",
/* MSI must be power of 2 */ }
else if ((
navail &
8) ==
8) {
}
else if ((
navail &
4) ==
4) {
}
else if ((
navail &
2) ==
2) {
"ddi_intr_get_navail(): (msi power of 2) nintrs %d, " " ddi_intr_alloc() failed: %d",
" ddi_intr_get_pri() failed: %d",
/* Free already allocated interrupts */ "nxge_add_intrs_adv_typ:nxge_ldgv_init " /* Free already allocated interrupts */ "nxge_add_intrs_adv_type: " "1-1 int handler (entry %d intdata 0x%x)\n",
"nxge_add_intrs_adv_type: " "(entry %d intdata 0x%x)\n",
"==> nxge_add_intrs_adv_type: ddi_add_intr(inum) #%d " "==> nxge_add_intrs_adv_type: failed #%d " /* Free already allocated intr */ "Requested: %d, Allowed: %d msi_intx_cnt %d intr_added %d",
"ddi_intr_get_nintrs() failed, status: 0x%x%, " "ddi_intr_get_navail() failed, status: 0x%x%, " "ddi_intr_get_navail() returned: nintrs %d, naavail %d",
" ddi_intr_alloc() failed: %d",
" ddi_intr_get_pri() failed: %d",
/* Free already allocated interrupts */ "nxge_add_intrs_adv_type_fix:nxge_ldgv_init " /* Free already allocated interrupts */ "nxge_add_intrs_adv_type_fix: " "1-1 int handler(%d) ldg %d ldv %d " "nxge_add_intrs_adv_type_fix: " "shared ldv %d int handler(%d) ldv %d ldg %d" "arg1 0x%016llx arg2 0x%016llx\n",
"==> nxge_add_intrs_adv_type_fix: failed #%d " /* Free already allocated intr */ "<== nxge_remove_intrs: interrupts not registered"));
"nxge_remove_intrs: ddi_intr_free inum %d " "msi_intx_cnt %d intr_added %d",
"==> nxge_remove_soft_intrs: removed"));
"interrupts are not registered"));
"<== nxge_intrs_enable: already enabled"));
"block enable - status 0x%x total inums #%d\n",
"ddi_intr_enable:enable - status 0x%x " "total inums %d enable inum #%d\n",
"interrupts are not registered"));
"!nxge_mac_register failed (status %d instance %d)",
"==> nxge_init_common_dev:func # %d",
* Loop through existing per neptune hardware list. "==> nxge_init_common_device:func # %d " "hw_p $%p parent dip $%p",
"==> nxge_init_common_device:func # %d " "hw_p $%p parent dip $%p " "==> nxge_init_common_device:func # %d " "==> nxge_init_common_device (nxge_hw_list) $%p",
"<== nxge_uninit_common_device (no common)"));
"==> nxge_uninit_common_device:func # %d " "hw_p $%p parent dip $%p " "==> nxge_uninit_common_device: " "hw_p $%p parent dip $%p " "==> nxge_uninit_common_device:" "hw_p $%p parent dip $%p " "==> nxge_uninit_common_device:" "remove middle func # %d " "hw_p $%p parent dip $%p " "==> nxge_uninit_common_device (nxge_hw_list) $%p",