1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  * Copyright 2012 Milan Jurik. All rights reserved.
  25  */
  26 
  27 #include <hxge_impl.h>
  28 #include <hxge_vmac.h>
  29 #include <hxge_pfc.h>
  30 #include <hpi_pfc.h>
  31 
  32 static hxge_status_t hxge_get_mac_addr_properties(p_hxge_t);
  33 static void hxge_use_cfg_hydra_properties(p_hxge_t);
  34 static void hxge_use_cfg_dma_config(p_hxge_t);
  35 static void hxge_use_cfg_class_config(p_hxge_t);
  36 static void hxge_set_hw_dma_config(p_hxge_t);
  37 static void hxge_set_hw_class_config(p_hxge_t);
  38 static void hxge_ldgv_setup(p_hxge_ldg_t *ldgp, p_hxge_ldv_t *ldvp, uint8_t ldv,
  39         uint8_t endldg, int *ngrps);
  40 
  41 extern uint16_t hxge_rcr_timeout;
  42 extern uint16_t hxge_rcr_threshold;
  43 
  44 extern uint32_t hxge_rbr_size;
  45 extern uint32_t hxge_rcr_size;
  46 
  47 extern uint_t hxge_rx_intr(caddr_t, caddr_t);
  48 extern uint_t hxge_tx_intr(caddr_t, caddr_t);
  49 extern uint_t hxge_vmac_intr(caddr_t, caddr_t);
  50 extern uint_t hxge_syserr_intr(caddr_t, caddr_t);
  51 extern uint_t hxge_pfc_intr(caddr_t, caddr_t);
  52 
  53 /*
  54  * Entry point to populate configuration parameters into the master hxge
  55  * data structure and to update the NDD parameter list.
  56  */
  57 hxge_status_t
  58 hxge_get_config_properties(p_hxge_t hxgep)
  59 {
  60         hxge_status_t           status = HXGE_OK;
  61 
  62         HXGE_DEBUG_MSG((hxgep, VPD_CTL, " ==> hxge_get_config_properties"));
  63 
  64         if (hxgep->hxge_hw_p == NULL) {
  65                 HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
  66                     " hxge_get_config_properties: common hardware not set"));
  67                 return (HXGE_ERROR);
  68         }
  69 
  70         hxgep->classifier.tcam_size = TCAM_HXGE_TCAM_MAX_ENTRY;
  71 
  72         status = hxge_get_mac_addr_properties(hxgep);
  73         if (status != HXGE_OK) {
  74                 HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
  75                     " hxge_get_config_properties: mac addr properties failed"));
  76                 return (status);
  77         }
  78 
  79         HXGE_DEBUG_MSG((hxgep, VPD_CTL,
  80             " ==> hxge_get_config_properties: Hydra"));
  81 
  82         hxge_use_cfg_hydra_properties(hxgep);
  83 
  84         HXGE_DEBUG_MSG((hxgep, VPD_CTL, " <== hxge_get_config_properties"));
  85         return (HXGE_OK);
  86 }
  87 
  88 
  89 static void
  90 hxge_set_hw_vlan_class_config(p_hxge_t hxgep)
  91 {
  92         int                     i;
  93         p_hxge_param_t          param_arr;
  94         uint_t                  vlan_cnt;
  95         int                     *vlan_cfg_val;
  96         hxge_param_map_t        *vmap;
  97         char                    *prop;
  98         p_hxge_class_pt_cfg_t   p_class_cfgp;
  99         uint32_t                good_cfg[32];
 100         int                     good_count = 0;
 101         hxge_mv_cfg_t           *vlan_tbl;
 102 
 103         HXGE_DEBUG_MSG((hxgep, CFG_CTL, " ==> hxge_set_hw_vlan_config"));
 104         p_class_cfgp = (p_hxge_class_pt_cfg_t)&hxgep->class_config;
 105 
 106         param_arr = hxgep->param_arr;
 107         prop = param_arr[param_vlan_ids].fcode_name;
 108 
 109         /*
 110          * uint32_t array, each array entry specifying a VLAN id
 111          */
 112         for (i = 0; i <= VLAN_ID_MAX; i++) {
 113                 p_class_cfgp->vlan_tbl[i].flag = 0;
 114         }
 115 
 116         vlan_tbl = (hxge_mv_cfg_t *)&p_class_cfgp->vlan_tbl[0];
 117         if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, hxgep->dip, 0, prop,
 118             &vlan_cfg_val, &vlan_cnt) != DDI_PROP_SUCCESS) {
 119                 return;
 120         }
 121 
 122         for (i = 0; i < vlan_cnt; i++) {
 123                 vmap = (hxge_param_map_t *)&vlan_cfg_val[i];
 124                 if ((vmap->param_id) && (vmap->param_id <= VLAN_ID_MAX)) {
 125                         HXGE_DEBUG_MSG((hxgep, CFG2_CTL,
 126                             " hxge_vlan_config vlan id %d", vmap->param_id));
 127 
 128                         good_cfg[good_count] = vlan_cfg_val[i];
 129                         if (vlan_tbl[vmap->param_id].flag == 0)
 130                                 good_count++;
 131 
 132                         vlan_tbl[vmap->param_id].flag = 1;
 133                 }
 134         }
 135 
 136         ddi_prop_free(vlan_cfg_val);
 137         if (good_count != vlan_cnt) {
 138                 (void) ddi_prop_update_int_array(DDI_DEV_T_NONE,
 139                     hxgep->dip, prop, (int *)good_cfg, good_count);
 140         }
 141 
 142         HXGE_DEBUG_MSG((hxgep, CFG_CTL, " <== hxge_set_hw_vlan_config"));
 143 }
 144 
 145 
 146 /*
 147  * Read param_vlan_ids and param_implicit_vlan_id properties from either
 148  * hxge.conf or OBP. Update the soft properties. Populate these
 149  * properties into the hxge data structure.
 150  */
 151 static void
 152 hxge_use_cfg_vlan_class_config(p_hxge_t hxgep)
 153 {
 154         uint_t          vlan_cnt;
 155         int             *vlan_cfg_val;
 156         int             status;
 157         p_hxge_param_t  param_arr;
 158         char            *prop;
 159         uint32_t        implicit_vlan_id = 0;
 160         int             *int_prop_val;
 161         uint_t          prop_len;
 162         p_hxge_param_t  pa;
 163 
 164         HXGE_DEBUG_MSG((hxgep, CFG_CTL, " ==> hxge_use_cfg_vlan_config"));
 165         param_arr = hxgep->param_arr;
 166         prop = param_arr[param_vlan_ids].fcode_name;
 167 
 168         status = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, hxgep->dip, 0, prop,
 169             &vlan_cfg_val, &vlan_cnt);
 170         if (status == DDI_PROP_SUCCESS) {
 171                 status = ddi_prop_update_int_array(DDI_DEV_T_NONE,
 172                     hxgep->dip, prop, vlan_cfg_val, vlan_cnt);
 173                 ddi_prop_free(vlan_cfg_val);
 174         }
 175 
 176         pa = &param_arr[param_implicit_vlan_id];
 177         prop = pa->fcode_name;
 178         if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, hxgep->dip, 0, prop,
 179             &int_prop_val, &prop_len) == DDI_PROP_SUCCESS) {
 180                 implicit_vlan_id = (uint32_t)*int_prop_val;
 181                 if ((implicit_vlan_id >= pa->minimum) ||
 182                     (implicit_vlan_id <= pa->maximum)) {
 183                         status = ddi_prop_update_int(DDI_DEV_T_NONE, hxgep->dip,
 184                             prop, (int)implicit_vlan_id);
 185                 }
 186                 ddi_prop_free(int_prop_val);
 187         }
 188 
 189         hxge_set_hw_vlan_class_config(hxgep);
 190 
 191         HXGE_DEBUG_MSG((hxgep, CFG_CTL, " <== hxge_use_cfg_vlan_config"));
 192 }
 193 
 194 /*
 195  * Read in the configuration parameters from either hxge.conf or OBP and
 196  * populate the master data structure hxge.
 197  * Use these parameters to update the soft properties and the ndd array.
 198  */
 199 static void
 200 hxge_use_cfg_hydra_properties(p_hxge_t hxgep)
 201 {
 202         HXGE_DEBUG_MSG((hxgep, CFG_CTL, " ==> hxge_use_cfg_hydra_properties"));
 203 
 204         (void) hxge_use_cfg_dma_config(hxgep);
 205         (void) hxge_use_cfg_vlan_class_config(hxgep);
 206         (void) hxge_use_cfg_class_config(hxgep);
 207 
 208         /*
 209          * Read in the hardware (fcode) properties and use these properties
 210          * to update the ndd array.
 211          */
 212         (void) hxge_get_param_soft_properties(hxgep);
 213         HXGE_DEBUG_MSG((hxgep, CFG_CTL, " <== hxge_use_cfg_hydra_properties"));
 214 }
 215 
 216 
 217 /*
 218  * Read param_accept_jumbo, param_rxdma_intr_time, and param_rxdma_intr_pkts
 219  * from either hxge.conf or OBP.
 220  * Update the soft properties.
 221  * Populate these properties into the hxge data structure for latter use.
 222  */
 223 static void
 224 hxge_use_cfg_dma_config(p_hxge_t hxgep)
 225 {
 226         int                     tx_ndmas, rx_ndmas;
 227         p_hxge_dma_pt_cfg_t     p_dma_cfgp;
 228         p_hxge_hw_pt_cfg_t      p_cfgp;
 229         dev_info_t              *dip;
 230         p_hxge_param_t          param_arr;
 231         char                    *prop;
 232         int                     *prop_val;
 233         uint_t                  prop_len;
 234 
 235         HXGE_DEBUG_MSG((hxgep, CFG_CTL, " ==> hxge_use_cfg_dma_config"));
 236         param_arr = hxgep->param_arr;
 237 
 238         p_dma_cfgp = (p_hxge_dma_pt_cfg_t)&hxgep->pt_config;
 239         p_cfgp = (p_hxge_hw_pt_cfg_t)&p_dma_cfgp->hw_config;
 240         dip = hxgep->dip;
 241 
 242         tx_ndmas = 4;
 243         p_cfgp->start_tdc = 0;
 244         p_cfgp->max_tdcs =  hxgep->max_tdcs = tx_ndmas;
 245         hxgep->tdc_mask = (tx_ndmas - 1);
 246         HXGE_DEBUG_MSG((hxgep, CFG_CTL, "==> hxge_use_cfg_dma_config: "
 247             "p_cfgp 0x%llx max_tdcs %d hxgep->max_tdcs %d",
 248             p_cfgp, p_cfgp->max_tdcs, hxgep->max_tdcs));
 249 
 250         rx_ndmas = 4;
 251         p_cfgp->start_rdc = 0;
 252         p_cfgp->max_rdcs =  hxgep->max_rdcs = rx_ndmas;
 253 
 254         p_cfgp->start_ldg = 0;
 255         p_cfgp->max_ldgs = HXGE_INT_MAX_LDG;
 256 
 257         HXGE_DEBUG_MSG((hxgep, CFG_CTL, "==> hxge_use_default_dma_config: "
 258             "p_cfgp 0x%llx max_rdcs %d hxgep->max_rdcs %d",
 259             p_cfgp, p_cfgp->max_rdcs, hxgep->max_rdcs));
 260 
 261         HXGE_DEBUG_MSG((hxgep, CFG_CTL, "==> hxge_use_cfg_dma_config: "
 262             "p_cfgp 0x%016llx start_ldg %d hxgep->max_ldgs %d ",
 263             p_cfgp, p_cfgp->start_ldg,  p_cfgp->max_ldgs));
 264 
 265         /*
 266          * add code for individual rdc properties
 267          */
 268         prop = param_arr[param_accept_jumbo].fcode_name;
 269 
 270         if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 0, prop,
 271             &prop_val, &prop_len) == DDI_PROP_SUCCESS) {
 272                 if ((prop_len > 0) && (prop_len <= p_cfgp->max_rdcs)) {
 273                         (void) ddi_prop_update_int_array(DDI_DEV_T_NONE,
 274                             hxgep->dip, prop, prop_val, prop_len);
 275                 }
 276                 ddi_prop_free(prop_val);
 277         }
 278 
 279         prop = param_arr[param_rxdma_intr_time].fcode_name;
 280 
 281         if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 0, prop,
 282             &prop_val, &prop_len) == DDI_PROP_SUCCESS) {
 283                 if ((prop_len > 0) && (prop_len <= p_cfgp->max_rdcs)) {
 284                         (void) ddi_prop_update_int_array(DDI_DEV_T_NONE,
 285                             hxgep->dip, prop, prop_val, prop_len);
 286                 }
 287                 ddi_prop_free(prop_val);
 288         }
 289 
 290         prop = param_arr[param_rxdma_intr_pkts].fcode_name;
 291 
 292         if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 0, prop,
 293             &prop_val, &prop_len) == DDI_PROP_SUCCESS) {
 294                 if ((prop_len > 0) && (prop_len <= p_cfgp->max_rdcs)) {
 295                         (void) ddi_prop_update_int_array(DDI_DEV_T_NONE,
 296                             hxgep->dip, prop, prop_val, prop_len);
 297                 }
 298                 ddi_prop_free(prop_val);
 299         }
 300 
 301         hxge_set_hw_dma_config(hxgep);
 302         HXGE_DEBUG_MSG((hxgep, CFG_CTL, "<== hxge_use_cfg_dma_config"));
 303 }
 304 
 305 static void
 306 hxge_use_cfg_class_config(p_hxge_t hxgep)
 307 {
 308         hxge_set_hw_class_config(hxgep);
 309 }
 310 
 311 static void
 312 hxge_set_hw_dma_config(p_hxge_t hxgep)
 313 {
 314         p_hxge_dma_pt_cfg_t     p_dma_cfgp;
 315         p_hxge_hw_pt_cfg_t      p_cfgp;
 316 
 317         HXGE_DEBUG_MSG((hxgep, CFG_CTL, "==> hxge_set_hw_dma_config"));
 318 
 319         p_dma_cfgp = (p_hxge_dma_pt_cfg_t)&hxgep->pt_config;
 320         p_cfgp = (p_hxge_hw_pt_cfg_t)&p_dma_cfgp->hw_config;
 321 
 322         /* Transmit DMA Channels */
 323         hxgep->ntdc = p_cfgp->max_tdcs;
 324 
 325         /* Receive DMA Channels */
 326         hxgep->nrdc = p_cfgp->max_rdcs;
 327 
 328         p_dma_cfgp->rbr_size = hxge_rbr_size;
 329         if (hxge_rcr_size > HXGE_RCR_MAX)
 330                 hxge_rcr_size = HXGE_RCR_MAX;
 331         p_dma_cfgp->rcr_size = hxge_rcr_size;
 332 
 333         HXGE_DEBUG_MSG((hxgep, CFG_CTL, " <== hxge_set_hw_dma_config"));
 334 }
 335 
 336 
 337 boolean_t
 338 hxge_check_rxdma_port_member(p_hxge_t hxgep, uint8_t rdc)
 339 {
 340         p_hxge_dma_pt_cfg_t     p_dma_cfgp;
 341         p_hxge_hw_pt_cfg_t      p_cfgp;
 342         int                     status = B_TRUE;
 343 
 344         HXGE_DEBUG_MSG((hxgep, CFG2_CTL, "==> hxge_check_rxdma_port_member"));
 345 
 346         p_dma_cfgp = (p_hxge_dma_pt_cfg_t)&hxgep->pt_config;
 347         p_cfgp = (p_hxge_hw_pt_cfg_t)&p_dma_cfgp->hw_config;
 348 
 349         /* Receive DMA Channels */
 350         if (rdc < p_cfgp->max_rdcs)
 351                 status = B_TRUE;
 352         HXGE_DEBUG_MSG((hxgep, CFG2_CTL, " <== hxge_check_rxdma_port_member"));
 353 
 354         return (status);
 355 }
 356 
 357 boolean_t
 358 hxge_check_txdma_port_member(p_hxge_t hxgep, uint8_t tdc)
 359 {
 360         p_hxge_dma_pt_cfg_t     p_dma_cfgp;
 361         p_hxge_hw_pt_cfg_t      p_cfgp;
 362         int                     status = B_FALSE;
 363 
 364         HXGE_DEBUG_MSG((hxgep, CFG2_CTL, "==> hxge_check_txdma_port_member"));
 365 
 366         p_dma_cfgp = (p_hxge_dma_pt_cfg_t)&hxgep->pt_config;
 367         p_cfgp = (p_hxge_hw_pt_cfg_t)&p_dma_cfgp->hw_config;
 368 
 369         /* Receive DMA Channels */
 370         if (tdc < p_cfgp->max_tdcs)
 371                 status = B_TRUE;
 372         HXGE_DEBUG_MSG((hxgep, CFG2_CTL, " <== hxge_check_txdma_port_member"));
 373 
 374         return (status);
 375 }
 376 
 377 
 378 /*
 379  * Read the L2 classes, L3 classes, and initial hash from either hxge.conf
 380  * or OBP. Populate these properties into the hxge data structure for latter
 381  * use. Note that we are not updating these soft properties.
 382  */
 383 static void
 384 hxge_set_hw_class_config(p_hxge_t hxgep)
 385 {
 386         int                     i, j;
 387         p_hxge_param_t          param_arr;
 388         int                     *int_prop_val;
 389         uint32_t                cfg_value;
 390         char                    *prop;
 391         p_hxge_class_pt_cfg_t   p_class_cfgp;
 392         int                     start_prop, end_prop;
 393         uint_t                  prop_cnt;
 394 
 395         HXGE_DEBUG_MSG((hxgep, CFG_CTL, " ==> hxge_set_hw_class_config"));
 396 
 397         p_class_cfgp = (p_hxge_class_pt_cfg_t)&hxgep->class_config;
 398 
 399         param_arr = hxgep->param_arr;
 400 
 401         /*
 402          * L2 class configuration. User configurable ether types
 403          */
 404         start_prop =  param_class_cfg_ether_usr1;
 405         end_prop = param_class_cfg_ether_usr2;
 406 
 407         for (i = start_prop; i <= end_prop; i++) {
 408                 prop = param_arr[i].fcode_name;
 409                 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, hxgep->dip,
 410                     0, prop, &int_prop_val, &prop_cnt) == DDI_PROP_SUCCESS) {
 411                         cfg_value =  (uint32_t)*int_prop_val;
 412                         ddi_prop_free(int_prop_val);
 413                 } else {
 414                         cfg_value = (uint32_t)param_arr[i].value;
 415                 }
 416 
 417                 j = (i - start_prop) + TCAM_CLASS_ETYPE_1;
 418                 p_class_cfgp->class_cfg[j] = cfg_value;
 419         }
 420 
 421         /*
 422          * Use properties from either .conf or the NDD param array. Only bits
 423          * 2 and 3 are significant
 424          */
 425         start_prop =  param_class_opt_ipv4_tcp;
 426         end_prop = param_class_opt_ipv6_sctp;
 427 
 428         for (i = start_prop; i <= end_prop; i++) {
 429                 prop = param_arr[i].fcode_name;
 430                 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, hxgep->dip,
 431                     0, prop, &int_prop_val, &prop_cnt) == DDI_PROP_SUCCESS) {
 432                         cfg_value =  (uint32_t)*int_prop_val;
 433                         ddi_prop_free(int_prop_val);
 434                 } else {
 435                         cfg_value = (uint32_t)param_arr[i].value;
 436                 }
 437 
 438                 j = (i - start_prop) + TCAM_CLASS_TCP_IPV4;
 439                 p_class_cfgp->class_cfg[j] = cfg_value;
 440         }
 441 
 442         prop = param_arr[param_hash_init_value].fcode_name;
 443 
 444         if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, hxgep->dip, 0, prop,
 445             &int_prop_val, &prop_cnt) == DDI_PROP_SUCCESS) {
 446                 cfg_value =  (uint32_t)*int_prop_val;
 447                 ddi_prop_free(int_prop_val);
 448         } else {
 449                 cfg_value = (uint32_t)param_arr[param_hash_init_value].value;
 450         }
 451 
 452         p_class_cfgp->init_hash = (uint32_t)cfg_value;
 453 
 454         HXGE_DEBUG_MSG((hxgep, CFG_CTL, " <== hxge_set_hw_class_config"));
 455 }
 456 
 457 
 458 /*
 459  * Interrupts related interface functions.
 460  */
 461 hxge_status_t
 462 hxge_ldgv_init(p_hxge_t hxgep, int *navail_p, int *nrequired_p)
 463 {
 464         uint8_t                 ldv, i, maxldvs, maxldgs, start, end, nldvs;
 465         int                     ldg, endldg, ngrps;
 466         uint8_t                 channel;
 467         p_hxge_dma_pt_cfg_t     p_dma_cfgp;
 468         p_hxge_hw_pt_cfg_t      p_cfgp;
 469         p_hxge_ldgv_t           ldgvp;
 470         p_hxge_ldg_t            ldgp, ptr;
 471         p_hxge_ldv_t            ldvp;
 472         hxge_status_t           status = HXGE_OK;
 473         peu_intr_mask_t         parity_err_mask;
 474 
 475         HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_ldgv_init"));
 476         if (!*navail_p) {
 477                 *nrequired_p = 0;
 478                 HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
 479                     "<== hxge_ldgv_init:no avail"));
 480                 return (HXGE_ERROR);
 481         }
 482         p_dma_cfgp = (p_hxge_dma_pt_cfg_t)&hxgep->pt_config;
 483         p_cfgp = (p_hxge_hw_pt_cfg_t)&p_dma_cfgp->hw_config;
 484 
 485         /* each DMA channels */
 486         nldvs = p_cfgp->max_tdcs + p_cfgp->max_rdcs;
 487 
 488         /* vmac */
 489         nldvs++;
 490 
 491         /* pfc */
 492         nldvs++;
 493 
 494         /* system error interrupts. */
 495         nldvs++;
 496 
 497         maxldvs = nldvs;
 498         maxldgs = p_cfgp->max_ldgs;
 499 
 500         if (!maxldvs || !maxldgs) {
 501                 /* No devices configured. */
 502                 HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL, "<== hxge_ldgv_init: "
 503                     "no logical devices or groups configured."));
 504                 return (HXGE_ERROR);
 505         }
 506         ldgvp = hxgep->ldgvp;
 507         if (ldgvp == NULL) {
 508                 ldgvp = KMEM_ZALLOC(sizeof (hxge_ldgv_t), KM_SLEEP);
 509                 hxgep->ldgvp = ldgvp;
 510                 ldgvp->maxldgs = maxldgs;
 511                 ldgvp->maxldvs = maxldvs;
 512                 ldgp = ldgvp->ldgp =
 513                     KMEM_ZALLOC(sizeof (hxge_ldg_t) * maxldgs, KM_SLEEP);
 514                 ldvp = ldgvp->ldvp =
 515                     KMEM_ZALLOC(sizeof (hxge_ldv_t) * maxldvs, KM_SLEEP);
 516         }
 517 
 518         ldgvp->ndma_ldvs = p_cfgp->max_tdcs + p_cfgp->max_rdcs;
 519         ldgvp->tmres = HXGE_TIMER_RESO;
 520 
 521         HXGE_DEBUG_MSG((hxgep, INT_CTL,
 522             "==> hxge_ldgv_init: maxldvs %d maxldgs %d nldvs %d",
 523             maxldvs, maxldgs, nldvs));
 524 
 525         ldg = p_cfgp->start_ldg;
 526         ptr = ldgp;
 527         for (i = 0; i < maxldgs; i++) {
 528                 ptr->arm = B_TRUE;
 529                 ptr->vldg_index = i;
 530                 ptr->ldg_timer = HXGE_TIMER_LDG;
 531                 ptr->ldg = ldg++;
 532                 ptr->sys_intr_handler = hxge_intr;
 533                 ptr->nldvs = 0;
 534                 ptr->hxgep = hxgep;
 535                 HXGE_DEBUG_MSG((hxgep, INT_CTL,
 536                     "==> hxge_ldgv_init: maxldvs %d maxldgs %d ldg %d",
 537                     maxldvs, maxldgs, ptr->ldg));
 538                 HXGE_DEBUG_MSG((hxgep, INT_CTL,
 539                     "==> hxge_ldv_init: timer %d", ptr->ldg_timer));
 540                 ptr++;
 541         }
 542 
 543         ldg = p_cfgp->start_ldg;
 544         if (maxldgs > *navail_p) {
 545                 ngrps = *navail_p;
 546         } else {
 547                 ngrps = maxldgs;
 548         }
 549         endldg = ldg + ngrps;
 550 
 551         /*
 552          * Receive DMA channels.
 553          */
 554         channel = p_cfgp->start_rdc;
 555         start = p_cfgp->start_rdc + HXGE_RDMA_LD_START;
 556         end = start + p_cfgp->max_rdcs;
 557         nldvs = 0;
 558         ldgvp->nldvs = 0;
 559         ldgp->ldvp = NULL;
 560         *nrequired_p = 0;
 561         ptr = ldgp;
 562 
 563         /*
 564          * Start with RDC to configure logical devices for each group.
 565          */
 566         for (i = 0, ldv = start; ldv < end; i++, ldv++) {
 567                 ldvp->is_rxdma = B_TRUE;
 568                 ldvp->ldv = ldv;
 569 
 570                 /*
 571                  * If non-seq needs to change the following code
 572                  */
 573                 ldvp->channel = channel++;
 574                 ldvp->vdma_index = i;
 575                 ldvp->ldv_intr_handler = hxge_rx_intr;
 576                 ldvp->ldv_ldf_masks = 0;
 577                 ldvp->use_timer = B_FALSE;
 578                 ldvp->hxgep = hxgep;
 579                 hxge_ldgv_setup(&ptr, &ldvp, ldv, endldg, nrequired_p);
 580                 nldvs++;
 581         }
 582 
 583         /*
 584          * Transmit DMA channels.
 585          */
 586         channel = p_cfgp->start_tdc;
 587         start = p_cfgp->start_tdc + HXGE_TDMA_LD_START;
 588         end = start + p_cfgp->max_tdcs;
 589         for (i = 0, ldv = start; ldv < end; i++, ldv++) {
 590                 ldvp->is_txdma = B_TRUE;
 591                 ldvp->ldv = ldv;
 592                 ldvp->channel = channel++;
 593                 ldvp->vdma_index = i;
 594                 ldvp->ldv_intr_handler = hxge_tx_intr;
 595                 ldvp->ldv_ldf_masks = 0;
 596                 ldvp->use_timer = B_FALSE;
 597                 ldvp->hxgep = hxgep;
 598                 hxge_ldgv_setup(&ptr, &ldvp, ldv, endldg, nrequired_p);
 599                 nldvs++;
 600         }
 601 
 602         /*
 603          * VMAC
 604          */
 605         ldvp->is_vmac = B_TRUE;
 606         ldvp->ldv_intr_handler = hxge_vmac_intr;
 607         ldvp->ldv_ldf_masks = 0;
 608         ldv = HXGE_VMAC_LD;
 609         ldvp->ldv = ldv;
 610         ldvp->use_timer = B_FALSE;
 611         ldvp->hxgep = hxgep;
 612         hxge_ldgv_setup(&ptr, &ldvp, ldv, endldg, nrequired_p);
 613         nldvs++;
 614 
 615         HXGE_DEBUG_MSG((hxgep, INT_CTL,
 616             "==> hxge_ldgv_init: nldvs %d navail %d nrequired %d",
 617             nldvs, *navail_p, *nrequired_p));
 618 
 619         /*
 620          * PFC
 621          */
 622         ldvp->is_pfc = B_TRUE;
 623         ldvp->ldv_intr_handler = hxge_pfc_intr;
 624         ldvp->ldv_ldf_masks = 0;
 625         ldv = HXGE_PFC_LD;
 626         ldvp->ldv = ldv;
 627         ldvp->use_timer = B_FALSE;
 628         ldvp->hxgep = hxgep;
 629         hxge_ldgv_setup(&ptr, &ldvp, ldv, endldg, nrequired_p);
 630         nldvs++;
 631 
 632         HXGE_DEBUG_MSG((hxgep, INT_CTL,
 633             "==> hxge_ldgv_init: nldvs %d navail %d nrequired %d",
 634             nldvs, *navail_p, *nrequired_p));
 635 
 636         /*
 637          * System error interrupts.
 638          */
 639         ldv = HXGE_SYS_ERROR_LD;
 640         ldvp->ldv = ldv;
 641         ldvp->is_syserr = B_TRUE;
 642         ldvp->ldv_intr_handler = hxge_syserr_intr;
 643         ldvp->ldv_ldf_masks = 0;
 644         ldvp->hxgep = hxgep;
 645         ldvp->use_timer = B_FALSE;
 646         ldgvp->ldvp_syserr = ldvp;
 647 
 648         /* Reset PEU error mask to allow PEU error interrupts */
 649         /*
 650          * Keep the msix parity error mask here and remove it
 651          * after ddi_intr_enable call to avoid a msix par err
 652          */
 653         parity_err_mask.value = 0;
 654         parity_err_mask.bits.eic_msix_parerr_mask = 1;
 655         HXGE_REG_WR32(hxgep->hpi_handle, PEU_INTR_MASK, parity_err_mask.value);
 656 
 657         /*
 658          * Unmask the system interrupt states.
 659          */
 660         (void) hxge_fzc_sys_err_mask_set(hxgep, B_FALSE);
 661         (void) hxge_ldgv_setup(&ptr, &ldvp, ldv, endldg, nrequired_p);
 662         nldvs++;
 663 
 664         ldgvp->ldg_intrs = *nrequired_p;
 665 
 666         HXGE_DEBUG_MSG((hxgep, INT_CTL,
 667             "==> hxge_ldgv_init: nldvs %d navail %d nrequired %d",
 668             nldvs, *navail_p, *nrequired_p));
 669         HXGE_DEBUG_MSG((hxgep, INT_CTL, "<== hxge_ldgv_init"));
 670         return (status);
 671 }
 672 
 673 hxge_status_t
 674 hxge_ldgv_uninit(p_hxge_t hxgep)
 675 {
 676         p_hxge_ldgv_t           ldgvp;
 677 
 678         HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_ldgv_uninit"));
 679         ldgvp = hxgep->ldgvp;
 680         if (ldgvp == NULL) {
 681                 HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
 682                     "<== hxge_ldgv_uninit: no logical group configured."));
 683                 return (HXGE_OK);
 684         }
 685 
 686         if (ldgvp->ldgp) {
 687                 KMEM_FREE(ldgvp->ldgp, sizeof (hxge_ldg_t) * ldgvp->maxldgs);
 688         }
 689         if (ldgvp->ldvp) {
 690                 KMEM_FREE(ldgvp->ldvp, sizeof (hxge_ldv_t) * ldgvp->maxldvs);
 691         }
 692 
 693         KMEM_FREE(ldgvp, sizeof (hxge_ldgv_t));
 694         hxgep->ldgvp = NULL;
 695 
 696         HXGE_DEBUG_MSG((hxgep, INT_CTL, "<== hxge_ldgv_uninit"));
 697         return (HXGE_OK);
 698 }
 699 
 700 hxge_status_t
 701 hxge_intr_ldgv_init(p_hxge_t hxgep)
 702 {
 703         hxge_status_t   status = HXGE_OK;
 704 
 705         HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_intr_ldgv_init"));
 706         /*
 707          * Configure the logical device group numbers, state vectors
 708          * and interrupt masks for each logical device.
 709          */
 710         status = hxge_fzc_intr_init(hxgep);
 711 
 712         /*
 713          * Configure logical device masks and timers.
 714          */
 715         status = hxge_intr_mask_mgmt(hxgep);
 716 
 717         HXGE_DEBUG_MSG((hxgep, INT_CTL, "<== hxge_intr_ldgv_init"));
 718         return (status);
 719 }
 720 
 721 hxge_status_t
 722 hxge_intr_mask_mgmt(p_hxge_t hxgep)
 723 {
 724         p_hxge_ldgv_t   ldgvp;
 725         p_hxge_ldg_t    ldgp;
 726         p_hxge_ldv_t    ldvp;
 727         hpi_handle_t    handle;
 728         int             i, j;
 729         hpi_status_t    rs = HPI_SUCCESS;
 730 
 731         HXGE_DEBUG_MSG((hxgep, INT_CTL, "==> hxge_intr_mask_mgmt"));
 732 
 733         if ((ldgvp = hxgep->ldgvp) == NULL) {
 734                 HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
 735                     "<== hxge_intr_mask_mgmt: Null ldgvp"));
 736                 return (HXGE_ERROR);
 737         }
 738         handle = HXGE_DEV_HPI_HANDLE(hxgep);
 739         ldgp = ldgvp->ldgp;
 740         ldvp = ldgvp->ldvp;
 741         if (ldgp == NULL || ldvp == NULL) {
 742                 HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
 743                     "<== hxge_intr_mask_mgmt: Null ldgp or ldvp"));
 744                 return (HXGE_ERROR);
 745         }
 746 
 747         HXGE_DEBUG_MSG((hxgep, INT_CTL,
 748             "==> hxge_intr_mask_mgmt: # of intrs %d ", ldgvp->ldg_intrs));
 749         /* Initialize masks. */
 750         HXGE_DEBUG_MSG((hxgep, INT_CTL,
 751             "==> hxge_intr_mask_mgmt(Hydra): # intrs %d ", ldgvp->ldg_intrs));
 752         for (i = 0; i < ldgvp->ldg_intrs; i++, ldgp++) {
 753                 HXGE_DEBUG_MSG((hxgep, INT_CTL,
 754                     "==> hxge_intr_mask_mgmt(Hydra): # ldv %d in group %d",
 755                     ldgp->nldvs, ldgp->ldg));
 756                 for (j = 0; j < ldgp->nldvs; j++, ldvp++) {
 757                         HXGE_DEBUG_MSG((hxgep, INT_CTL,
 758                             "==> hxge_intr_mask_mgmt: set ldv # %d "
 759                             "for ldg %d", ldvp->ldv, ldgp->ldg));
 760                         rs = hpi_intr_mask_set(handle, ldvp->ldv,
 761                             ldvp->ldv_ldf_masks);
 762                         if (rs != HPI_SUCCESS) {
 763                                 HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
 764                                     "<== hxge_intr_mask_mgmt: set mask failed "
 765                                     " rs 0x%x ldv %d mask 0x%x",
 766                                     rs, ldvp->ldv, ldvp->ldv_ldf_masks));
 767                                 return (HXGE_ERROR | rs);
 768                         }
 769                         HXGE_DEBUG_MSG((hxgep, INT_CTL,
 770                             "==> hxge_intr_mask_mgmt: set mask OK "
 771                             " rs 0x%x ldv %d mask 0x%x",
 772                             rs, ldvp->ldv, ldvp->ldv_ldf_masks));
 773                 }
 774         }
 775 
 776         ldgp = ldgvp->ldgp;
 777         /* Configure timer and arm bit */
 778         for (i = 0; i < hxgep->ldgvp->ldg_intrs; i++, ldgp++) {
 779                 rs = hpi_intr_ldg_mgmt_set(handle, ldgp->ldg,
 780                     ldgp->arm, ldgp->ldg_timer);
 781                 if (rs != HPI_SUCCESS) {
 782                         HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
 783                             "<== hxge_intr_mask_mgmt: set timer failed "
 784                             " rs 0x%x dg %d timer 0x%x",
 785                             rs, ldgp->ldg, ldgp->ldg_timer));
 786                         return (HXGE_ERROR | rs);
 787                 }
 788                 HXGE_DEBUG_MSG((hxgep, INT_CTL,
 789                     "==> hxge_intr_mask_mgmt: set timer OK "
 790                     " rs 0x%x ldg %d timer 0x%x",
 791                     rs, ldgp->ldg, ldgp->ldg_timer));
 792         }
 793 
 794         HXGE_DEBUG_MSG((hxgep, INT_CTL, "<== hxge_fzc_intr_mask_mgmt"));
 795         return (HXGE_OK);
 796 }
 797 
 798 hxge_status_t
 799 hxge_intr_mask_mgmt_set(p_hxge_t hxgep, boolean_t on)
 800 {
 801         p_hxge_ldgv_t   ldgvp;
 802         p_hxge_ldg_t    ldgp;
 803         p_hxge_ldv_t    ldvp;
 804         hpi_handle_t    handle;
 805         int             i, j;
 806         hpi_status_t    rs = HPI_SUCCESS;
 807 
 808         HXGE_DEBUG_MSG((hxgep, INT_CTL,
 809             "==> hxge_intr_mask_mgmt_set (%d)", on));
 810 
 811         if ((ldgvp = hxgep->ldgvp) == NULL) {
 812                 HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
 813                     "==> hxge_intr_mask_mgmt_set: Null ldgvp"));
 814                 return (HXGE_ERROR);
 815         }
 816         handle = HXGE_DEV_HPI_HANDLE(hxgep);
 817         ldgp = ldgvp->ldgp;
 818         ldvp = ldgvp->ldvp;
 819         if (ldgp == NULL || ldvp == NULL) {
 820                 HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
 821                     "<== hxge_intr_mask_mgmt_set: Null ldgp or ldvp"));
 822                 return (HXGE_ERROR);
 823         }
 824 
 825         /* set masks. */
 826         for (i = 0; i < ldgvp->ldg_intrs; i++, ldgp++) {
 827                 HXGE_DEBUG_MSG((hxgep, INT_CTL,
 828                     "==> hxge_intr_mask_mgmt_set: flag %d ldg %d"
 829                     "set mask nldvs %d", on, ldgp->ldg, ldgp->nldvs));
 830                 for (j = 0; j < ldgp->nldvs; j++, ldvp++) {
 831                         HXGE_DEBUG_MSG((hxgep, INT_CTL,
 832                             "==> hxge_intr_mask_mgmt_set: "
 833                             "for %d %d flag %d", i, j, on));
 834                         if (on) {
 835                                 ldvp->ldv_ldf_masks = 0;
 836                                 HXGE_DEBUG_MSG((hxgep, INT_CTL,
 837                                     "==> hxge_intr_mask_mgmt_set: "
 838                                     "ON mask off"));
 839                         } else {
 840                                 ldvp->ldv_ldf_masks = (uint8_t)LD_IM_MASK;
 841                                 HXGE_DEBUG_MSG((hxgep, INT_CTL,
 842                                     "==> hxge_intr_mask_mgmt_set:mask on"));
 843                         }
 844 
 845                         rs = hpi_intr_mask_set(handle, ldvp->ldv,
 846                             ldvp->ldv_ldf_masks);
 847                         if (rs != HPI_SUCCESS) {
 848                                 HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
 849                                     "==> hxge_intr_mask_mgmt_set: "
 850                                     "set mask failed rs 0x%x ldv %d mask 0x%x",
 851                                     rs, ldvp->ldv, ldvp->ldv_ldf_masks));
 852                                 return (HXGE_ERROR | rs);
 853                         }
 854                         HXGE_DEBUG_MSG((hxgep, INT_CTL,
 855                             "==> hxge_intr_mask_mgmt_set: flag %d"
 856                             "set mask OK ldv %d mask 0x%x",
 857                             on, ldvp->ldv, ldvp->ldv_ldf_masks));
 858                 }
 859         }
 860 
 861         ldgp = ldgvp->ldgp;
 862         /* set the arm bit */
 863         for (i = 0; i < hxgep->ldgvp->ldg_intrs; i++, ldgp++) {
 864                 if (on && !ldgp->arm) {
 865                         ldgp->arm = B_TRUE;
 866                 } else if (!on && ldgp->arm) {
 867                         ldgp->arm = B_FALSE;
 868                 }
 869                 rs = hpi_intr_ldg_mgmt_set(handle, ldgp->ldg,
 870                     ldgp->arm, ldgp->ldg_timer);
 871                 if (rs != HPI_SUCCESS) {
 872                         HXGE_ERROR_MSG((hxgep, HXGE_ERR_CTL,
 873                             "<== hxge_intr_mask_mgmt_set: "
 874                             "set timer failed rs 0x%x ldg %d timer 0x%x",
 875                             rs, ldgp->ldg, ldgp->ldg_timer));
 876                         return (HXGE_ERROR | rs);
 877                 }
 878                 HXGE_DEBUG_MSG((hxgep, INT_CTL,
 879                     "==> hxge_intr_mask_mgmt_set: OK (flag %d) "
 880                     "set timer ldg %d timer 0x%x",
 881                     on, ldgp->ldg, ldgp->ldg_timer));
 882         }
 883 
 884         HXGE_DEBUG_MSG((hxgep, INT_CTL, "<== hxge_intr_mask_mgmt_set"));
 885         return (HXGE_OK);
 886 }
 887 
 888 /*
 889  * For Big Endian systems, the mac address will be from OBP. For Little
 890  * Endian (x64) systems, it will be retrieved from the card since it cannot
 891  * be programmed into PXE.
 892  * This function also populates the MMAC parameters.
 893  */
 894 static hxge_status_t
 895 hxge_get_mac_addr_properties(p_hxge_t hxgep)
 896 {
 897         HXGE_DEBUG_MSG((hxgep, DDI_CTL, "==> hxge_get_mac_addr_properties "));
 898 
 899         (void) hxge_pfc_mac_addrs_get(hxgep);
 900         hxgep->ouraddr = hxgep->factaddr;
 901 
 902         HXGE_DEBUG_MSG((hxgep, DDI_CTL, "<== hxge_get_mac_addr_properties "));
 903         return (HXGE_OK);
 904 }
 905 
 906 static void
 907 hxge_ldgv_setup(p_hxge_ldg_t *ldgp, p_hxge_ldv_t *ldvp, uint8_t ldv,
 908         uint8_t endldg, int *ngrps)
 909 {
 910         HXGE_DEBUG_MSG((NULL, INT_CTL, "==> hxge_ldgv_setup"));
 911         /* Assign the group number for each device. */
 912         (*ldvp)->ldg_assigned = (*ldgp)->ldg;
 913         (*ldvp)->ldgp = *ldgp;
 914         (*ldvp)->ldv = ldv;
 915 
 916         HXGE_DEBUG_MSG((NULL, INT_CTL,
 917             "==> hxge_ldgv_setup: ldv %d endldg %d ldg %d, ldvp $%p",
 918             ldv, endldg, (*ldgp)->ldg, (*ldgp)->ldvp));
 919 
 920         (*ldgp)->nldvs++;
 921         if ((*ldgp)->ldg == (endldg - 1)) {
 922                 if ((*ldgp)->ldvp == NULL) {
 923                         (*ldgp)->ldvp = *ldvp;
 924                         *ngrps += 1;
 925                         HXGE_DEBUG_MSG((NULL, INT_CTL,
 926                             "==> hxge_ldgv_setup: ngrps %d", *ngrps));
 927                 }
 928                 HXGE_DEBUG_MSG((NULL, INT_CTL,
 929                     "==> hxge_ldgv_setup: ldvp $%p ngrps %d",
 930                     *ldvp, *ngrps));
 931                 ++*ldvp;
 932         } else {
 933                 (*ldgp)->ldvp = *ldvp;
 934                 *ngrps += 1;
 935                 HXGE_DEBUG_MSG((NULL, INT_CTL, "==> hxge_ldgv_setup(done): "
 936                     "ldv %d endldg %d ldg %d, ldvp $%p",
 937                     ldv, endldg, (*ldgp)->ldg, (*ldgp)->ldvp));
 938                 (*ldvp) = ++*ldvp;
 939                 (*ldgp) = ++*ldgp;
 940                 HXGE_DEBUG_MSG((NULL, INT_CTL,
 941                     "==> hxge_ldgv_setup: new ngrps %d", *ngrps));
 942         }
 943 
 944         HXGE_DEBUG_MSG((NULL, INT_CTL, "==> hxge_ldgv_setup: "
 945             "ldg %d nldvs %d ldv %d ldvp $%p endldg %d ngrps %d",
 946             (*ldgp)->ldg, (*ldgp)->nldvs, ldv, ldvp, endldg, *ngrps));
 947 
 948         HXGE_DEBUG_MSG((NULL, INT_CTL, "<== hxge_ldgv_setup"));
 949 }