xref: /illumos-gate/usr/src/uts/common/io/bnx/bnxmod.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 "bnxgld.h"
22*eef4f27bSRobert Mustacchi #include "bnxhwi.h"
23*eef4f27bSRobert Mustacchi #include "bnxint.h"
24*eef4f27bSRobert Mustacchi #include "bnxtmr.h"
25*eef4f27bSRobert Mustacchi #include "bnxcfg.h"
26*eef4f27bSRobert Mustacchi 
27*eef4f27bSRobert Mustacchi #define	BNX_PRODUCT_BANNER "QLogic 570x/571x Gigabit Ethernet Driver "\
28*eef4f27bSRobert Mustacchi     BRCMVERSION
29*eef4f27bSRobert Mustacchi 
30*eef4f27bSRobert Mustacchi #define	BNX_PRODUCT_INFO "QLogic 570x/571x GbE "\
31*eef4f27bSRobert Mustacchi     BRCMVERSION
32*eef4f27bSRobert Mustacchi 
33*eef4f27bSRobert Mustacchi ddi_device_acc_attr_t bnxAccessAttribBAR = {
34*eef4f27bSRobert Mustacchi 	DDI_DEVICE_ATTR_V0,	/* devacc_attr_version */
35*eef4f27bSRobert Mustacchi 	DDI_STRUCTURE_LE_ACC,	/* devacc_attr_endian_flags */
36*eef4f27bSRobert Mustacchi 	DDI_STRICTORDER_ACC,	/* devacc_attr_dataorder */
37*eef4f27bSRobert Mustacchi 	DDI_DEFAULT_ACC		/* devacc_attr_access */
38*eef4f27bSRobert Mustacchi };
39*eef4f27bSRobert Mustacchi 
40*eef4f27bSRobert Mustacchi ddi_device_acc_attr_t bnxAccessAttribBUF = {
41*eef4f27bSRobert Mustacchi 	DDI_DEVICE_ATTR_V0,	/* devacc_attr_version */
42*eef4f27bSRobert Mustacchi 	DDI_NEVERSWAP_ACC,	/* devacc_attr_endian_flags */
43*eef4f27bSRobert Mustacchi 	DDI_STRICTORDER_ACC,	/* devacc_attr_dataorder */
44*eef4f27bSRobert Mustacchi 	DDI_DEFAULT_ACC		/* devacc_attr_access */
45*eef4f27bSRobert Mustacchi };
46*eef4f27bSRobert Mustacchi 
47*eef4f27bSRobert Mustacchi 
48*eef4f27bSRobert Mustacchi /*
49*eef4f27bSRobert Mustacchi  * Name:    bnx_free_system_resources
50*eef4f27bSRobert Mustacchi  *
51*eef4f27bSRobert Mustacchi  * Input:   ptr to device structure
52*eef4f27bSRobert Mustacchi  *
53*eef4f27bSRobert Mustacchi  * Return:  void
54*eef4f27bSRobert Mustacchi  *
55*eef4f27bSRobert Mustacchi  * Description:
56*eef4f27bSRobert Mustacchi  *          This function is called from detach() entry point to free most
57*eef4f27bSRobert Mustacchi  *          resources held by this device instance.
58*eef4f27bSRobert Mustacchi  */
59*eef4f27bSRobert Mustacchi static int
bnx_free_system_resources(um_device_t * const umdevice)60*eef4f27bSRobert Mustacchi bnx_free_system_resources(um_device_t * const umdevice)
61*eef4f27bSRobert Mustacchi {
62*eef4f27bSRobert Mustacchi 	if (umdevice->os_param.active_resc_flag & DRV_RESOURCE_MINOR_NODE) {
63*eef4f27bSRobert Mustacchi 		umdevice->os_param.active_resc_flag &= ~DRV_RESOURCE_MINOR_NODE;
64*eef4f27bSRobert Mustacchi #ifdef _USE_FRIENDLY_NAME
65*eef4f27bSRobert Mustacchi 		ddi_remove_minor_node(umdevice->os_param.dip,
66*eef4f27bSRobert Mustacchi 		    (char *)ddi_driver_name(umdevice->os_param.dip));
67*eef4f27bSRobert Mustacchi #else
68*eef4f27bSRobert Mustacchi 		ddi_remove_minor_node(umdevice->os_param.dip,
69*eef4f27bSRobert Mustacchi 		    ddi_get_name(umdevice->os_param.dip));
70*eef4f27bSRobert Mustacchi #endif
71*eef4f27bSRobert Mustacchi 	}
72*eef4f27bSRobert Mustacchi 
73*eef4f27bSRobert Mustacchi 	if (umdevice->os_param.active_resc_flag & DRV_RESOURCE_TIMER) {
74*eef4f27bSRobert Mustacchi 		umdevice->os_param.active_resc_flag &=
75*eef4f27bSRobert Mustacchi 		    ~DRV_RESOURCE_TIMER;
76*eef4f27bSRobert Mustacchi 		bnx_timer_fini(umdevice);
77*eef4f27bSRobert Mustacchi 	}
78*eef4f27bSRobert Mustacchi 
79*eef4f27bSRobert Mustacchi 	if (umdevice->os_param.active_resc_flag & DRV_RESOURCE_GLD_REGISTER) {
80*eef4f27bSRobert Mustacchi 		if (bnx_gld_fini(umdevice)) {
81*eef4f27bSRobert Mustacchi 			/*
82*eef4f27bSRobert Mustacchi 			 * FIXME -- If bnx_gld_fini() fails, we need to
83*eef4f27bSRobert Mustacchi 			 * reactivate resources.
84*eef4f27bSRobert Mustacchi 			 */
85*eef4f27bSRobert Mustacchi 			return (-1);
86*eef4f27bSRobert Mustacchi 		}
87*eef4f27bSRobert Mustacchi 		umdevice->os_param.active_resc_flag &=
88*eef4f27bSRobert Mustacchi 		    ~DRV_RESOURCE_GLD_REGISTER;
89*eef4f27bSRobert Mustacchi 	}
90*eef4f27bSRobert Mustacchi 
91*eef4f27bSRobert Mustacchi 	if (umdevice->os_param.active_resc_flag & DRV_RESOURCE_KSTAT) {
92*eef4f27bSRobert Mustacchi 		umdevice->os_param.active_resc_flag &= ~DRV_RESOURCE_KSTAT;
93*eef4f27bSRobert Mustacchi 		bnx_kstat_fini(umdevice);
94*eef4f27bSRobert Mustacchi 	}
95*eef4f27bSRobert Mustacchi 
96*eef4f27bSRobert Mustacchi 	if (umdevice->os_param.active_resc_flag & DRV_RESOURCE_HDWR_REGISTER) {
97*eef4f27bSRobert Mustacchi 		umdevice->os_param.active_resc_flag &=
98*eef4f27bSRobert Mustacchi 		    ~DRV_RESOURCE_HDWR_REGISTER;
99*eef4f27bSRobert Mustacchi 		bnx_hdwr_fini(umdevice);
100*eef4f27bSRobert Mustacchi 	}
101*eef4f27bSRobert Mustacchi 
102*eef4f27bSRobert Mustacchi 	if (umdevice->os_param.active_resc_flag & DRV_RESOURCE_MUTEX) {
103*eef4f27bSRobert Mustacchi 		umdevice->os_param.active_resc_flag &= ~DRV_RESOURCE_MUTEX;
104*eef4f27bSRobert Mustacchi 		mutex_destroy(&umdevice->os_param.ind_mutex);
105*eef4f27bSRobert Mustacchi 		mutex_destroy(&umdevice->os_param.phy_mutex);
106*eef4f27bSRobert Mustacchi 		mutex_destroy(&umdevice->os_param.rcv_mutex);
107*eef4f27bSRobert Mustacchi 	}
108*eef4f27bSRobert Mustacchi 
109*eef4f27bSRobert Mustacchi 	if (umdevice->os_param.active_resc_flag & DRV_RESOURCE_INTR_1) {
110*eef4f27bSRobert Mustacchi 		umdevice->os_param.active_resc_flag &= ~DRV_RESOURCE_INTR_1;
111*eef4f27bSRobert Mustacchi 		bnxIntrFini(umdevice);
112*eef4f27bSRobert Mustacchi 	}
113*eef4f27bSRobert Mustacchi 
114*eef4f27bSRobert Mustacchi 	if (umdevice->os_param.active_resc_flag & DRV_RESOURCE_MAP_REGS) {
115*eef4f27bSRobert Mustacchi 		umdevice->os_param.active_resc_flag &= ~DRV_RESOURCE_MAP_REGS;
116*eef4f27bSRobert Mustacchi 		ddi_regs_map_free(&umdevice->os_param.reg_acc_handle);
117*eef4f27bSRobert Mustacchi 		umdevice->lm_dev.vars.dmaRegAccHandle = NULL;
118*eef4f27bSRobert Mustacchi 		umdevice->os_param.reg_acc_handle = NULL;
119*eef4f27bSRobert Mustacchi 	}
120*eef4f27bSRobert Mustacchi 
121*eef4f27bSRobert Mustacchi 	if (umdevice->os_param.active_resc_flag & DRV_RESOURCE_PCICFG_MAPPED) {
122*eef4f27bSRobert Mustacchi 		umdevice->os_param.active_resc_flag &=
123*eef4f27bSRobert Mustacchi 		    ~DRV_RESOURCE_PCICFG_MAPPED;
124*eef4f27bSRobert Mustacchi 		pci_config_teardown(&umdevice->os_param.pci_cfg_handle);
125*eef4f27bSRobert Mustacchi 	}
126*eef4f27bSRobert Mustacchi 
127*eef4f27bSRobert Mustacchi 	return (0);
128*eef4f27bSRobert Mustacchi }
129*eef4f27bSRobert Mustacchi 
130*eef4f27bSRobert Mustacchi 
131*eef4f27bSRobert Mustacchi 
132*eef4f27bSRobert Mustacchi /*
133*eef4f27bSRobert Mustacchi  * Name:    bnx_attach_attach
134*eef4f27bSRobert Mustacchi  *
135*eef4f27bSRobert Mustacchi  * Input:   ptr to dev_info_t
136*eef4f27bSRobert Mustacchi  *
137*eef4f27bSRobert Mustacchi  * Return:  DDI_SUCCESS or DDI_FAILURE.
138*eef4f27bSRobert Mustacchi  *
139*eef4f27bSRobert Mustacchi  * Description: This is the main code involving all important driver data struct
140*eef4f27bSRobert Mustacchi  *		and device initialization stuff. This function allocates driver
141*eef4f27bSRobert Mustacchi  *		soft state for this instance of the driver,  sets access up
142*eef4f27bSRobert Mustacchi  *		attributes for the device, maps BAR register space, initializes
143*eef4f27bSRobert Mustacchi  *		the hardware, determines interrupt pin, registers interrupt
144*eef4f27bSRobert Mustacchi  *		service routine with the OS and initializes receive/transmit
145*eef4f27bSRobert Mustacchi  *		mutex. After successful completion of above mentioned tasks,
146*eef4f27bSRobert Mustacchi  *		the driver registers with the GLD and creates minor node in
147*eef4f27bSRobert Mustacchi  *		the file system tree for this device.
148*eef4f27bSRobert Mustacchi  */
149*eef4f27bSRobert Mustacchi static int
bnx_attach_attach(um_device_t * umdevice)150*eef4f27bSRobert Mustacchi bnx_attach_attach(um_device_t *umdevice)
151*eef4f27bSRobert Mustacchi {
152*eef4f27bSRobert Mustacchi 	int rc;
153*eef4f27bSRobert Mustacchi 	int instance;
154*eef4f27bSRobert Mustacchi 	unsigned int val;
155*eef4f27bSRobert Mustacchi 	int chip_id;
156*eef4f27bSRobert Mustacchi 	int device_id;
157*eef4f27bSRobert Mustacchi 	int subdevice_id;
158*eef4f27bSRobert Mustacchi 	off_t regSize;
159*eef4f27bSRobert Mustacchi 
160*eef4f27bSRobert Mustacchi 	dev_info_t *dip;
161*eef4f27bSRobert Mustacchi 
162*eef4f27bSRobert Mustacchi 	dip = umdevice->os_param.dip;
163*eef4f27bSRobert Mustacchi 
164*eef4f27bSRobert Mustacchi 	umdevice->os_param.active_resc_flag = 0;
165*eef4f27bSRobert Mustacchi 
166*eef4f27bSRobert Mustacchi 	rc = pci_config_setup(umdevice->os_param.dip,
167*eef4f27bSRobert Mustacchi 	    &umdevice->os_param.pci_cfg_handle);
168*eef4f27bSRobert Mustacchi 	if (rc != DDI_SUCCESS) {
169*eef4f27bSRobert Mustacchi 		cmn_err(CE_WARN,
170*eef4f27bSRobert Mustacchi 		    "%s: Failed to setup PCI configuration space accesses.\n",
171*eef4f27bSRobert Mustacchi 		    umdevice->dev_name);
172*eef4f27bSRobert Mustacchi 		goto error;
173*eef4f27bSRobert Mustacchi 	}
174*eef4f27bSRobert Mustacchi 
175*eef4f27bSRobert Mustacchi 	umdevice->os_param.active_resc_flag |= DRV_RESOURCE_PCICFG_MAPPED;
176*eef4f27bSRobert Mustacchi 
177*eef4f27bSRobert Mustacchi 	rc = ddi_dev_regsize(dip, 1, &regSize);
178*eef4f27bSRobert Mustacchi 	if (rc != DDI_SUCCESS) {
179*eef4f27bSRobert Mustacchi 		cmn_err(CE_WARN, "%s: failed to determine register set size.",
180*eef4f27bSRobert Mustacchi 		    umdevice->dev_name);
181*eef4f27bSRobert Mustacchi 	}
182*eef4f27bSRobert Mustacchi 
183*eef4f27bSRobert Mustacchi 	/*
184*eef4f27bSRobert Mustacchi 	 * Setup device memory mapping so that LM driver can start accessing it.
185*eef4f27bSRobert Mustacchi 	 */
186*eef4f27bSRobert Mustacchi 	rc = ddi_regs_map_setup(dip,
187*eef4f27bSRobert Mustacchi 	    1, /* BAR */
188*eef4f27bSRobert Mustacchi 	    &umdevice->os_param.regs_addr,
189*eef4f27bSRobert Mustacchi 	    0, /* OFFSET */
190*eef4f27bSRobert Mustacchi 	    regSize,
191*eef4f27bSRobert Mustacchi 	    &bnxAccessAttribBAR,
192*eef4f27bSRobert Mustacchi 	    &umdevice->os_param.reg_acc_handle);
193*eef4f27bSRobert Mustacchi 	if (rc != DDI_SUCCESS) {
194*eef4f27bSRobert Mustacchi 		cmn_err(CE_WARN,
195*eef4f27bSRobert Mustacchi 		    "%s: Failed to memory map device.\n",
196*eef4f27bSRobert Mustacchi 		    umdevice->dev_name);
197*eef4f27bSRobert Mustacchi 		goto error;
198*eef4f27bSRobert Mustacchi 	}
199*eef4f27bSRobert Mustacchi 
200*eef4f27bSRobert Mustacchi 	umdevice->os_param.active_resc_flag |= DRV_RESOURCE_MAP_REGS;
201*eef4f27bSRobert Mustacchi 
202*eef4f27bSRobert Mustacchi 	bnx_cfg_msix(umdevice);
203*eef4f27bSRobert Mustacchi 
204*eef4f27bSRobert Mustacchi 	if (bnxIntrInit(umdevice) != 0) {
205*eef4f27bSRobert Mustacchi 		goto error;
206*eef4f27bSRobert Mustacchi 	}
207*eef4f27bSRobert Mustacchi 
208*eef4f27bSRobert Mustacchi 	umdevice->os_param.active_resc_flag |= DRV_RESOURCE_INTR_1;
209*eef4f27bSRobert Mustacchi 
210*eef4f27bSRobert Mustacchi 	mutex_init(&umdevice->os_param.rcv_mutex, NULL,
211*eef4f27bSRobert Mustacchi 	    MUTEX_DRIVER, DDI_INTR_PRI(umdevice->intrPriority));
212*eef4f27bSRobert Mustacchi 	mutex_init(&umdevice->os_param.phy_mutex, NULL,
213*eef4f27bSRobert Mustacchi 	    MUTEX_DRIVER, DDI_INTR_PRI(umdevice->intrPriority));
214*eef4f27bSRobert Mustacchi 	mutex_init(&umdevice->os_param.ind_mutex, NULL,
215*eef4f27bSRobert Mustacchi 	    MUTEX_DRIVER, DDI_INTR_PRI(umdevice->intrPriority));
216*eef4f27bSRobert Mustacchi 
217*eef4f27bSRobert Mustacchi 	umdevice->os_param.active_resc_flag |= DRV_RESOURCE_MUTEX;
218*eef4f27bSRobert Mustacchi 
219*eef4f27bSRobert Mustacchi 	/*
220*eef4f27bSRobert Mustacchi 	 * Call lower module's initialization routines to initialize
221*eef4f27bSRobert Mustacchi 	 * hardware and related components within BNX.
222*eef4f27bSRobert Mustacchi 	 */
223*eef4f27bSRobert Mustacchi 	if (bnx_hdwr_init(umdevice)) {
224*eef4f27bSRobert Mustacchi 		goto error;
225*eef4f27bSRobert Mustacchi 	}
226*eef4f27bSRobert Mustacchi 
227*eef4f27bSRobert Mustacchi 	umdevice->os_param.active_resc_flag |= DRV_RESOURCE_HDWR_REGISTER;
228*eef4f27bSRobert Mustacchi 
229*eef4f27bSRobert Mustacchi 	if (!bnx_kstat_init(umdevice)) {
230*eef4f27bSRobert Mustacchi 		goto error;
231*eef4f27bSRobert Mustacchi 	}
232*eef4f27bSRobert Mustacchi 
233*eef4f27bSRobert Mustacchi 	umdevice->os_param.active_resc_flag |= DRV_RESOURCE_KSTAT;
234*eef4f27bSRobert Mustacchi 
235*eef4f27bSRobert Mustacchi 	if (bnx_gld_init(umdevice)) {
236*eef4f27bSRobert Mustacchi 		goto error;
237*eef4f27bSRobert Mustacchi 	}
238*eef4f27bSRobert Mustacchi 
239*eef4f27bSRobert Mustacchi 	umdevice->os_param.active_resc_flag |= DRV_RESOURCE_GLD_REGISTER;
240*eef4f27bSRobert Mustacchi 
241*eef4f27bSRobert Mustacchi 	bnx_timer_init(umdevice);
242*eef4f27bSRobert Mustacchi 
243*eef4f27bSRobert Mustacchi 	umdevice->os_param.active_resc_flag |= DRV_RESOURCE_TIMER;
244*eef4f27bSRobert Mustacchi 
245*eef4f27bSRobert Mustacchi 	instance = ddi_get_instance(umdevice->os_param.dip);
246*eef4f27bSRobert Mustacchi 
247*eef4f27bSRobert Mustacchi 	/* Create a minor node entry in /devices . */
248*eef4f27bSRobert Mustacchi #ifdef _USE_FRIENDLY_NAME
249*eef4f27bSRobert Mustacchi 	rc = ddi_create_minor_node(dip, (char *)ddi_driver_name(dip),
250*eef4f27bSRobert Mustacchi 	    S_IFCHR, instance, DDI_PSEUDO, 0);
251*eef4f27bSRobert Mustacchi #else
252*eef4f27bSRobert Mustacchi 	rc = ddi_create_minor_node(dip, ddi_get_name(dip),
253*eef4f27bSRobert Mustacchi 	    S_IFCHR, instance, DDI_PSEUDO, 0);
254*eef4f27bSRobert Mustacchi #endif
255*eef4f27bSRobert Mustacchi 	if (rc == DDI_FAILURE) {
256*eef4f27bSRobert Mustacchi 		cmn_err(CE_WARN, "%s: Failed to create device minor node.\n",
257*eef4f27bSRobert Mustacchi 		    umdevice->dev_name);
258*eef4f27bSRobert Mustacchi 		goto error;
259*eef4f27bSRobert Mustacchi 	}
260*eef4f27bSRobert Mustacchi 
261*eef4f27bSRobert Mustacchi 	umdevice->os_param.active_resc_flag |= DRV_RESOURCE_MINOR_NODE;
262*eef4f27bSRobert Mustacchi 
263*eef4f27bSRobert Mustacchi 	ddi_report_dev(dip);
264*eef4f27bSRobert Mustacchi 
265*eef4f27bSRobert Mustacchi 	device_id = pci_config_get16(umdevice->os_param.pci_cfg_handle,
266*eef4f27bSRobert Mustacchi 	    0x2);
267*eef4f27bSRobert Mustacchi 	subdevice_id = pci_config_get16(umdevice->os_param.pci_cfg_handle,
268*eef4f27bSRobert Mustacchi 	    0x2e);
269*eef4f27bSRobert Mustacchi 
270*eef4f27bSRobert Mustacchi 	/*  Dip into PCI config space to determine if we have 5716's */
271*eef4f27bSRobert Mustacchi 	if ((device_id == 0x163b) && (subdevice_id == 0x163b)) {
272*eef4f27bSRobert Mustacchi 		chip_id = 0x5716;
273*eef4f27bSRobert Mustacchi 	} else {
274*eef4f27bSRobert Mustacchi 		chip_id = CHIP_NUM(&umdevice->lm_dev) >> 16;
275*eef4f27bSRobert Mustacchi 	}
276*eef4f27bSRobert Mustacchi 
277*eef4f27bSRobert Mustacchi 	(void) snprintf(umdevice->version, sizeof (umdevice->version), "%s",
278*eef4f27bSRobert Mustacchi 	    BRCMVERSION);
279*eef4f27bSRobert Mustacchi 
280*eef4f27bSRobert Mustacchi 	/* Get firmware version. */
281*eef4f27bSRobert Mustacchi 	REG_RD_IND(&umdevice->lm_dev,
282*eef4f27bSRobert Mustacchi 	    umdevice->lm_dev.hw_info.shmem_base +
283*eef4f27bSRobert Mustacchi 	    OFFSETOF(shmem_region_t, dev_info.bc_rev), &val);
284*eef4f27bSRobert Mustacchi 	umdevice->dev_var.fw_ver = (val & 0xFFFF0000) | ((val & 0xFF00) >> 8);
285*eef4f27bSRobert Mustacchi 
286*eef4f27bSRobert Mustacchi 	(void) snprintf(umdevice->versionFW, sizeof (umdevice->versionFW),
287*eef4f27bSRobert Mustacchi 	    "0x%x", umdevice->dev_var.fw_ver);
288*eef4f27bSRobert Mustacchi 
289*eef4f27bSRobert Mustacchi 	(void) snprintf(umdevice->chipName, sizeof (umdevice->chipName),
290*eef4f27bSRobert Mustacchi 	    "BCM%x", chip_id);
291*eef4f27bSRobert Mustacchi 
292*eef4f27bSRobert Mustacchi 	(void) snprintf(umdevice->intrAlloc, sizeof (umdevice->intrAlloc),
293*eef4f27bSRobert Mustacchi 	    "1 %s", (umdevice->intrType == DDI_INTR_TYPE_MSIX) ? "MSIX" :
294*eef4f27bSRobert Mustacchi 	    (umdevice->intrType == DDI_INTR_TYPE_MSI)  ? "MSI"  :
295*eef4f27bSRobert Mustacchi 	    "Fixed");
296*eef4f27bSRobert Mustacchi 
297*eef4f27bSRobert Mustacchi 	cmn_err(CE_NOTE,
298*eef4f27bSRobert Mustacchi 	    "!%s: (%s) BCM%x device with F/W Ver%x is initialized (%s)",
299*eef4f27bSRobert Mustacchi 	    umdevice->dev_name, umdevice->version,
300*eef4f27bSRobert Mustacchi 	    chip_id, umdevice->dev_var.fw_ver,
301*eef4f27bSRobert Mustacchi 	    umdevice->intrAlloc);
302*eef4f27bSRobert Mustacchi 
303*eef4f27bSRobert Mustacchi 	return (0);
304*eef4f27bSRobert Mustacchi 
305*eef4f27bSRobert Mustacchi error:
306*eef4f27bSRobert Mustacchi 	(void) bnx_free_system_resources(umdevice);
307*eef4f27bSRobert Mustacchi 
308*eef4f27bSRobert Mustacchi 	return (-1);
309*eef4f27bSRobert Mustacchi }
310*eef4f27bSRobert Mustacchi 
311*eef4f27bSRobert Mustacchi /*
312*eef4f27bSRobert Mustacchi  * Name:    bnx_attach
313*eef4f27bSRobert Mustacchi  *
314*eef4f27bSRobert Mustacchi  * Input:   ptr to dev_info_t, command code for the task to be executed
315*eef4f27bSRobert Mustacchi  *
316*eef4f27bSRobert Mustacchi  * Return:  DDI_SUCCESS or DDI_FAILURE.
317*eef4f27bSRobert Mustacchi  *
318*eef4f27bSRobert Mustacchi  * Description:	OS determined module attach entry point.
319*eef4f27bSRobert Mustacchi  */
320*eef4f27bSRobert Mustacchi static int
bnx_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)321*eef4f27bSRobert Mustacchi bnx_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
322*eef4f27bSRobert Mustacchi {
323*eef4f27bSRobert Mustacchi 	um_device_t *umdevice;
324*eef4f27bSRobert Mustacchi 	int ret_val = DDI_SUCCESS;
325*eef4f27bSRobert Mustacchi 
326*eef4f27bSRobert Mustacchi 	switch (cmd) {
327*eef4f27bSRobert Mustacchi 		case DDI_ATTACH:
328*eef4f27bSRobert Mustacchi 			umdevice = kmem_zalloc(sizeof (um_device_t),
329*eef4f27bSRobert Mustacchi 			    KM_NOSLEEP);
330*eef4f27bSRobert Mustacchi 			if (umdevice == NULL) {
331*eef4f27bSRobert Mustacchi 				cmn_err(CE_WARN, "%s: Failed to allocate "
332*eef4f27bSRobert Mustacchi 				    "device memory.\n", __func__);
333*eef4f27bSRobert Mustacchi 				ret_val = DDI_FAILURE;
334*eef4f27bSRobert Mustacchi 				break;
335*eef4f27bSRobert Mustacchi 			}
336*eef4f27bSRobert Mustacchi 
337*eef4f27bSRobert Mustacchi 			/* Save dev_info_t info in the driver struture. */
338*eef4f27bSRobert Mustacchi 			umdevice->os_param.dip = dip;
339*eef4f27bSRobert Mustacchi 
340*eef4f27bSRobert Mustacchi 			/*
341*eef4f27bSRobert Mustacchi 			 * Obtain a human-readable name to prepend all our
342*eef4f27bSRobert Mustacchi 			 * messages with.
343*eef4f27bSRobert Mustacchi 			 */
344*eef4f27bSRobert Mustacchi 			umdevice->instance = ddi_get_instance(dip);
345*eef4f27bSRobert Mustacchi 			(void) snprintf(umdevice->dev_name,
346*eef4f27bSRobert Mustacchi 			    sizeof (umdevice->dev_name), "%s%d", "bnx",
347*eef4f27bSRobert Mustacchi 			    umdevice->instance);
348*eef4f27bSRobert Mustacchi 
349*eef4f27bSRobert Mustacchi 			/*
350*eef4f27bSRobert Mustacchi 			 * Set driver private pointer to per device structure
351*eef4f27bSRobert Mustacchi 			 * ptr.
352*eef4f27bSRobert Mustacchi 			 */
353*eef4f27bSRobert Mustacchi 			ddi_set_driver_private(dip, (caddr_t)umdevice);
354*eef4f27bSRobert Mustacchi 
355*eef4f27bSRobert Mustacchi 			umdevice->magic = BNX_MAGIC;
356*eef4f27bSRobert Mustacchi 
357*eef4f27bSRobert Mustacchi 			if (bnx_attach_attach(umdevice)) {
358*eef4f27bSRobert Mustacchi 				ddi_set_driver_private(dip, (caddr_t)NULL);
359*eef4f27bSRobert Mustacchi 				kmem_free(umdevice, sizeof (um_device_t));
360*eef4f27bSRobert Mustacchi 				ret_val = DDI_FAILURE;
361*eef4f27bSRobert Mustacchi 			}
362*eef4f27bSRobert Mustacchi 			break;
363*eef4f27bSRobert Mustacchi 
364*eef4f27bSRobert Mustacchi 		case DDI_RESUME:
365*eef4f27bSRobert Mustacchi 			/* Retrieve our device structure. */
366*eef4f27bSRobert Mustacchi 			umdevice = ddi_get_driver_private(dip);
367*eef4f27bSRobert Mustacchi 			if (umdevice == NULL) {
368*eef4f27bSRobert Mustacchi 				ret_val = DDI_FAILURE;
369*eef4f27bSRobert Mustacchi 				break;
370*eef4f27bSRobert Mustacchi 			}
371*eef4f27bSRobert Mustacchi 			break;
372*eef4f27bSRobert Mustacchi 
373*eef4f27bSRobert Mustacchi 		default:
374*eef4f27bSRobert Mustacchi 			ret_val = DDI_FAILURE;
375*eef4f27bSRobert Mustacchi 			break;
376*eef4f27bSRobert Mustacchi 	}
377*eef4f27bSRobert Mustacchi 
378*eef4f27bSRobert Mustacchi 	return (ret_val);
379*eef4f27bSRobert Mustacchi }
380*eef4f27bSRobert Mustacchi 
381*eef4f27bSRobert Mustacchi /*
382*eef4f27bSRobert Mustacchi  * Name:    bnx_detach
383*eef4f27bSRobert Mustacchi  *
384*eef4f27bSRobert Mustacchi  * Input:   ptr to dev_info_t, command code for the task to be executed
385*eef4f27bSRobert Mustacchi  *
386*eef4f27bSRobert Mustacchi  * Return:  DDI_SUCCESS or DDI_FAILURE.
387*eef4f27bSRobert Mustacchi  *
388*eef4f27bSRobert Mustacchi  * Description:	OS determined module detach entry point.
389*eef4f27bSRobert Mustacchi  */
390*eef4f27bSRobert Mustacchi static int
bnx_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)391*eef4f27bSRobert Mustacchi bnx_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
392*eef4f27bSRobert Mustacchi {
393*eef4f27bSRobert Mustacchi 	um_device_t *umdevice;
394*eef4f27bSRobert Mustacchi 	int ret_val = DDI_SUCCESS;
395*eef4f27bSRobert Mustacchi 
396*eef4f27bSRobert Mustacchi 	switch (cmd) {
397*eef4f27bSRobert Mustacchi 		case DDI_DETACH:
398*eef4f27bSRobert Mustacchi 			umdevice = ddi_get_driver_private(dip);
399*eef4f27bSRobert Mustacchi 			if (umdevice == NULL) {
400*eef4f27bSRobert Mustacchi 				/* Must have failed attach. */
401*eef4f27bSRobert Mustacchi 				ret_val = DDI_SUCCESS;
402*eef4f27bSRobert Mustacchi 				break;
403*eef4f27bSRobert Mustacchi 			}
404*eef4f27bSRobert Mustacchi 
405*eef4f27bSRobert Mustacchi 			/* Sanity check. */
406*eef4f27bSRobert Mustacchi 			if (umdevice == NULL) {
407*eef4f27bSRobert Mustacchi 				cmn_err(CE_WARN,
408*eef4f27bSRobert Mustacchi 				    "%s: Sanity check failed(1).", __func__);
409*eef4f27bSRobert Mustacchi 				ret_val = DDI_SUCCESS;
410*eef4f27bSRobert Mustacchi 				break;
411*eef4f27bSRobert Mustacchi 			}
412*eef4f27bSRobert Mustacchi 
413*eef4f27bSRobert Mustacchi 			/* Sanity check. */
414*eef4f27bSRobert Mustacchi 			if (umdevice->os_param.dip != dip) {
415*eef4f27bSRobert Mustacchi 				cmn_err(CE_WARN,
416*eef4f27bSRobert Mustacchi 				    "%s: Sanity check failed(2).", __func__);
417*eef4f27bSRobert Mustacchi 				ret_val = DDI_SUCCESS;
418*eef4f27bSRobert Mustacchi 				break;
419*eef4f27bSRobert Mustacchi 			}
420*eef4f27bSRobert Mustacchi 
421*eef4f27bSRobert Mustacchi 			/* Another sanity check. */
422*eef4f27bSRobert Mustacchi 			if (umdevice->intr_enabled != B_FALSE) {
423*eef4f27bSRobert Mustacchi 				cmn_err(CE_WARN, "%s: Detaching a device "
424*eef4f27bSRobert Mustacchi 				    "that is currently running!!!\n",
425*eef4f27bSRobert Mustacchi 				    umdevice->dev_name);
426*eef4f27bSRobert Mustacchi 				ret_val = DDI_FAILURE;
427*eef4f27bSRobert Mustacchi 				break;
428*eef4f27bSRobert Mustacchi 			}
429*eef4f27bSRobert Mustacchi 
430*eef4f27bSRobert Mustacchi 			if (bnx_free_system_resources(umdevice)) {
431*eef4f27bSRobert Mustacchi 				ret_val = DDI_FAILURE;
432*eef4f27bSRobert Mustacchi 				break;
433*eef4f27bSRobert Mustacchi 			}
434*eef4f27bSRobert Mustacchi 
435*eef4f27bSRobert Mustacchi 			ddi_set_driver_private(dip, (caddr_t)NULL);
436*eef4f27bSRobert Mustacchi 			kmem_free(umdevice, sizeof (um_device_t));
437*eef4f27bSRobert Mustacchi 			break;
438*eef4f27bSRobert Mustacchi 
439*eef4f27bSRobert Mustacchi 		case DDI_SUSPEND:
440*eef4f27bSRobert Mustacchi 			/* Retrieve our device structure. */
441*eef4f27bSRobert Mustacchi 			umdevice = ddi_get_driver_private(dip);
442*eef4f27bSRobert Mustacchi 			if (umdevice == NULL) {
443*eef4f27bSRobert Mustacchi 				ret_val = DDI_FAILURE;
444*eef4f27bSRobert Mustacchi 				break;
445*eef4f27bSRobert Mustacchi 			}
446*eef4f27bSRobert Mustacchi 			break;
447*eef4f27bSRobert Mustacchi 
448*eef4f27bSRobert Mustacchi 		default:
449*eef4f27bSRobert Mustacchi 			ret_val = DDI_FAILURE;
450*eef4f27bSRobert Mustacchi 			break;
451*eef4f27bSRobert Mustacchi 	}
452*eef4f27bSRobert Mustacchi 
453*eef4f27bSRobert Mustacchi 	return (ret_val);
454*eef4f27bSRobert Mustacchi }
455*eef4f27bSRobert Mustacchi 
456*eef4f27bSRobert Mustacchi /*
457*eef4f27bSRobert Mustacchi  * Name:    bnx_quiesce
458*eef4f27bSRobert Mustacchi  *
459*eef4f27bSRobert Mustacchi  * Input:   ptr to dev_info_t
460*eef4f27bSRobert Mustacchi  *
461*eef4f27bSRobert Mustacchi  * Return:  DDI_SUCCESS or DDI_FAILURE.
462*eef4f27bSRobert Mustacchi  *
463*eef4f27bSRobert Mustacchi  * Description: quiesce(9E) entry point.
464*eef4f27bSRobert Mustacchi  *              This function will make sure no more interrupts and DMA of
465*eef4f27bSRobert Mustacchi  *              the hardware. It is called when the system is single-threaded
466*eef4f27bSRobert Mustacchi  *              at high PIL with preemption disabled. Thus this function should
467*eef4f27bSRobert Mustacchi  *              not be blocked.
468*eef4f27bSRobert Mustacchi  */
469*eef4f27bSRobert Mustacchi static int
bnx_quiesce(dev_info_t * dip)470*eef4f27bSRobert Mustacchi bnx_quiesce(dev_info_t *dip)
471*eef4f27bSRobert Mustacchi {
472*eef4f27bSRobert Mustacchi 	um_device_t *umdevice;
473*eef4f27bSRobert Mustacchi 
474*eef4f27bSRobert Mustacchi 	umdevice = ddi_get_driver_private(dip);
475*eef4f27bSRobert Mustacchi 
476*eef4f27bSRobert Mustacchi 	/* Sanity check. */
477*eef4f27bSRobert Mustacchi 	if (umdevice == NULL || umdevice->os_param.dip != dip) {
478*eef4f27bSRobert Mustacchi 		cmn_err(CE_WARN, "%s: Sanity check failed.", __func__);
479*eef4f27bSRobert Mustacchi 		return (DDI_FAILURE);
480*eef4f27bSRobert Mustacchi 	}
481*eef4f27bSRobert Mustacchi 
482*eef4f27bSRobert Mustacchi 	/* Stop the device from generating any interrupts. */
483*eef4f27bSRobert Mustacchi 	lm_disable_int(&(umdevice->lm_dev));
484*eef4f27bSRobert Mustacchi 
485*eef4f27bSRobert Mustacchi 	/* Set RX mask to stop receiving any further packets */
486*eef4f27bSRobert Mustacchi 	(void) lm_set_rx_mask(&(umdevice->lm_dev), RX_FILTER_USER_IDX0,
487*eef4f27bSRobert Mustacchi 	    LM_RX_MASK_ACCEPT_NONE);
488*eef4f27bSRobert Mustacchi 
489*eef4f27bSRobert Mustacchi 	return (DDI_SUCCESS);
490*eef4f27bSRobert Mustacchi }
491*eef4f27bSRobert Mustacchi 
492*eef4f27bSRobert Mustacchi DDI_DEFINE_STREAM_OPS(bnx_dev_ops, nulldev, nulldev, bnx_attach, bnx_detach, \
493*eef4f27bSRobert Mustacchi     nodev, NULL, (D_MP | D_64BIT), NULL, bnx_quiesce);
494*eef4f27bSRobert Mustacchi 
495*eef4f27bSRobert Mustacchi static struct modldrv bnx_modldrv = {
496*eef4f27bSRobert Mustacchi 	&mod_driverops,		/* drv_modops */
497*eef4f27bSRobert Mustacchi 	BNX_PRODUCT_INFO,	/* drv_linkinfo */
498*eef4f27bSRobert Mustacchi 	&bnx_dev_ops		/* drv_dev_ops */
499*eef4f27bSRobert Mustacchi };
500*eef4f27bSRobert Mustacchi 
501*eef4f27bSRobert Mustacchi static struct modlinkage bnx_modlinkage = {
502*eef4f27bSRobert Mustacchi 	MODREV_1,	/* ml_rev */
503*eef4f27bSRobert Mustacchi 	&bnx_modldrv,	/* ml_linkage */
504*eef4f27bSRobert Mustacchi 	NULL		/* NULL termination */
505*eef4f27bSRobert Mustacchi };
506*eef4f27bSRobert Mustacchi 
507*eef4f27bSRobert Mustacchi /*
508*eef4f27bSRobert Mustacchi  * Name:        _init
509*eef4f27bSRobert Mustacchi  *
510*eef4f27bSRobert Mustacchi  * Input:       None
511*eef4f27bSRobert Mustacchi  *
512*eef4f27bSRobert Mustacchi  * Return:      SUCCESS or FAILURE.
513*eef4f27bSRobert Mustacchi  *
514*eef4f27bSRobert Mustacchi  * Description: OS determined driver module load entry point.
515*eef4f27bSRobert Mustacchi  */
516*eef4f27bSRobert Mustacchi int
_init(void)517*eef4f27bSRobert Mustacchi _init(void)
518*eef4f27bSRobert Mustacchi {
519*eef4f27bSRobert Mustacchi 	int rc;
520*eef4f27bSRobert Mustacchi 
521*eef4f27bSRobert Mustacchi 	mac_init_ops(&bnx_dev_ops, "bnx");
522*eef4f27bSRobert Mustacchi 
523*eef4f27bSRobert Mustacchi 	/* Install module information with O/S */
524*eef4f27bSRobert Mustacchi 	rc = mod_install(&bnx_modlinkage);
525*eef4f27bSRobert Mustacchi 	if (rc != 0) {
526*eef4f27bSRobert Mustacchi 		cmn_err(CE_WARN, "%s:_init - mod_install returned 0x%x", "bnx",
527*eef4f27bSRobert Mustacchi 		    rc);
528*eef4f27bSRobert Mustacchi 		return (rc);
529*eef4f27bSRobert Mustacchi 	}
530*eef4f27bSRobert Mustacchi 
531*eef4f27bSRobert Mustacchi 	cmn_err(CE_NOTE, "!%s", BNX_PRODUCT_BANNER);
532*eef4f27bSRobert Mustacchi 
533*eef4f27bSRobert Mustacchi 	return (rc);
534*eef4f27bSRobert Mustacchi }
535*eef4f27bSRobert Mustacchi 
536*eef4f27bSRobert Mustacchi 
537*eef4f27bSRobert Mustacchi 
538*eef4f27bSRobert Mustacchi /*
539*eef4f27bSRobert Mustacchi  * Name:        _fini
540*eef4f27bSRobert Mustacchi  *
541*eef4f27bSRobert Mustacchi  * Input:       None
542*eef4f27bSRobert Mustacchi  *
543*eef4f27bSRobert Mustacchi  * Return:      SUCCESS or FAILURE.
544*eef4f27bSRobert Mustacchi  *
545*eef4f27bSRobert Mustacchi  * Description: OS determined driver module unload entry point.
546*eef4f27bSRobert Mustacchi  */
547*eef4f27bSRobert Mustacchi int
_fini(void)548*eef4f27bSRobert Mustacchi _fini(void)
549*eef4f27bSRobert Mustacchi {
550*eef4f27bSRobert Mustacchi 	int rc;
551*eef4f27bSRobert Mustacchi 
552*eef4f27bSRobert Mustacchi 	rc = mod_remove(&bnx_modlinkage);
553*eef4f27bSRobert Mustacchi 
554*eef4f27bSRobert Mustacchi 	if (rc == 0) {
555*eef4f27bSRobert Mustacchi 		mac_fini_ops(&bnx_dev_ops);
556*eef4f27bSRobert Mustacchi 	}
557*eef4f27bSRobert Mustacchi 
558*eef4f27bSRobert Mustacchi 	return (rc);
559*eef4f27bSRobert Mustacchi }
560*eef4f27bSRobert Mustacchi 
561*eef4f27bSRobert Mustacchi /*
562*eef4f27bSRobert Mustacchi  * Name:        _info
563*eef4f27bSRobert Mustacchi  *
564*eef4f27bSRobert Mustacchi  * Input:       None
565*eef4f27bSRobert Mustacchi  *
566*eef4f27bSRobert Mustacchi  * Return:      SUCCESS or FAILURE.
567*eef4f27bSRobert Mustacchi  *
568*eef4f27bSRobert Mustacchi  * Description: OS determined module info entry point.
569*eef4f27bSRobert Mustacchi  */
570*eef4f27bSRobert Mustacchi int
_info(struct modinfo * modinfop)571*eef4f27bSRobert Mustacchi _info(struct modinfo *modinfop)
572*eef4f27bSRobert Mustacchi {
573*eef4f27bSRobert Mustacchi 	int rc;
574*eef4f27bSRobert Mustacchi 
575*eef4f27bSRobert Mustacchi 	rc = mod_info(&bnx_modlinkage, modinfop);
576*eef4f27bSRobert Mustacchi 
577*eef4f27bSRobert Mustacchi 	return (rc);
578*eef4f27bSRobert Mustacchi }
579