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 © 2003-2011 Emulex. All rights reserved.  */
  23 
  24 /*
  25  * Source file containing the implementation of the Hardware specific
  26  * functions
  27  */
  28 
  29 #include <oce_impl.h>
  30 #include <oce_stat.h>
  31 #include <oce_ioctl.h>
  32 
  33 static ddi_device_acc_attr_t reg_accattr = {
  34         DDI_DEVICE_ATTR_V1,
  35         DDI_STRUCTURE_LE_ACC,
  36         DDI_STRICTORDER_ACC,
  37         DDI_FLAGERR_ACC
  38 };
  39 
  40 extern int oce_destroy_q(struct oce_dev *dev, struct oce_mbx *mbx,
  41     size_t req_size, enum qtype qtype);
  42 
  43 static int
  44 oce_map_regs(struct oce_dev *dev)
  45 {
  46         int ret = 0;
  47         off_t bar_size = 0;
  48 
  49         ASSERT(NULL != dev);
  50         ASSERT(NULL != dev->dip);
  51 
  52         /* get number of supported bars */
  53         ret = ddi_dev_nregs(dev->dip, &dev->num_bars);
  54         if (ret != DDI_SUCCESS) {
  55                 oce_log(dev, CE_WARN, MOD_CONFIG,
  56                     "%d: could not retrieve num_bars", MOD_CONFIG);
  57                 return (DDI_FAILURE);
  58         }
  59 
  60         /* verify each bar and map it accordingly */
  61         /* PCI CFG */
  62         ret = ddi_dev_regsize(dev->dip, OCE_DEV_CFG_BAR, &bar_size);
  63         if (ret != DDI_SUCCESS) {
  64                 oce_log(dev, CE_WARN, MOD_CONFIG,
  65                     "Could not get sizeof BAR %d",
  66                     OCE_DEV_CFG_BAR);
  67                 return (DDI_FAILURE);
  68         }
  69 
  70         ret = ddi_regs_map_setup(dev->dip, OCE_DEV_CFG_BAR, &dev->dev_cfg_addr,
  71             0, bar_size, &reg_accattr, &dev->dev_cfg_handle);
  72 
  73         if (ret != DDI_SUCCESS) {
  74                 oce_log(dev, CE_WARN, MOD_CONFIG,
  75                     "Could not map bar %d",
  76                     OCE_DEV_CFG_BAR);
  77                 return (DDI_FAILURE);
  78         }
  79 
  80         /* CSR */
  81         ret = ddi_dev_regsize(dev->dip, OCE_PCI_CSR_BAR, &bar_size);
  82 
  83         if (ret != DDI_SUCCESS) {
  84                 oce_log(dev, CE_WARN, MOD_CONFIG,
  85                     "Could not get sizeof BAR %d",
  86                     OCE_PCI_CSR_BAR);
  87                 return (DDI_FAILURE);
  88         }
  89 
  90         ret = ddi_regs_map_setup(dev->dip, OCE_PCI_CSR_BAR, &dev->csr_addr,
  91             0, bar_size, &reg_accattr, &dev->csr_handle);
  92         if (ret != DDI_SUCCESS) {
  93                 oce_log(dev, CE_WARN, MOD_CONFIG,
  94                     "Could not map bar %d",
  95                     OCE_PCI_CSR_BAR);
  96                 ddi_regs_map_free(&dev->dev_cfg_handle);
  97                 return (DDI_FAILURE);
  98         }
  99 
 100         /* Doorbells */
 101         ret = ddi_dev_regsize(dev->dip, OCE_PCI_DB_BAR, &bar_size);
 102         if (ret != DDI_SUCCESS) {
 103                 oce_log(dev, CE_WARN, MOD_CONFIG,
 104                     "%d Could not get sizeof BAR %d",
 105                     ret, OCE_PCI_DB_BAR);
 106                 ddi_regs_map_free(&dev->csr_handle);
 107                 ddi_regs_map_free(&dev->dev_cfg_handle);
 108                 return (DDI_FAILURE);
 109         }
 110 
 111         ret = ddi_regs_map_setup(dev->dip, OCE_PCI_DB_BAR, &dev->db_addr,
 112             0, 0, &reg_accattr, &dev->db_handle);
 113         if (ret != DDI_SUCCESS) {
 114                 oce_log(dev, CE_WARN, MOD_CONFIG,
 115                     "Could not map bar %d", OCE_PCI_DB_BAR);
 116                 ddi_regs_map_free(&dev->csr_handle);
 117                 ddi_regs_map_free(&dev->dev_cfg_handle);
 118                 return (DDI_FAILURE);
 119         }
 120         return (DDI_SUCCESS);
 121 }
 122 static void
 123 oce_unmap_regs(struct oce_dev *dev)
 124 {
 125 
 126         ASSERT(NULL != dev);
 127         ASSERT(NULL != dev->dip);
 128 
 129         ddi_regs_map_free(&dev->db_handle);
 130         ddi_regs_map_free(&dev->csr_handle);
 131         ddi_regs_map_free(&dev->dev_cfg_handle);
 132 
 133 }
 134 
 135 
 136 
 137 
 138 
 139 /*
 140  * function to map the device memory
 141  *
 142  * dev - handle to device private data structure
 143  *
 144  */
 145 int
 146 oce_pci_init(struct oce_dev *dev)
 147 {
 148         int ret = 0;
 149 
 150         ret = oce_map_regs(dev);
 151 
 152         if (ret != DDI_SUCCESS) {
 153                 return (DDI_FAILURE);
 154         }
 155         dev->fn =  OCE_PCI_FUNC(dev);
 156         if (oce_fm_check_acc_handle(dev, dev->dev_cfg_handle) != DDI_FM_OK) {
 157                 ddi_fm_service_impact(dev->dip, DDI_SERVICE_DEGRADED);
 158         }
 159 
 160         if (ret != DDI_FM_OK) {
 161                 oce_pci_fini(dev);
 162                 return (DDI_FAILURE);
 163         }
 164 
 165         return (DDI_SUCCESS);
 166 } /* oce_pci_init */
 167 
 168 /*
 169  * function to free device memory mapping mapped using
 170  * oce_pci_init
 171  *
 172  * dev - handle to device private data
 173  */
 174 void
 175 oce_pci_fini(struct oce_dev *dev)
 176 {
 177         oce_unmap_regs(dev);
 178 } /* oce_pci_fini */
 179 
 180 /*
 181  * function to read the PCI Bus, Device, and function numbers for the
 182  * device instance.
 183  *
 184  * dev - handle to device private data
 185  */
 186 int
 187 oce_get_bdf(struct oce_dev *dev)
 188 {
 189         pci_regspec_t *pci_rp;
 190         uint32_t length;
 191         int rc;
 192 
 193         /* Get "reg" property */
 194         rc = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dev->dip,
 195             0, "reg", (int **)&pci_rp, (uint_t *)&length);
 196 
 197         if ((rc != DDI_SUCCESS) ||
 198             (length < (sizeof (pci_regspec_t) / sizeof (int)))) {
 199                 oce_log(dev, CE_WARN, MOD_CONFIG,
 200                     "Failed to read \"reg\" property, Status = 0x%x", rc);
 201                 return (rc);
 202         }
 203 
 204         dev->pci_bus = PCI_REG_BUS_G(pci_rp->pci_phys_hi);
 205         dev->pci_device = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
 206         dev->pci_function = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
 207 
 208         oce_log(dev, CE_NOTE, MOD_CONFIG,
 209             "\"reg\" property num=%d, Bus=%d, Device=%d, Function=%d",
 210             length, dev->pci_bus, dev->pci_device, dev->pci_function);
 211 
 212         /* Free the memory allocated by ddi_prop_lookup_int_array() */
 213         ddi_prop_free(pci_rp);
 214         return (rc);
 215 }
 216 
 217 int
 218 oce_identify_hw(struct oce_dev *dev)
 219 {
 220         int ret = DDI_SUCCESS;
 221 
 222         dev->vendor_id = pci_config_get16(dev->pci_cfg_handle,
 223             PCI_CONF_VENID);
 224         dev->device_id = pci_config_get16(dev->pci_cfg_handle,
 225             PCI_CONF_DEVID);
 226         dev->subsys_id = pci_config_get16(dev->pci_cfg_handle,
 227             PCI_CONF_SUBSYSID);
 228         dev->subvendor_id = pci_config_get16(dev->pci_cfg_handle,
 229             PCI_CONF_SUBVENID);
 230 
 231         switch (dev->device_id) {
 232 
 233         case DEVID_TIGERSHARK:
 234                 dev->chip_rev = OC_CNA_GEN2;
 235                 break;
 236         case DEVID_TOMCAT:
 237                 dev->chip_rev = OC_CNA_GEN3;
 238                 break;
 239         default:
 240                 dev->chip_rev = 0;
 241                 ret = DDI_FAILURE;
 242                 break;
 243         }
 244         return (ret);
 245 }
 246 
 247 
 248 /*
 249  * function to check if a reset is required
 250  *
 251  * dev - software handle to the device
 252  *
 253  */
 254 boolean_t
 255 oce_is_reset_pci(struct oce_dev *dev)
 256 {
 257         mpu_ep_semaphore_t post_status;
 258 
 259         ASSERT(dev != NULL);
 260         ASSERT(dev->dip != NULL);
 261 
 262         post_status.dw0 = 0;
 263         post_status.dw0 = OCE_CSR_READ32(dev, MPU_EP_SEMAPHORE);
 264 
 265         if (post_status.bits.stage == POST_STAGE_ARMFW_READY) {
 266                 return (B_FALSE);
 267         }
 268         return (B_TRUE);
 269 } /* oce_is_reset_pci */
 270 
 271 /*
 272  * function to do a soft reset on the device
 273  *
 274  * dev - software handle to the device
 275  *
 276  */
 277 int
 278 oce_pci_soft_reset(struct oce_dev *dev)
 279 {
 280         pcicfg_soft_reset_t soft_rst;
 281         /* struct mpu_ep_control ep_control; */
 282         /* struct pcicfg_online1 online1; */
 283         clock_t tmo;
 284         clock_t earlier = ddi_get_lbolt();
 285 
 286         ASSERT(dev != NULL);
 287 
 288         /* issue soft reset */
 289         soft_rst.dw0 = OCE_CFG_READ32(dev, PCICFG_SOFT_RESET);
 290         soft_rst.bits.soft_reset = 0x01;
 291         OCE_CFG_WRITE32(dev, PCICFG_SOFT_RESET, soft_rst.dw0);
 292 
 293         /* wait till soft reset bit deasserts */
 294         tmo = drv_usectohz(60000000); /* 1.0min */
 295         do {
 296                 if ((ddi_get_lbolt() - earlier) > tmo) {
 297                         tmo = 0;
 298                         break;
 299                 }
 300 
 301                 soft_rst.dw0 = OCE_CFG_READ32(dev, PCICFG_SOFT_RESET);
 302                 if (soft_rst.bits.soft_reset)
 303                         drv_usecwait(100);
 304         } while (soft_rst.bits.soft_reset);
 305 
 306         if (soft_rst.bits.soft_reset) {
 307                 oce_log(dev, CE_WARN, MOD_CONFIG,
 308                     "0x%x soft_reset"
 309                     "bit asserted[1]. Reset failed",
 310                     soft_rst.dw0);
 311                 return (DDI_FAILURE);
 312         }
 313 
 314         return (oce_POST(dev));
 315 } /* oce_pci_soft_reset */
 316 /*
 317  * function to trigger a POST on the device
 318  *
 319  * dev - software handle to the device
 320  *
 321  */
 322 int
 323 oce_POST(struct oce_dev *dev)
 324 {
 325         mpu_ep_semaphore_t post_status;
 326         clock_t tmo;
 327         clock_t earlier = ddi_get_lbolt();
 328 
 329         /* read semaphore CSR */
 330         post_status.dw0 = OCE_CSR_READ32(dev, MPU_EP_SEMAPHORE);
 331         if (oce_fm_check_acc_handle(dev, dev->csr_handle) != DDI_FM_OK) {
 332                 ddi_fm_service_impact(dev->dip, DDI_SERVICE_DEGRADED);
 333                 return (DDI_FAILURE);
 334         }
 335         /* if host is ready then wait for fw ready else send POST */
 336         if (post_status.bits.stage <= POST_STAGE_AWAITING_HOST_RDY) {
 337                 post_status.bits.stage = POST_STAGE_CHIP_RESET;
 338                 OCE_CSR_WRITE32(dev, MPU_EP_SEMAPHORE, post_status.dw0);
 339                 if (oce_fm_check_acc_handle(dev, dev->csr_handle) !=
 340                     DDI_FM_OK) {
 341                         ddi_fm_service_impact(dev->dip, DDI_SERVICE_DEGRADED);
 342                         return (DDI_FAILURE);
 343                 }
 344         }
 345 
 346         /* wait for FW ready */
 347         tmo = drv_usectohz(60000000); /* 1.0min */
 348         for (;;) {
 349                 if ((ddi_get_lbolt() - earlier) > tmo) {
 350                         tmo = 0;
 351                         break;
 352                 }
 353 
 354                 post_status.dw0 = OCE_CSR_READ32(dev, MPU_EP_SEMAPHORE);
 355                 if (oce_fm_check_acc_handle(dev, dev->csr_handle) !=
 356                     DDI_FM_OK) {
 357                         ddi_fm_service_impact(dev->dip, DDI_SERVICE_DEGRADED);
 358                         return (DDI_FAILURE);
 359                 }
 360                 if (post_status.bits.error) {
 361                         oce_log(dev, CE_WARN, MOD_CONFIG,
 362                             "0x%x POST ERROR!!", post_status.dw0);
 363                         return (DDI_FAILURE);
 364                 }
 365                 if (post_status.bits.stage == POST_STAGE_ARMFW_READY)
 366                         return (DDI_SUCCESS);
 367 
 368                 drv_usecwait(100);
 369         }
 370         return (DDI_FAILURE);
 371 } /* oce_POST */
 372 /*
 373  * function to modify register access attributes corresponding to the
 374  * FM capabilities configured by the user
 375  *
 376  * fm_caps - fm capability configured by the user and accepted by the driver
 377  */
 378 void
 379 oce_set_reg_fma_flags(int fm_caps)
 380 {
 381         if (fm_caps == DDI_FM_NOT_CAPABLE) {
 382                 return;
 383         }
 384         if (DDI_FM_ACC_ERR_CAP(fm_caps)) {
 385                 reg_accattr.devacc_attr_access = DDI_FLAGERR_ACC;
 386         } else {
 387                 reg_accattr.devacc_attr_access = DDI_DEFAULT_ACC;
 388         }
 389 } /* oce_set_fma_flags */
 390 
 391 
 392 int
 393 oce_create_nw_interface(struct oce_dev *dev)
 394 {
 395         int ret;
 396         uint32_t capab_flags = OCE_CAPAB_FLAGS;
 397         uint32_t capab_en_flags = OCE_CAPAB_ENABLE;
 398 
 399         if (dev->rss_enable) {
 400                 capab_flags |= MBX_RX_IFACE_FLAGS_RSS;
 401                 capab_en_flags |= MBX_RX_IFACE_FLAGS_RSS;
 402         }
 403 
 404         /* create an interface for the device with out mac */
 405         ret = oce_if_create(dev, capab_flags, capab_en_flags,
 406             0, &dev->mac_addr[0], (uint32_t *)&dev->if_id);
 407         if (ret != 0) {
 408                 oce_log(dev, CE_WARN, MOD_CONFIG,
 409                     "Interface creation failed: 0x%x", ret);
 410                 return (ret);
 411         }
 412         atomic_inc_32(&dev->nifs);
 413 
 414         dev->if_cap_flags = capab_en_flags;
 415 
 416         /* Enable VLAN Promisc on HW */
 417         ret = oce_config_vlan(dev, (uint8_t)dev->if_id, NULL, 0,
 418             B_TRUE, B_TRUE);
 419         if (ret != 0) {
 420                 oce_log(dev, CE_WARN, MOD_CONFIG,
 421                     "Config vlan failed: %d", ret);
 422                 oce_delete_nw_interface(dev);
 423                 return (ret);
 424 
 425         }
 426 
 427         /* set default flow control */
 428         ret = oce_set_flow_control(dev, dev->flow_control);
 429         if (ret != 0) {
 430                 oce_log(dev, CE_NOTE, MOD_CONFIG,
 431                     "Set flow control failed: %d", ret);
 432         }
 433         ret = oce_set_promiscuous(dev, dev->promisc);
 434 
 435         if (ret != 0) {
 436                 oce_log(dev, CE_NOTE, MOD_CONFIG,
 437                     "Set Promisc failed: %d", ret);
 438         }
 439 
 440         return (0);
 441 }
 442 
 443 void
 444 oce_delete_nw_interface(struct oce_dev *dev) {
 445 
 446         /* currently only single interface is implmeneted */
 447         if (dev->nifs > 0) {
 448                 (void) oce_if_del(dev, dev->if_id);
 449                 atomic_dec_32(&dev->nifs);
 450         }
 451 }
 452 
 453 static void
 454 oce_create_itbl(struct oce_dev *dev, char *itbl)
 455 {
 456         int i;
 457         struct oce_rq **rss_queuep = &dev->rq[1];
 458         int nrss  = dev->nrqs - 1;
 459         /* fill the indirection table rq 0 is default queue */
 460         for (i = 0; i < OCE_ITBL_SIZE; i++) {
 461                 itbl[i] = rss_queuep[i % nrss]->rss_cpuid;
 462         }
 463 }
 464 
 465 int
 466 oce_setup_adapter(struct oce_dev *dev)
 467 {
 468         int ret;
 469         char itbl[OCE_ITBL_SIZE];
 470         char hkey[OCE_HKEY_SIZE];
 471 
 472         /* disable the interrupts here and enable in start */
 473         oce_chip_di(dev);
 474 
 475         ret = oce_create_nw_interface(dev);
 476         if (ret != DDI_SUCCESS) {
 477                 return (DDI_FAILURE);
 478         }
 479         ret = oce_create_queues(dev);
 480         if (ret != DDI_SUCCESS) {
 481                 oce_delete_nw_interface(dev);
 482                 return (DDI_FAILURE);
 483         }
 484         if (dev->rss_enable) {
 485                 (void) oce_create_itbl(dev, itbl);
 486                 (void) oce_gen_hkey(hkey, OCE_HKEY_SIZE);
 487                 ret = oce_config_rss(dev, dev->if_id, hkey, itbl, OCE_ITBL_SIZE,
 488                     OCE_DEFAULT_RSS_TYPE, B_TRUE);
 489                 if (ret != DDI_SUCCESS) {
 490                         oce_log(dev, CE_NOTE, MOD_CONFIG, "%s",
 491                             "Failed to Configure RSS");
 492                         oce_delete_queues(dev);
 493                         oce_delete_nw_interface(dev);
 494                         return (ret);
 495                 }
 496         }
 497         ret = oce_setup_handlers(dev);
 498         if (ret != DDI_SUCCESS) {
 499                 oce_log(dev, CE_NOTE, MOD_CONFIG, "%s",
 500                     "Failed to Setup handlers");
 501                 oce_delete_queues(dev);
 502                 oce_delete_nw_interface(dev);
 503                 return (ret);
 504         }
 505         return (DDI_SUCCESS);
 506 }
 507 
 508 void
 509 oce_unsetup_adapter(struct oce_dev *dev)
 510 {
 511         oce_remove_handler(dev);
 512         if (dev->rss_enable) {
 513                 char itbl[OCE_ITBL_SIZE] = {0};
 514                 char hkey[OCE_HKEY_SIZE] = {0};
 515                 int ret = 0;
 516 
 517                 ret = oce_config_rss(dev, dev->if_id, hkey, itbl, OCE_ITBL_SIZE,
 518                     RSS_ENABLE_NONE, B_TRUE);
 519 
 520                 if (ret != DDI_SUCCESS) {
 521                         oce_log(dev, CE_NOTE, MOD_CONFIG, "%s",
 522                             "Failed to Disable RSS");
 523                 }
 524         }
 525         oce_delete_queues(dev);
 526         oce_delete_nw_interface(dev);
 527 }
 528 
 529 int
 530 oce_hw_init(struct oce_dev *dev)
 531 {
 532         int  ret;
 533         struct mac_address_format mac_addr;
 534 
 535         ret = oce_POST(dev);
 536         if (ret != DDI_SUCCESS) {
 537                 oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
 538                     "!!!HW POST1 FAILED");
 539                 /* ADD FM FAULT */
 540                 return (DDI_FAILURE);
 541         }
 542         /* create bootstrap mailbox */
 543         dev->bmbx = oce_alloc_dma_buffer(dev,
 544             sizeof (struct oce_bmbx), NULL, DDI_DMA_CONSISTENT);
 545         if (dev->bmbx == NULL) {
 546                 oce_log(dev, CE_WARN, MOD_CONFIG,
 547                     "Failed to allocate bmbx: size = %u",
 548                     (uint32_t)sizeof (struct oce_bmbx));
 549                 return (DDI_FAILURE);
 550         }
 551 
 552         ret = oce_reset_fun(dev);
 553         if (ret != 0) {
 554                 oce_log(dev, CE_WARN, MOD_CONFIG, "%s",
 555                     "!!!FUNCTION RESET FAILED");
 556                 goto init_fail;
 557         }
 558 
 559         /* reset the Endianess of BMBX */
 560         ret = oce_mbox_init(dev);
 561         if (ret != 0) {
 562                 oce_log(dev, CE_WARN, MOD_CONFIG,
 563                     "Mailbox initialization2 Failed with %d", ret);
 564                 goto init_fail;
 565         }
 566 
 567         /* read the firmware version */
 568         ret = oce_get_fw_version(dev);
 569         if (ret != 0) {
 570                 oce_log(dev, CE_WARN, MOD_CONFIG,
 571                     "Firmaware version read failed with %d", ret);
 572                 goto init_fail;
 573         }
 574 
 575         /* read the fw config */
 576         ret = oce_get_fw_config(dev);
 577         if (ret != 0) {
 578                 oce_log(dev, CE_WARN, MOD_CONFIG,
 579                     "Firmware configuration read failed with %d", ret);
 580                 goto init_fail;
 581         }
 582 
 583         /* read the Factory MAC address */
 584         ret = oce_read_mac_addr(dev, 0, 1,
 585             MAC_ADDRESS_TYPE_NETWORK, &mac_addr);
 586         if (ret != 0) {
 587                 oce_log(dev, CE_WARN, MOD_CONFIG,
 588                     "MAC address read failed with %d", ret);
 589                 goto init_fail;
 590         }
 591         bcopy(&mac_addr.mac_addr[0], &dev->mac_addr[0], ETHERADDRL);
 592         return (DDI_SUCCESS);
 593 init_fail:
 594         oce_hw_fini(dev);
 595         return (DDI_FAILURE);
 596 }
 597 void
 598 oce_hw_fini(struct oce_dev *dev)
 599 {
 600         if (dev->bmbx != NULL) {
 601                 oce_free_dma_buffer(dev, dev->bmbx);
 602                 dev->bmbx = NULL;
 603         }
 604 }