19517SBill.Taylor@Sun.COM /*
29517SBill.Taylor@Sun.COM * CDDL HEADER START
39517SBill.Taylor@Sun.COM *
49517SBill.Taylor@Sun.COM * The contents of this file are subject to the terms of the
59517SBill.Taylor@Sun.COM * Common Development and Distribution License (the "License").
69517SBill.Taylor@Sun.COM * You may not use this file except in compliance with the License.
79517SBill.Taylor@Sun.COM *
89517SBill.Taylor@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99517SBill.Taylor@Sun.COM * or http://www.opensolaris.org/os/licensing.
109517SBill.Taylor@Sun.COM * See the License for the specific language governing permissions
119517SBill.Taylor@Sun.COM * and limitations under the License.
129517SBill.Taylor@Sun.COM *
139517SBill.Taylor@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
149517SBill.Taylor@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159517SBill.Taylor@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
169517SBill.Taylor@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
179517SBill.Taylor@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
189517SBill.Taylor@Sun.COM *
199517SBill.Taylor@Sun.COM * CDDL HEADER END
209517SBill.Taylor@Sun.COM */
219517SBill.Taylor@Sun.COM
229517SBill.Taylor@Sun.COM /*
2312688SWilliam.Taylor@Oracle.COM * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
249517SBill.Taylor@Sun.COM */
259517SBill.Taylor@Sun.COM
269517SBill.Taylor@Sun.COM /*
279517SBill.Taylor@Sun.COM * hermon.c
289517SBill.Taylor@Sun.COM * Hermon (InfiniBand) HCA Driver attach/detach Routines
299517SBill.Taylor@Sun.COM *
309517SBill.Taylor@Sun.COM * Implements all the routines necessary for the attach, setup,
319517SBill.Taylor@Sun.COM * initialization (and subsequent possible teardown and detach) of the
329517SBill.Taylor@Sun.COM * Hermon InfiniBand HCA driver.
339517SBill.Taylor@Sun.COM */
349517SBill.Taylor@Sun.COM
359517SBill.Taylor@Sun.COM #include <sys/types.h>
369517SBill.Taylor@Sun.COM #include <sys/file.h>
379517SBill.Taylor@Sun.COM #include <sys/open.h>
389517SBill.Taylor@Sun.COM #include <sys/conf.h>
399517SBill.Taylor@Sun.COM #include <sys/ddi.h>
409517SBill.Taylor@Sun.COM #include <sys/sunddi.h>
419517SBill.Taylor@Sun.COM #include <sys/modctl.h>
429517SBill.Taylor@Sun.COM #include <sys/stat.h>
439517SBill.Taylor@Sun.COM #include <sys/pci.h>
449517SBill.Taylor@Sun.COM #include <sys/pci_cap.h>
459517SBill.Taylor@Sun.COM #include <sys/bitmap.h>
469517SBill.Taylor@Sun.COM #include <sys/policy.h>
479517SBill.Taylor@Sun.COM
489517SBill.Taylor@Sun.COM #include <sys/ib/adapters/hermon/hermon.h>
499517SBill.Taylor@Sun.COM
5012965SWilliam.Taylor@Oracle.COM /* /etc/system can tune this down, if that is desirable. */
5112965SWilliam.Taylor@Oracle.COM int hermon_msix_max = HERMON_MSIX_MAX;
5212965SWilliam.Taylor@Oracle.COM
539517SBill.Taylor@Sun.COM /* The following works around a problem in pre-2_7_000 firmware. */
549517SBill.Taylor@Sun.COM #define HERMON_FW_WORKAROUND
559517SBill.Taylor@Sun.COM
569517SBill.Taylor@Sun.COM int hermon_verbose = 0;
579517SBill.Taylor@Sun.COM
589517SBill.Taylor@Sun.COM /* Hermon HCA State Pointer */
599517SBill.Taylor@Sun.COM void *hermon_statep;
609517SBill.Taylor@Sun.COM
619778SEiji.Ota@Sun.COM int debug_vpd = 0;
629778SEiji.Ota@Sun.COM
639778SEiji.Ota@Sun.COM /* Disable the internal error-check polling thread */
649778SEiji.Ota@Sun.COM int hermon_no_inter_err_chk = 0;
659517SBill.Taylor@Sun.COM
669517SBill.Taylor@Sun.COM /*
679517SBill.Taylor@Sun.COM * The Hermon "userland resource database" is common to instances of the
689517SBill.Taylor@Sun.COM * Hermon HCA driver. This structure "hermon_userland_rsrc_db" contains all
699517SBill.Taylor@Sun.COM * the necessary information to maintain it.
709517SBill.Taylor@Sun.COM */
719517SBill.Taylor@Sun.COM hermon_umap_db_t hermon_userland_rsrc_db;
729517SBill.Taylor@Sun.COM
739517SBill.Taylor@Sun.COM static int hermon_attach(dev_info_t *, ddi_attach_cmd_t);
749517SBill.Taylor@Sun.COM static int hermon_detach(dev_info_t *, ddi_detach_cmd_t);
759517SBill.Taylor@Sun.COM static int hermon_open(dev_t *, int, int, cred_t *);
769517SBill.Taylor@Sun.COM static int hermon_close(dev_t, int, int, cred_t *);
779517SBill.Taylor@Sun.COM static int hermon_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
789517SBill.Taylor@Sun.COM
799517SBill.Taylor@Sun.COM static int hermon_drv_init(hermon_state_t *state, dev_info_t *dip,
809517SBill.Taylor@Sun.COM int instance);
819517SBill.Taylor@Sun.COM static void hermon_drv_fini(hermon_state_t *state);
829517SBill.Taylor@Sun.COM static void hermon_drv_fini2(hermon_state_t *state);
839517SBill.Taylor@Sun.COM static int hermon_isr_init(hermon_state_t *state);
849517SBill.Taylor@Sun.COM static void hermon_isr_fini(hermon_state_t *state);
859517SBill.Taylor@Sun.COM
869517SBill.Taylor@Sun.COM static int hermon_hw_init(hermon_state_t *state);
879517SBill.Taylor@Sun.COM
889517SBill.Taylor@Sun.COM static void hermon_hw_fini(hermon_state_t *state,
899517SBill.Taylor@Sun.COM hermon_drv_cleanup_level_t cleanup);
909517SBill.Taylor@Sun.COM static int hermon_soft_state_init(hermon_state_t *state);
919517SBill.Taylor@Sun.COM static void hermon_soft_state_fini(hermon_state_t *state);
929517SBill.Taylor@Sun.COM static int hermon_icm_config_setup(hermon_state_t *state,
939517SBill.Taylor@Sun.COM hermon_hw_initqueryhca_t *inithca);
949517SBill.Taylor@Sun.COM static void hermon_icm_tables_init(hermon_state_t *state);
959517SBill.Taylor@Sun.COM static void hermon_icm_tables_fini(hermon_state_t *state);
969517SBill.Taylor@Sun.COM static int hermon_icm_dma_init(hermon_state_t *state);
979517SBill.Taylor@Sun.COM static void hermon_icm_dma_fini(hermon_state_t *state);
989517SBill.Taylor@Sun.COM static void hermon_inithca_set(hermon_state_t *state,
999517SBill.Taylor@Sun.COM hermon_hw_initqueryhca_t *inithca);
1009517SBill.Taylor@Sun.COM static int hermon_hca_port_init(hermon_state_t *state);
1019517SBill.Taylor@Sun.COM static int hermon_hca_ports_shutdown(hermon_state_t *state, uint_t num_init);
1029517SBill.Taylor@Sun.COM static int hermon_internal_uarpg_init(hermon_state_t *state);
1039517SBill.Taylor@Sun.COM static void hermon_internal_uarpg_fini(hermon_state_t *state);
1049517SBill.Taylor@Sun.COM static int hermon_special_qp_contexts_reserve(hermon_state_t *state);
1059517SBill.Taylor@Sun.COM static void hermon_special_qp_contexts_unreserve(hermon_state_t *state);
1069517SBill.Taylor@Sun.COM static int hermon_sw_reset(hermon_state_t *state);
1079517SBill.Taylor@Sun.COM static int hermon_mcg_init(hermon_state_t *state);
1089517SBill.Taylor@Sun.COM static void hermon_mcg_fini(hermon_state_t *state);
1099517SBill.Taylor@Sun.COM static int hermon_fw_version_check(hermon_state_t *state);
1109517SBill.Taylor@Sun.COM static void hermon_device_info_report(hermon_state_t *state);
1119517SBill.Taylor@Sun.COM static int hermon_pci_capability_list(hermon_state_t *state,
1129517SBill.Taylor@Sun.COM ddi_acc_handle_t hdl);
1139517SBill.Taylor@Sun.COM static void hermon_pci_capability_vpd(hermon_state_t *state,
1149517SBill.Taylor@Sun.COM ddi_acc_handle_t hdl, uint_t offset);
1159517SBill.Taylor@Sun.COM static int hermon_pci_read_vpd(ddi_acc_handle_t hdl, uint_t offset,
1169517SBill.Taylor@Sun.COM uint32_t addr, uint32_t *data);
1179517SBill.Taylor@Sun.COM static int hermon_intr_or_msi_init(hermon_state_t *state);
1189517SBill.Taylor@Sun.COM static int hermon_add_intrs(hermon_state_t *state, int intr_type);
1199517SBill.Taylor@Sun.COM static int hermon_intr_or_msi_fini(hermon_state_t *state);
1209517SBill.Taylor@Sun.COM void hermon_pci_capability_msix(hermon_state_t *state, ddi_acc_handle_t hdl,
1219517SBill.Taylor@Sun.COM uint_t offset);
1229517SBill.Taylor@Sun.COM
1239517SBill.Taylor@Sun.COM static uint64_t hermon_size_icm(hermon_state_t *state);
1249517SBill.Taylor@Sun.COM
1259517SBill.Taylor@Sun.COM /* X86 fastreboot support */
1269517SBill.Taylor@Sun.COM static ushort_t get_msix_ctrl(dev_info_t *);
1279517SBill.Taylor@Sun.COM static size_t get_msix_tbl_size(dev_info_t *);
1289517SBill.Taylor@Sun.COM static size_t get_msix_pba_size(dev_info_t *);
1299517SBill.Taylor@Sun.COM static void hermon_set_msix_info(hermon_state_t *);
1309517SBill.Taylor@Sun.COM static int hermon_intr_disable(hermon_state_t *);
1319517SBill.Taylor@Sun.COM static int hermon_quiesce(dev_info_t *);
1329517SBill.Taylor@Sun.COM
1339517SBill.Taylor@Sun.COM
1349517SBill.Taylor@Sun.COM /* Character/Block Operations */
1359517SBill.Taylor@Sun.COM static struct cb_ops hermon_cb_ops = {
1369517SBill.Taylor@Sun.COM hermon_open, /* open */
1379517SBill.Taylor@Sun.COM hermon_close, /* close */
1389517SBill.Taylor@Sun.COM nodev, /* strategy (block) */
1399517SBill.Taylor@Sun.COM nodev, /* print (block) */
1409517SBill.Taylor@Sun.COM nodev, /* dump (block) */
1419517SBill.Taylor@Sun.COM nodev, /* read */
1429517SBill.Taylor@Sun.COM nodev, /* write */
1439517SBill.Taylor@Sun.COM hermon_ioctl, /* ioctl */
1449517SBill.Taylor@Sun.COM hermon_devmap, /* devmap */
1459517SBill.Taylor@Sun.COM NULL, /* mmap */
1469517SBill.Taylor@Sun.COM nodev, /* segmap */
1479517SBill.Taylor@Sun.COM nochpoll, /* chpoll */
1489517SBill.Taylor@Sun.COM ddi_prop_op, /* prop_op */
1499517SBill.Taylor@Sun.COM NULL, /* streams */
1509517SBill.Taylor@Sun.COM D_NEW | D_MP |
15112688SWilliam.Taylor@Oracle.COM D_64BIT | D_HOTPLUG |
1529517SBill.Taylor@Sun.COM D_DEVMAP, /* flags */
1539517SBill.Taylor@Sun.COM CB_REV /* rev */
1549517SBill.Taylor@Sun.COM };
1559517SBill.Taylor@Sun.COM
1569517SBill.Taylor@Sun.COM /* Driver Operations */
1579517SBill.Taylor@Sun.COM static struct dev_ops hermon_ops = {
1589517SBill.Taylor@Sun.COM DEVO_REV, /* struct rev */
1599517SBill.Taylor@Sun.COM 0, /* refcnt */
1609517SBill.Taylor@Sun.COM hermon_getinfo, /* getinfo */
1619517SBill.Taylor@Sun.COM nulldev, /* identify */
1629517SBill.Taylor@Sun.COM nulldev, /* probe */
1639517SBill.Taylor@Sun.COM hermon_attach, /* attach */
1649517SBill.Taylor@Sun.COM hermon_detach, /* detach */
1659517SBill.Taylor@Sun.COM nodev, /* reset */
1669517SBill.Taylor@Sun.COM &hermon_cb_ops, /* cb_ops */
1679517SBill.Taylor@Sun.COM NULL, /* bus_ops */
1689517SBill.Taylor@Sun.COM nodev, /* power */
1699517SBill.Taylor@Sun.COM hermon_quiesce, /* devo_quiesce */
1709517SBill.Taylor@Sun.COM };
1719517SBill.Taylor@Sun.COM
1729517SBill.Taylor@Sun.COM /* Module Driver Info */
1739517SBill.Taylor@Sun.COM static struct modldrv hermon_modldrv = {
1749517SBill.Taylor@Sun.COM &mod_driverops,
1759517SBill.Taylor@Sun.COM "ConnectX IB Driver",
1769517SBill.Taylor@Sun.COM &hermon_ops
1779517SBill.Taylor@Sun.COM };
1789517SBill.Taylor@Sun.COM
1799517SBill.Taylor@Sun.COM /* Module Linkage */
1809517SBill.Taylor@Sun.COM static struct modlinkage hermon_modlinkage = {
1819517SBill.Taylor@Sun.COM MODREV_1,
1829517SBill.Taylor@Sun.COM &hermon_modldrv,
1839517SBill.Taylor@Sun.COM NULL
1849517SBill.Taylor@Sun.COM };
1859517SBill.Taylor@Sun.COM
1869517SBill.Taylor@Sun.COM /*
1879517SBill.Taylor@Sun.COM * This extern refers to the ibc_operations_t function vector that is defined
1889517SBill.Taylor@Sun.COM * in the hermon_ci.c file.
1899517SBill.Taylor@Sun.COM */
1909517SBill.Taylor@Sun.COM extern ibc_operations_t hermon_ibc_ops;
1919517SBill.Taylor@Sun.COM
1929517SBill.Taylor@Sun.COM /*
1939517SBill.Taylor@Sun.COM * _init()
1949517SBill.Taylor@Sun.COM */
1959517SBill.Taylor@Sun.COM int
_init()1969517SBill.Taylor@Sun.COM _init()
1979517SBill.Taylor@Sun.COM {
1989517SBill.Taylor@Sun.COM int status;
1999517SBill.Taylor@Sun.COM
2009517SBill.Taylor@Sun.COM status = ddi_soft_state_init(&hermon_statep, sizeof (hermon_state_t),
2019517SBill.Taylor@Sun.COM (size_t)HERMON_INITIAL_STATES);
2029517SBill.Taylor@Sun.COM if (status != 0) {
2039517SBill.Taylor@Sun.COM return (status);
2049517SBill.Taylor@Sun.COM }
2059517SBill.Taylor@Sun.COM
2069517SBill.Taylor@Sun.COM status = ibc_init(&hermon_modlinkage);
2079517SBill.Taylor@Sun.COM if (status != 0) {
2089517SBill.Taylor@Sun.COM ddi_soft_state_fini(&hermon_statep);
2099517SBill.Taylor@Sun.COM return (status);
2109517SBill.Taylor@Sun.COM }
2119517SBill.Taylor@Sun.COM
2129517SBill.Taylor@Sun.COM status = mod_install(&hermon_modlinkage);
2139517SBill.Taylor@Sun.COM if (status != 0) {
2149517SBill.Taylor@Sun.COM ibc_fini(&hermon_modlinkage);
2159517SBill.Taylor@Sun.COM ddi_soft_state_fini(&hermon_statep);
2169517SBill.Taylor@Sun.COM return (status);
2179517SBill.Taylor@Sun.COM }
2189517SBill.Taylor@Sun.COM
2199517SBill.Taylor@Sun.COM /* Initialize the Hermon "userland resources database" */
2209517SBill.Taylor@Sun.COM hermon_umap_db_init();
2219517SBill.Taylor@Sun.COM
2229517SBill.Taylor@Sun.COM return (status);
2239517SBill.Taylor@Sun.COM }
2249517SBill.Taylor@Sun.COM
2259517SBill.Taylor@Sun.COM
2269517SBill.Taylor@Sun.COM /*
2279517SBill.Taylor@Sun.COM * _info()
2289517SBill.Taylor@Sun.COM */
2299517SBill.Taylor@Sun.COM int
_info(struct modinfo * modinfop)2309517SBill.Taylor@Sun.COM _info(struct modinfo *modinfop)
2319517SBill.Taylor@Sun.COM {
2329517SBill.Taylor@Sun.COM int status;
2339517SBill.Taylor@Sun.COM
2349517SBill.Taylor@Sun.COM status = mod_info(&hermon_modlinkage, modinfop);
2359517SBill.Taylor@Sun.COM return (status);
2369517SBill.Taylor@Sun.COM }
2379517SBill.Taylor@Sun.COM
2389517SBill.Taylor@Sun.COM
2399517SBill.Taylor@Sun.COM /*
2409517SBill.Taylor@Sun.COM * _fini()
2419517SBill.Taylor@Sun.COM */
2429517SBill.Taylor@Sun.COM int
_fini()2439517SBill.Taylor@Sun.COM _fini()
2449517SBill.Taylor@Sun.COM {
2459517SBill.Taylor@Sun.COM int status;
2469517SBill.Taylor@Sun.COM
2479517SBill.Taylor@Sun.COM status = mod_remove(&hermon_modlinkage);
2489517SBill.Taylor@Sun.COM if (status != 0) {
2499517SBill.Taylor@Sun.COM return (status);
2509517SBill.Taylor@Sun.COM }
2519517SBill.Taylor@Sun.COM
2529517SBill.Taylor@Sun.COM /* Destroy the Hermon "userland resources database" */
2539517SBill.Taylor@Sun.COM hermon_umap_db_fini();
2549517SBill.Taylor@Sun.COM
2559517SBill.Taylor@Sun.COM ibc_fini(&hermon_modlinkage);
2569517SBill.Taylor@Sun.COM ddi_soft_state_fini(&hermon_statep);
2579517SBill.Taylor@Sun.COM
2589517SBill.Taylor@Sun.COM return (status);
2599517SBill.Taylor@Sun.COM }
2609517SBill.Taylor@Sun.COM
2619517SBill.Taylor@Sun.COM
2629517SBill.Taylor@Sun.COM /*
2639517SBill.Taylor@Sun.COM * hermon_getinfo()
2649517SBill.Taylor@Sun.COM */
2659517SBill.Taylor@Sun.COM /* ARGSUSED */
2669517SBill.Taylor@Sun.COM static int
hermon_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** result)2679517SBill.Taylor@Sun.COM hermon_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
2689517SBill.Taylor@Sun.COM {
2699517SBill.Taylor@Sun.COM dev_t dev;
2709517SBill.Taylor@Sun.COM hermon_state_t *state;
2719517SBill.Taylor@Sun.COM minor_t instance;
2729517SBill.Taylor@Sun.COM
2739517SBill.Taylor@Sun.COM switch (cmd) {
2749517SBill.Taylor@Sun.COM case DDI_INFO_DEVT2DEVINFO:
2759517SBill.Taylor@Sun.COM dev = (dev_t)arg;
2769517SBill.Taylor@Sun.COM instance = HERMON_DEV_INSTANCE(dev);
2779517SBill.Taylor@Sun.COM state = ddi_get_soft_state(hermon_statep, instance);
2789517SBill.Taylor@Sun.COM if (state == NULL) {
2799517SBill.Taylor@Sun.COM return (DDI_FAILURE);
2809517SBill.Taylor@Sun.COM }
2819517SBill.Taylor@Sun.COM *result = (void *)state->hs_dip;
2829517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
2839517SBill.Taylor@Sun.COM
2849517SBill.Taylor@Sun.COM case DDI_INFO_DEVT2INSTANCE:
2859517SBill.Taylor@Sun.COM dev = (dev_t)arg;
2869517SBill.Taylor@Sun.COM instance = HERMON_DEV_INSTANCE(dev);
2879517SBill.Taylor@Sun.COM *result = (void *)(uintptr_t)instance;
2889517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
2899517SBill.Taylor@Sun.COM
2909517SBill.Taylor@Sun.COM default:
2919517SBill.Taylor@Sun.COM break;
2929517SBill.Taylor@Sun.COM }
2939517SBill.Taylor@Sun.COM
2949517SBill.Taylor@Sun.COM return (DDI_FAILURE);
2959517SBill.Taylor@Sun.COM }
2969517SBill.Taylor@Sun.COM
2979517SBill.Taylor@Sun.COM
2989517SBill.Taylor@Sun.COM /*
2999517SBill.Taylor@Sun.COM * hermon_open()
3009517SBill.Taylor@Sun.COM */
3019517SBill.Taylor@Sun.COM /* ARGSUSED */
3029517SBill.Taylor@Sun.COM static int
hermon_open(dev_t * devp,int flag,int otyp,cred_t * credp)3039517SBill.Taylor@Sun.COM hermon_open(dev_t *devp, int flag, int otyp, cred_t *credp)
3049517SBill.Taylor@Sun.COM {
3059517SBill.Taylor@Sun.COM hermon_state_t *state;
3069517SBill.Taylor@Sun.COM hermon_rsrc_t *rsrcp;
3079517SBill.Taylor@Sun.COM hermon_umap_db_entry_t *umapdb, *umapdb2;
3089517SBill.Taylor@Sun.COM minor_t instance;
3099517SBill.Taylor@Sun.COM uint64_t key, value;
3109517SBill.Taylor@Sun.COM uint_t hr_indx;
3119517SBill.Taylor@Sun.COM dev_t dev;
3129517SBill.Taylor@Sun.COM int status;
3139517SBill.Taylor@Sun.COM
3149517SBill.Taylor@Sun.COM instance = HERMON_DEV_INSTANCE(*devp);
3159517SBill.Taylor@Sun.COM state = ddi_get_soft_state(hermon_statep, instance);
3169517SBill.Taylor@Sun.COM if (state == NULL) {
3179517SBill.Taylor@Sun.COM return (ENXIO);
3189517SBill.Taylor@Sun.COM }
3199517SBill.Taylor@Sun.COM
3209517SBill.Taylor@Sun.COM /*
3219517SBill.Taylor@Sun.COM * Only allow driver to be opened for character access, and verify
3229517SBill.Taylor@Sun.COM * whether exclusive access is allowed.
3239517SBill.Taylor@Sun.COM */
3249517SBill.Taylor@Sun.COM if ((otyp != OTYP_CHR) || ((flag & FEXCL) &&
3259517SBill.Taylor@Sun.COM secpolicy_excl_open(credp) != 0)) {
3269517SBill.Taylor@Sun.COM return (EINVAL);
3279517SBill.Taylor@Sun.COM }
3289517SBill.Taylor@Sun.COM
3299517SBill.Taylor@Sun.COM /*
3309517SBill.Taylor@Sun.COM * Search for the current process PID in the "userland resources
3319517SBill.Taylor@Sun.COM * database". If it is not found, then attempt to allocate a UAR
3329517SBill.Taylor@Sun.COM * page and add the ("key", "value") pair to the database.
3339517SBill.Taylor@Sun.COM * Note: As a last step we always return a devp appropriate for
3349517SBill.Taylor@Sun.COM * the open. Either we return a new minor number (based on the
3359517SBill.Taylor@Sun.COM * instance and the UAR page index) or we return the current minor
3369517SBill.Taylor@Sun.COM * number for the given client process.
3379517SBill.Taylor@Sun.COM *
3389517SBill.Taylor@Sun.COM * We also add an entry to the database to allow for lookup from
3399517SBill.Taylor@Sun.COM * "dev_t" to the current process PID. This is necessary because,
3409517SBill.Taylor@Sun.COM * under certain circumstance, the process PID that calls the Hermon
3419517SBill.Taylor@Sun.COM * close() entry point may not be the same as the one who called
3429517SBill.Taylor@Sun.COM * open(). Specifically, this can happen if a child process calls
3439517SBill.Taylor@Sun.COM * the Hermon's open() entry point, gets a UAR page, maps it out (using
3449517SBill.Taylor@Sun.COM * mmap()), and then exits without calling munmap(). Because mmap()
3459517SBill.Taylor@Sun.COM * adds a reference to the file descriptor, at the exit of the child
3469517SBill.Taylor@Sun.COM * process the file descriptor is "inherited" by the parent (and will
3479517SBill.Taylor@Sun.COM * be close()'d by the parent's PID only when it exits).
3489517SBill.Taylor@Sun.COM *
3499517SBill.Taylor@Sun.COM * Note: We use the hermon_umap_db_find_nolock() and
3509517SBill.Taylor@Sun.COM * hermon_umap_db_add_nolock() database access routines below (with
3519517SBill.Taylor@Sun.COM * an explicit mutex_enter of the database lock - "hdl_umapdb_lock")
3529517SBill.Taylor@Sun.COM * to ensure that the multiple accesses (in this case searching for,
3539517SBill.Taylor@Sun.COM * and then adding _two_ database entries) can be done atomically.
3549517SBill.Taylor@Sun.COM */
3559517SBill.Taylor@Sun.COM key = ddi_get_pid();
3569517SBill.Taylor@Sun.COM mutex_enter(&hermon_userland_rsrc_db.hdl_umapdb_lock);
3579517SBill.Taylor@Sun.COM status = hermon_umap_db_find_nolock(instance, key,
3589517SBill.Taylor@Sun.COM MLNX_UMAP_UARPG_RSRC, &value, 0, NULL);
3599517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
3609517SBill.Taylor@Sun.COM /*
3619517SBill.Taylor@Sun.COM * If we are in 'maintenance mode', we cannot alloc a UAR page.
3629517SBill.Taylor@Sun.COM * But we still need some rsrcp value, and a mostly unique
3639517SBill.Taylor@Sun.COM * hr_indx value. So we set rsrcp to NULL for maintenance
3649517SBill.Taylor@Sun.COM * mode, and use a rolling count for hr_indx. The field
3659517SBill.Taylor@Sun.COM * 'hs_open_hr_indx' is used only in this maintenance mode
3669517SBill.Taylor@Sun.COM * condition.
3679517SBill.Taylor@Sun.COM *
3689517SBill.Taylor@Sun.COM * Otherwise, if we are in operational mode then we allocate
3699517SBill.Taylor@Sun.COM * the UAR page as normal, and use the rsrcp value and tr_indx
3709517SBill.Taylor@Sun.COM * value from that allocation.
3719517SBill.Taylor@Sun.COM */
3729517SBill.Taylor@Sun.COM if (!HERMON_IS_OPERATIONAL(state->hs_operational_mode)) {
3739517SBill.Taylor@Sun.COM rsrcp = NULL;
3749517SBill.Taylor@Sun.COM hr_indx = state->hs_open_ar_indx++;
3759517SBill.Taylor@Sun.COM } else {
3769517SBill.Taylor@Sun.COM /* Allocate a new UAR page for this process */
3779517SBill.Taylor@Sun.COM status = hermon_rsrc_alloc(state, HERMON_UARPG, 1,
3789517SBill.Taylor@Sun.COM HERMON_NOSLEEP, &rsrcp);
3799517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
3809517SBill.Taylor@Sun.COM mutex_exit(
3819517SBill.Taylor@Sun.COM &hermon_userland_rsrc_db.hdl_umapdb_lock);
3829517SBill.Taylor@Sun.COM return (EAGAIN);
3839517SBill.Taylor@Sun.COM }
3849517SBill.Taylor@Sun.COM
3859517SBill.Taylor@Sun.COM hr_indx = rsrcp->hr_indx;
3869517SBill.Taylor@Sun.COM }
3879517SBill.Taylor@Sun.COM
3889517SBill.Taylor@Sun.COM /*
3899517SBill.Taylor@Sun.COM * Allocate an entry to track the UAR page resource in the
3909517SBill.Taylor@Sun.COM * "userland resources database".
3919517SBill.Taylor@Sun.COM */
3929517SBill.Taylor@Sun.COM umapdb = hermon_umap_db_alloc(instance, key,
3939517SBill.Taylor@Sun.COM MLNX_UMAP_UARPG_RSRC, (uint64_t)(uintptr_t)rsrcp);
3949517SBill.Taylor@Sun.COM if (umapdb == NULL) {
3959517SBill.Taylor@Sun.COM mutex_exit(&hermon_userland_rsrc_db.hdl_umapdb_lock);
3969517SBill.Taylor@Sun.COM /* If in "maintenance mode", don't free the rsrc */
3979517SBill.Taylor@Sun.COM if (HERMON_IS_OPERATIONAL(state->hs_operational_mode)) {
3989517SBill.Taylor@Sun.COM hermon_rsrc_free(state, &rsrcp);
3999517SBill.Taylor@Sun.COM }
4009517SBill.Taylor@Sun.COM return (EAGAIN);
4019517SBill.Taylor@Sun.COM }
4029517SBill.Taylor@Sun.COM
4039517SBill.Taylor@Sun.COM /*
4049517SBill.Taylor@Sun.COM * Create a new device number. Minor number is a function of
4059517SBill.Taylor@Sun.COM * the UAR page index (15 bits) and the device instance number
4069517SBill.Taylor@Sun.COM * (3 bits).
4079517SBill.Taylor@Sun.COM */
4089517SBill.Taylor@Sun.COM dev = makedevice(getmajor(*devp), (hr_indx <<
4099517SBill.Taylor@Sun.COM HERMON_MINORNUM_SHIFT) | instance);
4109517SBill.Taylor@Sun.COM
4119517SBill.Taylor@Sun.COM /*
4129517SBill.Taylor@Sun.COM * Allocate another entry in the "userland resources database"
4139517SBill.Taylor@Sun.COM * to track the association of the device number (above) to
4149517SBill.Taylor@Sun.COM * the current process ID (in "key").
4159517SBill.Taylor@Sun.COM */
4169517SBill.Taylor@Sun.COM umapdb2 = hermon_umap_db_alloc(instance, dev,
4179517SBill.Taylor@Sun.COM MLNX_UMAP_PID_RSRC, (uint64_t)key);
4189517SBill.Taylor@Sun.COM if (umapdb2 == NULL) {
4199517SBill.Taylor@Sun.COM mutex_exit(&hermon_userland_rsrc_db.hdl_umapdb_lock);
4209517SBill.Taylor@Sun.COM hermon_umap_db_free(umapdb);
4219517SBill.Taylor@Sun.COM /* If in "maintenance mode", don't free the rsrc */
4229517SBill.Taylor@Sun.COM if (HERMON_IS_OPERATIONAL(state->hs_operational_mode)) {
4239517SBill.Taylor@Sun.COM hermon_rsrc_free(state, &rsrcp);
4249517SBill.Taylor@Sun.COM }
4259517SBill.Taylor@Sun.COM return (EAGAIN);
4269517SBill.Taylor@Sun.COM }
4279517SBill.Taylor@Sun.COM
4289517SBill.Taylor@Sun.COM /* Add the entries to the database */
4299517SBill.Taylor@Sun.COM hermon_umap_db_add_nolock(umapdb);
4309517SBill.Taylor@Sun.COM hermon_umap_db_add_nolock(umapdb2);
4319517SBill.Taylor@Sun.COM
4329517SBill.Taylor@Sun.COM } else {
4339517SBill.Taylor@Sun.COM /*
4349517SBill.Taylor@Sun.COM * Return the same device number as on the original open()
4359517SBill.Taylor@Sun.COM * call. This was calculated as a function of the UAR page
4369517SBill.Taylor@Sun.COM * index (top 16 bits) and the device instance number
4379517SBill.Taylor@Sun.COM */
4389517SBill.Taylor@Sun.COM rsrcp = (hermon_rsrc_t *)(uintptr_t)value;
4399517SBill.Taylor@Sun.COM dev = makedevice(getmajor(*devp), (rsrcp->hr_indx <<
4409517SBill.Taylor@Sun.COM HERMON_MINORNUM_SHIFT) | instance);
4419517SBill.Taylor@Sun.COM }
4429517SBill.Taylor@Sun.COM mutex_exit(&hermon_userland_rsrc_db.hdl_umapdb_lock);
4439517SBill.Taylor@Sun.COM
4449517SBill.Taylor@Sun.COM *devp = dev;
4459517SBill.Taylor@Sun.COM
4469517SBill.Taylor@Sun.COM return (0);
4479517SBill.Taylor@Sun.COM }
4489517SBill.Taylor@Sun.COM
4499517SBill.Taylor@Sun.COM
4509517SBill.Taylor@Sun.COM /*
4519517SBill.Taylor@Sun.COM * hermon_close()
4529517SBill.Taylor@Sun.COM */
4539517SBill.Taylor@Sun.COM /* ARGSUSED */
4549517SBill.Taylor@Sun.COM static int
hermon_close(dev_t dev,int flag,int otyp,cred_t * credp)4559517SBill.Taylor@Sun.COM hermon_close(dev_t dev, int flag, int otyp, cred_t *credp)
4569517SBill.Taylor@Sun.COM {
4579517SBill.Taylor@Sun.COM hermon_state_t *state;
4589517SBill.Taylor@Sun.COM hermon_rsrc_t *rsrcp;
4599517SBill.Taylor@Sun.COM hermon_umap_db_entry_t *umapdb;
4609517SBill.Taylor@Sun.COM hermon_umap_db_priv_t *priv;
4619517SBill.Taylor@Sun.COM minor_t instance;
4629517SBill.Taylor@Sun.COM uint64_t key, value;
4639517SBill.Taylor@Sun.COM int status, reset_status = 0;
4649517SBill.Taylor@Sun.COM
4659517SBill.Taylor@Sun.COM instance = HERMON_DEV_INSTANCE(dev);
4669517SBill.Taylor@Sun.COM state = ddi_get_soft_state(hermon_statep, instance);
4679517SBill.Taylor@Sun.COM if (state == NULL) {
4689517SBill.Taylor@Sun.COM return (ENXIO);
4699517SBill.Taylor@Sun.COM }
4709517SBill.Taylor@Sun.COM
4719517SBill.Taylor@Sun.COM /*
4729517SBill.Taylor@Sun.COM * Search for "dev_t" in the "userland resources database". As
4739517SBill.Taylor@Sun.COM * explained above in hermon_open(), we can't depend on using the
4749517SBill.Taylor@Sun.COM * current process ID here to do the lookup because the process
4759517SBill.Taylor@Sun.COM * that ultimately closes may not be the same one who opened
4769517SBill.Taylor@Sun.COM * (because of inheritance).
4779517SBill.Taylor@Sun.COM * So we lookup the "dev_t" (which points to the PID of the process
4789517SBill.Taylor@Sun.COM * that opened), and we remove the entry from the database (and free
4799517SBill.Taylor@Sun.COM * it up). Then we do another query based on the PID value. And when
4809517SBill.Taylor@Sun.COM * we find that database entry, we free it up too and then free the
4819517SBill.Taylor@Sun.COM * Hermon UAR page resource.
4829517SBill.Taylor@Sun.COM *
4839517SBill.Taylor@Sun.COM * Note: We use the hermon_umap_db_find_nolock() database access
4849517SBill.Taylor@Sun.COM * routine below (with an explicit mutex_enter of the database lock)
4859517SBill.Taylor@Sun.COM * to ensure that the multiple accesses (which attempt to remove the
4869517SBill.Taylor@Sun.COM * two database entries) can be done atomically.
4879517SBill.Taylor@Sun.COM *
4889517SBill.Taylor@Sun.COM * This works the same in both maintenance mode and HCA mode, except
4899517SBill.Taylor@Sun.COM * for the call to hermon_rsrc_free(). In the case of maintenance mode,
4909517SBill.Taylor@Sun.COM * this call is not needed, as it was not allocated in hermon_open()
4919517SBill.Taylor@Sun.COM * above.
4929517SBill.Taylor@Sun.COM */
4939517SBill.Taylor@Sun.COM key = dev;
4949517SBill.Taylor@Sun.COM mutex_enter(&hermon_userland_rsrc_db.hdl_umapdb_lock);
4959517SBill.Taylor@Sun.COM status = hermon_umap_db_find_nolock(instance, key, MLNX_UMAP_PID_RSRC,
4969517SBill.Taylor@Sun.COM &value, HERMON_UMAP_DB_REMOVE, &umapdb);
4979517SBill.Taylor@Sun.COM if (status == DDI_SUCCESS) {
4989517SBill.Taylor@Sun.COM /*
4999517SBill.Taylor@Sun.COM * If the "hdb_priv" field is non-NULL, it indicates that
5009517SBill.Taylor@Sun.COM * some "on close" handling is still necessary. Call
5019517SBill.Taylor@Sun.COM * hermon_umap_db_handle_onclose_cb() to do the handling (i.e.
5029517SBill.Taylor@Sun.COM * to invoke all the registered callbacks). Then free up
5039517SBill.Taylor@Sun.COM * the resources associated with "hdb_priv" and continue
5049517SBill.Taylor@Sun.COM * closing.
5059517SBill.Taylor@Sun.COM */
5069517SBill.Taylor@Sun.COM priv = (hermon_umap_db_priv_t *)umapdb->hdbe_common.hdb_priv;
5079517SBill.Taylor@Sun.COM if (priv != NULL) {
5089517SBill.Taylor@Sun.COM reset_status = hermon_umap_db_handle_onclose_cb(priv);
5099517SBill.Taylor@Sun.COM kmem_free(priv, sizeof (hermon_umap_db_priv_t));
5109517SBill.Taylor@Sun.COM umapdb->hdbe_common.hdb_priv = (void *)NULL;
5119517SBill.Taylor@Sun.COM }
5129517SBill.Taylor@Sun.COM
5139517SBill.Taylor@Sun.COM hermon_umap_db_free(umapdb);
5149517SBill.Taylor@Sun.COM
5159517SBill.Taylor@Sun.COM /*
5169517SBill.Taylor@Sun.COM * Now do another lookup using PID as the key (copy it from
5179517SBill.Taylor@Sun.COM * "value"). When this lookup is complete, the "value" field
5189517SBill.Taylor@Sun.COM * will contain the hermon_rsrc_t pointer for the UAR page
5199517SBill.Taylor@Sun.COM * resource.
5209517SBill.Taylor@Sun.COM */
5219517SBill.Taylor@Sun.COM key = value;
5229517SBill.Taylor@Sun.COM status = hermon_umap_db_find_nolock(instance, key,
5239517SBill.Taylor@Sun.COM MLNX_UMAP_UARPG_RSRC, &value, HERMON_UMAP_DB_REMOVE,
5249517SBill.Taylor@Sun.COM &umapdb);
5259517SBill.Taylor@Sun.COM if (status == DDI_SUCCESS) {
5269517SBill.Taylor@Sun.COM hermon_umap_db_free(umapdb);
5279517SBill.Taylor@Sun.COM /* If in "maintenance mode", don't free the rsrc */
5289517SBill.Taylor@Sun.COM if (HERMON_IS_OPERATIONAL(state->hs_operational_mode)) {
5299517SBill.Taylor@Sun.COM rsrcp = (hermon_rsrc_t *)(uintptr_t)value;
5309517SBill.Taylor@Sun.COM hermon_rsrc_free(state, &rsrcp);
5319517SBill.Taylor@Sun.COM }
5329517SBill.Taylor@Sun.COM }
5339517SBill.Taylor@Sun.COM }
5349517SBill.Taylor@Sun.COM mutex_exit(&hermon_userland_rsrc_db.hdl_umapdb_lock);
5359517SBill.Taylor@Sun.COM return (reset_status);
5369517SBill.Taylor@Sun.COM }
5379517SBill.Taylor@Sun.COM
5389517SBill.Taylor@Sun.COM
5399517SBill.Taylor@Sun.COM /*
5409517SBill.Taylor@Sun.COM * hermon_attach()
5419517SBill.Taylor@Sun.COM * Context: Only called from attach() path context
5429517SBill.Taylor@Sun.COM */
5439517SBill.Taylor@Sun.COM static int
hermon_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)5449517SBill.Taylor@Sun.COM hermon_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
5459517SBill.Taylor@Sun.COM {
5469517SBill.Taylor@Sun.COM hermon_state_t *state;
5479517SBill.Taylor@Sun.COM ibc_clnt_hdl_t tmp_ibtfpriv;
5489517SBill.Taylor@Sun.COM ibc_status_t ibc_status;
5499517SBill.Taylor@Sun.COM int instance;
5509517SBill.Taylor@Sun.COM int status;
5519517SBill.Taylor@Sun.COM
5529517SBill.Taylor@Sun.COM #ifdef __lock_lint
5539517SBill.Taylor@Sun.COM (void) hermon_quiesce(dip);
5549517SBill.Taylor@Sun.COM #endif
5559517SBill.Taylor@Sun.COM
5569517SBill.Taylor@Sun.COM switch (cmd) {
5579517SBill.Taylor@Sun.COM case DDI_ATTACH:
5589517SBill.Taylor@Sun.COM instance = ddi_get_instance(dip);
5599517SBill.Taylor@Sun.COM status = ddi_soft_state_zalloc(hermon_statep, instance);
5609517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
5619517SBill.Taylor@Sun.COM cmn_err(CE_NOTE, "hermon%d: driver failed to attach: "
5629517SBill.Taylor@Sun.COM "attach_ssz_fail", instance);
5639517SBill.Taylor@Sun.COM goto fail_attach_nomsg;
5649517SBill.Taylor@Sun.COM
5659517SBill.Taylor@Sun.COM }
5669517SBill.Taylor@Sun.COM state = ddi_get_soft_state(hermon_statep, instance);
5679517SBill.Taylor@Sun.COM if (state == NULL) {
5689517SBill.Taylor@Sun.COM ddi_soft_state_free(hermon_statep, instance);
5699517SBill.Taylor@Sun.COM cmn_err(CE_NOTE, "hermon%d: driver failed to attach: "
5709517SBill.Taylor@Sun.COM "attach_gss_fail", instance);
5719517SBill.Taylor@Sun.COM goto fail_attach_nomsg;
5729517SBill.Taylor@Sun.COM }
5739517SBill.Taylor@Sun.COM
5749517SBill.Taylor@Sun.COM /* clear the attach error buffer */
5759517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG_INIT(state->hs_attach_buf);
5769517SBill.Taylor@Sun.COM
5779517SBill.Taylor@Sun.COM /* Save away devinfo and instance before hermon_fm_init() */
5789517SBill.Taylor@Sun.COM state->hs_dip = dip;
5799517SBill.Taylor@Sun.COM state->hs_instance = instance;
5809517SBill.Taylor@Sun.COM
5819517SBill.Taylor@Sun.COM hermon_fm_init(state);
5829517SBill.Taylor@Sun.COM
5839517SBill.Taylor@Sun.COM /*
5849517SBill.Taylor@Sun.COM * Initialize Hermon driver and hardware.
5859517SBill.Taylor@Sun.COM *
5869517SBill.Taylor@Sun.COM * Note: If this initialization fails we may still wish to
5879517SBill.Taylor@Sun.COM * create a device node and remain operational so that Hermon
5889517SBill.Taylor@Sun.COM * firmware can be updated/flashed (i.e. "maintenance mode").
5899517SBill.Taylor@Sun.COM * If this is the case, then "hs_operational_mode" will be
5909517SBill.Taylor@Sun.COM * equal to HERMON_MAINTENANCE_MODE. We will not attempt to
5919517SBill.Taylor@Sun.COM * attach to the IBTF or register with the IBMF (i.e. no
5929517SBill.Taylor@Sun.COM * InfiniBand interfaces will be enabled).
5939517SBill.Taylor@Sun.COM */
5949517SBill.Taylor@Sun.COM status = hermon_drv_init(state, dip, instance);
5959517SBill.Taylor@Sun.COM if ((status != DDI_SUCCESS) &&
5969517SBill.Taylor@Sun.COM (HERMON_IS_OPERATIONAL(state->hs_operational_mode))) {
5979517SBill.Taylor@Sun.COM goto fail_attach;
5989517SBill.Taylor@Sun.COM }
5999517SBill.Taylor@Sun.COM
6009517SBill.Taylor@Sun.COM /*
6019517SBill.Taylor@Sun.COM * Change the Hermon FM mode
6029517SBill.Taylor@Sun.COM */
6039517SBill.Taylor@Sun.COM if ((hermon_get_state(state) & HCA_PIO_FM) &&
6049517SBill.Taylor@Sun.COM HERMON_IS_OPERATIONAL(state->hs_operational_mode)) {
6059517SBill.Taylor@Sun.COM /*
6069517SBill.Taylor@Sun.COM * Now we wait for 50ms to give an opportunity
6079517SBill.Taylor@Sun.COM * to Solaris FMA so that HW errors can be notified.
6089517SBill.Taylor@Sun.COM * Then check if there are HW errors or not. If
6099517SBill.Taylor@Sun.COM * a HW error is detected, the Hermon attachment
6109517SBill.Taylor@Sun.COM * must be failed.
6119517SBill.Taylor@Sun.COM */
6129517SBill.Taylor@Sun.COM delay(drv_usectohz(50000));
6139517SBill.Taylor@Sun.COM if (hermon_init_failure(state)) {
6149517SBill.Taylor@Sun.COM hermon_drv_fini(state);
6159517SBill.Taylor@Sun.COM HERMON_WARNING(state, "unable to "
6169517SBill.Taylor@Sun.COM "attach Hermon due to a HW error");
6179517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
6189517SBill.Taylor@Sun.COM "hermon_attach_failure");
6199517SBill.Taylor@Sun.COM goto fail_attach;
6209517SBill.Taylor@Sun.COM }
6219517SBill.Taylor@Sun.COM
6229517SBill.Taylor@Sun.COM /*
6239517SBill.Taylor@Sun.COM * There seems no HW errors during the attachment,
6249517SBill.Taylor@Sun.COM * so let's change the Hermon FM state to the
6259517SBill.Taylor@Sun.COM * ereport only mode.
6269517SBill.Taylor@Sun.COM */
6279517SBill.Taylor@Sun.COM if (hermon_fm_ereport_init(state) != DDI_SUCCESS) {
6289517SBill.Taylor@Sun.COM /* unwind the resources */
6299517SBill.Taylor@Sun.COM hermon_drv_fini(state);
6309517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
6319517SBill.Taylor@Sun.COM "hermon_attach_failure");
6329517SBill.Taylor@Sun.COM goto fail_attach;
6339517SBill.Taylor@Sun.COM }
6349517SBill.Taylor@Sun.COM }
6359517SBill.Taylor@Sun.COM
6369517SBill.Taylor@Sun.COM /* Create the minor node for device */
6379517SBill.Taylor@Sun.COM status = ddi_create_minor_node(dip, "devctl", S_IFCHR, instance,
6389517SBill.Taylor@Sun.COM DDI_PSEUDO, 0);
6399517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
6409517SBill.Taylor@Sun.COM hermon_drv_fini(state);
6419517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
6429517SBill.Taylor@Sun.COM "attach_create_mn_fail");
6439517SBill.Taylor@Sun.COM goto fail_attach;
6449517SBill.Taylor@Sun.COM }
6459517SBill.Taylor@Sun.COM
6469517SBill.Taylor@Sun.COM /*
6479517SBill.Taylor@Sun.COM * If we are in "maintenance mode", then we don't want to
6489517SBill.Taylor@Sun.COM * register with the IBTF. All InfiniBand interfaces are
6499517SBill.Taylor@Sun.COM * uninitialized, and the device is only capable of handling
6509517SBill.Taylor@Sun.COM * requests to update/flash firmware (or test/debug requests).
6519517SBill.Taylor@Sun.COM */
6529517SBill.Taylor@Sun.COM if (HERMON_IS_OPERATIONAL(state->hs_operational_mode)) {
6539517SBill.Taylor@Sun.COM cmn_err(CE_NOTE, "!Hermon is operational\n");
6549517SBill.Taylor@Sun.COM
6559517SBill.Taylor@Sun.COM /* Attach to InfiniBand Transport Framework (IBTF) */
6569517SBill.Taylor@Sun.COM ibc_status = ibc_attach(&tmp_ibtfpriv,
6579517SBill.Taylor@Sun.COM &state->hs_ibtfinfo);
6589517SBill.Taylor@Sun.COM if (ibc_status != IBC_SUCCESS) {
6599517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "hermon_attach: ibc_attach "
6609517SBill.Taylor@Sun.COM "failed\n");
6619517SBill.Taylor@Sun.COM ddi_remove_minor_node(dip, "devctl");
6629517SBill.Taylor@Sun.COM hermon_drv_fini(state);
6639517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
6649517SBill.Taylor@Sun.COM "attach_ibcattach_fail");
6659517SBill.Taylor@Sun.COM goto fail_attach;
6669517SBill.Taylor@Sun.COM }
6679517SBill.Taylor@Sun.COM
6689517SBill.Taylor@Sun.COM /*
6699517SBill.Taylor@Sun.COM * Now that we've successfully attached to the IBTF,
6709517SBill.Taylor@Sun.COM * we enable all appropriate asynch and CQ events to
6719517SBill.Taylor@Sun.COM * be forwarded to the IBTF.
6729517SBill.Taylor@Sun.COM */
6739517SBill.Taylor@Sun.COM HERMON_ENABLE_IBTF_CALLB(state, tmp_ibtfpriv);
6749517SBill.Taylor@Sun.COM
6759517SBill.Taylor@Sun.COM ibc_post_attach(state->hs_ibtfpriv);
6769517SBill.Taylor@Sun.COM
6779517SBill.Taylor@Sun.COM /* Register agents with IB Mgmt Framework (IBMF) */
6789517SBill.Taylor@Sun.COM status = hermon_agent_handlers_init(state);
6799517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
6809517SBill.Taylor@Sun.COM (void) ibc_pre_detach(tmp_ibtfpriv, DDI_DETACH);
6819517SBill.Taylor@Sun.COM HERMON_QUIESCE_IBTF_CALLB(state);
6829517SBill.Taylor@Sun.COM if (state->hs_in_evcallb != 0) {
6839517SBill.Taylor@Sun.COM HERMON_WARNING(state, "unable to "
6849517SBill.Taylor@Sun.COM "quiesce Hermon IBTF callbacks");
6859517SBill.Taylor@Sun.COM }
6869517SBill.Taylor@Sun.COM ibc_detach(tmp_ibtfpriv);
6879517SBill.Taylor@Sun.COM ddi_remove_minor_node(dip, "devctl");
6889517SBill.Taylor@Sun.COM hermon_drv_fini(state);
6899517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
6909517SBill.Taylor@Sun.COM "attach_agentinit_fail");
6919517SBill.Taylor@Sun.COM goto fail_attach;
6929517SBill.Taylor@Sun.COM }
6939517SBill.Taylor@Sun.COM }
6949517SBill.Taylor@Sun.COM
6959517SBill.Taylor@Sun.COM /* Report attach in maintenance mode, if appropriate */
6969517SBill.Taylor@Sun.COM if (!(HERMON_IS_OPERATIONAL(state->hs_operational_mode))) {
6979517SBill.Taylor@Sun.COM cmn_err(CE_NOTE, "hermon%d: driver attached "
6989517SBill.Taylor@Sun.COM "(for maintenance mode only)", state->hs_instance);
6999517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_IBA_ERR, HCA_ERR_DEGRADED);
7009517SBill.Taylor@Sun.COM }
7019517SBill.Taylor@Sun.COM
7029517SBill.Taylor@Sun.COM /* Report that driver was loaded */
7039517SBill.Taylor@Sun.COM ddi_report_dev(dip);
7049517SBill.Taylor@Sun.COM
7059517SBill.Taylor@Sun.COM /* Send device information to log file */
7069517SBill.Taylor@Sun.COM hermon_device_info_report(state);
7079517SBill.Taylor@Sun.COM
7089517SBill.Taylor@Sun.COM /* DEBUG PRINT */
7099517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "!Hermon attach complete\n");
7109517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
7119517SBill.Taylor@Sun.COM
7129517SBill.Taylor@Sun.COM case DDI_RESUME:
7139517SBill.Taylor@Sun.COM /* Add code here for DDI_RESUME XXX */
7149517SBill.Taylor@Sun.COM return (DDI_FAILURE);
7159517SBill.Taylor@Sun.COM
7169517SBill.Taylor@Sun.COM default:
7179517SBill.Taylor@Sun.COM cmn_err(CE_WARN, "hermon_attach: unknown cmd (0x%x)\n", cmd);
7189517SBill.Taylor@Sun.COM break;
7199517SBill.Taylor@Sun.COM }
7209517SBill.Taylor@Sun.COM
7219517SBill.Taylor@Sun.COM fail_attach:
7229517SBill.Taylor@Sun.COM cmn_err(CE_NOTE, "hermon%d: driver failed to attach: %s", instance,
7239517SBill.Taylor@Sun.COM state->hs_attach_buf);
7249517SBill.Taylor@Sun.COM if (hermon_get_state(state) & HCA_EREPORT_FM) {
7259517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
7269517SBill.Taylor@Sun.COM }
7279582SEiji.Ota@Sun.COM hermon_drv_fini2(state);
7289517SBill.Taylor@Sun.COM hermon_fm_fini(state);
7299517SBill.Taylor@Sun.COM ddi_soft_state_free(hermon_statep, instance);
7309517SBill.Taylor@Sun.COM
7319517SBill.Taylor@Sun.COM fail_attach_nomsg:
7329517SBill.Taylor@Sun.COM return (DDI_FAILURE);
7339517SBill.Taylor@Sun.COM }
7349517SBill.Taylor@Sun.COM
7359517SBill.Taylor@Sun.COM
7369517SBill.Taylor@Sun.COM /*
7379517SBill.Taylor@Sun.COM * hermon_detach()
7389517SBill.Taylor@Sun.COM * Context: Only called from detach() path context
7399517SBill.Taylor@Sun.COM */
7409517SBill.Taylor@Sun.COM static int
hermon_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)7419517SBill.Taylor@Sun.COM hermon_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
7429517SBill.Taylor@Sun.COM {
7439517SBill.Taylor@Sun.COM hermon_state_t *state;
7449517SBill.Taylor@Sun.COM ibc_clnt_hdl_t tmp_ibtfpriv;
7459517SBill.Taylor@Sun.COM ibc_status_t ibc_status;
7469517SBill.Taylor@Sun.COM int instance, status;
7479517SBill.Taylor@Sun.COM
7489517SBill.Taylor@Sun.COM instance = ddi_get_instance(dip);
7499517SBill.Taylor@Sun.COM state = ddi_get_soft_state(hermon_statep, instance);
7509517SBill.Taylor@Sun.COM if (state == NULL) {
7519517SBill.Taylor@Sun.COM return (DDI_FAILURE);
7529517SBill.Taylor@Sun.COM }
7539517SBill.Taylor@Sun.COM
7549517SBill.Taylor@Sun.COM switch (cmd) {
7559517SBill.Taylor@Sun.COM case DDI_DETACH:
7569517SBill.Taylor@Sun.COM /*
7579517SBill.Taylor@Sun.COM * If we are in "maintenance mode", then we do not want to
7589517SBill.Taylor@Sun.COM * do teardown for any of the InfiniBand interfaces.
7599517SBill.Taylor@Sun.COM * Specifically, this means not detaching from IBTF (we never
7609517SBill.Taylor@Sun.COM * attached to begin with) and not deregistering from IBMF.
7619517SBill.Taylor@Sun.COM */
7629517SBill.Taylor@Sun.COM if (HERMON_IS_OPERATIONAL(state->hs_operational_mode)) {
7639517SBill.Taylor@Sun.COM /* Unregister agents from IB Mgmt Framework (IBMF) */
7649517SBill.Taylor@Sun.COM status = hermon_agent_handlers_fini(state);
7659517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
7669517SBill.Taylor@Sun.COM return (DDI_FAILURE);
7679517SBill.Taylor@Sun.COM }
7689517SBill.Taylor@Sun.COM
7699517SBill.Taylor@Sun.COM /*
7709517SBill.Taylor@Sun.COM * Attempt the "pre-detach" from InfiniBand Transport
7719517SBill.Taylor@Sun.COM * Framework (IBTF). At this point the IBTF is still
7729517SBill.Taylor@Sun.COM * capable of handling incoming asynch and completion
7739517SBill.Taylor@Sun.COM * events. This "pre-detach" is primarily a mechanism
7749517SBill.Taylor@Sun.COM * to notify the appropriate IBTF clients that the
7759517SBill.Taylor@Sun.COM * HCA is being removed/offlined.
7769517SBill.Taylor@Sun.COM */
7779517SBill.Taylor@Sun.COM ibc_status = ibc_pre_detach(state->hs_ibtfpriv, cmd);
7789517SBill.Taylor@Sun.COM if (ibc_status != IBC_SUCCESS) {
7799517SBill.Taylor@Sun.COM status = hermon_agent_handlers_init(state);
7809517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
7819517SBill.Taylor@Sun.COM HERMON_WARNING(state, "failed to "
7829517SBill.Taylor@Sun.COM "restart Hermon agents");
7839517SBill.Taylor@Sun.COM }
7849517SBill.Taylor@Sun.COM return (DDI_FAILURE);
7859517SBill.Taylor@Sun.COM }
7869517SBill.Taylor@Sun.COM
7879517SBill.Taylor@Sun.COM /*
7889517SBill.Taylor@Sun.COM * Before we can fully detach from the IBTF we need to
7899517SBill.Taylor@Sun.COM * ensure that we have handled all outstanding event
7909517SBill.Taylor@Sun.COM * callbacks. This is accomplished by quiescing the
7919517SBill.Taylor@Sun.COM * event callback mechanism. Note: if we are unable
7929517SBill.Taylor@Sun.COM * to successfully quiesce the callbacks, then this is
7939517SBill.Taylor@Sun.COM * an indication that something has probably gone
7949517SBill.Taylor@Sun.COM * seriously wrong. We print out a warning, but
7959517SBill.Taylor@Sun.COM * continue.
7969517SBill.Taylor@Sun.COM */
7979517SBill.Taylor@Sun.COM tmp_ibtfpriv = state->hs_ibtfpriv;
7989517SBill.Taylor@Sun.COM HERMON_QUIESCE_IBTF_CALLB(state);
7999517SBill.Taylor@Sun.COM if (state->hs_in_evcallb != 0) {
8009517SBill.Taylor@Sun.COM HERMON_WARNING(state, "unable to quiesce "
8019517SBill.Taylor@Sun.COM "Hermon IBTF callbacks");
8029517SBill.Taylor@Sun.COM }
8039517SBill.Taylor@Sun.COM
8049517SBill.Taylor@Sun.COM /* Complete the detach from the IBTF */
8059517SBill.Taylor@Sun.COM ibc_detach(tmp_ibtfpriv);
8069517SBill.Taylor@Sun.COM }
8079517SBill.Taylor@Sun.COM
8089517SBill.Taylor@Sun.COM /* Remove the minor node for device */
8099517SBill.Taylor@Sun.COM ddi_remove_minor_node(dip, "devctl");
8109517SBill.Taylor@Sun.COM
8119517SBill.Taylor@Sun.COM /*
8129517SBill.Taylor@Sun.COM * Only call hermon_drv_fini() if we are in Hermon HCA mode.
8139517SBill.Taylor@Sun.COM * (Because if we are in "maintenance mode", then we never
8149517SBill.Taylor@Sun.COM * successfully finished init.) Only report successful
8159517SBill.Taylor@Sun.COM * detach for normal HCA mode.
8169517SBill.Taylor@Sun.COM */
8179517SBill.Taylor@Sun.COM if (HERMON_IS_OPERATIONAL(state->hs_operational_mode)) {
8189517SBill.Taylor@Sun.COM /* Cleanup driver resources and shutdown hardware */
8199517SBill.Taylor@Sun.COM hermon_drv_fini(state);
8209517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "!Hermon driver successfully "
8219517SBill.Taylor@Sun.COM "detached\n");
8229517SBill.Taylor@Sun.COM }
8239517SBill.Taylor@Sun.COM
8249517SBill.Taylor@Sun.COM hermon_drv_fini2(state);
8259517SBill.Taylor@Sun.COM hermon_fm_fini(state);
8269517SBill.Taylor@Sun.COM ddi_soft_state_free(hermon_statep, instance);
8279517SBill.Taylor@Sun.COM
8289517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
8299517SBill.Taylor@Sun.COM
8309517SBill.Taylor@Sun.COM case DDI_SUSPEND:
8319517SBill.Taylor@Sun.COM /* Add code here for DDI_SUSPEND XXX */
8329517SBill.Taylor@Sun.COM return (DDI_FAILURE);
8339517SBill.Taylor@Sun.COM
8349517SBill.Taylor@Sun.COM default:
8359517SBill.Taylor@Sun.COM cmn_err(CE_WARN, "hermon_detach: unknown cmd (0x%x)\n", cmd);
8369517SBill.Taylor@Sun.COM break;
8379517SBill.Taylor@Sun.COM }
8389517SBill.Taylor@Sun.COM
8399517SBill.Taylor@Sun.COM return (DDI_FAILURE);
8409517SBill.Taylor@Sun.COM }
8419517SBill.Taylor@Sun.COM
8429517SBill.Taylor@Sun.COM /*
8439517SBill.Taylor@Sun.COM * hermon_dma_attr_init()
8449517SBill.Taylor@Sun.COM * Context: Can be called from interrupt or base context.
8459517SBill.Taylor@Sun.COM */
8469517SBill.Taylor@Sun.COM
8479517SBill.Taylor@Sun.COM /* ARGSUSED */
8489517SBill.Taylor@Sun.COM void
hermon_dma_attr_init(hermon_state_t * state,ddi_dma_attr_t * dma_attr)8499517SBill.Taylor@Sun.COM hermon_dma_attr_init(hermon_state_t *state, ddi_dma_attr_t *dma_attr)
8509517SBill.Taylor@Sun.COM {
8519517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dma_attr))
8529517SBill.Taylor@Sun.COM
8539517SBill.Taylor@Sun.COM dma_attr->dma_attr_version = DMA_ATTR_V0;
8549517SBill.Taylor@Sun.COM dma_attr->dma_attr_addr_lo = 0;
8559517SBill.Taylor@Sun.COM dma_attr->dma_attr_addr_hi = 0xFFFFFFFFFFFFFFFFull;
8569517SBill.Taylor@Sun.COM dma_attr->dma_attr_count_max = 0xFFFFFFFFFFFFFFFFull;
8579517SBill.Taylor@Sun.COM dma_attr->dma_attr_align = HERMON_PAGESIZE; /* default 4K */
8589517SBill.Taylor@Sun.COM dma_attr->dma_attr_burstsizes = 0x3FF;
8599517SBill.Taylor@Sun.COM dma_attr->dma_attr_minxfer = 1;
8609517SBill.Taylor@Sun.COM dma_attr->dma_attr_maxxfer = 0xFFFFFFFFFFFFFFFFull;
8619517SBill.Taylor@Sun.COM dma_attr->dma_attr_seg = 0xFFFFFFFFFFFFFFFFull;
8629517SBill.Taylor@Sun.COM dma_attr->dma_attr_sgllen = 0x7FFFFFFF;
8639517SBill.Taylor@Sun.COM dma_attr->dma_attr_granular = 1;
8649517SBill.Taylor@Sun.COM dma_attr->dma_attr_flags = 0;
8659517SBill.Taylor@Sun.COM }
8669517SBill.Taylor@Sun.COM
8679517SBill.Taylor@Sun.COM /*
8689517SBill.Taylor@Sun.COM * hermon_dma_alloc()
8699517SBill.Taylor@Sun.COM * Context: Can be called from base context.
8709517SBill.Taylor@Sun.COM */
8719517SBill.Taylor@Sun.COM int
hermon_dma_alloc(hermon_state_t * state,hermon_dma_info_t * dma_info,uint16_t opcode)8729517SBill.Taylor@Sun.COM hermon_dma_alloc(hermon_state_t *state, hermon_dma_info_t *dma_info,
8739517SBill.Taylor@Sun.COM uint16_t opcode)
8749517SBill.Taylor@Sun.COM {
8759517SBill.Taylor@Sun.COM ddi_dma_handle_t dma_hdl;
8769517SBill.Taylor@Sun.COM ddi_dma_attr_t dma_attr;
8779517SBill.Taylor@Sun.COM ddi_acc_handle_t acc_hdl;
8789517SBill.Taylor@Sun.COM ddi_dma_cookie_t cookie;
8799517SBill.Taylor@Sun.COM uint64_t kaddr;
8809517SBill.Taylor@Sun.COM uint64_t real_len;
8819517SBill.Taylor@Sun.COM uint_t ccount;
8829517SBill.Taylor@Sun.COM int status;
8839517SBill.Taylor@Sun.COM
8849517SBill.Taylor@Sun.COM hermon_dma_attr_init(state, &dma_attr);
88511972SBill.Taylor@Sun.COM #ifdef __sparc
88611972SBill.Taylor@Sun.COM if (state->hs_cfg_profile->cp_iommu_bypass == HERMON_BINDMEM_BYPASS)
88711972SBill.Taylor@Sun.COM dma_attr.dma_attr_flags = DDI_DMA_FORCE_PHYSICAL;
88811972SBill.Taylor@Sun.COM #endif
8899517SBill.Taylor@Sun.COM
8909517SBill.Taylor@Sun.COM /* Allocate a DMA handle */
8919517SBill.Taylor@Sun.COM status = ddi_dma_alloc_handle(state->hs_dip, &dma_attr, DDI_DMA_SLEEP,
8929517SBill.Taylor@Sun.COM NULL, &dma_hdl);
8939517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
8949517SBill.Taylor@Sun.COM IBTF_DPRINTF_L2("DMA", "alloc handle failed: %d", status);
8959517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "DMA alloc handle failed(status %d)", status);
8969517SBill.Taylor@Sun.COM return (DDI_FAILURE);
8979517SBill.Taylor@Sun.COM }
8989517SBill.Taylor@Sun.COM
8999517SBill.Taylor@Sun.COM /* Allocate DMA memory */
9009517SBill.Taylor@Sun.COM status = ddi_dma_mem_alloc(dma_hdl, dma_info->length,
9019517SBill.Taylor@Sun.COM &state->hs_reg_accattr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
9029517SBill.Taylor@Sun.COM (caddr_t *)&kaddr, (size_t *)&real_len, &acc_hdl);
9039517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
9049517SBill.Taylor@Sun.COM ddi_dma_free_handle(&dma_hdl);
9059517SBill.Taylor@Sun.COM IBTF_DPRINTF_L2("DMA", "memory alloc failed: %d", status);
9069517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "DMA memory alloc failed(status %d)", status);
9079517SBill.Taylor@Sun.COM return (DDI_FAILURE);
9089517SBill.Taylor@Sun.COM }
9099517SBill.Taylor@Sun.COM bzero((caddr_t)(uintptr_t)kaddr, real_len);
9109517SBill.Taylor@Sun.COM
9119517SBill.Taylor@Sun.COM /* Bind the memory to the handle */
9129517SBill.Taylor@Sun.COM status = ddi_dma_addr_bind_handle(dma_hdl, NULL,
9139517SBill.Taylor@Sun.COM (caddr_t)(uintptr_t)kaddr, (size_t)real_len, DDI_DMA_RDWR |
9149517SBill.Taylor@Sun.COM DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &cookie, &ccount);
9159517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
9169517SBill.Taylor@Sun.COM ddi_dma_mem_free(&acc_hdl);
9179517SBill.Taylor@Sun.COM ddi_dma_free_handle(&dma_hdl);
9189517SBill.Taylor@Sun.COM IBTF_DPRINTF_L2("DMA", "bind handle failed: %d", status);
9199517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "DMA bind handle failed(status %d)", status);
9209517SBill.Taylor@Sun.COM return (DDI_FAILURE);
9219517SBill.Taylor@Sun.COM }
9229517SBill.Taylor@Sun.COM
9239517SBill.Taylor@Sun.COM /* Package the hermon_dma_info contents and return */
9249517SBill.Taylor@Sun.COM dma_info->vaddr = kaddr;
9259517SBill.Taylor@Sun.COM dma_info->dma_hdl = dma_hdl;
9269517SBill.Taylor@Sun.COM dma_info->acc_hdl = acc_hdl;
9279517SBill.Taylor@Sun.COM
9289517SBill.Taylor@Sun.COM /* Pass the mapping information to the firmware */
9299517SBill.Taylor@Sun.COM status = hermon_map_cmd_post(state, dma_info, opcode, cookie, ccount);
9309517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
9319517SBill.Taylor@Sun.COM char *s;
9329517SBill.Taylor@Sun.COM hermon_dma_free(dma_info);
9339517SBill.Taylor@Sun.COM switch (opcode) {
9349517SBill.Taylor@Sun.COM case MAP_ICM:
9359517SBill.Taylor@Sun.COM s = "MAP_ICM";
9369517SBill.Taylor@Sun.COM break;
9379517SBill.Taylor@Sun.COM case MAP_FA:
9389517SBill.Taylor@Sun.COM s = "MAP_FA";
9399517SBill.Taylor@Sun.COM break;
9409517SBill.Taylor@Sun.COM case MAP_ICM_AUX:
9419517SBill.Taylor@Sun.COM s = "MAP_ICM_AUX";
9429517SBill.Taylor@Sun.COM break;
9439517SBill.Taylor@Sun.COM default:
9449517SBill.Taylor@Sun.COM s = "UNKNOWN";
9459517SBill.Taylor@Sun.COM }
9469517SBill.Taylor@Sun.COM cmn_err(CE_NOTE, "Map cmd '%s' failed, status %08x\n",
9479517SBill.Taylor@Sun.COM s, status);
9489517SBill.Taylor@Sun.COM return (DDI_FAILURE);
9499517SBill.Taylor@Sun.COM }
9509517SBill.Taylor@Sun.COM
9519517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
9529517SBill.Taylor@Sun.COM }
9539517SBill.Taylor@Sun.COM
9549517SBill.Taylor@Sun.COM /*
9559517SBill.Taylor@Sun.COM * hermon_dma_free()
9569517SBill.Taylor@Sun.COM * Context: Can be called from base context.
9579517SBill.Taylor@Sun.COM */
9589517SBill.Taylor@Sun.COM void
hermon_dma_free(hermon_dma_info_t * info)9599517SBill.Taylor@Sun.COM hermon_dma_free(hermon_dma_info_t *info)
9609517SBill.Taylor@Sun.COM {
9619517SBill.Taylor@Sun.COM /* Unbind the handles and free the memory */
9629517SBill.Taylor@Sun.COM (void) ddi_dma_unbind_handle(info->dma_hdl);
9639517SBill.Taylor@Sun.COM ddi_dma_mem_free(&info->acc_hdl);
9649517SBill.Taylor@Sun.COM ddi_dma_free_handle(&info->dma_hdl);
9659517SBill.Taylor@Sun.COM }
9669517SBill.Taylor@Sun.COM
9679517SBill.Taylor@Sun.COM /* These macros are valid for use only in hermon_icm_alloc/hermon_icm_free. */
9689517SBill.Taylor@Sun.COM #define HERMON_ICM_ALLOC(rsrc) \
9699517SBill.Taylor@Sun.COM hermon_icm_alloc(state, rsrc, index1, index2)
9709517SBill.Taylor@Sun.COM #define HERMON_ICM_FREE(rsrc) \
9719517SBill.Taylor@Sun.COM hermon_icm_free(state, rsrc, index1, index2)
9729517SBill.Taylor@Sun.COM
9739517SBill.Taylor@Sun.COM /*
9749517SBill.Taylor@Sun.COM * hermon_icm_alloc()
9759517SBill.Taylor@Sun.COM * Context: Can be called from base context.
9769517SBill.Taylor@Sun.COM *
9779517SBill.Taylor@Sun.COM * Only one thread can be here for a given hermon_rsrc_type_t "type".
97812965SWilliam.Taylor@Oracle.COM *
97912965SWilliam.Taylor@Oracle.COM * "num_to_hdl" is set if there is a need for lookups from resource
98012965SWilliam.Taylor@Oracle.COM * number/index to resource handle. This is needed for QPs/CQs/SRQs
98112965SWilliam.Taylor@Oracle.COM * for the various affiliated events/errors.
9829517SBill.Taylor@Sun.COM */
9839517SBill.Taylor@Sun.COM int
hermon_icm_alloc(hermon_state_t * state,hermon_rsrc_type_t type,uint32_t index1,uint32_t index2)9849517SBill.Taylor@Sun.COM hermon_icm_alloc(hermon_state_t *state, hermon_rsrc_type_t type,
9859517SBill.Taylor@Sun.COM uint32_t index1, uint32_t index2)
9869517SBill.Taylor@Sun.COM {
9879517SBill.Taylor@Sun.COM hermon_icm_table_t *icm;
9889517SBill.Taylor@Sun.COM hermon_dma_info_t *dma_info;
9899517SBill.Taylor@Sun.COM uint8_t *bitmap;
9909517SBill.Taylor@Sun.COM int status;
99112965SWilliam.Taylor@Oracle.COM int num_to_hdl = 0;
9929517SBill.Taylor@Sun.COM
9939517SBill.Taylor@Sun.COM if (hermon_verbose) {
9949517SBill.Taylor@Sun.COM IBTF_DPRINTF_L2("hermon", "hermon_icm_alloc: rsrc_type (0x%x) "
9959517SBill.Taylor@Sun.COM "index1/2 (0x%x/0x%x)", type, index1, index2);
9969517SBill.Taylor@Sun.COM }
9979517SBill.Taylor@Sun.COM
9989517SBill.Taylor@Sun.COM icm = &state->hs_icm[type];
9999517SBill.Taylor@Sun.COM
10009517SBill.Taylor@Sun.COM switch (type) {
10019517SBill.Taylor@Sun.COM case HERMON_QPC:
10029517SBill.Taylor@Sun.COM status = HERMON_ICM_ALLOC(HERMON_CMPT_QPC);
10039517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
10049517SBill.Taylor@Sun.COM return (status);
10059517SBill.Taylor@Sun.COM }
10069517SBill.Taylor@Sun.COM status = HERMON_ICM_ALLOC(HERMON_RDB);
10079517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) { /* undo icm_alloc's */
10089517SBill.Taylor@Sun.COM HERMON_ICM_FREE(HERMON_CMPT_QPC);
10099517SBill.Taylor@Sun.COM return (status);
10109517SBill.Taylor@Sun.COM }
10119517SBill.Taylor@Sun.COM status = HERMON_ICM_ALLOC(HERMON_ALTC);
10129517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) { /* undo icm_alloc's */
10139517SBill.Taylor@Sun.COM HERMON_ICM_FREE(HERMON_RDB);
10149517SBill.Taylor@Sun.COM HERMON_ICM_FREE(HERMON_CMPT_QPC);
10159517SBill.Taylor@Sun.COM return (status);
10169517SBill.Taylor@Sun.COM }
10179517SBill.Taylor@Sun.COM status = HERMON_ICM_ALLOC(HERMON_AUXC);
10189517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) { /* undo icm_alloc's */
10199517SBill.Taylor@Sun.COM HERMON_ICM_FREE(HERMON_ALTC);
10209517SBill.Taylor@Sun.COM HERMON_ICM_FREE(HERMON_RDB);
10219517SBill.Taylor@Sun.COM HERMON_ICM_FREE(HERMON_CMPT_QPC);
10229517SBill.Taylor@Sun.COM return (status);
10239517SBill.Taylor@Sun.COM }
102412965SWilliam.Taylor@Oracle.COM num_to_hdl = 1;
10259517SBill.Taylor@Sun.COM break;
10269517SBill.Taylor@Sun.COM case HERMON_SRQC:
10279517SBill.Taylor@Sun.COM status = HERMON_ICM_ALLOC(HERMON_CMPT_SRQC);
10289517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
10299517SBill.Taylor@Sun.COM return (status);
10309517SBill.Taylor@Sun.COM }
103112965SWilliam.Taylor@Oracle.COM num_to_hdl = 1;
10329517SBill.Taylor@Sun.COM break;
10339517SBill.Taylor@Sun.COM case HERMON_CQC:
10349517SBill.Taylor@Sun.COM status = HERMON_ICM_ALLOC(HERMON_CMPT_CQC);
10359517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
10369517SBill.Taylor@Sun.COM return (status);
10379517SBill.Taylor@Sun.COM }
103812965SWilliam.Taylor@Oracle.COM num_to_hdl = 1;
10399517SBill.Taylor@Sun.COM break;
10409517SBill.Taylor@Sun.COM case HERMON_EQC:
10419517SBill.Taylor@Sun.COM status = HERMON_ICM_ALLOC(HERMON_CMPT_EQC);
10429517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) { /* undo icm_alloc's */
10439517SBill.Taylor@Sun.COM return (status);
10449517SBill.Taylor@Sun.COM }
10459517SBill.Taylor@Sun.COM break;
10469517SBill.Taylor@Sun.COM }
10479517SBill.Taylor@Sun.COM
10489517SBill.Taylor@Sun.COM /* ensure existence of bitmap and dmainfo, sets "dma_info" */
104912965SWilliam.Taylor@Oracle.COM hermon_bitmap(bitmap, dma_info, icm, index1, num_to_hdl);
10509517SBill.Taylor@Sun.COM
10519517SBill.Taylor@Sun.COM /* Set up the DMA handle for allocation and mapping */
105212965SWilliam.Taylor@Oracle.COM dma_info += index2;
10539517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dma_info))
10549517SBill.Taylor@Sun.COM dma_info->length = icm->span << icm->log_object_size;
10559517SBill.Taylor@Sun.COM dma_info->icmaddr = icm->icm_baseaddr +
10569517SBill.Taylor@Sun.COM (((index1 << icm->split_shift) +
10579517SBill.Taylor@Sun.COM (index2 << icm->span_shift)) << icm->log_object_size);
10589517SBill.Taylor@Sun.COM
105912965SWilliam.Taylor@Oracle.COM /* Allocate memory for the num_to_qp/cq/srq pointers */
106012965SWilliam.Taylor@Oracle.COM if (num_to_hdl)
106112965SWilliam.Taylor@Oracle.COM icm->num_to_hdl[index1][index2] =
106212965SWilliam.Taylor@Oracle.COM kmem_zalloc(HERMON_ICM_SPAN * sizeof (void *), KM_SLEEP);
106312965SWilliam.Taylor@Oracle.COM
10649517SBill.Taylor@Sun.COM if (hermon_verbose) {
10659517SBill.Taylor@Sun.COM IBTF_DPRINTF_L2("hermon", "alloc DMA: "
10669517SBill.Taylor@Sun.COM "rsrc (0x%x) index (%x, %x) "
10679517SBill.Taylor@Sun.COM "icm_addr/len (%llx/%x) bitmap %p", type, index1, index2,
10689517SBill.Taylor@Sun.COM (longlong_t)dma_info->icmaddr, dma_info->length, bitmap);
10699517SBill.Taylor@Sun.COM }
10709517SBill.Taylor@Sun.COM
10719517SBill.Taylor@Sun.COM /* Allocate and map memory for this span */
10729517SBill.Taylor@Sun.COM status = hermon_dma_alloc(state, dma_info, MAP_ICM);
10739517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
10749517SBill.Taylor@Sun.COM IBTF_DPRINTF_L2("hermon", "hermon_icm_alloc: DMA "
10759517SBill.Taylor@Sun.COM "allocation failed, status 0x%x", status);
10769517SBill.Taylor@Sun.COM switch (type) {
10779517SBill.Taylor@Sun.COM case HERMON_QPC:
10789517SBill.Taylor@Sun.COM HERMON_ICM_FREE(HERMON_AUXC);
10799517SBill.Taylor@Sun.COM HERMON_ICM_FREE(HERMON_ALTC);
10809517SBill.Taylor@Sun.COM HERMON_ICM_FREE(HERMON_RDB);
10819517SBill.Taylor@Sun.COM HERMON_ICM_FREE(HERMON_CMPT_QPC);
10829517SBill.Taylor@Sun.COM break;
10839517SBill.Taylor@Sun.COM case HERMON_SRQC:
10849517SBill.Taylor@Sun.COM HERMON_ICM_FREE(HERMON_CMPT_SRQC);
10859517SBill.Taylor@Sun.COM break;
10869517SBill.Taylor@Sun.COM case HERMON_CQC:
10879517SBill.Taylor@Sun.COM HERMON_ICM_FREE(HERMON_CMPT_CQC);
10889517SBill.Taylor@Sun.COM break;
10899517SBill.Taylor@Sun.COM case HERMON_EQC:
10909517SBill.Taylor@Sun.COM HERMON_ICM_FREE(HERMON_CMPT_EQC);
10919517SBill.Taylor@Sun.COM break;
10929517SBill.Taylor@Sun.COM }
10939517SBill.Taylor@Sun.COM
10949517SBill.Taylor@Sun.COM return (DDI_FAILURE);
10959517SBill.Taylor@Sun.COM }
10969517SBill.Taylor@Sun.COM if (hermon_verbose) {
10979517SBill.Taylor@Sun.COM IBTF_DPRINTF_L2("hermon", "hermon_icm_alloc: mapping ICM: "
10989517SBill.Taylor@Sun.COM "rsrc_type (0x%x) index (0x%x, 0x%x) alloc length (0x%x) "
10999517SBill.Taylor@Sun.COM "icm_addr (0x%lx)", type, index1, index2, dma_info->length,
11009517SBill.Taylor@Sun.COM dma_info->icmaddr);
11019517SBill.Taylor@Sun.COM }
11029517SBill.Taylor@Sun.COM
11039517SBill.Taylor@Sun.COM /* Set the bit for this slot in the table bitmap */
11049517SBill.Taylor@Sun.COM HERMON_BMAP_BIT_SET(icm->icm_bitmap[index1], index2);
11059517SBill.Taylor@Sun.COM
11069517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
11079517SBill.Taylor@Sun.COM }
11089517SBill.Taylor@Sun.COM
11099517SBill.Taylor@Sun.COM /*
11109517SBill.Taylor@Sun.COM * hermon_icm_free()
11119517SBill.Taylor@Sun.COM * Context: Can be called from base context.
11129517SBill.Taylor@Sun.COM *
11139517SBill.Taylor@Sun.COM * ICM resources have been successfully returned from hermon_icm_alloc().
11149517SBill.Taylor@Sun.COM * Associated dma_info is no longer in use. Free the ICM backing memory.
11159517SBill.Taylor@Sun.COM */
11169517SBill.Taylor@Sun.COM void
hermon_icm_free(hermon_state_t * state,hermon_rsrc_type_t type,uint32_t index1,uint32_t index2)11179517SBill.Taylor@Sun.COM hermon_icm_free(hermon_state_t *state, hermon_rsrc_type_t type,
11189517SBill.Taylor@Sun.COM uint32_t index1, uint32_t index2)
11199517SBill.Taylor@Sun.COM {
11209517SBill.Taylor@Sun.COM hermon_icm_table_t *icm;
11219517SBill.Taylor@Sun.COM hermon_dma_info_t *dma_info;
11229517SBill.Taylor@Sun.COM int status;
11239517SBill.Taylor@Sun.COM
11249517SBill.Taylor@Sun.COM icm = &state->hs_icm[type];
11259517SBill.Taylor@Sun.COM ASSERT(icm->icm_dma[index1][index2].icm_refcnt == 0);
11269517SBill.Taylor@Sun.COM
11279517SBill.Taylor@Sun.COM if (hermon_verbose) {
11289517SBill.Taylor@Sun.COM IBTF_DPRINTF_L2("hermon", "hermon_icm_free: rsrc_type (0x%x) "
11299517SBill.Taylor@Sun.COM "index (0x%x, 0x%x)", type, index1, index2);
11309517SBill.Taylor@Sun.COM }
11319517SBill.Taylor@Sun.COM
11329517SBill.Taylor@Sun.COM dma_info = icm->icm_dma[index1] + index2;
11339517SBill.Taylor@Sun.COM
11349517SBill.Taylor@Sun.COM /* The following only happens if attach() is failing. */
11359517SBill.Taylor@Sun.COM if (dma_info == NULL)
11369517SBill.Taylor@Sun.COM return;
11379517SBill.Taylor@Sun.COM
11389517SBill.Taylor@Sun.COM /* Unmap the ICM allocation, then free the backing DMA memory */
11399517SBill.Taylor@Sun.COM status = hermon_unmap_icm_cmd_post(state, dma_info);
11409517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
11419517SBill.Taylor@Sun.COM HERMON_WARNING(state, "UNMAP_ICM failure");
11429517SBill.Taylor@Sun.COM }
11439517SBill.Taylor@Sun.COM hermon_dma_free(dma_info);
11449517SBill.Taylor@Sun.COM
11459517SBill.Taylor@Sun.COM /* Clear the bit in the ICM table bitmap */
11469517SBill.Taylor@Sun.COM HERMON_BMAP_BIT_CLR(icm->icm_bitmap[index1], index2);
11479517SBill.Taylor@Sun.COM
11489517SBill.Taylor@Sun.COM switch (type) {
11499517SBill.Taylor@Sun.COM case HERMON_QPC:
11509517SBill.Taylor@Sun.COM HERMON_ICM_FREE(HERMON_AUXC);
11519517SBill.Taylor@Sun.COM HERMON_ICM_FREE(HERMON_ALTC);
11529517SBill.Taylor@Sun.COM HERMON_ICM_FREE(HERMON_RDB);
11539517SBill.Taylor@Sun.COM HERMON_ICM_FREE(HERMON_CMPT_QPC);
11549517SBill.Taylor@Sun.COM break;
11559517SBill.Taylor@Sun.COM case HERMON_SRQC:
11569517SBill.Taylor@Sun.COM HERMON_ICM_FREE(HERMON_CMPT_SRQC);
11579517SBill.Taylor@Sun.COM break;
11589517SBill.Taylor@Sun.COM case HERMON_CQC:
11599517SBill.Taylor@Sun.COM HERMON_ICM_FREE(HERMON_CMPT_CQC);
11609517SBill.Taylor@Sun.COM break;
11619517SBill.Taylor@Sun.COM case HERMON_EQC:
11629517SBill.Taylor@Sun.COM HERMON_ICM_FREE(HERMON_CMPT_EQC);
11639517SBill.Taylor@Sun.COM break;
11649517SBill.Taylor@Sun.COM
11659517SBill.Taylor@Sun.COM }
11669517SBill.Taylor@Sun.COM }
11679517SBill.Taylor@Sun.COM
116812688SWilliam.Taylor@Oracle.COM
116912688SWilliam.Taylor@Oracle.COM /*
117012965SWilliam.Taylor@Oracle.COM * hermon_icm_num_to_hdl()
117112965SWilliam.Taylor@Oracle.COM * Context: Can be called from base or interrupt context.
117212965SWilliam.Taylor@Oracle.COM *
117312965SWilliam.Taylor@Oracle.COM * Given an index of a resource, index through the sparsely allocated
117412965SWilliam.Taylor@Oracle.COM * arrays to find the pointer to its software handle. Return NULL if
117512965SWilliam.Taylor@Oracle.COM * any of the arrays of pointers has been freed (should never happen).
117612965SWilliam.Taylor@Oracle.COM */
117712965SWilliam.Taylor@Oracle.COM void *
hermon_icm_num_to_hdl(hermon_state_t * state,hermon_rsrc_type_t type,uint32_t idx)117812965SWilliam.Taylor@Oracle.COM hermon_icm_num_to_hdl(hermon_state_t *state, hermon_rsrc_type_t type,
117912965SWilliam.Taylor@Oracle.COM uint32_t idx)
118012965SWilliam.Taylor@Oracle.COM {
118112965SWilliam.Taylor@Oracle.COM hermon_icm_table_t *icm;
118212965SWilliam.Taylor@Oracle.COM uint32_t span_offset;
118312965SWilliam.Taylor@Oracle.COM uint32_t index1, index2;
118412965SWilliam.Taylor@Oracle.COM void ***p1, **p2;
118512965SWilliam.Taylor@Oracle.COM
118612965SWilliam.Taylor@Oracle.COM icm = &state->hs_icm[type];
118712965SWilliam.Taylor@Oracle.COM hermon_index(index1, index2, idx, icm, span_offset);
118812965SWilliam.Taylor@Oracle.COM p1 = icm->num_to_hdl[index1];
118912965SWilliam.Taylor@Oracle.COM if (p1 == NULL) {
119012965SWilliam.Taylor@Oracle.COM IBTF_DPRINTF_L2("hermon", "icm_num_to_hdl failed at level 1"
119112965SWilliam.Taylor@Oracle.COM ": rsrc_type %d, index 0x%x", type, idx);
119212965SWilliam.Taylor@Oracle.COM return (NULL);
119312965SWilliam.Taylor@Oracle.COM }
119412965SWilliam.Taylor@Oracle.COM p2 = p1[index2];
119512965SWilliam.Taylor@Oracle.COM if (p2 == NULL) {
119612965SWilliam.Taylor@Oracle.COM IBTF_DPRINTF_L2("hermon", "icm_num_to_hdl failed at level 2"
119712965SWilliam.Taylor@Oracle.COM ": rsrc_type %d, index 0x%x", type, idx);
119812965SWilliam.Taylor@Oracle.COM return (NULL);
119912965SWilliam.Taylor@Oracle.COM }
120012965SWilliam.Taylor@Oracle.COM return (p2[span_offset]);
120112965SWilliam.Taylor@Oracle.COM }
120212965SWilliam.Taylor@Oracle.COM
120312965SWilliam.Taylor@Oracle.COM /*
120412965SWilliam.Taylor@Oracle.COM * hermon_icm_set_num_to_hdl()
120512965SWilliam.Taylor@Oracle.COM * Context: Can be called from base or interrupt context.
120612965SWilliam.Taylor@Oracle.COM *
120712965SWilliam.Taylor@Oracle.COM * Given an index of a resource, we index through the sparsely allocated
120812965SWilliam.Taylor@Oracle.COM * arrays to store the software handle, used by hermon_icm_num_to_hdl().
120912965SWilliam.Taylor@Oracle.COM * This function is used to both set and reset (set to NULL) the handle.
121012965SWilliam.Taylor@Oracle.COM * This table is allocated during ICM allocation for the given resource,
121112965SWilliam.Taylor@Oracle.COM * so its existence is a given, and the store location does not conflict
121212965SWilliam.Taylor@Oracle.COM * with any other stores to the table (no locking needed).
121312965SWilliam.Taylor@Oracle.COM */
121412965SWilliam.Taylor@Oracle.COM void
hermon_icm_set_num_to_hdl(hermon_state_t * state,hermon_rsrc_type_t type,uint32_t idx,void * hdl)121512965SWilliam.Taylor@Oracle.COM hermon_icm_set_num_to_hdl(hermon_state_t *state, hermon_rsrc_type_t type,
121612965SWilliam.Taylor@Oracle.COM uint32_t idx, void *hdl)
121712965SWilliam.Taylor@Oracle.COM {
121812965SWilliam.Taylor@Oracle.COM hermon_icm_table_t *icm;
121912965SWilliam.Taylor@Oracle.COM uint32_t span_offset;
122012965SWilliam.Taylor@Oracle.COM uint32_t index1, index2;
122112965SWilliam.Taylor@Oracle.COM
122212965SWilliam.Taylor@Oracle.COM icm = &state->hs_icm[type];
122312965SWilliam.Taylor@Oracle.COM hermon_index(index1, index2, idx, icm, span_offset);
122412965SWilliam.Taylor@Oracle.COM ASSERT((hdl == NULL) ^
122512965SWilliam.Taylor@Oracle.COM (icm->num_to_hdl[index1][index2][span_offset] == NULL));
122612965SWilliam.Taylor@Oracle.COM icm->num_to_hdl[index1][index2][span_offset] = hdl;
122712965SWilliam.Taylor@Oracle.COM }
122812965SWilliam.Taylor@Oracle.COM
122912965SWilliam.Taylor@Oracle.COM /*
123012688SWilliam.Taylor@Oracle.COM * hermon_device_mode()
123112688SWilliam.Taylor@Oracle.COM * Context: Can be called from base or interrupt context.
123212688SWilliam.Taylor@Oracle.COM *
123312688SWilliam.Taylor@Oracle.COM * Return HERMON_HCA_MODE for operational mode
123412688SWilliam.Taylor@Oracle.COM * Return HERMON_MAINTENANCE_MODE for maintenance mode
123512688SWilliam.Taylor@Oracle.COM * Return 0 otherwise
123612688SWilliam.Taylor@Oracle.COM *
123712688SWilliam.Taylor@Oracle.COM * A non-zero return for either operational or maintenance mode simplifies
123812688SWilliam.Taylor@Oracle.COM * one of the 2 uses of this function.
123912688SWilliam.Taylor@Oracle.COM */
124012688SWilliam.Taylor@Oracle.COM int
hermon_device_mode(hermon_state_t * state)124112688SWilliam.Taylor@Oracle.COM hermon_device_mode(hermon_state_t *state)
124212688SWilliam.Taylor@Oracle.COM {
124312688SWilliam.Taylor@Oracle.COM if (state->hs_vendor_id != PCI_VENID_MLX)
124412688SWilliam.Taylor@Oracle.COM return (0);
124512688SWilliam.Taylor@Oracle.COM
124612688SWilliam.Taylor@Oracle.COM switch (state->hs_device_id) {
124712688SWilliam.Taylor@Oracle.COM case PCI_DEVID_HERMON_SDR:
124812688SWilliam.Taylor@Oracle.COM case PCI_DEVID_HERMON_DDR:
124912688SWilliam.Taylor@Oracle.COM case PCI_DEVID_HERMON_DDRG2:
125012688SWilliam.Taylor@Oracle.COM case PCI_DEVID_HERMON_QDRG2:
125112688SWilliam.Taylor@Oracle.COM case PCI_DEVID_HERMON_QDRG2V:
125212688SWilliam.Taylor@Oracle.COM return (HERMON_HCA_MODE);
125312688SWilliam.Taylor@Oracle.COM case PCI_DEVID_HERMON_MAINT:
125412688SWilliam.Taylor@Oracle.COM return (HERMON_MAINTENANCE_MODE);
125512688SWilliam.Taylor@Oracle.COM default:
125612688SWilliam.Taylor@Oracle.COM return (0);
125712688SWilliam.Taylor@Oracle.COM }
125812688SWilliam.Taylor@Oracle.COM }
125912688SWilliam.Taylor@Oracle.COM
12609517SBill.Taylor@Sun.COM /*
12619517SBill.Taylor@Sun.COM * hermon_drv_init()
12629517SBill.Taylor@Sun.COM * Context: Only called from attach() path context
12639517SBill.Taylor@Sun.COM */
12649517SBill.Taylor@Sun.COM /* ARGSUSED */
12659517SBill.Taylor@Sun.COM static int
hermon_drv_init(hermon_state_t * state,dev_info_t * dip,int instance)12669517SBill.Taylor@Sun.COM hermon_drv_init(hermon_state_t *state, dev_info_t *dip, int instance)
12679517SBill.Taylor@Sun.COM {
12689517SBill.Taylor@Sun.COM int status;
12699517SBill.Taylor@Sun.COM
127012688SWilliam.Taylor@Oracle.COM /* Retrieve PCI device, vendor and rev IDs */
127112688SWilliam.Taylor@Oracle.COM state->hs_vendor_id = HERMON_GET_VENDOR_ID(state->hs_dip);
127212688SWilliam.Taylor@Oracle.COM state->hs_device_id = HERMON_GET_DEVICE_ID(state->hs_dip);
127312688SWilliam.Taylor@Oracle.COM state->hs_revision_id = HERMON_GET_REVISION_ID(state->hs_dip);
127412688SWilliam.Taylor@Oracle.COM
12759517SBill.Taylor@Sun.COM /*
12769517SBill.Taylor@Sun.COM * Check and set the operational mode of the device. If the driver is
12779517SBill.Taylor@Sun.COM * bound to the Hermon device in "maintenance mode", then this generally
12789517SBill.Taylor@Sun.COM * means that either the device has been specifically jumpered to
12799517SBill.Taylor@Sun.COM * start in this mode or the firmware boot process has failed to
12809517SBill.Taylor@Sun.COM * successfully load either the primary or the secondary firmware
12819517SBill.Taylor@Sun.COM * image.
12829517SBill.Taylor@Sun.COM */
128312688SWilliam.Taylor@Oracle.COM state->hs_operational_mode = hermon_device_mode(state);
128412688SWilliam.Taylor@Oracle.COM switch (state->hs_operational_mode) {
128512688SWilliam.Taylor@Oracle.COM case HERMON_HCA_MODE:
12869517SBill.Taylor@Sun.COM state->hs_cfg_profile_setting = HERMON_CFG_MEMFREE;
128712688SWilliam.Taylor@Oracle.COM break;
128812688SWilliam.Taylor@Oracle.COM case HERMON_MAINTENANCE_MODE:
12899517SBill.Taylor@Sun.COM HERMON_FMANOTE(state, HERMON_FMA_MAINT);
129010125SEiji.Ota@Sun.COM state->hs_fm_degraded_reason = HCA_FW_MISC; /* not fw reason */
12919517SBill.Taylor@Sun.COM return (DDI_FAILURE);
129212688SWilliam.Taylor@Oracle.COM default:
12939517SBill.Taylor@Sun.COM HERMON_FMANOTE(state, HERMON_FMA_PCIID);
12949517SBill.Taylor@Sun.COM HERMON_WARNING(state, "unexpected device type detected");
12959517SBill.Taylor@Sun.COM return (DDI_FAILURE);
12969517SBill.Taylor@Sun.COM }
12979517SBill.Taylor@Sun.COM
12989517SBill.Taylor@Sun.COM /*
12999517SBill.Taylor@Sun.COM * Initialize the Hermon hardware.
13009517SBill.Taylor@Sun.COM *
13019517SBill.Taylor@Sun.COM * Note: If this routine returns an error, it is often a reasonably
13029517SBill.Taylor@Sun.COM * good indication that something Hermon firmware-related has caused
13039517SBill.Taylor@Sun.COM * the failure or some HW related errors have caused the failure.
13049517SBill.Taylor@Sun.COM * (also there are few possibilities that SW (e.g. SW resource
13059517SBill.Taylor@Sun.COM * shortage) can cause the failure, but the majority case is due to
13069517SBill.Taylor@Sun.COM * either a firmware related error or a HW related one) In order to
13079517SBill.Taylor@Sun.COM * give the user an opportunity (if desired) to update or reflash
13089517SBill.Taylor@Sun.COM * the Hermon firmware image, we set "hs_operational_mode" flag
13099517SBill.Taylor@Sun.COM * (described above) to indicate that we wish to enter maintenance
13109517SBill.Taylor@Sun.COM * mode in case of the firmware-related issue.
13119517SBill.Taylor@Sun.COM */
13129517SBill.Taylor@Sun.COM status = hermon_hw_init(state);
13139517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
13149517SBill.Taylor@Sun.COM cmn_err(CE_NOTE, "hermon%d: error during attach: %s", instance,
13159517SBill.Taylor@Sun.COM state->hs_attach_buf);
13169517SBill.Taylor@Sun.COM return (DDI_FAILURE);
13179517SBill.Taylor@Sun.COM }
13189517SBill.Taylor@Sun.COM
13199517SBill.Taylor@Sun.COM /*
13209517SBill.Taylor@Sun.COM * Now that the ISR has been setup, arm all the EQs for event
13219517SBill.Taylor@Sun.COM * generation.
13229517SBill.Taylor@Sun.COM */
13239517SBill.Taylor@Sun.COM
13249517SBill.Taylor@Sun.COM status = hermon_eq_arm_all(state);
13259517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
13269517SBill.Taylor@Sun.COM cmn_err(CE_NOTE, "EQ Arm All failed\n");
13279517SBill.Taylor@Sun.COM hermon_hw_fini(state, HERMON_DRV_CLEANUP_ALL);
13289517SBill.Taylor@Sun.COM return (DDI_FAILURE);
13299517SBill.Taylor@Sun.COM }
13309517SBill.Taylor@Sun.COM
13319517SBill.Taylor@Sun.COM /* test interrupts and event queues */
13329517SBill.Taylor@Sun.COM status = hermon_nop_post(state, 0x0, 0x0);
13339517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
13349517SBill.Taylor@Sun.COM cmn_err(CE_NOTE, "Interrupts/EQs failed\n");
13359517SBill.Taylor@Sun.COM hermon_hw_fini(state, HERMON_DRV_CLEANUP_ALL);
13369517SBill.Taylor@Sun.COM return (DDI_FAILURE);
13379517SBill.Taylor@Sun.COM }
13389517SBill.Taylor@Sun.COM
13399517SBill.Taylor@Sun.COM /* Initialize Hermon softstate */
13409517SBill.Taylor@Sun.COM status = hermon_soft_state_init(state);
13419517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
13429517SBill.Taylor@Sun.COM cmn_err(CE_NOTE, "Failed to init soft state\n");
13439517SBill.Taylor@Sun.COM hermon_hw_fini(state, HERMON_DRV_CLEANUP_ALL);
13449517SBill.Taylor@Sun.COM return (DDI_FAILURE);
13459517SBill.Taylor@Sun.COM }
13469517SBill.Taylor@Sun.COM
13479517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
13489517SBill.Taylor@Sun.COM }
13499517SBill.Taylor@Sun.COM
13509517SBill.Taylor@Sun.COM
13519517SBill.Taylor@Sun.COM /*
13529517SBill.Taylor@Sun.COM * hermon_drv_fini()
13539517SBill.Taylor@Sun.COM * Context: Only called from attach() and/or detach() path contexts
13549517SBill.Taylor@Sun.COM */
13559517SBill.Taylor@Sun.COM static void
hermon_drv_fini(hermon_state_t * state)13569517SBill.Taylor@Sun.COM hermon_drv_fini(hermon_state_t *state)
13579517SBill.Taylor@Sun.COM {
13589517SBill.Taylor@Sun.COM /* Cleanup Hermon softstate */
13599517SBill.Taylor@Sun.COM hermon_soft_state_fini(state);
13609517SBill.Taylor@Sun.COM
13619517SBill.Taylor@Sun.COM /* Cleanup Hermon resources and shutdown hardware */
13629517SBill.Taylor@Sun.COM hermon_hw_fini(state, HERMON_DRV_CLEANUP_ALL);
13639517SBill.Taylor@Sun.COM }
13649517SBill.Taylor@Sun.COM
13659517SBill.Taylor@Sun.COM
13669517SBill.Taylor@Sun.COM /*
13679517SBill.Taylor@Sun.COM * hermon_drv_fini2()
13689582SEiji.Ota@Sun.COM * Context: Only called from attach() and/or detach() path contexts
13699517SBill.Taylor@Sun.COM */
13709517SBill.Taylor@Sun.COM static void
hermon_drv_fini2(hermon_state_t * state)13719517SBill.Taylor@Sun.COM hermon_drv_fini2(hermon_state_t *state)
13729517SBill.Taylor@Sun.COM {
13739517SBill.Taylor@Sun.COM if (state->hs_fm_poll_thread) {
13749517SBill.Taylor@Sun.COM ddi_periodic_delete(state->hs_fm_poll_thread);
13759517SBill.Taylor@Sun.COM state->hs_fm_poll_thread = NULL;
13769517SBill.Taylor@Sun.COM }
13779582SEiji.Ota@Sun.COM
13789582SEiji.Ota@Sun.COM /* HERMON_DRV_CLEANUP_LEVEL1 */
13799517SBill.Taylor@Sun.COM if (state->hs_fm_cmdhdl) {
13809517SBill.Taylor@Sun.COM hermon_regs_map_free(state, &state->hs_fm_cmdhdl);
13819517SBill.Taylor@Sun.COM state->hs_fm_cmdhdl = NULL;
13829517SBill.Taylor@Sun.COM }
13839582SEiji.Ota@Sun.COM
13849517SBill.Taylor@Sun.COM if (state->hs_reg_cmdhdl) {
13859517SBill.Taylor@Sun.COM ddi_regs_map_free(&state->hs_reg_cmdhdl);
13869517SBill.Taylor@Sun.COM state->hs_reg_cmdhdl = NULL;
13879517SBill.Taylor@Sun.COM }
13889582SEiji.Ota@Sun.COM
13899582SEiji.Ota@Sun.COM /* HERMON_DRV_CLEANUP_LEVEL0 */
13909582SEiji.Ota@Sun.COM if (state->hs_msix_tbl_entries) {
13919582SEiji.Ota@Sun.COM kmem_free(state->hs_msix_tbl_entries,
13929582SEiji.Ota@Sun.COM state->hs_msix_tbl_size);
13939582SEiji.Ota@Sun.COM state->hs_msix_tbl_entries = NULL;
13949582SEiji.Ota@Sun.COM }
13959582SEiji.Ota@Sun.COM
13969582SEiji.Ota@Sun.COM if (state->hs_msix_pba_entries) {
13979582SEiji.Ota@Sun.COM kmem_free(state->hs_msix_pba_entries,
13989582SEiji.Ota@Sun.COM state->hs_msix_pba_size);
13999582SEiji.Ota@Sun.COM state->hs_msix_pba_entries = NULL;
14009582SEiji.Ota@Sun.COM }
14019582SEiji.Ota@Sun.COM
14029582SEiji.Ota@Sun.COM if (state->hs_fm_msix_tblhdl) {
14039582SEiji.Ota@Sun.COM hermon_regs_map_free(state, &state->hs_fm_msix_tblhdl);
14049582SEiji.Ota@Sun.COM state->hs_fm_msix_tblhdl = NULL;
14059582SEiji.Ota@Sun.COM }
14069582SEiji.Ota@Sun.COM
14079582SEiji.Ota@Sun.COM if (state->hs_reg_msix_tblhdl) {
14089582SEiji.Ota@Sun.COM ddi_regs_map_free(&state->hs_reg_msix_tblhdl);
14099582SEiji.Ota@Sun.COM state->hs_reg_msix_tblhdl = NULL;
14109582SEiji.Ota@Sun.COM }
14119582SEiji.Ota@Sun.COM
14129582SEiji.Ota@Sun.COM if (state->hs_fm_msix_pbahdl) {
14139582SEiji.Ota@Sun.COM hermon_regs_map_free(state, &state->hs_fm_msix_pbahdl);
14149582SEiji.Ota@Sun.COM state->hs_fm_msix_pbahdl = NULL;
14159582SEiji.Ota@Sun.COM }
14169582SEiji.Ota@Sun.COM
14179582SEiji.Ota@Sun.COM if (state->hs_reg_msix_pbahdl) {
14189582SEiji.Ota@Sun.COM ddi_regs_map_free(&state->hs_reg_msix_pbahdl);
14199582SEiji.Ota@Sun.COM state->hs_reg_msix_pbahdl = NULL;
14209582SEiji.Ota@Sun.COM }
14219582SEiji.Ota@Sun.COM
14229582SEiji.Ota@Sun.COM if (state->hs_fm_pcihdl) {
14239582SEiji.Ota@Sun.COM hermon_pci_config_teardown(state, &state->hs_fm_pcihdl);
14249582SEiji.Ota@Sun.COM state->hs_fm_pcihdl = NULL;
14259582SEiji.Ota@Sun.COM }
14269582SEiji.Ota@Sun.COM
14279582SEiji.Ota@Sun.COM if (state->hs_reg_pcihdl) {
14289582SEiji.Ota@Sun.COM pci_config_teardown(&state->hs_reg_pcihdl);
14299582SEiji.Ota@Sun.COM state->hs_reg_pcihdl = NULL;
14309582SEiji.Ota@Sun.COM }
14319517SBill.Taylor@Sun.COM }
14329517SBill.Taylor@Sun.COM
14339517SBill.Taylor@Sun.COM
14349517SBill.Taylor@Sun.COM /*
14359517SBill.Taylor@Sun.COM * hermon_isr_init()
14369517SBill.Taylor@Sun.COM * Context: Only called from attach() path context
14379517SBill.Taylor@Sun.COM */
14389517SBill.Taylor@Sun.COM static int
hermon_isr_init(hermon_state_t * state)14399517SBill.Taylor@Sun.COM hermon_isr_init(hermon_state_t *state)
14409517SBill.Taylor@Sun.COM {
14419517SBill.Taylor@Sun.COM int status;
14429517SBill.Taylor@Sun.COM int intr;
14439517SBill.Taylor@Sun.COM
14449517SBill.Taylor@Sun.COM for (intr = 0; intr < state->hs_intrmsi_allocd; intr++) {
14459517SBill.Taylor@Sun.COM
14469517SBill.Taylor@Sun.COM /*
14479517SBill.Taylor@Sun.COM * Add a handler for the interrupt or MSI
14489517SBill.Taylor@Sun.COM */
14499517SBill.Taylor@Sun.COM status = ddi_intr_add_handler(state->hs_intrmsi_hdl[intr],
14509517SBill.Taylor@Sun.COM hermon_isr, (caddr_t)state, (void *)(uintptr_t)intr);
14519517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
14529517SBill.Taylor@Sun.COM return (DDI_FAILURE);
14539517SBill.Taylor@Sun.COM }
14549517SBill.Taylor@Sun.COM
14559517SBill.Taylor@Sun.COM /*
14569517SBill.Taylor@Sun.COM * Enable the software interrupt. Note: depending on the value
14579517SBill.Taylor@Sun.COM * returned in the capability flag, we have to call either
14589517SBill.Taylor@Sun.COM * ddi_intr_block_enable() or ddi_intr_enable().
14599517SBill.Taylor@Sun.COM */
14609517SBill.Taylor@Sun.COM if (state->hs_intrmsi_cap & DDI_INTR_FLAG_BLOCK) {
14619517SBill.Taylor@Sun.COM status = ddi_intr_block_enable(
14629517SBill.Taylor@Sun.COM &state->hs_intrmsi_hdl[intr], 1);
14639517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
14649517SBill.Taylor@Sun.COM return (DDI_FAILURE);
14659517SBill.Taylor@Sun.COM }
14669517SBill.Taylor@Sun.COM } else {
14679517SBill.Taylor@Sun.COM status = ddi_intr_enable(state->hs_intrmsi_hdl[intr]);
14689517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
14699517SBill.Taylor@Sun.COM return (DDI_FAILURE);
14709517SBill.Taylor@Sun.COM }
14719517SBill.Taylor@Sun.COM }
14729517SBill.Taylor@Sun.COM }
14739517SBill.Taylor@Sun.COM
14749517SBill.Taylor@Sun.COM /*
14759517SBill.Taylor@Sun.COM * Now that the ISR has been enabled, defer arm_all EQs for event
14769517SBill.Taylor@Sun.COM * generation until later, in case MSIX is enabled
14779517SBill.Taylor@Sun.COM */
14789517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
14799517SBill.Taylor@Sun.COM }
14809517SBill.Taylor@Sun.COM
14819517SBill.Taylor@Sun.COM
14829517SBill.Taylor@Sun.COM /*
14839517SBill.Taylor@Sun.COM * hermon_isr_fini()
14849517SBill.Taylor@Sun.COM * Context: Only called from attach() and/or detach() path contexts
14859517SBill.Taylor@Sun.COM */
14869517SBill.Taylor@Sun.COM static void
hermon_isr_fini(hermon_state_t * state)14879517SBill.Taylor@Sun.COM hermon_isr_fini(hermon_state_t *state)
14889517SBill.Taylor@Sun.COM {
14899517SBill.Taylor@Sun.COM int intr;
14909517SBill.Taylor@Sun.COM
14919517SBill.Taylor@Sun.COM for (intr = 0; intr < state->hs_intrmsi_allocd; intr++) {
14929517SBill.Taylor@Sun.COM /* Disable the software interrupt */
14939517SBill.Taylor@Sun.COM if (state->hs_intrmsi_cap & DDI_INTR_FLAG_BLOCK) {
14949517SBill.Taylor@Sun.COM (void) ddi_intr_block_disable(
14959517SBill.Taylor@Sun.COM &state->hs_intrmsi_hdl[intr], 1);
14969517SBill.Taylor@Sun.COM } else {
14979517SBill.Taylor@Sun.COM (void) ddi_intr_disable(state->hs_intrmsi_hdl[intr]);
14989517SBill.Taylor@Sun.COM }
14999517SBill.Taylor@Sun.COM
15009517SBill.Taylor@Sun.COM /*
15019517SBill.Taylor@Sun.COM * Remove the software handler for the interrupt or MSI
15029517SBill.Taylor@Sun.COM */
15039517SBill.Taylor@Sun.COM (void) ddi_intr_remove_handler(state->hs_intrmsi_hdl[intr]);
15049517SBill.Taylor@Sun.COM }
15059517SBill.Taylor@Sun.COM }
15069517SBill.Taylor@Sun.COM
15079517SBill.Taylor@Sun.COM
15089517SBill.Taylor@Sun.COM /*
15099517SBill.Taylor@Sun.COM * Sum of ICM configured values:
15109517SBill.Taylor@Sun.COM * cMPT, dMPT, MTT, QPC, SRQC, RDB, CQC, ALTC, AUXC, EQC, MCG
15119517SBill.Taylor@Sun.COM *
15129517SBill.Taylor@Sun.COM */
15139517SBill.Taylor@Sun.COM static uint64_t
hermon_size_icm(hermon_state_t * state)15149517SBill.Taylor@Sun.COM hermon_size_icm(hermon_state_t *state)
15159517SBill.Taylor@Sun.COM {
15169517SBill.Taylor@Sun.COM hermon_hw_querydevlim_t *devlim;
15179517SBill.Taylor@Sun.COM hermon_cfg_profile_t *cfg;
15189517SBill.Taylor@Sun.COM uint64_t num_cmpts, num_dmpts, num_mtts;
15199517SBill.Taylor@Sun.COM uint64_t num_qpcs, num_srqc, num_rdbs;
15209517SBill.Taylor@Sun.COM #ifndef HERMON_FW_WORKAROUND
15219517SBill.Taylor@Sun.COM uint64_t num_auxc;
15229517SBill.Taylor@Sun.COM #endif
15239517SBill.Taylor@Sun.COM uint64_t num_cqcs, num_altc;
15249517SBill.Taylor@Sun.COM uint64_t num_eqcs, num_mcgs;
15259517SBill.Taylor@Sun.COM uint64_t size;
15269517SBill.Taylor@Sun.COM
15279517SBill.Taylor@Sun.COM devlim = &state->hs_devlim;
15289517SBill.Taylor@Sun.COM cfg = state->hs_cfg_profile;
15299517SBill.Taylor@Sun.COM /* number of respective entries */
15309517SBill.Taylor@Sun.COM num_cmpts = (uint64_t)0x1 << cfg->cp_log_num_cmpt;
15319517SBill.Taylor@Sun.COM num_mtts = (uint64_t)0x1 << cfg->cp_log_num_mtt;
15329517SBill.Taylor@Sun.COM num_dmpts = (uint64_t)0x1 << cfg->cp_log_num_dmpt;
15339517SBill.Taylor@Sun.COM num_qpcs = (uint64_t)0x1 << cfg->cp_log_num_qp;
15349517SBill.Taylor@Sun.COM num_srqc = (uint64_t)0x1 << cfg->cp_log_num_srq;
15359517SBill.Taylor@Sun.COM num_rdbs = (uint64_t)0x1 << cfg->cp_log_num_rdb;
15369517SBill.Taylor@Sun.COM num_cqcs = (uint64_t)0x1 << cfg->cp_log_num_cq;
15379517SBill.Taylor@Sun.COM num_altc = (uint64_t)0x1 << cfg->cp_log_num_qp;
15389517SBill.Taylor@Sun.COM #ifndef HERMON_FW_WORKAROUND
15399517SBill.Taylor@Sun.COM num_auxc = (uint64_t)0x1 << cfg->cp_log_num_qp;
15409517SBill.Taylor@Sun.COM #endif
15419517SBill.Taylor@Sun.COM num_eqcs = (uint64_t)0x1 << cfg->cp_log_num_eq;
15429517SBill.Taylor@Sun.COM num_mcgs = (uint64_t)0x1 << cfg->cp_log_num_mcg;
15439517SBill.Taylor@Sun.COM
15449517SBill.Taylor@Sun.COM size =
15459517SBill.Taylor@Sun.COM num_cmpts * devlim->cmpt_entry_sz +
15469517SBill.Taylor@Sun.COM num_dmpts * devlim->dmpt_entry_sz +
15479517SBill.Taylor@Sun.COM num_mtts * devlim->mtt_entry_sz +
15489517SBill.Taylor@Sun.COM num_qpcs * devlim->qpc_entry_sz +
15499517SBill.Taylor@Sun.COM num_srqc * devlim->srq_entry_sz +
15509517SBill.Taylor@Sun.COM num_rdbs * devlim->rdmardc_entry_sz +
15519517SBill.Taylor@Sun.COM num_cqcs * devlim->cqc_entry_sz +
15529517SBill.Taylor@Sun.COM num_altc * devlim->altc_entry_sz +
15539517SBill.Taylor@Sun.COM #ifdef HERMON_FW_WORKAROUND
15549517SBill.Taylor@Sun.COM 0x80000000ull +
15559517SBill.Taylor@Sun.COM #else
15569517SBill.Taylor@Sun.COM num_auxc * devlim->aux_entry_sz +
15579517SBill.Taylor@Sun.COM #endif
15589517SBill.Taylor@Sun.COM num_eqcs * devlim->eqc_entry_sz +
15599517SBill.Taylor@Sun.COM num_mcgs * HERMON_MCGMEM_SZ(state);
15609517SBill.Taylor@Sun.COM return (size);
15619517SBill.Taylor@Sun.COM }
15629517SBill.Taylor@Sun.COM
15639517SBill.Taylor@Sun.COM
15649517SBill.Taylor@Sun.COM /*
15659517SBill.Taylor@Sun.COM * hermon_hw_init()
15669517SBill.Taylor@Sun.COM * Context: Only called from attach() path context
15679517SBill.Taylor@Sun.COM */
15689517SBill.Taylor@Sun.COM static int
hermon_hw_init(hermon_state_t * state)15699517SBill.Taylor@Sun.COM hermon_hw_init(hermon_state_t *state)
15709517SBill.Taylor@Sun.COM {
15719517SBill.Taylor@Sun.COM hermon_drv_cleanup_level_t cleanup;
15729517SBill.Taylor@Sun.COM sm_nodeinfo_t nodeinfo;
15739517SBill.Taylor@Sun.COM uint64_t clr_intr_offset;
15749517SBill.Taylor@Sun.COM int status;
15759517SBill.Taylor@Sun.COM uint32_t fw_size; /* in page */
15769517SBill.Taylor@Sun.COM uint64_t offset;
15779517SBill.Taylor@Sun.COM
15789517SBill.Taylor@Sun.COM /* This is where driver initialization begins */
15799517SBill.Taylor@Sun.COM cleanup = HERMON_DRV_CLEANUP_LEVEL0;
15809517SBill.Taylor@Sun.COM
15819517SBill.Taylor@Sun.COM /* Setup device access attributes */
158211236SStephen.Hanson@Sun.COM state->hs_reg_accattr.devacc_attr_version = DDI_DEVICE_ATTR_V1;
15839517SBill.Taylor@Sun.COM state->hs_reg_accattr.devacc_attr_endian_flags = DDI_STRUCTURE_BE_ACC;
15849517SBill.Taylor@Sun.COM state->hs_reg_accattr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
15859517SBill.Taylor@Sun.COM state->hs_reg_accattr.devacc_attr_access = DDI_DEFAULT_ACC;
15869517SBill.Taylor@Sun.COM
15879517SBill.Taylor@Sun.COM /* Setup fma-protected access attributes */
15889517SBill.Taylor@Sun.COM state->hs_fm_accattr.devacc_attr_version =
15899517SBill.Taylor@Sun.COM hermon_devacc_attr_version(state);
15909517SBill.Taylor@Sun.COM state->hs_fm_accattr.devacc_attr_endian_flags = DDI_STRUCTURE_BE_ACC;
15919517SBill.Taylor@Sun.COM state->hs_fm_accattr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
15929517SBill.Taylor@Sun.COM /* set acc err protection type */
15939517SBill.Taylor@Sun.COM state->hs_fm_accattr.devacc_attr_access =
15949517SBill.Taylor@Sun.COM hermon_devacc_attr_access(state);
15959517SBill.Taylor@Sun.COM
15969517SBill.Taylor@Sun.COM /* Setup for PCI config read/write of HCA device */
15979517SBill.Taylor@Sun.COM status = hermon_pci_config_setup(state, &state->hs_fm_pcihdl);
15989517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
15999517SBill.Taylor@Sun.COM hermon_hw_fini(state, cleanup);
16009517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
16019517SBill.Taylor@Sun.COM "hw_init_PCI_config_space_regmap_fail");
16029517SBill.Taylor@Sun.COM /* This case is not the degraded one */
16039517SBill.Taylor@Sun.COM return (DDI_FAILURE);
16049517SBill.Taylor@Sun.COM }
16059517SBill.Taylor@Sun.COM
16069517SBill.Taylor@Sun.COM /* Map PCI config space and MSI-X tables/pba */
16079517SBill.Taylor@Sun.COM hermon_set_msix_info(state);
16089517SBill.Taylor@Sun.COM
16099517SBill.Taylor@Sun.COM /* Map in Hermon registers (CMD, UAR, MSIX) and setup offsets */
16109517SBill.Taylor@Sun.COM status = hermon_regs_map_setup(state, HERMON_CMD_BAR,
16119517SBill.Taylor@Sun.COM &state->hs_reg_cmd_baseaddr, 0, 0, &state->hs_fm_accattr,
16129517SBill.Taylor@Sun.COM &state->hs_fm_cmdhdl);
16139517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
16149517SBill.Taylor@Sun.COM hermon_hw_fini(state, cleanup);
16159517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
16169517SBill.Taylor@Sun.COM "hw_init_CMD_BAR_regmap_fail");
16179517SBill.Taylor@Sun.COM /* This case is not the degraded one */
16189517SBill.Taylor@Sun.COM return (DDI_FAILURE);
16199517SBill.Taylor@Sun.COM }
16209517SBill.Taylor@Sun.COM
16219517SBill.Taylor@Sun.COM cleanup = HERMON_DRV_CLEANUP_LEVEL1;
16229517SBill.Taylor@Sun.COM /*
16239517SBill.Taylor@Sun.COM * We defer UAR-BAR mapping until later. Need to know if
16249517SBill.Taylor@Sun.COM * blueflame mapping is to be done, and don't know that until after
16259517SBill.Taylor@Sun.COM * we get the dev_caps, so do it right after that
16269517SBill.Taylor@Sun.COM */
16279517SBill.Taylor@Sun.COM
16289517SBill.Taylor@Sun.COM /*
16299517SBill.Taylor@Sun.COM * There is a third BAR defined for Hermon - it is for MSIX
16309517SBill.Taylor@Sun.COM *
16319517SBill.Taylor@Sun.COM * Will need to explore it's possible need/use w/ Mellanox
16329517SBill.Taylor@Sun.COM * [es] Temporary mapping maybe
16339517SBill.Taylor@Sun.COM */
16349517SBill.Taylor@Sun.COM
16359517SBill.Taylor@Sun.COM #ifdef HERMON_SUPPORTS_MSIX_BAR
16369517SBill.Taylor@Sun.COM status = ddi_regs_map_setup(state->hs_dip, HERMON_MSIX_BAR,
16379517SBill.Taylor@Sun.COM &state->hs_reg_msi_baseaddr, 0, 0, &state->hs_reg_accattr,
16389517SBill.Taylor@Sun.COM &state->hs_reg_msihdl);
16399517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
16409517SBill.Taylor@Sun.COM hermon_hw_fini(state, cleanup);
16419517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
16429517SBill.Taylor@Sun.COM "hw_init_MSIX_BAR_regmap_fail");
16439517SBill.Taylor@Sun.COM /* This case is not the degraded one */
16449517SBill.Taylor@Sun.COM return (DDI_FAILURE);
16459517SBill.Taylor@Sun.COM }
16469517SBill.Taylor@Sun.COM #endif
16479517SBill.Taylor@Sun.COM
16489517SBill.Taylor@Sun.COM cleanup = HERMON_DRV_CLEANUP_LEVEL2;
16499517SBill.Taylor@Sun.COM
16509517SBill.Taylor@Sun.COM /*
16519517SBill.Taylor@Sun.COM * Save interesting registers away. The offsets of the first two
16529517SBill.Taylor@Sun.COM * here (HCR and sw_reset) are detailed in the PRM, the others are
16539517SBill.Taylor@Sun.COM * derived from values in the QUERY_FW output, so we'll save them
16549517SBill.Taylor@Sun.COM * off later.
16559517SBill.Taylor@Sun.COM */
16569517SBill.Taylor@Sun.COM /* Host Command Register (HCR) */
16579517SBill.Taylor@Sun.COM state->hs_cmd_regs.hcr = (hermon_hw_hcr_t *)
16589517SBill.Taylor@Sun.COM ((uintptr_t)state->hs_reg_cmd_baseaddr + HERMON_CMD_HCR_OFFSET);
16599517SBill.Taylor@Sun.COM state->hs_cmd_toggle = 0; /* initialize it for use */
16609517SBill.Taylor@Sun.COM
16619517SBill.Taylor@Sun.COM /* Software Reset register (sw_reset) and semaphore */
16629517SBill.Taylor@Sun.COM state->hs_cmd_regs.sw_reset = (uint32_t *)
16639517SBill.Taylor@Sun.COM ((uintptr_t)state->hs_reg_cmd_baseaddr +
16649517SBill.Taylor@Sun.COM HERMON_CMD_SW_RESET_OFFSET);
16659517SBill.Taylor@Sun.COM state->hs_cmd_regs.sw_semaphore = (uint32_t *)
16669517SBill.Taylor@Sun.COM ((uintptr_t)state->hs_reg_cmd_baseaddr +
16679517SBill.Taylor@Sun.COM HERMON_CMD_SW_SEMAPHORE_OFFSET);
16689517SBill.Taylor@Sun.COM
16699517SBill.Taylor@Sun.COM /* make sure init'd before we start filling things in */
16709517SBill.Taylor@Sun.COM bzero(&state->hs_hcaparams, sizeof (struct hermon_hw_initqueryhca_s));
16719517SBill.Taylor@Sun.COM
16729517SBill.Taylor@Sun.COM /* Initialize the Phase1 configuration profile */
16739517SBill.Taylor@Sun.COM status = hermon_cfg_profile_init_phase1(state);
16749517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
16759517SBill.Taylor@Sun.COM hermon_hw_fini(state, cleanup);
16769517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
16779517SBill.Taylor@Sun.COM "hw_init_cfginit1_fail");
16789517SBill.Taylor@Sun.COM /* This case is not the degraded one */
16799517SBill.Taylor@Sun.COM return (DDI_FAILURE);
16809517SBill.Taylor@Sun.COM }
16819517SBill.Taylor@Sun.COM cleanup = HERMON_DRV_CLEANUP_LEVEL3;
16829517SBill.Taylor@Sun.COM
16839517SBill.Taylor@Sun.COM /* Do a software reset of the adapter to ensure proper state */
16849517SBill.Taylor@Sun.COM status = hermon_sw_reset(state);
16859517SBill.Taylor@Sun.COM if (status != HERMON_CMD_SUCCESS) {
16869517SBill.Taylor@Sun.COM hermon_hw_fini(state, cleanup);
16879517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
16889517SBill.Taylor@Sun.COM "hw_init_sw_reset_fail");
16899517SBill.Taylor@Sun.COM /* This case is not the degraded one */
16909517SBill.Taylor@Sun.COM return (DDI_FAILURE);
16919517SBill.Taylor@Sun.COM }
16929517SBill.Taylor@Sun.COM
16939517SBill.Taylor@Sun.COM /* Initialize mailboxes */
16949517SBill.Taylor@Sun.COM status = hermon_rsrc_init_phase1(state);
16959517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
16969517SBill.Taylor@Sun.COM hermon_hw_fini(state, cleanup);
16979517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
16989517SBill.Taylor@Sun.COM "hw_init_rsrcinit1_fail");
16999517SBill.Taylor@Sun.COM /* This case is not the degraded one */
17009517SBill.Taylor@Sun.COM return (DDI_FAILURE);
17019517SBill.Taylor@Sun.COM }
17029517SBill.Taylor@Sun.COM cleanup = HERMON_DRV_CLEANUP_LEVEL4;
17039517SBill.Taylor@Sun.COM
17049517SBill.Taylor@Sun.COM /* Post QUERY_FW */
17059517SBill.Taylor@Sun.COM status = hermon_cmn_query_cmd_post(state, QUERY_FW, 0, 0, &state->hs_fw,
17069517SBill.Taylor@Sun.COM sizeof (hermon_hw_queryfw_t), HERMON_CMD_NOSLEEP_SPIN);
17079517SBill.Taylor@Sun.COM if (status != HERMON_CMD_SUCCESS) {
17089517SBill.Taylor@Sun.COM cmn_err(CE_NOTE, "QUERY_FW command failed: %08x\n", status);
17099517SBill.Taylor@Sun.COM hermon_hw_fini(state, cleanup);
17109517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
17119517SBill.Taylor@Sun.COM "hw_init_query_fw_cmd_fail");
17129517SBill.Taylor@Sun.COM /* This case is not the degraded one */
17139517SBill.Taylor@Sun.COM return (DDI_FAILURE);
17149517SBill.Taylor@Sun.COM }
17159517SBill.Taylor@Sun.COM
17169517SBill.Taylor@Sun.COM /* Validate what/that HERMON FW version is appropriate */
17179517SBill.Taylor@Sun.COM
17189517SBill.Taylor@Sun.COM status = hermon_fw_version_check(state);
17199517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
17209517SBill.Taylor@Sun.COM HERMON_FMANOTE(state, HERMON_FMA_FWVER);
17219517SBill.Taylor@Sun.COM if (state->hs_operational_mode == HERMON_HCA_MODE) {
17229517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "Unsupported Hermon FW version: "
17239517SBill.Taylor@Sun.COM "expected: %04d.%04d.%04d, "
17249517SBill.Taylor@Sun.COM "actual: %04d.%04d.%04d\n",
17259517SBill.Taylor@Sun.COM HERMON_FW_VER_MAJOR,
17269517SBill.Taylor@Sun.COM HERMON_FW_VER_MINOR,
17279517SBill.Taylor@Sun.COM HERMON_FW_VER_SUBMINOR,
17289517SBill.Taylor@Sun.COM state->hs_fw.fw_rev_major,
17299517SBill.Taylor@Sun.COM state->hs_fw.fw_rev_minor,
17309517SBill.Taylor@Sun.COM state->hs_fw.fw_rev_subminor);
17319517SBill.Taylor@Sun.COM } else {
17329517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "Unsupported FW version: "
17339517SBill.Taylor@Sun.COM "%04d.%04d.%04d\n",
17349517SBill.Taylor@Sun.COM state->hs_fw.fw_rev_major,
17359517SBill.Taylor@Sun.COM state->hs_fw.fw_rev_minor,
17369517SBill.Taylor@Sun.COM state->hs_fw.fw_rev_subminor);
17379517SBill.Taylor@Sun.COM }
17389517SBill.Taylor@Sun.COM state->hs_operational_mode = HERMON_MAINTENANCE_MODE;
173910125SEiji.Ota@Sun.COM state->hs_fm_degraded_reason = HCA_FW_MISMATCH;
17409517SBill.Taylor@Sun.COM hermon_hw_fini(state, cleanup);
17419517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
17429517SBill.Taylor@Sun.COM "hw_init_checkfwver_fail");
17439517SBill.Taylor@Sun.COM /* This case is the degraded one */
17449517SBill.Taylor@Sun.COM return (HERMON_CMD_BAD_NVMEM);
17459517SBill.Taylor@Sun.COM }
17469517SBill.Taylor@Sun.COM
17479517SBill.Taylor@Sun.COM /*
17489517SBill.Taylor@Sun.COM * Save off the rest of the interesting registers that we'll be using.
17499517SBill.Taylor@Sun.COM * Setup the offsets for the other registers.
17509517SBill.Taylor@Sun.COM */
17519517SBill.Taylor@Sun.COM
17529517SBill.Taylor@Sun.COM /*
17539517SBill.Taylor@Sun.COM * Hermon does the intr_offset from the BAR - technically should get the
17549517SBill.Taylor@Sun.COM * BAR info from the response, but PRM says it's from BAR0-1, which is
17559517SBill.Taylor@Sun.COM * for us the CMD BAR
17569517SBill.Taylor@Sun.COM */
17579517SBill.Taylor@Sun.COM
17589517SBill.Taylor@Sun.COM clr_intr_offset = state->hs_fw.clr_intr_offs & HERMON_CMD_OFFSET_MASK;
17599517SBill.Taylor@Sun.COM
17609517SBill.Taylor@Sun.COM /* Save Clear Interrupt address */
17619517SBill.Taylor@Sun.COM state->hs_cmd_regs.clr_intr = (uint64_t *)
17629517SBill.Taylor@Sun.COM (uintptr_t)(state->hs_reg_cmd_baseaddr + clr_intr_offset);
17639517SBill.Taylor@Sun.COM
17649517SBill.Taylor@Sun.COM /*
17659517SBill.Taylor@Sun.COM * Set the error buffer also into the structure - used in hermon_event.c
17669517SBill.Taylor@Sun.COM * to check for internal error on the HCA, not reported in eqe or
17679517SBill.Taylor@Sun.COM * (necessarily) by interrupt
17689517SBill.Taylor@Sun.COM */
17699517SBill.Taylor@Sun.COM state->hs_cmd_regs.fw_err_buf = (uint32_t *)(uintptr_t)
17709517SBill.Taylor@Sun.COM (state->hs_reg_cmd_baseaddr + state->hs_fw.error_buf_addr);
17719517SBill.Taylor@Sun.COM
17729517SBill.Taylor@Sun.COM /*
17739517SBill.Taylor@Sun.COM * Invoke a polling thread to check the error buffer periodically.
17749517SBill.Taylor@Sun.COM */
17759778SEiji.Ota@Sun.COM if (!hermon_no_inter_err_chk) {
17769778SEiji.Ota@Sun.COM state->hs_fm_poll_thread = ddi_periodic_add(
17779778SEiji.Ota@Sun.COM hermon_inter_err_chk, (void *)state, FM_POLL_INTERVAL,
17789778SEiji.Ota@Sun.COM DDI_IPL_0);
17799778SEiji.Ota@Sun.COM }
17809517SBill.Taylor@Sun.COM
17819517SBill.Taylor@Sun.COM cleanup = HERMON_DRV_CLEANUP_LEVEL5;
17829517SBill.Taylor@Sun.COM
17839517SBill.Taylor@Sun.COM /*
17849517SBill.Taylor@Sun.COM * Allocate, map, and run the HCA Firmware.
17859517SBill.Taylor@Sun.COM */
17869517SBill.Taylor@Sun.COM
17879517SBill.Taylor@Sun.COM /* Allocate memory for the firmware to load into and map it */
17889517SBill.Taylor@Sun.COM
17899517SBill.Taylor@Sun.COM /* get next higher power of 2 */
17909517SBill.Taylor@Sun.COM fw_size = 1 << highbit(state->hs_fw.fw_pages);
17919517SBill.Taylor@Sun.COM state->hs_fw_dma.length = fw_size << HERMON_PAGESHIFT;
17929517SBill.Taylor@Sun.COM status = hermon_dma_alloc(state, &state->hs_fw_dma, MAP_FA);
17939517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
17949517SBill.Taylor@Sun.COM cmn_err(CE_NOTE, "FW alloc failed\n");
17959517SBill.Taylor@Sun.COM hermon_hw_fini(state, cleanup);
17969517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
17979517SBill.Taylor@Sun.COM "hw_init_dma_alloc_fw_fail");
17989517SBill.Taylor@Sun.COM /* This case is not the degraded one */
17999517SBill.Taylor@Sun.COM return (DDI_FAILURE);
18009517SBill.Taylor@Sun.COM }
18019517SBill.Taylor@Sun.COM
18029517SBill.Taylor@Sun.COM cleanup = HERMON_DRV_CLEANUP_LEVEL6;
18039517SBill.Taylor@Sun.COM
18049517SBill.Taylor@Sun.COM /* Invoke the RUN_FW cmd to run the firmware */
18059517SBill.Taylor@Sun.COM status = hermon_run_fw_cmd_post(state);
18069517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
18079517SBill.Taylor@Sun.COM cmn_err(CE_NOTE, "RUN_FW command failed: 0x%08x\n", status);
18089517SBill.Taylor@Sun.COM if (status == HERMON_CMD_BAD_NVMEM) {
18099517SBill.Taylor@Sun.COM state->hs_operational_mode = HERMON_MAINTENANCE_MODE;
181010125SEiji.Ota@Sun.COM state->hs_fm_degraded_reason = HCA_FW_CORRUPT;
18119517SBill.Taylor@Sun.COM }
18129517SBill.Taylor@Sun.COM hermon_hw_fini(state, cleanup);
18139517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf, "hw_init_run_fw_fail");
18149517SBill.Taylor@Sun.COM /*
18159517SBill.Taylor@Sun.COM * If the status is HERMON_CMD_BAD_NVMEM, it's likely the
18169517SBill.Taylor@Sun.COM * firmware is corrupted, so the mode falls into the
18179517SBill.Taylor@Sun.COM * maintenance mode.
18189517SBill.Taylor@Sun.COM */
18199517SBill.Taylor@Sun.COM return (status == HERMON_CMD_BAD_NVMEM ? HERMON_CMD_BAD_NVMEM :
18209517SBill.Taylor@Sun.COM DDI_FAILURE);
18219517SBill.Taylor@Sun.COM }
18229517SBill.Taylor@Sun.COM
18239517SBill.Taylor@Sun.COM
18249517SBill.Taylor@Sun.COM /*
18259517SBill.Taylor@Sun.COM * QUERY DEVICE LIMITS/CAPABILITIES
18269517SBill.Taylor@Sun.COM * NOTE - in Hermon, the command is changed to QUERY_DEV_CAP,
18279517SBill.Taylor@Sun.COM * but for familiarity we have kept the structure name the
18289517SBill.Taylor@Sun.COM * same as Tavor/Arbel
18299517SBill.Taylor@Sun.COM */
18309517SBill.Taylor@Sun.COM
18319517SBill.Taylor@Sun.COM status = hermon_cmn_query_cmd_post(state, QUERY_DEV_CAP, 0, 0,
18329517SBill.Taylor@Sun.COM &state->hs_devlim, sizeof (hermon_hw_querydevlim_t),
18339517SBill.Taylor@Sun.COM HERMON_CMD_NOSLEEP_SPIN);
18349517SBill.Taylor@Sun.COM if (status != HERMON_CMD_SUCCESS) {
18359517SBill.Taylor@Sun.COM cmn_err(CE_NOTE, "QUERY_DEV_CAP command failed: 0x%08x\n",
18369517SBill.Taylor@Sun.COM status);
18379517SBill.Taylor@Sun.COM hermon_hw_fini(state, cleanup);
18389517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf, "hw_init_devcap_fail");
18399517SBill.Taylor@Sun.COM /* This case is not the degraded one */
18409517SBill.Taylor@Sun.COM return (DDI_FAILURE);
18419517SBill.Taylor@Sun.COM }
18429517SBill.Taylor@Sun.COM
184312965SWilliam.Taylor@Oracle.COM state->hs_rsvd_eqs = max(state->hs_devlim.num_rsvd_eq,
184412965SWilliam.Taylor@Oracle.COM (4 * state->hs_devlim.num_rsvd_uar));
18459517SBill.Taylor@Sun.COM
18469517SBill.Taylor@Sun.COM /* now we have enough info to map in the UAR BAR */
18479517SBill.Taylor@Sun.COM /*
18489517SBill.Taylor@Sun.COM * First, we figure out how to map the BAR for UAR - use only half if
18499517SBill.Taylor@Sun.COM * BlueFlame is enabled - in that case the mapped length is 1/2 the
18509517SBill.Taylor@Sun.COM * log_max_uar_sz (max__uar - 1) * 1MB ( +20).
18519517SBill.Taylor@Sun.COM */
18529517SBill.Taylor@Sun.COM
18539517SBill.Taylor@Sun.COM if (state->hs_devlim.blu_flm) { /* Blue Flame Enabled */
18549517SBill.Taylor@Sun.COM offset = (uint64_t)1 << (state->hs_devlim.log_max_uar_sz + 20);
18559517SBill.Taylor@Sun.COM } else {
18569517SBill.Taylor@Sun.COM offset = 0; /* a zero length means map the whole thing */
18579517SBill.Taylor@Sun.COM }
18589517SBill.Taylor@Sun.COM status = hermon_regs_map_setup(state, HERMON_UAR_BAR,
18599517SBill.Taylor@Sun.COM &state->hs_reg_uar_baseaddr, 0, offset, &state->hs_fm_accattr,
18609517SBill.Taylor@Sun.COM &state->hs_fm_uarhdl);
18619517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
18629517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf, "UAR BAR mapping");
18639517SBill.Taylor@Sun.COM /* This case is not the degraded one */
18649517SBill.Taylor@Sun.COM return (DDI_FAILURE);
18659517SBill.Taylor@Sun.COM }
18669517SBill.Taylor@Sun.COM
18679517SBill.Taylor@Sun.COM /* and if BlueFlame is enabled, map the other half there */
18689517SBill.Taylor@Sun.COM if (state->hs_devlim.blu_flm) { /* Blue Flame Enabled */
18699517SBill.Taylor@Sun.COM offset = (uint64_t)1 << (state->hs_devlim.log_max_uar_sz + 20);
18709517SBill.Taylor@Sun.COM status = ddi_regs_map_setup(state->hs_dip, HERMON_UAR_BAR,
18719517SBill.Taylor@Sun.COM &state->hs_reg_bf_baseaddr, offset, offset,
18729517SBill.Taylor@Sun.COM &state->hs_reg_accattr, &state->hs_reg_bfhdl);
18739517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
18749517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
18759517SBill.Taylor@Sun.COM "BlueFlame BAR mapping");
18769517SBill.Taylor@Sun.COM /* This case is not the degraded one */
18779517SBill.Taylor@Sun.COM return (DDI_FAILURE);
18789517SBill.Taylor@Sun.COM }
18799517SBill.Taylor@Sun.COM /* This will be used in hw_fini if we fail to init. */
18809517SBill.Taylor@Sun.COM state->hs_bf_offset = offset;
18819517SBill.Taylor@Sun.COM }
18829517SBill.Taylor@Sun.COM cleanup = HERMON_DRV_CLEANUP_LEVEL7;
18839517SBill.Taylor@Sun.COM
18849517SBill.Taylor@Sun.COM /* Hermon has a couple of things needed for phase 2 in query port */
18859517SBill.Taylor@Sun.COM
18869517SBill.Taylor@Sun.COM status = hermon_cmn_query_cmd_post(state, QUERY_PORT, 0, 0x01,
18879517SBill.Taylor@Sun.COM &state->hs_queryport, sizeof (hermon_hw_query_port_t),
18889517SBill.Taylor@Sun.COM HERMON_CMD_NOSLEEP_SPIN);
18899517SBill.Taylor@Sun.COM if (status != HERMON_CMD_SUCCESS) {
18909517SBill.Taylor@Sun.COM cmn_err(CE_NOTE, "QUERY_PORT command failed: 0x%08x\n",
18919517SBill.Taylor@Sun.COM status);
18929517SBill.Taylor@Sun.COM hermon_hw_fini(state, cleanup);
18939517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
18949517SBill.Taylor@Sun.COM "hw_init_queryport_fail");
18959517SBill.Taylor@Sun.COM /* This case is not the degraded one */
18969517SBill.Taylor@Sun.COM return (DDI_FAILURE);
18979517SBill.Taylor@Sun.COM }
18989517SBill.Taylor@Sun.COM
18999517SBill.Taylor@Sun.COM /* Initialize the Phase2 Hermon configuration profile */
19009517SBill.Taylor@Sun.COM status = hermon_cfg_profile_init_phase2(state);
19019517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
19029517SBill.Taylor@Sun.COM cmn_err(CE_NOTE, "CFG phase 2 failed: 0x%08x\n", status);
19039517SBill.Taylor@Sun.COM hermon_hw_fini(state, cleanup);
19049517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
19059517SBill.Taylor@Sun.COM "hw_init_cfginit2_fail");
19069517SBill.Taylor@Sun.COM /* This case is not the degraded one */
19079517SBill.Taylor@Sun.COM return (DDI_FAILURE);
19089517SBill.Taylor@Sun.COM }
19099517SBill.Taylor@Sun.COM
19109517SBill.Taylor@Sun.COM /* Determine and set the ICM size */
19119517SBill.Taylor@Sun.COM state->hs_icm_sz = hermon_size_icm(state);
19129517SBill.Taylor@Sun.COM status = hermon_set_icm_size_cmd_post(state);
19139517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
19149517SBill.Taylor@Sun.COM cmn_err(CE_NOTE, "Hermon: SET_ICM_SIZE cmd failed: 0x%08x\n",
19159517SBill.Taylor@Sun.COM status);
19169517SBill.Taylor@Sun.COM hermon_hw_fini(state, cleanup);
19179517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
19189517SBill.Taylor@Sun.COM "hw_init_seticmsz_fail");
19199517SBill.Taylor@Sun.COM /* This case is not the degraded one */
19209517SBill.Taylor@Sun.COM return (DDI_FAILURE);
19219517SBill.Taylor@Sun.COM }
19229517SBill.Taylor@Sun.COM /* alloc icm aux physical memory and map it */
19239517SBill.Taylor@Sun.COM
19249517SBill.Taylor@Sun.COM state->hs_icma_dma.length = 1 << highbit(state->hs_icma_sz);
19259517SBill.Taylor@Sun.COM
19269517SBill.Taylor@Sun.COM status = hermon_dma_alloc(state, &state->hs_icma_dma, MAP_ICM_AUX);
19279517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
19289517SBill.Taylor@Sun.COM cmn_err(CE_NOTE, "failed to alloc (0x%llx) bytes for ICMA\n",
19299517SBill.Taylor@Sun.COM (longlong_t)state->hs_icma_dma.length);
19309517SBill.Taylor@Sun.COM hermon_hw_fini(state, cleanup);
19319517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
19329517SBill.Taylor@Sun.COM "hw_init_dma_alloc_icm_aux_fail");
19339517SBill.Taylor@Sun.COM /* This case is not the degraded one */
19349517SBill.Taylor@Sun.COM return (DDI_FAILURE);
19359517SBill.Taylor@Sun.COM }
19369517SBill.Taylor@Sun.COM cleanup = HERMON_DRV_CLEANUP_LEVEL8;
19379517SBill.Taylor@Sun.COM
19389517SBill.Taylor@Sun.COM cleanup = HERMON_DRV_CLEANUP_LEVEL9;
19399517SBill.Taylor@Sun.COM
19409517SBill.Taylor@Sun.COM /* Allocate an array of structures to house the ICM tables */
19419517SBill.Taylor@Sun.COM state->hs_icm = kmem_zalloc(HERMON_NUM_ICM_RESOURCES *
19429517SBill.Taylor@Sun.COM sizeof (hermon_icm_table_t), KM_SLEEP);
19439517SBill.Taylor@Sun.COM
19449517SBill.Taylor@Sun.COM /* Set up the ICM address space and the INIT_HCA command input */
19459517SBill.Taylor@Sun.COM status = hermon_icm_config_setup(state, &state->hs_hcaparams);
19469517SBill.Taylor@Sun.COM if (status != HERMON_CMD_SUCCESS) {
19479517SBill.Taylor@Sun.COM cmn_err(CE_NOTE, "ICM configuration failed\n");
19489517SBill.Taylor@Sun.COM hermon_hw_fini(state, cleanup);
19499517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
19509517SBill.Taylor@Sun.COM "hw_init_icm_config_setup_fail");
19519517SBill.Taylor@Sun.COM /* This case is not the degraded one */
19529517SBill.Taylor@Sun.COM return (DDI_FAILURE);
19539517SBill.Taylor@Sun.COM }
19549517SBill.Taylor@Sun.COM cleanup = HERMON_DRV_CLEANUP_LEVEL10;
19559517SBill.Taylor@Sun.COM
19569517SBill.Taylor@Sun.COM /* Initialize the adapter with the INIT_HCA cmd */
19579517SBill.Taylor@Sun.COM status = hermon_init_hca_cmd_post(state, &state->hs_hcaparams,
19589517SBill.Taylor@Sun.COM HERMON_CMD_NOSLEEP_SPIN);
19599517SBill.Taylor@Sun.COM if (status != HERMON_CMD_SUCCESS) {
19609517SBill.Taylor@Sun.COM cmn_err(CE_NOTE, "INIT_HCA command failed: %08x\n", status);
19619517SBill.Taylor@Sun.COM hermon_hw_fini(state, cleanup);
19629517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf, "hw_init_hca_fail");
19639517SBill.Taylor@Sun.COM /* This case is not the degraded one */
19649517SBill.Taylor@Sun.COM return (DDI_FAILURE);
19659517SBill.Taylor@Sun.COM }
19669517SBill.Taylor@Sun.COM cleanup = HERMON_DRV_CLEANUP_LEVEL11;
19679517SBill.Taylor@Sun.COM
19689517SBill.Taylor@Sun.COM /* Enter the second phase of init for Hermon configuration/resources */
19699517SBill.Taylor@Sun.COM status = hermon_rsrc_init_phase2(state);
19709517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
19719517SBill.Taylor@Sun.COM hermon_hw_fini(state, cleanup);
19729517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
19739517SBill.Taylor@Sun.COM "hw_init_rsrcinit2_fail");
19749517SBill.Taylor@Sun.COM /* This case is not the degraded one */
19759517SBill.Taylor@Sun.COM return (DDI_FAILURE);
19769517SBill.Taylor@Sun.COM }
19779517SBill.Taylor@Sun.COM cleanup = HERMON_DRV_CLEANUP_LEVEL12;
19789517SBill.Taylor@Sun.COM
19799517SBill.Taylor@Sun.COM /* Query the adapter via QUERY_ADAPTER */
19809517SBill.Taylor@Sun.COM status = hermon_cmn_query_cmd_post(state, QUERY_ADAPTER, 0, 0,
19819517SBill.Taylor@Sun.COM &state->hs_adapter, sizeof (hermon_hw_queryadapter_t),
19829517SBill.Taylor@Sun.COM HERMON_CMD_NOSLEEP_SPIN);
19839517SBill.Taylor@Sun.COM if (status != HERMON_CMD_SUCCESS) {
19849517SBill.Taylor@Sun.COM cmn_err(CE_NOTE, "Hermon: QUERY_ADAPTER command failed: %08x\n",
19859517SBill.Taylor@Sun.COM status);
19869517SBill.Taylor@Sun.COM hermon_hw_fini(state, cleanup);
19879517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
19889517SBill.Taylor@Sun.COM "hw_init_query_adapter_fail");
19899517SBill.Taylor@Sun.COM /* This case is not the degraded one */
19909517SBill.Taylor@Sun.COM return (DDI_FAILURE);
19919517SBill.Taylor@Sun.COM }
19929517SBill.Taylor@Sun.COM
19939517SBill.Taylor@Sun.COM /* Allocate protection domain (PD) for Hermon internal use */
19949517SBill.Taylor@Sun.COM status = hermon_pd_alloc(state, &state->hs_pdhdl_internal,
19959517SBill.Taylor@Sun.COM HERMON_SLEEP);
19969517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
19979517SBill.Taylor@Sun.COM cmn_err(CE_NOTE, "failed to alloc internal PD\n");
19989517SBill.Taylor@Sun.COM hermon_hw_fini(state, cleanup);
19999517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
20009517SBill.Taylor@Sun.COM "hw_init_internal_pd_alloc_fail");
20019517SBill.Taylor@Sun.COM /* This case is not the degraded one */
20029517SBill.Taylor@Sun.COM return (DDI_FAILURE);
20039517SBill.Taylor@Sun.COM }
20049517SBill.Taylor@Sun.COM cleanup = HERMON_DRV_CLEANUP_LEVEL13;
20059517SBill.Taylor@Sun.COM
20069517SBill.Taylor@Sun.COM /* Setup UAR page for kernel use */
20079517SBill.Taylor@Sun.COM status = hermon_internal_uarpg_init(state);
20089517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
20099517SBill.Taylor@Sun.COM cmn_err(CE_NOTE, "failed to setup internal UAR\n");
20109517SBill.Taylor@Sun.COM hermon_hw_fini(state, cleanup);
20119517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
20129517SBill.Taylor@Sun.COM "hw_init_internal_uarpg_alloc_fail");
20139517SBill.Taylor@Sun.COM /* This case is not the degraded one */
20149517SBill.Taylor@Sun.COM return (DDI_FAILURE);
20159517SBill.Taylor@Sun.COM }
20169517SBill.Taylor@Sun.COM cleanup = HERMON_DRV_CLEANUP_LEVEL14;
20179517SBill.Taylor@Sun.COM
20189517SBill.Taylor@Sun.COM /* Query and initialize the Hermon interrupt/MSI information */
20199517SBill.Taylor@Sun.COM status = hermon_intr_or_msi_init(state);
20209517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
20219517SBill.Taylor@Sun.COM cmn_err(CE_NOTE, "failed to setup INTR/MSI\n");
20229517SBill.Taylor@Sun.COM hermon_hw_fini(state, cleanup);
20239517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
20249517SBill.Taylor@Sun.COM "hw_init_intr_or_msi_init_fail");
20259517SBill.Taylor@Sun.COM /* This case is not the degraded one */
20269517SBill.Taylor@Sun.COM return (DDI_FAILURE);
20279517SBill.Taylor@Sun.COM }
20289517SBill.Taylor@Sun.COM cleanup = HERMON_DRV_CLEANUP_LEVEL15;
20299517SBill.Taylor@Sun.COM
20309517SBill.Taylor@Sun.COM status = hermon_isr_init(state); /* set up the isr */
20319517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
20329517SBill.Taylor@Sun.COM cmn_err(CE_NOTE, "failed to init isr\n");
20339517SBill.Taylor@Sun.COM hermon_hw_fini(state, cleanup);
20349517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
20359517SBill.Taylor@Sun.COM "hw_init_isrinit_fail");
20369517SBill.Taylor@Sun.COM /* This case is not the degraded one */
20379517SBill.Taylor@Sun.COM return (DDI_FAILURE);
20389517SBill.Taylor@Sun.COM }
20399517SBill.Taylor@Sun.COM cleanup = HERMON_DRV_CLEANUP_LEVEL16;
20409517SBill.Taylor@Sun.COM
20419517SBill.Taylor@Sun.COM /* Setup the event queues */
20429517SBill.Taylor@Sun.COM status = hermon_eq_init_all(state);
20439517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
20449517SBill.Taylor@Sun.COM cmn_err(CE_NOTE, "failed to init EQs\n");
20459517SBill.Taylor@Sun.COM hermon_hw_fini(state, cleanup);
20469517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
20479517SBill.Taylor@Sun.COM "hw_init_eqinitall_fail");
20489517SBill.Taylor@Sun.COM /* This case is not the degraded one */
20499517SBill.Taylor@Sun.COM return (DDI_FAILURE);
20509517SBill.Taylor@Sun.COM }
20519517SBill.Taylor@Sun.COM cleanup = HERMON_DRV_CLEANUP_LEVEL17;
20529517SBill.Taylor@Sun.COM
20539517SBill.Taylor@Sun.COM
20549517SBill.Taylor@Sun.COM
20559517SBill.Taylor@Sun.COM /* Reserve contexts for QP0 and QP1 */
20569517SBill.Taylor@Sun.COM status = hermon_special_qp_contexts_reserve(state);
20579517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
20589517SBill.Taylor@Sun.COM cmn_err(CE_NOTE, "failed to init special QPs\n");
20599517SBill.Taylor@Sun.COM hermon_hw_fini(state, cleanup);
20609517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
20619517SBill.Taylor@Sun.COM "hw_init_rsrv_sqp_fail");
20629517SBill.Taylor@Sun.COM /* This case is not the degraded one */
20639517SBill.Taylor@Sun.COM return (DDI_FAILURE);
20649517SBill.Taylor@Sun.COM }
20659517SBill.Taylor@Sun.COM cleanup = HERMON_DRV_CLEANUP_LEVEL18;
20669517SBill.Taylor@Sun.COM
20679517SBill.Taylor@Sun.COM /* Initialize for multicast group handling */
20689517SBill.Taylor@Sun.COM status = hermon_mcg_init(state);
20699517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
20709517SBill.Taylor@Sun.COM cmn_err(CE_NOTE, "failed to init multicast\n");
20719517SBill.Taylor@Sun.COM hermon_hw_fini(state, cleanup);
20729517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
20739517SBill.Taylor@Sun.COM "hw_init_mcg_init_fail");
20749517SBill.Taylor@Sun.COM /* This case is not the degraded one */
20759517SBill.Taylor@Sun.COM return (DDI_FAILURE);
20769517SBill.Taylor@Sun.COM }
20779517SBill.Taylor@Sun.COM cleanup = HERMON_DRV_CLEANUP_LEVEL19;
20789517SBill.Taylor@Sun.COM
20799517SBill.Taylor@Sun.COM /* Initialize the Hermon IB port(s) */
20809517SBill.Taylor@Sun.COM status = hermon_hca_port_init(state);
20819517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
20829517SBill.Taylor@Sun.COM cmn_err(CE_NOTE, "failed to init HCA Port\n");
20839517SBill.Taylor@Sun.COM hermon_hw_fini(state, cleanup);
20849517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
20859517SBill.Taylor@Sun.COM "hw_init_hca_port_init_fail");
20869517SBill.Taylor@Sun.COM /* This case is not the degraded one */
20879517SBill.Taylor@Sun.COM return (DDI_FAILURE);
20889517SBill.Taylor@Sun.COM }
20899517SBill.Taylor@Sun.COM
20909517SBill.Taylor@Sun.COM cleanup = HERMON_DRV_CLEANUP_ALL;
20919517SBill.Taylor@Sun.COM
20929517SBill.Taylor@Sun.COM /* Determine NodeGUID and SystemImageGUID */
20939517SBill.Taylor@Sun.COM status = hermon_getnodeinfo_cmd_post(state, HERMON_CMD_NOSLEEP_SPIN,
20949517SBill.Taylor@Sun.COM &nodeinfo);
20959517SBill.Taylor@Sun.COM if (status != HERMON_CMD_SUCCESS) {
20969517SBill.Taylor@Sun.COM cmn_err(CE_NOTE, "GetNodeInfo command failed: %08x\n", status);
20979517SBill.Taylor@Sun.COM hermon_hw_fini(state, cleanup);
20989517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
20999517SBill.Taylor@Sun.COM "hw_init_getnodeinfo_cmd_fail");
21009517SBill.Taylor@Sun.COM /* This case is not the degraded one */
21019517SBill.Taylor@Sun.COM return (DDI_FAILURE);
21029517SBill.Taylor@Sun.COM }
21039517SBill.Taylor@Sun.COM
21049517SBill.Taylor@Sun.COM /*
21059517SBill.Taylor@Sun.COM * If the NodeGUID value was set in OBP properties, then we use that
21069517SBill.Taylor@Sun.COM * value. But we still print a message if the value we queried from
21079517SBill.Taylor@Sun.COM * firmware does not match this value.
21089517SBill.Taylor@Sun.COM *
21099517SBill.Taylor@Sun.COM * Otherwise if OBP value is not set then we use the value from
21109517SBill.Taylor@Sun.COM * firmware unconditionally.
21119517SBill.Taylor@Sun.COM */
21129517SBill.Taylor@Sun.COM if (state->hs_cfg_profile->cp_nodeguid) {
21139517SBill.Taylor@Sun.COM state->hs_nodeguid = state->hs_cfg_profile->cp_nodeguid;
21149517SBill.Taylor@Sun.COM } else {
21159517SBill.Taylor@Sun.COM state->hs_nodeguid = nodeinfo.NodeGUID;
21169517SBill.Taylor@Sun.COM }
21179517SBill.Taylor@Sun.COM
21189517SBill.Taylor@Sun.COM if (state->hs_nodeguid != nodeinfo.NodeGUID) {
21199517SBill.Taylor@Sun.COM cmn_err(CE_NOTE, "!NodeGUID value queried from firmware "
21209517SBill.Taylor@Sun.COM "does not match value set by device property");
21219517SBill.Taylor@Sun.COM }
21229517SBill.Taylor@Sun.COM
21239517SBill.Taylor@Sun.COM /*
21249517SBill.Taylor@Sun.COM * If the SystemImageGUID value was set in OBP properties, then we use
21259517SBill.Taylor@Sun.COM * that value. But we still print a message if the value we queried
21269517SBill.Taylor@Sun.COM * from firmware does not match this value.
21279517SBill.Taylor@Sun.COM *
21289517SBill.Taylor@Sun.COM * Otherwise if OBP value is not set then we use the value from
21299517SBill.Taylor@Sun.COM * firmware unconditionally.
21309517SBill.Taylor@Sun.COM */
21319517SBill.Taylor@Sun.COM if (state->hs_cfg_profile->cp_sysimgguid) {
21329517SBill.Taylor@Sun.COM state->hs_sysimgguid = state->hs_cfg_profile->cp_sysimgguid;
21339517SBill.Taylor@Sun.COM } else {
21349517SBill.Taylor@Sun.COM state->hs_sysimgguid = nodeinfo.SystemImageGUID;
21359517SBill.Taylor@Sun.COM }
21369517SBill.Taylor@Sun.COM
21379517SBill.Taylor@Sun.COM if (state->hs_sysimgguid != nodeinfo.SystemImageGUID) {
21389517SBill.Taylor@Sun.COM cmn_err(CE_NOTE, "!SystemImageGUID value queried from firmware "
21399517SBill.Taylor@Sun.COM "does not match value set by device property");
21409517SBill.Taylor@Sun.COM }
21419517SBill.Taylor@Sun.COM
21429517SBill.Taylor@Sun.COM /* Get NodeDescription */
21439517SBill.Taylor@Sun.COM status = hermon_getnodedesc_cmd_post(state, HERMON_CMD_NOSLEEP_SPIN,
21449517SBill.Taylor@Sun.COM (sm_nodedesc_t *)&state->hs_nodedesc);
21459517SBill.Taylor@Sun.COM if (status != HERMON_CMD_SUCCESS) {
21469517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "GetNodeDesc command failed: %08x\n", status);
21479517SBill.Taylor@Sun.COM hermon_hw_fini(state, cleanup);
21489517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
21499517SBill.Taylor@Sun.COM "hw_init_getnodedesc_cmd_fail");
21509517SBill.Taylor@Sun.COM /* This case is not the degraded one */
21519517SBill.Taylor@Sun.COM return (DDI_FAILURE);
21529517SBill.Taylor@Sun.COM }
21539517SBill.Taylor@Sun.COM
21549517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
21559517SBill.Taylor@Sun.COM }
21569517SBill.Taylor@Sun.COM
21579517SBill.Taylor@Sun.COM
21589517SBill.Taylor@Sun.COM /*
21599517SBill.Taylor@Sun.COM * hermon_hw_fini()
21609517SBill.Taylor@Sun.COM * Context: Only called from attach() and/or detach() path contexts
21619517SBill.Taylor@Sun.COM */
21629517SBill.Taylor@Sun.COM static void
hermon_hw_fini(hermon_state_t * state,hermon_drv_cleanup_level_t cleanup)21639517SBill.Taylor@Sun.COM hermon_hw_fini(hermon_state_t *state, hermon_drv_cleanup_level_t cleanup)
21649517SBill.Taylor@Sun.COM {
21659517SBill.Taylor@Sun.COM uint_t num_ports;
21669517SBill.Taylor@Sun.COM int i, status;
21679517SBill.Taylor@Sun.COM
21689517SBill.Taylor@Sun.COM
21699517SBill.Taylor@Sun.COM /*
21709517SBill.Taylor@Sun.COM * JBDB - We might not want to run these returns in all cases of
21719517SBill.Taylor@Sun.COM * Bad News. We should still attempt to free all of the DMA memory
21729517SBill.Taylor@Sun.COM * resources... This needs to be worked last, after all allocations
21739517SBill.Taylor@Sun.COM * are implemented. For now, and possibly for later, this works.
21749517SBill.Taylor@Sun.COM */
21759517SBill.Taylor@Sun.COM
21769517SBill.Taylor@Sun.COM switch (cleanup) {
21779517SBill.Taylor@Sun.COM /*
21789517SBill.Taylor@Sun.COM * If we add more driver initialization steps that should be cleaned
21799517SBill.Taylor@Sun.COM * up here, we need to ensure that HERMON_DRV_CLEANUP_ALL is still the
21809517SBill.Taylor@Sun.COM * first entry (i.e. corresponds to the last init step).
21819517SBill.Taylor@Sun.COM */
21829517SBill.Taylor@Sun.COM case HERMON_DRV_CLEANUP_ALL:
21839517SBill.Taylor@Sun.COM /* Shutdown the Hermon IB port(s) */
21849517SBill.Taylor@Sun.COM num_ports = state->hs_cfg_profile->cp_num_ports;
21859517SBill.Taylor@Sun.COM (void) hermon_hca_ports_shutdown(state, num_ports);
21869517SBill.Taylor@Sun.COM /* FALLTHROUGH */
21879517SBill.Taylor@Sun.COM
21889517SBill.Taylor@Sun.COM case HERMON_DRV_CLEANUP_LEVEL19:
21899517SBill.Taylor@Sun.COM /* Teardown resources used for multicast group handling */
21909517SBill.Taylor@Sun.COM hermon_mcg_fini(state);
21919517SBill.Taylor@Sun.COM /* FALLTHROUGH */
21929517SBill.Taylor@Sun.COM
21939517SBill.Taylor@Sun.COM case HERMON_DRV_CLEANUP_LEVEL18:
21949517SBill.Taylor@Sun.COM /* Unreserve the special QP contexts */
21959517SBill.Taylor@Sun.COM hermon_special_qp_contexts_unreserve(state);
21969517SBill.Taylor@Sun.COM /* FALLTHROUGH */
21979517SBill.Taylor@Sun.COM
21989517SBill.Taylor@Sun.COM case HERMON_DRV_CLEANUP_LEVEL17:
21999517SBill.Taylor@Sun.COM /*
22009517SBill.Taylor@Sun.COM * Attempt to teardown all event queues (EQ). If we fail
22019517SBill.Taylor@Sun.COM * here then print a warning message and return. Something
22029517SBill.Taylor@Sun.COM * (either in HW or SW) has gone seriously wrong.
22039517SBill.Taylor@Sun.COM */
22049517SBill.Taylor@Sun.COM status = hermon_eq_fini_all(state);
22059517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
22069517SBill.Taylor@Sun.COM HERMON_WARNING(state, "failed to teardown EQs");
22079517SBill.Taylor@Sun.COM return;
22089517SBill.Taylor@Sun.COM }
22099517SBill.Taylor@Sun.COM /* FALLTHROUGH */
22109517SBill.Taylor@Sun.COM case HERMON_DRV_CLEANUP_LEVEL16:
22119517SBill.Taylor@Sun.COM /* Teardown Hermon interrupts */
22129517SBill.Taylor@Sun.COM hermon_isr_fini(state);
22139517SBill.Taylor@Sun.COM /* FALLTHROUGH */
22149517SBill.Taylor@Sun.COM
22159517SBill.Taylor@Sun.COM case HERMON_DRV_CLEANUP_LEVEL15:
22169517SBill.Taylor@Sun.COM status = hermon_intr_or_msi_fini(state);
22179517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
22189517SBill.Taylor@Sun.COM HERMON_WARNING(state, "failed to free intr/MSI");
22199517SBill.Taylor@Sun.COM return;
22209517SBill.Taylor@Sun.COM }
22219517SBill.Taylor@Sun.COM /* FALLTHROUGH */
22229517SBill.Taylor@Sun.COM
22239517SBill.Taylor@Sun.COM case HERMON_DRV_CLEANUP_LEVEL14:
22249517SBill.Taylor@Sun.COM /* Free the resources for the Hermon internal UAR pages */
22259517SBill.Taylor@Sun.COM hermon_internal_uarpg_fini(state);
22269517SBill.Taylor@Sun.COM /* FALLTHROUGH */
22279517SBill.Taylor@Sun.COM
22289517SBill.Taylor@Sun.COM case HERMON_DRV_CLEANUP_LEVEL13:
22299517SBill.Taylor@Sun.COM /*
22309517SBill.Taylor@Sun.COM * Free the PD that was used internally by Hermon software. If
22319517SBill.Taylor@Sun.COM * we fail here then print a warning and return. Something
22329517SBill.Taylor@Sun.COM * (probably software-related, but perhaps HW) has gone wrong.
22339517SBill.Taylor@Sun.COM */
22349517SBill.Taylor@Sun.COM status = hermon_pd_free(state, &state->hs_pdhdl_internal);
22359517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
22369517SBill.Taylor@Sun.COM HERMON_WARNING(state, "failed to free internal PD");
22379517SBill.Taylor@Sun.COM return;
22389517SBill.Taylor@Sun.COM }
22399517SBill.Taylor@Sun.COM /* FALLTHROUGH */
22409517SBill.Taylor@Sun.COM
22419517SBill.Taylor@Sun.COM case HERMON_DRV_CLEANUP_LEVEL12:
22429517SBill.Taylor@Sun.COM /* Cleanup all the phase2 resources first */
22439517SBill.Taylor@Sun.COM hermon_rsrc_fini(state, HERMON_RSRC_CLEANUP_ALL);
22449517SBill.Taylor@Sun.COM /* FALLTHROUGH */
22459517SBill.Taylor@Sun.COM
22469517SBill.Taylor@Sun.COM case HERMON_DRV_CLEANUP_LEVEL11:
22479517SBill.Taylor@Sun.COM /* LEVEL11 is after INIT_HCA */
22489517SBill.Taylor@Sun.COM /* FALLTHROUGH */
22499517SBill.Taylor@Sun.COM
22509517SBill.Taylor@Sun.COM
22519517SBill.Taylor@Sun.COM case HERMON_DRV_CLEANUP_LEVEL10:
22529517SBill.Taylor@Sun.COM /*
22539517SBill.Taylor@Sun.COM * Unmap the ICM memory area with UNMAP_ICM command.
22549517SBill.Taylor@Sun.COM */
22559517SBill.Taylor@Sun.COM status = hermon_unmap_icm_cmd_post(state, NULL);
22569517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
22579517SBill.Taylor@Sun.COM cmn_err(CE_WARN,
22589517SBill.Taylor@Sun.COM "hermon_hw_fini: failed to unmap ICM\n");
22599517SBill.Taylor@Sun.COM }
22609517SBill.Taylor@Sun.COM
22619517SBill.Taylor@Sun.COM /* Free the initial ICM DMA handles */
22629517SBill.Taylor@Sun.COM hermon_icm_dma_fini(state);
22639517SBill.Taylor@Sun.COM
22649517SBill.Taylor@Sun.COM /* Free the ICM table structures */
22659517SBill.Taylor@Sun.COM hermon_icm_tables_fini(state);
22669517SBill.Taylor@Sun.COM
22679517SBill.Taylor@Sun.COM /* Free the ICM table handles */
22689517SBill.Taylor@Sun.COM kmem_free(state->hs_icm, HERMON_NUM_ICM_RESOURCES *
22699517SBill.Taylor@Sun.COM sizeof (hermon_icm_table_t));
22709517SBill.Taylor@Sun.COM
22719517SBill.Taylor@Sun.COM /* FALLTHROUGH */
22729517SBill.Taylor@Sun.COM
22739517SBill.Taylor@Sun.COM case HERMON_DRV_CLEANUP_LEVEL9:
22749517SBill.Taylor@Sun.COM /*
22759517SBill.Taylor@Sun.COM * Unmap the ICM Aux memory area with UNMAP_ICM_AUX command.
22769517SBill.Taylor@Sun.COM */
22779517SBill.Taylor@Sun.COM status = hermon_unmap_icm_aux_cmd_post(state);
22789517SBill.Taylor@Sun.COM if (status != HERMON_CMD_SUCCESS) {
22799517SBill.Taylor@Sun.COM cmn_err(CE_NOTE,
22809517SBill.Taylor@Sun.COM "hermon_hw_fini: failed to unmap ICMA\n");
22819517SBill.Taylor@Sun.COM }
22829517SBill.Taylor@Sun.COM /* FALLTHROUGH */
22839517SBill.Taylor@Sun.COM
22849517SBill.Taylor@Sun.COM case HERMON_DRV_CLEANUP_LEVEL8:
22859517SBill.Taylor@Sun.COM /*
22869517SBill.Taylor@Sun.COM * Deallocate ICM Aux DMA memory.
22879517SBill.Taylor@Sun.COM */
22889517SBill.Taylor@Sun.COM hermon_dma_free(&state->hs_icma_dma);
22899517SBill.Taylor@Sun.COM /* FALLTHROUGH */
22909517SBill.Taylor@Sun.COM
22919517SBill.Taylor@Sun.COM case HERMON_DRV_CLEANUP_LEVEL7:
22929517SBill.Taylor@Sun.COM if (state->hs_fm_uarhdl) {
22939517SBill.Taylor@Sun.COM hermon_regs_map_free(state, &state->hs_fm_uarhdl);
22949517SBill.Taylor@Sun.COM state->hs_fm_uarhdl = NULL;
22959517SBill.Taylor@Sun.COM }
22969517SBill.Taylor@Sun.COM
22979517SBill.Taylor@Sun.COM if (state->hs_reg_uarhdl) {
22989517SBill.Taylor@Sun.COM ddi_regs_map_free(&state->hs_reg_uarhdl);
22999517SBill.Taylor@Sun.COM state->hs_reg_uarhdl = NULL;
23009517SBill.Taylor@Sun.COM }
23019517SBill.Taylor@Sun.COM
23029517SBill.Taylor@Sun.COM if (state->hs_bf_offset != 0 && state->hs_reg_bfhdl) {
23039517SBill.Taylor@Sun.COM ddi_regs_map_free(&state->hs_reg_bfhdl);
23049517SBill.Taylor@Sun.COM state->hs_reg_bfhdl = NULL;
23059517SBill.Taylor@Sun.COM }
23069517SBill.Taylor@Sun.COM
23079517SBill.Taylor@Sun.COM for (i = 0; i < HERMON_MAX_PORTS; i++) {
23089517SBill.Taylor@Sun.COM if (state->hs_pkey[i]) {
23099517SBill.Taylor@Sun.COM kmem_free(state->hs_pkey[i], (1 <<
23109517SBill.Taylor@Sun.COM state->hs_cfg_profile->cp_log_max_pkeytbl) *
23119517SBill.Taylor@Sun.COM sizeof (ib_pkey_t));
23129517SBill.Taylor@Sun.COM state->hs_pkey[i] = NULL;
23139517SBill.Taylor@Sun.COM }
23149517SBill.Taylor@Sun.COM if (state->hs_guid[i]) {
23159517SBill.Taylor@Sun.COM kmem_free(state->hs_guid[i], (1 <<
23169517SBill.Taylor@Sun.COM state->hs_cfg_profile->cp_log_max_gidtbl) *
23179517SBill.Taylor@Sun.COM sizeof (ib_guid_t));
23189517SBill.Taylor@Sun.COM state->hs_guid[i] = NULL;
23199517SBill.Taylor@Sun.COM }
23209517SBill.Taylor@Sun.COM }
23219517SBill.Taylor@Sun.COM /* FALLTHROUGH */
23229517SBill.Taylor@Sun.COM
23239517SBill.Taylor@Sun.COM case HERMON_DRV_CLEANUP_LEVEL6:
23249517SBill.Taylor@Sun.COM /*
23259517SBill.Taylor@Sun.COM * Unmap the firmware memory area with UNMAP_FA command.
23269517SBill.Taylor@Sun.COM */
23279517SBill.Taylor@Sun.COM status = hermon_unmap_fa_cmd_post(state);
23289517SBill.Taylor@Sun.COM
23299517SBill.Taylor@Sun.COM if (status != HERMON_CMD_SUCCESS) {
23309517SBill.Taylor@Sun.COM cmn_err(CE_NOTE,
23319517SBill.Taylor@Sun.COM "hermon_hw_fini: failed to unmap FW\n");
23329517SBill.Taylor@Sun.COM }
23339517SBill.Taylor@Sun.COM
23349517SBill.Taylor@Sun.COM /*
23359517SBill.Taylor@Sun.COM * Deallocate firmware DMA memory.
23369517SBill.Taylor@Sun.COM */
23379517SBill.Taylor@Sun.COM hermon_dma_free(&state->hs_fw_dma);
23389517SBill.Taylor@Sun.COM /* FALLTHROUGH */
23399517SBill.Taylor@Sun.COM
23409517SBill.Taylor@Sun.COM case HERMON_DRV_CLEANUP_LEVEL5:
23419517SBill.Taylor@Sun.COM /* stop the poll thread */
23429517SBill.Taylor@Sun.COM if (state->hs_fm_poll_thread) {
23439517SBill.Taylor@Sun.COM ddi_periodic_delete(state->hs_fm_poll_thread);
23449517SBill.Taylor@Sun.COM state->hs_fm_poll_thread = NULL;
23459517SBill.Taylor@Sun.COM }
23469517SBill.Taylor@Sun.COM /* FALLTHROUGH */
23479517SBill.Taylor@Sun.COM
23489517SBill.Taylor@Sun.COM case HERMON_DRV_CLEANUP_LEVEL4:
23499517SBill.Taylor@Sun.COM /* Then cleanup the phase1 resources */
23509517SBill.Taylor@Sun.COM hermon_rsrc_fini(state, HERMON_RSRC_CLEANUP_PHASE1_COMPLETE);
23519517SBill.Taylor@Sun.COM /* FALLTHROUGH */
23529517SBill.Taylor@Sun.COM
23539517SBill.Taylor@Sun.COM case HERMON_DRV_CLEANUP_LEVEL3:
23549517SBill.Taylor@Sun.COM /* Teardown any resources allocated for the config profile */
23559517SBill.Taylor@Sun.COM hermon_cfg_profile_fini(state);
23569517SBill.Taylor@Sun.COM /* FALLTHROUGH */
23579517SBill.Taylor@Sun.COM
23589517SBill.Taylor@Sun.COM case HERMON_DRV_CLEANUP_LEVEL2:
23599517SBill.Taylor@Sun.COM #ifdef HERMON_SUPPORTS_MSIX_BAR
23609517SBill.Taylor@Sun.COM /*
23619517SBill.Taylor@Sun.COM * unmap 3rd BAR, MSIX BAR
23629517SBill.Taylor@Sun.COM */
23639517SBill.Taylor@Sun.COM if (state->hs_reg_msihdl) {
23649517SBill.Taylor@Sun.COM ddi_regs_map_free(&state->hs_reg_msihdl);
23659517SBill.Taylor@Sun.COM state->hs_reg_msihdl = NULL;
23669517SBill.Taylor@Sun.COM }
23679517SBill.Taylor@Sun.COM /* FALLTHROUGH */
23689517SBill.Taylor@Sun.COM #endif
23699517SBill.Taylor@Sun.COM case HERMON_DRV_CLEANUP_LEVEL1:
23709517SBill.Taylor@Sun.COM case HERMON_DRV_CLEANUP_LEVEL0:
23719582SEiji.Ota@Sun.COM /*
23729582SEiji.Ota@Sun.COM * LEVEL1 and LEVEL0 resources are freed in
23739582SEiji.Ota@Sun.COM * hermon_drv_fini2().
23749582SEiji.Ota@Sun.COM */
23759517SBill.Taylor@Sun.COM break;
23769517SBill.Taylor@Sun.COM
23779517SBill.Taylor@Sun.COM default:
23789517SBill.Taylor@Sun.COM HERMON_WARNING(state, "unexpected driver cleanup level");
23799517SBill.Taylor@Sun.COM return;
23809517SBill.Taylor@Sun.COM }
23819517SBill.Taylor@Sun.COM }
23829517SBill.Taylor@Sun.COM
23839517SBill.Taylor@Sun.COM
23849517SBill.Taylor@Sun.COM /*
23859517SBill.Taylor@Sun.COM * hermon_soft_state_init()
23869517SBill.Taylor@Sun.COM * Context: Only called from attach() path context
23879517SBill.Taylor@Sun.COM */
23889517SBill.Taylor@Sun.COM static int
hermon_soft_state_init(hermon_state_t * state)23899517SBill.Taylor@Sun.COM hermon_soft_state_init(hermon_state_t *state)
23909517SBill.Taylor@Sun.COM {
23919517SBill.Taylor@Sun.COM ibt_hca_attr_t *hca_attr;
23929517SBill.Taylor@Sun.COM uint64_t maxval, val;
23939517SBill.Taylor@Sun.COM ibt_hca_flags_t caps = IBT_HCA_NO_FLAGS;
23949517SBill.Taylor@Sun.COM ibt_hca_flags2_t caps2 = IBT_HCA2_NO_FLAGS;
23959517SBill.Taylor@Sun.COM int status;
23969517SBill.Taylor@Sun.COM int max_send_wqe_bytes;
23979517SBill.Taylor@Sun.COM int max_recv_wqe_bytes;
23989517SBill.Taylor@Sun.COM
23999517SBill.Taylor@Sun.COM /*
24009517SBill.Taylor@Sun.COM * The ibc_hca_info_t struct is passed to the IBTF. This is the
24019517SBill.Taylor@Sun.COM * routine where we initialize it. Many of the init values come from
24029517SBill.Taylor@Sun.COM * either configuration variables or successful queries of the Hermon
24039517SBill.Taylor@Sun.COM * hardware abilities
24049517SBill.Taylor@Sun.COM */
240512965SWilliam.Taylor@Oracle.COM state->hs_ibtfinfo.hca_ci_vers = IBCI_V4;
24069517SBill.Taylor@Sun.COM state->hs_ibtfinfo.hca_handle = (ibc_hca_hdl_t)state;
24079517SBill.Taylor@Sun.COM state->hs_ibtfinfo.hca_ops = &hermon_ibc_ops;
24089517SBill.Taylor@Sun.COM
24099517SBill.Taylor@Sun.COM hca_attr = kmem_zalloc(sizeof (ibt_hca_attr_t), KM_SLEEP);
24109517SBill.Taylor@Sun.COM state->hs_ibtfinfo.hca_attr = hca_attr;
24119517SBill.Taylor@Sun.COM
241212965SWilliam.Taylor@Oracle.COM hca_attr->hca_dip = state->hs_dip;
24139517SBill.Taylor@Sun.COM hca_attr->hca_fw_major_version = state->hs_fw.fw_rev_major;
24149517SBill.Taylor@Sun.COM hca_attr->hca_fw_minor_version = state->hs_fw.fw_rev_minor;
24159517SBill.Taylor@Sun.COM hca_attr->hca_fw_micro_version = state->hs_fw.fw_rev_subminor;
24169517SBill.Taylor@Sun.COM
24179517SBill.Taylor@Sun.COM /* CQ interrupt moderation maximums - each limited to 16 bits */
24189517SBill.Taylor@Sun.COM hca_attr->hca_max_cq_mod_count = 0xFFFF;
24199517SBill.Taylor@Sun.COM hca_attr->hca_max_cq_mod_usec = 0xFFFF;
242012965SWilliam.Taylor@Oracle.COM hca_attr->hca_max_cq_handlers = state->hs_intrmsi_allocd;
242112965SWilliam.Taylor@Oracle.COM
24229517SBill.Taylor@Sun.COM
24239517SBill.Taylor@Sun.COM /*
24249517SBill.Taylor@Sun.COM * Determine HCA capabilities:
24259517SBill.Taylor@Sun.COM * No default support for IBT_HCA_RD, IBT_HCA_RAW_MULTICAST,
24269517SBill.Taylor@Sun.COM * IBT_HCA_ATOMICS_GLOBAL, IBT_HCA_RESIZE_CHAN, IBT_HCA_INIT_TYPE,
24279517SBill.Taylor@Sun.COM * or IBT_HCA_SHUTDOWN_PORT
24289517SBill.Taylor@Sun.COM * But IBT_HCA_AH_PORT_CHECK, IBT_HCA_SQD_RTS_PORT, IBT_HCA_SI_GUID,
24299517SBill.Taylor@Sun.COM * IBT_HCA_RNR_NAK, IBT_HCA_CURRENT_QP_STATE, IBT_HCA_PORT_UP,
24309517SBill.Taylor@Sun.COM * IBT_HCA_SRQ, IBT_HCA_RESIZE_SRQ and IBT_HCA_FMR are always
24319517SBill.Taylor@Sun.COM * supported
24329517SBill.Taylor@Sun.COM * All other features are conditionally supported, depending on the
24339517SBill.Taylor@Sun.COM * status return by the Hermon HCA in QUERY_DEV_LIM.
24349517SBill.Taylor@Sun.COM */
24359517SBill.Taylor@Sun.COM if (state->hs_devlim.ud_multi) {
24369517SBill.Taylor@Sun.COM caps |= IBT_HCA_UD_MULTICAST;
24379517SBill.Taylor@Sun.COM }
24389517SBill.Taylor@Sun.COM if (state->hs_devlim.atomic) {
24399517SBill.Taylor@Sun.COM caps |= IBT_HCA_ATOMICS_HCA;
24409517SBill.Taylor@Sun.COM }
24419517SBill.Taylor@Sun.COM if (state->hs_devlim.apm) {
24429517SBill.Taylor@Sun.COM caps |= IBT_HCA_AUTO_PATH_MIG;
24439517SBill.Taylor@Sun.COM }
24449517SBill.Taylor@Sun.COM if (state->hs_devlim.pkey_v) {
24459517SBill.Taylor@Sun.COM caps |= IBT_HCA_PKEY_CNTR;
24469517SBill.Taylor@Sun.COM }
24479517SBill.Taylor@Sun.COM if (state->hs_devlim.qkey_v) {
24489517SBill.Taylor@Sun.COM caps |= IBT_HCA_QKEY_CNTR;
24499517SBill.Taylor@Sun.COM }
24509517SBill.Taylor@Sun.COM if (state->hs_devlim.ipoib_cksm) {
24519517SBill.Taylor@Sun.COM caps |= IBT_HCA_CKSUM_FULL;
24529517SBill.Taylor@Sun.COM caps2 |= IBT_HCA2_IP_CLASS;
24539517SBill.Taylor@Sun.COM }
24549517SBill.Taylor@Sun.COM if (state->hs_devlim.mod_wr_srq) {
24559517SBill.Taylor@Sun.COM caps |= IBT_HCA_RESIZE_SRQ;
24569517SBill.Taylor@Sun.COM }
24579517SBill.Taylor@Sun.COM if (state->hs_devlim.lif) {
24589517SBill.Taylor@Sun.COM caps |= IBT_HCA_LOCAL_INVAL_FENCE;
24599517SBill.Taylor@Sun.COM }
24609517SBill.Taylor@Sun.COM if (state->hs_devlim.reserved_lkey) {
24619517SBill.Taylor@Sun.COM caps2 |= IBT_HCA2_RES_LKEY;
24629517SBill.Taylor@Sun.COM hca_attr->hca_reserved_lkey = state->hs_devlim.rsv_lkey;
24639517SBill.Taylor@Sun.COM }
24649517SBill.Taylor@Sun.COM if (state->hs_devlim.local_inv && state->hs_devlim.remote_inv &&
246512965SWilliam.Taylor@Oracle.COM state->hs_devlim.fast_reg_wr) { /* fw needs to be >= 2.7.000 */
246612965SWilliam.Taylor@Oracle.COM if ((state->hs_fw.fw_rev_major > 2) ||
246712965SWilliam.Taylor@Oracle.COM ((state->hs_fw.fw_rev_major == 2) &&
246812965SWilliam.Taylor@Oracle.COM (state->hs_fw.fw_rev_minor >= 7)))
24699517SBill.Taylor@Sun.COM caps2 |= IBT_HCA2_MEM_MGT_EXT;
247012965SWilliam.Taylor@Oracle.COM }
247112965SWilliam.Taylor@Oracle.COM if (state->hs_devlim.log_max_rss_tbl_sz) {
247212965SWilliam.Taylor@Oracle.COM hca_attr->hca_rss_max_log2_table =
247312965SWilliam.Taylor@Oracle.COM state->hs_devlim.log_max_rss_tbl_sz;
247412965SWilliam.Taylor@Oracle.COM if (state->hs_devlim.rss_xor)
247512965SWilliam.Taylor@Oracle.COM caps2 |= IBT_HCA2_RSS_XOR_ALG;
247612965SWilliam.Taylor@Oracle.COM if (state->hs_devlim.rss_toep)
247712965SWilliam.Taylor@Oracle.COM caps2 |= IBT_HCA2_RSS_TPL_ALG;
24789517SBill.Taylor@Sun.COM }
24799517SBill.Taylor@Sun.COM if (state->hs_devlim.mps) {
24809517SBill.Taylor@Sun.COM caps |= IBT_HCA_ZERO_BASED_VA;
24819517SBill.Taylor@Sun.COM }
24829517SBill.Taylor@Sun.COM if (state->hs_devlim.zb) {
24839517SBill.Taylor@Sun.COM caps |= IBT_HCA_MULT_PAGE_SZ_MR;
24849517SBill.Taylor@Sun.COM }
24859517SBill.Taylor@Sun.COM caps |= (IBT_HCA_AH_PORT_CHECK | IBT_HCA_SQD_SQD_PORT |
24869517SBill.Taylor@Sun.COM IBT_HCA_SI_GUID | IBT_HCA_RNR_NAK | IBT_HCA_CURRENT_QP_STATE |
24879517SBill.Taylor@Sun.COM IBT_HCA_PORT_UP | IBT_HCA_RC_SRQ | IBT_HCA_UD_SRQ | IBT_HCA_FMR);
248812965SWilliam.Taylor@Oracle.COM caps2 |= IBT_HCA2_DMA_MR;
24899517SBill.Taylor@Sun.COM
24909517SBill.Taylor@Sun.COM if (state->hs_devlim.log_max_gso_sz) {
24919517SBill.Taylor@Sun.COM hca_attr->hca_max_lso_size =
24929517SBill.Taylor@Sun.COM (1 << state->hs_devlim.log_max_gso_sz);
249310633SRajkumar.Sivaprakasam@Sun.COM /* 64 = ctrl & datagram seg, 4 = LSO seg, 16 = 1 SGL */
249410633SRajkumar.Sivaprakasam@Sun.COM hca_attr->hca_max_lso_hdr_size =
249510633SRajkumar.Sivaprakasam@Sun.COM state->hs_devlim.max_desc_sz_sq - (64 + 4 + 16);
24969517SBill.Taylor@Sun.COM }
24979517SBill.Taylor@Sun.COM
24989517SBill.Taylor@Sun.COM caps |= IBT_HCA_WQE_SIZE_INFO;
24999517SBill.Taylor@Sun.COM max_send_wqe_bytes = state->hs_devlim.max_desc_sz_sq;
25009517SBill.Taylor@Sun.COM max_recv_wqe_bytes = state->hs_devlim.max_desc_sz_rq;
25019517SBill.Taylor@Sun.COM hca_attr->hca_ud_send_sgl_sz = (max_send_wqe_bytes / 16) - 4;
25029517SBill.Taylor@Sun.COM hca_attr->hca_conn_send_sgl_sz = (max_send_wqe_bytes / 16) - 1;
25039517SBill.Taylor@Sun.COM hca_attr->hca_conn_rdma_sgl_overhead = 1;
250412965SWilliam.Taylor@Oracle.COM hca_attr->hca_conn_rdma_write_sgl_sz = (max_send_wqe_bytes / 16) - 2;
250512965SWilliam.Taylor@Oracle.COM hca_attr->hca_conn_rdma_read_sgl_sz = (512 / 16) - 2; /* see PRM */
25069517SBill.Taylor@Sun.COM hca_attr->hca_recv_sgl_sz = max_recv_wqe_bytes / 16;
25079517SBill.Taylor@Sun.COM
25089517SBill.Taylor@Sun.COM /* We choose not to support "inline" unless it improves performance */
25099517SBill.Taylor@Sun.COM hca_attr->hca_max_inline_size = 0;
25109517SBill.Taylor@Sun.COM hca_attr->hca_ud_send_inline_sz = 0;
25119517SBill.Taylor@Sun.COM hca_attr->hca_conn_send_inline_sz = 0;
25129517SBill.Taylor@Sun.COM hca_attr->hca_conn_rdmaw_inline_overhead = 4;
25139517SBill.Taylor@Sun.COM
2514*13121SWilliam.Taylor@Oracle.COM #if defined(_ELF64)
2515*13121SWilliam.Taylor@Oracle.COM /* 32-bit kernels are too small for Fibre Channel over IB */
251612965SWilliam.Taylor@Oracle.COM if (state->hs_devlim.fcoib && (caps2 & IBT_HCA2_MEM_MGT_EXT)) {
251712965SWilliam.Taylor@Oracle.COM caps2 |= IBT_HCA2_FC;
251812965SWilliam.Taylor@Oracle.COM hca_attr->hca_rfci_max_log2_qp = 7; /* 128 per port */
251912965SWilliam.Taylor@Oracle.COM hca_attr->hca_fexch_max_log2_qp = 16; /* 64K per port */
2520*13121SWilliam.Taylor@Oracle.COM hca_attr->hca_fexch_max_log2_mem = 20; /* 1MB per MPT */
252112965SWilliam.Taylor@Oracle.COM }
2522*13121SWilliam.Taylor@Oracle.COM #endif
252312965SWilliam.Taylor@Oracle.COM
25249517SBill.Taylor@Sun.COM hca_attr->hca_flags = caps;
25259517SBill.Taylor@Sun.COM hca_attr->hca_flags2 = caps2;
25269517SBill.Taylor@Sun.COM
25279517SBill.Taylor@Sun.COM /*
25289517SBill.Taylor@Sun.COM * Set hca_attr's IDs
25299517SBill.Taylor@Sun.COM */
25309517SBill.Taylor@Sun.COM hca_attr->hca_vendor_id = state->hs_vendor_id;
25319517SBill.Taylor@Sun.COM hca_attr->hca_device_id = state->hs_device_id;
25329517SBill.Taylor@Sun.COM hca_attr->hca_version_id = state->hs_revision_id;
25339517SBill.Taylor@Sun.COM
25349517SBill.Taylor@Sun.COM /*
25359517SBill.Taylor@Sun.COM * Determine number of available QPs and max QP size. Number of
25369517SBill.Taylor@Sun.COM * available QPs is determined by subtracting the number of
25379517SBill.Taylor@Sun.COM * "reserved QPs" (i.e. reserved for firmware use) from the
25389517SBill.Taylor@Sun.COM * total number configured.
25399517SBill.Taylor@Sun.COM */
25409517SBill.Taylor@Sun.COM val = ((uint64_t)1 << state->hs_cfg_profile->cp_log_num_qp);
25419517SBill.Taylor@Sun.COM hca_attr->hca_max_qp = val - ((uint64_t)1 <<
25429517SBill.Taylor@Sun.COM state->hs_devlim.log_rsvd_qp);
25439517SBill.Taylor@Sun.COM maxval = ((uint64_t)1 << state->hs_devlim.log_max_qp_sz);
25449517SBill.Taylor@Sun.COM val = ((uint64_t)1 << state->hs_cfg_profile->cp_log_max_qp_sz);
25459517SBill.Taylor@Sun.COM if (val > maxval) {
25469517SBill.Taylor@Sun.COM kmem_free(hca_attr, sizeof (ibt_hca_attr_t));
25479517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
25489517SBill.Taylor@Sun.COM "soft_state_init_maxqpsz_toobig_fail");
25499517SBill.Taylor@Sun.COM return (DDI_FAILURE);
25509517SBill.Taylor@Sun.COM }
25519517SBill.Taylor@Sun.COM /* we need to reduce this by the max space needed for headroom */
25529517SBill.Taylor@Sun.COM hca_attr->hca_max_qp_sz = (uint_t)val - (HERMON_QP_OH_SIZE >>
25539517SBill.Taylor@Sun.COM HERMON_QP_WQE_LOG_MINIMUM) - 1;
25549517SBill.Taylor@Sun.COM
25559517SBill.Taylor@Sun.COM /*
25569517SBill.Taylor@Sun.COM * Determine max scatter-gather size in WQEs. The HCA has split
25579517SBill.Taylor@Sun.COM * the max sgl into rec'v Q and send Q values. Use the least.
25589517SBill.Taylor@Sun.COM *
25599517SBill.Taylor@Sun.COM * This is mainly useful for legacy clients. Smart clients
25609517SBill.Taylor@Sun.COM * such as IPoIB will use the IBT_HCA_WQE_SIZE_INFO sgl info.
25619517SBill.Taylor@Sun.COM */
25629517SBill.Taylor@Sun.COM if (state->hs_devlim.max_sg_rq <= state->hs_devlim.max_sg_sq) {
25639517SBill.Taylor@Sun.COM maxval = state->hs_devlim.max_sg_rq;
25649517SBill.Taylor@Sun.COM } else {
25659517SBill.Taylor@Sun.COM maxval = state->hs_devlim.max_sg_sq;
25669517SBill.Taylor@Sun.COM }
25679517SBill.Taylor@Sun.COM val = state->hs_cfg_profile->cp_wqe_max_sgl;
25689517SBill.Taylor@Sun.COM if (val > maxval) {
25699517SBill.Taylor@Sun.COM kmem_free(hca_attr, sizeof (ibt_hca_attr_t));
25709517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
25719517SBill.Taylor@Sun.COM "soft_state_init_toomanysgl_fail");
25729517SBill.Taylor@Sun.COM return (DDI_FAILURE);
25739517SBill.Taylor@Sun.COM }
25749517SBill.Taylor@Sun.COM /* If the rounded value for max SGL is too large, cap it */
25759517SBill.Taylor@Sun.COM if (state->hs_cfg_profile->cp_wqe_real_max_sgl > maxval) {
25769517SBill.Taylor@Sun.COM state->hs_cfg_profile->cp_wqe_real_max_sgl = (uint32_t)maxval;
25779517SBill.Taylor@Sun.COM val = maxval;
25789517SBill.Taylor@Sun.COM } else {
25799517SBill.Taylor@Sun.COM val = state->hs_cfg_profile->cp_wqe_real_max_sgl;
25809517SBill.Taylor@Sun.COM }
25819517SBill.Taylor@Sun.COM
25829517SBill.Taylor@Sun.COM hca_attr->hca_max_sgl = (uint_t)val;
25839517SBill.Taylor@Sun.COM hca_attr->hca_max_rd_sgl = 0; /* zero because RD is unsupported */
25849517SBill.Taylor@Sun.COM
25859517SBill.Taylor@Sun.COM /*
25869517SBill.Taylor@Sun.COM * Determine number of available CQs and max CQ size. Number of
25879517SBill.Taylor@Sun.COM * available CQs is determined by subtracting the number of
25889517SBill.Taylor@Sun.COM * "reserved CQs" (i.e. reserved for firmware use) from the
25899517SBill.Taylor@Sun.COM * total number configured.
25909517SBill.Taylor@Sun.COM */
25919517SBill.Taylor@Sun.COM val = ((uint64_t)1 << state->hs_cfg_profile->cp_log_num_cq);
25929517SBill.Taylor@Sun.COM hca_attr->hca_max_cq = val - ((uint64_t)1 <<
25939517SBill.Taylor@Sun.COM state->hs_devlim.log_rsvd_cq);
25949517SBill.Taylor@Sun.COM maxval = ((uint64_t)1 << state->hs_devlim.log_max_cq_sz);
25959517SBill.Taylor@Sun.COM val = ((uint64_t)1 << state->hs_cfg_profile->cp_log_max_cq_sz) - 1;
25969517SBill.Taylor@Sun.COM if (val > maxval) {
25979517SBill.Taylor@Sun.COM kmem_free(hca_attr, sizeof (ibt_hca_attr_t));
25989517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
25999517SBill.Taylor@Sun.COM "soft_state_init_maxcqsz_toobig_fail");
26009517SBill.Taylor@Sun.COM return (DDI_FAILURE);
26019517SBill.Taylor@Sun.COM }
26029517SBill.Taylor@Sun.COM hca_attr->hca_max_cq_sz = (uint_t)val;
26039517SBill.Taylor@Sun.COM
26049517SBill.Taylor@Sun.COM /*
26059517SBill.Taylor@Sun.COM * Determine number of available SRQs and max SRQ size. Number of
26069517SBill.Taylor@Sun.COM * available SRQs is determined by subtracting the number of
26079517SBill.Taylor@Sun.COM * "reserved SRQs" (i.e. reserved for firmware use) from the
26089517SBill.Taylor@Sun.COM * total number configured.
26099517SBill.Taylor@Sun.COM */
26109517SBill.Taylor@Sun.COM val = ((uint64_t)1 << state->hs_cfg_profile->cp_log_num_srq);
26119517SBill.Taylor@Sun.COM hca_attr->hca_max_srqs = val - ((uint64_t)1 <<
26129517SBill.Taylor@Sun.COM state->hs_devlim.log_rsvd_srq);
26139517SBill.Taylor@Sun.COM maxval = ((uint64_t)1 << state->hs_devlim.log_max_srq_sz);
26149517SBill.Taylor@Sun.COM val = ((uint64_t)1 << state->hs_cfg_profile->cp_log_max_srq_sz);
26159517SBill.Taylor@Sun.COM
26169517SBill.Taylor@Sun.COM if (val > maxval) {
26179517SBill.Taylor@Sun.COM kmem_free(hca_attr, sizeof (ibt_hca_attr_t));
26189517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
26199517SBill.Taylor@Sun.COM "soft_state_init_maxsrqsz_toobig_fail");
26209517SBill.Taylor@Sun.COM return (DDI_FAILURE);
26219517SBill.Taylor@Sun.COM }
26229517SBill.Taylor@Sun.COM hca_attr->hca_max_srqs_sz = (uint_t)val;
26239517SBill.Taylor@Sun.COM
26249517SBill.Taylor@Sun.COM val = hca_attr->hca_recv_sgl_sz - 1; /* SRQ has a list link */
26259517SBill.Taylor@Sun.COM maxval = state->hs_devlim.max_sg_rq - 1;
26269517SBill.Taylor@Sun.COM if (val > maxval) {
26279517SBill.Taylor@Sun.COM kmem_free(hca_attr, sizeof (ibt_hca_attr_t));
26289517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
26299517SBill.Taylor@Sun.COM "soft_state_init_toomanysrqsgl_fail");
26309517SBill.Taylor@Sun.COM return (DDI_FAILURE);
26319517SBill.Taylor@Sun.COM }
26329517SBill.Taylor@Sun.COM hca_attr->hca_max_srq_sgl = (uint_t)val;
26339517SBill.Taylor@Sun.COM
26349517SBill.Taylor@Sun.COM /*
26359517SBill.Taylor@Sun.COM * Determine supported HCA page sizes
26369517SBill.Taylor@Sun.COM * XXX
26379517SBill.Taylor@Sun.COM * For now we simply return the system pagesize as the only supported
26389517SBill.Taylor@Sun.COM * pagesize
26399517SBill.Taylor@Sun.COM */
26409517SBill.Taylor@Sun.COM hca_attr->hca_page_sz = ((PAGESIZE == (1 << 13)) ? IBT_PAGE_8K :
26419517SBill.Taylor@Sun.COM IBT_PAGE_4K);
26429517SBill.Taylor@Sun.COM
26439517SBill.Taylor@Sun.COM /*
26449517SBill.Taylor@Sun.COM * Determine number of available MemReg, MemWin, and their max size.
26459517SBill.Taylor@Sun.COM * Number of available MRs and MWs is determined by subtracting
26469517SBill.Taylor@Sun.COM * the number of "reserved MPTs" (i.e. reserved for firmware use)
26479517SBill.Taylor@Sun.COM * from the total number configured for each.
26489517SBill.Taylor@Sun.COM */
26499517SBill.Taylor@Sun.COM val = ((uint64_t)1 << state->hs_cfg_profile->cp_log_num_dmpt);
26509517SBill.Taylor@Sun.COM hca_attr->hca_max_memr = val - ((uint64_t)1 <<
26519517SBill.Taylor@Sun.COM state->hs_devlim.log_rsvd_dmpt);
26529517SBill.Taylor@Sun.COM hca_attr->hca_max_mem_win = state->hs_devlim.mem_win ? (val -
26539517SBill.Taylor@Sun.COM ((uint64_t)1 << state->hs_devlim.log_rsvd_dmpt)) : 0;
26549517SBill.Taylor@Sun.COM maxval = state->hs_devlim.log_max_mrw_sz;
26559517SBill.Taylor@Sun.COM val = state->hs_cfg_profile->cp_log_max_mrw_sz;
26569517SBill.Taylor@Sun.COM if (val > maxval) {
26579517SBill.Taylor@Sun.COM kmem_free(hca_attr, sizeof (ibt_hca_attr_t));
26589517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
26599517SBill.Taylor@Sun.COM "soft_state_init_maxmrwsz_toobig_fail");
26609517SBill.Taylor@Sun.COM return (DDI_FAILURE);
26619517SBill.Taylor@Sun.COM }
26629517SBill.Taylor@Sun.COM hca_attr->hca_max_memr_len = ((uint64_t)1 << val);
26639517SBill.Taylor@Sun.COM
26649517SBill.Taylor@Sun.COM /* Determine RDMA/Atomic properties */
26659517SBill.Taylor@Sun.COM val = ((uint64_t)1 << state->hs_cfg_profile->cp_log_num_rdb);
26669517SBill.Taylor@Sun.COM hca_attr->hca_max_rsc = (uint_t)val;
26679517SBill.Taylor@Sun.COM val = state->hs_cfg_profile->cp_hca_max_rdma_in_qp;
26689517SBill.Taylor@Sun.COM hca_attr->hca_max_rdma_in_qp = (uint8_t)val;
26699517SBill.Taylor@Sun.COM val = state->hs_cfg_profile->cp_hca_max_rdma_out_qp;
26709517SBill.Taylor@Sun.COM hca_attr->hca_max_rdma_out_qp = (uint8_t)val;
26719517SBill.Taylor@Sun.COM hca_attr->hca_max_rdma_in_ee = 0;
26729517SBill.Taylor@Sun.COM hca_attr->hca_max_rdma_out_ee = 0;
26739517SBill.Taylor@Sun.COM
26749517SBill.Taylor@Sun.COM /*
26759517SBill.Taylor@Sun.COM * Determine maximum number of raw IPv6 and Ether QPs. Set to 0
26769517SBill.Taylor@Sun.COM * because neither type of raw QP is supported
26779517SBill.Taylor@Sun.COM */
26789517SBill.Taylor@Sun.COM hca_attr->hca_max_ipv6_qp = 0;
26799517SBill.Taylor@Sun.COM hca_attr->hca_max_ether_qp = 0;
26809517SBill.Taylor@Sun.COM
26819517SBill.Taylor@Sun.COM /* Determine max number of MCGs and max QP-per-MCG */
26829517SBill.Taylor@Sun.COM val = ((uint64_t)1 << state->hs_cfg_profile->cp_log_num_qp);
26839517SBill.Taylor@Sun.COM hca_attr->hca_max_mcg_qps = (uint_t)val;
26849517SBill.Taylor@Sun.COM val = ((uint64_t)1 << state->hs_cfg_profile->cp_log_num_mcg);
26859517SBill.Taylor@Sun.COM hca_attr->hca_max_mcg = (uint_t)val;
26869517SBill.Taylor@Sun.COM val = state->hs_cfg_profile->cp_num_qp_per_mcg;
26879517SBill.Taylor@Sun.COM hca_attr->hca_max_qp_per_mcg = (uint_t)val;
26889517SBill.Taylor@Sun.COM
26899517SBill.Taylor@Sun.COM /* Determine max number partitions (i.e. PKeys) */
26909517SBill.Taylor@Sun.COM maxval = ((uint64_t)state->hs_cfg_profile->cp_num_ports <<
26919517SBill.Taylor@Sun.COM state->hs_queryport.log_max_pkey);
26929517SBill.Taylor@Sun.COM val = ((uint64_t)state->hs_cfg_profile->cp_num_ports <<
26939517SBill.Taylor@Sun.COM state->hs_cfg_profile->cp_log_max_pkeytbl);
26949517SBill.Taylor@Sun.COM
26959517SBill.Taylor@Sun.COM if (val > maxval) {
26969517SBill.Taylor@Sun.COM kmem_free(hca_attr, sizeof (ibt_hca_attr_t));
26979517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
26989517SBill.Taylor@Sun.COM "soft_state_init_toomanypkey_fail");
26999517SBill.Taylor@Sun.COM return (DDI_FAILURE);
27009517SBill.Taylor@Sun.COM }
27019517SBill.Taylor@Sun.COM hca_attr->hca_max_partitions = (uint16_t)val;
27029517SBill.Taylor@Sun.COM
27039517SBill.Taylor@Sun.COM /* Determine number of ports */
27049517SBill.Taylor@Sun.COM maxval = state->hs_devlim.num_ports;
27059517SBill.Taylor@Sun.COM val = state->hs_cfg_profile->cp_num_ports;
27069517SBill.Taylor@Sun.COM if ((val > maxval) || (val == 0)) {
27079517SBill.Taylor@Sun.COM kmem_free(hca_attr, sizeof (ibt_hca_attr_t));
27089517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
27099517SBill.Taylor@Sun.COM "soft_state_init_toomanyports_fail");
27109517SBill.Taylor@Sun.COM return (DDI_FAILURE);
27119517SBill.Taylor@Sun.COM }
27129517SBill.Taylor@Sun.COM hca_attr->hca_nports = (uint8_t)val;
27139517SBill.Taylor@Sun.COM
27149517SBill.Taylor@Sun.COM /* Copy NodeGUID and SystemImageGUID from softstate */
27159517SBill.Taylor@Sun.COM hca_attr->hca_node_guid = state->hs_nodeguid;
27169517SBill.Taylor@Sun.COM hca_attr->hca_si_guid = state->hs_sysimgguid;
27179517SBill.Taylor@Sun.COM
27189517SBill.Taylor@Sun.COM /*
27199517SBill.Taylor@Sun.COM * Determine local ACK delay. Use the value suggested by the Hermon
27209517SBill.Taylor@Sun.COM * hardware (from the QUERY_DEV_CAP command)
27219517SBill.Taylor@Sun.COM */
27229517SBill.Taylor@Sun.COM hca_attr->hca_local_ack_delay = state->hs_devlim.ca_ack_delay;
27239517SBill.Taylor@Sun.COM
27249517SBill.Taylor@Sun.COM /* Determine max SGID table and PKey table sizes */
27259517SBill.Taylor@Sun.COM val = ((uint64_t)1 << state->hs_cfg_profile->cp_log_max_gidtbl);
27269517SBill.Taylor@Sun.COM hca_attr->hca_max_port_sgid_tbl_sz = (uint_t)val;
27279517SBill.Taylor@Sun.COM val = ((uint64_t)1 << state->hs_cfg_profile->cp_log_max_pkeytbl);
27289517SBill.Taylor@Sun.COM hca_attr->hca_max_port_pkey_tbl_sz = (uint16_t)val;
27299517SBill.Taylor@Sun.COM
27309517SBill.Taylor@Sun.COM /* Determine max number of PDs */
27319517SBill.Taylor@Sun.COM maxval = ((uint64_t)1 << state->hs_devlim.log_max_pd);
27329517SBill.Taylor@Sun.COM val = ((uint64_t)1 << state->hs_cfg_profile->cp_log_num_pd);
27339517SBill.Taylor@Sun.COM if (val > maxval) {
27349517SBill.Taylor@Sun.COM kmem_free(hca_attr, sizeof (ibt_hca_attr_t));
27359517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
27369517SBill.Taylor@Sun.COM "soft_state_init_toomanypd_fail");
27379517SBill.Taylor@Sun.COM return (DDI_FAILURE);
27389517SBill.Taylor@Sun.COM }
27399517SBill.Taylor@Sun.COM hca_attr->hca_max_pd = (uint_t)val;
27409517SBill.Taylor@Sun.COM
27419517SBill.Taylor@Sun.COM /* Determine max number of Address Handles (NOT IN ARBEL or HERMON) */
27429517SBill.Taylor@Sun.COM hca_attr->hca_max_ah = 0;
27439517SBill.Taylor@Sun.COM
27449517SBill.Taylor@Sun.COM /* No RDDs or EECs (since Reliable Datagram is not supported) */
27459517SBill.Taylor@Sun.COM hca_attr->hca_max_rdd = 0;
27469517SBill.Taylor@Sun.COM hca_attr->hca_max_eec = 0;
27479517SBill.Taylor@Sun.COM
27489517SBill.Taylor@Sun.COM /* Initialize lock for reserved UAR page access */
27499517SBill.Taylor@Sun.COM mutex_init(&state->hs_uar_lock, NULL, MUTEX_DRIVER,
27509517SBill.Taylor@Sun.COM DDI_INTR_PRI(state->hs_intrmsi_pri));
27519517SBill.Taylor@Sun.COM
27529517SBill.Taylor@Sun.COM /* Initialize the flash fields */
27539517SBill.Taylor@Sun.COM state->hs_fw_flashstarted = 0;
27549517SBill.Taylor@Sun.COM mutex_init(&state->hs_fw_flashlock, NULL, MUTEX_DRIVER,
27559517SBill.Taylor@Sun.COM DDI_INTR_PRI(state->hs_intrmsi_pri));
27569517SBill.Taylor@Sun.COM
27579517SBill.Taylor@Sun.COM /* Initialize the lock for the info ioctl */
27589517SBill.Taylor@Sun.COM mutex_init(&state->hs_info_lock, NULL, MUTEX_DRIVER,
27599517SBill.Taylor@Sun.COM DDI_INTR_PRI(state->hs_intrmsi_pri));
27609517SBill.Taylor@Sun.COM
27619517SBill.Taylor@Sun.COM /* Initialize the AVL tree for QP number support */
27629517SBill.Taylor@Sun.COM hermon_qpn_avl_init(state);
27639517SBill.Taylor@Sun.COM
276412965SWilliam.Taylor@Oracle.COM /* Initialize the cq_sched info structure */
276512965SWilliam.Taylor@Oracle.COM status = hermon_cq_sched_init(state);
276612965SWilliam.Taylor@Oracle.COM if (status != DDI_SUCCESS) {
276712965SWilliam.Taylor@Oracle.COM hermon_qpn_avl_fini(state);
276812965SWilliam.Taylor@Oracle.COM mutex_destroy(&state->hs_info_lock);
276912965SWilliam.Taylor@Oracle.COM mutex_destroy(&state->hs_fw_flashlock);
277012965SWilliam.Taylor@Oracle.COM mutex_destroy(&state->hs_uar_lock);
277112965SWilliam.Taylor@Oracle.COM kmem_free(hca_attr, sizeof (ibt_hca_attr_t));
277212965SWilliam.Taylor@Oracle.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
277312965SWilliam.Taylor@Oracle.COM "soft_state_init_cqsched_init_fail");
277412965SWilliam.Taylor@Oracle.COM return (DDI_FAILURE);
277512965SWilliam.Taylor@Oracle.COM }
277612965SWilliam.Taylor@Oracle.COM
277712965SWilliam.Taylor@Oracle.COM /* Initialize the fcoib info structure */
277812965SWilliam.Taylor@Oracle.COM status = hermon_fcoib_init(state);
277912965SWilliam.Taylor@Oracle.COM if (status != DDI_SUCCESS) {
278012965SWilliam.Taylor@Oracle.COM hermon_cq_sched_fini(state);
278112965SWilliam.Taylor@Oracle.COM hermon_qpn_avl_fini(state);
278212965SWilliam.Taylor@Oracle.COM mutex_destroy(&state->hs_info_lock);
278312965SWilliam.Taylor@Oracle.COM mutex_destroy(&state->hs_fw_flashlock);
278412965SWilliam.Taylor@Oracle.COM mutex_destroy(&state->hs_uar_lock);
278512965SWilliam.Taylor@Oracle.COM kmem_free(hca_attr, sizeof (ibt_hca_attr_t));
278612965SWilliam.Taylor@Oracle.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
278712965SWilliam.Taylor@Oracle.COM "soft_state_init_fcoibinit_fail");
278812965SWilliam.Taylor@Oracle.COM return (DDI_FAILURE);
278912965SWilliam.Taylor@Oracle.COM }
279012965SWilliam.Taylor@Oracle.COM
27919517SBill.Taylor@Sun.COM /* Initialize the kstat info structure */
27929517SBill.Taylor@Sun.COM status = hermon_kstat_init(state);
27939517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
279412965SWilliam.Taylor@Oracle.COM hermon_fcoib_fini(state);
279512965SWilliam.Taylor@Oracle.COM hermon_cq_sched_fini(state);
27969517SBill.Taylor@Sun.COM hermon_qpn_avl_fini(state);
27979517SBill.Taylor@Sun.COM mutex_destroy(&state->hs_info_lock);
27989517SBill.Taylor@Sun.COM mutex_destroy(&state->hs_fw_flashlock);
27999517SBill.Taylor@Sun.COM mutex_destroy(&state->hs_uar_lock);
28009517SBill.Taylor@Sun.COM kmem_free(hca_attr, sizeof (ibt_hca_attr_t));
28019517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
28029517SBill.Taylor@Sun.COM "soft_state_init_kstatinit_fail");
28039517SBill.Taylor@Sun.COM return (DDI_FAILURE);
28049517SBill.Taylor@Sun.COM }
28059517SBill.Taylor@Sun.COM
28069517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
28079517SBill.Taylor@Sun.COM }
28089517SBill.Taylor@Sun.COM
28099517SBill.Taylor@Sun.COM
28109517SBill.Taylor@Sun.COM /*
28119517SBill.Taylor@Sun.COM * hermon_soft_state_fini()
28129517SBill.Taylor@Sun.COM * Context: Called only from detach() path context
28139517SBill.Taylor@Sun.COM */
28149517SBill.Taylor@Sun.COM static void
hermon_soft_state_fini(hermon_state_t * state)28159517SBill.Taylor@Sun.COM hermon_soft_state_fini(hermon_state_t *state)
28169517SBill.Taylor@Sun.COM {
28179517SBill.Taylor@Sun.COM
28189517SBill.Taylor@Sun.COM /* Teardown the kstat info */
28199517SBill.Taylor@Sun.COM hermon_kstat_fini(state);
28209517SBill.Taylor@Sun.COM
282112965SWilliam.Taylor@Oracle.COM /* Teardown the fcoib info */
282212965SWilliam.Taylor@Oracle.COM hermon_fcoib_fini(state);
282312965SWilliam.Taylor@Oracle.COM
282412965SWilliam.Taylor@Oracle.COM /* Teardown the cq_sched info */
282512965SWilliam.Taylor@Oracle.COM hermon_cq_sched_fini(state);
282612965SWilliam.Taylor@Oracle.COM
28279517SBill.Taylor@Sun.COM /* Teardown the AVL tree for QP number support */
28289517SBill.Taylor@Sun.COM hermon_qpn_avl_fini(state);
28299517SBill.Taylor@Sun.COM
28309517SBill.Taylor@Sun.COM /* Free up info ioctl mutex */
28319517SBill.Taylor@Sun.COM mutex_destroy(&state->hs_info_lock);
28329517SBill.Taylor@Sun.COM
28339517SBill.Taylor@Sun.COM /* Free up flash mutex */
28349517SBill.Taylor@Sun.COM mutex_destroy(&state->hs_fw_flashlock);
28359517SBill.Taylor@Sun.COM
28369517SBill.Taylor@Sun.COM /* Free up the UAR page access mutex */
28379517SBill.Taylor@Sun.COM mutex_destroy(&state->hs_uar_lock);
28389517SBill.Taylor@Sun.COM
28399517SBill.Taylor@Sun.COM /* Free up the hca_attr struct */
28409517SBill.Taylor@Sun.COM kmem_free(state->hs_ibtfinfo.hca_attr, sizeof (ibt_hca_attr_t));
28419517SBill.Taylor@Sun.COM
28429517SBill.Taylor@Sun.COM }
28439517SBill.Taylor@Sun.COM
28449517SBill.Taylor@Sun.COM /*
28459517SBill.Taylor@Sun.COM * hermon_icm_config_setup()
28469517SBill.Taylor@Sun.COM * Context: Only called from attach() path context
28479517SBill.Taylor@Sun.COM */
28489517SBill.Taylor@Sun.COM static int
hermon_icm_config_setup(hermon_state_t * state,hermon_hw_initqueryhca_t * inithca)28499517SBill.Taylor@Sun.COM hermon_icm_config_setup(hermon_state_t *state,
28509517SBill.Taylor@Sun.COM hermon_hw_initqueryhca_t *inithca)
28519517SBill.Taylor@Sun.COM {
28529517SBill.Taylor@Sun.COM hermon_hw_querydevlim_t *devlim;
28539517SBill.Taylor@Sun.COM hermon_cfg_profile_t *cfg;
28549517SBill.Taylor@Sun.COM hermon_icm_table_t *icm_p[HERMON_NUM_ICM_RESOURCES];
28559517SBill.Taylor@Sun.COM hermon_icm_table_t *icm;
28569517SBill.Taylor@Sun.COM hermon_icm_table_t *tmp;
28579517SBill.Taylor@Sun.COM uint64_t icm_addr;
28589517SBill.Taylor@Sun.COM uint64_t icm_size;
28599517SBill.Taylor@Sun.COM int status, i, j;
28609517SBill.Taylor@Sun.COM
28619517SBill.Taylor@Sun.COM
28629517SBill.Taylor@Sun.COM /* Bring in local devlims, cfg_profile and hs_icm table list */
28639517SBill.Taylor@Sun.COM devlim = &state->hs_devlim;
28649517SBill.Taylor@Sun.COM cfg = state->hs_cfg_profile;
28659517SBill.Taylor@Sun.COM icm = state->hs_icm;
28669517SBill.Taylor@Sun.COM
28679517SBill.Taylor@Sun.COM /*
28689517SBill.Taylor@Sun.COM * Assign each ICM table's entry size from data in the devlims,
28699517SBill.Taylor@Sun.COM * except for RDB and MCG sizes, which are not returned in devlims
28709517SBill.Taylor@Sun.COM * but do have a fixed size, and the UAR context entry size, which
28719517SBill.Taylor@Sun.COM * we determine. For this, we use the "cp_num_pgs_per_uce" value
28729517SBill.Taylor@Sun.COM * from our hs_cfg_profile.
28739517SBill.Taylor@Sun.COM */
28749517SBill.Taylor@Sun.COM icm[HERMON_CMPT].object_size = devlim->cmpt_entry_sz;
28759517SBill.Taylor@Sun.COM icm[HERMON_CMPT_QPC].object_size = devlim->cmpt_entry_sz;
28769517SBill.Taylor@Sun.COM icm[HERMON_CMPT_SRQC].object_size = devlim->cmpt_entry_sz;
28779517SBill.Taylor@Sun.COM icm[HERMON_CMPT_CQC].object_size = devlim->cmpt_entry_sz;
28789517SBill.Taylor@Sun.COM icm[HERMON_CMPT_EQC].object_size = devlim->cmpt_entry_sz;
28799517SBill.Taylor@Sun.COM icm[HERMON_MTT].object_size = devlim->mtt_entry_sz;
28809517SBill.Taylor@Sun.COM icm[HERMON_DMPT].object_size = devlim->dmpt_entry_sz;
28819517SBill.Taylor@Sun.COM icm[HERMON_QPC].object_size = devlim->qpc_entry_sz;
28829517SBill.Taylor@Sun.COM icm[HERMON_CQC].object_size = devlim->cqc_entry_sz;
28839517SBill.Taylor@Sun.COM icm[HERMON_SRQC].object_size = devlim->srq_entry_sz;
28849517SBill.Taylor@Sun.COM icm[HERMON_EQC].object_size = devlim->eqc_entry_sz;
28859517SBill.Taylor@Sun.COM icm[HERMON_RDB].object_size = devlim->rdmardc_entry_sz *
28869517SBill.Taylor@Sun.COM cfg->cp_hca_max_rdma_in_qp;
288710009SGiri.Adari@Sun.COM icm[HERMON_MCG].object_size = HERMON_MCGMEM_SZ(state);
28889517SBill.Taylor@Sun.COM icm[HERMON_ALTC].object_size = devlim->altc_entry_sz;
28899517SBill.Taylor@Sun.COM icm[HERMON_AUXC].object_size = devlim->aux_entry_sz;
28909517SBill.Taylor@Sun.COM
28919517SBill.Taylor@Sun.COM /* Assign each ICM table's log2 number of entries */
28929517SBill.Taylor@Sun.COM icm[HERMON_CMPT].log_num_entries = cfg->cp_log_num_cmpt;
28939517SBill.Taylor@Sun.COM icm[HERMON_CMPT_QPC].log_num_entries = cfg->cp_log_num_qp;
28949517SBill.Taylor@Sun.COM icm[HERMON_CMPT_SRQC].log_num_entries = cfg->cp_log_num_srq;
28959517SBill.Taylor@Sun.COM icm[HERMON_CMPT_CQC].log_num_entries = cfg->cp_log_num_cq;
28969517SBill.Taylor@Sun.COM icm[HERMON_CMPT_EQC].log_num_entries = HERMON_NUM_EQ_SHIFT;
28979517SBill.Taylor@Sun.COM icm[HERMON_MTT].log_num_entries = cfg->cp_log_num_mtt;
28989517SBill.Taylor@Sun.COM icm[HERMON_DMPT].log_num_entries = cfg->cp_log_num_dmpt;
28999517SBill.Taylor@Sun.COM icm[HERMON_QPC].log_num_entries = cfg->cp_log_num_qp;
29009517SBill.Taylor@Sun.COM icm[HERMON_SRQC].log_num_entries = cfg->cp_log_num_srq;
29019517SBill.Taylor@Sun.COM icm[HERMON_CQC].log_num_entries = cfg->cp_log_num_cq;
29029517SBill.Taylor@Sun.COM icm[HERMON_EQC].log_num_entries = HERMON_NUM_EQ_SHIFT;
29039517SBill.Taylor@Sun.COM icm[HERMON_RDB].log_num_entries = cfg->cp_log_num_qp;
29049517SBill.Taylor@Sun.COM icm[HERMON_MCG].log_num_entries = cfg->cp_log_num_mcg;
29059517SBill.Taylor@Sun.COM icm[HERMON_ALTC].log_num_entries = cfg->cp_log_num_qp;
29069517SBill.Taylor@Sun.COM icm[HERMON_AUXC].log_num_entries = cfg->cp_log_num_qp;
29079517SBill.Taylor@Sun.COM
29089517SBill.Taylor@Sun.COM /* Initialize the ICM tables */
29099517SBill.Taylor@Sun.COM hermon_icm_tables_init(state);
29109517SBill.Taylor@Sun.COM
29119517SBill.Taylor@Sun.COM /*
29129517SBill.Taylor@Sun.COM * ICM tables must be aligned on their size in the ICM address
29139517SBill.Taylor@Sun.COM * space. So, here we order the tables from largest total table
29149517SBill.Taylor@Sun.COM * size to the smallest. All tables are a power of 2 in size, so
29159517SBill.Taylor@Sun.COM * this will ensure that all tables are aligned on their own size
29169517SBill.Taylor@Sun.COM * without wasting space in the ICM.
29179517SBill.Taylor@Sun.COM *
29189517SBill.Taylor@Sun.COM * In order to easily set the ICM addresses without needing to
29199517SBill.Taylor@Sun.COM * worry about the ordering of our table indices as relates to
29209517SBill.Taylor@Sun.COM * the hermon_rsrc_type_t enum, we will use a list of pointers
29219517SBill.Taylor@Sun.COM * representing the tables for the sort, then assign ICM addresses
29229517SBill.Taylor@Sun.COM * below using it.
29239517SBill.Taylor@Sun.COM */
29249517SBill.Taylor@Sun.COM for (i = 0; i < HERMON_NUM_ICM_RESOURCES; i++) {
29259517SBill.Taylor@Sun.COM icm_p[i] = &icm[i];
29269517SBill.Taylor@Sun.COM }
29279517SBill.Taylor@Sun.COM for (i = HERMON_NUM_ICM_RESOURCES; i > 0; i--) {
29289517SBill.Taylor@Sun.COM switch (i) {
29299517SBill.Taylor@Sun.COM case HERMON_CMPT_QPC:
29309517SBill.Taylor@Sun.COM case HERMON_CMPT_SRQC:
29319517SBill.Taylor@Sun.COM case HERMON_CMPT_CQC:
29329517SBill.Taylor@Sun.COM case HERMON_CMPT_EQC:
29339517SBill.Taylor@Sun.COM continue;
29349517SBill.Taylor@Sun.COM }
29359517SBill.Taylor@Sun.COM for (j = 1; j < i; j++) {
29369517SBill.Taylor@Sun.COM if (icm_p[j]->table_size > icm_p[j - 1]->table_size) {
29379517SBill.Taylor@Sun.COM tmp = icm_p[j];
29389517SBill.Taylor@Sun.COM icm_p[j] = icm_p[j - 1];
29399517SBill.Taylor@Sun.COM icm_p[j - 1] = tmp;
29409517SBill.Taylor@Sun.COM }
29419517SBill.Taylor@Sun.COM }
29429517SBill.Taylor@Sun.COM }
29439517SBill.Taylor@Sun.COM
29449517SBill.Taylor@Sun.COM /* Initialize the ICM address and ICM size */
29459517SBill.Taylor@Sun.COM icm_addr = icm_size = 0;
29469517SBill.Taylor@Sun.COM
29479517SBill.Taylor@Sun.COM /*
29489517SBill.Taylor@Sun.COM * Set the ICM base address of each table, using our sorted
29499517SBill.Taylor@Sun.COM * list of pointers from above.
29509517SBill.Taylor@Sun.COM */
29519517SBill.Taylor@Sun.COM for (i = 0; i < HERMON_NUM_ICM_RESOURCES; i++) {
29529517SBill.Taylor@Sun.COM j = icm_p[i]->icm_type;
29539517SBill.Taylor@Sun.COM switch (j) {
29549517SBill.Taylor@Sun.COM case HERMON_CMPT_QPC:
29559517SBill.Taylor@Sun.COM case HERMON_CMPT_SRQC:
29569517SBill.Taylor@Sun.COM case HERMON_CMPT_CQC:
29579517SBill.Taylor@Sun.COM case HERMON_CMPT_EQC:
29589517SBill.Taylor@Sun.COM continue;
29599517SBill.Taylor@Sun.COM }
29609517SBill.Taylor@Sun.COM if (icm[j].table_size) {
29619517SBill.Taylor@Sun.COM /*
29629517SBill.Taylor@Sun.COM * Set the ICM base address in the table, save the
29639517SBill.Taylor@Sun.COM * ICM offset in the rsrc pool and increment the
29649517SBill.Taylor@Sun.COM * total ICM allocation.
29659517SBill.Taylor@Sun.COM */
29669517SBill.Taylor@Sun.COM icm[j].icm_baseaddr = icm_addr;
29679517SBill.Taylor@Sun.COM if (hermon_verbose) {
29689517SBill.Taylor@Sun.COM IBTF_DPRINTF_L2("ICMADDR", "rsrc %x @ %p"
29699517SBill.Taylor@Sun.COM " size %llx", j, icm[j].icm_baseaddr,
29709517SBill.Taylor@Sun.COM icm[j].table_size);
29719517SBill.Taylor@Sun.COM }
29729517SBill.Taylor@Sun.COM icm_size += icm[j].table_size;
29739517SBill.Taylor@Sun.COM }
29749517SBill.Taylor@Sun.COM
29759517SBill.Taylor@Sun.COM /* Verify that we don't exceed maximum ICM size */
29769517SBill.Taylor@Sun.COM if (icm_size > devlim->max_icm_size) {
29779517SBill.Taylor@Sun.COM /* free the ICM table memory resources */
29789517SBill.Taylor@Sun.COM hermon_icm_tables_fini(state);
29799517SBill.Taylor@Sun.COM cmn_err(CE_WARN, "ICM configuration exceeds maximum "
29809517SBill.Taylor@Sun.COM "configuration: max (0x%lx) requested (0x%lx)\n",
29819517SBill.Taylor@Sun.COM (ulong_t)devlim->max_icm_size, (ulong_t)icm_size);
29829517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
29839517SBill.Taylor@Sun.COM "icm_config_toobig_fail");
29849517SBill.Taylor@Sun.COM return (DDI_FAILURE);
29859517SBill.Taylor@Sun.COM }
29869517SBill.Taylor@Sun.COM
29879517SBill.Taylor@Sun.COM /* assign address to the 4 pieces of the CMPT */
29889517SBill.Taylor@Sun.COM if (j == HERMON_CMPT) {
29899517SBill.Taylor@Sun.COM uint64_t cmpt_size = icm[j].table_size >> 2;
29909517SBill.Taylor@Sun.COM #define init_cmpt_icm_baseaddr(rsrc, indx) \
29919517SBill.Taylor@Sun.COM icm[rsrc].icm_baseaddr = icm_addr + (indx * cmpt_size);
29929517SBill.Taylor@Sun.COM init_cmpt_icm_baseaddr(HERMON_CMPT_QPC, 0);
29939517SBill.Taylor@Sun.COM init_cmpt_icm_baseaddr(HERMON_CMPT_SRQC, 1);
29949517SBill.Taylor@Sun.COM init_cmpt_icm_baseaddr(HERMON_CMPT_CQC, 2);
29959517SBill.Taylor@Sun.COM init_cmpt_icm_baseaddr(HERMON_CMPT_EQC, 3);
29969517SBill.Taylor@Sun.COM }
29979517SBill.Taylor@Sun.COM
29989517SBill.Taylor@Sun.COM /* Increment the ICM address for the next table */
29999517SBill.Taylor@Sun.COM icm_addr += icm[j].table_size;
30009517SBill.Taylor@Sun.COM }
30019517SBill.Taylor@Sun.COM
30029517SBill.Taylor@Sun.COM /* Populate the structure for the INIT_HCA command */
30039517SBill.Taylor@Sun.COM hermon_inithca_set(state, inithca);
30049517SBill.Taylor@Sun.COM
30059517SBill.Taylor@Sun.COM /*
30069517SBill.Taylor@Sun.COM * Prior to invoking INIT_HCA, we must have ICM memory in place
30079517SBill.Taylor@Sun.COM * for the reserved objects in each table. We will allocate and map
30089517SBill.Taylor@Sun.COM * this initial ICM memory here. Note that given the assignment
30099517SBill.Taylor@Sun.COM * of span_size above, tables that are smaller or equal in total
30109517SBill.Taylor@Sun.COM * size to the default span_size will be mapped in full.
30119517SBill.Taylor@Sun.COM */
30129517SBill.Taylor@Sun.COM status = hermon_icm_dma_init(state);
30139517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
30149517SBill.Taylor@Sun.COM /* free the ICM table memory resources */
30159517SBill.Taylor@Sun.COM hermon_icm_tables_fini(state);
30169517SBill.Taylor@Sun.COM HERMON_WARNING(state, "Failed to allocate initial ICM");
30179517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
30189517SBill.Taylor@Sun.COM "icm_config_dma_init_fail");
30199517SBill.Taylor@Sun.COM return (DDI_FAILURE);
30209517SBill.Taylor@Sun.COM }
30219517SBill.Taylor@Sun.COM
30229517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
30239517SBill.Taylor@Sun.COM }
30249517SBill.Taylor@Sun.COM
30259517SBill.Taylor@Sun.COM /*
30269517SBill.Taylor@Sun.COM * hermon_inithca_set()
30279517SBill.Taylor@Sun.COM * Context: Only called from attach() path context
30289517SBill.Taylor@Sun.COM */
30299517SBill.Taylor@Sun.COM static void
hermon_inithca_set(hermon_state_t * state,hermon_hw_initqueryhca_t * inithca)30309517SBill.Taylor@Sun.COM hermon_inithca_set(hermon_state_t *state, hermon_hw_initqueryhca_t *inithca)
30319517SBill.Taylor@Sun.COM {
30329517SBill.Taylor@Sun.COM hermon_cfg_profile_t *cfg;
30339517SBill.Taylor@Sun.COM hermon_icm_table_t *icm;
30349517SBill.Taylor@Sun.COM int i;
30359517SBill.Taylor@Sun.COM
30369517SBill.Taylor@Sun.COM
30379517SBill.Taylor@Sun.COM /* Populate the INIT_HCA structure */
30389517SBill.Taylor@Sun.COM icm = state->hs_icm;
30399517SBill.Taylor@Sun.COM cfg = state->hs_cfg_profile;
30409517SBill.Taylor@Sun.COM
30419517SBill.Taylor@Sun.COM /* set version */
30429517SBill.Taylor@Sun.COM inithca->version = 0x02; /* PRM 0.36 */
30439517SBill.Taylor@Sun.COM /* set cacheline - log2 in 16-byte chunks */
30449517SBill.Taylor@Sun.COM inithca->log2_cacheline = 0x2; /* optimized for 64 byte cache */
30459517SBill.Taylor@Sun.COM
30469517SBill.Taylor@Sun.COM /* we need to update the inithca info with thie UAR info too */
30479517SBill.Taylor@Sun.COM inithca->uar.log_max_uars = highbit(cfg->cp_log_num_uar);
30489517SBill.Taylor@Sun.COM inithca->uar.uar_pg_sz = PAGESHIFT - HERMON_PAGESHIFT;
30499517SBill.Taylor@Sun.COM
30509517SBill.Taylor@Sun.COM /* Set endianess */
30519517SBill.Taylor@Sun.COM #ifdef _LITTLE_ENDIAN
30529517SBill.Taylor@Sun.COM inithca->big_endian = 0;
30539517SBill.Taylor@Sun.COM #else
30549517SBill.Taylor@Sun.COM inithca->big_endian = 1;
30559517SBill.Taylor@Sun.COM #endif
30569517SBill.Taylor@Sun.COM
30579517SBill.Taylor@Sun.COM /* Port Checking is on by default */
30589517SBill.Taylor@Sun.COM inithca->udav_port_chk = HERMON_UDAV_PORTCHK_ENABLED;
30599517SBill.Taylor@Sun.COM
30609517SBill.Taylor@Sun.COM /* Enable IPoIB checksum */
30619517SBill.Taylor@Sun.COM if (state->hs_devlim.ipoib_cksm)
30629517SBill.Taylor@Sun.COM inithca->chsum_en = 1;
30639517SBill.Taylor@Sun.COM
30649517SBill.Taylor@Sun.COM /* Set each ICM table's attributes */
30659517SBill.Taylor@Sun.COM for (i = 0; i < HERMON_NUM_ICM_RESOURCES; i++) {
30669517SBill.Taylor@Sun.COM switch (icm[i].icm_type) {
30679517SBill.Taylor@Sun.COM case HERMON_CMPT:
30689517SBill.Taylor@Sun.COM inithca->tpt.cmpt_baseaddr = icm[i].icm_baseaddr;
30699517SBill.Taylor@Sun.COM break;
30709517SBill.Taylor@Sun.COM
30719517SBill.Taylor@Sun.COM case HERMON_MTT:
30729517SBill.Taylor@Sun.COM inithca->tpt.mtt_baseaddr = icm[i].icm_baseaddr;
30739517SBill.Taylor@Sun.COM break;
30749517SBill.Taylor@Sun.COM
30759517SBill.Taylor@Sun.COM case HERMON_DMPT:
30769517SBill.Taylor@Sun.COM inithca->tpt.dmpt_baseaddr = icm[i].icm_baseaddr;
30779517SBill.Taylor@Sun.COM inithca->tpt.log_dmpt_sz = icm[i].log_num_entries;
30789517SBill.Taylor@Sun.COM inithca->tpt.pgfault_rnr_to = 0; /* just in case */
30799517SBill.Taylor@Sun.COM break;
30809517SBill.Taylor@Sun.COM
30819517SBill.Taylor@Sun.COM case HERMON_QPC:
30829517SBill.Taylor@Sun.COM inithca->context.log_num_qp = icm[i].log_num_entries;
30839517SBill.Taylor@Sun.COM inithca->context.qpc_baseaddr_h =
30849517SBill.Taylor@Sun.COM icm[i].icm_baseaddr >> 32;
30859517SBill.Taylor@Sun.COM inithca->context.qpc_baseaddr_l =
30869517SBill.Taylor@Sun.COM (icm[i].icm_baseaddr & 0xFFFFFFFF) >> 5;
30879517SBill.Taylor@Sun.COM break;
30889517SBill.Taylor@Sun.COM
30899517SBill.Taylor@Sun.COM case HERMON_CQC:
30909517SBill.Taylor@Sun.COM inithca->context.log_num_cq = icm[i].log_num_entries;
30919517SBill.Taylor@Sun.COM inithca->context.cqc_baseaddr_h =
30929517SBill.Taylor@Sun.COM icm[i].icm_baseaddr >> 32;
30939517SBill.Taylor@Sun.COM inithca->context.cqc_baseaddr_l =
30949517SBill.Taylor@Sun.COM (icm[i].icm_baseaddr & 0xFFFFFFFF) >> 5;
30959517SBill.Taylor@Sun.COM break;
30969517SBill.Taylor@Sun.COM
30979517SBill.Taylor@Sun.COM case HERMON_SRQC:
30989517SBill.Taylor@Sun.COM inithca->context.log_num_srq = icm[i].log_num_entries;
30999517SBill.Taylor@Sun.COM inithca->context.srqc_baseaddr_h =
31009517SBill.Taylor@Sun.COM icm[i].icm_baseaddr >> 32;
31019517SBill.Taylor@Sun.COM inithca->context.srqc_baseaddr_l =
31029517SBill.Taylor@Sun.COM (icm[i].icm_baseaddr & 0xFFFFFFFF) >> 5;
31039517SBill.Taylor@Sun.COM break;
31049517SBill.Taylor@Sun.COM
31059517SBill.Taylor@Sun.COM case HERMON_EQC:
31069517SBill.Taylor@Sun.COM inithca->context.log_num_eq = icm[i].log_num_entries;
31079517SBill.Taylor@Sun.COM inithca->context.eqc_baseaddr_h =
31089517SBill.Taylor@Sun.COM icm[i].icm_baseaddr >> 32;
31099517SBill.Taylor@Sun.COM inithca->context.eqc_baseaddr_l =
31109517SBill.Taylor@Sun.COM (icm[i].icm_baseaddr & 0xFFFFFFFF) >> 5;
31119517SBill.Taylor@Sun.COM break;
31129517SBill.Taylor@Sun.COM
31139517SBill.Taylor@Sun.COM case HERMON_RDB:
31149517SBill.Taylor@Sun.COM inithca->context.rdmardc_baseaddr_h =
31159517SBill.Taylor@Sun.COM icm[i].icm_baseaddr >> 32;
31169517SBill.Taylor@Sun.COM inithca->context.rdmardc_baseaddr_l =
31179517SBill.Taylor@Sun.COM (icm[i].icm_baseaddr & 0xFFFFFFFF) >> 5;
31189517SBill.Taylor@Sun.COM inithca->context.log_num_rdmardc =
311911010SBill.Taylor@Sun.COM cfg->cp_log_num_rdb - cfg->cp_log_num_qp;
31209517SBill.Taylor@Sun.COM break;
31219517SBill.Taylor@Sun.COM
31229517SBill.Taylor@Sun.COM case HERMON_MCG:
31239517SBill.Taylor@Sun.COM inithca->multi.mc_baseaddr = icm[i].icm_baseaddr;
31249517SBill.Taylor@Sun.COM inithca->multi.log_mc_tbl_sz = icm[i].log_num_entries;
31259517SBill.Taylor@Sun.COM inithca->multi.log_mc_tbl_ent =
31269517SBill.Taylor@Sun.COM highbit(HERMON_MCGMEM_SZ(state)) - 1;
31279517SBill.Taylor@Sun.COM inithca->multi.log_mc_tbl_hash_sz =
31289517SBill.Taylor@Sun.COM cfg->cp_log_num_mcg_hash;
31299517SBill.Taylor@Sun.COM inithca->multi.mc_hash_fn = HERMON_MCG_DEFAULT_HASH_FN;
31309517SBill.Taylor@Sun.COM break;
31319517SBill.Taylor@Sun.COM
31329517SBill.Taylor@Sun.COM case HERMON_ALTC:
31339517SBill.Taylor@Sun.COM inithca->context.altc_baseaddr = icm[i].icm_baseaddr;
31349517SBill.Taylor@Sun.COM break;
31359517SBill.Taylor@Sun.COM
31369517SBill.Taylor@Sun.COM case HERMON_AUXC:
31379517SBill.Taylor@Sun.COM inithca->context.auxc_baseaddr = icm[i].icm_baseaddr;
31389517SBill.Taylor@Sun.COM break;
31399517SBill.Taylor@Sun.COM
31409517SBill.Taylor@Sun.COM default:
31419517SBill.Taylor@Sun.COM break;
31429517SBill.Taylor@Sun.COM
31439517SBill.Taylor@Sun.COM }
31449517SBill.Taylor@Sun.COM }
31459517SBill.Taylor@Sun.COM
31469517SBill.Taylor@Sun.COM }
31479517SBill.Taylor@Sun.COM
31489517SBill.Taylor@Sun.COM /*
31499517SBill.Taylor@Sun.COM * hermon_icm_tables_init()
31509517SBill.Taylor@Sun.COM * Context: Only called from attach() path context
31519517SBill.Taylor@Sun.COM *
31529517SBill.Taylor@Sun.COM * Dynamic ICM breaks the various ICM tables into "span_size" chunks
31539517SBill.Taylor@Sun.COM * to enable allocation of backing memory on demand. Arbel used a
31549517SBill.Taylor@Sun.COM * fixed size ARBEL_ICM_SPAN_SIZE (initially was 512KB) as the
31559517SBill.Taylor@Sun.COM * span_size for all ICM chunks. Hermon has other considerations,
31569517SBill.Taylor@Sun.COM * so the span_size used differs from Arbel.
31579517SBill.Taylor@Sun.COM *
31589517SBill.Taylor@Sun.COM * The basic considerations for why Hermon differs are:
31599517SBill.Taylor@Sun.COM *
31609517SBill.Taylor@Sun.COM * 1) ICM memory is in units of HERMON pages.
31619517SBill.Taylor@Sun.COM *
31629517SBill.Taylor@Sun.COM * 2) The AUXC table is approximately 1 byte per QP.
31639517SBill.Taylor@Sun.COM *
31649517SBill.Taylor@Sun.COM * 3) ICM memory for AUXC, ALTC, and RDB is allocated when
31659517SBill.Taylor@Sun.COM * the ICM memory for the corresponding QPC is allocated.
31669517SBill.Taylor@Sun.COM *
31679517SBill.Taylor@Sun.COM * 4) ICM memory for the CMPT corresponding to the various primary
31689517SBill.Taylor@Sun.COM * resources (QPC, SRQC, CQC, and EQC) is allocated when the ICM
31699517SBill.Taylor@Sun.COM * memory for the primary resource is allocated.
31709517SBill.Taylor@Sun.COM *
31719517SBill.Taylor@Sun.COM * One HERMON page (4KB) would typically map 4K QPs worth of AUXC.
31729517SBill.Taylor@Sun.COM * So, the minimum chunk for the various QPC related ICM memory should
31739517SBill.Taylor@Sun.COM * all be allocated to support the 4K QPs. Currently, this means the
31749517SBill.Taylor@Sun.COM * amount of memory for the various QP chunks is:
31759517SBill.Taylor@Sun.COM *
31769517SBill.Taylor@Sun.COM * QPC 256*4K bytes
31779517SBill.Taylor@Sun.COM * RDB 128*4K bytes
31789517SBill.Taylor@Sun.COM * CMPT 64*4K bytes
31799517SBill.Taylor@Sun.COM * ALTC 64*4K bytes
31809517SBill.Taylor@Sun.COM * AUXC 1*4K bytes
31819517SBill.Taylor@Sun.COM *
31829517SBill.Taylor@Sun.COM * The span_size chosen for the QP resource is 4KB of AUXC entries,
31839517SBill.Taylor@Sun.COM * or 1 HERMON_PAGESIZE worth, which is the minimum ICM mapping size.
31849517SBill.Taylor@Sun.COM *
31859517SBill.Taylor@Sun.COM * Other ICM resources can have their span_size be more arbitrary.
31869517SBill.Taylor@Sun.COM * This is 4K (HERMON_ICM_SPAN), except for MTTs because they are tiny.
31879517SBill.Taylor@Sun.COM */
31889517SBill.Taylor@Sun.COM
31899517SBill.Taylor@Sun.COM /* macro to make the code below cleaner */
31909517SBill.Taylor@Sun.COM #define init_dependent(rsrc, dep) \
31919517SBill.Taylor@Sun.COM icm[dep].span = icm[rsrc].span; \
31929517SBill.Taylor@Sun.COM icm[dep].num_spans = icm[rsrc].num_spans; \
31939517SBill.Taylor@Sun.COM icm[dep].split_shift = icm[rsrc].split_shift; \
31949517SBill.Taylor@Sun.COM icm[dep].span_mask = icm[rsrc].span_mask; \
31959517SBill.Taylor@Sun.COM icm[dep].span_shift = icm[rsrc].span_shift; \
31969517SBill.Taylor@Sun.COM icm[dep].rsrc_mask = icm[rsrc].rsrc_mask; \
31979517SBill.Taylor@Sun.COM if (hermon_verbose) { \
31989517SBill.Taylor@Sun.COM IBTF_DPRINTF_L2("hermon", "tables_init: " \
31999517SBill.Taylor@Sun.COM "rsrc (0x%x) size (0x%lx) span (0x%x) " \
32009517SBill.Taylor@Sun.COM "num_spans (0x%x)", dep, icm[dep].table_size, \
32019517SBill.Taylor@Sun.COM icm[dep].span, icm[dep].num_spans); \
32029517SBill.Taylor@Sun.COM IBTF_DPRINTF_L2("hermon", "tables_init: " \
32039517SBill.Taylor@Sun.COM "span_shift (0x%x) split_shift (0x%x)", \
32049517SBill.Taylor@Sun.COM icm[dep].span_shift, icm[dep].split_shift); \
32059517SBill.Taylor@Sun.COM IBTF_DPRINTF_L2("hermon", "tables_init: " \
32069517SBill.Taylor@Sun.COM "span_mask (0x%x) rsrc_mask (0x%x)", \
32079517SBill.Taylor@Sun.COM icm[dep].span_mask, icm[dep].rsrc_mask); \
32089517SBill.Taylor@Sun.COM }
32099517SBill.Taylor@Sun.COM
32109517SBill.Taylor@Sun.COM static void
hermon_icm_tables_init(hermon_state_t * state)32119517SBill.Taylor@Sun.COM hermon_icm_tables_init(hermon_state_t *state)
32129517SBill.Taylor@Sun.COM {
32139517SBill.Taylor@Sun.COM hermon_icm_table_t *icm;
32149517SBill.Taylor@Sun.COM int i, k;
32159517SBill.Taylor@Sun.COM uint32_t per_split;
32169517SBill.Taylor@Sun.COM
32179517SBill.Taylor@Sun.COM
32189517SBill.Taylor@Sun.COM icm = state->hs_icm;
32199517SBill.Taylor@Sun.COM
32209517SBill.Taylor@Sun.COM for (i = 0; i < HERMON_NUM_ICM_RESOURCES; i++) {
32219517SBill.Taylor@Sun.COM icm[i].icm_type = i;
32229517SBill.Taylor@Sun.COM icm[i].num_entries = 1 << icm[i].log_num_entries;
32239517SBill.Taylor@Sun.COM icm[i].log_object_size = highbit(icm[i].object_size) - 1;
32249517SBill.Taylor@Sun.COM icm[i].table_size = icm[i].num_entries <<
32259517SBill.Taylor@Sun.COM icm[i].log_object_size;
32269517SBill.Taylor@Sun.COM
32279517SBill.Taylor@Sun.COM /* deal with "dependent" resource types */
32289517SBill.Taylor@Sun.COM switch (i) {
32299517SBill.Taylor@Sun.COM case HERMON_AUXC:
32309517SBill.Taylor@Sun.COM #ifdef HERMON_FW_WORKAROUND
32319517SBill.Taylor@Sun.COM icm[i].table_size = 0x80000000ull;
32329517SBill.Taylor@Sun.COM /* FALLTHROUGH */
32339517SBill.Taylor@Sun.COM #endif
32349517SBill.Taylor@Sun.COM case HERMON_CMPT_QPC:
32359517SBill.Taylor@Sun.COM case HERMON_RDB:
32369517SBill.Taylor@Sun.COM case HERMON_ALTC:
32379517SBill.Taylor@Sun.COM init_dependent(HERMON_QPC, i);
32389517SBill.Taylor@Sun.COM continue;
32399517SBill.Taylor@Sun.COM case HERMON_CMPT_SRQC:
32409517SBill.Taylor@Sun.COM init_dependent(HERMON_SRQC, i);
32419517SBill.Taylor@Sun.COM continue;
32429517SBill.Taylor@Sun.COM case HERMON_CMPT_CQC:
32439517SBill.Taylor@Sun.COM init_dependent(HERMON_CQC, i);
32449517SBill.Taylor@Sun.COM continue;
32459517SBill.Taylor@Sun.COM case HERMON_CMPT_EQC:
32469517SBill.Taylor@Sun.COM init_dependent(HERMON_EQC, i);
32479517SBill.Taylor@Sun.COM continue;
32489517SBill.Taylor@Sun.COM }
32499517SBill.Taylor@Sun.COM
32509517SBill.Taylor@Sun.COM icm[i].span = HERMON_ICM_SPAN; /* default #rsrc's in 1 span */
32519517SBill.Taylor@Sun.COM if (i == HERMON_MTT) /* Alloc enough MTTs to map 256MB */
32529517SBill.Taylor@Sun.COM icm[i].span = HERMON_ICM_SPAN * 16;
32539517SBill.Taylor@Sun.COM icm[i].num_spans = icm[i].num_entries / icm[i].span;
32549517SBill.Taylor@Sun.COM if (icm[i].num_spans == 0) {
32559517SBill.Taylor@Sun.COM icm[i].span = icm[i].num_entries;
32569517SBill.Taylor@Sun.COM per_split = 1;
32579517SBill.Taylor@Sun.COM icm[i].num_spans = icm[i].num_entries / icm[i].span;
32589517SBill.Taylor@Sun.COM } else {
32599517SBill.Taylor@Sun.COM per_split = icm[i].num_spans / HERMON_ICM_SPLIT;
32609517SBill.Taylor@Sun.COM if (per_split == 0) {
32619517SBill.Taylor@Sun.COM per_split = 1;
32629517SBill.Taylor@Sun.COM }
32639517SBill.Taylor@Sun.COM }
32649517SBill.Taylor@Sun.COM if (hermon_verbose)
32659517SBill.Taylor@Sun.COM IBTF_DPRINTF_L2("ICM", "rsrc %x span %x num_spans %x",
32669517SBill.Taylor@Sun.COM i, icm[i].span, icm[i].num_spans);
32679517SBill.Taylor@Sun.COM
32689517SBill.Taylor@Sun.COM /*
32699517SBill.Taylor@Sun.COM * Ensure a minimum table size of an ICM page, and a
32709517SBill.Taylor@Sun.COM * maximum span size of the ICM table size. This ensures
32719517SBill.Taylor@Sun.COM * that we don't have less than an ICM page to map, which is
32729517SBill.Taylor@Sun.COM * impossible, and that we will map an entire table at
32739517SBill.Taylor@Sun.COM * once if it's total size is less than the span size.
32749517SBill.Taylor@Sun.COM */
32759517SBill.Taylor@Sun.COM icm[i].table_size = max(icm[i].table_size, HERMON_PAGESIZE);
32769517SBill.Taylor@Sun.COM
32779517SBill.Taylor@Sun.COM icm[i].span_shift = 0;
32789517SBill.Taylor@Sun.COM for (k = icm[i].span; k != 1; k >>= 1)
32799517SBill.Taylor@Sun.COM icm[i].span_shift++;
32809517SBill.Taylor@Sun.COM icm[i].split_shift = icm[i].span_shift;
32819517SBill.Taylor@Sun.COM for (k = per_split; k != 1; k >>= 1)
32829517SBill.Taylor@Sun.COM icm[i].split_shift++;
32839517SBill.Taylor@Sun.COM icm[i].span_mask = (1 << icm[i].split_shift) -
32849517SBill.Taylor@Sun.COM (1 << icm[i].span_shift);
32859517SBill.Taylor@Sun.COM icm[i].rsrc_mask = (1 << icm[i].span_shift) - 1;
32869517SBill.Taylor@Sun.COM
32879517SBill.Taylor@Sun.COM
32889517SBill.Taylor@Sun.COM /* Initialize the table lock */
32899517SBill.Taylor@Sun.COM mutex_init(&icm[i].icm_table_lock, NULL, MUTEX_DRIVER,
32909517SBill.Taylor@Sun.COM DDI_INTR_PRI(state->hs_intrmsi_pri));
32919517SBill.Taylor@Sun.COM cv_init(&icm[i].icm_table_cv, NULL, CV_DRIVER, NULL);
32929517SBill.Taylor@Sun.COM
32939517SBill.Taylor@Sun.COM if (hermon_verbose) {
32949517SBill.Taylor@Sun.COM IBTF_DPRINTF_L2("hermon", "tables_init: "
32959517SBill.Taylor@Sun.COM "rsrc (0x%x) size (0x%lx)", i, icm[i].table_size);
32969517SBill.Taylor@Sun.COM IBTF_DPRINTF_L2("hermon", "tables_init: "
32979517SBill.Taylor@Sun.COM "span (0x%x) num_spans (0x%x)",
32989517SBill.Taylor@Sun.COM icm[i].span, icm[i].num_spans);
32999517SBill.Taylor@Sun.COM IBTF_DPRINTF_L2("hermon", "tables_init: "
33009517SBill.Taylor@Sun.COM "span_shift (0x%x) split_shift (0x%x)",
33019517SBill.Taylor@Sun.COM icm[i].span_shift, icm[i].split_shift);
33029517SBill.Taylor@Sun.COM IBTF_DPRINTF_L2("hermon", "tables_init: "
33039517SBill.Taylor@Sun.COM "span_mask (0x%x) rsrc_mask (0x%x)",
33049517SBill.Taylor@Sun.COM icm[i].span_mask, icm[i].rsrc_mask);
33059517SBill.Taylor@Sun.COM }
33069517SBill.Taylor@Sun.COM }
33079517SBill.Taylor@Sun.COM
33089517SBill.Taylor@Sun.COM }
33099517SBill.Taylor@Sun.COM
33109517SBill.Taylor@Sun.COM /*
33119517SBill.Taylor@Sun.COM * hermon_icm_tables_fini()
33129517SBill.Taylor@Sun.COM * Context: Only called from attach() path context
33139517SBill.Taylor@Sun.COM *
33149517SBill.Taylor@Sun.COM * Clean up all icm_tables. Free the bitmap and dma_info arrays.
33159517SBill.Taylor@Sun.COM */
33169517SBill.Taylor@Sun.COM static void
hermon_icm_tables_fini(hermon_state_t * state)33179517SBill.Taylor@Sun.COM hermon_icm_tables_fini(hermon_state_t *state)
33189517SBill.Taylor@Sun.COM {
33199517SBill.Taylor@Sun.COM hermon_icm_table_t *icm;
33209517SBill.Taylor@Sun.COM int nspans;
33219517SBill.Taylor@Sun.COM int i, j;
33229517SBill.Taylor@Sun.COM
33239517SBill.Taylor@Sun.COM
33249517SBill.Taylor@Sun.COM icm = state->hs_icm;
33259517SBill.Taylor@Sun.COM
33269517SBill.Taylor@Sun.COM for (i = 0; i < HERMON_NUM_ICM_RESOURCES; i++) {
33279517SBill.Taylor@Sun.COM
33289517SBill.Taylor@Sun.COM mutex_enter(&icm[i].icm_table_lock);
33299517SBill.Taylor@Sun.COM nspans = icm[i].num_spans;
33309517SBill.Taylor@Sun.COM
33319517SBill.Taylor@Sun.COM for (j = 0; j < HERMON_ICM_SPLIT; j++) {
33329517SBill.Taylor@Sun.COM if (icm[i].icm_dma[j])
33339517SBill.Taylor@Sun.COM /* Free the ICM DMA slots */
33349517SBill.Taylor@Sun.COM kmem_free(icm[i].icm_dma[j],
33359517SBill.Taylor@Sun.COM nspans * sizeof (hermon_dma_info_t));
33369517SBill.Taylor@Sun.COM
33379517SBill.Taylor@Sun.COM if (icm[i].icm_bitmap[j])
33389517SBill.Taylor@Sun.COM /* Free the table bitmap */
33399517SBill.Taylor@Sun.COM kmem_free(icm[i].icm_bitmap[j],
33409517SBill.Taylor@Sun.COM (nspans + 7) / 8);
33419517SBill.Taylor@Sun.COM }
33429517SBill.Taylor@Sun.COM /* Destroy the table lock */
33439517SBill.Taylor@Sun.COM cv_destroy(&icm[i].icm_table_cv);
33449517SBill.Taylor@Sun.COM mutex_exit(&icm[i].icm_table_lock);
33459517SBill.Taylor@Sun.COM mutex_destroy(&icm[i].icm_table_lock);
33469517SBill.Taylor@Sun.COM }
33479517SBill.Taylor@Sun.COM
33489517SBill.Taylor@Sun.COM }
33499517SBill.Taylor@Sun.COM
33509517SBill.Taylor@Sun.COM /*
33519517SBill.Taylor@Sun.COM * hermon_icm_dma_init()
33529517SBill.Taylor@Sun.COM * Context: Only called from attach() path context
33539517SBill.Taylor@Sun.COM */
33549517SBill.Taylor@Sun.COM static int
hermon_icm_dma_init(hermon_state_t * state)33559517SBill.Taylor@Sun.COM hermon_icm_dma_init(hermon_state_t *state)
33569517SBill.Taylor@Sun.COM {
33579517SBill.Taylor@Sun.COM hermon_icm_table_t *icm;
33589517SBill.Taylor@Sun.COM hermon_rsrc_type_t type;
33599517SBill.Taylor@Sun.COM int status;
33609517SBill.Taylor@Sun.COM
33619517SBill.Taylor@Sun.COM
33629517SBill.Taylor@Sun.COM /*
33639517SBill.Taylor@Sun.COM * This routine will allocate initial ICM DMA resources for ICM
33649517SBill.Taylor@Sun.COM * tables that have reserved ICM objects. This is the only routine
33659517SBill.Taylor@Sun.COM * where we should have to allocate ICM outside of hermon_rsrc_alloc().
33669517SBill.Taylor@Sun.COM * We need to allocate ICM here explicitly, rather than in
33679517SBill.Taylor@Sun.COM * hermon_rsrc_alloc(), because we've not yet completed the resource
33689517SBill.Taylor@Sun.COM * pool initialization. When the resource pools are initialized
33699517SBill.Taylor@Sun.COM * (in hermon_rsrc_init_phase2(), see hermon_rsrc.c for more
33709517SBill.Taylor@Sun.COM * information), resource preallocations will be invoked to match
33719517SBill.Taylor@Sun.COM * the ICM allocations seen here. We will then be able to use the
33729517SBill.Taylor@Sun.COM * normal allocation path. Note we don't need to set a refcnt on
33739517SBill.Taylor@Sun.COM * these initial allocations because that will be done in the calls
33749517SBill.Taylor@Sun.COM * to hermon_rsrc_alloc() from hermon_hw_entries_init() for the
33759517SBill.Taylor@Sun.COM * "prealloc" objects (see hermon_rsrc.c for more information).
33769517SBill.Taylor@Sun.COM */
33779517SBill.Taylor@Sun.COM for (type = 0; type < HERMON_NUM_ICM_RESOURCES; type++) {
33789517SBill.Taylor@Sun.COM
33799517SBill.Taylor@Sun.COM /* ICM for these is allocated within hermon_icm_alloc() */
33809517SBill.Taylor@Sun.COM switch (type) {
33819517SBill.Taylor@Sun.COM case HERMON_CMPT:
33829517SBill.Taylor@Sun.COM case HERMON_CMPT_QPC:
33839517SBill.Taylor@Sun.COM case HERMON_CMPT_SRQC:
33849517SBill.Taylor@Sun.COM case HERMON_CMPT_CQC:
33859517SBill.Taylor@Sun.COM case HERMON_CMPT_EQC:
33869517SBill.Taylor@Sun.COM case HERMON_AUXC:
33879517SBill.Taylor@Sun.COM case HERMON_ALTC:
33889517SBill.Taylor@Sun.COM case HERMON_RDB:
33899517SBill.Taylor@Sun.COM continue;
33909517SBill.Taylor@Sun.COM }
33919517SBill.Taylor@Sun.COM
33929517SBill.Taylor@Sun.COM icm = &state->hs_icm[type];
33939517SBill.Taylor@Sun.COM
33949517SBill.Taylor@Sun.COM mutex_enter(&icm->icm_table_lock);
33959517SBill.Taylor@Sun.COM status = hermon_icm_alloc(state, type, 0, 0);
33969517SBill.Taylor@Sun.COM mutex_exit(&icm->icm_table_lock);
33979517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
33989517SBill.Taylor@Sun.COM while (type--) {
33999517SBill.Taylor@Sun.COM icm = &state->hs_icm[type];
34009517SBill.Taylor@Sun.COM mutex_enter(&icm->icm_table_lock);
34019517SBill.Taylor@Sun.COM hermon_icm_free(state, type, 0, 0);
34029517SBill.Taylor@Sun.COM mutex_exit(&icm->icm_table_lock);
34039517SBill.Taylor@Sun.COM }
34049517SBill.Taylor@Sun.COM return (DDI_FAILURE);
34059517SBill.Taylor@Sun.COM }
34069517SBill.Taylor@Sun.COM
34079517SBill.Taylor@Sun.COM if (hermon_verbose) {
34089517SBill.Taylor@Sun.COM IBTF_DPRINTF_L2("hermon", "hermon_icm_dma_init: "
34099517SBill.Taylor@Sun.COM "table (0x%x) index (0x%x) allocated", type, 0);
34109517SBill.Taylor@Sun.COM }
34119517SBill.Taylor@Sun.COM }
34129517SBill.Taylor@Sun.COM
34139517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
34149517SBill.Taylor@Sun.COM }
34159517SBill.Taylor@Sun.COM
34169517SBill.Taylor@Sun.COM /*
34179517SBill.Taylor@Sun.COM * hermon_icm_dma_fini()
34189517SBill.Taylor@Sun.COM * Context: Only called from attach() path context
34199517SBill.Taylor@Sun.COM *
34209517SBill.Taylor@Sun.COM * ICM has been completely unmapped. We just free the memory here.
34219517SBill.Taylor@Sun.COM */
34229517SBill.Taylor@Sun.COM static void
hermon_icm_dma_fini(hermon_state_t * state)34239517SBill.Taylor@Sun.COM hermon_icm_dma_fini(hermon_state_t *state)
34249517SBill.Taylor@Sun.COM {
34259517SBill.Taylor@Sun.COM hermon_icm_table_t *icm;
34269517SBill.Taylor@Sun.COM hermon_dma_info_t *dma_info;
34279517SBill.Taylor@Sun.COM hermon_rsrc_type_t type;
34289517SBill.Taylor@Sun.COM int index1, index2;
34299517SBill.Taylor@Sun.COM
34309517SBill.Taylor@Sun.COM
34319517SBill.Taylor@Sun.COM for (type = 0; type < HERMON_NUM_ICM_RESOURCES; type++) {
34329517SBill.Taylor@Sun.COM icm = &state->hs_icm[type];
34339517SBill.Taylor@Sun.COM for (index1 = 0; index1 < HERMON_ICM_SPLIT; index1++) {
34349517SBill.Taylor@Sun.COM dma_info = icm->icm_dma[index1];
34359517SBill.Taylor@Sun.COM if (dma_info == NULL)
34369517SBill.Taylor@Sun.COM continue;
34379517SBill.Taylor@Sun.COM for (index2 = 0; index2 < icm->num_spans; index2++) {
34389517SBill.Taylor@Sun.COM if (dma_info[index2].dma_hdl)
34399517SBill.Taylor@Sun.COM hermon_dma_free(&dma_info[index2]);
34409517SBill.Taylor@Sun.COM dma_info[index2].dma_hdl = NULL;
34419517SBill.Taylor@Sun.COM }
34429517SBill.Taylor@Sun.COM }
34439517SBill.Taylor@Sun.COM }
34449517SBill.Taylor@Sun.COM
34459517SBill.Taylor@Sun.COM }
34469517SBill.Taylor@Sun.COM
34479517SBill.Taylor@Sun.COM /*
34489517SBill.Taylor@Sun.COM * hermon_hca_port_init()
34499517SBill.Taylor@Sun.COM * Context: Only called from attach() path context
34509517SBill.Taylor@Sun.COM */
34519517SBill.Taylor@Sun.COM static int
hermon_hca_port_init(hermon_state_t * state)34529517SBill.Taylor@Sun.COM hermon_hca_port_init(hermon_state_t *state)
34539517SBill.Taylor@Sun.COM {
34549517SBill.Taylor@Sun.COM hermon_hw_set_port_t *portinits, *initport;
34559517SBill.Taylor@Sun.COM hermon_cfg_profile_t *cfgprof;
34569517SBill.Taylor@Sun.COM uint_t num_ports;
34579517SBill.Taylor@Sun.COM int i = 0, status;
34589517SBill.Taylor@Sun.COM uint64_t maxval, val;
34599517SBill.Taylor@Sun.COM uint64_t sysimgguid, nodeguid, portguid;
34609517SBill.Taylor@Sun.COM
34619517SBill.Taylor@Sun.COM
34629517SBill.Taylor@Sun.COM cfgprof = state->hs_cfg_profile;
34639517SBill.Taylor@Sun.COM
34649517SBill.Taylor@Sun.COM /* Get number of HCA ports */
34659517SBill.Taylor@Sun.COM num_ports = cfgprof->cp_num_ports;
34669517SBill.Taylor@Sun.COM
34679517SBill.Taylor@Sun.COM /* Allocate space for Hermon set port struct(s) */
34689517SBill.Taylor@Sun.COM portinits = (hermon_hw_set_port_t *)kmem_zalloc(num_ports *
34699517SBill.Taylor@Sun.COM sizeof (hermon_hw_set_port_t), KM_SLEEP);
34709517SBill.Taylor@Sun.COM
34719517SBill.Taylor@Sun.COM
34729517SBill.Taylor@Sun.COM
34739517SBill.Taylor@Sun.COM /* Post commands to initialize each Hermon HCA port */
34749517SBill.Taylor@Sun.COM /*
34759517SBill.Taylor@Sun.COM * In Hermon, the process is different than in previous HCAs.
34769517SBill.Taylor@Sun.COM * Here, you have to:
34779517SBill.Taylor@Sun.COM * QUERY_PORT - to get basic information from the HCA
34789517SBill.Taylor@Sun.COM * set the fields accordingly
34799517SBill.Taylor@Sun.COM * SET_PORT - to change/set everything as desired
34809517SBill.Taylor@Sun.COM * INIT_PORT - to bring the port up
34819517SBill.Taylor@Sun.COM *
34829517SBill.Taylor@Sun.COM * Needs to be done for each port in turn
34839517SBill.Taylor@Sun.COM */
34849517SBill.Taylor@Sun.COM
34859517SBill.Taylor@Sun.COM for (i = 0; i < num_ports; i++) {
34869517SBill.Taylor@Sun.COM bzero(&state->hs_queryport, sizeof (hermon_hw_query_port_t));
34879517SBill.Taylor@Sun.COM status = hermon_cmn_query_cmd_post(state, QUERY_PORT, 0,
34889517SBill.Taylor@Sun.COM (i + 1), &state->hs_queryport,
34899517SBill.Taylor@Sun.COM sizeof (hermon_hw_query_port_t), HERMON_CMD_NOSLEEP_SPIN);
34909517SBill.Taylor@Sun.COM if (status != HERMON_CMD_SUCCESS) {
34919517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "Hermon: QUERY_PORT (port %02d) "
34929517SBill.Taylor@Sun.COM "command failed: %08x\n", i + 1, status);
34939517SBill.Taylor@Sun.COM goto init_ports_fail;
34949517SBill.Taylor@Sun.COM }
34959517SBill.Taylor@Sun.COM initport = &portinits[i];
34969517SBill.Taylor@Sun.COM state->hs_initport = &portinits[i];
34979517SBill.Taylor@Sun.COM
34989517SBill.Taylor@Sun.COM bzero(initport, sizeof (hermon_hw_query_port_t));
34999517SBill.Taylor@Sun.COM
35009517SBill.Taylor@Sun.COM /*
35019517SBill.Taylor@Sun.COM * Determine whether we need to override the firmware's
35029517SBill.Taylor@Sun.COM * default SystemImageGUID setting.
35039517SBill.Taylor@Sun.COM */
35049517SBill.Taylor@Sun.COM sysimgguid = cfgprof->cp_sysimgguid;
35059517SBill.Taylor@Sun.COM if (sysimgguid != 0) {
35069517SBill.Taylor@Sun.COM initport->sig = 1;
35079517SBill.Taylor@Sun.COM initport->sys_img_guid = sysimgguid;
35089517SBill.Taylor@Sun.COM }
35099517SBill.Taylor@Sun.COM
35109517SBill.Taylor@Sun.COM /*
35119517SBill.Taylor@Sun.COM * Determine whether we need to override the firmware's
35129517SBill.Taylor@Sun.COM * default NodeGUID setting.
35139517SBill.Taylor@Sun.COM */
35149517SBill.Taylor@Sun.COM nodeguid = cfgprof->cp_nodeguid;
35159517SBill.Taylor@Sun.COM if (nodeguid != 0) {
35169517SBill.Taylor@Sun.COM initport->ng = 1;
35179517SBill.Taylor@Sun.COM initport->node_guid = nodeguid;
35189517SBill.Taylor@Sun.COM }
35199517SBill.Taylor@Sun.COM
35209517SBill.Taylor@Sun.COM /*
35219517SBill.Taylor@Sun.COM * Determine whether we need to override the firmware's
35229517SBill.Taylor@Sun.COM * default PortGUID setting.
35239517SBill.Taylor@Sun.COM */
35249517SBill.Taylor@Sun.COM portguid = cfgprof->cp_portguid[i];
35259517SBill.Taylor@Sun.COM if (portguid != 0) {
35269517SBill.Taylor@Sun.COM initport->g0 = 1;
35279517SBill.Taylor@Sun.COM initport->guid0 = portguid;
35289517SBill.Taylor@Sun.COM }
35299517SBill.Taylor@Sun.COM
35309517SBill.Taylor@Sun.COM /* Validate max MTU size */
35319517SBill.Taylor@Sun.COM maxval = state->hs_queryport.ib_mtu;
35329517SBill.Taylor@Sun.COM val = cfgprof->cp_max_mtu;
35339517SBill.Taylor@Sun.COM if (val > maxval) {
35349517SBill.Taylor@Sun.COM goto init_ports_fail;
35359517SBill.Taylor@Sun.COM }
35369517SBill.Taylor@Sun.COM
353710852SBill.Taylor@Sun.COM /* Set mtu_cap to 4096 bytes */
353810852SBill.Taylor@Sun.COM initport->mmc = 1; /* set the change bit */
353910852SBill.Taylor@Sun.COM initport->mtu_cap = 5; /* for 4096 bytes */
354010852SBill.Taylor@Sun.COM
35419517SBill.Taylor@Sun.COM /* Validate the max port width */
35429517SBill.Taylor@Sun.COM maxval = state->hs_queryport.ib_port_wid;
35439517SBill.Taylor@Sun.COM val = cfgprof->cp_max_port_width;
35449517SBill.Taylor@Sun.COM if (val > maxval) {
35459517SBill.Taylor@Sun.COM goto init_ports_fail;
35469517SBill.Taylor@Sun.COM }
35479517SBill.Taylor@Sun.COM
35489517SBill.Taylor@Sun.COM /* Validate max VL cap size */
35499517SBill.Taylor@Sun.COM maxval = state->hs_queryport.max_vl;
35509517SBill.Taylor@Sun.COM val = cfgprof->cp_max_vlcap;
35519517SBill.Taylor@Sun.COM if (val > maxval) {
35529517SBill.Taylor@Sun.COM goto init_ports_fail;
35539517SBill.Taylor@Sun.COM }
35549517SBill.Taylor@Sun.COM
355510852SBill.Taylor@Sun.COM /* Since we're doing mtu_cap, cut vl_cap down */
355610852SBill.Taylor@Sun.COM initport->mvc = 1; /* set this change bit */
355710852SBill.Taylor@Sun.COM initport->vl_cap = 3; /* 3 means vl0-vl3, 4 total */
355810852SBill.Taylor@Sun.COM
35599517SBill.Taylor@Sun.COM /* Validate max GID table size */
35609517SBill.Taylor@Sun.COM maxval = ((uint64_t)1 << state->hs_queryport.log_max_gid);
35619517SBill.Taylor@Sun.COM val = ((uint64_t)1 << cfgprof->cp_log_max_gidtbl);
35629517SBill.Taylor@Sun.COM if (val > maxval) {
35639517SBill.Taylor@Sun.COM goto init_ports_fail;
35649517SBill.Taylor@Sun.COM }
356512965SWilliam.Taylor@Oracle.COM initport->max_gid = (uint16_t)val;
35669517SBill.Taylor@Sun.COM initport->mg = 1;
35679517SBill.Taylor@Sun.COM
35689517SBill.Taylor@Sun.COM /* Validate max PKey table size */
35699517SBill.Taylor@Sun.COM maxval = ((uint64_t)1 << state->hs_queryport.log_max_pkey);
35709517SBill.Taylor@Sun.COM val = ((uint64_t)1 << cfgprof->cp_log_max_pkeytbl);
35719517SBill.Taylor@Sun.COM if (val > maxval) {
35729517SBill.Taylor@Sun.COM goto init_ports_fail;
35739517SBill.Taylor@Sun.COM }
35749517SBill.Taylor@Sun.COM initport->max_pkey = (uint16_t)val;
35759517SBill.Taylor@Sun.COM initport->mp = 1;
35769517SBill.Taylor@Sun.COM /*
35779517SBill.Taylor@Sun.COM * Post the SET_PORT cmd to Hermon firmware. This sets
35789517SBill.Taylor@Sun.COM * the parameters of the port.
35799517SBill.Taylor@Sun.COM */
35809517SBill.Taylor@Sun.COM status = hermon_set_port_cmd_post(state, initport, i + 1,
35819517SBill.Taylor@Sun.COM HERMON_CMD_NOSLEEP_SPIN);
35829517SBill.Taylor@Sun.COM if (status != HERMON_CMD_SUCCESS) {
35839517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "Hermon: SET_PORT (port %02d) command "
35849517SBill.Taylor@Sun.COM "failed: %08x\n", i + 1, status);
35859517SBill.Taylor@Sun.COM goto init_ports_fail;
35869517SBill.Taylor@Sun.COM }
35879517SBill.Taylor@Sun.COM /* issue another SET_PORT cmd - performance fix/workaround */
35889517SBill.Taylor@Sun.COM /* XXX - need to discuss with Mellanox */
35899517SBill.Taylor@Sun.COM bzero(initport, sizeof (hermon_hw_query_port_t));
35909517SBill.Taylor@Sun.COM initport->cap_mask = 0x02500868;
35919517SBill.Taylor@Sun.COM status = hermon_set_port_cmd_post(state, initport, i + 1,
35929517SBill.Taylor@Sun.COM HERMON_CMD_NOSLEEP_SPIN);
35939517SBill.Taylor@Sun.COM if (status != HERMON_CMD_SUCCESS) {
35949517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "Hermon: SET_PORT (port %02d) command "
35959517SBill.Taylor@Sun.COM "failed: %08x\n", i + 1, status);
35969517SBill.Taylor@Sun.COM goto init_ports_fail;
35979517SBill.Taylor@Sun.COM }
35989517SBill.Taylor@Sun.COM }
35999517SBill.Taylor@Sun.COM
36009517SBill.Taylor@Sun.COM /*
36019517SBill.Taylor@Sun.COM * Finally, do the INIT_PORT for each port in turn
36029517SBill.Taylor@Sun.COM * When this command completes, the corresponding Hermon port
36039517SBill.Taylor@Sun.COM * will be physically "Up" and initialized.
36049517SBill.Taylor@Sun.COM */
36059517SBill.Taylor@Sun.COM for (i = 0; i < num_ports; i++) {
36069517SBill.Taylor@Sun.COM status = hermon_init_port_cmd_post(state, i + 1,
36079517SBill.Taylor@Sun.COM HERMON_CMD_NOSLEEP_SPIN);
36089517SBill.Taylor@Sun.COM if (status != HERMON_CMD_SUCCESS) {
36099517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "Hermon: INIT_PORT (port %02d) "
36109517SBill.Taylor@Sun.COM "comman failed: %08x\n", i + 1, status);
36119517SBill.Taylor@Sun.COM goto init_ports_fail;
36129517SBill.Taylor@Sun.COM }
36139517SBill.Taylor@Sun.COM }
36149517SBill.Taylor@Sun.COM
36159517SBill.Taylor@Sun.COM /* Free up the memory for Hermon port init struct(s), return success */
36169517SBill.Taylor@Sun.COM kmem_free(portinits, num_ports * sizeof (hermon_hw_set_port_t));
36179517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
36189517SBill.Taylor@Sun.COM
36199517SBill.Taylor@Sun.COM init_ports_fail:
36209517SBill.Taylor@Sun.COM /*
36219517SBill.Taylor@Sun.COM * Free up the memory for Hermon port init struct(s), shutdown any
36229517SBill.Taylor@Sun.COM * successfully initialized ports, and return failure
36239517SBill.Taylor@Sun.COM */
36249517SBill.Taylor@Sun.COM kmem_free(portinits, num_ports * sizeof (hermon_hw_set_port_t));
36259517SBill.Taylor@Sun.COM (void) hermon_hca_ports_shutdown(state, i);
36269517SBill.Taylor@Sun.COM
36279517SBill.Taylor@Sun.COM return (DDI_FAILURE);
36289517SBill.Taylor@Sun.COM }
36299517SBill.Taylor@Sun.COM
36309517SBill.Taylor@Sun.COM
36319517SBill.Taylor@Sun.COM /*
36329517SBill.Taylor@Sun.COM * hermon_hca_ports_shutdown()
36339517SBill.Taylor@Sun.COM * Context: Only called from attach() and/or detach() path contexts
36349517SBill.Taylor@Sun.COM */
36359517SBill.Taylor@Sun.COM static int
hermon_hca_ports_shutdown(hermon_state_t * state,uint_t num_init)36369517SBill.Taylor@Sun.COM hermon_hca_ports_shutdown(hermon_state_t *state, uint_t num_init)
36379517SBill.Taylor@Sun.COM {
36389517SBill.Taylor@Sun.COM int i, status;
36399517SBill.Taylor@Sun.COM
36409517SBill.Taylor@Sun.COM /*
36419517SBill.Taylor@Sun.COM * Post commands to shutdown all init'd Hermon HCA ports. Note: if
36429517SBill.Taylor@Sun.COM * any of these commands fail for any reason, it would be entirely
36439517SBill.Taylor@Sun.COM * unexpected and probably indicative a serious problem (HW or SW).
36449517SBill.Taylor@Sun.COM * Although we do return void from this function, this type of failure
36459517SBill.Taylor@Sun.COM * should not go unreported. That is why we have the warning message.
36469517SBill.Taylor@Sun.COM */
36479517SBill.Taylor@Sun.COM for (i = 0; i < num_init; i++) {
36489517SBill.Taylor@Sun.COM status = hermon_close_port_cmd_post(state, i + 1,
36499517SBill.Taylor@Sun.COM HERMON_CMD_NOSLEEP_SPIN);
36509517SBill.Taylor@Sun.COM if (status != HERMON_CMD_SUCCESS) {
36519517SBill.Taylor@Sun.COM HERMON_WARNING(state, "failed to shutdown HCA port");
36529517SBill.Taylor@Sun.COM return (status);
36539517SBill.Taylor@Sun.COM }
36549517SBill.Taylor@Sun.COM }
36559517SBill.Taylor@Sun.COM return (HERMON_CMD_SUCCESS);
36569517SBill.Taylor@Sun.COM }
36579517SBill.Taylor@Sun.COM
36589517SBill.Taylor@Sun.COM
36599517SBill.Taylor@Sun.COM /*
36609517SBill.Taylor@Sun.COM * hermon_internal_uarpg_init
36619517SBill.Taylor@Sun.COM * Context: Only called from attach() path context
36629517SBill.Taylor@Sun.COM */
36639517SBill.Taylor@Sun.COM static int
hermon_internal_uarpg_init(hermon_state_t * state)36649517SBill.Taylor@Sun.COM hermon_internal_uarpg_init(hermon_state_t *state)
36659517SBill.Taylor@Sun.COM {
36669517SBill.Taylor@Sun.COM int status;
36679517SBill.Taylor@Sun.COM hermon_dbr_info_t *info;
36689517SBill.Taylor@Sun.COM
36699517SBill.Taylor@Sun.COM /*
36709517SBill.Taylor@Sun.COM * Allocate the UAR page for kernel use. This UAR page is
36719517SBill.Taylor@Sun.COM * the privileged UAR page through which all kernel generated
36729517SBill.Taylor@Sun.COM * doorbells will be rung. There are a number of UAR pages
36739517SBill.Taylor@Sun.COM * reserved by hardware at the front of the UAR BAR, indicated
36749517SBill.Taylor@Sun.COM * by DEVCAP.num_rsvd_uar, which we have already allocated. So,
36759517SBill.Taylor@Sun.COM * the kernel page, or UAR page index num_rsvd_uar, will be
36769517SBill.Taylor@Sun.COM * allocated here for kernel use.
36779517SBill.Taylor@Sun.COM */
36789517SBill.Taylor@Sun.COM
36799517SBill.Taylor@Sun.COM status = hermon_rsrc_alloc(state, HERMON_UARPG, 1, HERMON_SLEEP,
36809517SBill.Taylor@Sun.COM &state->hs_uarkpg_rsrc);
36819517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
36829517SBill.Taylor@Sun.COM return (DDI_FAILURE);
36839517SBill.Taylor@Sun.COM }
36849517SBill.Taylor@Sun.COM
36859517SBill.Taylor@Sun.COM /* Setup pointer to kernel UAR page */
36869517SBill.Taylor@Sun.COM state->hs_uar = (hermon_hw_uar_t *)state->hs_uarkpg_rsrc->hr_addr;
36879517SBill.Taylor@Sun.COM
36889517SBill.Taylor@Sun.COM /* need to set up DBr tracking as well */
36899517SBill.Taylor@Sun.COM status = hermon_dbr_page_alloc(state, &info);
36909517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
36919517SBill.Taylor@Sun.COM return (DDI_FAILURE);
36929517SBill.Taylor@Sun.COM }
369310027SGiri.Adari@Sun.COM state->hs_kern_dbr = info;
36949517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
36959517SBill.Taylor@Sun.COM }
36969517SBill.Taylor@Sun.COM
36979517SBill.Taylor@Sun.COM
36989517SBill.Taylor@Sun.COM /*
36999517SBill.Taylor@Sun.COM * hermon_internal_uarpg_fini
37009517SBill.Taylor@Sun.COM * Context: Only called from attach() and/or detach() path contexts
37019517SBill.Taylor@Sun.COM */
37029517SBill.Taylor@Sun.COM static void
hermon_internal_uarpg_fini(hermon_state_t * state)37039517SBill.Taylor@Sun.COM hermon_internal_uarpg_fini(hermon_state_t *state)
37049517SBill.Taylor@Sun.COM {
37059517SBill.Taylor@Sun.COM /* Free up Hermon UAR page #1 (kernel driver doorbells) */
37069517SBill.Taylor@Sun.COM hermon_rsrc_free(state, &state->hs_uarkpg_rsrc);
37079517SBill.Taylor@Sun.COM }
37089517SBill.Taylor@Sun.COM
37099517SBill.Taylor@Sun.COM
37109517SBill.Taylor@Sun.COM /*
37119517SBill.Taylor@Sun.COM * hermon_special_qp_contexts_reserve()
37129517SBill.Taylor@Sun.COM * Context: Only called from attach() path context
37139517SBill.Taylor@Sun.COM */
37149517SBill.Taylor@Sun.COM static int
hermon_special_qp_contexts_reserve(hermon_state_t * state)37159517SBill.Taylor@Sun.COM hermon_special_qp_contexts_reserve(hermon_state_t *state)
37169517SBill.Taylor@Sun.COM {
37179517SBill.Taylor@Sun.COM hermon_rsrc_t *qp0_rsrc, *qp1_rsrc, *qp_resvd;
37189517SBill.Taylor@Sun.COM int status;
37199517SBill.Taylor@Sun.COM
37209517SBill.Taylor@Sun.COM /* Initialize the lock used for special QP rsrc management */
37219517SBill.Taylor@Sun.COM mutex_init(&state->hs_spec_qplock, NULL, MUTEX_DRIVER,
37229517SBill.Taylor@Sun.COM DDI_INTR_PRI(state->hs_intrmsi_pri));
37239517SBill.Taylor@Sun.COM
37249517SBill.Taylor@Sun.COM /*
37259517SBill.Taylor@Sun.COM * Reserve contexts for QP0. These QP contexts will be setup to
37269517SBill.Taylor@Sun.COM * act as aliases for the real QP0. Note: We are required to grab
37279517SBill.Taylor@Sun.COM * two QPs (one per port) even if we are operating in single-port
37289517SBill.Taylor@Sun.COM * mode.
37299517SBill.Taylor@Sun.COM */
37309517SBill.Taylor@Sun.COM status = hermon_rsrc_alloc(state, HERMON_QPC, 2,
37319517SBill.Taylor@Sun.COM HERMON_SLEEP, &qp0_rsrc);
37329517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
37339517SBill.Taylor@Sun.COM mutex_destroy(&state->hs_spec_qplock);
37349517SBill.Taylor@Sun.COM return (DDI_FAILURE);
37359517SBill.Taylor@Sun.COM }
37369517SBill.Taylor@Sun.COM state->hs_spec_qp0 = qp0_rsrc;
37379517SBill.Taylor@Sun.COM
37389517SBill.Taylor@Sun.COM /*
37399517SBill.Taylor@Sun.COM * Reserve contexts for QP1. These QP contexts will be setup to
37409517SBill.Taylor@Sun.COM * act as aliases for the real QP1. Note: We are required to grab
37419517SBill.Taylor@Sun.COM * two QPs (one per port) even if we are operating in single-port
37429517SBill.Taylor@Sun.COM * mode.
37439517SBill.Taylor@Sun.COM */
37449517SBill.Taylor@Sun.COM status = hermon_rsrc_alloc(state, HERMON_QPC, 2,
37459517SBill.Taylor@Sun.COM HERMON_SLEEP, &qp1_rsrc);
37469517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
37479517SBill.Taylor@Sun.COM hermon_rsrc_free(state, &qp0_rsrc);
37489517SBill.Taylor@Sun.COM mutex_destroy(&state->hs_spec_qplock);
37499517SBill.Taylor@Sun.COM return (DDI_FAILURE);
37509517SBill.Taylor@Sun.COM }
37519517SBill.Taylor@Sun.COM state->hs_spec_qp1 = qp1_rsrc;
37529517SBill.Taylor@Sun.COM
37539517SBill.Taylor@Sun.COM status = hermon_rsrc_alloc(state, HERMON_QPC, 4,
37549517SBill.Taylor@Sun.COM HERMON_SLEEP, &qp_resvd);
37559517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
37569517SBill.Taylor@Sun.COM hermon_rsrc_free(state, &qp1_rsrc);
37579517SBill.Taylor@Sun.COM hermon_rsrc_free(state, &qp0_rsrc);
37589517SBill.Taylor@Sun.COM mutex_destroy(&state->hs_spec_qplock);
37599517SBill.Taylor@Sun.COM return (DDI_FAILURE);
37609517SBill.Taylor@Sun.COM }
37619517SBill.Taylor@Sun.COM state->hs_spec_qp_unused = qp_resvd;
37629517SBill.Taylor@Sun.COM
37639517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
37649517SBill.Taylor@Sun.COM }
37659517SBill.Taylor@Sun.COM
37669517SBill.Taylor@Sun.COM
37679517SBill.Taylor@Sun.COM /*
37689517SBill.Taylor@Sun.COM * hermon_special_qp_contexts_unreserve()
37699517SBill.Taylor@Sun.COM * Context: Only called from attach() and/or detach() path contexts
37709517SBill.Taylor@Sun.COM */
37719517SBill.Taylor@Sun.COM static void
hermon_special_qp_contexts_unreserve(hermon_state_t * state)37729517SBill.Taylor@Sun.COM hermon_special_qp_contexts_unreserve(hermon_state_t *state)
37739517SBill.Taylor@Sun.COM {
37749517SBill.Taylor@Sun.COM
37759517SBill.Taylor@Sun.COM /* Unreserve contexts for spec_qp_unused */
37769517SBill.Taylor@Sun.COM hermon_rsrc_free(state, &state->hs_spec_qp_unused);
37779517SBill.Taylor@Sun.COM
37789517SBill.Taylor@Sun.COM /* Unreserve contexts for QP1 */
37799517SBill.Taylor@Sun.COM hermon_rsrc_free(state, &state->hs_spec_qp1);
37809517SBill.Taylor@Sun.COM
37819517SBill.Taylor@Sun.COM /* Unreserve contexts for QP0 */
37829517SBill.Taylor@Sun.COM hermon_rsrc_free(state, &state->hs_spec_qp0);
37839517SBill.Taylor@Sun.COM
37849517SBill.Taylor@Sun.COM /* Destroy the lock used for special QP rsrc management */
37859517SBill.Taylor@Sun.COM mutex_destroy(&state->hs_spec_qplock);
37869517SBill.Taylor@Sun.COM
37879517SBill.Taylor@Sun.COM }
37889517SBill.Taylor@Sun.COM
37899517SBill.Taylor@Sun.COM
37909517SBill.Taylor@Sun.COM /*
37919517SBill.Taylor@Sun.COM * hermon_sw_reset()
37929517SBill.Taylor@Sun.COM * Context: Currently called only from attach() path context
37939517SBill.Taylor@Sun.COM */
37949517SBill.Taylor@Sun.COM static int
hermon_sw_reset(hermon_state_t * state)37959517SBill.Taylor@Sun.COM hermon_sw_reset(hermon_state_t *state)
37969517SBill.Taylor@Sun.COM {
37979517SBill.Taylor@Sun.COM ddi_acc_handle_t hdl = hermon_get_pcihdl(state);
37989517SBill.Taylor@Sun.COM ddi_acc_handle_t cmdhdl = hermon_get_cmdhdl(state);
37999517SBill.Taylor@Sun.COM uint32_t reset_delay;
38009517SBill.Taylor@Sun.COM int status, i;
38019517SBill.Taylor@Sun.COM uint32_t sem;
38029517SBill.Taylor@Sun.COM uint_t offset;
38039517SBill.Taylor@Sun.COM uint32_t data32; /* for devctl & linkctl */
38049517SBill.Taylor@Sun.COM int loopcnt;
38059517SBill.Taylor@Sun.COM
38069517SBill.Taylor@Sun.COM /* initialize the FMA retry loop */
38079517SBill.Taylor@Sun.COM hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
38089517SBill.Taylor@Sun.COM hermon_pio_init(fm_loop_cnt2, fm_status2, fm_test2);
38099517SBill.Taylor@Sun.COM
38109517SBill.Taylor@Sun.COM /*
38119517SBill.Taylor@Sun.COM * If the configured software reset delay is set to zero, then we
38129517SBill.Taylor@Sun.COM * will not attempt a software reset of the Hermon device.
38139517SBill.Taylor@Sun.COM */
38149517SBill.Taylor@Sun.COM reset_delay = state->hs_cfg_profile->cp_sw_reset_delay;
38159517SBill.Taylor@Sun.COM if (reset_delay == 0) {
38169517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
38179517SBill.Taylor@Sun.COM }
38189517SBill.Taylor@Sun.COM
38199517SBill.Taylor@Sun.COM /* the FMA retry loop starts. */
38209517SBill.Taylor@Sun.COM hermon_pio_start(state, cmdhdl, pio_error, fm_loop_cnt, fm_status,
38219517SBill.Taylor@Sun.COM fm_test);
38229517SBill.Taylor@Sun.COM hermon_pio_start(state, hdl, pio_error2, fm_loop_cnt2, fm_status2,
38239517SBill.Taylor@Sun.COM fm_test2);
38249517SBill.Taylor@Sun.COM
38259517SBill.Taylor@Sun.COM /* Query the PCI capabilities of the HCA device */
38269517SBill.Taylor@Sun.COM /* but don't process the VPD until after reset */
38279517SBill.Taylor@Sun.COM status = hermon_pci_capability_list(state, hdl);
38289517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
38299517SBill.Taylor@Sun.COM cmn_err(CE_NOTE, "failed to get pci capabilities list(0x%x)\n",
38309517SBill.Taylor@Sun.COM status);
38319517SBill.Taylor@Sun.COM return (DDI_FAILURE);
38329517SBill.Taylor@Sun.COM }
38339517SBill.Taylor@Sun.COM
38349517SBill.Taylor@Sun.COM /*
38359517SBill.Taylor@Sun.COM * Read all PCI config info (reg0...reg63). Note: According to the
38369517SBill.Taylor@Sun.COM * Hermon software reset application note, we should not read or
38379517SBill.Taylor@Sun.COM * restore the values in reg22 and reg23.
38389517SBill.Taylor@Sun.COM * NOTE: For Hermon (and Arbel too) it says to restore the command
38399517SBill.Taylor@Sun.COM * register LAST, and technically, you need to restore the
38409517SBill.Taylor@Sun.COM * PCIE Capability "device control" and "link control" (word-sized,
38419517SBill.Taylor@Sun.COM * at offsets 0x08 and 0x10 from the capbility ID respectively).
38429517SBill.Taylor@Sun.COM * We hold off restoring the command register - offset 0x4 - till last
38439517SBill.Taylor@Sun.COM */
38449517SBill.Taylor@Sun.COM
38459517SBill.Taylor@Sun.COM /* 1st, wait for the semaphore assure accessibility - per PRM */
38469517SBill.Taylor@Sun.COM status = -1;
38479517SBill.Taylor@Sun.COM for (i = 0; i < NANOSEC/MICROSEC /* 1sec timeout */; i++) {
38489517SBill.Taylor@Sun.COM sem = ddi_get32(cmdhdl, state->hs_cmd_regs.sw_semaphore);
38499517SBill.Taylor@Sun.COM if (sem == 0) {
38509517SBill.Taylor@Sun.COM status = 0;
38519517SBill.Taylor@Sun.COM break;
38529517SBill.Taylor@Sun.COM }
38539517SBill.Taylor@Sun.COM drv_usecwait(1);
38549517SBill.Taylor@Sun.COM }
38559517SBill.Taylor@Sun.COM
38569517SBill.Taylor@Sun.COM /* Check if timeout happens */
38579517SBill.Taylor@Sun.COM if (status == -1) {
38589517SBill.Taylor@Sun.COM /*
38599517SBill.Taylor@Sun.COM * Remove this acc handle from Hermon, then log
38609517SBill.Taylor@Sun.COM * the error.
38619517SBill.Taylor@Sun.COM */
38629517SBill.Taylor@Sun.COM hermon_pci_config_teardown(state, &hdl);
38639517SBill.Taylor@Sun.COM
38649517SBill.Taylor@Sun.COM cmn_err(CE_WARN, "hermon_sw_reset timeout: "
38659517SBill.Taylor@Sun.COM "failed to get the semaphore(0x%p)\n",
38669517SBill.Taylor@Sun.COM (void *)state->hs_cmd_regs.sw_semaphore);
38679517SBill.Taylor@Sun.COM
38689517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_IBA_ERR, HCA_ERR_NON_FATAL);
38699517SBill.Taylor@Sun.COM return (DDI_FAILURE);
38709517SBill.Taylor@Sun.COM }
38719517SBill.Taylor@Sun.COM
38729517SBill.Taylor@Sun.COM for (i = 0; i < HERMON_SW_RESET_NUMREGS; i++) {
38739517SBill.Taylor@Sun.COM if ((i != HERMON_SW_RESET_REG22_RSVD) &&
38749517SBill.Taylor@Sun.COM (i != HERMON_SW_RESET_REG23_RSVD)) {
38759517SBill.Taylor@Sun.COM state->hs_cfg_data[i] = pci_config_get32(hdl, i << 2);
38769517SBill.Taylor@Sun.COM }
38779517SBill.Taylor@Sun.COM }
38789517SBill.Taylor@Sun.COM
38799517SBill.Taylor@Sun.COM /*
38809517SBill.Taylor@Sun.COM * Perform the software reset (by writing 1 at offset 0xF0010)
38819517SBill.Taylor@Sun.COM */
38829517SBill.Taylor@Sun.COM ddi_put32(cmdhdl, state->hs_cmd_regs.sw_reset, HERMON_SW_RESET_START);
38839517SBill.Taylor@Sun.COM
38849517SBill.Taylor@Sun.COM /*
38859517SBill.Taylor@Sun.COM * This delay is required so as not to cause a panic here. If the
38869517SBill.Taylor@Sun.COM * device is accessed too soon after reset it will not respond to
38879517SBill.Taylor@Sun.COM * config cycles, causing a Master Abort and panic.
38889517SBill.Taylor@Sun.COM */
38899517SBill.Taylor@Sun.COM drv_usecwait(reset_delay);
38909517SBill.Taylor@Sun.COM
38919517SBill.Taylor@Sun.COM /*
38929517SBill.Taylor@Sun.COM * Poll waiting for the device to finish resetting.
38939517SBill.Taylor@Sun.COM */
38949517SBill.Taylor@Sun.COM loopcnt = 100; /* 100 times @ 100 usec - total delay 10 msec */
38959517SBill.Taylor@Sun.COM while ((pci_config_get32(hdl, 0) & 0x0000FFFF) != PCI_VENID_MLX) {
38969517SBill.Taylor@Sun.COM drv_usecwait(HERMON_SW_RESET_POLL_DELAY);
38979517SBill.Taylor@Sun.COM if (--loopcnt == 0)
38989517SBill.Taylor@Sun.COM break; /* just in case, break and go on */
38999517SBill.Taylor@Sun.COM }
39009517SBill.Taylor@Sun.COM if (loopcnt == 0)
39019517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "!Never see VEND_ID - read == %X",
39029517SBill.Taylor@Sun.COM pci_config_get32(hdl, 0));
39039517SBill.Taylor@Sun.COM
39049517SBill.Taylor@Sun.COM /*
39059517SBill.Taylor@Sun.COM * Restore the config info
39069517SBill.Taylor@Sun.COM */
39079517SBill.Taylor@Sun.COM for (i = 0; i < HERMON_SW_RESET_NUMREGS; i++) {
39089517SBill.Taylor@Sun.COM if (i == 1) continue; /* skip the status/ctrl reg */
39099517SBill.Taylor@Sun.COM if ((i != HERMON_SW_RESET_REG22_RSVD) &&
39109517SBill.Taylor@Sun.COM (i != HERMON_SW_RESET_REG23_RSVD)) {
39119517SBill.Taylor@Sun.COM pci_config_put32(hdl, i << 2, state->hs_cfg_data[i]);
39129517SBill.Taylor@Sun.COM }
39139517SBill.Taylor@Sun.COM }
39149517SBill.Taylor@Sun.COM
39159517SBill.Taylor@Sun.COM /*
39169517SBill.Taylor@Sun.COM * PCI Express Capability - we saved during capability list, and
39179517SBill.Taylor@Sun.COM * we'll restore them here.
39189517SBill.Taylor@Sun.COM */
39199517SBill.Taylor@Sun.COM offset = state->hs_pci_cap_offset;
39209517SBill.Taylor@Sun.COM data32 = state->hs_pci_cap_devctl;
39219517SBill.Taylor@Sun.COM pci_config_put32(hdl, offset + HERMON_PCI_CAP_DEV_OFFS, data32);
39229517SBill.Taylor@Sun.COM data32 = state->hs_pci_cap_lnkctl;
39239517SBill.Taylor@Sun.COM pci_config_put32(hdl, offset + HERMON_PCI_CAP_LNK_OFFS, data32);
39249517SBill.Taylor@Sun.COM
39259517SBill.Taylor@Sun.COM pci_config_put32(hdl, 0x04, (state->hs_cfg_data[1] | 0x0006));
39269517SBill.Taylor@Sun.COM
39279517SBill.Taylor@Sun.COM /* the FMA retry loop ends. */
39289517SBill.Taylor@Sun.COM hermon_pio_end(state, hdl, pio_error2, fm_loop_cnt2, fm_status2,
39299517SBill.Taylor@Sun.COM fm_test2);
39309517SBill.Taylor@Sun.COM hermon_pio_end(state, cmdhdl, pio_error, fm_loop_cnt, fm_status,
39319517SBill.Taylor@Sun.COM fm_test);
39329517SBill.Taylor@Sun.COM
39339517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
39349517SBill.Taylor@Sun.COM
39359517SBill.Taylor@Sun.COM pio_error2:
39369517SBill.Taylor@Sun.COM /* fall through */
39379517SBill.Taylor@Sun.COM pio_error:
39389517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_NON_FATAL);
39399517SBill.Taylor@Sun.COM return (DDI_FAILURE);
39409517SBill.Taylor@Sun.COM }
39419517SBill.Taylor@Sun.COM
39429517SBill.Taylor@Sun.COM
39439517SBill.Taylor@Sun.COM /*
39449517SBill.Taylor@Sun.COM * hermon_mcg_init()
39459517SBill.Taylor@Sun.COM * Context: Only called from attach() path context
39469517SBill.Taylor@Sun.COM */
39479517SBill.Taylor@Sun.COM static int
hermon_mcg_init(hermon_state_t * state)39489517SBill.Taylor@Sun.COM hermon_mcg_init(hermon_state_t *state)
39499517SBill.Taylor@Sun.COM {
39509517SBill.Taylor@Sun.COM uint_t mcg_tmp_sz;
39519517SBill.Taylor@Sun.COM
39529517SBill.Taylor@Sun.COM
39539517SBill.Taylor@Sun.COM /*
39549517SBill.Taylor@Sun.COM * Allocate space for the MCG temporary copy buffer. This is
39559517SBill.Taylor@Sun.COM * used by the Attach/Detach Multicast Group code
39569517SBill.Taylor@Sun.COM */
39579517SBill.Taylor@Sun.COM mcg_tmp_sz = HERMON_MCGMEM_SZ(state);
39589517SBill.Taylor@Sun.COM state->hs_mcgtmp = kmem_zalloc(mcg_tmp_sz, KM_SLEEP);
39599517SBill.Taylor@Sun.COM
39609517SBill.Taylor@Sun.COM /*
39619517SBill.Taylor@Sun.COM * Initialize the multicast group mutex. This ensures atomic
39629517SBill.Taylor@Sun.COM * access to add, modify, and remove entries in the multicast
39639517SBill.Taylor@Sun.COM * group hash lists.
39649517SBill.Taylor@Sun.COM */
39659517SBill.Taylor@Sun.COM mutex_init(&state->hs_mcglock, NULL, MUTEX_DRIVER,
39669517SBill.Taylor@Sun.COM DDI_INTR_PRI(state->hs_intrmsi_pri));
39679517SBill.Taylor@Sun.COM
39689517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
39699517SBill.Taylor@Sun.COM }
39709517SBill.Taylor@Sun.COM
39719517SBill.Taylor@Sun.COM
39729517SBill.Taylor@Sun.COM /*
39739517SBill.Taylor@Sun.COM * hermon_mcg_fini()
39749517SBill.Taylor@Sun.COM * Context: Only called from attach() and/or detach() path contexts
39759517SBill.Taylor@Sun.COM */
39769517SBill.Taylor@Sun.COM static void
hermon_mcg_fini(hermon_state_t * state)39779517SBill.Taylor@Sun.COM hermon_mcg_fini(hermon_state_t *state)
39789517SBill.Taylor@Sun.COM {
39799517SBill.Taylor@Sun.COM uint_t mcg_tmp_sz;
39809517SBill.Taylor@Sun.COM
39819517SBill.Taylor@Sun.COM
39829517SBill.Taylor@Sun.COM /* Free up the space used for the MCG temporary copy buffer */
39839517SBill.Taylor@Sun.COM mcg_tmp_sz = HERMON_MCGMEM_SZ(state);
39849517SBill.Taylor@Sun.COM kmem_free(state->hs_mcgtmp, mcg_tmp_sz);
39859517SBill.Taylor@Sun.COM
39869517SBill.Taylor@Sun.COM /* Destroy the multicast group mutex */
39879517SBill.Taylor@Sun.COM mutex_destroy(&state->hs_mcglock);
39889517SBill.Taylor@Sun.COM
39899517SBill.Taylor@Sun.COM }
39909517SBill.Taylor@Sun.COM
39919517SBill.Taylor@Sun.COM
39929517SBill.Taylor@Sun.COM /*
39939517SBill.Taylor@Sun.COM * hermon_fw_version_check()
39949517SBill.Taylor@Sun.COM * Context: Only called from attach() path context
39959517SBill.Taylor@Sun.COM */
39969517SBill.Taylor@Sun.COM static int
hermon_fw_version_check(hermon_state_t * state)39979517SBill.Taylor@Sun.COM hermon_fw_version_check(hermon_state_t *state)
39989517SBill.Taylor@Sun.COM {
39999517SBill.Taylor@Sun.COM
40009517SBill.Taylor@Sun.COM uint_t hermon_fw_ver_major;
40019517SBill.Taylor@Sun.COM uint_t hermon_fw_ver_minor;
40029517SBill.Taylor@Sun.COM uint_t hermon_fw_ver_subminor;
40039517SBill.Taylor@Sun.COM
40049517SBill.Taylor@Sun.COM #ifdef FMA_TEST
40059517SBill.Taylor@Sun.COM if (hermon_test_num == -1) {
40069517SBill.Taylor@Sun.COM return (DDI_FAILURE);
40079517SBill.Taylor@Sun.COM }
40089517SBill.Taylor@Sun.COM #endif
40099517SBill.Taylor@Sun.COM
40109517SBill.Taylor@Sun.COM /*
40119517SBill.Taylor@Sun.COM * Depending on which version of driver we have attached, and which
40129517SBill.Taylor@Sun.COM * HCA we've attached, the firmware version checks will be different.
40139517SBill.Taylor@Sun.COM * We set up the comparison values for both Arbel and Sinai HCAs.
40149517SBill.Taylor@Sun.COM */
40159517SBill.Taylor@Sun.COM switch (state->hs_operational_mode) {
40169517SBill.Taylor@Sun.COM case HERMON_HCA_MODE:
40179517SBill.Taylor@Sun.COM hermon_fw_ver_major = HERMON_FW_VER_MAJOR;
40189517SBill.Taylor@Sun.COM hermon_fw_ver_minor = HERMON_FW_VER_MINOR;
40199517SBill.Taylor@Sun.COM hermon_fw_ver_subminor = HERMON_FW_VER_SUBMINOR;
40209517SBill.Taylor@Sun.COM break;
40219517SBill.Taylor@Sun.COM
40229517SBill.Taylor@Sun.COM default:
40239517SBill.Taylor@Sun.COM return (DDI_FAILURE);
40249517SBill.Taylor@Sun.COM }
40259517SBill.Taylor@Sun.COM
40269517SBill.Taylor@Sun.COM /*
40279517SBill.Taylor@Sun.COM * If FW revision major number is less than acceptable,
40289517SBill.Taylor@Sun.COM * return failure, else if greater return success. If
40299517SBill.Taylor@Sun.COM * the major numbers are equal than check the minor number
40309517SBill.Taylor@Sun.COM */
40319517SBill.Taylor@Sun.COM if (state->hs_fw.fw_rev_major < hermon_fw_ver_major) {
40329517SBill.Taylor@Sun.COM return (DDI_FAILURE);
40339517SBill.Taylor@Sun.COM } else if (state->hs_fw.fw_rev_major > hermon_fw_ver_major) {
40349517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
40359517SBill.Taylor@Sun.COM }
40369517SBill.Taylor@Sun.COM
40379517SBill.Taylor@Sun.COM /*
40389517SBill.Taylor@Sun.COM * Do the same check as above, except for minor revision numbers
40399517SBill.Taylor@Sun.COM * If the minor numbers are equal than check the subminor number
40409517SBill.Taylor@Sun.COM */
40419517SBill.Taylor@Sun.COM if (state->hs_fw.fw_rev_minor < hermon_fw_ver_minor) {
40429517SBill.Taylor@Sun.COM return (DDI_FAILURE);
40439517SBill.Taylor@Sun.COM } else if (state->hs_fw.fw_rev_minor > hermon_fw_ver_minor) {
40449517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
40459517SBill.Taylor@Sun.COM }
40469517SBill.Taylor@Sun.COM
40479517SBill.Taylor@Sun.COM /*
40489517SBill.Taylor@Sun.COM * Once again we do the same check as above, except for the subminor
40499517SBill.Taylor@Sun.COM * revision number. If the subminor numbers are equal here, then
40509517SBill.Taylor@Sun.COM * these are the same firmware version, return success
40519517SBill.Taylor@Sun.COM */
40529517SBill.Taylor@Sun.COM if (state->hs_fw.fw_rev_subminor < hermon_fw_ver_subminor) {
40539517SBill.Taylor@Sun.COM return (DDI_FAILURE);
40549517SBill.Taylor@Sun.COM } else if (state->hs_fw.fw_rev_subminor > hermon_fw_ver_subminor) {
40559517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
40569517SBill.Taylor@Sun.COM }
40579517SBill.Taylor@Sun.COM
40589517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
40599517SBill.Taylor@Sun.COM }
40609517SBill.Taylor@Sun.COM
40619517SBill.Taylor@Sun.COM
40629517SBill.Taylor@Sun.COM /*
40639517SBill.Taylor@Sun.COM * hermon_device_info_report()
40649517SBill.Taylor@Sun.COM * Context: Only called from attach() path context
40659517SBill.Taylor@Sun.COM */
40669517SBill.Taylor@Sun.COM static void
hermon_device_info_report(hermon_state_t * state)40679517SBill.Taylor@Sun.COM hermon_device_info_report(hermon_state_t *state)
40689517SBill.Taylor@Sun.COM {
40699517SBill.Taylor@Sun.COM
40709517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "?hermon%d: FW ver: %04d.%04d.%04d, "
40719517SBill.Taylor@Sun.COM "HW rev: %02d\n", state->hs_instance, state->hs_fw.fw_rev_major,
40729517SBill.Taylor@Sun.COM state->hs_fw.fw_rev_minor, state->hs_fw.fw_rev_subminor,
40739517SBill.Taylor@Sun.COM state->hs_revision_id);
40749517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "?hermon%d: %64s (0x%016" PRIx64 ")\n",
40759517SBill.Taylor@Sun.COM state->hs_instance, state->hs_nodedesc, state->hs_nodeguid);
40769517SBill.Taylor@Sun.COM
40779517SBill.Taylor@Sun.COM }
40789517SBill.Taylor@Sun.COM
40799517SBill.Taylor@Sun.COM
40809517SBill.Taylor@Sun.COM /*
40819517SBill.Taylor@Sun.COM * hermon_pci_capability_list()
40829517SBill.Taylor@Sun.COM * Context: Only called from attach() path context
40839517SBill.Taylor@Sun.COM */
40849517SBill.Taylor@Sun.COM static int
hermon_pci_capability_list(hermon_state_t * state,ddi_acc_handle_t hdl)40859517SBill.Taylor@Sun.COM hermon_pci_capability_list(hermon_state_t *state, ddi_acc_handle_t hdl)
40869517SBill.Taylor@Sun.COM {
40879517SBill.Taylor@Sun.COM uint_t offset, data;
40889517SBill.Taylor@Sun.COM uint32_t data32;
40899517SBill.Taylor@Sun.COM
40909517SBill.Taylor@Sun.COM state->hs_pci_cap_offset = 0; /* make sure it's cleared */
40919517SBill.Taylor@Sun.COM
40929517SBill.Taylor@Sun.COM /*
40939517SBill.Taylor@Sun.COM * Check for the "PCI Capabilities" bit in the "Status Register".
40949517SBill.Taylor@Sun.COM * Bit 4 in this register indicates the presence of a "PCI
40959517SBill.Taylor@Sun.COM * Capabilities" list.
40969517SBill.Taylor@Sun.COM *
40979517SBill.Taylor@Sun.COM * PCI-Express requires this bit to be set to 1.
40989517SBill.Taylor@Sun.COM */
40999517SBill.Taylor@Sun.COM data = pci_config_get16(hdl, 0x06);
41009517SBill.Taylor@Sun.COM if ((data & 0x10) == 0) {
41019517SBill.Taylor@Sun.COM return (DDI_FAILURE);
41029517SBill.Taylor@Sun.COM }
41039517SBill.Taylor@Sun.COM
41049517SBill.Taylor@Sun.COM /*
41059517SBill.Taylor@Sun.COM * Starting from offset 0x34 in PCI config space, find the
41069517SBill.Taylor@Sun.COM * head of "PCI capabilities" list, and walk the list. If
41079517SBill.Taylor@Sun.COM * capabilities of a known type are encountered (e.g.
41089517SBill.Taylor@Sun.COM * "PCI-X Capability"), then call the appropriate handler
41099517SBill.Taylor@Sun.COM * function.
41109517SBill.Taylor@Sun.COM */
41119517SBill.Taylor@Sun.COM offset = pci_config_get8(hdl, 0x34);
41129517SBill.Taylor@Sun.COM while (offset != 0x0) {
41139517SBill.Taylor@Sun.COM data = pci_config_get8(hdl, offset);
41149517SBill.Taylor@Sun.COM /*
41159517SBill.Taylor@Sun.COM * Check for known capability types. Hermon has the
41169517SBill.Taylor@Sun.COM * following:
41179517SBill.Taylor@Sun.COM * o Power Mgmt (0x02)
41189517SBill.Taylor@Sun.COM * o VPD Capability (0x03)
41199517SBill.Taylor@Sun.COM * o PCI-E Capability (0x10)
41209517SBill.Taylor@Sun.COM * o MSIX Capability (0x11)
41219517SBill.Taylor@Sun.COM */
41229517SBill.Taylor@Sun.COM switch (data) {
41239517SBill.Taylor@Sun.COM case 0x01:
41249517SBill.Taylor@Sun.COM /* power mgmt handling */
41259517SBill.Taylor@Sun.COM break;
41269517SBill.Taylor@Sun.COM case 0x03:
41279517SBill.Taylor@Sun.COM
41289517SBill.Taylor@Sun.COM /*
41299517SBill.Taylor@Sun.COM * Reading the PCIe VPD is inconsistent - that is, sometimes causes
41309517SBill.Taylor@Sun.COM * problems on (mostly) X64, though we've also seen problems w/ Sparc
41319517SBill.Taylor@Sun.COM * and Tavor --- so, for now until it's root caused, don't try and
41329517SBill.Taylor@Sun.COM * read it
41339517SBill.Taylor@Sun.COM */
41349517SBill.Taylor@Sun.COM #ifdef HERMON_VPD_WORKS
41359517SBill.Taylor@Sun.COM hermon_pci_capability_vpd(state, hdl, offset);
41369517SBill.Taylor@Sun.COM #else
41379517SBill.Taylor@Sun.COM delay(100);
41389517SBill.Taylor@Sun.COM hermon_pci_capability_vpd(state, hdl, offset);
41399517SBill.Taylor@Sun.COM #endif
41409517SBill.Taylor@Sun.COM break;
41419517SBill.Taylor@Sun.COM case 0x10:
41429517SBill.Taylor@Sun.COM /*
41439517SBill.Taylor@Sun.COM * PCI Express Capability - save offset & contents
41449517SBill.Taylor@Sun.COM * for later in reset
41459517SBill.Taylor@Sun.COM */
41469517SBill.Taylor@Sun.COM state->hs_pci_cap_offset = offset;
41479517SBill.Taylor@Sun.COM data32 = pci_config_get32(hdl,
41489517SBill.Taylor@Sun.COM offset + HERMON_PCI_CAP_DEV_OFFS);
41499517SBill.Taylor@Sun.COM state->hs_pci_cap_devctl = data32;
41509517SBill.Taylor@Sun.COM data32 = pci_config_get32(hdl,
41519517SBill.Taylor@Sun.COM offset + HERMON_PCI_CAP_LNK_OFFS);
41529517SBill.Taylor@Sun.COM state->hs_pci_cap_lnkctl = data32;
41539517SBill.Taylor@Sun.COM break;
41549517SBill.Taylor@Sun.COM case 0x11:
41559517SBill.Taylor@Sun.COM /*
41569517SBill.Taylor@Sun.COM * MSIX support - nothing to do, taken care of in the
41579517SBill.Taylor@Sun.COM * MSI/MSIX interrupt frameworkd
41589517SBill.Taylor@Sun.COM */
41599517SBill.Taylor@Sun.COM break;
41609517SBill.Taylor@Sun.COM default:
41619517SBill.Taylor@Sun.COM /* just go on to the next */
41629517SBill.Taylor@Sun.COM break;
41639517SBill.Taylor@Sun.COM }
41649517SBill.Taylor@Sun.COM
41659517SBill.Taylor@Sun.COM /* Get offset of next entry in list */
41669517SBill.Taylor@Sun.COM offset = pci_config_get8(hdl, offset + 1);
41679517SBill.Taylor@Sun.COM }
41689517SBill.Taylor@Sun.COM
41699517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
41709517SBill.Taylor@Sun.COM }
41719517SBill.Taylor@Sun.COM
41729517SBill.Taylor@Sun.COM /*
41739517SBill.Taylor@Sun.COM * hermon_pci_read_vpd()
41749517SBill.Taylor@Sun.COM * Context: Only called from attach() path context
41759517SBill.Taylor@Sun.COM * utility routine for hermon_pci_capability_vpd()
41769517SBill.Taylor@Sun.COM */
41779517SBill.Taylor@Sun.COM static int
hermon_pci_read_vpd(ddi_acc_handle_t hdl,uint_t offset,uint32_t addr,uint32_t * data)41789517SBill.Taylor@Sun.COM hermon_pci_read_vpd(ddi_acc_handle_t hdl, uint_t offset, uint32_t addr,
41799517SBill.Taylor@Sun.COM uint32_t *data)
41809517SBill.Taylor@Sun.COM {
41819517SBill.Taylor@Sun.COM int retry = 40; /* retry counter for EEPROM poll */
41829517SBill.Taylor@Sun.COM uint32_t val;
41839517SBill.Taylor@Sun.COM int vpd_addr = offset + 2;
41849517SBill.Taylor@Sun.COM int vpd_data = offset + 4;
41859517SBill.Taylor@Sun.COM
41869517SBill.Taylor@Sun.COM /*
41879517SBill.Taylor@Sun.COM * In order to read a 32-bit value from VPD, we are to write down
41889517SBill.Taylor@Sun.COM * the address (offset in the VPD itself) to the address register.
41899517SBill.Taylor@Sun.COM * To signal the read, we also clear bit 31. We then poll on bit 31
41909517SBill.Taylor@Sun.COM * and when it is set, we can then read our 4 bytes from the data
41919517SBill.Taylor@Sun.COM * register.
41929517SBill.Taylor@Sun.COM */
41939517SBill.Taylor@Sun.COM (void) pci_config_put32(hdl, offset, addr << 16);
41949517SBill.Taylor@Sun.COM do {
41959517SBill.Taylor@Sun.COM drv_usecwait(1000);
41969517SBill.Taylor@Sun.COM val = pci_config_get16(hdl, vpd_addr);
41979517SBill.Taylor@Sun.COM if (val & 0x8000) { /* flag bit set */
41989517SBill.Taylor@Sun.COM *data = pci_config_get32(hdl, vpd_data);
41999517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
42009517SBill.Taylor@Sun.COM }
42019517SBill.Taylor@Sun.COM } while (--retry);
42029517SBill.Taylor@Sun.COM /* read of flag failed write one message but count the failures */
42039517SBill.Taylor@Sun.COM if (debug_vpd == 0)
42049517SBill.Taylor@Sun.COM cmn_err(CE_NOTE,
42059517SBill.Taylor@Sun.COM "!Failed to see flag bit after VPD addr write\n");
42069517SBill.Taylor@Sun.COM debug_vpd++;
42079517SBill.Taylor@Sun.COM
42089517SBill.Taylor@Sun.COM
42099517SBill.Taylor@Sun.COM vpd_read_fail:
42109517SBill.Taylor@Sun.COM return (DDI_FAILURE);
42119517SBill.Taylor@Sun.COM }
42129517SBill.Taylor@Sun.COM
42139517SBill.Taylor@Sun.COM
42149517SBill.Taylor@Sun.COM
42159517SBill.Taylor@Sun.COM /*
42169517SBill.Taylor@Sun.COM * hermon_pci_capability_vpd()
42179517SBill.Taylor@Sun.COM * Context: Only called from attach() path context
42189517SBill.Taylor@Sun.COM */
42199517SBill.Taylor@Sun.COM static void
hermon_pci_capability_vpd(hermon_state_t * state,ddi_acc_handle_t hdl,uint_t offset)42209517SBill.Taylor@Sun.COM hermon_pci_capability_vpd(hermon_state_t *state, ddi_acc_handle_t hdl,
42219517SBill.Taylor@Sun.COM uint_t offset)
42229517SBill.Taylor@Sun.COM {
42239517SBill.Taylor@Sun.COM uint8_t name_length;
42249517SBill.Taylor@Sun.COM uint8_t pn_length;
42259517SBill.Taylor@Sun.COM int i, err = 0;
42269517SBill.Taylor@Sun.COM int vpd_str_id = 0;
42279517SBill.Taylor@Sun.COM int vpd_ro_desc;
42289517SBill.Taylor@Sun.COM int vpd_ro_pn_desc;
42299517SBill.Taylor@Sun.COM #ifdef _BIG_ENDIAN
42309517SBill.Taylor@Sun.COM uint32_t data32;
42319517SBill.Taylor@Sun.COM #endif /* _BIG_ENDIAN */
42329517SBill.Taylor@Sun.COM union {
42339517SBill.Taylor@Sun.COM uint32_t vpd_int[HERMON_VPD_HDR_DWSIZE];
42349517SBill.Taylor@Sun.COM uchar_t vpd_char[HERMON_VPD_HDR_BSIZE];
42359517SBill.Taylor@Sun.COM } vpd;
42369517SBill.Taylor@Sun.COM
42379517SBill.Taylor@Sun.COM
42389517SBill.Taylor@Sun.COM /*
42399517SBill.Taylor@Sun.COM * Read in the Vital Product Data (VPD) to the extend needed
42409517SBill.Taylor@Sun.COM * by the fwflash utility
42419517SBill.Taylor@Sun.COM */
42429517SBill.Taylor@Sun.COM for (i = 0; i < HERMON_VPD_HDR_DWSIZE; i++) {
42439517SBill.Taylor@Sun.COM err = hermon_pci_read_vpd(hdl, offset, i << 2, &vpd.vpd_int[i]);
42449517SBill.Taylor@Sun.COM if (err != DDI_SUCCESS) {
42459517SBill.Taylor@Sun.COM cmn_err(CE_NOTE, "!VPD read failed\n");
42469517SBill.Taylor@Sun.COM goto out;
42479517SBill.Taylor@Sun.COM }
42489517SBill.Taylor@Sun.COM }
42499517SBill.Taylor@Sun.COM
42509517SBill.Taylor@Sun.COM #ifdef _BIG_ENDIAN
42519517SBill.Taylor@Sun.COM /* Need to swap bytes for big endian. */
42529517SBill.Taylor@Sun.COM for (i = 0; i < HERMON_VPD_HDR_DWSIZE; i++) {
42539517SBill.Taylor@Sun.COM data32 = vpd.vpd_int[i];
42549517SBill.Taylor@Sun.COM vpd.vpd_char[(i << 2) + 3] =
42559517SBill.Taylor@Sun.COM (uchar_t)((data32 & 0xFF000000) >> 24);
42569517SBill.Taylor@Sun.COM vpd.vpd_char[(i << 2) + 2] =
42579517SBill.Taylor@Sun.COM (uchar_t)((data32 & 0x00FF0000) >> 16);
42589517SBill.Taylor@Sun.COM vpd.vpd_char[(i << 2) + 1] =
42599517SBill.Taylor@Sun.COM (uchar_t)((data32 & 0x0000FF00) >> 8);
42609517SBill.Taylor@Sun.COM vpd.vpd_char[i << 2] = (uchar_t)(data32 & 0x000000FF);
42619517SBill.Taylor@Sun.COM }
42629517SBill.Taylor@Sun.COM #endif /* _BIG_ENDIAN */
42639517SBill.Taylor@Sun.COM
42649517SBill.Taylor@Sun.COM /* Check for VPD String ID Tag */
42659517SBill.Taylor@Sun.COM if (vpd.vpd_char[vpd_str_id] == 0x82) {
42669517SBill.Taylor@Sun.COM /* get the product name */
42679517SBill.Taylor@Sun.COM name_length = (uint8_t)vpd.vpd_char[vpd_str_id + 1];
42689517SBill.Taylor@Sun.COM if (name_length > sizeof (state->hs_hca_name)) {
42699517SBill.Taylor@Sun.COM cmn_err(CE_NOTE, "!VPD name too large (0x%x)\n",
42709517SBill.Taylor@Sun.COM name_length);
42719517SBill.Taylor@Sun.COM goto out;
42729517SBill.Taylor@Sun.COM }
42739517SBill.Taylor@Sun.COM (void) memcpy(state->hs_hca_name, &vpd.vpd_char[vpd_str_id + 3],
42749517SBill.Taylor@Sun.COM name_length);
42759517SBill.Taylor@Sun.COM state->hs_hca_name[name_length] = 0;
42769517SBill.Taylor@Sun.COM
42779517SBill.Taylor@Sun.COM /* get the part number */
42789517SBill.Taylor@Sun.COM vpd_ro_desc = name_length + 3; /* read-only tag location */
42799517SBill.Taylor@Sun.COM vpd_ro_pn_desc = vpd_ro_desc + 3; /* P/N keyword location */
42809517SBill.Taylor@Sun.COM
42819517SBill.Taylor@Sun.COM /* Verify read-only tag and Part Number keyword. */
42829517SBill.Taylor@Sun.COM if (vpd.vpd_char[vpd_ro_desc] != 0x90 ||
42839517SBill.Taylor@Sun.COM (vpd.vpd_char[vpd_ro_pn_desc] != 'P' &&
42849517SBill.Taylor@Sun.COM vpd.vpd_char[vpd_ro_pn_desc + 1] != 'N')) {
42859517SBill.Taylor@Sun.COM cmn_err(CE_NOTE, "!VPD Part Number not found\n");
42869517SBill.Taylor@Sun.COM goto out;
42879517SBill.Taylor@Sun.COM }
42889517SBill.Taylor@Sun.COM
42899517SBill.Taylor@Sun.COM pn_length = (uint8_t)vpd.vpd_char[vpd_ro_pn_desc + 2];
42909517SBill.Taylor@Sun.COM if (pn_length > sizeof (state->hs_hca_pn)) {
42919517SBill.Taylor@Sun.COM cmn_err(CE_NOTE, "!VPD part number too large (0x%x)\n",
42929517SBill.Taylor@Sun.COM name_length);
42939517SBill.Taylor@Sun.COM goto out;
42949517SBill.Taylor@Sun.COM }
42959517SBill.Taylor@Sun.COM (void) memcpy(state->hs_hca_pn,
42969517SBill.Taylor@Sun.COM &vpd.vpd_char[vpd_ro_pn_desc + 3],
42979517SBill.Taylor@Sun.COM pn_length);
42989517SBill.Taylor@Sun.COM state->hs_hca_pn[pn_length] = 0;
42999517SBill.Taylor@Sun.COM state->hs_hca_pn_len = pn_length;
43009517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "!vpd %s\n", state->hs_hca_pn);
43019517SBill.Taylor@Sun.COM } else {
43029517SBill.Taylor@Sun.COM /* Wrong VPD String ID Tag */
43039517SBill.Taylor@Sun.COM cmn_err(CE_NOTE, "!VPD String ID Tag not found, tag: %02x\n",
43049517SBill.Taylor@Sun.COM vpd.vpd_char[0]);
43059517SBill.Taylor@Sun.COM goto out;
43069517SBill.Taylor@Sun.COM }
43079517SBill.Taylor@Sun.COM return;
43089517SBill.Taylor@Sun.COM out:
43099517SBill.Taylor@Sun.COM state->hs_hca_pn_len = 0;
43109517SBill.Taylor@Sun.COM }
43119517SBill.Taylor@Sun.COM
43129517SBill.Taylor@Sun.COM
43139517SBill.Taylor@Sun.COM
43149517SBill.Taylor@Sun.COM /*
43159517SBill.Taylor@Sun.COM * hermon_intr_or_msi_init()
43169517SBill.Taylor@Sun.COM * Context: Only called from attach() path context
43179517SBill.Taylor@Sun.COM */
43189517SBill.Taylor@Sun.COM static int
hermon_intr_or_msi_init(hermon_state_t * state)43199517SBill.Taylor@Sun.COM hermon_intr_or_msi_init(hermon_state_t *state)
43209517SBill.Taylor@Sun.COM {
43219517SBill.Taylor@Sun.COM int status;
43229517SBill.Taylor@Sun.COM
43239517SBill.Taylor@Sun.COM /* Query for the list of supported interrupt event types */
43249517SBill.Taylor@Sun.COM status = ddi_intr_get_supported_types(state->hs_dip,
43259517SBill.Taylor@Sun.COM &state->hs_intr_types_avail);
43269517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
43279517SBill.Taylor@Sun.COM return (DDI_FAILURE);
43289517SBill.Taylor@Sun.COM }
43299517SBill.Taylor@Sun.COM
43309517SBill.Taylor@Sun.COM /*
43319517SBill.Taylor@Sun.COM * If Hermon supports MSI-X in this system (and, if it
43329517SBill.Taylor@Sun.COM * hasn't been overridden by a configuration variable), then
43339517SBill.Taylor@Sun.COM * the default behavior is to use a single MSI-X. Otherwise,
43349517SBill.Taylor@Sun.COM * fallback to using legacy interrupts. Also, if MSI-X is chosen,
43359517SBill.Taylor@Sun.COM * but fails for whatever reasons, then next try MSI
43369517SBill.Taylor@Sun.COM */
43379517SBill.Taylor@Sun.COM if ((state->hs_cfg_profile->cp_use_msi_if_avail != 0) &&
43389517SBill.Taylor@Sun.COM (state->hs_intr_types_avail & DDI_INTR_TYPE_MSIX)) {
43399517SBill.Taylor@Sun.COM status = hermon_add_intrs(state, DDI_INTR_TYPE_MSIX);
43409517SBill.Taylor@Sun.COM if (status == DDI_SUCCESS) {
43419517SBill.Taylor@Sun.COM state->hs_intr_type_chosen = DDI_INTR_TYPE_MSIX;
43429517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
43439517SBill.Taylor@Sun.COM }
43449517SBill.Taylor@Sun.COM }
43459517SBill.Taylor@Sun.COM
43469517SBill.Taylor@Sun.COM /*
43479517SBill.Taylor@Sun.COM * If Hermon supports MSI in this system (and, if it
43489517SBill.Taylor@Sun.COM * hasn't been overridden by a configuration variable), then
43499517SBill.Taylor@Sun.COM * the default behavior is to use a single MSIX. Otherwise,
43509517SBill.Taylor@Sun.COM * fallback to using legacy interrupts. Also, if MSI is chosen,
43519517SBill.Taylor@Sun.COM * but fails for whatever reasons, then fallback to using legacy
43529517SBill.Taylor@Sun.COM * interrupts.
43539517SBill.Taylor@Sun.COM */
43549517SBill.Taylor@Sun.COM if ((state->hs_cfg_profile->cp_use_msi_if_avail != 0) &&
43559517SBill.Taylor@Sun.COM (state->hs_intr_types_avail & DDI_INTR_TYPE_MSI)) {
43569517SBill.Taylor@Sun.COM status = hermon_add_intrs(state, DDI_INTR_TYPE_MSI);
43579517SBill.Taylor@Sun.COM if (status == DDI_SUCCESS) {
43589517SBill.Taylor@Sun.COM state->hs_intr_type_chosen = DDI_INTR_TYPE_MSI;
43599517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
43609517SBill.Taylor@Sun.COM }
43619517SBill.Taylor@Sun.COM }
43629517SBill.Taylor@Sun.COM
43639517SBill.Taylor@Sun.COM /*
43649517SBill.Taylor@Sun.COM * MSI interrupt allocation failed, or was not available. Fallback to
43659517SBill.Taylor@Sun.COM * legacy interrupt support.
43669517SBill.Taylor@Sun.COM */
43679517SBill.Taylor@Sun.COM if (state->hs_intr_types_avail & DDI_INTR_TYPE_FIXED) {
43689517SBill.Taylor@Sun.COM status = hermon_add_intrs(state, DDI_INTR_TYPE_FIXED);
43699517SBill.Taylor@Sun.COM if (status == DDI_SUCCESS) {
43709517SBill.Taylor@Sun.COM state->hs_intr_type_chosen = DDI_INTR_TYPE_FIXED;
43719517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
43729517SBill.Taylor@Sun.COM }
43739517SBill.Taylor@Sun.COM }
43749517SBill.Taylor@Sun.COM
43759517SBill.Taylor@Sun.COM /*
43769517SBill.Taylor@Sun.COM * None of MSI, MSI-X, nor legacy interrupts were successful.
43779517SBill.Taylor@Sun.COM * Return failure.
43789517SBill.Taylor@Sun.COM */
43799517SBill.Taylor@Sun.COM return (DDI_FAILURE);
43809517SBill.Taylor@Sun.COM }
43819517SBill.Taylor@Sun.COM
438212965SWilliam.Taylor@Oracle.COM /* ARGSUSED */
438312965SWilliam.Taylor@Oracle.COM static int
hermon_intr_cb_handler(dev_info_t * dip,ddi_cb_action_t action,void * cbarg,void * arg1,void * arg2)438412965SWilliam.Taylor@Oracle.COM hermon_intr_cb_handler(dev_info_t *dip, ddi_cb_action_t action, void *cbarg,
438512965SWilliam.Taylor@Oracle.COM void *arg1, void *arg2)
438612965SWilliam.Taylor@Oracle.COM {
438712965SWilliam.Taylor@Oracle.COM hermon_state_t *state = (hermon_state_t *)arg1;
438812965SWilliam.Taylor@Oracle.COM
438912965SWilliam.Taylor@Oracle.COM IBTF_DPRINTF_L2("hermon", "interrupt callback: instance %d, "
439012965SWilliam.Taylor@Oracle.COM "action %d, cbarg %d\n", state->hs_instance, action,
439112965SWilliam.Taylor@Oracle.COM (uint32_t)(uintptr_t)cbarg);
439212965SWilliam.Taylor@Oracle.COM return (DDI_SUCCESS);
439312965SWilliam.Taylor@Oracle.COM }
439412965SWilliam.Taylor@Oracle.COM
43959517SBill.Taylor@Sun.COM /*
43969517SBill.Taylor@Sun.COM * hermon_add_intrs()
43979517SBill.Taylor@Sun.COM * Context: Only called from attach() patch context
43989517SBill.Taylor@Sun.COM */
43999517SBill.Taylor@Sun.COM static int
hermon_add_intrs(hermon_state_t * state,int intr_type)44009517SBill.Taylor@Sun.COM hermon_add_intrs(hermon_state_t *state, int intr_type)
44019517SBill.Taylor@Sun.COM {
44029517SBill.Taylor@Sun.COM int status;
44039517SBill.Taylor@Sun.COM
440412965SWilliam.Taylor@Oracle.COM if (state->hs_intr_cb_hdl == NULL) {
440512965SWilliam.Taylor@Oracle.COM status = ddi_cb_register(state->hs_dip, DDI_CB_FLAG_INTR,
440612965SWilliam.Taylor@Oracle.COM hermon_intr_cb_handler, state, NULL,
440712965SWilliam.Taylor@Oracle.COM &state->hs_intr_cb_hdl);
440812965SWilliam.Taylor@Oracle.COM if (status != DDI_SUCCESS) {
440912965SWilliam.Taylor@Oracle.COM cmn_err(CE_CONT, "ddi_cb_register failed: 0x%x\n",
441012965SWilliam.Taylor@Oracle.COM status);
441112965SWilliam.Taylor@Oracle.COM state->hs_intr_cb_hdl = NULL;
441212965SWilliam.Taylor@Oracle.COM return (DDI_FAILURE);
441312965SWilliam.Taylor@Oracle.COM }
441412965SWilliam.Taylor@Oracle.COM }
44159517SBill.Taylor@Sun.COM
44169517SBill.Taylor@Sun.COM /* Get number of interrupts/MSI supported */
44179517SBill.Taylor@Sun.COM status = ddi_intr_get_nintrs(state->hs_dip, intr_type,
44189517SBill.Taylor@Sun.COM &state->hs_intrmsi_count);
44199517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
442012965SWilliam.Taylor@Oracle.COM (void) ddi_cb_unregister(state->hs_intr_cb_hdl);
442112965SWilliam.Taylor@Oracle.COM state->hs_intr_cb_hdl = NULL;
44229517SBill.Taylor@Sun.COM return (DDI_FAILURE);
44239517SBill.Taylor@Sun.COM }
44249517SBill.Taylor@Sun.COM
44259517SBill.Taylor@Sun.COM /* Get number of available interrupts/MSI */
44269517SBill.Taylor@Sun.COM status = ddi_intr_get_navail(state->hs_dip, intr_type,
44279517SBill.Taylor@Sun.COM &state->hs_intrmsi_avail);
44289517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
442912965SWilliam.Taylor@Oracle.COM (void) ddi_cb_unregister(state->hs_intr_cb_hdl);
443012965SWilliam.Taylor@Oracle.COM state->hs_intr_cb_hdl = NULL;
44319517SBill.Taylor@Sun.COM return (DDI_FAILURE);
44329517SBill.Taylor@Sun.COM }
44339517SBill.Taylor@Sun.COM
44349517SBill.Taylor@Sun.COM /* Ensure that we have at least one (1) usable MSI or interrupt */
44359517SBill.Taylor@Sun.COM if ((state->hs_intrmsi_avail < 1) || (state->hs_intrmsi_count < 1)) {
443612965SWilliam.Taylor@Oracle.COM (void) ddi_cb_unregister(state->hs_intr_cb_hdl);
443712965SWilliam.Taylor@Oracle.COM state->hs_intr_cb_hdl = NULL;
44389517SBill.Taylor@Sun.COM return (DDI_FAILURE);
44399517SBill.Taylor@Sun.COM }
44409517SBill.Taylor@Sun.COM
444112965SWilliam.Taylor@Oracle.COM /*
444212965SWilliam.Taylor@Oracle.COM * Allocate the #interrupt/MSI handles.
444312965SWilliam.Taylor@Oracle.COM * The number we request is the minimum of these three values:
444412965SWilliam.Taylor@Oracle.COM * HERMON_MSIX_MAX driver maximum (array size)
444512965SWilliam.Taylor@Oracle.COM * hermon_msix_max /etc/system override to...
444612965SWilliam.Taylor@Oracle.COM * HERMON_MSIX_MAX
444712965SWilliam.Taylor@Oracle.COM * state->hs_intrmsi_avail Maximum the ddi provides.
444812965SWilliam.Taylor@Oracle.COM */
44499517SBill.Taylor@Sun.COM status = ddi_intr_alloc(state->hs_dip, &state->hs_intrmsi_hdl[0],
445012965SWilliam.Taylor@Oracle.COM intr_type, 0, min(min(HERMON_MSIX_MAX, state->hs_intrmsi_avail),
445112965SWilliam.Taylor@Oracle.COM hermon_msix_max), &state->hs_intrmsi_allocd, DDI_INTR_ALLOC_NORMAL);
44529517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
445312965SWilliam.Taylor@Oracle.COM (void) ddi_cb_unregister(state->hs_intr_cb_hdl);
445412965SWilliam.Taylor@Oracle.COM state->hs_intr_cb_hdl = NULL;
44559517SBill.Taylor@Sun.COM return (DDI_FAILURE);
44569517SBill.Taylor@Sun.COM }
44579517SBill.Taylor@Sun.COM
44589517SBill.Taylor@Sun.COM /* Ensure that we have allocated at least one (1) MSI or interrupt */
44599517SBill.Taylor@Sun.COM if (state->hs_intrmsi_allocd < 1) {
446012965SWilliam.Taylor@Oracle.COM (void) ddi_cb_unregister(state->hs_intr_cb_hdl);
446112965SWilliam.Taylor@Oracle.COM state->hs_intr_cb_hdl = NULL;
44629517SBill.Taylor@Sun.COM return (DDI_FAILURE);
44639517SBill.Taylor@Sun.COM }
44649517SBill.Taylor@Sun.COM
44659517SBill.Taylor@Sun.COM /*
44669517SBill.Taylor@Sun.COM * Extract the priority for the allocated interrupt/MSI. This
44679517SBill.Taylor@Sun.COM * will be used later when initializing certain mutexes.
44689517SBill.Taylor@Sun.COM */
44699517SBill.Taylor@Sun.COM status = ddi_intr_get_pri(state->hs_intrmsi_hdl[0],
44709517SBill.Taylor@Sun.COM &state->hs_intrmsi_pri);
44719517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
44729517SBill.Taylor@Sun.COM /* Free the allocated interrupt/MSI handle */
44739517SBill.Taylor@Sun.COM (void) ddi_intr_free(state->hs_intrmsi_hdl[0]);
44749517SBill.Taylor@Sun.COM
447512965SWilliam.Taylor@Oracle.COM (void) ddi_cb_unregister(state->hs_intr_cb_hdl);
447612965SWilliam.Taylor@Oracle.COM state->hs_intr_cb_hdl = NULL;
44779517SBill.Taylor@Sun.COM return (DDI_FAILURE);
44789517SBill.Taylor@Sun.COM }
44799517SBill.Taylor@Sun.COM
44809517SBill.Taylor@Sun.COM /* Make sure the interrupt/MSI priority is below 'high level' */
44819517SBill.Taylor@Sun.COM if (state->hs_intrmsi_pri >= ddi_intr_get_hilevel_pri()) {
44829517SBill.Taylor@Sun.COM /* Free the allocated interrupt/MSI handle */
44839517SBill.Taylor@Sun.COM (void) ddi_intr_free(state->hs_intrmsi_hdl[0]);
44849517SBill.Taylor@Sun.COM
44859517SBill.Taylor@Sun.COM return (DDI_FAILURE);
44869517SBill.Taylor@Sun.COM }
44879517SBill.Taylor@Sun.COM
44889517SBill.Taylor@Sun.COM /* Get add'l capability information regarding interrupt/MSI */
44899517SBill.Taylor@Sun.COM status = ddi_intr_get_cap(state->hs_intrmsi_hdl[0],
44909517SBill.Taylor@Sun.COM &state->hs_intrmsi_cap);
44919517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
44929517SBill.Taylor@Sun.COM /* Free the allocated interrupt/MSI handle */
44939517SBill.Taylor@Sun.COM (void) ddi_intr_free(state->hs_intrmsi_hdl[0]);
44949517SBill.Taylor@Sun.COM
44959517SBill.Taylor@Sun.COM return (DDI_FAILURE);
44969517SBill.Taylor@Sun.COM }
44979517SBill.Taylor@Sun.COM
44989517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
44999517SBill.Taylor@Sun.COM }
45009517SBill.Taylor@Sun.COM
45019517SBill.Taylor@Sun.COM
45029517SBill.Taylor@Sun.COM /*
45039517SBill.Taylor@Sun.COM * hermon_intr_or_msi_fini()
45049517SBill.Taylor@Sun.COM * Context: Only called from attach() and/or detach() path contexts
45059517SBill.Taylor@Sun.COM */
45069517SBill.Taylor@Sun.COM static int
hermon_intr_or_msi_fini(hermon_state_t * state)45079517SBill.Taylor@Sun.COM hermon_intr_or_msi_fini(hermon_state_t *state)
45089517SBill.Taylor@Sun.COM {
45099517SBill.Taylor@Sun.COM int status;
45109517SBill.Taylor@Sun.COM int intr;
45119517SBill.Taylor@Sun.COM
45129517SBill.Taylor@Sun.COM for (intr = 0; intr < state->hs_intrmsi_allocd; intr++) {
45139517SBill.Taylor@Sun.COM
45149517SBill.Taylor@Sun.COM /* Free the allocated interrupt/MSI handle */
45159517SBill.Taylor@Sun.COM status = ddi_intr_free(state->hs_intrmsi_hdl[intr]);
45169517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
45179517SBill.Taylor@Sun.COM return (DDI_FAILURE);
45189517SBill.Taylor@Sun.COM }
45199517SBill.Taylor@Sun.COM }
452012965SWilliam.Taylor@Oracle.COM if (state->hs_intr_cb_hdl) {
452112965SWilliam.Taylor@Oracle.COM (void) ddi_cb_unregister(state->hs_intr_cb_hdl);
452212965SWilliam.Taylor@Oracle.COM state->hs_intr_cb_hdl = NULL;
452312965SWilliam.Taylor@Oracle.COM }
45249517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
45259517SBill.Taylor@Sun.COM }
45269517SBill.Taylor@Sun.COM
45279517SBill.Taylor@Sun.COM
45289517SBill.Taylor@Sun.COM /*ARGSUSED*/
45299517SBill.Taylor@Sun.COM void
hermon_pci_capability_msix(hermon_state_t * state,ddi_acc_handle_t hdl,uint_t offset)45309517SBill.Taylor@Sun.COM hermon_pci_capability_msix(hermon_state_t *state, ddi_acc_handle_t hdl,
45319517SBill.Taylor@Sun.COM uint_t offset)
45329517SBill.Taylor@Sun.COM {
45339517SBill.Taylor@Sun.COM uint32_t msix_data;
45349517SBill.Taylor@Sun.COM uint16_t msg_cntr;
45359517SBill.Taylor@Sun.COM uint32_t t_offset; /* table offset */
45369517SBill.Taylor@Sun.COM uint32_t t_bir;
45379517SBill.Taylor@Sun.COM uint32_t p_offset; /* pba */
45389517SBill.Taylor@Sun.COM uint32_t p_bir;
45399517SBill.Taylor@Sun.COM int t_size; /* size in entries - each is 4 dwords */
45409517SBill.Taylor@Sun.COM
45419517SBill.Taylor@Sun.COM /* come in with offset pointing at the capability structure */
45429517SBill.Taylor@Sun.COM
45439517SBill.Taylor@Sun.COM msix_data = pci_config_get32(hdl, offset);
45449517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "Full cap structure dword = %X\n", msix_data);
45459517SBill.Taylor@Sun.COM msg_cntr = pci_config_get16(hdl, offset+2);
45469517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "MSIX msg_control = %X\n", msg_cntr);
45479517SBill.Taylor@Sun.COM offset += 4;
45489517SBill.Taylor@Sun.COM msix_data = pci_config_get32(hdl, offset); /* table info */
45499517SBill.Taylor@Sun.COM t_offset = (msix_data & 0xFFF8) >> 3;
45509517SBill.Taylor@Sun.COM t_bir = msix_data & 0x07;
45519517SBill.Taylor@Sun.COM offset += 4;
45529517SBill.Taylor@Sun.COM cmn_err(CE_CONT, " table %X --offset = %X, bir(bar) = %X\n",
45539517SBill.Taylor@Sun.COM msix_data, t_offset, t_bir);
45549517SBill.Taylor@Sun.COM msix_data = pci_config_get32(hdl, offset); /* PBA info */
45559517SBill.Taylor@Sun.COM p_offset = (msix_data & 0xFFF8) >> 3;
45569517SBill.Taylor@Sun.COM p_bir = msix_data & 0x07;
45579517SBill.Taylor@Sun.COM
45589517SBill.Taylor@Sun.COM cmn_err(CE_CONT, " PBA %X --offset = %X, bir(bar) = %X\n",
45599517SBill.Taylor@Sun.COM msix_data, p_offset, p_bir);
45609517SBill.Taylor@Sun.COM t_size = msg_cntr & 0x7FF; /* low eleven bits */
45619517SBill.Taylor@Sun.COM cmn_err(CE_CONT, " table size = %X entries\n", t_size);
45629517SBill.Taylor@Sun.COM
45639517SBill.Taylor@Sun.COM offset = t_offset; /* reuse this for offset from BAR */
45649517SBill.Taylor@Sun.COM #ifdef HERMON_SUPPORTS_MSIX_BAR
45659517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "First 2 table entries behind BAR2 \n");
45669517SBill.Taylor@Sun.COM for (i = 0; i < 2; i++) {
45679517SBill.Taylor@Sun.COM for (j = 0; j < 4; j++, offset += 4) {
45689517SBill.Taylor@Sun.COM msix_data = ddi_get32(state->hs_reg_msihdl,
45699517SBill.Taylor@Sun.COM (uint32_t *)((uintptr_t)state->hs_reg_msi_baseaddr
45709517SBill.Taylor@Sun.COM + offset));
45719517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "MSI table entry %d, dword %d == %X\n",
45729517SBill.Taylor@Sun.COM i, j, msix_data);
45739517SBill.Taylor@Sun.COM }
45749517SBill.Taylor@Sun.COM }
45759517SBill.Taylor@Sun.COM #endif
45769517SBill.Taylor@Sun.COM
45779517SBill.Taylor@Sun.COM }
45789517SBill.Taylor@Sun.COM
45799517SBill.Taylor@Sun.COM /*
45809517SBill.Taylor@Sun.COM * X86 fastreboot support functions.
45819517SBill.Taylor@Sun.COM * These functions are used to save/restore MSI-X table/PBA and also
45829517SBill.Taylor@Sun.COM * to disable MSI-X interrupts in hermon_quiesce().
45839517SBill.Taylor@Sun.COM */
45849517SBill.Taylor@Sun.COM
45859517SBill.Taylor@Sun.COM /* Return the message control for MSI-X */
45869517SBill.Taylor@Sun.COM static ushort_t
get_msix_ctrl(dev_info_t * dip)45879517SBill.Taylor@Sun.COM get_msix_ctrl(dev_info_t *dip)
45889517SBill.Taylor@Sun.COM {
45899517SBill.Taylor@Sun.COM ushort_t msix_ctrl = 0, caps_ctrl = 0;
45909517SBill.Taylor@Sun.COM hermon_state_t *state = ddi_get_soft_state(hermon_statep,
45919517SBill.Taylor@Sun.COM DEVI(dip)->devi_instance);
45929517SBill.Taylor@Sun.COM ddi_acc_handle_t pci_cfg_hdl = hermon_get_pcihdl(state);
45939517SBill.Taylor@Sun.COM ASSERT(pci_cfg_hdl != NULL);
45949517SBill.Taylor@Sun.COM
45959517SBill.Taylor@Sun.COM if ((PCI_CAP_LOCATE(pci_cfg_hdl,
45969517SBill.Taylor@Sun.COM PCI_CAP_ID_MSI_X, &caps_ctrl) == DDI_SUCCESS)) {
45979517SBill.Taylor@Sun.COM if ((msix_ctrl = PCI_CAP_GET16(pci_cfg_hdl, NULL, caps_ctrl,
45989517SBill.Taylor@Sun.COM PCI_MSIX_CTRL)) == PCI_CAP_EINVAL16)
45999517SBill.Taylor@Sun.COM return (0);
46009517SBill.Taylor@Sun.COM }
46019517SBill.Taylor@Sun.COM ASSERT(msix_ctrl != 0);
46029517SBill.Taylor@Sun.COM
46039517SBill.Taylor@Sun.COM return (msix_ctrl);
46049517SBill.Taylor@Sun.COM }
46059517SBill.Taylor@Sun.COM
46069517SBill.Taylor@Sun.COM /* Return the MSI-X table size */
46079517SBill.Taylor@Sun.COM static size_t
get_msix_tbl_size(dev_info_t * dip)46089517SBill.Taylor@Sun.COM get_msix_tbl_size(dev_info_t *dip)
46099517SBill.Taylor@Sun.COM {
46109517SBill.Taylor@Sun.COM ushort_t msix_ctrl = get_msix_ctrl(dip);
46119517SBill.Taylor@Sun.COM ASSERT(msix_ctrl != 0);
46129517SBill.Taylor@Sun.COM
46139517SBill.Taylor@Sun.COM return (((msix_ctrl & PCI_MSIX_TBL_SIZE_MASK) + 1) *
46149517SBill.Taylor@Sun.COM PCI_MSIX_VECTOR_SIZE);
46159517SBill.Taylor@Sun.COM }
46169517SBill.Taylor@Sun.COM
46179517SBill.Taylor@Sun.COM /* Return the MSI-X PBA size */
46189517SBill.Taylor@Sun.COM static size_t
get_msix_pba_size(dev_info_t * dip)46199517SBill.Taylor@Sun.COM get_msix_pba_size(dev_info_t *dip)
46209517SBill.Taylor@Sun.COM {
46219517SBill.Taylor@Sun.COM ushort_t msix_ctrl = get_msix_ctrl(dip);
46229517SBill.Taylor@Sun.COM ASSERT(msix_ctrl != 0);
46239517SBill.Taylor@Sun.COM
46249517SBill.Taylor@Sun.COM return (((msix_ctrl & PCI_MSIX_TBL_SIZE_MASK) + 64) / 64 * 8);
46259517SBill.Taylor@Sun.COM }
46269517SBill.Taylor@Sun.COM
46279517SBill.Taylor@Sun.COM /* Set up the MSI-X table/PBA save area */
46289517SBill.Taylor@Sun.COM static void
hermon_set_msix_info(hermon_state_t * state)46299517SBill.Taylor@Sun.COM hermon_set_msix_info(hermon_state_t *state)
46309517SBill.Taylor@Sun.COM {
46319517SBill.Taylor@Sun.COM uint_t rnumber, breg, nregs;
46329517SBill.Taylor@Sun.COM ushort_t caps_ctrl, msix_ctrl;
46339517SBill.Taylor@Sun.COM pci_regspec_t *rp;
46349517SBill.Taylor@Sun.COM int reg_size, addr_space, offset, *regs_list, i;
46359517SBill.Taylor@Sun.COM
46369517SBill.Taylor@Sun.COM /*
46379517SBill.Taylor@Sun.COM * MSI-X BIR Index Table:
46389517SBill.Taylor@Sun.COM * BAR indicator register (BIR) to Base Address register.
46399517SBill.Taylor@Sun.COM */
46409517SBill.Taylor@Sun.COM uchar_t pci_msix_bir_index[8] = {0x10, 0x14, 0x18, 0x1c,
46419517SBill.Taylor@Sun.COM 0x20, 0x24, 0xff, 0xff};
46429517SBill.Taylor@Sun.COM
46439517SBill.Taylor@Sun.COM /* Fastreboot data access attribute */
46449517SBill.Taylor@Sun.COM ddi_device_acc_attr_t dev_attr = {
46459517SBill.Taylor@Sun.COM 0, /* version */
46469517SBill.Taylor@Sun.COM DDI_STRUCTURE_LE_ACC,
46479517SBill.Taylor@Sun.COM DDI_STRICTORDER_ACC, /* attr access */
46489517SBill.Taylor@Sun.COM 0
46499517SBill.Taylor@Sun.COM };
46509517SBill.Taylor@Sun.COM
46519517SBill.Taylor@Sun.COM ddi_acc_handle_t pci_cfg_hdl = hermon_get_pcihdl(state);
46529517SBill.Taylor@Sun.COM ASSERT(pci_cfg_hdl != NULL);
46539517SBill.Taylor@Sun.COM
46549517SBill.Taylor@Sun.COM if ((PCI_CAP_LOCATE(pci_cfg_hdl,
46559517SBill.Taylor@Sun.COM PCI_CAP_ID_MSI_X, &caps_ctrl) == DDI_SUCCESS)) {
46569517SBill.Taylor@Sun.COM if ((msix_ctrl = PCI_CAP_GET16(pci_cfg_hdl, NULL, caps_ctrl,
46579517SBill.Taylor@Sun.COM PCI_MSIX_CTRL)) == PCI_CAP_EINVAL16)
46589517SBill.Taylor@Sun.COM return;
46599517SBill.Taylor@Sun.COM }
46609517SBill.Taylor@Sun.COM ASSERT(msix_ctrl != 0);
46619517SBill.Taylor@Sun.COM
46629517SBill.Taylor@Sun.COM state->hs_msix_tbl_offset = PCI_CAP_GET32(pci_cfg_hdl, NULL, caps_ctrl,
46639517SBill.Taylor@Sun.COM PCI_MSIX_TBL_OFFSET);
46649517SBill.Taylor@Sun.COM
46659517SBill.Taylor@Sun.COM /* Get the BIR for MSI-X table */
46669517SBill.Taylor@Sun.COM breg = pci_msix_bir_index[state->hs_msix_tbl_offset &
46679517SBill.Taylor@Sun.COM PCI_MSIX_TBL_BIR_MASK];
46689517SBill.Taylor@Sun.COM ASSERT(breg != 0xFF);
46699517SBill.Taylor@Sun.COM
46709517SBill.Taylor@Sun.COM /* Set the MSI-X table offset */
46719517SBill.Taylor@Sun.COM state->hs_msix_tbl_offset = state->hs_msix_tbl_offset &
46729517SBill.Taylor@Sun.COM ~PCI_MSIX_TBL_BIR_MASK;
46739517SBill.Taylor@Sun.COM
46749517SBill.Taylor@Sun.COM /* Set the MSI-X table size */
46759517SBill.Taylor@Sun.COM state->hs_msix_tbl_size = ((msix_ctrl & PCI_MSIX_TBL_SIZE_MASK) + 1) *
46769517SBill.Taylor@Sun.COM PCI_MSIX_VECTOR_SIZE;
46779517SBill.Taylor@Sun.COM
46789517SBill.Taylor@Sun.COM if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, state->hs_dip,
46799517SBill.Taylor@Sun.COM DDI_PROP_DONTPASS, "reg", (int **)®s_list, &nregs) !=
46809517SBill.Taylor@Sun.COM DDI_PROP_SUCCESS) {
46819517SBill.Taylor@Sun.COM return;
46829517SBill.Taylor@Sun.COM }
46839517SBill.Taylor@Sun.COM reg_size = sizeof (pci_regspec_t) / sizeof (int);
46849517SBill.Taylor@Sun.COM
46859517SBill.Taylor@Sun.COM /* Check the register number for MSI-X table */
46869517SBill.Taylor@Sun.COM for (i = 1, rnumber = 0; i < nregs/reg_size; i++) {
46879517SBill.Taylor@Sun.COM rp = (pci_regspec_t *)®s_list[i * reg_size];
46889517SBill.Taylor@Sun.COM addr_space = rp->pci_phys_hi & PCI_ADDR_MASK;
46899517SBill.Taylor@Sun.COM offset = PCI_REG_REG_G(rp->pci_phys_hi);
46909517SBill.Taylor@Sun.COM
46919517SBill.Taylor@Sun.COM if ((offset == breg) && ((addr_space == PCI_ADDR_MEM32) ||
46929517SBill.Taylor@Sun.COM (addr_space == PCI_ADDR_MEM64))) {
46939517SBill.Taylor@Sun.COM rnumber = i;
46949517SBill.Taylor@Sun.COM break;
46959517SBill.Taylor@Sun.COM }
46969517SBill.Taylor@Sun.COM }
46979517SBill.Taylor@Sun.COM ASSERT(rnumber != 0);
46989517SBill.Taylor@Sun.COM state->hs_msix_tbl_rnumber = rnumber;
46999517SBill.Taylor@Sun.COM
47009517SBill.Taylor@Sun.COM /* Set device attribute version and access according to Hermon FM */
47019517SBill.Taylor@Sun.COM dev_attr.devacc_attr_version = hermon_devacc_attr_version(state);
47029517SBill.Taylor@Sun.COM dev_attr.devacc_attr_access = hermon_devacc_attr_access(state);
47039517SBill.Taylor@Sun.COM
47049517SBill.Taylor@Sun.COM /* Map the entire MSI-X vector table */
47059517SBill.Taylor@Sun.COM if (hermon_regs_map_setup(state, state->hs_msix_tbl_rnumber,
47069517SBill.Taylor@Sun.COM (caddr_t *)&state->hs_msix_tbl_addr, state->hs_msix_tbl_offset,
47079517SBill.Taylor@Sun.COM state->hs_msix_tbl_size, &dev_attr,
47089517SBill.Taylor@Sun.COM &state->hs_fm_msix_tblhdl) != DDI_SUCCESS) {
47099517SBill.Taylor@Sun.COM return;
47109517SBill.Taylor@Sun.COM }
47119517SBill.Taylor@Sun.COM
47129517SBill.Taylor@Sun.COM state->hs_msix_pba_offset = PCI_CAP_GET32(pci_cfg_hdl, NULL, caps_ctrl,
47139517SBill.Taylor@Sun.COM PCI_MSIX_PBA_OFFSET);
47149517SBill.Taylor@Sun.COM
47159517SBill.Taylor@Sun.COM /* Get the BIR for MSI-X PBA */
47169517SBill.Taylor@Sun.COM breg = pci_msix_bir_index[state->hs_msix_pba_offset &
47179517SBill.Taylor@Sun.COM PCI_MSIX_PBA_BIR_MASK];
47189517SBill.Taylor@Sun.COM ASSERT(breg != 0xFF);
47199517SBill.Taylor@Sun.COM
47209517SBill.Taylor@Sun.COM /* Set the MSI-X PBA offset */
47219517SBill.Taylor@Sun.COM state->hs_msix_pba_offset = state->hs_msix_pba_offset &
47229517SBill.Taylor@Sun.COM ~PCI_MSIX_PBA_BIR_MASK;
47239517SBill.Taylor@Sun.COM
47249517SBill.Taylor@Sun.COM /* Set the MSI-X PBA size */
47259517SBill.Taylor@Sun.COM state->hs_msix_pba_size =
47269517SBill.Taylor@Sun.COM ((msix_ctrl & PCI_MSIX_TBL_SIZE_MASK) + 64) / 64 * 8;
47279517SBill.Taylor@Sun.COM
47289517SBill.Taylor@Sun.COM /* Check the register number for MSI-X PBA */
47299517SBill.Taylor@Sun.COM for (i = 1, rnumber = 0; i < nregs/reg_size; i++) {
47309517SBill.Taylor@Sun.COM rp = (pci_regspec_t *)®s_list[i * reg_size];
47319517SBill.Taylor@Sun.COM addr_space = rp->pci_phys_hi & PCI_ADDR_MASK;
47329517SBill.Taylor@Sun.COM offset = PCI_REG_REG_G(rp->pci_phys_hi);
47339517SBill.Taylor@Sun.COM
47349517SBill.Taylor@Sun.COM if ((offset == breg) && ((addr_space == PCI_ADDR_MEM32) ||
47359517SBill.Taylor@Sun.COM (addr_space == PCI_ADDR_MEM64))) {
47369517SBill.Taylor@Sun.COM rnumber = i;
47379517SBill.Taylor@Sun.COM break;
47389517SBill.Taylor@Sun.COM }
47399517SBill.Taylor@Sun.COM }
47409517SBill.Taylor@Sun.COM ASSERT(rnumber != 0);
47419517SBill.Taylor@Sun.COM state->hs_msix_pba_rnumber = rnumber;
474212688SWilliam.Taylor@Oracle.COM ddi_prop_free(regs_list);
47439517SBill.Taylor@Sun.COM
47449517SBill.Taylor@Sun.COM /* Map in the MSI-X Pending Bit Array */
47459517SBill.Taylor@Sun.COM if (hermon_regs_map_setup(state, state->hs_msix_pba_rnumber,
47469517SBill.Taylor@Sun.COM (caddr_t *)&state->hs_msix_pba_addr, state->hs_msix_pba_offset,
47479517SBill.Taylor@Sun.COM state->hs_msix_pba_size, &dev_attr,
47489517SBill.Taylor@Sun.COM &state->hs_fm_msix_pbahdl) != DDI_SUCCESS) {
47499517SBill.Taylor@Sun.COM hermon_regs_map_free(state, &state->hs_fm_msix_tblhdl);
47509517SBill.Taylor@Sun.COM state->hs_fm_msix_tblhdl = NULL;
47519517SBill.Taylor@Sun.COM return;
47529517SBill.Taylor@Sun.COM }
47539517SBill.Taylor@Sun.COM
47549517SBill.Taylor@Sun.COM /* Set the MSI-X table save area */
47559517SBill.Taylor@Sun.COM state->hs_msix_tbl_entries = kmem_alloc(state->hs_msix_tbl_size,
47569517SBill.Taylor@Sun.COM KM_SLEEP);
47579517SBill.Taylor@Sun.COM
47589517SBill.Taylor@Sun.COM /* Set the MSI-X PBA save area */
47599517SBill.Taylor@Sun.COM state->hs_msix_pba_entries = kmem_alloc(state->hs_msix_pba_size,
47609517SBill.Taylor@Sun.COM KM_SLEEP);
47619517SBill.Taylor@Sun.COM }
47629517SBill.Taylor@Sun.COM
47639517SBill.Taylor@Sun.COM /* Disable Hermon interrupts */
47649517SBill.Taylor@Sun.COM static int
hermon_intr_disable(hermon_state_t * state)47659517SBill.Taylor@Sun.COM hermon_intr_disable(hermon_state_t *state)
47669517SBill.Taylor@Sun.COM {
47679517SBill.Taylor@Sun.COM ushort_t msix_ctrl = 0, caps_ctrl = 0;
47689517SBill.Taylor@Sun.COM ddi_acc_handle_t pci_cfg_hdl = hermon_get_pcihdl(state);
47699517SBill.Taylor@Sun.COM ddi_acc_handle_t msix_tblhdl = hermon_get_msix_tblhdl(state);
47709517SBill.Taylor@Sun.COM int i, j;
47719517SBill.Taylor@Sun.COM ASSERT(pci_cfg_hdl != NULL && msix_tblhdl != NULL);
47729517SBill.Taylor@Sun.COM ASSERT(state->hs_intr_types_avail &
47739517SBill.Taylor@Sun.COM (DDI_INTR_TYPE_FIXED | DDI_INTR_TYPE_MSI | DDI_INTR_TYPE_MSIX));
47749517SBill.Taylor@Sun.COM
47759517SBill.Taylor@Sun.COM /*
47769517SBill.Taylor@Sun.COM * Check if MSI-X interrupts are used. If so, disable MSI-X interupts.
47779517SBill.Taylor@Sun.COM * If not, since Hermon doesn't support MSI interrupts, assuming the
47789517SBill.Taylor@Sun.COM * legacy interrupt is used instead, disable the legacy interrupt.
47799517SBill.Taylor@Sun.COM */
47809517SBill.Taylor@Sun.COM if ((state->hs_cfg_profile->cp_use_msi_if_avail != 0) &&
47819517SBill.Taylor@Sun.COM (state->hs_intr_types_avail & DDI_INTR_TYPE_MSIX)) {
47829517SBill.Taylor@Sun.COM
47839517SBill.Taylor@Sun.COM if ((PCI_CAP_LOCATE(pci_cfg_hdl,
47849517SBill.Taylor@Sun.COM PCI_CAP_ID_MSI_X, &caps_ctrl) == DDI_SUCCESS)) {
47859517SBill.Taylor@Sun.COM if ((msix_ctrl = PCI_CAP_GET16(pci_cfg_hdl, NULL,
47869517SBill.Taylor@Sun.COM caps_ctrl, PCI_MSIX_CTRL)) == PCI_CAP_EINVAL16)
47879517SBill.Taylor@Sun.COM return (DDI_FAILURE);
47889517SBill.Taylor@Sun.COM }
47899517SBill.Taylor@Sun.COM ASSERT(msix_ctrl != 0);
47909517SBill.Taylor@Sun.COM
47919517SBill.Taylor@Sun.COM if (!(msix_ctrl & PCI_MSIX_ENABLE_BIT))
47929517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
47939517SBill.Taylor@Sun.COM
47949517SBill.Taylor@Sun.COM /* Clear all inums in MSI-X table */
47959517SBill.Taylor@Sun.COM for (i = 0; i < get_msix_tbl_size(state->hs_dip);
47969517SBill.Taylor@Sun.COM i += PCI_MSIX_VECTOR_SIZE) {
47979517SBill.Taylor@Sun.COM for (j = 0; j < PCI_MSIX_VECTOR_SIZE; j += 4) {
47989517SBill.Taylor@Sun.COM char *addr = state->hs_msix_tbl_addr + i + j;
47999517SBill.Taylor@Sun.COM ddi_put32(msix_tblhdl,
48009517SBill.Taylor@Sun.COM (uint32_t *)(uintptr_t)addr, 0x0);
48019517SBill.Taylor@Sun.COM }
48029517SBill.Taylor@Sun.COM }
48039517SBill.Taylor@Sun.COM
48049517SBill.Taylor@Sun.COM /* Disable MSI-X interrupts */
48059517SBill.Taylor@Sun.COM msix_ctrl &= ~PCI_MSIX_ENABLE_BIT;
48069517SBill.Taylor@Sun.COM PCI_CAP_PUT16(pci_cfg_hdl, NULL, caps_ctrl, PCI_MSIX_CTRL,
48079517SBill.Taylor@Sun.COM msix_ctrl);
48089517SBill.Taylor@Sun.COM
48099517SBill.Taylor@Sun.COM } else {
48109517SBill.Taylor@Sun.COM uint16_t cmdreg = pci_config_get16(pci_cfg_hdl, PCI_CONF_COMM);
48119517SBill.Taylor@Sun.COM ASSERT(state->hs_intr_types_avail & DDI_INTR_TYPE_FIXED);
48129517SBill.Taylor@Sun.COM
48139517SBill.Taylor@Sun.COM /* Disable the legacy interrupts */
48149517SBill.Taylor@Sun.COM cmdreg |= PCI_COMM_INTX_DISABLE;
48159517SBill.Taylor@Sun.COM pci_config_put16(pci_cfg_hdl, PCI_CONF_COMM, cmdreg);
48169517SBill.Taylor@Sun.COM }
48179517SBill.Taylor@Sun.COM
48189517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
48199517SBill.Taylor@Sun.COM }
48209517SBill.Taylor@Sun.COM
48219517SBill.Taylor@Sun.COM /* Hermon quiesce(9F) entry */
48229517SBill.Taylor@Sun.COM static int
hermon_quiesce(dev_info_t * dip)48239517SBill.Taylor@Sun.COM hermon_quiesce(dev_info_t *dip)
48249517SBill.Taylor@Sun.COM {
48259517SBill.Taylor@Sun.COM hermon_state_t *state = ddi_get_soft_state(hermon_statep,
48269517SBill.Taylor@Sun.COM DEVI(dip)->devi_instance);
48279517SBill.Taylor@Sun.COM ddi_acc_handle_t pcihdl = hermon_get_pcihdl(state);
48289517SBill.Taylor@Sun.COM ddi_acc_handle_t cmdhdl = hermon_get_cmdhdl(state);
48299517SBill.Taylor@Sun.COM ddi_acc_handle_t msix_tbl_hdl = hermon_get_msix_tblhdl(state);
48309517SBill.Taylor@Sun.COM ddi_acc_handle_t msix_pba_hdl = hermon_get_msix_pbahdl(state);
48319517SBill.Taylor@Sun.COM uint32_t sem, reset_delay = state->hs_cfg_profile->cp_sw_reset_delay;
48329517SBill.Taylor@Sun.COM uint64_t data64;
48339517SBill.Taylor@Sun.COM uint32_t data32;
48349517SBill.Taylor@Sun.COM int status, i, j, loopcnt;
48359517SBill.Taylor@Sun.COM uint_t offset;
48369517SBill.Taylor@Sun.COM
48379517SBill.Taylor@Sun.COM ASSERT(state != NULL);
48389517SBill.Taylor@Sun.COM
48399517SBill.Taylor@Sun.COM /* start fastreboot */
48409517SBill.Taylor@Sun.COM state->hs_quiescing = B_TRUE;
48419517SBill.Taylor@Sun.COM
48429778SEiji.Ota@Sun.COM /* If it's in maintenance mode, do nothing but return with SUCCESS */
48439778SEiji.Ota@Sun.COM if (!HERMON_IS_OPERATIONAL(state->hs_operational_mode)) {
48449778SEiji.Ota@Sun.COM return (DDI_SUCCESS);
48459778SEiji.Ota@Sun.COM }
48469778SEiji.Ota@Sun.COM
48479517SBill.Taylor@Sun.COM /* suppress Hermon FM ereports */
48489517SBill.Taylor@Sun.COM if (hermon_get_state(state) & HCA_EREPORT_FM) {
48499517SBill.Taylor@Sun.COM hermon_clr_state_nolock(state, HCA_EREPORT_FM);
48509517SBill.Taylor@Sun.COM }
48519517SBill.Taylor@Sun.COM
48529517SBill.Taylor@Sun.COM /* Shutdown HCA ports */
48539517SBill.Taylor@Sun.COM if (hermon_hca_ports_shutdown(state,
48549517SBill.Taylor@Sun.COM state->hs_cfg_profile->cp_num_ports) != HERMON_CMD_SUCCESS) {
48559517SBill.Taylor@Sun.COM state->hs_quiescing = B_FALSE;
48569517SBill.Taylor@Sun.COM return (DDI_FAILURE);
48579517SBill.Taylor@Sun.COM }
48589517SBill.Taylor@Sun.COM
48599517SBill.Taylor@Sun.COM /* Close HCA */
48609517SBill.Taylor@Sun.COM if (hermon_close_hca_cmd_post(state, HERMON_CMD_NOSLEEP_SPIN) !=
48619517SBill.Taylor@Sun.COM HERMON_CMD_SUCCESS) {
48629517SBill.Taylor@Sun.COM state->hs_quiescing = B_FALSE;
48639517SBill.Taylor@Sun.COM return (DDI_FAILURE);
48649517SBill.Taylor@Sun.COM }
48659517SBill.Taylor@Sun.COM
48669517SBill.Taylor@Sun.COM /* Disable interrupts */
48679517SBill.Taylor@Sun.COM if (hermon_intr_disable(state) != DDI_SUCCESS) {
48689517SBill.Taylor@Sun.COM state->hs_quiescing = B_FALSE;
48699517SBill.Taylor@Sun.COM return (DDI_FAILURE);
48709517SBill.Taylor@Sun.COM }
48719517SBill.Taylor@Sun.COM
48729517SBill.Taylor@Sun.COM /*
48739517SBill.Taylor@Sun.COM * Query the PCI capabilities of the HCA device, but don't process
48749517SBill.Taylor@Sun.COM * the VPD until after reset.
48759517SBill.Taylor@Sun.COM */
48769517SBill.Taylor@Sun.COM if (hermon_pci_capability_list(state, pcihdl) != DDI_SUCCESS) {
48779517SBill.Taylor@Sun.COM state->hs_quiescing = B_FALSE;
48789517SBill.Taylor@Sun.COM return (DDI_FAILURE);
48799517SBill.Taylor@Sun.COM }
48809517SBill.Taylor@Sun.COM
48819517SBill.Taylor@Sun.COM /*
48829517SBill.Taylor@Sun.COM * Read all PCI config info (reg0...reg63). Note: According to the
48839517SBill.Taylor@Sun.COM * Hermon software reset application note, we should not read or
48849517SBill.Taylor@Sun.COM * restore the values in reg22 and reg23.
48859517SBill.Taylor@Sun.COM * NOTE: For Hermon (and Arbel too) it says to restore the command
48869517SBill.Taylor@Sun.COM * register LAST, and technically, you need to restore the
48879517SBill.Taylor@Sun.COM * PCIE Capability "device control" and "link control" (word-sized,
48889517SBill.Taylor@Sun.COM * at offsets 0x08 and 0x10 from the capbility ID respectively).
48899517SBill.Taylor@Sun.COM * We hold off restoring the command register - offset 0x4 - till last
48909517SBill.Taylor@Sun.COM */
48919517SBill.Taylor@Sun.COM
48929517SBill.Taylor@Sun.COM /* 1st, wait for the semaphore assure accessibility - per PRM */
48939517SBill.Taylor@Sun.COM status = -1;
48949517SBill.Taylor@Sun.COM for (i = 0; i < NANOSEC/MICROSEC /* 1sec timeout */; i++) {
48959517SBill.Taylor@Sun.COM sem = ddi_get32(cmdhdl, state->hs_cmd_regs.sw_semaphore);
48969517SBill.Taylor@Sun.COM if (sem == 0) {
48979517SBill.Taylor@Sun.COM status = 0;
48989517SBill.Taylor@Sun.COM break;
48999517SBill.Taylor@Sun.COM }
49009517SBill.Taylor@Sun.COM drv_usecwait(1);
49019517SBill.Taylor@Sun.COM }
49029517SBill.Taylor@Sun.COM
49039517SBill.Taylor@Sun.COM /* Check if timeout happens */
49049517SBill.Taylor@Sun.COM if (status == -1) {
49059517SBill.Taylor@Sun.COM state->hs_quiescing = B_FALSE;
49069517SBill.Taylor@Sun.COM return (DDI_FAILURE);
49079517SBill.Taylor@Sun.COM }
49089517SBill.Taylor@Sun.COM
49099517SBill.Taylor@Sun.COM /* MSI-X interrupts are used, save the MSI-X table */
49109517SBill.Taylor@Sun.COM if (msix_tbl_hdl && msix_pba_hdl) {
49119517SBill.Taylor@Sun.COM /* save MSI-X table */
49129517SBill.Taylor@Sun.COM for (i = 0; i < get_msix_tbl_size(state->hs_dip);
49139517SBill.Taylor@Sun.COM i += PCI_MSIX_VECTOR_SIZE) {
49149517SBill.Taylor@Sun.COM for (j = 0; j < PCI_MSIX_VECTOR_SIZE; j += 4) {
49159517SBill.Taylor@Sun.COM char *addr = state->hs_msix_tbl_addr + i + j;
49169517SBill.Taylor@Sun.COM data32 = ddi_get32(msix_tbl_hdl,
49179517SBill.Taylor@Sun.COM (uint32_t *)(uintptr_t)addr);
49189517SBill.Taylor@Sun.COM *(uint32_t *)(uintptr_t)(state->
49199517SBill.Taylor@Sun.COM hs_msix_tbl_entries + i + j) = data32;
49209517SBill.Taylor@Sun.COM }
49219517SBill.Taylor@Sun.COM }
49229517SBill.Taylor@Sun.COM /* save MSI-X PBA */
49239517SBill.Taylor@Sun.COM for (i = 0; i < get_msix_pba_size(state->hs_dip); i += 8) {
49249517SBill.Taylor@Sun.COM char *addr = state->hs_msix_pba_addr + i;
49259517SBill.Taylor@Sun.COM data64 = ddi_get64(msix_pba_hdl,
49269517SBill.Taylor@Sun.COM (uint64_t *)(uintptr_t)addr);
49279517SBill.Taylor@Sun.COM *(uint64_t *)(uintptr_t)(state->
49289517SBill.Taylor@Sun.COM hs_msix_pba_entries + i) = data64;
49299517SBill.Taylor@Sun.COM }
49309517SBill.Taylor@Sun.COM }
49319517SBill.Taylor@Sun.COM
49329517SBill.Taylor@Sun.COM /* save PCI config space */
49339517SBill.Taylor@Sun.COM for (i = 0; i < HERMON_SW_RESET_NUMREGS; i++) {
49349517SBill.Taylor@Sun.COM if ((i != HERMON_SW_RESET_REG22_RSVD) &&
49359517SBill.Taylor@Sun.COM (i != HERMON_SW_RESET_REG23_RSVD)) {
49369517SBill.Taylor@Sun.COM state->hs_cfg_data[i] =
49379517SBill.Taylor@Sun.COM pci_config_get32(pcihdl, i << 2);
49389517SBill.Taylor@Sun.COM }
49399517SBill.Taylor@Sun.COM }
49409517SBill.Taylor@Sun.COM
49419517SBill.Taylor@Sun.COM /* SW-reset HCA */
49429517SBill.Taylor@Sun.COM ddi_put32(cmdhdl, state->hs_cmd_regs.sw_reset, HERMON_SW_RESET_START);
49439517SBill.Taylor@Sun.COM
49449517SBill.Taylor@Sun.COM /*
49459517SBill.Taylor@Sun.COM * This delay is required so as not to cause a panic here. If the
49469517SBill.Taylor@Sun.COM * device is accessed too soon after reset it will not respond to
49479517SBill.Taylor@Sun.COM * config cycles, causing a Master Abort and panic.
49489517SBill.Taylor@Sun.COM */
49499517SBill.Taylor@Sun.COM drv_usecwait(reset_delay);
49509517SBill.Taylor@Sun.COM
49519517SBill.Taylor@Sun.COM /* Poll waiting for the device to finish resetting */
49529517SBill.Taylor@Sun.COM loopcnt = 100; /* 100 times @ 100 usec - total delay 10 msec */
49539517SBill.Taylor@Sun.COM while ((pci_config_get32(pcihdl, 0) & 0x0000FFFF) != PCI_VENID_MLX) {
49549517SBill.Taylor@Sun.COM drv_usecwait(HERMON_SW_RESET_POLL_DELAY);
49559517SBill.Taylor@Sun.COM if (--loopcnt == 0)
49569517SBill.Taylor@Sun.COM break; /* just in case, break and go on */
49579517SBill.Taylor@Sun.COM }
49589517SBill.Taylor@Sun.COM if (loopcnt == 0) {
49599517SBill.Taylor@Sun.COM state->hs_quiescing = B_FALSE;
49609517SBill.Taylor@Sun.COM return (DDI_FAILURE);
49619517SBill.Taylor@Sun.COM }
49629517SBill.Taylor@Sun.COM
49639517SBill.Taylor@Sun.COM /* Restore the config info */
49649517SBill.Taylor@Sun.COM for (i = 0; i < HERMON_SW_RESET_NUMREGS; i++) {
49659517SBill.Taylor@Sun.COM if (i == 1) continue; /* skip the status/ctrl reg */
49669517SBill.Taylor@Sun.COM if ((i != HERMON_SW_RESET_REG22_RSVD) &&
49679517SBill.Taylor@Sun.COM (i != HERMON_SW_RESET_REG23_RSVD)) {
49689517SBill.Taylor@Sun.COM pci_config_put32(pcihdl, i << 2, state->hs_cfg_data[i]);
49699517SBill.Taylor@Sun.COM }
49709517SBill.Taylor@Sun.COM }
49719517SBill.Taylor@Sun.COM
49729517SBill.Taylor@Sun.COM /* If MSI-X interrupts are used, restore the MSI-X table */
49739517SBill.Taylor@Sun.COM if (msix_tbl_hdl && msix_pba_hdl) {
49749517SBill.Taylor@Sun.COM /* restore MSI-X PBA */
49759517SBill.Taylor@Sun.COM for (i = 0; i < get_msix_pba_size(state->hs_dip); i += 8) {
49769517SBill.Taylor@Sun.COM char *addr = state->hs_msix_pba_addr + i;
49779517SBill.Taylor@Sun.COM data64 = *(uint64_t *)(uintptr_t)
49789517SBill.Taylor@Sun.COM (state->hs_msix_pba_entries + i);
49799517SBill.Taylor@Sun.COM ddi_put64(msix_pba_hdl,
49809517SBill.Taylor@Sun.COM (uint64_t *)(uintptr_t)addr, data64);
49819517SBill.Taylor@Sun.COM }
49829517SBill.Taylor@Sun.COM /* restore MSI-X table */
49839517SBill.Taylor@Sun.COM for (i = 0; i < get_msix_tbl_size(state->hs_dip);
49849517SBill.Taylor@Sun.COM i += PCI_MSIX_VECTOR_SIZE) {
49859517SBill.Taylor@Sun.COM for (j = 0; j < PCI_MSIX_VECTOR_SIZE; j += 4) {
49869517SBill.Taylor@Sun.COM char *addr = state->hs_msix_tbl_addr + i + j;
49879517SBill.Taylor@Sun.COM data32 = *(uint32_t *)(uintptr_t)
49889517SBill.Taylor@Sun.COM (state->hs_msix_tbl_entries + i + j);
49899517SBill.Taylor@Sun.COM ddi_put32(msix_tbl_hdl,
49909517SBill.Taylor@Sun.COM (uint32_t *)(uintptr_t)addr, data32);
49919517SBill.Taylor@Sun.COM }
49929517SBill.Taylor@Sun.COM }
49939517SBill.Taylor@Sun.COM }
49949517SBill.Taylor@Sun.COM
49959517SBill.Taylor@Sun.COM /*
49969517SBill.Taylor@Sun.COM * PCI Express Capability - we saved during capability list, and
49979517SBill.Taylor@Sun.COM * we'll restore them here.
49989517SBill.Taylor@Sun.COM */
49999517SBill.Taylor@Sun.COM offset = state->hs_pci_cap_offset;
50009517SBill.Taylor@Sun.COM data32 = state->hs_pci_cap_devctl;
50019517SBill.Taylor@Sun.COM pci_config_put32(pcihdl, offset + HERMON_PCI_CAP_DEV_OFFS, data32);
50029517SBill.Taylor@Sun.COM data32 = state->hs_pci_cap_lnkctl;
50039517SBill.Taylor@Sun.COM pci_config_put32(pcihdl, offset + HERMON_PCI_CAP_LNK_OFFS, data32);
50049517SBill.Taylor@Sun.COM
50059517SBill.Taylor@Sun.COM /* restore the command register */
50069517SBill.Taylor@Sun.COM pci_config_put32(pcihdl, 0x04, (state->hs_cfg_data[1] | 0x0006));
50079517SBill.Taylor@Sun.COM
50089517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
50099517SBill.Taylor@Sun.COM }
5010