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
oce_map_regs(struct oce_dev * dev)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, ®_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, ®_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, ®_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
oce_unmap_regs(struct oce_dev * dev)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
oce_pci_init(struct oce_dev * dev)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
oce_pci_fini(struct oce_dev * dev)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
oce_get_bdf(struct oce_dev * dev)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
oce_identify_hw(struct oce_dev * dev)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
oce_is_reset_pci(struct oce_dev * dev)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
oce_pci_soft_reset(struct oce_dev * dev)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
oce_POST(struct oce_dev * dev)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
oce_set_reg_fma_flags(int fm_caps)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
oce_create_nw_interface(struct oce_dev * dev)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
oce_delete_nw_interface(struct oce_dev * dev)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
oce_create_itbl(struct oce_dev * dev,char * itbl)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
oce_setup_adapter(struct oce_dev * dev)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
oce_unsetup_adapter(struct oce_dev * dev)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
oce_hw_init(struct oce_dev * dev)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
oce_hw_fini(struct oce_dev * dev)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 }
605