/* * 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 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _SYS_IB_ADAPTERS_HERMON_H #define _SYS_IB_ADAPTERS_HERMON_H /* * hermon.h * Contains the #defines and typedefs necessary for the Hermon softstate * structure and for proper attach() and detach() processing. Also * includes all the other Hermon header files (and so is the only header * file that is directly included by the Hermon source files). * Lastly, this file includes everything necessary for implementing the * devmap interface and for maintaining the "mapped resource database". */ #include #include #include #include #include #include #include #ifdef FMA_TEST #include #endif #include #include #include /* * First include all the Hermon typedefs, then include all the other Hermon * specific headers (many of which depend on the typedefs having already * been defined). */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif /* * Number of initial states to setup. Used in call to ddi_soft_state_init() */ #define HERMON_INITIAL_STATES 3 /* * Macro and defines used to calculate device instance number from minor * number (and vice versa). */ #define HERMON_MINORNUM_SHIFT 3 #define HERMON_DEV_INSTANCE(dev) (getminor((dev)) & \ ((1 << HERMON_MINORNUM_SHIFT) - 1)) /* * Locations for the various Hermon hardware CMD,UAR & MSIx PCIe BARs */ #define HERMON_CMD_BAR 1 /* device config space */ #define HERMON_UAR_BAR 2 /* UAR Region */ #define HERMON_MSIX_BAR 3 /* MSI-X Table */ #define HERMON_ONCLOSE_FLASH_INPROGRESS (1 << 0) #define HERMON_MSIX_MAX 8 /* max # of interrupt vectors */ /* * VPD header size - or more rightfully, the area of interest for fwflash * There's more, but we don't need it for our use so we don't read it */ #define HERMON_VPD_HDR_DWSIZE 0x10 /* 16 Dwords */ #define HERMON_VPD_HDR_BSIZE 0x40 /* 64 Bytes */ /* * Offsets to be used w/ reset to save/restore PCI capability stuff */ #define HERMON_PCI_CAP_DEV_OFFS 0x08 #define HERMON_PCI_CAP_LNK_OFFS 0x10 /* * Some defines for the software reset. These define the value that should * be written to begin the reset (HERMON_SW_RESET_START), the delay before * beginning to poll for completion (HERMON_SW_RESET_DELAY), the in-between * polling delay (HERMON_SW_RESET_POLL_DELAY), and the value that indicates * that the reset has not completed (HERMON_SW_RESET_NOTDONE). */ #define HERMON_SW_RESET_START 0x00000001 #define HERMON_SW_RESET_DELAY 1000000 /* 1000 ms, per 0.36 PRM */ #define HERMON_SW_RESET_POLL_DELAY 100 /* 100 us */ #define HERMON_SW_RESET_NOTDONE 0xFFFFFFFF /* * These defines are used in the Hermon software reset operation. They define * the total number PCI registers to read/restore during the reset. And they * also specify two config registers which should not be read or restored. */ #define HERMON_SW_RESET_NUMREGS 0x40 #define HERMON_SW_RESET_REG22_RSVD 0x16 /* 22 dec */ #define HERMON_SW_RESET_REG23_RSVD 0x17 /* 23 dec */ /* * Macro used to output HCA warning messages. Note: HCA warning messages * are only generated when an unexpected condition has been detected. This * can be the result of a software bug or some other problem, but it is more * often an indication that the HCA firmware (and/or hardware) has done * something unexpected. This warning message means that the driver state * in unpredictable and that shutdown/restart is suggested. */ #define HERMON_WARNING(state, string) \ cmn_err(CE_WARN, "hermon%d: %s\n", (state)->hs_instance, string) #define HERMON_NOTE(state, string) \ cmn_err(CE_CONT, "hermon%d: %s\n", (state)->hs_instance, string) /* * Macro used to set attach failure messages. Also, the attach message buf * size is set here. */ #define HERMON_ATTACH_MSGSIZE 80 #define HERMON_ATTACH_MSG(attach_buf, attach_msg) \ (void) snprintf((attach_buf), HERMON_ATTACH_MSGSIZE, (attach_msg)); #define HERMON_ATTACH_MSG_INIT(attach_buf) \ (attach_buf)[0] = '\0'; /* * Macros used for controlling whether or not event callbacks will be forwarded * to the IBTF. This is necessary because there are certain race conditions * that can occur (e.g. calling IBTF with an asynch event before the IBTF * registration has successfully completed or handling an event after we've * detached from the IBTF.) * * HERMON_ENABLE_IBTF_CALLB() initializes the "hs_ibtfpriv" field in the Hermon * softstate. When "hs_ibtfpriv" is non-NULL, it is OK to forward asynch * and CQ events to the IBTF. * * HERMON_DO_IBTF_ASYNC_CALLB() and HERMON_DO_IBTF_CQ_CALLB() both set and clear * the "hs_in_evcallb" flag, as necessary, to indicate that an IBTF * callback is currently in progress. This is necessary so that we can * block on this condition in hermon_detach(). * * HERMON_QUIESCE_IBTF_CALLB() is used in hermon_detach() to set the * "hs_ibtfpriv" to NULL (thereby disabling any further IBTF callbacks) * and to poll on the "hs_in_evcallb" flag. When this flag is zero, all * IBTF callbacks have quiesced and it is safe to continue with detach * (i.e. continue detaching from IBTF). */ #define HERMON_ENABLE_IBTF_CALLB(state, tmp_ibtfpriv) \ (state)->hs_ibtfpriv = (tmp_ibtfpriv); #define HERMON_DO_IBTF_ASYNC_CALLB(state, type, event) \ _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS((state)->hs_in_evcallb)) \ (state)->hs_in_evcallb = 1; \ ibc_async_handler((state)->hs_ibtfpriv, (type), (event)); \ (state)->hs_in_evcallb = 0; #define HERMON_DO_IBTF_CQ_CALLB(state, cq) \ _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS((state)->hs_in_evcallb)) \ (state)->hs_in_evcallb = 1; \ ibc_cq_handler((state)->hs_ibtfpriv, (cq)->cq_hdlrarg); \ (state)->hs_in_evcallb = 0; #define HERMON_QUIESCE_IBTF_CALLB(state) \ { \ uint_t count = 0; \ \ state->hs_ibtfpriv = NULL; \ while (((state)->hs_in_evcallb != 0) && \ (count++ < HERMON_QUIESCE_IBTF_CALLB_POLL_MAX)) { \ drv_usecwait(HERMON_QUIESCE_IBTF_CALLB_POLL_DELAY); \ } \ } /* * Defines used by the HERMON_QUIESCE_IBTF_CALLB() macro to determine the * duration and number of times (at maximum) to poll while waiting for IBTF * callbacks to quiesce. */ #define HERMON_QUIESCE_IBTF_CALLB_POLL_DELAY 1 #define HERMON_QUIESCE_IBTF_CALLB_POLL_MAX 1000000 /* * Macros to retrieve PCI id's of the device */ #define HERMON_DDI_PROP_GET(dip, property) \ (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, \ property, -1)) #define HERMON_GET_VENDOR_ID(dip) HERMON_DDI_PROP_GET(dip, "vendor-id") #define HERMON_GET_DEVICE_ID(dip) HERMON_DDI_PROP_GET(dip, "device-id") #define HERMON_GET_REVISION_ID(dip) HERMON_DDI_PROP_GET(dip, "revision-id") /* * Define used to determine the device mode to which Hermon driver has been * attached. HERMON_IS_MAINTENANCE_MODE() returns true when the device has * come up in the "maintenance mode". In this mode, no InfiniBand interfaces * are enabled, but the device's firmware can be updated/flashed (and * test/debug interfaces should be useable). * HERMON_IS_HCA_MODE() returns true when the device has come up in the * normal HCA mode. In this mode, all necessary InfiniBand interfaces are * enabled (and, if necessary, HERMON firmware can be updated/flashed). */ #define HERMON_IS_MAINTENANCE_MODE(dip) \ ((ddi_prop_get_int(DDI_DEV_T_ANY, (dip), DDI_PROP_DONTPASS, \ "device-id", -1) == PCI_DEVID_HERMON_MAINT) && \ (ddi_prop_get_int(DDI_DEV_T_ANY, (dip), DDI_PROP_DONTPASS, \ "vendor-id", -1) == PCI_VENID_MLX)) #define HERMON_IS_HCA_MODE(dip) \ (((ddi_prop_get_int(DDI_DEV_T_ANY, (dip), DDI_PROP_DONTPASS, \ "device-id", -1) == PCI_DEVID_HERMON_SDR) || \ (ddi_prop_get_int(DDI_DEV_T_ANY, (dip), DDI_PROP_DONTPASS, \ "device-id", -1) == PCI_DEVID_HERMON_DDR) || \ (ddi_prop_get_int(DDI_DEV_T_ANY, (dip), DDI_PROP_DONTPASS, \ "device-id", -1) == PCI_DEVID_HERMON_DDRG2) || \ (ddi_prop_get_int(DDI_DEV_T_ANY, (dip), DDI_PROP_DONTPASS, \ "device-id", -1) == PCI_DEVID_HERMON_QDRG2)) && \ (ddi_prop_get_int(DDI_DEV_T_ANY, (dip), DDI_PROP_DONTPASS, \ "vendor-id", -1) == PCI_VENID_MLX)) #define HERMON_MAINTENANCE_MODE 1 #define HERMON_HCA_MODE 2 /* * Used to determine if the device is operational, or not in maintenance mode. * This means either the driver has attached successfully against an hermon * device in hermon compatibility mode, or against a hermon device in full HCA * mode. */ #define HERMON_IS_OPERATIONAL(mode) \ (mode == HERMON_HCA_MODE) /* * The following define is used (in hermon_umap_db_set_onclose_cb()) to * indicate that a cleanup callback is needed to undo initialization done * by the firmware flash burn code. */ #define HERMON_ONCLOSE_FLASH_INPROGRESS (1 << 0) /* * The following enumerated type and structures are used during driver * initialization. Note: The HERMON_DRV_CLEANUP_ALL type is used as a marker * for end of the cleanup steps. No cleanup steps should be added after * HERMON_DRV_CLEANUP_ALL. Any addition steps should be added before it. */ typedef enum { HERMON_DRV_CLEANUP_LEVEL0, HERMON_DRV_CLEANUP_LEVEL1, HERMON_DRV_CLEANUP_LEVEL2, HERMON_DRV_CLEANUP_LEVEL3, HERMON_DRV_CLEANUP_LEVEL4, HERMON_DRV_CLEANUP_LEVEL5, HERMON_DRV_CLEANUP_LEVEL6, HERMON_DRV_CLEANUP_LEVEL7, HERMON_DRV_CLEANUP_LEVEL8, HERMON_DRV_CLEANUP_LEVEL9, HERMON_DRV_CLEANUP_LEVEL10, HERMON_DRV_CLEANUP_LEVEL11, HERMON_DRV_CLEANUP_LEVEL12, HERMON_DRV_CLEANUP_LEVEL13, HERMON_DRV_CLEANUP_LEVEL14, HERMON_DRV_CLEANUP_LEVEL15, HERMON_DRV_CLEANUP_LEVEL16, HERMON_DRV_CLEANUP_LEVEL17, HERMON_DRV_CLEANUP_LEVEL18, HERMON_DRV_CLEANUP_LEVEL19, /* No more driver cleanup steps below this point! */ HERMON_DRV_CLEANUP_ALL } hermon_drv_cleanup_level_t; /* * The hermon_dma_info_t structure is used to store information related to * the various ICM resources' DMA allocations. The related ICM table and * virtual address are stored here. The DMA and Access handles are stored * here. Also, the allocation length and virtual (host) address. */ struct hermon_dma_info_s { ddi_dma_handle_t dma_hdl; ddi_acc_handle_t acc_hdl; uint64_t icmaddr; /* ICM virtual address */ uint64_t vaddr; /* host virtual address */ uint_t length; /* length requested */ uint_t icm_refcnt; /* refcnt */ }; _NOTE(SCHEME_PROTECTS_DATA("safe sharing", hermon_dma_info_s::icm_refcnt)) /* * The hermon_cmd_reg_t structure is used to hold the address of the each of * the most frequently accessed hardware registers. Specifically, it holds * the HCA Command Registers (HCR, used to pass command and mailbox * information back and forth to Hermon firmware) and the lock used to guarantee * mutually exclusive access to the registers. * Related to this, is the "clr_int" register which is used to clear the * interrupt once all EQs have been serviced. * Finally, there is the software reset register which is used to reinitialize * the Hermon device and to put it into a known state at driver startup time. * Below we also have the offsets (into the CMD register space) for each of * the various registers. */ typedef struct hermon_cmd_reg_s { hermon_hw_hcr_t *hcr; kmutex_t hcr_lock; uint64_t *clr_intr; uint64_t *eq_arm; uint64_t *eq_set_ci; uint32_t *sw_reset; uint32_t *sw_semaphore; uint32_t *fw_err_buf; } hermon_cmd_reg_t; _NOTE(MUTEX_PROTECTS_DATA(hermon_cmd_reg_t::hcr_lock, hermon_cmd_reg_t::hcr)) /* SOME TEMPORARY PRINTING THINGS */ #define HERMON_PRINT_CI (0x01 << 0) #define HERMON_PRINT_MEM (0x01 << 1) #define HERMON_PRINT_CQ (0x01 << 2) #define HD_PRINT(state, mask) \ if (state->hs_debug_lev & mask) /* END PRINTING THINGS */ /* * The hermon_state_t structure is the HCA software state structure. It * contains all the pointers and placeholder for everything that the HCA * driver needs to properly operate. One of these structures exists for * every instance of the HCA driver. */ struct hermon_state_s { dev_info_t *hs_dip; int hs_instance; int hs_debug; /* for debug, a way of tracing */ uint32_t hs_debug_lev; /* for controlling prints, a bit mask */ /* see hermon.c for setting it */ /* PCI device, vendor, and revision IDs */ uint16_t hs_vendor_id; uint16_t hs_device_id; uint8_t hs_revision_id; struct hermon_hw_qpc_s hs_debug_qpc; struct hermon_hw_cqc_s hs_debug_cqc; struct hermon_hw_eqc_s hs_debug_eqc; hermon_hw_sm_perfcntr_t hs_debug_perf; /* * DMA information for the InfiniHost Context Memory (ICM), * ICM Auxiliary allocation and the firmware. Also, record * of ICM and ICMA sizes, in bytes. */ /* JBDB -- store here hs_icm_table, with hs_icm_dma in */ uint64_t hs_icm_sz; hermon_icm_table_t *hs_icm; uint64_t hs_icma_sz; hermon_dma_info_t hs_icma_dma; hermon_dma_info_t hs_fw_dma; /* Hermon interrupt/MSI information */ int hs_intr_types_avail; uint_t hs_intr_type_chosen; int hs_intrmsi_count; int hs_intrmsi_avail; int hs_intrmsi_allocd; ddi_intr_handle_t hs_intrmsi_hdl[HERMON_MSIX_MAX]; uint_t hs_intrmsi_pri; int hs_intrmsi_cap; /* assign EQs to CQs in a round robin fashion */ uint_t hs_eq_dist; /* increment when used */ /* hermon HCA name and HCA part number */ char hs_hca_name[64]; char hs_hca_pn[64]; int hs_hca_pn_len; /* Hermon device operational mode */ int hs_operational_mode; /* Attach buffer saved per state to store detailed attach errors */ char hs_attach_buf[HERMON_ATTACH_MSGSIZE]; /* Hermon NodeGUID, SystemImageGUID, and NodeDescription */ uint64_t hs_nodeguid; uint64_t hs_sysimgguid; char hs_nodedesc[64]; /* Info passed to IBTF during registration */ ibc_hca_info_t hs_ibtfinfo; ibc_clnt_hdl_t hs_ibtfpriv; /* * Hermon register mapping. Holds the device access attributes, * kernel mapped addresses, and DDI access handles for both * Hermon's CMD and UAR BARs. */ ddi_device_acc_attr_t hs_reg_accattr; caddr_t hs_reg_cmd_baseaddr; /* Hermon CMD BAR */ ddi_acc_handle_t hs_reg_cmdhdl; caddr_t hs_reg_uar_baseaddr; /* Hermon UAR BAR */ ddi_acc_handle_t hs_reg_uarhdl; caddr_t hs_reg_msi_baseaddr; /* Hermon MSIx BAR */ ddi_acc_handle_t hs_reg_msihdl; /* * Some additional things for UAR Pages */ uint64_t hs_kernel_uar_index; /* kernel UAR index */ uint64_t hs_bf_offset; /* offset from UAR */ /* Bar to Blueflame */ caddr_t hs_reg_bf_baseaddr; /* blueflame base */ ddi_acc_handle_t hs_reg_bfhdl; /* blueflame handle */ /* * Hermon PCI config space registers. This array is used to * save and restore the PCI config registers before and after a * software reset. */ uint32_t hs_cfg_data[HERMON_SW_RESET_NUMREGS]; /* for reset per Linux driver */ uint32_t hs_pci_cap_offset; uint32_t hs_pci_cap_devctl; uint32_t hs_pci_cap_lnkctl; /* * Hermon UAR page resources. Holds the resource pointers for * UAR page #0 (reserved) and for UAR page #1 (used for kernel * driver doorbells). In addition, we save a pointer to the * UAR page #1 doorbells which will be used throughout the driver * whenever it is necessary to ring one of them. And, in case we * are unable to do 64-bit writes to the page (because of system * architecture), we include a lock (to ensure atomic 64-bit access). */ hermon_rsrc_t *hs_uarpg0_rsrc_rsrvd; hermon_rsrc_t *hs_uarkpg_rsrc; hermon_hw_uar_t *hs_uar; kmutex_t hs_uar_lock; /* * Used during a call to open() if we are in maintenance mode, this * field serves as a semi-unique rolling count index value, used only * in the setup of umap_db entries. This is primarily needed to * firmware device access ioctl operations can still be guaranteed to * close in the event of an unplanned process exit, even in maintenance * mode. */ uint_t hs_open_ar_indx; /* * Hermon command registers. This structure contains the addresses * for each of the most frequently accessed CMD registers. Since * almost all accesses to the Hermon hardware are through the Hermon * command interface (i.e. the HCR), we save away the pointer to * the HCR, as well as pointers to the ECR and INT registers (as * well as their corresponding "clear" registers) for interrupt * processing. And we also save away a pointer to the software * reset register (see above). */ hermon_cmd_reg_t hs_cmd_regs; uint32_t hs_cmd_toggle; /* * Hermon resource pointers. The following are pointers to the * kmem cache (from which the Hermon resource handles are allocated), * and the array of "resource pools" (which store all the pertinent * information necessary to manage each of the various types of * resources that are used by the driver. See hermon_rsrc.h for * more detail. */ kmem_cache_t *hs_rsrc_cache; hermon_rsrc_pool_info_t *hs_rsrc_hdl; /* * Hermon mailbox lists. These hold the information necessary to * manage the pools of pre-allocated Hermon mailboxes (both "In" and * "Out" type). See hermon_cmd.h for more detail. */ hermon_mboxlist_t hs_in_mblist; hermon_mboxlist_t hs_out_mblist; /* * Hermon interrupt mailbox lists. We allocate both an "In" mailbox * and an "Out" type mailbox for the interrupt context. This is in * order to guarantee that a mailbox entry will always be available in * the interrupt context, and we can NOSLEEP without having to worry * about possible failure allocating the mbox. We create this as an * mboxlist so that we have the potential for having multiple mboxes * available based on the number of interrupts we can receive at once. */ hermon_mboxlist_t hs_in_intr_mblist; hermon_mboxlist_t hs_out_intr_mblist; /* * Hermon outstanding command list. Used to hold all the information * necessary to manage the Hermon "outstanding command list". See * hermon_cmd.h for more detail. */ hermon_cmdlist_t hs_cmd_list; /* * This structure contains the Hermon driver's "configuration profile". * This is the collected set of configuration information, such as * number of QPs, CQs, mailboxes and other resources, sizes of * individual resources, other system level configuration information, * etc. See hermon_cfg.h for more detail. */ hermon_cfg_profile_t *hs_cfg_profile; /* * This flag contains the profile setting, selecting which profile the * driver would use. This is needed in the case where we have to * fallback to a smaller profile based on some DDR conditions. If we * don't fallback, then it is set to the size of DDR in the system. */ uint32_t hs_cfg_profile_setting; /* * The following are a collection of resource handles used by the * Hermon driver (internally). First is the protection domain (PD) * handle that is used when mapping all kernel memory (work queues, * completion queues, etc). Next is an array of EQ handles. This * array is indexed by EQ number and allows the Hermon driver to quickly * convert an EQ number into the software structure associated with the * given EQ. Likewise, we have three arrays for CQ, QP and SRQ * handles. These arrays are also indexed by CQ, QP or SRQ number and * allow the driver to quickly find the corresponding CQ, QP or SRQ * software structure. Note: while the EQ table is of fixed size * (because there are a maximum of 64 EQs), each of the CQ, QP and SRQ * handle lists must be allocated at driver startup. */ hermon_pdhdl_t hs_pdhdl_internal; hermon_eqhdl_t hs_eqhdl[HERMON_NUM_EQ]; hermon_cqhdl_t *hs_cqhdl; hermon_qphdl_t *hs_qphdl; hermon_srqhdl_t *hs_srqhdl; kmutex_t hs_dbr_lock; /* lock for dbr mgmt */ /* linked list of kernel dbr resources */ hermon_dbr_info_t *hs_kern_dbr; /* linked list of non-kernel dbr resources */ hermon_user_dbr_t *hs_user_dbr; /* * The AVL tree is used to store information regarding QP number * allocations. The lock protects access to the AVL tree. */ avl_tree_t hs_qpn_avl; kmutex_t hs_qpn_avl_lock; /* * This field is used to indicate whether or not the Hermon driver is * currently in an IBTF event callback elsewhere in the system. Note: * It is "volatile" because we intend to poll on this value - in * hermon_detach() - until we are assured that no further IBTF callbacks * are currently being processed. */ volatile uint32_t hs_in_evcallb; /* * The following structures are used to store the results of several * device query commands passed to the Hermon hardware at startup. * Specifically, we have hung onto the results of QUERY_DDR (which * gives information about how much DDR memory is present and where * it is located), QUERY_FW (which gives information about firmware * version numbers and the location and extent of firmware's footprint * in DDR, QUERY_DEVLIM (which gives the device limitations/resource * maximums) and QUERY_PORT (where some of the specs from DEVLIM moved), * QUERY_ADAPTER (which gives additional miscellaneous * information), and INIT/QUERY_HCA (which serves the purpose of * recording what configuration information was passed to the firmware * when the HCA was initialized). */ struct hermon_hw_queryfw_s hs_fw; struct hermon_hw_querydevlim_s hs_devlim; struct hermon_hw_query_port_s hs_queryport; struct hermon_hw_set_port_s *hs_initport; struct hermon_hw_queryadapter_s hs_adapter; struct hermon_hw_initqueryhca_s hs_hcaparams; /* * The following are used for managing special QP resources. * Specifically, we have a lock, a set of flags (in "hs_spec_qpflags") * used to track the special QP resources, and two Hermon resource * handle pointers. Each resource handle actually corresponds to two * consecutive QP contexts (one per port) for each special QP type. */ kmutex_t hs_spec_qplock; uint_t hs_spec_qpflags; hermon_rsrc_t *hs_spec_qp0; hermon_rsrc_t *hs_spec_qp1; /* * For Hermon, you have to alloc 8 qp's total, but the last 4 are * unused/reserved. The following represents the handle for those * last 4 qp's */ hermon_rsrc_t *hs_spec_qp_unused; /* * Related in some ways to the special QP handling above are these * resources which are used specifically for implementing the Hermon * agents (SMA, PMA, and BMA). Although, each of these agents does * little more that intercept the appropriate incoming MAD and forward * it along to the firmware (see hermon_agents.c for more details), we * do still use a task queue to queue them up. We can also configure * the driver to force firmware handling for certain classes of MAD, * and, therefore, we require the agent list and number of agents * in order to know what needs to be torn down at detach() time. */ hermon_agent_list_t *hs_agents; ddi_taskq_t *hs_taskq_agents; uint_t hs_num_agents; /* * Multicast group lists. These are used to track the "shadow" MCG * lists that speed up the processing of attach and detach multicast * group operations. See hermon_misc.h for more details. Note: we * need the pointer to the "temporary" MCG entry here primarily * because the size of a given MCG entry is configurable. Therefore, * it is impossible to put this variable on the stack. And rather * than allocate and deallocate the entry multiple times, we choose * instead to preallocate it once and reuse it over and over again. */ kmutex_t hs_mcglock; hermon_mcghdl_t hs_mcghdl; hermon_hw_mcg_t *hs_mcgtmp; /* * Cache of the pkey table, sgid (guid-only) tables, and * sgid (subnet) prefix. These arrays are set * during port_query, and mainly used for generating MLX GSI wqes. */ ib_pkey_t *hs_pkey[HERMON_MAX_PORTS]; ib_sn_prefix_t hs_sn_prefix[HERMON_MAX_PORTS]; ib_guid_t *hs_guid[HERMON_MAX_PORTS]; /* * Used for tracking Hermon kstat information */ hermon_ks_info_t *hs_ks_info; /* * Used for Hermon info ioctl used by VTS */ kmutex_t hs_info_lock; /* * Used for Hermon FW flash burning. They are used exclusively * within the ioctl calls for use when accessing the hermon * flash device. */ kmutex_t hs_fw_flashlock; int hs_fw_flashstarted; dev_t hs_fw_flashdev; uint32_t hs_fw_log_sector_sz; uint32_t hs_fw_device_sz; uint32_t hs_fw_flashbank; uint32_t *hs_fw_sector; uint32_t hs_fw_gpio[4]; int hs_fw_cmdset; /* * Used for Hermon FM. They are basically used to manage * the toggle switch to enable/disable Hermon FM. * Please see the comment in hermon_fm.c. */ int hs_fm_capabilities; /* FM capabilities */ int hs_fm_disable; /* Hermon FM disable flag */ int hs_fm_state; /* Hermon FM state */ boolean_t hs_fm_async_fatal; /* async internal error */ uint32_t hs_fm_async_errcnt; /* async error count */ boolean_t hs_fm_poll_suspend; /* poll thread suspend */ kmutex_t hs_fm_lock; /* mutex for state */ hermon_hca_fm_t *hs_fm_hca_fm; /* HCA FM pointer */ ddi_acc_handle_t hs_fm_cmdhdl; /* fm-protected CMD hdl */ ddi_acc_handle_t hs_fm_uarhdl; /* fm-protected UAR hdl */ ddi_device_acc_attr_t hs_fm_accattr; /* fm-protected acc attr */ ddi_periodic_t hs_fm_poll_thread; /* fma poll thread */ int32_t hs_fm_degraded_reason; /* degradation cause */ #ifdef FMA_TEST mod_hash_t *hs_fm_test_hash; /* testset */ mod_hash_t *hs_fm_id_hash; /* testid */ #endif /* * Hermon fastreboot support. To sw-reset Hermon HCA, the driver * needs to save/restore MSI-X tables and PBA. Those members are * used for the purpose. */ /* Access handle for PCI config space */ ddi_acc_handle_t hs_reg_pcihdl; /* PCI cfg handle */ ddi_acc_handle_t hs_fm_pcihdl; /* fm handle */ ushort_t hs_caps_ptr; /* MSI-X caps */ ushort_t hs_msix_ctrl; /* MSI-X ctrl */ /* members to handle MSI-X tables */ ddi_acc_handle_t hs_reg_msix_tblhdl; /* MSI-X table handle */ ddi_acc_handle_t hs_fm_msix_tblhdl; /* fm handle */ char *hs_msix_tbl_addr; /* MSI-X table addr */ char *hs_msix_tbl_entries; /* MSI-X table entry */ size_t hs_msix_tbl_size; /* MSI-X table size */ uint32_t hs_msix_tbl_offset; /* MSI-X table offset */ uint32_t hs_msix_tbl_rnumber; /* MSI-X table reg# */ /* members to handle MSI-X PBA */ ddi_acc_handle_t hs_reg_msix_pbahdl; /* MSI-X PBA handle */ ddi_acc_handle_t hs_fm_msix_pbahdl; /* fm handle */ char *hs_msix_pba_addr; /* MSI-X PBA addr */ char *hs_msix_pba_entries; /* MSI-X PBA entry */ size_t hs_msix_pba_size; /* MSI-X PBA size */ uint32_t hs_msix_pba_offset; /* MSI-X PBA offset */ uint32_t hs_msix_pba_rnumber; /* MSI-X PBA reg# */ boolean_t hs_quiescing; /* in fastreboot */ }; _NOTE(MUTEX_PROTECTS_DATA(hermon_state_s::hs_fw_flashlock, hermon_state_s::hs_fw_flashstarted hermon_state_s::hs_fw_flashdev hermon_state_s::hs_fw_log_sector_sz hermon_state_s::hs_fw_device_sz)) _NOTE(MUTEX_PROTECTS_DATA(hermon_state_s::hs_spec_qplock, hermon_state_s::hs_spec_qpflags hermon_state_s::hs_spec_qp0 hermon_state_s::hs_spec_qp1)) _NOTE(MUTEX_PROTECTS_DATA(hermon_state_s::hs_mcglock, hermon_state_s::hs_mcghdl hermon_state_s::hs_mcgtmp)) _NOTE(DATA_READABLE_WITHOUT_LOCK(hermon_state_s::hs_in_evcallb hermon_state_s::hs_fw_log_sector_sz hermon_state_s::hs_fw_device_sz hermon_state_s::hs_spec_qpflags hermon_state_s::hs_spec_qp0 hermon_state_s::hs_spec_qp1)) _NOTE(MUTEX_PROTECTS_DATA(hermon_state_s::hs_qpn_avl_lock, hermon_state_s::hs_qpn_avl)) _NOTE(SCHEME_PROTECTS_DATA("safe sharing", hermon_state_s::hs_fm_async_fatal hermon_state_s::hs_fw_sector)) /* * HERMON_IN_FASTREBOOT() shows if Hermon driver is at fastreboot. * This macro should be used to check if the mutex lock can be used * since the lock cannot be used if the driver is in the quiesce mode. */ #define HERMON_IN_FASTREBOOT(state) (state->hs_quiescing == B_TRUE) /* * Bit positions in the "hs_spec_qpflags" field above. The flags are (from * least significant to most): (QP0,Port1), (QP0,Port2), (QP1,Port1), and * (QP1,Port2). The masks are there to help with some specific allocation * and freeing operations */ #define HERMON_SPECIAL_QP0_RSRC 0 #define HERMON_SPECIAL_QP0_RSRC_MASK 0x3 #define HERMON_SPECIAL_QP1_RSRC 2 #define HERMON_SPECIAL_QP1_RSRC_MASK 0xC /* * These flags specifies additional behaviors on database access. * HERMON_UMAP_DB_REMOVE, for example, specifies that (if found) the database * entry should be removed from the database. HERMON_UMAP_DB_IGNORE_INSTANCE * specifies that a particular database query should ignore value in the * "tdb_instance" field as a criterion for the search. */ #define HERMON_UMAP_DB_REMOVE (1 << 0) #define HERMON_UMAP_DB_IGNORE_INSTANCE (1 << 1) /* * The hermon_umap_db_t structure contains what is referred to throughout the * driver code as the "userland resources database". This structure contains * all the necessary information to track resources that have been prepared * for direct-from-userland access. There is an AVL tree ("hdl_umapdb_avl") * which consists of the "hermon_umap_db_entry_t" (below) and a lock to ensure * atomic access when adding or removing entries from the database. */ typedef struct hermon_umap_db_s { kmutex_t hdl_umapdb_lock; avl_tree_t hdl_umapdb_avl; } hermon_umap_db_t; /* * The hermon_umap_db_priv_t structure currently contains information necessary * to provide the "on close" callback to the firmware flash interfaces. It * is intended that this structure could be extended to enable other "on * close" callbacks as well. */ typedef struct hermon_umap_db_priv_s { int (*hdp_cb)(void *); void *hdp_arg; } hermon_umap_db_priv_t; /* * The hermon_umap_db_common_t structure contains fields which are common * between the database entries ("hermon_umap_db_entry_t") and the structure * used to contain the search criteria ("hermon_umap_db_query_t"). This * structure contains a key, a resource type (described above), an instance * (corresponding to the driver instance which inserted the database entry), * and a "value" field. Typically, "hdb_value" is a pointer to a Hermon * resource object. Although for memory regions, the value field corresponds * to the ddi_umem_cookie_t for the pinned userland memory. * The structure also includes a placeholder for private data ("hdb_priv"). * Currently this data is being used for holding "on close" callback * information to allow certain kinds of cleanup even if a userland process * prematurely exits. */ typedef struct hermon_umap_db_common_s { uint64_t hdb_key; uint64_t hdb_value; uint_t hdb_type; uint_t hdb_instance; void *hdb_priv; } hermon_umap_db_common_t; /* * The hermon_umap_db_entry_t structure is the entry in "userland resources * database". As required by the AVL framework, each entry contains an * "avl_node_t". Then, as required to implement the database, each entry * contains a "hermon_umap_db_common_t" structure used to contain all of the * relevant entries. */ typedef struct hermon_umap_db_entry_s { avl_node_t hdbe_avlnode; hermon_umap_db_common_t hdbe_common; } hermon_umap_db_entry_t; /* * The hermon_umap_db_query_t structure is used in queries to the "userland * resources database". In addition to the "hermon_umap_db_common_t" structure * used to contain the various search criteria, this structure also contains * a flags field "hqdb_flags" which can be used to specify additional behaviors * (as described above). Specifically, the flags field can be used to specify * that an entry should be removed from the database, if found, and to * specify whether the database lookup should consider "tdb_instance" in the * search. */ typedef struct hermon_umap_db_query_s { uint_t hqdb_flags; hermon_umap_db_common_t hqdb_common; } hermon_umap_db_query_t; _NOTE(MUTEX_PROTECTS_DATA(hermon_umap_db_s::hdl_umapdb_lock, hermon_umap_db_entry_s::hdbe_avlnode hermon_umap_db_entry_s::hdbe_common.hdb_key hermon_umap_db_entry_s::hdbe_common.hdb_value hermon_umap_db_entry_s::hdbe_common.hdb_type hermon_umap_db_entry_s::hdbe_common.hdb_instance)) /* * The hermon_devmap_track_t structure contains all the necessary information * to track resources that have been mapped through devmap. There is a * back-pointer to the Hermon softstate, the logical offset corresponding with * the mapped resource, the size of the mapped resource (zero indicates an * "invalid mapping"), and a reference count and lock used to determine when * to free the structure (specifically, this is necessary to handle partial * unmappings). */ typedef struct hermon_devmap_track_s { hermon_state_t *hdt_state; uint64_t hdt_offset; uint_t hdt_size; int hdt_refcnt; kmutex_t hdt_lock; } hermon_devmap_track_t; #define HERMON_ICM_SPLIT 64 #define HERMON_ICM_SPAN 4096 #define hermon_bitmap(bitmap, dma_info, icm_table, split_index) \ bitmap = (icm_table)->icm_bitmap[split_index]; \ if (bitmap == NULL) { \ _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*(icm_table))) \ int num_spans = (icm_table)->num_spans; \ bitmap = \ (icm_table)->icm_bitmap[split_index] = \ kmem_zalloc((num_spans + 7) / 8, KM_SLEEP); \ ASSERT((icm_table)->icm_dma[split_index] == NULL); \ (icm_table)->icm_dma[split_index] = \ kmem_zalloc(num_spans * sizeof (hermon_dma_info_t), \ KM_SLEEP); \ } \ dma_info = (icm_table)->icm_dma[split_index] /* * The hermon_icm_table_t encodes data pertaining to a given ICM table, and * holds an array of hermon_dma_info_t's related to its backing memory. Each * ICM table is sized during initialization, but real memory is allocated * and mapped into and out of ICM in the device throughout the life of the * instance. We use a bitmap to determine whether or not a given ICM object * has memory backing it or not, and an array of hermon_dma_info_t's to house * the actual allocations. Memory is allocated in chunks of span_size, stored * in the icm_dma array, and can later be looked up by using the bitmap index. * The total number of ICM spans is equal to table_size / span_size. We also * keep track of the ICM characteristics, such as ICM object size and the * number of entries in the ICM area. */ struct hermon_icm_table_s { kmutex_t icm_table_lock; kcondvar_t icm_table_cv; uint8_t icm_busy; hermon_rsrc_type_t icm_type; uint64_t icm_baseaddr; uint64_t table_size; uint64_t num_entries; /* maximum #entries */ uint32_t object_size; uint32_t span; /* #rsrc's per span */ uint32_t num_spans; /* #dmainfos in icm_dma */ uint32_t split_shift; uint32_t span_mask; uint32_t span_shift; uint32_t rsrc_mask; uint16_t log_num_entries; uint16_t log_object_size; /* two arrays of pointers, each pointer points to arrays */ uint8_t *icm_bitmap[HERMON_ICM_SPLIT]; hermon_dma_info_t *icm_dma[HERMON_ICM_SPLIT]; }; /* * Split the rsrc index into three pieces: * * index1 - icm_bitmap[HERMON_ICM_SPLIT], icm_dma[HERMON_ICM_SPLIT] * index2 - bitmap[], dma[] * offset - rsrc within the icm mapping */ #define hermon_index(index1, index2, rindx, table, offset) \ index1 = (rindx) >> table->split_shift; \ index2 = ((rindx) & table->span_mask) >> table->span_shift; \ offset = (rindx) & table->rsrc_mask /* Defined in hermon.c */ int hermon_dma_alloc(hermon_state_t *state, hermon_dma_info_t *dma_info, uint16_t opcode); void hermon_dma_attr_init(hermon_state_t *state, ddi_dma_attr_t *dma_attr); void hermon_dma_free(hermon_dma_info_t *info); int hermon_icm_alloc(hermon_state_t *state, hermon_rsrc_type_t type, uint32_t icm_index1, uint32_t icm_index2); void hermon_icm_free(hermon_state_t *state, hermon_rsrc_type_t type, uint32_t icm_index1, uint32_t icm_index2); /* Defined in hermon_umap.c */ int hermon_devmap(dev_t dev, devmap_cookie_t dhp, offset_t off, size_t len, size_t *maplen, uint_t model); ibt_status_t hermon_umap_ci_data_in(hermon_state_t *state, ibt_ci_data_flags_t flags, ibt_object_type_t object, void *hdl, void *data_p, size_t data_sz); ibt_status_t hermon_umap_ci_data_out(hermon_state_t *state, ibt_ci_data_flags_t flags, ibt_object_type_t object, void *hdl, void *data_p, size_t data_sz); void hermon_umap_db_init(void); void hermon_umap_db_fini(void); hermon_umap_db_entry_t *hermon_umap_db_alloc(uint_t instance, uint64_t key, uint_t type, uint64_t value); void hermon_umap_db_free(hermon_umap_db_entry_t *umapdb); void hermon_umap_db_add(hermon_umap_db_entry_t *umapdb); void hermon_umap_db_add_nolock(hermon_umap_db_entry_t *umapdb); int hermon_umap_db_find(uint_t instance, uint64_t key, uint_t type, uint64_t *value, uint_t flags, hermon_umap_db_entry_t **umapdb); int hermon_umap_db_find_nolock(uint_t instance, uint64_t key, uint_t type, uint64_t *value, uint_t flags, hermon_umap_db_entry_t **umapdb); void hermon_umap_umemlock_cb(ddi_umem_cookie_t *umem_cookie); int hermon_umap_db_set_onclose_cb(dev_t dev, uint64_t flag, int (*callback)(void *), void *arg); int hermon_umap_db_clear_onclose_cb(dev_t dev, uint64_t flag); int hermon_umap_db_handle_onclose_cb(hermon_umap_db_priv_t *priv); int hermon_rsrc_hw_entries_init(hermon_state_t *state, hermon_rsrc_hw_entry_info_t *info); void hermon_rsrc_hw_entries_fini(hermon_state_t *state, hermon_rsrc_hw_entry_info_t *info); #ifdef __cplusplus } #endif #endif /* _SYS_IB_ADAPTERS_HERMON_H */