xref: /illumos-gate/usr/src/uts/common/io/bnx/bnx_mm.c (revision bde334a8dbd66dfa70ce4d7fc9dcad6e1ae45fe4)
1 /*
2  * Copyright 2014-2017 Cavium, Inc.
3  * The contents of this file are subject to the terms of the Common Development
4  * and Distribution License, v.1,  (the "License").
5  *
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the License at available
9  * at http://opensource.org/licenses/CDDL-1.0
10  *
11  * See the License for the specific language governing permissions and
12  * limitations under the License.
13  */
14 
15 /*
16  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
17  * Copyright (c) 2019, Joyent, Inc.
18  */
19 
20 #include "bnx.h"
21 #include "bnx_mm.h"
22 #include "bnxgld.h"
23 #include "bnxsnd.h"
24 #include "bnxtmr.h"
25 #include "bnxcfg.h"
26 #include "serdes.h"
27 
28 #include "shmem.h"
29 
30 #define	MII_REG(_type, _field)	(OFFSETOF(_type, _field)/2)
31 
32 ddi_dma_attr_t bnx_std_dma_attrib = {
33 	DMA_ATTR_V0,		/* dma_attr_version */
34 	0,			/* dma_attr_addr_lo */
35 	0xffffffffffffffff,	/* dma_attr_addr_hi */
36 	0x0ffffff,		/* dma_attr_count_max */
37 	BNX_DMA_ALIGNMENT,	/* dma_attr_align */
38 	0xffffffff,		/* dma_attr_burstsizes */
39 	1,			/* dma_attr_minxfer */
40 	0x00ffffff,		/* dma_attr_maxxfer */
41 	0xffffffff,		/* dma_attr_seg */
42 	1,			/* dma_attr_sgllen */
43 	1,			/* dma_attr_granular */
44 	0,			/* dma_attr_flags */
45 };
46 
47 
48 static ddi_dma_attr_t bnx_page_dma_attrib = {
49 	DMA_ATTR_V0,		/* dma_attr_version */
50 	0,			/* dma_attr_addr_lo */
51 	0xffffffffffffffff,	/* dma_attr_addr_hi */
52 	0x0ffffff,		/* dma_attr_count_max */
53 	LM_PAGE_SIZE,		/* dma_attr_align */
54 	0xffffffff,		/* dma_attr_burstsizes */
55 	1,			/* dma_attr_minxfer */
56 	0x00ffffff,		/* dma_attr_maxxfer */
57 	0xffffffff,		/* dma_attr_seg */
58 	1,			/* dma_attr_sgllen */
59 	1,			/* dma_attr_granular */
60 	0,			/* dma_attr_flags */
61 };
62 
63 
64 
65 /*
66  * Name:        mm_wait
67  *
68  * Input:       ptr to LM's device structure,
69  *              delay value in micro-secs
70  *
71  * Return:      None.
72  *
73  * Description: This funtion will be in a busy loop for specified number of
74  *              micro-seconds and will return only after the time is elasped.
75  */
76 void
77 mm_wait(lm_device_t *pdev, u32_t delay_us)
78 {
79 	FLUSHPOSTEDWRITES(pdev);
80 	drv_usecwait(delay_us * 10);
81 } /* mm_wait */
82 
83 
84 
85 /*
86  * Name:        mm_read_pci
87  *
88  * Input:       ptr to LM's device structure,
89  *              register offset into config space,
90  *              ptr to u32 where the register value is returned
91  *
92  * Return:      LM_STATUS_SUCCESS, if successful
93  *              LM_STATUS_FAILURE, if BAR register veiw is not mapped
94  *
95  * Description: This routine reads the PCI config space for the given device
96  *              by calling pci_config_get32().
97  */
98 lm_status_t
99 mm_read_pci(lm_device_t *pdev, u32_t pci_reg, u32_t *reg_value)
100 {
101 	um_device_t *udevp = (um_device_t *)pdev;
102 
103 	*reg_value = pci_config_get32(udevp->os_param.pci_cfg_handle,
104 	    (off_t)pci_reg);
105 
106 	return (LM_STATUS_SUCCESS);
107 } /* mm_read_pci */
108 
109 
110 
111 /*
112  * Name:        mm_write_pci
113  *
114  * Input:       ptr to LM's device structure,
115  *              register offset into config space,
116  *              u32 value to be written to PCI config register
117  *
118  * Return:      LM_STATUS_SUCCESS, if successful
119  *              LM_STATUS_FAILURE, if BAR register veiw is not mapped
120  *
121  * Description: This routine writes to PCI config register using DDI call,
122  *              pci_config_put32().
123  */
124 lm_status_t
125 mm_write_pci(lm_device_t *pdev, u32_t pci_reg, u32_t reg_value)
126 {
127 	um_device_t *udevp = (um_device_t *)pdev;
128 
129 	pci_config_put32(udevp->os_param.pci_cfg_handle,
130 	    (off_t)pci_reg, (uint32_t)reg_value);
131 
132 	return (LM_STATUS_SUCCESS);
133 } /* mm_write_pci */
134 
135 
136 
137 /*
138  * Name:        mm_map_io_base
139  *
140  * Input:       ptr to LM's device structure,
141  *              physical address of the BAR reg
142  *                      (not used in this implementation),
143  *              size of the register window
144  *
145  * Return:      ptr to mapped virtual memory
146  *
147  * Description: This routine maps the BAR register window and returns the
148  *              virtual address in the CPU address scape
149  */
150 void *
151 mm_map_io_base(lm_device_t *pdev, lm_address_t base_addr, u32_t size)
152 {
153 	um_device_t *udevp = (um_device_t *)pdev;
154 
155 	pdev->vars.dmaRegAccHandle = udevp->os_param.reg_acc_handle;
156 
157 	return ((void *)(udevp->os_param.regs_addr));
158 } /* mm_map_io_base */
159 
160 
161 
162 /*
163  * Name:        mm_desc_size
164  *
165  * Input:       ptr to LM's device structure,
166  *              descriptor type
167  *
168  * Return:      size of the descriptor structure
169  *
170  * Description: This routine currently returns the size of packet descriptor
171  *              as defined by the UM module (lm_pkt_t is embedded in this
172  *              struct). This is used by LM's init routines trying to allocate
173  *              memory for TX/RX descriptor queues.
174  */
175 u32_t
176 mm_desc_size(lm_device_t *pdev, u32_t desc_type)
177 {
178 	u32_t desc_size;
179 
180 	switch (desc_type) {
181 	case DESC_TYPE_L2RX_PACKET:
182 		desc_size = sizeof (um_rxpacket_t);
183 		break;
184 
185 	default:
186 		desc_size = 0;
187 		break;
188 	}
189 
190 	desc_size = ALIGN_VALUE_TO_WORD_BOUNDARY(desc_size);
191 
192 	return (desc_size);
193 } /* mm_desc_size */
194 
195 
196 
197 /*
198  * Name:        mm_get_user_config
199  *
200  * Input:       ptr to LM's device structure
201  *
202  * Return:      SUCCESS
203  *
204  * Description: This rotuine maps user option to corresponding parameters in
205  *              LM and UM device structures.
206  */
207 lm_status_t
208 mm_get_user_config(lm_device_t *pdev)
209 {
210 	u32_t keep_vlan_tag = 0;
211 	u32_t offset;
212 	u32_t val;
213 	um_device_t *umdevice = (um_device_t *)pdev;
214 
215 	bnx_cfg_init(umdevice);
216 
217 	bnx_cfg_map_phy(umdevice);
218 
219 	/*
220 	 * If Management Firmware is running ensure that we don't
221 	 * keep the VLAN tag, this is for older firmware
222 	 */
223 	offset = pdev->hw_info.shmem_base;
224 	offset += OFFSETOF(shmem_region_t,
225 	    dev_info.port_feature_config.config);
226 	REG_RD_IND(pdev, offset, &val);
227 
228 	if (!(val & PORT_FEATURE_MFW_ENABLED))
229 		keep_vlan_tag = 1;
230 
231 	/*
232 	 * Newer versions of the firmware can handle VLAN tags
233 	 * check to see if this version of the firmware can handle them
234 	 */
235 	offset = pdev->hw_info.shmem_base;
236 	offset += OFFSETOF(shmem_region_t, drv_fw_cap_mb.fw_cap_mb);
237 	REG_RD_IND(pdev, offset, &val);
238 
239 	if ((val & FW_CAP_SIGNATURE) == FW_CAP_SIGNATURE) {
240 		if ((val & (FW_CAP_MFW_CAN_KEEP_VLAN |
241 		    FW_CAP_BC_CAN_UPDATE_VLAN)) ==
242 		    (FW_CAP_MFW_CAN_KEEP_VLAN | FW_CAP_BC_CAN_UPDATE_VLAN)) {
243 			offset = pdev->hw_info.shmem_base;
244 			offset += OFFSETOF(shmem_region_t,
245 			    drv_fw_cap_mb.drv_ack_cap_mb);
246 			REG_WR_IND(pdev, offset, DRV_ACK_CAP_SIGNATURE |
247 			    FW_CAP_MFW_CAN_KEEP_VLAN |
248 			    FW_CAP_BC_CAN_UPDATE_VLAN);
249 
250 			keep_vlan_tag = 1;
251 		}
252 	}
253 
254 	pdev->params.keep_vlan_tag = keep_vlan_tag;
255 
256 	return (LM_STATUS_SUCCESS);
257 } /* mm_get_user_config */
258 
259 
260 
261 /*
262  * Name:        mm_alloc_mem
263  *
264  * Input:       ptr to LM's device structure,
265  *              size of the memory block to be allocated
266  *
267  * Return:      ptr to newly allocated memory region
268  *
269  * Description: This routine allocates memory region, updates the
270  *              resource list to reflect this newly allocated memory.
271  */
272 void *
273 mm_alloc_mem(lm_device_t *pdev, u32_t mem_size, void *resc_list)
274 {
275 	void *memptr;
276 	bnx_memreq_t *memreq;
277 	um_device_t *umdevice;
278 
279 	(void) resc_list;
280 
281 	umdevice = (um_device_t *)pdev;
282 
283 	if (mem_size == 0) {
284 		return (NULL);
285 	}
286 
287 	if (umdevice->memcnt == BNX_MAX_MEMREQS) {
288 		cmn_err(CE_WARN, "%s: Lower module memreq overflow.\n",
289 		    umdevice->dev_name);
290 		return (NULL);
291 	}
292 
293 	memptr = kmem_zalloc(mem_size, KM_NOSLEEP);
294 	if (memptr == NULL) {
295 		cmn_err(CE_WARN, "%s: Failed to allocate local memory.\n",
296 		    umdevice->dev_name);
297 		return (NULL);
298 	}
299 
300 	memreq = &umdevice->memreq[umdevice->memcnt];
301 
302 	memreq->addr = memptr;
303 	memreq->size = mem_size;
304 
305 	umdevice->memcnt++;
306 
307 	return (memptr);
308 } /* mm_alloc_mem */
309 
310 
311 
312 /*
313  * Name:        mm_alloc_phys_mem
314  *
315  * Input:       ptr to LM's device structure,
316  *              size of the memory block to be allocated,
317  *              pointer to store phys address,
318  *              memory type
319  *
320  * Return:      virtual memory ptr to newly allocated memory region
321  *
322  * Description: This routine allocates memory region, updates the
323  *              resource list to reflect this newly allocated memory.
324  *              This function returns physical address in addition the
325  *              virtual address pointer.
326  */
327 void *
328 mm_alloc_phys_mem(lm_device_t *pdev, u32_t mem_size, lm_address_t *phys_mem,
329     u8_t mem_type, void *resc_list)
330 {
331 	int rc;
332 	caddr_t pbuf;
333 	um_device_t *udevp;
334 	size_t real_len;
335 	unsigned int count;
336 	ddi_dma_attr_t *dma_attrib;
337 	ddi_dma_handle_t *dma_handle;
338 	ddi_acc_handle_t *acc_handle;
339 	ddi_dma_cookie_t cookie;
340 
341 	(void) mem_type;
342 	(void) resc_list;
343 
344 	udevp = (um_device_t *)pdev;
345 
346 	if (mem_size == 0) {
347 		return (NULL);
348 	}
349 
350 	if (udevp->os_param.dma_handles_used == BNX_MAX_PHYS_MEMREQS) {
351 		cmn_err(CE_WARN, "%s: %s: Lower module phys memreq overflow.\n",
352 		    udevp->dev_name, __func__);
353 		return (NULL);
354 	}
355 
356 	if (!(mem_size & LM_PAGE_MASK)) {
357 		/* Size is multiple of page size. */
358 		dma_attrib = &bnx_page_dma_attrib;
359 	} else {
360 		dma_attrib = &bnx_std_dma_attrib;
361 	}
362 
363 	rc = udevp->os_param.dma_handles_used;
364 	dma_handle = &udevp->os_param.dma_handle[rc];
365 	acc_handle = &udevp->os_param.dma_acc_handle[rc];
366 
367 	rc = ddi_dma_alloc_handle(udevp->os_param.dip, dma_attrib,
368 	    DDI_DMA_DONTWAIT, (void *)0, dma_handle);
369 	if (rc != DDI_SUCCESS) {
370 		cmn_err(CE_WARN, "%s: %s: Failed to alloc phys dma handle.\n",
371 		    udevp->dev_name, __func__);
372 		return (NULL);
373 	}
374 
375 	rc = ddi_dma_mem_alloc(*dma_handle, (size_t)mem_size +
376 	    BNX_DMA_ALIGNMENT, &bnxAccessAttribBUF, DDI_DMA_CONSISTENT,
377 	    DDI_DMA_DONTWAIT, (void *)0, &pbuf, &real_len, acc_handle);
378 	if (rc != DDI_SUCCESS) {
379 		cmn_err(CE_WARN, "%s: %s: Failed to alloc phys memory.\n",
380 		    udevp->dev_name, __func__);
381 		goto error1;
382 	}
383 
384 	rc = ddi_dma_addr_bind_handle(*dma_handle, (struct as *)0, pbuf,
385 	    real_len, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT,
386 	    (void *)0, &cookie, &count);
387 	if (rc != DDI_SUCCESS) {
388 		cmn_err(CE_WARN, "%s: %s: Failed to bind DMA address.\n",
389 		    udevp->dev_name, __func__);
390 		goto error2;
391 	}
392 
393 	phys_mem->as_u64 = (u64_t)cookie.dmac_laddress;
394 
395 	/*
396 	 * Save the virtual memory address so
397 	 * we can get the dma_handle later.
398 	 */
399 	udevp->os_param.dma_virt[udevp->os_param.dma_handles_used] = pbuf;
400 
401 	udevp->os_param.dma_handles_used++;
402 
403 	/* Zero the memory... */
404 	bzero(pbuf, real_len);
405 
406 	/* ...and make sure the new contents are flushed back to main memory. */
407 	(void) ddi_dma_sync(*dma_handle, 0, real_len, DDI_DMA_SYNC_FORDEV);
408 
409 	return (pbuf);
410 
411 error2:
412 	ddi_dma_mem_free(acc_handle);
413 
414 error1:
415 	ddi_dma_free_handle(dma_handle);
416 
417 	return (NULL);
418 } /* mm_alloc_phys_mem */
419 
420 
421 
422 /*
423  * Name:        mm_indicate_tx
424  *
425  * Input:       ptr to LM's device structure,
426  *              TX chain index,
427  *              array of pointers to packet descriptors,
428  *              number of packet descriptors in array
429  *
430  * Return:      None
431  *
432  * Description:
433  *              Lower module calls this API function to return transmit packet
434  *              buffers to the system, and to allow the driver to reclaim
435  *              transmit resources.  This function is only called upon transmit
436  *              abort and so is not in the fast path.
437  */
438 void
439 mm_indicate_tx(lm_device_t *pdev, u32_t chain_idx,
440     struct _lm_packet_t *packet_arr[], u32_t num_packets)
441 {
442 	um_txpacket_t **pkt_ptr;
443 	um_txpacket_t *pkt;
444 	s_list_t comp_list;
445 
446 	pkt_ptr = (um_txpacket_t **)packet_arr;
447 
448 	s_list_init(&comp_list, NULL, NULL, 0);
449 
450 	while (num_packets) {
451 		pkt = *pkt_ptr;
452 
453 		s_list_push_tail(&comp_list, &(pkt->lm_pkt.link));
454 
455 		pkt_ptr++;
456 		num_packets--;
457 	}
458 
459 	bnx_xmit_ring_reclaim((um_device_t *)pdev, chain_idx, &comp_list);
460 } /* mm_indicate_tx */
461 
462 
463 
464 /*
465  * Description:
466  *
467  * Return:
468  */
469 static void
470 bnx_display_link_msg(um_device_t * const umdevice)
471 {
472 	char *media;
473 	char linkstr[128];
474 
475 	if (umdevice->dev_var.isfiber) {
476 		media = "Fiber";
477 	} else {
478 		media = "Copper";
479 	}
480 
481 	if (umdevice->nddcfg.link_speed != 0) {
482 		(void) strlcpy(linkstr, "up (", sizeof (linkstr));
483 
484 		switch (umdevice->nddcfg.link_speed) {
485 		case 2500:
486 			(void) strlcat(linkstr, "2500Mbps, ", sizeof (linkstr));
487 			break;
488 		case 1000:
489 			(void) strlcat(linkstr, "1000Mbps, ", sizeof (linkstr));
490 			break;
491 		case 100:
492 			(void) strlcat(linkstr, "100Mbps, ", sizeof (linkstr));
493 			break;
494 		case 10:
495 			(void) strlcat(linkstr, "10Mbps, ", sizeof (linkstr));
496 			break;
497 		default:
498 			(void) strlcat(linkstr, "0Mbps, ", sizeof (linkstr));
499 		}
500 
501 		if (umdevice->nddcfg.link_duplex) {
502 			(void) strlcat(linkstr, "Full Duplex",
503 			    sizeof (linkstr));
504 		} else {
505 			(void) strlcat(linkstr, "Half Duplex",
506 			    sizeof (linkstr));
507 		}
508 
509 		if (umdevice->nddcfg.link_tx_pause ||
510 		    umdevice->nddcfg.link_rx_pause) {
511 			(void) strlcat(linkstr, ", ", sizeof (linkstr));
512 			if (umdevice->nddcfg.link_tx_pause) {
513 				(void) strlcat(linkstr, "Tx", sizeof (linkstr));
514 				if (umdevice->nddcfg.link_rx_pause) {
515 					(void) strlcat(linkstr, " & Rx",
516 					    sizeof (linkstr));
517 				}
518 			} else {
519 				(void) strlcat(linkstr, "Rx", sizeof (linkstr));
520 			}
521 			(void) strlcat(linkstr, " Flow Control ON",
522 			    sizeof (linkstr));
523 		}
524 		(void) strlcat(linkstr, ")", sizeof (linkstr));
525 	} else {
526 		(void) snprintf(linkstr, sizeof (linkstr), "down");
527 	}
528 
529 	cmn_err(CE_NOTE, "!%s: %s link is %s", umdevice->dev_name, media,
530 	    linkstr);
531 } /* bnx_display_link_msg */
532 
533 
534 
535 /*
536  * Name:        bnx_update_lp_cap
537  *
538  * Input:       ptr to device structure
539  *
540  * Return:      None
541  *
542  * Description: This function is updates link partners advertised
543  *              capabilities.
544  */
545 static void
546 bnx_update_lp_cap(um_device_t *const umdevice)
547 {
548 	u32_t		miireg;
549 	lm_status_t	lmstatus;
550 	lm_device_t	*lmdevice;
551 
552 	lmdevice = &(umdevice->lm_dev);
553 
554 	if (umdevice->dev_var.isfiber) {
555 		lmstatus = lm_mread(lmdevice, lmdevice->params.phy_addr,
556 		    MII_REG(serdes_reg_t, mii_aneg_nxt_pg_rcv1), &miireg);
557 		if (lmstatus == LM_STATUS_SUCCESS) {
558 			if (miireg & MII_ANEG_NXT_PG_RCV1_2G5) {
559 				umdevice->remote.param_2500fdx = B_TRUE;
560 			}
561 		}
562 
563 		lmstatus = lm_mread(lmdevice, lmdevice->params.phy_addr,
564 		    PHY_LINK_PARTNER_ABILITY_REG, &miireg);
565 		if (lmstatus == LM_STATUS_SUCCESS) {
566 			miireg &= MII_ABILITY_PAUSE;
567 			if (miireg == MII_ADVERT_SYM_PAUSE) {
568 				umdevice->remote.param_tx_pause = B_TRUE;
569 				umdevice->remote.param_rx_pause = B_TRUE;
570 			} else if (miireg == MII_ADVERT_ASYM_PAUSE) {
571 				umdevice->remote.param_tx_pause = B_TRUE;
572 			}
573 
574 			if (miireg & MII_ABILITY_FULL) {
575 				umdevice->remote.param_1000fdx = B_TRUE;
576 			}
577 
578 			if (miireg & MII_ABILITY_HALF) {
579 				umdevice->remote.param_1000hdx = B_TRUE;
580 			}
581 		}
582 	} else {
583 		/* Copper */
584 		lmstatus = lm_mread(lmdevice, lmdevice->params.phy_addr,
585 		    PHY_1000BASET_STATUS_REG, &miireg);
586 		if (lmstatus == LM_STATUS_SUCCESS) {
587 			if (miireg & PHY_LINK_PARTNER_1000BASET_FULL) {
588 				umdevice->remote.param_1000fdx = B_TRUE;
589 			}
590 
591 			if (miireg & PHY_LINK_PARTNER_1000BASET_HALF) {
592 				umdevice->remote.param_1000hdx = B_TRUE;
593 			}
594 		}
595 
596 		lmstatus = lm_mread(lmdevice, lmdevice->params.phy_addr,
597 		    PHY_LINK_PARTNER_ABILITY_REG, &miireg);
598 		if (lmstatus == LM_STATUS_SUCCESS) {
599 			if (miireg & PHY_LINK_PARTNER_PAUSE_CAPABLE) {
600 				umdevice->remote.param_tx_pause = B_TRUE;
601 				umdevice->remote.param_rx_pause = B_TRUE;
602 			} else if (miireg & PHY_LINK_PARTNER_ASYM_PAUSE) {
603 				umdevice->remote.param_tx_pause = B_TRUE;
604 			}
605 
606 			if (miireg & PHY_LINK_PARTNER_100BASETX_FULL) {
607 				umdevice->remote.param_100fdx = B_TRUE;
608 			}
609 
610 			if (miireg & PHY_LINK_PARTNER_100BASETX_HALF) {
611 				umdevice->remote.param_100hdx = B_TRUE;
612 			}
613 
614 			if (miireg & PHY_LINK_PARTNER_10BASET_FULL) {
615 				umdevice->remote.param_10fdx = B_TRUE;
616 			}
617 
618 			if (miireg & PHY_LINK_PARTNER_10BASET_HALF) {
619 				umdevice->remote.param_10hdx = B_TRUE;
620 			}
621 		}
622 	}
623 
624 #if 0
625 	/*
626 	 * If we can gather _any_ information about our link partner, then
627 	 * because this information is exchanged through autonegotiation, we
628 	 * know that our link partner supports autonegotiation.
629 	 *
630 	 * FIXME -- Find a more authoritative way to update link_autoneg.  I'm
631 	 * not sure it is legal, but it sounds possible to have autonegotiation
632 	 * enabled on the remote end with no capabilities advertised.
633 	 */
634 	if (umdevice->remote.param_2500fdx ||
635 	    umdevice->remote.param_1000fdx ||
636 	    umdevice->remote.param_1000hdx ||
637 	    umdevice->remote.param_100fdx ||
638 	    umdevice->remote.param_100hdx ||
639 	    umdevice->remote.param_10fdx ||
640 	    umdevice->remote.param_10hdx ||
641 	    umdevice->remote.param_tx_pause ||
642 	    umdevice->remote.param_rx_pause) {
643 		umdevice->remote.param_autoneg = B_TRUE;
644 	}
645 #else
646 	lmstatus = lm_mread(lmdevice, lmdevice->params.phy_addr,
647 	    BCM540X_AUX_STATUS_REG, &miireg);
648 	if (lmstatus == LM_STATUS_SUCCESS) {
649 		if (miireg & BIT_12) {
650 			umdevice->remote.link_autoneg = B_TRUE;
651 		}
652 	}
653 #endif
654 } /* bnx_update_lp_cap */
655 
656 
657 
658 /*
659  * Name:        mm_indicate_link
660  *
661  * Input:       ptr to LM's device structure,
662  *              link status,
663  *              lm_medium_t struct
664  *
665  * Return:      None
666  *
667  * Description: Lower module calls this function when ever there is a network
668  *              link status change. This routine updates the driver data
669  *              structure as well calls gld_linkstate() to notify event to GLD.
670  */
671 void
672 mm_indicate_link(lm_device_t *lmdevice, lm_status_t link, lm_medium_t medium)
673 {
674 	int link_speed;
675 	um_device_t *umdevice;
676 
677 	umdevice = (um_device_t *)lmdevice;
678 
679 	if (umdevice->link_updates_ok == B_FALSE) {
680 		return;
681 	}
682 
683 	/* ignore link status if it has not changed since the last indicate */
684 	if ((umdevice->dev_var.indLink == link) &&
685 	    (umdevice->dev_var.indMedium == medium)) {
686 		return;
687 	}
688 
689 	umdevice->dev_var.indLink = link;
690 	umdevice->dev_var.indMedium = medium;
691 
692 	switch (GET_MEDIUM_SPEED(medium)) {
693 	case LM_MEDIUM_SPEED_10MBPS:
694 		link_speed = 10;
695 		break;
696 
697 	case LM_MEDIUM_SPEED_100MBPS:
698 		link_speed = 100;
699 		break;
700 
701 	case LM_MEDIUM_SPEED_1000MBPS:
702 		link_speed = 1000;
703 		break;
704 
705 	case LM_MEDIUM_SPEED_2500MBPS:
706 		link_speed = 2500;
707 		break;
708 
709 	default:
710 		link_speed = 0;
711 		break;
712 	}
713 
714 	/*
715 	 * Validate the linespeed against known hardware capabilities.
716 	 * This is a common occurance.
717 	 */
718 	if (umdevice->dev_var.isfiber) {
719 		if (link_speed != 2500 && link_speed != 1000) {
720 			link_speed = 0;
721 		}
722 	}
723 
724 	if (link_speed == 0) {
725 		link = LM_STATUS_LINK_DOWN;
726 	}
727 
728 	/*
729 	 * If neither link-up or link-down flag is present, then there must
730 	 * have been multiple link events.  Do the right thing.
731 	 */
732 	if (link != LM_STATUS_LINK_ACTIVE && link != LM_STATUS_LINK_DOWN) {
733 		/* Fill in the missing information. */
734 		if (link_speed != 0) {
735 			link = LM_STATUS_LINK_ACTIVE;
736 		} else {
737 			link = LM_STATUS_LINK_DOWN;
738 		}
739 	}
740 
741 #if 0
742 	if (((umdevice->nddcfg.link_speed == 0) &&
743 	    (link != LM_STATUS_LINK_ACTIVE)) ||
744 	    ((umdevice->nddcfg.link_speed != 0) &&
745 	    (link != LM_STATUS_LINK_DOWN))) {
746 		/* This is a false notification. */
747 		return;
748 	}
749 #endif
750 
751 	if (umdevice->timer_link_check_interval) {
752 		if (link == LM_STATUS_LINK_ACTIVE) {
753 			if (lmdevice->vars.serdes_fallback_status) {
754 				/*
755 				 * Start the timer to poll the serdes for
756 				 * reception of configs from the link partner.
757 				 * When this happens the remote has autoneg
758 				 * enabled and we'll restart our autoneg.
759 				 */
760 				bnx_link_timer_restart(umdevice);
761 			}
762 		} else {
763 			if (umdevice->timer_link_check_counter) {
764 				bnx_link_timer_restart(umdevice);
765 			}
766 		}
767 	}
768 
769 	if (link == LM_STATUS_LINK_DOWN) {
770 		umdevice->nddcfg.link_speed = 0;
771 		umdevice->nddcfg.link_duplex  = B_FALSE;
772 		umdevice->nddcfg.link_tx_pause = B_FALSE;
773 		umdevice->nddcfg.link_rx_pause = B_FALSE;
774 
775 		umdevice->remote.link_autoneg  = B_FALSE;
776 		umdevice->remote.param_2500fdx = B_FALSE;
777 		umdevice->remote.param_1000fdx = B_FALSE;
778 		umdevice->remote.param_1000hdx = B_FALSE;
779 		umdevice->remote.param_100fdx  = B_FALSE;
780 		umdevice->remote.param_100hdx  = B_FALSE;
781 		umdevice->remote.param_10fdx = B_FALSE;
782 		umdevice->remote.param_10hdx = B_FALSE;
783 		umdevice->remote.param_tx_pause = B_FALSE;
784 		umdevice->remote.param_rx_pause = B_FALSE;
785 
786 		bnx_display_link_msg(umdevice);
787 
788 		bnx_gld_link(umdevice, LINK_STATE_DOWN);
789 	} else if (link == LM_STATUS_LINK_ACTIVE) {
790 		umdevice->nddcfg.link_speed  = link_speed;
791 
792 		if (GET_MEDIUM_DUPLEX(medium)) {
793 			/* half duplex */
794 			umdevice->nddcfg.link_duplex = B_FALSE;
795 		} else {
796 			/* full duplex */
797 			umdevice->nddcfg.link_duplex = B_TRUE;
798 		}
799 
800 		if (lmdevice->vars.flow_control &
801 		    LM_FLOW_CONTROL_TRANSMIT_PAUSE) {
802 			umdevice->nddcfg.link_tx_pause = B_TRUE;
803 		} else {
804 			umdevice->nddcfg.link_tx_pause = B_FALSE;
805 		}
806 
807 		if (lmdevice->vars.flow_control &
808 		    LM_FLOW_CONTROL_RECEIVE_PAUSE) {
809 			umdevice->nddcfg.link_rx_pause = B_TRUE;
810 		} else {
811 			umdevice->nddcfg.link_rx_pause = B_FALSE;
812 		}
813 
814 		if (umdevice->curcfg.lnkcfg.link_autoneg == B_TRUE) {
815 			bnx_update_lp_cap(umdevice);
816 		}
817 
818 		bnx_display_link_msg(umdevice);
819 
820 		bnx_gld_link(umdevice, LINK_STATE_UP);
821 	}
822 } /* mm_indicate_link */
823 
824 
825 
826 /*
827  * Description:
828  *
829  * Return:
830  */
831 void
832 mm_acquire_ind_reg_lock(struct _lm_device_t *pdev)
833 {
834 	um_device_t *umdevice;
835 
836 	umdevice = (um_device_t *)pdev;
837 
838 	mutex_enter(&umdevice->os_param.ind_mutex);
839 } /* mm_acquire_ind_reg_lock */
840 
841 
842 
843 /*
844  * Description:
845  *
846  * Return:
847  */
848 void
849 mm_release_ind_reg_lock(struct _lm_device_t *pdev)
850 {
851 	um_device_t *umdevice;
852 
853 	umdevice = (um_device_t *)pdev;
854 
855 	mutex_exit(&umdevice->os_param.ind_mutex);
856 } /* mm_release_ind_reg_lock */
857