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