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