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