#include <sys/sysmacros.h>
#include <sys/types.h>
#include <sys/conf.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/modctl.h>
#include <sys/bitmap.h>
#include <sys/ib/adapters/hermon/hermon.h>
uint32_t hermon_log_num_qp = HERMON_NUM_QP_SHIFT;
uint32_t hermon_log_num_cq = HERMON_NUM_CQ_SHIFT;
uint32_t hermon_log_num_srq = HERMON_NUM_SRQ_SHIFT;
uint32_t hermon_wqe_max_sgl = HERMON_NUM_SGL_PER_WQE;
uint32_t hermon_srq_max_sgl = HERMON_SRQ_MAX_SGL;
uint32_t hermon_log_num_rdb_per_qp = HERMON_LOG_NUM_RDB_PER_QP;
uint32_t hermon_log_num_mcg = HERMON_NUM_MCG_SHIFT;
uint32_t hermon_num_qp_per_mcg = HERMON_NUM_QP_PER_MCG;
uint32_t hermon_log_num_mcg_hash = HERMON_NUM_MCG_HASH_SHIFT;
uint32_t hermon_log_num_ah = HERMON_NUM_AH_SHIFT;
uint32_t hermon_log_num_eq = HERMON_NUM_EQ_SHIFT;
uint32_t hermon_log_eq_sz = HERMON_DEFAULT_EQ_SZ_SHIFT;
uint32_t hermon_log_num_mtt = HERMON_NUM_MTT_SHIFT;
uint32_t hermon_log_num_dmpt = HERMON_NUM_DMPT_SHIFT;
uint32_t hermon_log_max_mrw_sz = HERMON_MAX_MEM_MPT_SHIFT;
uint32_t hermon_log_num_uar = HERMON_NUM_UAR_SHIFT;
uint32_t hermon_fmr_num_remaps = HERMON_FMR_MAX_REMAPS;
uint32_t hermon_log_num_inmbox = HERMON_NUM_MAILBOXES_SHIFT;
uint32_t hermon_log_num_outmbox = HERMON_NUM_MAILBOXES_SHIFT;
uint32_t hermon_log_inmbox_size = HERMON_MBOX_SIZE_SHIFT;
uint32_t hermon_log_outmbox_size = HERMON_MBOX_SIZE_SHIFT;
uint32_t hermon_log_num_intr_inmbox = HERMON_NUM_INTR_MAILBOXES_SHIFT;
uint32_t hermon_log_num_intr_outmbox = HERMON_NUM_INTR_MAILBOXES_SHIFT;
uint32_t hermon_log_num_pd = HERMON_NUM_PD_SHIFT;
uint32_t hermon_log_max_pkeytbl = HERMON_NUM_PKEYTBL_SHIFT;
uint32_t hermon_log_max_gidtbl = HERMON_NUM_GIDTBL_SHIFT;
uint32_t hermon_max_mtu = HERMON_MAX_MTU;
uint32_t hermon_max_port_width = HERMON_MAX_PORT_WIDTH;
uint32_t hermon_max_vlcap = HERMON_MAX_VLCAP;
uint32_t hermon_qp0_agents_in_fw = 0;
uint32_t hermon_qp1_agents_in_fw = 0;
uint32_t hermon_iommu_bypass = 1;
uint32_t hermon_kernel_data_ro = HERMON_RO_ENABLED;
uint32_t hermon_user_data_ro = HERMON_RO_ENABLED;
uint32_t hermon_use_msi_if_avail = 1;
uint32_t hermon_sw_reset_delay = HERMON_SW_RESET_DELAY;
uint32_t hermon_cmd_poll_delay = HERMON_CMD_POLL_DELAY;
uint32_t hermon_cmd_poll_max = HERMON_CMD_POLL_MAX;
uint32_t hermon_qp_ackreq_freq = HERMON_QP_ACKREQ_FREQ;
static void hermon_cfg_wqe_sizes(hermon_state_t *state,
hermon_cfg_profile_t *cp);
#ifdef __sparc
static void hermon_check_iommu_bypass(hermon_state_t *state,
hermon_cfg_profile_t *cp);
#endif
int
hermon_cfg_profile_init_phase1(hermon_state_t *state)
{
hermon_cfg_profile_t *cp;
cp = (hermon_cfg_profile_t *)kmem_zalloc(sizeof (hermon_cfg_profile_t),
KM_SLEEP);
cp->cp_qp0_agents_in_fw = hermon_qp0_agents_in_fw;
cp->cp_qp1_agents_in_fw = hermon_qp1_agents_in_fw;
cp->cp_sw_reset_delay = hermon_sw_reset_delay;
cp->cp_cmd_poll_delay = hermon_cmd_poll_delay;
cp->cp_cmd_poll_max = hermon_cmd_poll_max;
cp->cp_ackreq_freq = hermon_qp_ackreq_freq;
cp->cp_fmr_max_remaps = hermon_fmr_num_remaps;
if (state->hs_cfg_profile_setting == HERMON_CFG_MEMFREE) {
cp->cp_log_num_outmbox = hermon_log_num_outmbox;
cp->cp_log_outmbox_size = hermon_log_outmbox_size;
cp->cp_log_num_inmbox = hermon_log_num_inmbox;
cp->cp_log_inmbox_size = hermon_log_inmbox_size;
cp->cp_log_num_intr_inmbox = hermon_log_num_intr_inmbox;
cp->cp_log_num_intr_outmbox = hermon_log_num_intr_outmbox;
} else {
return (DDI_FAILURE);
}
#ifdef __sparc
if (hermon_iommu_bypass == 1) {
hermon_check_iommu_bypass(state, cp);
} else {
cp->cp_iommu_bypass = HERMON_BINDMEM_NORMAL;
}
#else
cp->cp_iommu_bypass = HERMON_BINDMEM_NORMAL;
#endif
state->hs_cfg_profile = cp;
return (DDI_SUCCESS);
}
int
hermon_cfg_profile_init_phase2(hermon_state_t *state)
{
hermon_cfg_profile_t *cp;
hermon_hw_querydevlim_t *devlim;
hermon_hw_query_port_t *port;
uint32_t num, size;
int i;
devlim = &state->hs_devlim;
port = &state->hs_queryport;
cp = state->hs_cfg_profile;
if (state->hs_cfg_profile_setting != HERMON_CFG_MEMFREE) {
return (DDI_FAILURE);
}
cp->cp_log_num_mtt = min(hermon_log_num_mtt, devlim->log_max_mtt);
cp->cp_log_num_dmpt = min(hermon_log_num_dmpt, devlim->log_max_dmpt);
cp->cp_log_num_cmpt = HERMON_LOG_CMPT_PER_TYPE + 2;
cp->cp_log_max_mrw_sz = min(hermon_log_max_mrw_sz,
devlim->log_max_mrw_sz);
cp->cp_log_num_pd = min(hermon_log_num_pd, devlim->log_max_pd);
cp->cp_log_num_qp = min(hermon_log_num_qp, devlim->log_max_qp);
cp->cp_log_num_cq = min(hermon_log_num_cq, devlim->log_max_cq);
cp->cp_log_num_srq = min(hermon_log_num_srq, devlim->log_max_srq);
cp->cp_log_num_eq = min(hermon_log_num_eq, devlim->log_max_eq);
cp->cp_log_eq_sz = min(hermon_log_eq_sz, devlim->log_max_eq_sz);
cp->cp_log_num_rdb = cp->cp_log_num_qp +
min(hermon_log_num_rdb_per_qp, devlim->log_max_ra_req_qp);
cp->cp_hca_max_rdma_in_qp = cp->cp_hca_max_rdma_out_qp =
1 << min(hermon_log_num_rdb_per_qp, devlim->log_max_ra_req_qp);
cp->cp_num_qp_per_mcg = max(hermon_num_qp_per_mcg,
HERMON_NUM_QP_PER_MCG_MIN);
cp->cp_num_qp_per_mcg = min(cp->cp_num_qp_per_mcg,
(1 << devlim->log_max_qp_mcg) - 8);
cp->cp_num_qp_per_mcg = (1 << highbit(cp->cp_num_qp_per_mcg + 7)) - 8;
cp->cp_log_num_mcg = min(hermon_log_num_mcg, devlim->log_max_mcg);
cp->cp_log_num_mcg_hash = hermon_log_num_mcg_hash;
cp->cp_srq_resize_enabled = 0;
size = devlim->log_max_uar_sz;
num = (20 + size) - 13;
if (devlim->blu_flm)
num -= 1;
cp->cp_log_num_uar = min(hermon_log_num_uar, num);
state->hs_kernel_uar_index = (devlim->num_rsvd_uar > 128) ?
devlim->num_rsvd_uar : 128;
cp->cp_log_max_pkeytbl = port->log_max_pkey;
cp->cp_log_max_qp_sz = devlim->log_max_qp_sz;
cp->cp_log_max_cq_sz = devlim->log_max_cq_sz;
cp->cp_log_max_srq_sz = devlim->log_max_srq_sz;
cp->cp_log_max_gidtbl = port->log_max_gid;
cp->cp_max_mtu = port->ib_mtu;
cp->cp_max_port_width = port->ib_port_wid;
cp->cp_max_vlcap = port->max_vl;
cp->cp_log_num_ah = hermon_log_num_ah;
cp->cp_num_ports = devlim->num_ports;
if (cp->cp_num_ports > HERMON_MAX_PORTS) {
cmn_err(CE_CONT, "device has more ports (%d) than are "
"supported; Using %d ports\n",
cp->cp_num_ports, HERMON_MAX_PORTS);
cp->cp_num_ports = HERMON_MAX_PORTS;
};
for (i = 0; i < HERMON_MAX_PORTS; i++) {
state->hs_pkey[i] = kmem_zalloc((1 << cp->cp_log_max_pkeytbl) *
sizeof (ib_pkey_t), KM_SLEEP);
state->hs_guid[i] = kmem_zalloc((1 << cp->cp_log_max_gidtbl) *
sizeof (ib_guid_t), KM_SLEEP);
}
hermon_cfg_wqe_sizes(state, cp);
cp->cp_use_msi_if_avail = hermon_use_msi_if_avail;
#if !defined(_ELF64)
cp->cp_log_num_mtt -= 6;
cp->cp_log_num_dmpt -= 6;
cp->cp_log_num_pd -= 6;
cp->cp_log_num_qp -= 6;
cp->cp_log_num_cq -= 6;
cp->cp_log_num_srq -= 6;
cp->cp_log_num_rdb = cp->cp_log_num_qp +
min(hermon_log_num_rdb_per_qp, devlim->log_max_ra_req_qp);
cp->cp_hca_max_rdma_in_qp = cp->cp_hca_max_rdma_out_qp =
1 << min(hermon_log_num_rdb_per_qp, devlim->log_max_ra_req_qp);
#endif
return (DDI_SUCCESS);
}
void
hermon_cfg_profile_fini(hermon_state_t *state)
{
kmem_free(state->hs_cfg_profile, sizeof (hermon_cfg_profile_t));
}
static void
hermon_cfg_wqe_sizes(hermon_state_t *state, hermon_cfg_profile_t *cp)
{
uint_t max_size, log2;
uint_t max_sgl, real_max_sgl;
max_sgl = hermon_wqe_max_sgl;
max_size = (HERMON_QP_WQE_MLX_QP1_HDRS + (max_sgl << 4));
log2 = highbit(max_size);
if (ISP2(max_size)) {
log2 = log2 - 1;
}
max_size = (1 << log2);
max_size = min(max_size, state->hs_devlim.max_desc_sz_sq);
real_max_sgl = (max_size - HERMON_QP_WQE_MLX_QP1_HDRS) >> 4;
cp->cp_wqe_max_sgl = max_sgl;
cp->cp_wqe_real_max_sgl = real_max_sgl;
cp->cp_srq_max_sgl = hermon_srq_max_sgl;
}
#ifdef __sparc
static void
hermon_check_iommu_bypass(hermon_state_t *state, hermon_cfg_profile_t *cp)
{
ddi_dma_handle_t dmahdl;
ddi_dma_attr_t dma_attr;
int status;
ddi_acc_handle_t acc_hdl;
caddr_t kaddr;
size_t actual_len;
ddi_dma_cookie_t cookie;
uint_t cookiecnt;
hermon_dma_attr_init(state, &dma_attr);
dma_attr.dma_attr_flags = DDI_DMA_FORCE_PHYSICAL |
DDI_DMA_RELAXED_ORDERING;
status = ddi_dma_alloc_handle(state->hs_dip, &dma_attr,
DDI_DMA_SLEEP, NULL, &dmahdl);
if (status == DDI_DMA_BADATTR) {
cp->cp_iommu_bypass = HERMON_BINDMEM_NORMAL;
return;
} else if (status != DDI_SUCCESS) {
hermon_kernel_data_ro = HERMON_RO_DISABLED;
hermon_user_data_ro = HERMON_RO_DISABLED;
cp->cp_iommu_bypass = HERMON_BINDMEM_BYPASS;
return;
} else {
cp->cp_iommu_bypass = HERMON_BINDMEM_BYPASS;
}
status = ddi_dma_mem_alloc(dmahdl, 256,
&state->hs_reg_accattr, DDI_DMA_CONSISTENT,
DDI_DMA_SLEEP, NULL, (caddr_t *)&kaddr, &actual_len, &acc_hdl);
if (status != DDI_SUCCESS) {
hermon_kernel_data_ro = HERMON_RO_DISABLED;
hermon_user_data_ro = HERMON_RO_DISABLED;
ddi_dma_free_handle(&dmahdl);
return;
}
status = ddi_dma_addr_bind_handle(dmahdl, NULL, kaddr, actual_len,
DDI_DMA_RDWR, DDI_DMA_SLEEP, NULL, &cookie, &cookiecnt);
if (status == DDI_DMA_MAPPED) {
(void) ddi_dma_unbind_handle(dmahdl);
} else {
hermon_kernel_data_ro = HERMON_RO_DISABLED;
hermon_user_data_ro = HERMON_RO_DISABLED;
}
ddi_dma_mem_free(&acc_hdl);
ddi_dma_free_handle(&dmahdl);
}
#endif