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, &reg_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, &reg_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, &reg_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