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 return (DDI_FAILURE); 162 } 163 dev->fn = OCE_PCI_FUNC(dev); 164 if (oce_fm_check_acc_handle(dev, dev->dev_cfg_handle) != DDI_FM_OK) { 165 ddi_fm_service_impact(dev->dip, DDI_SERVICE_DEGRADED); 166 } 167 168 if (ret != DDI_FM_OK) { 169 oce_pci_fini(dev); 170 return (DDI_FAILURE); 171 } 172 173 return (DDI_SUCCESS); 174 } /* oce_pci_init */ 175 176 /* 177 * function to free device memory mapping mapped using 178 * oce_pci_init 179 * 180 * dev - handle to device private data 181 */ 182 void 183 oce_pci_fini(struct oce_dev *dev) 184 { 185 oce_unmap_regs(dev); 186 pci_config_teardown(&dev->pci_cfg_handle); 187 } /* oce_pci_fini */ 188 189 190 /* 191 * function to check if a reset is required 192 * 193 * dev - software handle to the device 194 * 195 */ 196 boolean_t 197 oce_is_reset_pci(struct oce_dev *dev) 198 { 199 mpu_ep_semaphore_t post_status; 200 201 ASSERT(dev != NULL); 202 ASSERT(dev->dip != NULL); 203 204 post_status.dw0 = 0; 205 post_status.dw0 = OCE_CSR_READ32(dev, MPU_EP_SEMAPHORE); 206 207 if (post_status.bits.stage == POST_STAGE_ARMFW_READY) { 208 return (B_FALSE); 209 } 210 return (B_TRUE); 211 } /* oce_is_reset_pci */ 212 213 /* 214 * function to do a soft reset on the device 215 * 216 * dev - software handle to the device 217 * 218 */ 219 int 220 oce_pci_soft_reset(struct oce_dev *dev) 221 { 222 pcicfg_soft_reset_t soft_rst; 223 /* struct mpu_ep_control ep_control; */ 224 /* struct pcicfg_online1 online1; */ 225 clock_t tmo; 226 clock_t earlier = ddi_get_lbolt(); 227 228 ASSERT(dev != NULL); 229 230 /* issue soft reset */ 231 soft_rst.dw0 = OCE_CFG_READ32(dev, PCICFG_SOFT_RESET); 232 soft_rst.bits.soft_reset = 0x01; 233 OCE_CFG_WRITE32(dev, PCICFG_SOFT_RESET, soft_rst.dw0); 234 235 /* wait till soft reset bit deasserts */ 236 tmo = drv_usectohz(60000000); /* 1.0min */ 237 do { 238 if ((ddi_get_lbolt() - earlier) > tmo) { 239 tmo = 0; 240 break; 241 } 242 243 soft_rst.dw0 = OCE_CFG_READ32(dev, PCICFG_SOFT_RESET); 244 if (soft_rst.bits.soft_reset) 245 drv_usecwait(100); 246 } while (soft_rst.bits.soft_reset); 247 248 if (soft_rst.bits.soft_reset) { 249 oce_log(dev, CE_WARN, MOD_CONFIG, 250 "0x%x soft_reset" 251 "bit asserted[1]. Reset failed", 252 soft_rst.dw0); 253 return (DDI_FAILURE); 254 } 255 256 return (oce_POST(dev)); 257 } /* oce_pci_soft_reset */ 258 /* 259 * function to trigger a POST on the device 260 * 261 * dev - software handle to the device 262 * 263 */ 264 int 265 oce_POST(struct oce_dev *dev) 266 { 267 mpu_ep_semaphore_t post_status; 268 clock_t tmo; 269 clock_t earlier = ddi_get_lbolt(); 270 271 /* read semaphore CSR */ 272 post_status.dw0 = OCE_CSR_READ32(dev, MPU_EP_SEMAPHORE); 273 if (oce_fm_check_acc_handle(dev, dev->csr_handle) != DDI_FM_OK) { 274 ddi_fm_service_impact(dev->dip, DDI_SERVICE_DEGRADED); 275 return (DDI_FAILURE); 276 } 277 /* if host is ready then wait for fw ready else send POST */ 278 if (post_status.bits.stage <= POST_STAGE_AWAITING_HOST_RDY) { 279 post_status.bits.stage = POST_STAGE_CHIP_RESET; 280 OCE_CSR_WRITE32(dev, MPU_EP_SEMAPHORE, post_status.dw0); 281 if (oce_fm_check_acc_handle(dev, dev->csr_handle) != 282 DDI_FM_OK) { 283 ddi_fm_service_impact(dev->dip, DDI_SERVICE_DEGRADED); 284 return (DDI_FAILURE); 285 } 286 } 287 288 /* wait for FW ready */ 289 tmo = drv_usectohz(60000000); /* 1.0min */ 290 for (;;) { 291 if ((ddi_get_lbolt() - earlier) > tmo) { 292 tmo = 0; 293 break; 294 } 295 296 post_status.dw0 = OCE_CSR_READ32(dev, MPU_EP_SEMAPHORE); 297 if (oce_fm_check_acc_handle(dev, dev->csr_handle) != 298 DDI_FM_OK) { 299 ddi_fm_service_impact(dev->dip, DDI_SERVICE_DEGRADED); 300 return (DDI_FAILURE); 301 } 302 if (post_status.bits.error) { 303 oce_log(dev, CE_WARN, MOD_CONFIG, 304 "0x%x POST ERROR!!", post_status.dw0); 305 return (DDI_FAILURE); 306 } 307 if (post_status.bits.stage == POST_STAGE_ARMFW_READY) 308 return (DDI_SUCCESS); 309 310 drv_usecwait(100); 311 } 312 return (DDI_FAILURE); 313 } /* oce_POST */ 314 /* 315 * function to modify register access attributes corresponding to the 316 * FM capabilities configured by the user 317 * 318 * fm_caps - fm capability configured by the user and accepted by the driver 319 */ 320 void 321 oce_set_reg_fma_flags(int fm_caps) 322 { 323 if (fm_caps == DDI_FM_NOT_CAPABLE) { 324 return; 325 } 326 if (DDI_FM_ACC_ERR_CAP(fm_caps)) { 327 reg_accattr.devacc_attr_access = DDI_FLAGERR_ACC; 328 } else { 329 reg_accattr.devacc_attr_access = DDI_DEFAULT_ACC; 330 } 331 } /* oce_set_fma_flags */ 332 333 334 int 335 oce_create_nw_interface(struct oce_dev *dev) 336 { 337 int ret; 338 339 /* create an interface for the device with out mac */ 340 ret = oce_if_create(dev, OCE_DEFAULT_IF_CAP, OCE_DEFAULT_IF_CAP_EN, 341 0, &dev->mac_addr[0], (uint32_t *)&dev->if_id); 342 if (ret != 0) { 343 oce_log(dev, CE_WARN, MOD_CONFIG, 344 "Interface creation failed: 0x%x", ret); 345 return (ret); 346 } 347 atomic_inc_32(&dev->nifs); 348 349 dev->if_cap_flags = OCE_DEFAULT_IF_CAP_EN; 350 351 /* Enable VLAN Promisc on HW */ 352 ret = oce_config_vlan(dev, (uint8_t)dev->if_id, NULL, 0, 353 B_TRUE, B_TRUE); 354 if (ret != 0) { 355 oce_log(dev, CE_WARN, MOD_CONFIG, 356 "Config vlan failed: %d", ret); 357 oce_delete_nw_interface(dev); 358 return (ret); 359 360 } 361 362 /* set default flow control */ 363 ret = oce_set_flow_control(dev, dev->flow_control); 364 if (ret != 0) { 365 oce_log(dev, CE_NOTE, MOD_CONFIG, 366 "Set flow control failed: %d", ret); 367 } 368 ret = oce_set_promiscuous(dev, dev->promisc); 369 370 if (ret != 0) { 371 oce_log(dev, CE_NOTE, MOD_CONFIG, 372 "Set Promisc failed: %d", ret); 373 } 374 #if 0 375 /* this could happen if the driver is resuming after suspend */ 376 if (dev->num_mca > 0) { 377 ret = oce_set_multicast_table(dev, dev->multi_cast, 378 dev->num_mca); 379 if (ret != 0) { 380 oce_log(dev, CE_NOTE, MOD_CONFIG, 381 "Set Multicast failed: %d", ret); 382 } 383 } 384 #endif 385 386 return (0); 387 } 388 389 void 390 oce_delete_nw_interface(struct oce_dev *dev) { 391 392 /* currently only single interface is implmeneted */ 393 if (dev->nifs > 0) { 394 (void) oce_if_del(dev, dev->if_id); 395 atomic_dec_32(&dev->nifs); 396 } 397 } 398 399 400 int 401 oce_setup_adapter(struct oce_dev *dev) 402 { 403 int ret; 404 ret = oce_create_nw_interface(dev); 405 if (ret != DDI_SUCCESS) { 406 return (DDI_FAILURE); 407 } 408 ret = oce_create_queues(dev); 409 if (ret != DDI_SUCCESS) { 410 oce_delete_nw_interface(dev); 411 return (DDI_FAILURE); 412 } 413 return (DDI_SUCCESS); 414 } 415 416 void 417 oce_unsetup_adapter(struct oce_dev *dev) 418 { 419 oce_delete_queues(dev); 420 oce_delete_nw_interface(dev); 421 } 422 423 int 424 oce_hw_init(struct oce_dev *dev) 425 { 426 int ret; 427 struct mac_address_format mac_addr; 428 429 ret = oce_POST(dev); 430 if (ret != DDI_SUCCESS) { 431 oce_log(dev, CE_WARN, MOD_CONFIG, "%s", 432 "!!!HW POST1 FAILED"); 433 /* ADD FM FAULT */ 434 return (DDI_FAILURE); 435 } 436 /* create bootstrap mailbox */ 437 dev->bmbx = oce_alloc_dma_buffer(dev, 438 sizeof (struct oce_bmbx), DDI_DMA_CONSISTENT); 439 if (dev->bmbx == NULL) { 440 oce_log(dev, CE_WARN, MOD_CONFIG, 441 "Failed to allocate bmbx: size = %u", 442 (uint32_t)sizeof (struct oce_bmbx)); 443 return (DDI_FAILURE); 444 } 445 446 ret = oce_reset_fun(dev); 447 if (ret != 0) { 448 oce_log(dev, CE_WARN, MOD_CONFIG, "%s", 449 "!!!FUNCTION RESET FAILED"); 450 goto init_fail; 451 } 452 453 /* reset the Endianess of BMBX */ 454 ret = oce_mbox_init(dev); 455 if (ret != 0) { 456 oce_log(dev, CE_WARN, MOD_CONFIG, 457 "Mailbox initialization2 Failed with %d", ret); 458 goto init_fail; 459 } 460 461 /* read the firmware version */ 462 ret = oce_get_fw_version(dev); 463 if (ret != 0) { 464 oce_log(dev, CE_WARN, MOD_CONFIG, 465 "Firmaware version read failed with %d", ret); 466 goto init_fail; 467 } 468 469 /* read the fw config */ 470 ret = oce_get_fw_config(dev); 471 if (ret != 0) { 472 oce_log(dev, CE_WARN, MOD_CONFIG, 473 "Firmware configuration read failed with %d", ret); 474 goto init_fail; 475 } 476 477 /* read the Factory MAC address */ 478 ret = oce_read_mac_addr(dev, 0, 1, 479 MAC_ADDRESS_TYPE_NETWORK, &mac_addr); 480 if (ret != 0) { 481 oce_log(dev, CE_WARN, MOD_CONFIG, 482 "MAC address read failed with %d", ret); 483 goto init_fail; 484 } 485 bcopy(&mac_addr.mac_addr[0], &dev->mac_addr[0], ETHERADDRL); 486 return (DDI_SUCCESS); 487 init_fail: 488 oce_hw_fini(dev); 489 return (DDI_FAILURE); 490 } 491 void 492 oce_hw_fini(struct oce_dev *dev) 493 { 494 if (dev->bmbx != NULL) { 495 oce_free_dma_buffer(dev, dev->bmbx); 496 dev->bmbx = NULL; 497 } 498 } 499