156b2bdd1SGireesh Nagabhushana /*
256b2bdd1SGireesh Nagabhushana  * This file and its contents are supplied under the terms of the
356b2bdd1SGireesh Nagabhushana  * Common Development and Distribution License ("CDDL"), version 1.0.
456b2bdd1SGireesh Nagabhushana  * You may only use this file in accordance with the terms of version
556b2bdd1SGireesh Nagabhushana  * 1.0 of the CDDL.
656b2bdd1SGireesh Nagabhushana  *
756b2bdd1SGireesh Nagabhushana  * A full copy of the text of the CDDL should have accompanied this
856b2bdd1SGireesh Nagabhushana  * source. A copy of the CDDL is also available via the Internet at
956b2bdd1SGireesh Nagabhushana  * http://www.illumos.org/license/CDDL.
1056b2bdd1SGireesh Nagabhushana  */
1156b2bdd1SGireesh Nagabhushana 
1256b2bdd1SGireesh Nagabhushana /*
1356b2bdd1SGireesh Nagabhushana  * This file is part of the Chelsio T4 support code.
1456b2bdd1SGireesh Nagabhushana  *
1556b2bdd1SGireesh Nagabhushana  * Copyright (C) 2010-2013 Chelsio Communications.  All rights reserved.
1656b2bdd1SGireesh Nagabhushana  *
1756b2bdd1SGireesh Nagabhushana  * This program is distributed in the hope that it will be useful, but WITHOUT
1856b2bdd1SGireesh Nagabhushana  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1956b2bdd1SGireesh Nagabhushana  * FITNESS FOR A PARTICULAR PURPOSE.  See the LICENSE file included in this
2056b2bdd1SGireesh Nagabhushana  * release for licensing terms and conditions.
2156b2bdd1SGireesh Nagabhushana  */
2256b2bdd1SGireesh Nagabhushana 
23618f2068SAndy Fiddaman /*
24618f2068SAndy Fiddaman  * Copyright 2023 Oxide Computer Company
25618f2068SAndy Fiddaman  */
26618f2068SAndy Fiddaman 
2756b2bdd1SGireesh Nagabhushana #include <sys/ddi.h>
2856b2bdd1SGireesh Nagabhushana #include <sys/sunddi.h>
2956b2bdd1SGireesh Nagabhushana #include <sys/sunndi.h>
3056b2bdd1SGireesh Nagabhushana #include <sys/modctl.h>
3156b2bdd1SGireesh Nagabhushana #include <sys/conf.h>
3256b2bdd1SGireesh Nagabhushana #include <sys/devops.h>
3356b2bdd1SGireesh Nagabhushana #include <sys/pci.h>
3456b2bdd1SGireesh Nagabhushana #include <sys/atomic.h>
3556b2bdd1SGireesh Nagabhushana #include <sys/types.h>
3656b2bdd1SGireesh Nagabhushana #include <sys/file.h>
3756b2bdd1SGireesh Nagabhushana #include <sys/errno.h>
3856b2bdd1SGireesh Nagabhushana #include <sys/open.h>
3956b2bdd1SGireesh Nagabhushana #include <sys/cred.h>
4056b2bdd1SGireesh Nagabhushana #include <sys/stat.h>
4156b2bdd1SGireesh Nagabhushana #include <sys/mkdev.h>
4256b2bdd1SGireesh Nagabhushana #include <sys/queue.h>
4394c3dad2SToomas Soome #include <sys/containerof.h>
4473439c83SRobert Mustacchi #include <sys/sensors.h>
45618f2068SAndy Fiddaman #include <sys/firmload.h>
4656b2bdd1SGireesh Nagabhushana 
4756b2bdd1SGireesh Nagabhushana #include "version.h"
4856b2bdd1SGireesh Nagabhushana #include "common/common.h"
49de483253SVishal Kulkarni #include "common/t4_msg.h"
5056b2bdd1SGireesh Nagabhushana #include "common/t4_regs.h"
51*c990198dSRobert Mustacchi #include "common/t4_extra_regs.h"
5256b2bdd1SGireesh Nagabhushana #include "t4_l2t.h"
5356b2bdd1SGireesh Nagabhushana 
5456b2bdd1SGireesh Nagabhushana static int t4_cb_open(dev_t *devp, int flag, int otyp, cred_t *credp);
5556b2bdd1SGireesh Nagabhushana static int t4_cb_close(dev_t dev, int flag, int otyp, cred_t *credp);
5656b2bdd1SGireesh Nagabhushana static int t4_cb_ioctl(dev_t dev, int cmd, intptr_t d, int mode, cred_t *credp,
5756b2bdd1SGireesh Nagabhushana     int *rp);
5856b2bdd1SGireesh Nagabhushana struct cb_ops t4_cb_ops = {
5956b2bdd1SGireesh Nagabhushana 	.cb_open =		t4_cb_open,
6056b2bdd1SGireesh Nagabhushana 	.cb_close =		t4_cb_close,
6156b2bdd1SGireesh Nagabhushana 	.cb_strategy =		nodev,
6294c3dad2SToomas Soome 	.cb_print =		nodev,
6356b2bdd1SGireesh Nagabhushana 	.cb_dump =		nodev,
6456b2bdd1SGireesh Nagabhushana 	.cb_read =		nodev,
6556b2bdd1SGireesh Nagabhushana 	.cb_write =		nodev,
6656b2bdd1SGireesh Nagabhushana 	.cb_ioctl =		t4_cb_ioctl,
6756b2bdd1SGireesh Nagabhushana 	.cb_devmap =		nodev,
6856b2bdd1SGireesh Nagabhushana 	.cb_mmap =		nodev,
6956b2bdd1SGireesh Nagabhushana 	.cb_segmap =		nodev,
7056b2bdd1SGireesh Nagabhushana 	.cb_chpoll =		nochpoll,
7156b2bdd1SGireesh Nagabhushana 	.cb_prop_op =		ddi_prop_op,
7256b2bdd1SGireesh Nagabhushana 	.cb_flag =		D_MP,
7356b2bdd1SGireesh Nagabhushana 	.cb_rev =		CB_REV,
7456b2bdd1SGireesh Nagabhushana 	.cb_aread =		nodev,
7556b2bdd1SGireesh Nagabhushana 	.cb_awrite =		nodev
7656b2bdd1SGireesh Nagabhushana };
7756b2bdd1SGireesh Nagabhushana 
7856b2bdd1SGireesh Nagabhushana static int t4_bus_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t op,
7956b2bdd1SGireesh Nagabhushana     void *arg, void *result);
8056b2bdd1SGireesh Nagabhushana static int t4_bus_config(dev_info_t *dip, uint_t flags, ddi_bus_config_op_t op,
8156b2bdd1SGireesh Nagabhushana     void *arg, dev_info_t **cdipp);
8256b2bdd1SGireesh Nagabhushana static int t4_bus_unconfig(dev_info_t *dip, uint_t flags,
8356b2bdd1SGireesh Nagabhushana     ddi_bus_config_op_t op, void *arg);
8456b2bdd1SGireesh Nagabhushana struct bus_ops t4_bus_ops = {
8556b2bdd1SGireesh Nagabhushana 	.busops_rev =		BUSO_REV,
8656b2bdd1SGireesh Nagabhushana 	.bus_ctl =		t4_bus_ctl,
8756b2bdd1SGireesh Nagabhushana 	.bus_prop_op =		ddi_bus_prop_op,
8856b2bdd1SGireesh Nagabhushana 	.bus_config =		t4_bus_config,
8956b2bdd1SGireesh Nagabhushana 	.bus_unconfig =		t4_bus_unconfig,
9056b2bdd1SGireesh Nagabhushana };
9156b2bdd1SGireesh Nagabhushana 
9256b2bdd1SGireesh Nagabhushana static int t4_devo_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
9356b2bdd1SGireesh Nagabhushana     void **rp);
9456b2bdd1SGireesh Nagabhushana static int t4_devo_probe(dev_info_t *dip);
9556b2bdd1SGireesh Nagabhushana static int t4_devo_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
9656b2bdd1SGireesh Nagabhushana static int t4_devo_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
9756b2bdd1SGireesh Nagabhushana static int t4_devo_quiesce(dev_info_t *dip);
9856b2bdd1SGireesh Nagabhushana struct dev_ops t4_dev_ops = {
9956b2bdd1SGireesh Nagabhushana 	.devo_rev =		DEVO_REV,
10056b2bdd1SGireesh Nagabhushana 	.devo_getinfo =		t4_devo_getinfo,
10156b2bdd1SGireesh Nagabhushana 	.devo_identify =	nulldev,
10256b2bdd1SGireesh Nagabhushana 	.devo_probe =		t4_devo_probe,
10356b2bdd1SGireesh Nagabhushana 	.devo_attach =		t4_devo_attach,
10456b2bdd1SGireesh Nagabhushana 	.devo_detach =		t4_devo_detach,
10556b2bdd1SGireesh Nagabhushana 	.devo_reset =		nodev,
10656b2bdd1SGireesh Nagabhushana 	.devo_cb_ops =		&t4_cb_ops,
10756b2bdd1SGireesh Nagabhushana 	.devo_bus_ops =		&t4_bus_ops,
10856b2bdd1SGireesh Nagabhushana 	.devo_quiesce =		&t4_devo_quiesce,
10956b2bdd1SGireesh Nagabhushana };
11056b2bdd1SGireesh Nagabhushana 
11156b2bdd1SGireesh Nagabhushana static struct modldrv modldrv = {
11256b2bdd1SGireesh Nagabhushana 	.drv_modops =		&mod_driverops,
11356b2bdd1SGireesh Nagabhushana 	.drv_linkinfo =		"Chelsio T4 nexus " DRV_VERSION,
11456b2bdd1SGireesh Nagabhushana 	.drv_dev_ops =		&t4_dev_ops
11556b2bdd1SGireesh Nagabhushana };
11656b2bdd1SGireesh Nagabhushana 
11756b2bdd1SGireesh Nagabhushana static struct modlinkage modlinkage = {
11856b2bdd1SGireesh Nagabhushana 	.ml_rev =		MODREV_1,
11956b2bdd1SGireesh Nagabhushana 	.ml_linkage =		{&modldrv, NULL},
12056b2bdd1SGireesh Nagabhushana };
12156b2bdd1SGireesh Nagabhushana 
12256b2bdd1SGireesh Nagabhushana void *t4_list;
12356b2bdd1SGireesh Nagabhushana 
12456b2bdd1SGireesh Nagabhushana struct intrs_and_queues {
12556b2bdd1SGireesh Nagabhushana 	int intr_type;		/* DDI_INTR_TYPE_* */
12656b2bdd1SGireesh Nagabhushana 	int nirq;		/* Number of vectors */
12756b2bdd1SGireesh Nagabhushana 	int intr_fwd;		/* Interrupts forwarded */
12856b2bdd1SGireesh Nagabhushana 	int ntxq10g;		/* # of NIC txq's for each 10G port */
12956b2bdd1SGireesh Nagabhushana 	int nrxq10g;		/* # of NIC rxq's for each 10G port */
13056b2bdd1SGireesh Nagabhushana 	int ntxq1g;		/* # of NIC txq's for each 1G port */
13156b2bdd1SGireesh Nagabhushana 	int nrxq1g;		/* # of NIC rxq's for each 1G port */
1323dde7c95SVishal Kulkarni #ifdef TCP_OFFLOAD_ENABLE
13356b2bdd1SGireesh Nagabhushana 	int nofldtxq10g;	/* # of TOE txq's for each 10G port */
13456b2bdd1SGireesh Nagabhushana 	int nofldrxq10g;	/* # of TOE rxq's for each 10G port */
13556b2bdd1SGireesh Nagabhushana 	int nofldtxq1g;		/* # of TOE txq's for each 1G port */
13656b2bdd1SGireesh Nagabhushana 	int nofldrxq1g;		/* # of TOE rxq's for each 1G port */
13756b2bdd1SGireesh Nagabhushana #endif
13856b2bdd1SGireesh Nagabhushana };
13956b2bdd1SGireesh Nagabhushana 
14056b2bdd1SGireesh Nagabhushana static int cpl_not_handled(struct sge_iq *iq, const struct rss_header *rss,
14156b2bdd1SGireesh Nagabhushana     mblk_t *m);
142de483253SVishal Kulkarni static int fw_msg_not_handled(struct adapter *, const __be64 *);
14356b2bdd1SGireesh Nagabhushana int t4_register_cpl_handler(struct adapter *sc, int opcode, cpl_handler_t h);
14456b2bdd1SGireesh Nagabhushana static unsigned int getpf(struct adapter *sc);
14556b2bdd1SGireesh Nagabhushana static int prep_firmware(struct adapter *sc);
14656b2bdd1SGireesh Nagabhushana static int upload_config_file(struct adapter *sc, uint32_t *mt, uint32_t *ma);
14756b2bdd1SGireesh Nagabhushana static int partition_resources(struct adapter *sc);
1483dde7c95SVishal Kulkarni static int adap__pre_init_tweaks(struct adapter *sc);
14956b2bdd1SGireesh Nagabhushana static int get_params__pre_init(struct adapter *sc);
15056b2bdd1SGireesh Nagabhushana static int get_params__post_init(struct adapter *sc);
151de483253SVishal Kulkarni static int set_params__post_init(struct adapter *);
15256b2bdd1SGireesh Nagabhushana static void setup_memwin(struct adapter *sc);
153de483253SVishal Kulkarni static int validate_mt_off_len(struct adapter *, int, uint32_t, int,
154de483253SVishal Kulkarni     uint32_t *);
155de483253SVishal Kulkarni void memwin_info(struct adapter *, int, uint32_t *, uint32_t *);
156de483253SVishal Kulkarni uint32_t position_memwin(struct adapter *, int, uint32_t);
15756b2bdd1SGireesh Nagabhushana static int prop_lookup_int_array(struct adapter *sc, char *name, int *data,
15856b2bdd1SGireesh Nagabhushana     uint_t count);
15956b2bdd1SGireesh Nagabhushana static int prop_lookup_int_array(struct adapter *sc, char *name, int *data,
16056b2bdd1SGireesh Nagabhushana     uint_t count);
16156b2bdd1SGireesh Nagabhushana static int init_driver_props(struct adapter *sc, struct driver_properties *p);
16256b2bdd1SGireesh Nagabhushana static int remove_extra_props(struct adapter *sc, int n10g, int n1g);
16356b2bdd1SGireesh Nagabhushana static int cfg_itype_and_nqueues(struct adapter *sc, int n10g, int n1g,
16456b2bdd1SGireesh Nagabhushana     struct intrs_and_queues *iaq);
16556b2bdd1SGireesh Nagabhushana static int add_child_node(struct adapter *sc, int idx);
16656b2bdd1SGireesh Nagabhushana static int remove_child_node(struct adapter *sc, int idx);
16756b2bdd1SGireesh Nagabhushana static kstat_t *setup_kstats(struct adapter *sc);
168de483253SVishal Kulkarni static kstat_t *setup_wc_kstats(struct adapter *);
169de483253SVishal Kulkarni static int update_wc_kstats(kstat_t *, int);
1703dde7c95SVishal Kulkarni #ifdef TCP_OFFLOAD_ENABLE
17156b2bdd1SGireesh Nagabhushana static int toe_capability(struct port_info *pi, int enable);
17256b2bdd1SGireesh Nagabhushana static int activate_uld(struct adapter *sc, int id, struct uld_softc *usc);
17356b2bdd1SGireesh Nagabhushana static int deactivate_uld(struct uld_softc *usc);
17456b2bdd1SGireesh Nagabhushana #endif
17556b2bdd1SGireesh Nagabhushana static kmutex_t t4_adapter_list_lock;
17656b2bdd1SGireesh Nagabhushana static SLIST_HEAD(, adapter) t4_adapter_list;
1773dde7c95SVishal Kulkarni #ifdef TCP_OFFLOAD_ENABLE
17856b2bdd1SGireesh Nagabhushana static kmutex_t t4_uld_list_lock;
17956b2bdd1SGireesh Nagabhushana static SLIST_HEAD(, uld_info) t4_uld_list;
18056b2bdd1SGireesh Nagabhushana #endif
18156b2bdd1SGireesh Nagabhushana 
18273439c83SRobert Mustacchi static int t4_temperature_read(void *, sensor_ioctl_scalar_t *);
18373439c83SRobert Mustacchi static int t4_voltage_read(void *, sensor_ioctl_scalar_t *);
18473439c83SRobert Mustacchi static const ksensor_ops_t t4_temp_ops = {
18573439c83SRobert Mustacchi 	.kso_kind = ksensor_kind_temperature,
18673439c83SRobert Mustacchi 	.kso_scalar = t4_temperature_read
18773439c83SRobert Mustacchi };
18873439c83SRobert Mustacchi 
18973439c83SRobert Mustacchi static const ksensor_ops_t t4_volt_ops = {
19073439c83SRobert Mustacchi 	.kso_kind = ksensor_kind_voltage,
19173439c83SRobert Mustacchi 	.kso_scalar = t4_voltage_read
19273439c83SRobert Mustacchi };
19373439c83SRobert Mustacchi 
1942e7b048cSRobert Mustacchi static int t4_ufm_getcaps(ddi_ufm_handle_t *, void *, ddi_ufm_cap_t *);
1952e7b048cSRobert Mustacchi static int t4_ufm_fill_image(ddi_ufm_handle_t *, void *, uint_t,
1962e7b048cSRobert Mustacchi     ddi_ufm_image_t *);
1972e7b048cSRobert Mustacchi static int t4_ufm_fill_slot(ddi_ufm_handle_t *, void *, uint_t, uint_t,
1982e7b048cSRobert Mustacchi     ddi_ufm_slot_t *);
1992e7b048cSRobert Mustacchi static ddi_ufm_ops_t t4_ufm_ops = {
2002e7b048cSRobert Mustacchi 	.ddi_ufm_op_fill_image = t4_ufm_fill_image,
2012e7b048cSRobert Mustacchi 	.ddi_ufm_op_fill_slot = t4_ufm_fill_slot,
2022e7b048cSRobert Mustacchi 	.ddi_ufm_op_getcaps = t4_ufm_getcaps
2032e7b048cSRobert Mustacchi };
2042e7b048cSRobert Mustacchi 
20556b2bdd1SGireesh Nagabhushana int
_init(void)20656b2bdd1SGireesh Nagabhushana _init(void)
20756b2bdd1SGireesh Nagabhushana {
20856b2bdd1SGireesh Nagabhushana 	int rc;
20956b2bdd1SGireesh Nagabhushana 
21056b2bdd1SGireesh Nagabhushana 	rc = ddi_soft_state_init(&t4_list, sizeof (struct adapter), 0);
21156b2bdd1SGireesh Nagabhushana 	if (rc != 0)
21256b2bdd1SGireesh Nagabhushana 		return (rc);
21356b2bdd1SGireesh Nagabhushana 
21456b2bdd1SGireesh Nagabhushana 	rc = mod_install(&modlinkage);
21556b2bdd1SGireesh Nagabhushana 	if (rc != 0)
21656b2bdd1SGireesh Nagabhushana 		ddi_soft_state_fini(&t4_list);
21756b2bdd1SGireesh Nagabhushana 
21856b2bdd1SGireesh Nagabhushana 	mutex_init(&t4_adapter_list_lock, NULL, MUTEX_DRIVER, NULL);
21956b2bdd1SGireesh Nagabhushana 	SLIST_INIT(&t4_adapter_list);
22056b2bdd1SGireesh Nagabhushana 
2213dde7c95SVishal Kulkarni #ifdef TCP_OFFLOAD_ENABLE
22256b2bdd1SGireesh Nagabhushana 	mutex_init(&t4_uld_list_lock, NULL, MUTEX_DRIVER, NULL);
22356b2bdd1SGireesh Nagabhushana 	SLIST_INIT(&t4_uld_list);
22456b2bdd1SGireesh Nagabhushana #endif
22556b2bdd1SGireesh Nagabhushana 
22656b2bdd1SGireesh Nagabhushana 	return (rc);
22756b2bdd1SGireesh Nagabhushana }
22856b2bdd1SGireesh Nagabhushana 
22956b2bdd1SGireesh Nagabhushana int
_fini(void)23056b2bdd1SGireesh Nagabhushana _fini(void)
23156b2bdd1SGireesh Nagabhushana {
23256b2bdd1SGireesh Nagabhushana 	int rc;
23356b2bdd1SGireesh Nagabhushana 
23456b2bdd1SGireesh Nagabhushana 	rc = mod_remove(&modlinkage);
23556b2bdd1SGireesh Nagabhushana 	if (rc != 0)
23656b2bdd1SGireesh Nagabhushana 		return (rc);
23756b2bdd1SGireesh Nagabhushana 
23856b2bdd1SGireesh Nagabhushana 	ddi_soft_state_fini(&t4_list);
23956b2bdd1SGireesh Nagabhushana 	return (0);
24056b2bdd1SGireesh Nagabhushana }
24156b2bdd1SGireesh Nagabhushana 
24256b2bdd1SGireesh Nagabhushana int
_info(struct modinfo * mi)24356b2bdd1SGireesh Nagabhushana _info(struct modinfo *mi)
24456b2bdd1SGireesh Nagabhushana {
24556b2bdd1SGireesh Nagabhushana 	return (mod_info(&modlinkage, mi));
24656b2bdd1SGireesh Nagabhushana }
24756b2bdd1SGireesh Nagabhushana 
24856b2bdd1SGireesh Nagabhushana /* ARGSUSED */
24956b2bdd1SGireesh Nagabhushana static int
t4_devo_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** rp)25056b2bdd1SGireesh Nagabhushana t4_devo_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **rp)
25156b2bdd1SGireesh Nagabhushana {
25256b2bdd1SGireesh Nagabhushana 	struct adapter *sc;
25356b2bdd1SGireesh Nagabhushana 	minor_t minor;
25456b2bdd1SGireesh Nagabhushana 
25556b2bdd1SGireesh Nagabhushana 	minor = getminor((dev_t)arg);	/* same as instance# in our case */
25656b2bdd1SGireesh Nagabhushana 
25756b2bdd1SGireesh Nagabhushana 	if (cmd == DDI_INFO_DEVT2DEVINFO) {
25856b2bdd1SGireesh Nagabhushana 		sc = ddi_get_soft_state(t4_list, minor);
25956b2bdd1SGireesh Nagabhushana 		if (sc == NULL)
26056b2bdd1SGireesh Nagabhushana 			return (DDI_FAILURE);
26156b2bdd1SGireesh Nagabhushana 
26256b2bdd1SGireesh Nagabhushana 		ASSERT(sc->dev == (dev_t)arg);
26356b2bdd1SGireesh Nagabhushana 		*rp = (void *)sc->dip;
26456b2bdd1SGireesh Nagabhushana 	} else if (cmd == DDI_INFO_DEVT2INSTANCE)
26556b2bdd1SGireesh Nagabhushana 		*rp = (void *) (unsigned long) minor;
26656b2bdd1SGireesh Nagabhushana 	else
26756b2bdd1SGireesh Nagabhushana 		ASSERT(0);
26856b2bdd1SGireesh Nagabhushana 
26956b2bdd1SGireesh Nagabhushana 	return (DDI_SUCCESS);
27056b2bdd1SGireesh Nagabhushana }
27156b2bdd1SGireesh Nagabhushana 
27256b2bdd1SGireesh Nagabhushana static int
t4_devo_probe(dev_info_t * dip)27356b2bdd1SGireesh Nagabhushana t4_devo_probe(dev_info_t *dip)
27456b2bdd1SGireesh Nagabhushana {
27556b2bdd1SGireesh Nagabhushana 	int rc, id, *reg;
27656b2bdd1SGireesh Nagabhushana 	uint_t n, pf;
27756b2bdd1SGireesh Nagabhushana 
27856b2bdd1SGireesh Nagabhushana 	id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
27956b2bdd1SGireesh Nagabhushana 	    "device-id", 0xffff);
28056b2bdd1SGireesh Nagabhushana 	if (id == 0xffff)
28156b2bdd1SGireesh Nagabhushana 		return (DDI_PROBE_DONTCARE);
28256b2bdd1SGireesh Nagabhushana 
28356b2bdd1SGireesh Nagabhushana 	rc = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
28456b2bdd1SGireesh Nagabhushana 	    "reg", &reg, &n);
28556b2bdd1SGireesh Nagabhushana 	if (rc != DDI_SUCCESS)
28656b2bdd1SGireesh Nagabhushana 		return (DDI_PROBE_DONTCARE);
28756b2bdd1SGireesh Nagabhushana 
28856b2bdd1SGireesh Nagabhushana 	pf = PCI_REG_FUNC_G(reg[0]);
28956b2bdd1SGireesh Nagabhushana 	ddi_prop_free(reg);
29056b2bdd1SGireesh Nagabhushana 
29156b2bdd1SGireesh Nagabhushana 	/* Prevent driver attachment on any PF except 0 on the FPGA */
29256b2bdd1SGireesh Nagabhushana 	if (id == 0xa000 && pf != 0)
29356b2bdd1SGireesh Nagabhushana 		return (DDI_PROBE_FAILURE);
29456b2bdd1SGireesh Nagabhushana 
29556b2bdd1SGireesh Nagabhushana 	return (DDI_PROBE_DONTCARE);
29656b2bdd1SGireesh Nagabhushana }
29756b2bdd1SGireesh Nagabhushana 
29856b2bdd1SGireesh Nagabhushana static int
t4_devo_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)29956b2bdd1SGireesh Nagabhushana t4_devo_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
30056b2bdd1SGireesh Nagabhushana {
30156b2bdd1SGireesh Nagabhushana 	struct adapter *sc = NULL;
30256b2bdd1SGireesh Nagabhushana 	struct sge *s;
3033dde7c95SVishal Kulkarni 	int i, instance, rc = DDI_SUCCESS, rqidx, tqidx, q;
30477ac03cbSRahul Lakkireddy 	int irq = 0, nxg = 0, n1g = 0;
3053dde7c95SVishal Kulkarni #ifdef TCP_OFFLOAD_ENABLE
30656b2bdd1SGireesh Nagabhushana 	int ofld_rqidx, ofld_tqidx;
30756b2bdd1SGireesh Nagabhushana #endif
30856b2bdd1SGireesh Nagabhushana 	char name[16];
30956b2bdd1SGireesh Nagabhushana 	struct driver_properties *prp;
31056b2bdd1SGireesh Nagabhushana 	struct intrs_and_queues iaq;
31156b2bdd1SGireesh Nagabhushana 	ddi_device_acc_attr_t da = {
31256b2bdd1SGireesh Nagabhushana 		.devacc_attr_version = DDI_DEVICE_ATTR_V0,
31356b2bdd1SGireesh Nagabhushana 		.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC,
314*c990198dSRobert Mustacchi 		.devacc_attr_dataorder = DDI_STRICTORDER_ACC
31556b2bdd1SGireesh Nagabhushana 	};
316de483253SVishal Kulkarni 	ddi_device_acc_attr_t da1 = {
317de483253SVishal Kulkarni 		.devacc_attr_version = DDI_DEVICE_ATTR_V0,
318de483253SVishal Kulkarni 		.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC,
319fe07c600SRobert Mustacchi 		.devacc_attr_dataorder = DDI_STRICTORDER_ACC
320de483253SVishal Kulkarni 	};
32194c3dad2SToomas Soome 
32256b2bdd1SGireesh Nagabhushana 	if (cmd != DDI_ATTACH)
32356b2bdd1SGireesh Nagabhushana 		return (DDI_FAILURE);
32456b2bdd1SGireesh Nagabhushana 
32556b2bdd1SGireesh Nagabhushana 	/*
32656b2bdd1SGireesh Nagabhushana 	 * Allocate space for soft state.
32756b2bdd1SGireesh Nagabhushana 	 */
32856b2bdd1SGireesh Nagabhushana 	instance = ddi_get_instance(dip);
32956b2bdd1SGireesh Nagabhushana 	rc = ddi_soft_state_zalloc(t4_list, instance);
33056b2bdd1SGireesh Nagabhushana 	if (rc != DDI_SUCCESS) {
33156b2bdd1SGireesh Nagabhushana 		cxgb_printf(dip, CE_WARN,
33256b2bdd1SGireesh Nagabhushana 		    "failed to allocate soft state: %d", rc);
33356b2bdd1SGireesh Nagabhushana 		return (DDI_FAILURE);
33456b2bdd1SGireesh Nagabhushana 	}
33556b2bdd1SGireesh Nagabhushana 
33656b2bdd1SGireesh Nagabhushana 	sc = ddi_get_soft_state(t4_list, instance);
33756b2bdd1SGireesh Nagabhushana 	sc->dip = dip;
33856b2bdd1SGireesh Nagabhushana 	sc->dev = makedevice(ddi_driver_major(dip), instance);
33956b2bdd1SGireesh Nagabhushana 	mutex_init(&sc->lock, NULL, MUTEX_DRIVER, NULL);
34056b2bdd1SGireesh Nagabhushana 	cv_init(&sc->cv, NULL, CV_DRIVER, NULL);
34156b2bdd1SGireesh Nagabhushana 	mutex_init(&sc->sfl_lock, NULL, MUTEX_DRIVER, NULL);
342bbb9d5d6SJohn Levon 	TAILQ_INIT(&sc->sfl);
3436feac2e3SRahul Lakkireddy 	mutex_init(&sc->mbox_lock, NULL, MUTEX_DRIVER, NULL);
3446feac2e3SRahul Lakkireddy 	STAILQ_INIT(&sc->mbox_list);
34556b2bdd1SGireesh Nagabhushana 
34656b2bdd1SGireesh Nagabhushana 	mutex_enter(&t4_adapter_list_lock);
34756b2bdd1SGireesh Nagabhushana 	SLIST_INSERT_HEAD(&t4_adapter_list, sc, link);
34856b2bdd1SGireesh Nagabhushana 	mutex_exit(&t4_adapter_list_lock);
34956b2bdd1SGireesh Nagabhushana 
35056b2bdd1SGireesh Nagabhushana 	sc->pf = getpf(sc);
35156b2bdd1SGireesh Nagabhushana 	if (sc->pf > 8) {
35256b2bdd1SGireesh Nagabhushana 		rc = EINVAL;
35356b2bdd1SGireesh Nagabhushana 		cxgb_printf(dip, CE_WARN,
35456b2bdd1SGireesh Nagabhushana 		    "failed to determine PCI PF# of device");
35556b2bdd1SGireesh Nagabhushana 		goto done;
35656b2bdd1SGireesh Nagabhushana 	}
35756b2bdd1SGireesh Nagabhushana 	sc->mbox = sc->pf;
35856b2bdd1SGireesh Nagabhushana 
359de483253SVishal Kulkarni 	/* Initialize the driver properties */
360de483253SVishal Kulkarni 	prp = &sc->props;
361de483253SVishal Kulkarni 	(void)init_driver_props(sc, prp);
362de483253SVishal Kulkarni 
36356b2bdd1SGireesh Nagabhushana 	/*
36456b2bdd1SGireesh Nagabhushana 	 * Enable access to the PCI config space.
36556b2bdd1SGireesh Nagabhushana 	 */
36656b2bdd1SGireesh Nagabhushana 	rc = pci_config_setup(dip, &sc->pci_regh);
36756b2bdd1SGireesh Nagabhushana 	if (rc != DDI_SUCCESS) {
36856b2bdd1SGireesh Nagabhushana 		cxgb_printf(dip, CE_WARN,
36956b2bdd1SGireesh Nagabhushana 		    "failed to enable PCI config space access: %d", rc);
37056b2bdd1SGireesh Nagabhushana 		goto done;
37156b2bdd1SGireesh Nagabhushana 	}
37256b2bdd1SGireesh Nagabhushana 
37356b2bdd1SGireesh Nagabhushana 	/* TODO: Set max read request to 4K */
37456b2bdd1SGireesh Nagabhushana 
37556b2bdd1SGireesh Nagabhushana 	/*
37656b2bdd1SGireesh Nagabhushana 	 * Enable MMIO access.
37756b2bdd1SGireesh Nagabhushana 	 */
37856b2bdd1SGireesh Nagabhushana 	rc = ddi_regs_map_setup(dip, 1, &sc->regp, 0, 0, &da, &sc->regh);
37956b2bdd1SGireesh Nagabhushana 	if (rc != DDI_SUCCESS) {
38056b2bdd1SGireesh Nagabhushana 		cxgb_printf(dip, CE_WARN,
38156b2bdd1SGireesh Nagabhushana 		    "failed to map device registers: %d", rc);
38256b2bdd1SGireesh Nagabhushana 		goto done;
38356b2bdd1SGireesh Nagabhushana 	}
38456b2bdd1SGireesh Nagabhushana 
38556b2bdd1SGireesh Nagabhushana 	(void) memset(sc->chan_map, 0xff, sizeof (sc->chan_map));
38656b2bdd1SGireesh Nagabhushana 
38756b2bdd1SGireesh Nagabhushana 	/*
38856b2bdd1SGireesh Nagabhushana 	 * Initialize cpl handler.
38956b2bdd1SGireesh Nagabhushana 	 */
39056b2bdd1SGireesh Nagabhushana 	for (i = 0; i < ARRAY_SIZE(sc->cpl_handler); i++) {
39156b2bdd1SGireesh Nagabhushana 		sc->cpl_handler[i] = cpl_not_handled;
39256b2bdd1SGireesh Nagabhushana 	}
39356b2bdd1SGireesh Nagabhushana 
394de483253SVishal Kulkarni 	for (i = 0; i < ARRAY_SIZE(sc->fw_msg_handler); i++) {
395de483253SVishal Kulkarni 		sc->fw_msg_handler[i] = fw_msg_not_handled;
396de483253SVishal Kulkarni 	}
39794c3dad2SToomas Soome 
39806b05760SVishal Kulkarni 	for (i = 0; i < NCHAN; i++) {
39906b05760SVishal Kulkarni 		(void) snprintf(name, sizeof (name), "%s-%d",
40006b05760SVishal Kulkarni 				"reclaim", i);
40106b05760SVishal Kulkarni 		sc->tq[i] = ddi_taskq_create(sc->dip,
40206b05760SVishal Kulkarni 		   name, 1, TASKQ_DEFAULTPRI, 0);
40306b05760SVishal Kulkarni 
40406b05760SVishal Kulkarni 		if (sc->tq[i] == NULL) {
40506b05760SVishal Kulkarni 			cxgb_printf(dip, CE_WARN,
40606b05760SVishal Kulkarni 				   "failed to create task queues");
40706b05760SVishal Kulkarni 			rc = DDI_FAILURE;
40806b05760SVishal Kulkarni 			goto done;
40906b05760SVishal Kulkarni 		}
41006b05760SVishal Kulkarni 	}
41106b05760SVishal Kulkarni 
41256b2bdd1SGireesh Nagabhushana 	/*
41356b2bdd1SGireesh Nagabhushana 	 * Prepare the adapter for operation.
41456b2bdd1SGireesh Nagabhushana 	 */
4153dde7c95SVishal Kulkarni 	rc = -t4_prep_adapter(sc, false);
41656b2bdd1SGireesh Nagabhushana 	if (rc != 0) {
41756b2bdd1SGireesh Nagabhushana 		cxgb_printf(dip, CE_WARN, "failed to prepare adapter: %d", rc);
41856b2bdd1SGireesh Nagabhushana 		goto done;
41956b2bdd1SGireesh Nagabhushana 	}
42056b2bdd1SGireesh Nagabhushana 
421de483253SVishal Kulkarni 	/*
422de483253SVishal Kulkarni 	 * Enable BAR1 access.
423de483253SVishal Kulkarni 	 */
424de483253SVishal Kulkarni 	sc->doorbells |= DOORBELL_KDB;
425de483253SVishal Kulkarni 	rc = ddi_regs_map_setup(dip, 2, &sc->reg1p, 0, 0, &da1, &sc->reg1h);
426de483253SVishal Kulkarni 	if (rc != DDI_SUCCESS) {
427de483253SVishal Kulkarni 		cxgb_printf(dip, CE_WARN,
428de483253SVishal Kulkarni 		    "failed to map BAR1 device registers: %d", rc);
429de483253SVishal Kulkarni 		goto done;
430de483253SVishal Kulkarni 	} else {
431de483253SVishal Kulkarni 		if (is_t5(sc->params.chip)) {
432de483253SVishal Kulkarni 			sc->doorbells |= DOORBELL_UDB;
433de483253SVishal Kulkarni 			if (prp->wc) {
434de483253SVishal Kulkarni 				/*
435de483253SVishal Kulkarni 				 * Enable write combining on BAR2.  This is the
436de483253SVishal Kulkarni 				 * userspace doorbell BAR and is split into 128B
437de483253SVishal Kulkarni 				 * (UDBS_SEG_SIZE) doorbell regions, each associated
438de483253SVishal Kulkarni 				 * with an egress queue.  The first 64B has the doorbell
439de483253SVishal Kulkarni 				 * and the second 64B can be used to submit a tx work
440de483253SVishal Kulkarni 				 * request with an implicit doorbell.
441de483253SVishal Kulkarni 				 */
442de483253SVishal Kulkarni 				sc->doorbells &= ~DOORBELL_UDB;
443de483253SVishal Kulkarni 				sc->doorbells |= (DOORBELL_WCWR |
444de483253SVishal Kulkarni 				    DOORBELL_UDBWC);
445de483253SVishal Kulkarni 				t4_write_reg(sc, A_SGE_STAT_CFG,
446de483253SVishal Kulkarni 				    V_STATSOURCE_T5(7) | V_STATMODE(0));
447de483253SVishal Kulkarni 			}
448de483253SVishal Kulkarni 		}
449de483253SVishal Kulkarni 	}
450de483253SVishal Kulkarni 
45156b2bdd1SGireesh Nagabhushana 	/*
45256b2bdd1SGireesh Nagabhushana 	 * Do this really early.  Note that minor number = instance.
45356b2bdd1SGireesh Nagabhushana 	 */
45456b2bdd1SGireesh Nagabhushana 	(void) snprintf(name, sizeof (name), "%s,%d", T4_NEXUS_NAME, instance);
45556b2bdd1SGireesh Nagabhushana 	rc = ddi_create_minor_node(dip, name, S_IFCHR, instance,
45656b2bdd1SGireesh Nagabhushana 	    DDI_NT_NEXUS, 0);
45756b2bdd1SGireesh Nagabhushana 	if (rc != DDI_SUCCESS) {
45856b2bdd1SGireesh Nagabhushana 		cxgb_printf(dip, CE_WARN,
45956b2bdd1SGireesh Nagabhushana 		    "failed to create device node: %d", rc);
46056b2bdd1SGireesh Nagabhushana 		rc = DDI_SUCCESS; /* carry on */
46156b2bdd1SGireesh Nagabhushana 	}
46256b2bdd1SGireesh Nagabhushana 
46356b2bdd1SGireesh Nagabhushana 	/* Do this early. Memory window is required for loading config file. */
46456b2bdd1SGireesh Nagabhushana 	setup_memwin(sc);
46556b2bdd1SGireesh Nagabhushana 
46656b2bdd1SGireesh Nagabhushana 	/* Prepare the firmware for operation */
46756b2bdd1SGireesh Nagabhushana 	rc = prep_firmware(sc);
46856b2bdd1SGireesh Nagabhushana 	if (rc != 0)
46956b2bdd1SGireesh Nagabhushana 		goto done; /* error message displayed already */
47056b2bdd1SGireesh Nagabhushana 
4713dde7c95SVishal Kulkarni 	rc = adap__pre_init_tweaks(sc);
4723dde7c95SVishal Kulkarni 	if (rc != 0)
4733dde7c95SVishal Kulkarni 		goto done;
4743dde7c95SVishal Kulkarni 
47556b2bdd1SGireesh Nagabhushana 	rc = get_params__pre_init(sc);
47656b2bdd1SGireesh Nagabhushana 	if (rc != 0)
47756b2bdd1SGireesh Nagabhushana 		goto done; /* error message displayed already */
47856b2bdd1SGireesh Nagabhushana 
47956b2bdd1SGireesh Nagabhushana 	t4_sge_init(sc);
48056b2bdd1SGireesh Nagabhushana 
48156b2bdd1SGireesh Nagabhushana 	if (sc->flags & MASTER_PF) {
48256b2bdd1SGireesh Nagabhushana 		/* get basic stuff going */
48356b2bdd1SGireesh Nagabhushana 		rc = -t4_fw_initialize(sc, sc->mbox);
48456b2bdd1SGireesh Nagabhushana 		if (rc != 0) {
48556b2bdd1SGireesh Nagabhushana 			cxgb_printf(sc->dip, CE_WARN,
48656b2bdd1SGireesh Nagabhushana 			    "early init failed: %d.\n", rc);
48756b2bdd1SGireesh Nagabhushana 			goto done;
48856b2bdd1SGireesh Nagabhushana 		}
48956b2bdd1SGireesh Nagabhushana 	}
49056b2bdd1SGireesh Nagabhushana 
49156b2bdd1SGireesh Nagabhushana 	rc = get_params__post_init(sc);
49256b2bdd1SGireesh Nagabhushana 	if (rc != 0)
49356b2bdd1SGireesh Nagabhushana 		goto done; /* error message displayed already */
49456b2bdd1SGireesh Nagabhushana 
495de483253SVishal Kulkarni 	rc = set_params__post_init(sc);
496de483253SVishal Kulkarni 	if (rc != 0)
497de483253SVishal Kulkarni 		goto done; /* error message displayed already */
498de483253SVishal Kulkarni 
49956b2bdd1SGireesh Nagabhushana 	/*
50056b2bdd1SGireesh Nagabhushana 	 * TODO: This is the place to call t4_set_filter_mode()
50156b2bdd1SGireesh Nagabhushana 	 */
50256b2bdd1SGireesh Nagabhushana 
50356b2bdd1SGireesh Nagabhushana 	/* tweak some settings */
50456b2bdd1SGireesh Nagabhushana 	t4_write_reg(sc, A_TP_SHIFT_CNT, V_SYNSHIFTMAX(6) | V_RXTSHIFTMAXR1(4) |
50556b2bdd1SGireesh Nagabhushana 	    V_RXTSHIFTMAXR2(15) | V_PERSHIFTBACKOFFMAX(8) | V_PERSHIFTMAX(8) |
50656b2bdd1SGireesh Nagabhushana 	    V_KEEPALIVEMAXR1(4) | V_KEEPALIVEMAXR2(9));
50756b2bdd1SGireesh Nagabhushana 	t4_write_reg(sc, A_ULP_RX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12));
50856b2bdd1SGireesh Nagabhushana 
50956b2bdd1SGireesh Nagabhushana 	/*
51056b2bdd1SGireesh Nagabhushana 	 * Work-around for bug 2619
51156b2bdd1SGireesh Nagabhushana 	 * Set DisableVlan field in TP_RSS_CONFIG_VRT register so that the
51256b2bdd1SGireesh Nagabhushana 	 * VLAN tag extraction is disabled.
51356b2bdd1SGireesh Nagabhushana 	 */
51456b2bdd1SGireesh Nagabhushana 	t4_set_reg_field(sc, A_TP_RSS_CONFIG_VRT, F_DISABLEVLAN, F_DISABLEVLAN);
51556b2bdd1SGireesh Nagabhushana 
51656b2bdd1SGireesh Nagabhushana 	/* Store filter mode */
51756b2bdd1SGireesh Nagabhushana 	t4_read_indirect(sc, A_TP_PIO_ADDR, A_TP_PIO_DATA, &sc->filter_mode, 1,
51856b2bdd1SGireesh Nagabhushana 	    A_TP_VLAN_PRI_MAP);
51956b2bdd1SGireesh Nagabhushana 
52056b2bdd1SGireesh Nagabhushana 	/*
52156b2bdd1SGireesh Nagabhushana 	 * First pass over all the ports - allocate VIs and initialize some
52256b2bdd1SGireesh Nagabhushana 	 * basic parameters like mac address, port type, etc.  We also figure
52356b2bdd1SGireesh Nagabhushana 	 * out whether a port is 10G or 1G and use that information when
52456b2bdd1SGireesh Nagabhushana 	 * calculating how many interrupts to attempt to allocate.
52556b2bdd1SGireesh Nagabhushana 	 */
52656b2bdd1SGireesh Nagabhushana 	for_each_port(sc, i) {
52756b2bdd1SGireesh Nagabhushana 		struct port_info *pi;
52856b2bdd1SGireesh Nagabhushana 
52956b2bdd1SGireesh Nagabhushana 		pi = kmem_zalloc(sizeof (*pi), KM_SLEEP);
53056b2bdd1SGireesh Nagabhushana 		sc->port[i] = pi;
53156b2bdd1SGireesh Nagabhushana 
53256b2bdd1SGireesh Nagabhushana 		/* These must be set before t4_port_init */
53356b2bdd1SGireesh Nagabhushana 		pi->adapter = sc;
53456b2bdd1SGireesh Nagabhushana 		/* LINTED: E_ASSIGN_NARROW_CONV */
53556b2bdd1SGireesh Nagabhushana 		pi->port_id = i;
5363dde7c95SVishal Kulkarni 	}
53756b2bdd1SGireesh Nagabhushana 
5383dde7c95SVishal Kulkarni 	/* Allocate the vi and initialize parameters like mac addr */
5393dde7c95SVishal Kulkarni 	rc = -t4_port_init(sc, sc->mbox, sc->pf, 0);
5403dde7c95SVishal Kulkarni 	if (rc) {
5413dde7c95SVishal Kulkarni 		cxgb_printf(dip, CE_WARN,
5423dde7c95SVishal Kulkarni 			    "unable to initialize port: %d", rc);
5433dde7c95SVishal Kulkarni 		goto done;
5443dde7c95SVishal Kulkarni 	}
5453dde7c95SVishal Kulkarni 
5463dde7c95SVishal Kulkarni 	for_each_port(sc, i) {
5473dde7c95SVishal Kulkarni 		struct port_info *pi = sc->port[i];
54856b2bdd1SGireesh Nagabhushana 
54956b2bdd1SGireesh Nagabhushana 		mutex_init(&pi->lock, NULL, MUTEX_DRIVER, NULL);
55056b2bdd1SGireesh Nagabhushana 		pi->mtu = ETHERMTU;
55156b2bdd1SGireesh Nagabhushana 
55277ac03cbSRahul Lakkireddy 		if (is_10XG_port(pi)) {
55377ac03cbSRahul Lakkireddy 			nxg++;
55456b2bdd1SGireesh Nagabhushana 			pi->tmr_idx = prp->tmr_idx_10g;
55556b2bdd1SGireesh Nagabhushana 			pi->pktc_idx = prp->pktc_idx_10g;
55656b2bdd1SGireesh Nagabhushana 		} else {
55756b2bdd1SGireesh Nagabhushana 			n1g++;
55856b2bdd1SGireesh Nagabhushana 			pi->tmr_idx = prp->tmr_idx_1g;
55956b2bdd1SGireesh Nagabhushana 			pi->pktc_idx = prp->pktc_idx_1g;
56056b2bdd1SGireesh Nagabhushana 		}
56156b2bdd1SGireesh Nagabhushana 
56256b2bdd1SGireesh Nagabhushana 		pi->xact_addr_filt = -1;
56356b2bdd1SGireesh Nagabhushana 		t4_mc_init(pi);
56456b2bdd1SGireesh Nagabhushana 
56556b2bdd1SGireesh Nagabhushana 		setbit(&sc->registered_device_map, i);
56656b2bdd1SGireesh Nagabhushana 	}
5673dde7c95SVishal Kulkarni 
5683dde7c95SVishal Kulkarni 	(void) remove_extra_props(sc, nxg, n1g);
56956b2bdd1SGireesh Nagabhushana 
57056b2bdd1SGireesh Nagabhushana 	if (sc->registered_device_map == 0) {
57156b2bdd1SGireesh Nagabhushana 		cxgb_printf(dip, CE_WARN, "no usable ports");
57256b2bdd1SGireesh Nagabhushana 		rc = DDI_FAILURE;
57356b2bdd1SGireesh Nagabhushana 		goto done;
57456b2bdd1SGireesh Nagabhushana 	}
57556b2bdd1SGireesh Nagabhushana 
5763dde7c95SVishal Kulkarni 	rc = cfg_itype_and_nqueues(sc, nxg, n1g, &iaq);
57756b2bdd1SGireesh Nagabhushana 	if (rc != 0)
57856b2bdd1SGireesh Nagabhushana 		goto done; /* error message displayed already */
57956b2bdd1SGireesh Nagabhushana 
58056b2bdd1SGireesh Nagabhushana 	sc->intr_type = iaq.intr_type;
58156b2bdd1SGireesh Nagabhushana 	sc->intr_count = iaq.nirq;
58256b2bdd1SGireesh Nagabhushana 
5833dde7c95SVishal Kulkarni 	if (sc->props.multi_rings && (sc->intr_type != DDI_INTR_TYPE_MSIX)) {
5843dde7c95SVishal Kulkarni 		sc->props.multi_rings = 0;
5853dde7c95SVishal Kulkarni 		cxgb_printf(dip, CE_WARN,
5863dde7c95SVishal Kulkarni 		    "Multiple rings disabled as interrupt type is not MSI-X");
5873dde7c95SVishal Kulkarni 	}
5883dde7c95SVishal Kulkarni 
5893dde7c95SVishal Kulkarni 	if (sc->props.multi_rings && iaq.intr_fwd) {
5903dde7c95SVishal Kulkarni 		sc->props.multi_rings = 0;
5913dde7c95SVishal Kulkarni 		cxgb_printf(dip, CE_WARN,
5923dde7c95SVishal Kulkarni 		    "Multiple rings disabled as interrupts are forwarded");
5933dde7c95SVishal Kulkarni 	}
5943dde7c95SVishal Kulkarni 
5953dde7c95SVishal Kulkarni 	if (!sc->props.multi_rings) {
5963dde7c95SVishal Kulkarni 		iaq.ntxq10g = 1;
5973dde7c95SVishal Kulkarni 		iaq.ntxq1g = 1;
5983dde7c95SVishal Kulkarni 	}
59956b2bdd1SGireesh Nagabhushana 	s = &sc->sge;
6003dde7c95SVishal Kulkarni 	s->nrxq = nxg * iaq.nrxq10g + n1g * iaq.nrxq1g;
6013dde7c95SVishal Kulkarni 	s->ntxq = nxg * iaq.ntxq10g + n1g * iaq.ntxq1g;
60256b2bdd1SGireesh Nagabhushana 	s->neq = s->ntxq + s->nrxq;	/* the fl in an rxq is an eq */
6033dde7c95SVishal Kulkarni #ifdef TCP_OFFLOAD_ENABLE
60456b2bdd1SGireesh Nagabhushana 	/* control queues, 1 per port + 1 mgmtq */
60556b2bdd1SGireesh Nagabhushana 	s->neq += sc->params.nports + 1;
60656b2bdd1SGireesh Nagabhushana #endif
60756b2bdd1SGireesh Nagabhushana 	s->niq = s->nrxq + 1;		/* 1 extra for firmware event queue */
60856b2bdd1SGireesh Nagabhushana 	if (iaq.intr_fwd != 0)
60956b2bdd1SGireesh Nagabhushana 		sc->flags |= INTR_FWD;
6103dde7c95SVishal Kulkarni #ifdef TCP_OFFLOAD_ENABLE
61156b2bdd1SGireesh Nagabhushana 	if (is_offload(sc) != 0) {
61256b2bdd1SGireesh Nagabhushana 
6133dde7c95SVishal Kulkarni 		s->nofldrxq = nxg * iaq.nofldrxq10g + n1g * iaq.nofldrxq1g;
6143dde7c95SVishal Kulkarni 		s->nofldtxq = nxg * iaq.nofldtxq10g + n1g * iaq.nofldtxq1g;
61556b2bdd1SGireesh Nagabhushana 		s->neq += s->nofldtxq + s->nofldrxq;
61656b2bdd1SGireesh Nagabhushana 		s->niq += s->nofldrxq;
61756b2bdd1SGireesh Nagabhushana 
61856b2bdd1SGireesh Nagabhushana 		s->ofld_rxq = kmem_zalloc(s->nofldrxq *
61956b2bdd1SGireesh Nagabhushana 		    sizeof (struct sge_ofld_rxq), KM_SLEEP);
62056b2bdd1SGireesh Nagabhushana 		s->ofld_txq = kmem_zalloc(s->nofldtxq *
62156b2bdd1SGireesh Nagabhushana 		    sizeof (struct sge_wrq), KM_SLEEP);
62256b2bdd1SGireesh Nagabhushana 		s->ctrlq = kmem_zalloc(sc->params.nports *
62356b2bdd1SGireesh Nagabhushana 		    sizeof (struct sge_wrq), KM_SLEEP);
62456b2bdd1SGireesh Nagabhushana 
62556b2bdd1SGireesh Nagabhushana 	}
62656b2bdd1SGireesh Nagabhushana #endif
62756b2bdd1SGireesh Nagabhushana 	s->rxq = kmem_zalloc(s->nrxq * sizeof (struct sge_rxq), KM_SLEEP);
62856b2bdd1SGireesh Nagabhushana 	s->txq = kmem_zalloc(s->ntxq * sizeof (struct sge_txq), KM_SLEEP);
62977ac03cbSRahul Lakkireddy 	s->iqmap = kmem_zalloc(s->iqmap_sz * sizeof (struct sge_iq *), KM_SLEEP);
63077ac03cbSRahul Lakkireddy 	s->eqmap = kmem_zalloc(s->eqmap_sz * sizeof (struct sge_eq *), KM_SLEEP);
63156b2bdd1SGireesh Nagabhushana 
63256b2bdd1SGireesh Nagabhushana 	sc->intr_handle = kmem_zalloc(sc->intr_count *
63356b2bdd1SGireesh Nagabhushana 	    sizeof (ddi_intr_handle_t), KM_SLEEP);
63456b2bdd1SGireesh Nagabhushana 
63556b2bdd1SGireesh Nagabhushana 	/*
63656b2bdd1SGireesh Nagabhushana 	 * Second pass over the ports.  This time we know the number of rx and
63756b2bdd1SGireesh Nagabhushana 	 * tx queues that each port should get.
63856b2bdd1SGireesh Nagabhushana 	 */
63956b2bdd1SGireesh Nagabhushana 	rqidx = tqidx = 0;
6403dde7c95SVishal Kulkarni #ifdef TCP_OFFLOAD_ENABLE
64156b2bdd1SGireesh Nagabhushana 	ofld_rqidx = ofld_tqidx = 0;
64256b2bdd1SGireesh Nagabhushana #endif
64356b2bdd1SGireesh Nagabhushana 	for_each_port(sc, i) {
64456b2bdd1SGireesh Nagabhushana 		struct port_info *pi = sc->port[i];
64556b2bdd1SGireesh Nagabhushana 
64656b2bdd1SGireesh Nagabhushana 		if (pi == NULL)
64756b2bdd1SGireesh Nagabhushana 			continue;
64856b2bdd1SGireesh Nagabhushana 
6493dde7c95SVishal Kulkarni 		t4_mc_cb_init(pi);
65056b2bdd1SGireesh Nagabhushana 		/* LINTED: E_ASSIGN_NARROW_CONV */
65156b2bdd1SGireesh Nagabhushana 		pi->first_rxq = rqidx;
65256b2bdd1SGireesh Nagabhushana 		/* LINTED: E_ASSIGN_NARROW_CONV */
6533dde7c95SVishal Kulkarni 		pi->nrxq = (is_10XG_port(pi)) ? iaq.nrxq10g
654de483253SVishal Kulkarni 		    : iaq.nrxq1g;
65556b2bdd1SGireesh Nagabhushana 		/* LINTED: E_ASSIGN_NARROW_CONV */
65656b2bdd1SGireesh Nagabhushana 		pi->first_txq = tqidx;
65756b2bdd1SGireesh Nagabhushana 		/* LINTED: E_ASSIGN_NARROW_CONV */
6583dde7c95SVishal Kulkarni 		pi->ntxq = (is_10XG_port(pi)) ? iaq.ntxq10g
659de483253SVishal Kulkarni 		    : iaq.ntxq1g;
66056b2bdd1SGireesh Nagabhushana 
66156b2bdd1SGireesh Nagabhushana 		rqidx += pi->nrxq;
66256b2bdd1SGireesh Nagabhushana 		tqidx += pi->ntxq;
66356b2bdd1SGireesh Nagabhushana 
6643dde7c95SVishal Kulkarni #ifdef TCP_OFFLOAD_ENABLE
66556b2bdd1SGireesh Nagabhushana 		if (is_offload(sc) != 0) {
66656b2bdd1SGireesh Nagabhushana 			/* LINTED: E_ASSIGN_NARROW_CONV */
66756b2bdd1SGireesh Nagabhushana 			pi->first_ofld_rxq = ofld_rqidx;
66856b2bdd1SGireesh Nagabhushana 			pi->nofldrxq = max(1, pi->nrxq / 4);
66956b2bdd1SGireesh Nagabhushana 
67056b2bdd1SGireesh Nagabhushana 			/* LINTED: E_ASSIGN_NARROW_CONV */
67156b2bdd1SGireesh Nagabhushana 			pi->first_ofld_txq = ofld_tqidx;
67256b2bdd1SGireesh Nagabhushana 			pi->nofldtxq = max(1, pi->ntxq / 2);
67356b2bdd1SGireesh Nagabhushana 
67456b2bdd1SGireesh Nagabhushana 			ofld_rqidx += pi->nofldrxq;
67556b2bdd1SGireesh Nagabhushana 			ofld_tqidx += pi->nofldtxq;
67656b2bdd1SGireesh Nagabhushana 		}
67756b2bdd1SGireesh Nagabhushana #endif
67856b2bdd1SGireesh Nagabhushana 
67956b2bdd1SGireesh Nagabhushana 		/*
68056b2bdd1SGireesh Nagabhushana 		 * Enable hw checksumming and LSO for all ports by default.
68156b2bdd1SGireesh Nagabhushana 		 * They can be disabled using ndd (hw_csum and hw_lso).
68256b2bdd1SGireesh Nagabhushana 		 */
68356b2bdd1SGireesh Nagabhushana 		pi->features |= (CXGBE_HW_CSUM | CXGBE_HW_LSO);
68456b2bdd1SGireesh Nagabhushana 	}
68556b2bdd1SGireesh Nagabhushana 
6863dde7c95SVishal Kulkarni #ifdef TCP_OFFLOAD_ENABLE
68756b2bdd1SGireesh Nagabhushana 		sc->l2t = t4_init_l2t(sc);
68856b2bdd1SGireesh Nagabhushana #endif
68956b2bdd1SGireesh Nagabhushana 
69056b2bdd1SGireesh Nagabhushana 	/*
69156b2bdd1SGireesh Nagabhushana 	 * Setup Interrupts.
69256b2bdd1SGireesh Nagabhushana 	 */
69356b2bdd1SGireesh Nagabhushana 
69456b2bdd1SGireesh Nagabhushana 	i = 0;
69556b2bdd1SGireesh Nagabhushana 	rc = ddi_intr_alloc(dip, sc->intr_handle, sc->intr_type, 0,
69656b2bdd1SGireesh Nagabhushana 	    sc->intr_count, &i, DDI_INTR_ALLOC_STRICT);
69756b2bdd1SGireesh Nagabhushana 	if (rc != DDI_SUCCESS) {
69856b2bdd1SGireesh Nagabhushana 		cxgb_printf(dip, CE_WARN,
69956b2bdd1SGireesh Nagabhushana 		    "failed to allocate %d interrupt(s) of type %d: %d, %d",
70056b2bdd1SGireesh Nagabhushana 		    sc->intr_count, sc->intr_type, rc, i);
70156b2bdd1SGireesh Nagabhushana 		goto done;
70256b2bdd1SGireesh Nagabhushana 	}
70356b2bdd1SGireesh Nagabhushana 	ASSERT(sc->intr_count == i); /* allocation was STRICT */
70456b2bdd1SGireesh Nagabhushana 	(void) ddi_intr_get_cap(sc->intr_handle[0], &sc->intr_cap);
70556b2bdd1SGireesh Nagabhushana 	(void) ddi_intr_get_pri(sc->intr_handle[0], &sc->intr_pri);
70656b2bdd1SGireesh Nagabhushana 	if (sc->intr_count == 1) {
70756b2bdd1SGireesh Nagabhushana 		ASSERT(sc->flags & INTR_FWD);
70856b2bdd1SGireesh Nagabhushana 		(void) ddi_intr_add_handler(sc->intr_handle[0], t4_intr_all, sc,
70956b2bdd1SGireesh Nagabhushana 		    &s->fwq);
71056b2bdd1SGireesh Nagabhushana 	} else {
71156b2bdd1SGireesh Nagabhushana 		/* Multiple interrupts.  The first one is always error intr */
71256b2bdd1SGireesh Nagabhushana 		(void) ddi_intr_add_handler(sc->intr_handle[0], t4_intr_err, sc,
71356b2bdd1SGireesh Nagabhushana 		    NULL);
71456b2bdd1SGireesh Nagabhushana 		irq++;
71556b2bdd1SGireesh Nagabhushana 
71656b2bdd1SGireesh Nagabhushana 		/* The second one is always the firmware event queue */
71756b2bdd1SGireesh Nagabhushana 		(void) ddi_intr_add_handler(sc->intr_handle[1], t4_intr, sc,
71856b2bdd1SGireesh Nagabhushana 		    &s->fwq);
71956b2bdd1SGireesh Nagabhushana 		irq++;
72056b2bdd1SGireesh Nagabhushana 		/*
72156b2bdd1SGireesh Nagabhushana 		 * Note that if INTR_FWD is set then either the NIC rx
72256b2bdd1SGireesh Nagabhushana 		 * queues or (exclusive or) the TOE rx queueus will be taking
72356b2bdd1SGireesh Nagabhushana 		 * direct interrupts.
72456b2bdd1SGireesh Nagabhushana 		 *
72556b2bdd1SGireesh Nagabhushana 		 * There is no need to check for is_offload(sc) as nofldrxq
72656b2bdd1SGireesh Nagabhushana 		 * will be 0 if offload is disabled.
72756b2bdd1SGireesh Nagabhushana 		 */
72856b2bdd1SGireesh Nagabhushana 		for_each_port(sc, i) {
72956b2bdd1SGireesh Nagabhushana 			struct port_info *pi = sc->port[i];
73056b2bdd1SGireesh Nagabhushana 			struct sge_rxq *rxq;
7313dde7c95SVishal Kulkarni #ifdef TCP_OFFLOAD_ENABLE
73256b2bdd1SGireesh Nagabhushana 			struct sge_ofld_rxq *ofld_rxq;
73356b2bdd1SGireesh Nagabhushana 
73456b2bdd1SGireesh Nagabhushana 			/*
73556b2bdd1SGireesh Nagabhushana 			 * Skip over the NIC queues if they aren't taking direct
73656b2bdd1SGireesh Nagabhushana 			 * interrupts.
73756b2bdd1SGireesh Nagabhushana 			 */
73856b2bdd1SGireesh Nagabhushana 			if ((sc->flags & INTR_FWD) &&
73956b2bdd1SGireesh Nagabhushana 			    pi->nofldrxq > pi->nrxq)
74056b2bdd1SGireesh Nagabhushana 				goto ofld_queues;
74156b2bdd1SGireesh Nagabhushana #endif
74256b2bdd1SGireesh Nagabhushana 			rxq = &s->rxq[pi->first_rxq];
74356b2bdd1SGireesh Nagabhushana 			for (q = 0; q < pi->nrxq; q++, rxq++) {
74456b2bdd1SGireesh Nagabhushana 				(void) ddi_intr_add_handler(
74556b2bdd1SGireesh Nagabhushana 				    sc->intr_handle[irq], t4_intr, sc,
74656b2bdd1SGireesh Nagabhushana 				    &rxq->iq);
74756b2bdd1SGireesh Nagabhushana 				irq++;
74856b2bdd1SGireesh Nagabhushana 			}
74956b2bdd1SGireesh Nagabhushana 
7503dde7c95SVishal Kulkarni #ifdef TCP_OFFLOAD_ENABLE
75156b2bdd1SGireesh Nagabhushana 			/*
75256b2bdd1SGireesh Nagabhushana 			 * Skip over the offload queues if they aren't taking
75356b2bdd1SGireesh Nagabhushana 			 * direct interrupts.
75456b2bdd1SGireesh Nagabhushana 			 */
75556b2bdd1SGireesh Nagabhushana 			if ((sc->flags & INTR_FWD))
75656b2bdd1SGireesh Nagabhushana 				continue;
75756b2bdd1SGireesh Nagabhushana ofld_queues:
75856b2bdd1SGireesh Nagabhushana 			ofld_rxq = &s->ofld_rxq[pi->first_ofld_rxq];
75956b2bdd1SGireesh Nagabhushana 			for (q = 0; q < pi->nofldrxq; q++, ofld_rxq++) {
76056b2bdd1SGireesh Nagabhushana 				(void) ddi_intr_add_handler(
76156b2bdd1SGireesh Nagabhushana 				    sc->intr_handle[irq], t4_intr, sc,
76256b2bdd1SGireesh Nagabhushana 				    &ofld_rxq->iq);
76356b2bdd1SGireesh Nagabhushana 				irq++;
76456b2bdd1SGireesh Nagabhushana 			}
76556b2bdd1SGireesh Nagabhushana #endif
76656b2bdd1SGireesh Nagabhushana 		}
76756b2bdd1SGireesh Nagabhushana 
76856b2bdd1SGireesh Nagabhushana 	}
76956b2bdd1SGireesh Nagabhushana 	sc->flags |= INTR_ALLOCATED;
77056b2bdd1SGireesh Nagabhushana 
77173439c83SRobert Mustacchi 	if ((rc = ksensor_create_scalar_pcidev(dip, SENSOR_KIND_TEMPERATURE,
77273439c83SRobert Mustacchi 	    &t4_temp_ops, sc, "temp", &sc->temp_sensor)) != 0) {
77373439c83SRobert Mustacchi 		cxgb_printf(dip, CE_WARN, "failed to create temperature "
77473439c83SRobert Mustacchi 		    "sensor: %d", rc);
77573439c83SRobert Mustacchi 		rc = DDI_FAILURE;
77673439c83SRobert Mustacchi 		goto done;
77773439c83SRobert Mustacchi 	}
77873439c83SRobert Mustacchi 
77973439c83SRobert Mustacchi 	if ((rc = ksensor_create_scalar_pcidev(dip, SENSOR_KIND_VOLTAGE,
78073439c83SRobert Mustacchi 	    &t4_volt_ops, sc, "vdd", &sc->volt_sensor)) != 0) {
78173439c83SRobert Mustacchi 		cxgb_printf(dip, CE_WARN, "failed to create voltage "
78273439c83SRobert Mustacchi 		    "sensor: %d", rc);
78373439c83SRobert Mustacchi 		rc = DDI_FAILURE;
78473439c83SRobert Mustacchi 		goto done;
78573439c83SRobert Mustacchi 	}
78673439c83SRobert Mustacchi 
78773439c83SRobert Mustacchi 
7882e7b048cSRobert Mustacchi 	if ((rc = ddi_ufm_init(dip, DDI_UFM_CURRENT_VERSION, &t4_ufm_ops,
7892e7b048cSRobert Mustacchi 	    &sc->ufm_hdl, sc)) != 0) {
7902e7b048cSRobert Mustacchi 		cxgb_printf(dip, CE_WARN, "failed to enable UFM ops: %d", rc);
7912e7b048cSRobert Mustacchi 		rc = DDI_FAILURE;
7922e7b048cSRobert Mustacchi 		goto done;
7932e7b048cSRobert Mustacchi 	}
7942e7b048cSRobert Mustacchi 	ddi_ufm_update(sc->ufm_hdl);
79556b2bdd1SGireesh Nagabhushana 	ddi_report_dev(dip);
79656b2bdd1SGireesh Nagabhushana 
7973dde7c95SVishal Kulkarni 	/*
7983dde7c95SVishal Kulkarni 	 * Hardware/Firmware/etc. Version/Revision IDs.
7993dde7c95SVishal Kulkarni 	 */
8003dde7c95SVishal Kulkarni 	t4_dump_version_info(sc);
8013dde7c95SVishal Kulkarni 
80277ac03cbSRahul Lakkireddy 	cxgb_printf(dip, CE_NOTE,
80377ac03cbSRahul Lakkireddy 		    "(%d rxq, %d txq total) %d %s.",
80477ac03cbSRahul Lakkireddy 		    rqidx, tqidx, sc->intr_count,
8053dde7c95SVishal Kulkarni 		    sc->intr_type == DDI_INTR_TYPE_MSIX ? "MSI-X interrupts" :
8063dde7c95SVishal Kulkarni 		    sc->intr_type == DDI_INTR_TYPE_MSI ? "MSI interrupts" :
8073dde7c95SVishal Kulkarni 		    "fixed interrupt");
80856b2bdd1SGireesh Nagabhushana 
80956b2bdd1SGireesh Nagabhushana 	sc->ksp = setup_kstats(sc);
810de483253SVishal Kulkarni 	sc->ksp_stat = setup_wc_kstats(sc);
8113dde7c95SVishal Kulkarni 	sc->params.drv_memwin = MEMWIN_NIC;
81256b2bdd1SGireesh Nagabhushana 
81356b2bdd1SGireesh Nagabhushana done:
81456b2bdd1SGireesh Nagabhushana 	if (rc != DDI_SUCCESS) {
81556b2bdd1SGireesh Nagabhushana 		(void) t4_devo_detach(dip, DDI_DETACH);
81656b2bdd1SGireesh Nagabhushana 
81756b2bdd1SGireesh Nagabhushana 		/* rc may have errno style errors or DDI errors */
81856b2bdd1SGireesh Nagabhushana 		rc = DDI_FAILURE;
81956b2bdd1SGireesh Nagabhushana 	}
82056b2bdd1SGireesh Nagabhushana 
82156b2bdd1SGireesh Nagabhushana 	return (rc);
82256b2bdd1SGireesh Nagabhushana }
82356b2bdd1SGireesh Nagabhushana 
82456b2bdd1SGireesh Nagabhushana static int
t4_devo_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)82556b2bdd1SGireesh Nagabhushana t4_devo_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
82656b2bdd1SGireesh Nagabhushana {
82756b2bdd1SGireesh Nagabhushana 	int instance, i;
82856b2bdd1SGireesh Nagabhushana 	struct adapter *sc;
82956b2bdd1SGireesh Nagabhushana 	struct port_info *pi;
83056b2bdd1SGireesh Nagabhushana 	struct sge *s;
83156b2bdd1SGireesh Nagabhushana 
83256b2bdd1SGireesh Nagabhushana 	if (cmd != DDI_DETACH)
83356b2bdd1SGireesh Nagabhushana 		return (DDI_FAILURE);
83456b2bdd1SGireesh Nagabhushana 
83556b2bdd1SGireesh Nagabhushana 	instance = ddi_get_instance(dip);
83656b2bdd1SGireesh Nagabhushana 	sc = ddi_get_soft_state(t4_list, instance);
83756b2bdd1SGireesh Nagabhushana 	if (sc == NULL)
83856b2bdd1SGireesh Nagabhushana 		return (DDI_SUCCESS);
83956b2bdd1SGireesh Nagabhushana 
84056b2bdd1SGireesh Nagabhushana 	if (sc->flags & FULL_INIT_DONE) {
84156b2bdd1SGireesh Nagabhushana 		t4_intr_disable(sc);
84256b2bdd1SGireesh Nagabhushana 		for_each_port(sc, i) {
84356b2bdd1SGireesh Nagabhushana 			pi = sc->port[i];
84456b2bdd1SGireesh Nagabhushana 			if (pi && pi->flags & PORT_INIT_DONE)
84556b2bdd1SGireesh Nagabhushana 				(void) port_full_uninit(pi);
84656b2bdd1SGireesh Nagabhushana 		}
84756b2bdd1SGireesh Nagabhushana 		(void) adapter_full_uninit(sc);
84856b2bdd1SGireesh Nagabhushana 	}
84956b2bdd1SGireesh Nagabhushana 
85056b2bdd1SGireesh Nagabhushana 	/* Safe to call no matter what */
8512e7b048cSRobert Mustacchi 	if (sc->ufm_hdl != NULL) {
8522e7b048cSRobert Mustacchi 		ddi_ufm_fini(sc->ufm_hdl);
8532e7b048cSRobert Mustacchi 		sc->ufm_hdl = NULL;
8542e7b048cSRobert Mustacchi 	}
85573439c83SRobert Mustacchi 	(void) ksensor_remove(dip, KSENSOR_ALL_IDS);
85656b2bdd1SGireesh Nagabhushana 	ddi_prop_remove_all(dip);
85756b2bdd1SGireesh Nagabhushana 	ddi_remove_minor_node(dip, NULL);
85856b2bdd1SGireesh Nagabhushana 
85906b05760SVishal Kulkarni 	for (i = 0; i < NCHAN; i++) {
86006b05760SVishal Kulkarni 		if (sc->tq[i]) {
86106b05760SVishal Kulkarni 			ddi_taskq_wait(sc->tq[i]);
86206b05760SVishal Kulkarni 			ddi_taskq_destroy(sc->tq[i]);
86306b05760SVishal Kulkarni 		}
86406b05760SVishal Kulkarni 	}
86506b05760SVishal Kulkarni 
86656b2bdd1SGireesh Nagabhushana 	if (sc->ksp != NULL)
86756b2bdd1SGireesh Nagabhushana 		kstat_delete(sc->ksp);
868de483253SVishal Kulkarni 	if (sc->ksp_stat != NULL)
869de483253SVishal Kulkarni 		kstat_delete(sc->ksp_stat);
87056b2bdd1SGireesh Nagabhushana 
87156b2bdd1SGireesh Nagabhushana 	s = &sc->sge;
87256b2bdd1SGireesh Nagabhushana 	if (s->rxq != NULL)
87356b2bdd1SGireesh Nagabhushana 		kmem_free(s->rxq, s->nrxq * sizeof (struct sge_rxq));
8743dde7c95SVishal Kulkarni #ifdef TCP_OFFLOAD_ENABLE
87556b2bdd1SGireesh Nagabhushana 	if (s->ofld_txq != NULL)
87656b2bdd1SGireesh Nagabhushana 		kmem_free(s->ofld_txq, s->nofldtxq * sizeof (struct sge_wrq));
87756b2bdd1SGireesh Nagabhushana 	if (s->ofld_rxq != NULL)
87856b2bdd1SGireesh Nagabhushana 		kmem_free(s->ofld_rxq,
87956b2bdd1SGireesh Nagabhushana 		    s->nofldrxq * sizeof (struct sge_ofld_rxq));
88056b2bdd1SGireesh Nagabhushana 	if (s->ctrlq != NULL)
88156b2bdd1SGireesh Nagabhushana 		kmem_free(s->ctrlq,
88256b2bdd1SGireesh Nagabhushana 		    sc->params.nports * sizeof (struct sge_wrq));
88356b2bdd1SGireesh Nagabhushana #endif
88456b2bdd1SGireesh Nagabhushana 	if (s->txq != NULL)
88556b2bdd1SGireesh Nagabhushana 		kmem_free(s->txq, s->ntxq * sizeof (struct sge_txq));
88656b2bdd1SGireesh Nagabhushana 	if (s->iqmap != NULL)
88777ac03cbSRahul Lakkireddy 		kmem_free(s->iqmap, s->iqmap_sz * sizeof (struct sge_iq *));
88856b2bdd1SGireesh Nagabhushana 	if (s->eqmap != NULL)
88977ac03cbSRahul Lakkireddy 		kmem_free(s->eqmap, s->eqmap_sz * sizeof (struct sge_eq *));
89056b2bdd1SGireesh Nagabhushana 
89156b2bdd1SGireesh Nagabhushana 	if (s->rxbuf_cache != NULL)
89256b2bdd1SGireesh Nagabhushana 		rxbuf_cache_destroy(s->rxbuf_cache);
89356b2bdd1SGireesh Nagabhushana 
89456b2bdd1SGireesh Nagabhushana 	if (sc->flags & INTR_ALLOCATED) {
89556b2bdd1SGireesh Nagabhushana 		for (i = 0; i < sc->intr_count; i++) {
89656b2bdd1SGireesh Nagabhushana 			(void) ddi_intr_remove_handler(sc->intr_handle[i]);
89756b2bdd1SGireesh Nagabhushana 			(void) ddi_intr_free(sc->intr_handle[i]);
89856b2bdd1SGireesh Nagabhushana 		}
89956b2bdd1SGireesh Nagabhushana 		sc->flags &= ~INTR_ALLOCATED;
90056b2bdd1SGireesh Nagabhushana 	}
90156b2bdd1SGireesh Nagabhushana 
90256b2bdd1SGireesh Nagabhushana 	if (sc->intr_handle != NULL) {
90356b2bdd1SGireesh Nagabhushana 		kmem_free(sc->intr_handle,
90456b2bdd1SGireesh Nagabhushana 		    sc->intr_count * sizeof (*sc->intr_handle));
90556b2bdd1SGireesh Nagabhushana 	}
90656b2bdd1SGireesh Nagabhushana 
90756b2bdd1SGireesh Nagabhushana 	for_each_port(sc, i) {
90856b2bdd1SGireesh Nagabhushana 		pi = sc->port[i];
90956b2bdd1SGireesh Nagabhushana 		if (pi != NULL) {
91056b2bdd1SGireesh Nagabhushana 			mutex_destroy(&pi->lock);
91156b2bdd1SGireesh Nagabhushana 			kmem_free(pi, sizeof (*pi));
91256b2bdd1SGireesh Nagabhushana 			clrbit(&sc->registered_device_map, i);
91356b2bdd1SGireesh Nagabhushana 		}
91456b2bdd1SGireesh Nagabhushana 	}
91556b2bdd1SGireesh Nagabhushana 
91656b2bdd1SGireesh Nagabhushana 	if (sc->flags & FW_OK)
91756b2bdd1SGireesh Nagabhushana 		(void) t4_fw_bye(sc, sc->mbox);
91856b2bdd1SGireesh Nagabhushana 
919de483253SVishal Kulkarni 	if (sc->reg1h != NULL)
920de483253SVishal Kulkarni 		ddi_regs_map_free(&sc->reg1h);
921de483253SVishal Kulkarni 
92256b2bdd1SGireesh Nagabhushana 	if (sc->regh != NULL)
92356b2bdd1SGireesh Nagabhushana 		ddi_regs_map_free(&sc->regh);
92456b2bdd1SGireesh Nagabhushana 
92556b2bdd1SGireesh Nagabhushana 	if (sc->pci_regh != NULL)
92656b2bdd1SGireesh Nagabhushana 		pci_config_teardown(&sc->pci_regh);
92756b2bdd1SGireesh Nagabhushana 
92856b2bdd1SGireesh Nagabhushana 	mutex_enter(&t4_adapter_list_lock);
9296feac2e3SRahul Lakkireddy 	SLIST_REMOVE(&t4_adapter_list, sc, adapter, link);
93056b2bdd1SGireesh Nagabhushana 	mutex_exit(&t4_adapter_list_lock);
93156b2bdd1SGireesh Nagabhushana 
9326feac2e3SRahul Lakkireddy 	mutex_destroy(&sc->mbox_lock);
93356b2bdd1SGireesh Nagabhushana 	mutex_destroy(&sc->lock);
93456b2bdd1SGireesh Nagabhushana 	cv_destroy(&sc->cv);
93556b2bdd1SGireesh Nagabhushana 	mutex_destroy(&sc->sfl_lock);
93656b2bdd1SGireesh Nagabhushana 
93756b2bdd1SGireesh Nagabhushana #ifdef DEBUG
93856b2bdd1SGireesh Nagabhushana 	bzero(sc, sizeof (*sc));
93956b2bdd1SGireesh Nagabhushana #endif
94056b2bdd1SGireesh Nagabhushana 	ddi_soft_state_free(t4_list, instance);
94156b2bdd1SGireesh Nagabhushana 
94256b2bdd1SGireesh Nagabhushana 	return (DDI_SUCCESS);
94356b2bdd1SGireesh Nagabhushana }
94456b2bdd1SGireesh Nagabhushana 
94556b2bdd1SGireesh Nagabhushana static int
t4_devo_quiesce(dev_info_t * dip)94656b2bdd1SGireesh Nagabhushana t4_devo_quiesce(dev_info_t *dip)
94756b2bdd1SGireesh Nagabhushana {
94856b2bdd1SGireesh Nagabhushana 	int instance;
94956b2bdd1SGireesh Nagabhushana 	struct adapter *sc;
95056b2bdd1SGireesh Nagabhushana 
95156b2bdd1SGireesh Nagabhushana 	instance = ddi_get_instance(dip);
95256b2bdd1SGireesh Nagabhushana 	sc = ddi_get_soft_state(t4_list, instance);
95356b2bdd1SGireesh Nagabhushana 	if (sc == NULL)
95456b2bdd1SGireesh Nagabhushana 		return (DDI_SUCCESS);
95556b2bdd1SGireesh Nagabhushana 
95656b2bdd1SGireesh Nagabhushana 	t4_set_reg_field(sc, A_SGE_CONTROL, F_GLOBALENABLE, 0);
95756b2bdd1SGireesh Nagabhushana 	t4_intr_disable(sc);
95856b2bdd1SGireesh Nagabhushana 	t4_write_reg(sc, A_PL_RST, F_PIORSTMODE | F_PIORST);
95956b2bdd1SGireesh Nagabhushana 
96056b2bdd1SGireesh Nagabhushana 	return (DDI_SUCCESS);
96156b2bdd1SGireesh Nagabhushana }
96256b2bdd1SGireesh Nagabhushana 
96356b2bdd1SGireesh Nagabhushana static int
t4_bus_ctl(dev_info_t * dip,dev_info_t * rdip,ddi_ctl_enum_t op,void * arg,void * result)96456b2bdd1SGireesh Nagabhushana t4_bus_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t op, void *arg,
96556b2bdd1SGireesh Nagabhushana     void *result)
96656b2bdd1SGireesh Nagabhushana {
96756b2bdd1SGireesh Nagabhushana 	char s[4];
96856b2bdd1SGireesh Nagabhushana 	struct port_info *pi;
96956b2bdd1SGireesh Nagabhushana 	dev_info_t *child = (dev_info_t *)arg;
97056b2bdd1SGireesh Nagabhushana 
97156b2bdd1SGireesh Nagabhushana 	switch (op) {
97256b2bdd1SGireesh Nagabhushana 	case DDI_CTLOPS_REPORTDEV:
97356b2bdd1SGireesh Nagabhushana 		pi = ddi_get_parent_data(rdip);
97456b2bdd1SGireesh Nagabhushana 		pi->instance = ddi_get_instance(dip);
97556b2bdd1SGireesh Nagabhushana 		pi->child_inst = ddi_get_instance(rdip);
97656b2bdd1SGireesh Nagabhushana 		cmn_err(CE_CONT, "?%s%d is port %s on %s%d\n",
97756b2bdd1SGireesh Nagabhushana 		    ddi_node_name(rdip), ddi_get_instance(rdip),
97856b2bdd1SGireesh Nagabhushana 		    ddi_get_name_addr(rdip), ddi_driver_name(dip),
97956b2bdd1SGireesh Nagabhushana 		    ddi_get_instance(dip));
98056b2bdd1SGireesh Nagabhushana 		return (DDI_SUCCESS);
98156b2bdd1SGireesh Nagabhushana 
98256b2bdd1SGireesh Nagabhushana 	case DDI_CTLOPS_INITCHILD:
98356b2bdd1SGireesh Nagabhushana 		pi = ddi_get_parent_data(child);
98456b2bdd1SGireesh Nagabhushana 		if (pi == NULL)
98556b2bdd1SGireesh Nagabhushana 			return (DDI_NOT_WELL_FORMED);
98656b2bdd1SGireesh Nagabhushana 		(void) snprintf(s, sizeof (s), "%d", pi->port_id);
98756b2bdd1SGireesh Nagabhushana 		ddi_set_name_addr(child, s);
98856b2bdd1SGireesh Nagabhushana 		return (DDI_SUCCESS);
98956b2bdd1SGireesh Nagabhushana 
99056b2bdd1SGireesh Nagabhushana 	case DDI_CTLOPS_UNINITCHILD:
99156b2bdd1SGireesh Nagabhushana 		ddi_set_name_addr(child, NULL);
99256b2bdd1SGireesh Nagabhushana 		return (DDI_SUCCESS);
99356b2bdd1SGireesh Nagabhushana 
99456b2bdd1SGireesh Nagabhushana 	case DDI_CTLOPS_ATTACH:
99556b2bdd1SGireesh Nagabhushana 	case DDI_CTLOPS_DETACH:
99656b2bdd1SGireesh Nagabhushana 		return (DDI_SUCCESS);
99756b2bdd1SGireesh Nagabhushana 
99856b2bdd1SGireesh Nagabhushana 	default:
99956b2bdd1SGireesh Nagabhushana 		return (ddi_ctlops(dip, rdip, op, arg, result));
100056b2bdd1SGireesh Nagabhushana 	}
100156b2bdd1SGireesh Nagabhushana }
100256b2bdd1SGireesh Nagabhushana 
100356b2bdd1SGireesh Nagabhushana static int
t4_bus_config(dev_info_t * dip,uint_t flags,ddi_bus_config_op_t op,void * arg,dev_info_t ** cdipp)100456b2bdd1SGireesh Nagabhushana t4_bus_config(dev_info_t *dip, uint_t flags, ddi_bus_config_op_t op, void *arg,
100556b2bdd1SGireesh Nagabhushana     dev_info_t **cdipp)
100656b2bdd1SGireesh Nagabhushana {
100756b2bdd1SGireesh Nagabhushana 	int instance, i;
100856b2bdd1SGireesh Nagabhushana 	struct adapter *sc;
100956b2bdd1SGireesh Nagabhushana 
101056b2bdd1SGireesh Nagabhushana 	instance = ddi_get_instance(dip);
101156b2bdd1SGireesh Nagabhushana 	sc = ddi_get_soft_state(t4_list, instance);
101256b2bdd1SGireesh Nagabhushana 
101356b2bdd1SGireesh Nagabhushana 	if (op == BUS_CONFIG_ONE) {
101456b2bdd1SGireesh Nagabhushana 		char *c;
101556b2bdd1SGireesh Nagabhushana 
101656b2bdd1SGireesh Nagabhushana 		/*
101756b2bdd1SGireesh Nagabhushana 		 * arg is something like "cxgb@0" where 0 is the port_id hanging
101856b2bdd1SGireesh Nagabhushana 		 * off this nexus.
101956b2bdd1SGireesh Nagabhushana 		 */
102056b2bdd1SGireesh Nagabhushana 
102156b2bdd1SGireesh Nagabhushana 		c = arg;
102256b2bdd1SGireesh Nagabhushana 		while (*(c + 1))
102356b2bdd1SGireesh Nagabhushana 			c++;
102456b2bdd1SGireesh Nagabhushana 
102556b2bdd1SGireesh Nagabhushana 		/* There should be exactly 1 digit after '@' */
102656b2bdd1SGireesh Nagabhushana 		if (*(c - 1) != '@')
102756b2bdd1SGireesh Nagabhushana 			return (NDI_FAILURE);
102856b2bdd1SGireesh Nagabhushana 
102956b2bdd1SGireesh Nagabhushana 		i = *c - '0';
103056b2bdd1SGireesh Nagabhushana 
103156b2bdd1SGireesh Nagabhushana 		if (add_child_node(sc, i) != 0)
103256b2bdd1SGireesh Nagabhushana 			return (NDI_FAILURE);
103356b2bdd1SGireesh Nagabhushana 
103456b2bdd1SGireesh Nagabhushana 		flags |= NDI_ONLINE_ATTACH;
103556b2bdd1SGireesh Nagabhushana 
103656b2bdd1SGireesh Nagabhushana 	} else if (op == BUS_CONFIG_ALL || op == BUS_CONFIG_DRIVER) {
103756b2bdd1SGireesh Nagabhushana 		/* Allocate and bind all child device nodes */
103856b2bdd1SGireesh Nagabhushana 		for_each_port(sc, i)
103956b2bdd1SGireesh Nagabhushana 		    (void) add_child_node(sc, i);
104056b2bdd1SGireesh Nagabhushana 		flags |= NDI_ONLINE_ATTACH;
104156b2bdd1SGireesh Nagabhushana 	}
104256b2bdd1SGireesh Nagabhushana 
104356b2bdd1SGireesh Nagabhushana 	return (ndi_busop_bus_config(dip, flags, op, arg, cdipp, 0));
104456b2bdd1SGireesh Nagabhushana }
104556b2bdd1SGireesh Nagabhushana 
104656b2bdd1SGireesh Nagabhushana static int
t4_bus_unconfig(dev_info_t * dip,uint_t flags,ddi_bus_config_op_t op,void * arg)104756b2bdd1SGireesh Nagabhushana t4_bus_unconfig(dev_info_t *dip, uint_t flags, ddi_bus_config_op_t op,
104856b2bdd1SGireesh Nagabhushana     void *arg)
104956b2bdd1SGireesh Nagabhushana {
105056b2bdd1SGireesh Nagabhushana 	int instance, i, rc;
105156b2bdd1SGireesh Nagabhushana 	struct adapter *sc;
105256b2bdd1SGireesh Nagabhushana 
105356b2bdd1SGireesh Nagabhushana 	instance = ddi_get_instance(dip);
105456b2bdd1SGireesh Nagabhushana 	sc = ddi_get_soft_state(t4_list, instance);
105556b2bdd1SGireesh Nagabhushana 
105656b2bdd1SGireesh Nagabhushana 	if (op == BUS_CONFIG_ONE || op == BUS_UNCONFIG_ALL ||
105756b2bdd1SGireesh Nagabhushana 	    op == BUS_UNCONFIG_DRIVER)
105856b2bdd1SGireesh Nagabhushana 		flags |= NDI_UNCONFIG;
105956b2bdd1SGireesh Nagabhushana 
106056b2bdd1SGireesh Nagabhushana 	rc = ndi_busop_bus_unconfig(dip, flags, op, arg);
106156b2bdd1SGireesh Nagabhushana 	if (rc != 0)
106256b2bdd1SGireesh Nagabhushana 		return (rc);
106356b2bdd1SGireesh Nagabhushana 
106456b2bdd1SGireesh Nagabhushana 	if (op == BUS_UNCONFIG_ONE) {
106556b2bdd1SGireesh Nagabhushana 		char *c;
106656b2bdd1SGireesh Nagabhushana 
106756b2bdd1SGireesh Nagabhushana 		c = arg;
106856b2bdd1SGireesh Nagabhushana 		while (*(c + 1))
106956b2bdd1SGireesh Nagabhushana 			c++;
107056b2bdd1SGireesh Nagabhushana 
107156b2bdd1SGireesh Nagabhushana 		if (*(c - 1) != '@')
107256b2bdd1SGireesh Nagabhushana 			return (NDI_SUCCESS);
107356b2bdd1SGireesh Nagabhushana 
107456b2bdd1SGireesh Nagabhushana 		i = *c - '0';
107556b2bdd1SGireesh Nagabhushana 
107656b2bdd1SGireesh Nagabhushana 		rc = remove_child_node(sc, i);
107756b2bdd1SGireesh Nagabhushana 
107856b2bdd1SGireesh Nagabhushana 	} else if (op == BUS_UNCONFIG_ALL || op == BUS_UNCONFIG_DRIVER) {
107956b2bdd1SGireesh Nagabhushana 
108056b2bdd1SGireesh Nagabhushana 		for_each_port(sc, i)
108156b2bdd1SGireesh Nagabhushana 		    (void) remove_child_node(sc, i);
108256b2bdd1SGireesh Nagabhushana 	}
108356b2bdd1SGireesh Nagabhushana 
108456b2bdd1SGireesh Nagabhushana 	return (rc);
108556b2bdd1SGireesh Nagabhushana }
108656b2bdd1SGireesh Nagabhushana 
108756b2bdd1SGireesh Nagabhushana /* ARGSUSED */
108856b2bdd1SGireesh Nagabhushana static int
t4_cb_open(dev_t * devp,int flag,int otyp,cred_t * credp)108956b2bdd1SGireesh Nagabhushana t4_cb_open(dev_t *devp, int flag, int otyp, cred_t *credp)
109056b2bdd1SGireesh Nagabhushana {
109156b2bdd1SGireesh Nagabhushana 	struct adapter *sc;
109256b2bdd1SGireesh Nagabhushana 
109356b2bdd1SGireesh Nagabhushana 	if (otyp != OTYP_CHR)
109456b2bdd1SGireesh Nagabhushana 		return (EINVAL);
109556b2bdd1SGireesh Nagabhushana 
109656b2bdd1SGireesh Nagabhushana 	sc = ddi_get_soft_state(t4_list, getminor(*devp));
109756b2bdd1SGireesh Nagabhushana 	if (sc == NULL)
109856b2bdd1SGireesh Nagabhushana 		return (ENXIO);
109956b2bdd1SGireesh Nagabhushana 
110056b2bdd1SGireesh Nagabhushana 	return (atomic_cas_uint(&sc->open, 0, EBUSY));
110156b2bdd1SGireesh Nagabhushana }
110256b2bdd1SGireesh Nagabhushana 
110356b2bdd1SGireesh Nagabhushana /* ARGSUSED */
110456b2bdd1SGireesh Nagabhushana static int
t4_cb_close(dev_t dev,int flag,int otyp,cred_t * credp)110556b2bdd1SGireesh Nagabhushana t4_cb_close(dev_t dev, int flag, int otyp, cred_t *credp)
110656b2bdd1SGireesh Nagabhushana {
110756b2bdd1SGireesh Nagabhushana 	struct adapter *sc;
110856b2bdd1SGireesh Nagabhushana 
110956b2bdd1SGireesh Nagabhushana 	sc = ddi_get_soft_state(t4_list, getminor(dev));
111056b2bdd1SGireesh Nagabhushana 	if (sc == NULL)
111156b2bdd1SGireesh Nagabhushana 		return (EINVAL);
111256b2bdd1SGireesh Nagabhushana 
111356b2bdd1SGireesh Nagabhushana 	(void) atomic_swap_uint(&sc->open, 0);
111456b2bdd1SGireesh Nagabhushana 	return (0);
111556b2bdd1SGireesh Nagabhushana }
111656b2bdd1SGireesh Nagabhushana 
111756b2bdd1SGireesh Nagabhushana /* ARGSUSED */
111856b2bdd1SGireesh Nagabhushana static int
t4_cb_ioctl(dev_t dev,int cmd,intptr_t d,int mode,cred_t * credp,int * rp)111956b2bdd1SGireesh Nagabhushana t4_cb_ioctl(dev_t dev, int cmd, intptr_t d, int mode, cred_t *credp, int *rp)
112056b2bdd1SGireesh Nagabhushana {
112156b2bdd1SGireesh Nagabhushana 	int instance;
112256b2bdd1SGireesh Nagabhushana 	struct adapter *sc;
112356b2bdd1SGireesh Nagabhushana 	void *data = (void *)d;
112456b2bdd1SGireesh Nagabhushana 
112556b2bdd1SGireesh Nagabhushana 	if (crgetuid(credp) != 0)
112656b2bdd1SGireesh Nagabhushana 		return (EPERM);
112756b2bdd1SGireesh Nagabhushana 
112856b2bdd1SGireesh Nagabhushana 	instance = getminor(dev);
112956b2bdd1SGireesh Nagabhushana 	sc = ddi_get_soft_state(t4_list, instance);
113056b2bdd1SGireesh Nagabhushana 	if (sc == NULL)
113156b2bdd1SGireesh Nagabhushana 		return (EINVAL);
113256b2bdd1SGireesh Nagabhushana 
113356b2bdd1SGireesh Nagabhushana 	return (t4_ioctl(sc, cmd, data, mode));
113456b2bdd1SGireesh Nagabhushana }
113556b2bdd1SGireesh Nagabhushana 
113656b2bdd1SGireesh Nagabhushana static unsigned int
getpf(struct adapter * sc)113756b2bdd1SGireesh Nagabhushana getpf(struct adapter *sc)
113856b2bdd1SGireesh Nagabhushana {
113956b2bdd1SGireesh Nagabhushana 	int rc, *data;
114056b2bdd1SGireesh Nagabhushana 	uint_t n, pf;
114156b2bdd1SGireesh Nagabhushana 
114256b2bdd1SGireesh Nagabhushana 	rc = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, sc->dip,
114356b2bdd1SGireesh Nagabhushana 	    DDI_PROP_DONTPASS, "reg", &data, &n);
114456b2bdd1SGireesh Nagabhushana 	if (rc != DDI_SUCCESS) {
114556b2bdd1SGireesh Nagabhushana 		cxgb_printf(sc->dip, CE_WARN,
114656b2bdd1SGireesh Nagabhushana 		    "failed to lookup \"reg\" property: %d", rc);
114756b2bdd1SGireesh Nagabhushana 		return (0xff);
114856b2bdd1SGireesh Nagabhushana 	}
114956b2bdd1SGireesh Nagabhushana 
115056b2bdd1SGireesh Nagabhushana 	pf = PCI_REG_FUNC_G(data[0]);
115156b2bdd1SGireesh Nagabhushana 	ddi_prop_free(data);
115256b2bdd1SGireesh Nagabhushana 
115356b2bdd1SGireesh Nagabhushana 	return (pf);
115456b2bdd1SGireesh Nagabhushana }
115556b2bdd1SGireesh Nagabhushana 
115656b2bdd1SGireesh Nagabhushana /*
115756b2bdd1SGireesh Nagabhushana  * Install a compatible firmware (if required), establish contact with it,
115856b2bdd1SGireesh Nagabhushana  * become the master, and reset the device.
115956b2bdd1SGireesh Nagabhushana  */
116056b2bdd1SGireesh Nagabhushana static int
prep_firmware(struct adapter * sc)116156b2bdd1SGireesh Nagabhushana prep_firmware(struct adapter *sc)
116256b2bdd1SGireesh Nagabhushana {
116356b2bdd1SGireesh Nagabhushana 	int rc;
1164618f2068SAndy Fiddaman 	size_t fw_size;
11653dde7c95SVishal Kulkarni 	int reset = 1;
116656b2bdd1SGireesh Nagabhushana 	enum dev_state state;
11673dde7c95SVishal Kulkarni 	unsigned char *fw_data;
1168618f2068SAndy Fiddaman 	struct fw_hdr *card_fw, *hdr;
1169618f2068SAndy Fiddaman 	const char *fw_file = NULL;
1170618f2068SAndy Fiddaman 	firmware_handle_t fw_hdl;
1171618f2068SAndy Fiddaman 	struct fw_info fi, *fw_info = &fi;
117294c3dad2SToomas Soome 
11733dde7c95SVishal Kulkarni 	struct driver_properties *p = &sc->props;
117456b2bdd1SGireesh Nagabhushana 
117556b2bdd1SGireesh Nagabhushana 	/* Contact firmware, request master */
117656b2bdd1SGireesh Nagabhushana 	rc = t4_fw_hello(sc, sc->mbox, sc->mbox, MASTER_MUST, &state);
117756b2bdd1SGireesh Nagabhushana 	if (rc < 0) {
117856b2bdd1SGireesh Nagabhushana 		rc = -rc;
117956b2bdd1SGireesh Nagabhushana 		cxgb_printf(sc->dip, CE_WARN,
118056b2bdd1SGireesh Nagabhushana 		    "failed to connect to the firmware: %d.", rc);
118156b2bdd1SGireesh Nagabhushana 		return (rc);
118256b2bdd1SGireesh Nagabhushana 	}
118356b2bdd1SGireesh Nagabhushana 
118456b2bdd1SGireesh Nagabhushana 	if (rc == sc->mbox)
118556b2bdd1SGireesh Nagabhushana 		sc->flags |= MASTER_PF;
118656b2bdd1SGireesh Nagabhushana 
11873dde7c95SVishal Kulkarni 	/* We may need FW version info for later reporting */
11883dde7c95SVishal Kulkarni 	t4_get_version_info(sc);
1189618f2068SAndy Fiddaman 
11903dde7c95SVishal Kulkarni 	switch(CHELSIO_CHIP_VERSION(sc->params.chip)) {
11913dde7c95SVishal Kulkarni 	case CHELSIO_T4:
1192618f2068SAndy Fiddaman 		fw_file = "t4fw.bin";
11933dde7c95SVishal Kulkarni 		break;
11943dde7c95SVishal Kulkarni 	case CHELSIO_T5:
1195618f2068SAndy Fiddaman 		fw_file = "t5fw.bin";
11963dde7c95SVishal Kulkarni 		break;
11973dde7c95SVishal Kulkarni 	case CHELSIO_T6:
1198618f2068SAndy Fiddaman 		fw_file = "t6fw.bin";
11993dde7c95SVishal Kulkarni 		break;
12003dde7c95SVishal Kulkarni 	default:
12013dde7c95SVishal Kulkarni 		cxgb_printf(sc->dip, CE_WARN, "Adapter type not supported\n");
1202618f2068SAndy Fiddaman 		return (EINVAL);
12033dde7c95SVishal Kulkarni 	}
120494c3dad2SToomas Soome 
1205618f2068SAndy Fiddaman 	if (firmware_open(T4_PORT_NAME, fw_file, &fw_hdl) != 0) {
1206618f2068SAndy Fiddaman 		cxgb_printf(sc->dip, CE_WARN, "Could not open %s\n", fw_file);
1207618f2068SAndy Fiddaman 		return (EINVAL);
1208618f2068SAndy Fiddaman 	}
1209618f2068SAndy Fiddaman 
1210618f2068SAndy Fiddaman 	fw_size = firmware_get_size(fw_hdl);
1211618f2068SAndy Fiddaman 
1212618f2068SAndy Fiddaman 	if (fw_size < sizeof (struct fw_hdr)) {
1213618f2068SAndy Fiddaman 		cxgb_printf(sc->dip, CE_WARN, "%s is too small (%ld bytes)\n",
1214618f2068SAndy Fiddaman 		    fw_file, fw_size);
1215618f2068SAndy Fiddaman 		firmware_close(fw_hdl);
1216618f2068SAndy Fiddaman 		return (EINVAL);
1217618f2068SAndy Fiddaman 	}
1218618f2068SAndy Fiddaman 
1219618f2068SAndy Fiddaman 	if (fw_size > FLASH_FW_MAX_SIZE) {
1220618f2068SAndy Fiddaman 		cxgb_printf(sc->dip, CE_WARN,
1221618f2068SAndy Fiddaman 		    "%s is too large (%ld bytes, max allowed is %ld)\n",
1222618f2068SAndy Fiddaman 		    fw_file, fw_size, FLASH_FW_MAX_SIZE);
1223618f2068SAndy Fiddaman 		firmware_close(fw_hdl);
1224618f2068SAndy Fiddaman 		return (EFBIG);
1225618f2068SAndy Fiddaman 	}
1226618f2068SAndy Fiddaman 
1227618f2068SAndy Fiddaman 	fw_data = kmem_zalloc(fw_size, KM_SLEEP);
1228618f2068SAndy Fiddaman 	if (firmware_read(fw_hdl, 0, fw_data, fw_size) != 0) {
1229618f2068SAndy Fiddaman 		cxgb_printf(sc->dip, CE_WARN, "Failed to read from %s\n",
1230618f2068SAndy Fiddaman 		    fw_file);
1231618f2068SAndy Fiddaman 		firmware_close(fw_hdl);
1232618f2068SAndy Fiddaman 		kmem_free(fw_data, fw_size);
1233618f2068SAndy Fiddaman 		return (EINVAL);
1234618f2068SAndy Fiddaman 	}
1235618f2068SAndy Fiddaman 	firmware_close(fw_hdl);
1236618f2068SAndy Fiddaman 
1237618f2068SAndy Fiddaman 	bzero(fw_info, sizeof (*fw_info));
1238618f2068SAndy Fiddaman 	fw_info->chip = CHELSIO_CHIP_VERSION(sc->params.chip);
1239618f2068SAndy Fiddaman 
1240618f2068SAndy Fiddaman 	hdr = (struct fw_hdr *)fw_data;
1241618f2068SAndy Fiddaman 	fw_info->fw_hdr.fw_ver = hdr->fw_ver;
1242618f2068SAndy Fiddaman 	fw_info->fw_hdr.chip = hdr->chip;
1243618f2068SAndy Fiddaman 	fw_info->fw_hdr.intfver_nic = hdr->intfver_nic;
1244618f2068SAndy Fiddaman 	fw_info->fw_hdr.intfver_vnic = hdr->intfver_vnic;
1245618f2068SAndy Fiddaman 	fw_info->fw_hdr.intfver_ofld = hdr->intfver_ofld;
1246618f2068SAndy Fiddaman 	fw_info->fw_hdr.intfver_ri = hdr->intfver_ri;
1247618f2068SAndy Fiddaman 	fw_info->fw_hdr.intfver_iscsipdu = hdr->intfver_iscsipdu;
1248618f2068SAndy Fiddaman 	fw_info->fw_hdr.intfver_iscsi = hdr->intfver_iscsi;
1249618f2068SAndy Fiddaman 	fw_info->fw_hdr.intfver_fcoepdu = hdr->intfver_fcoepdu;
1250618f2068SAndy Fiddaman 	fw_info->fw_hdr.intfver_fcoe = hdr->intfver_fcoe;
1251618f2068SAndy Fiddaman 
1252618f2068SAndy Fiddaman 	/* allocate memory to read the header of the firmware on the card */
1253618f2068SAndy Fiddaman 	card_fw = kmem_zalloc(sizeof (*card_fw), KM_SLEEP);
1254618f2068SAndy Fiddaman 
12553dde7c95SVishal Kulkarni 	rc = -t4_prep_fw(sc, fw_info, fw_data, fw_size, card_fw,
1256618f2068SAndy Fiddaman 	    p->t4_fw_install, state, &reset);
12573dde7c95SVishal Kulkarni 
1258618f2068SAndy Fiddaman 	kmem_free(card_fw, sizeof (*card_fw));
1259618f2068SAndy Fiddaman 	kmem_free(fw_data, fw_size);
12603dde7c95SVishal Kulkarni 
12613dde7c95SVishal Kulkarni 	if (rc != 0) {
12623dde7c95SVishal Kulkarni 		cxgb_printf(sc->dip, CE_WARN,
12633dde7c95SVishal Kulkarni 		    "failed to install firmware: %d", rc);
12643dde7c95SVishal Kulkarni 		return (rc);
12653dde7c95SVishal Kulkarni 	} else {
12663dde7c95SVishal Kulkarni 		/* refresh */
12673dde7c95SVishal Kulkarni 		(void) t4_check_fw_version(sc);
12683dde7c95SVishal Kulkarni 	}
12693dde7c95SVishal Kulkarni 
127056b2bdd1SGireesh Nagabhushana 	/* Reset device */
127156b2bdd1SGireesh Nagabhushana 	rc = -t4_fw_reset(sc, sc->mbox, F_PIORSTMODE | F_PIORST);
127256b2bdd1SGireesh Nagabhushana 	if (rc != 0) {
127356b2bdd1SGireesh Nagabhushana 		cxgb_printf(sc->dip, CE_WARN,
127456b2bdd1SGireesh Nagabhushana 		    "firmware reset failed: %d.", rc);
127556b2bdd1SGireesh Nagabhushana 		if (rc != ETIMEDOUT && rc != EIO)
127656b2bdd1SGireesh Nagabhushana 			(void) t4_fw_bye(sc, sc->mbox);
127756b2bdd1SGireesh Nagabhushana 		return (rc);
127856b2bdd1SGireesh Nagabhushana 	}
127956b2bdd1SGireesh Nagabhushana 
128056b2bdd1SGireesh Nagabhushana 	/* Partition adapter resources as specified in the config file. */
128156b2bdd1SGireesh Nagabhushana 	if (sc->flags & MASTER_PF) {
128256b2bdd1SGireesh Nagabhushana 		/* Handle default vs special T4 config file */
128356b2bdd1SGireesh Nagabhushana 
128456b2bdd1SGireesh Nagabhushana 		rc = partition_resources(sc);
128556b2bdd1SGireesh Nagabhushana 		if (rc != 0)
128656b2bdd1SGireesh Nagabhushana 			goto err;	/* error message displayed already */
128756b2bdd1SGireesh Nagabhushana 	}
128856b2bdd1SGireesh Nagabhushana 
128956b2bdd1SGireesh Nagabhushana 	sc->flags |= FW_OK;
129056b2bdd1SGireesh Nagabhushana 	return (0);
129156b2bdd1SGireesh Nagabhushana err:
129256b2bdd1SGireesh Nagabhushana 	return (rc);
129356b2bdd1SGireesh Nagabhushana 
129456b2bdd1SGireesh Nagabhushana }
129556b2bdd1SGireesh Nagabhushana 
1296de483253SVishal Kulkarni static const struct memwin t4_memwin[] = {
1297de483253SVishal Kulkarni 	{ MEMWIN0_BASE, MEMWIN0_APERTURE },
1298de483253SVishal Kulkarni 	{ MEMWIN1_BASE, MEMWIN1_APERTURE },
12993dde7c95SVishal Kulkarni 	{ MEMWIN2_BASE, MEMWIN2_APERTURE }
1300de483253SVishal Kulkarni };
1301de483253SVishal Kulkarni 
1302de483253SVishal Kulkarni static const struct memwin t5_memwin[] = {
1303de483253SVishal Kulkarni 	{ MEMWIN0_BASE, MEMWIN0_APERTURE },
1304de483253SVishal Kulkarni 	{ MEMWIN1_BASE, MEMWIN1_APERTURE },
1305de483253SVishal Kulkarni 	{ MEMWIN2_BASE_T5, MEMWIN2_APERTURE_T5 },
1306de483253SVishal Kulkarni };
1307de483253SVishal Kulkarni 
130856b2bdd1SGireesh Nagabhushana #define	FW_PARAM_DEV(param) \
130956b2bdd1SGireesh Nagabhushana 	(V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | \
131056b2bdd1SGireesh Nagabhushana 	    V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_##param))
131156b2bdd1SGireesh Nagabhushana #define	FW_PARAM_PFVF(param) \
131256b2bdd1SGireesh Nagabhushana 	(V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_PFVF) | \
131356b2bdd1SGireesh Nagabhushana 	    V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_PFVF_##param))
131456b2bdd1SGireesh Nagabhushana 
1315de483253SVishal Kulkarni /*
1316de483253SVishal Kulkarni  * Verify that the memory range specified by the memtype/offset/len pair is
1317de483253SVishal Kulkarni  * valid and lies entirely within the memtype specified.  The global address of
1318de483253SVishal Kulkarni  * the start of the range is returned in addr.
1319de483253SVishal Kulkarni  */
1320de483253SVishal Kulkarni int
validate_mt_off_len(struct adapter * sc,int mtype,uint32_t off,int len,uint32_t * addr)1321de483253SVishal Kulkarni validate_mt_off_len(struct adapter *sc, int mtype, uint32_t off, int len,
1322de483253SVishal Kulkarni 	uint32_t *addr)
1323de483253SVishal Kulkarni {
1324de483253SVishal Kulkarni 	uint32_t em, addr_len, maddr, mlen;
1325de483253SVishal Kulkarni 
1326de483253SVishal Kulkarni 	/* Memory can only be accessed in naturally aligned 4 byte units */
1327de483253SVishal Kulkarni 	if (off & 3 || len & 3 || len == 0)
1328de483253SVishal Kulkarni 		return (EINVAL);
1329de483253SVishal Kulkarni 
1330de483253SVishal Kulkarni 	em = t4_read_reg(sc, A_MA_TARGET_MEM_ENABLE);
1331de483253SVishal Kulkarni 	switch (mtype) {
1332de483253SVishal Kulkarni 		case MEM_EDC0:
1333de483253SVishal Kulkarni 			if (!(em & F_EDRAM0_ENABLE))
1334de483253SVishal Kulkarni 				return (EINVAL);
1335de483253SVishal Kulkarni 			addr_len = t4_read_reg(sc, A_MA_EDRAM0_BAR);
1336de483253SVishal Kulkarni 			maddr = G_EDRAM0_BASE(addr_len) << 20;
1337de483253SVishal Kulkarni 			mlen = G_EDRAM0_SIZE(addr_len) << 20;
1338de483253SVishal Kulkarni 			break;
1339de483253SVishal Kulkarni 		case MEM_EDC1:
1340de483253SVishal Kulkarni 			if (!(em & F_EDRAM1_ENABLE))
1341de483253SVishal Kulkarni 				return (EINVAL);
1342de483253SVishal Kulkarni 			addr_len = t4_read_reg(sc, A_MA_EDRAM1_BAR);
1343de483253SVishal Kulkarni 			maddr = G_EDRAM1_BASE(addr_len) << 20;
1344de483253SVishal Kulkarni 			mlen = G_EDRAM1_SIZE(addr_len) << 20;
1345de483253SVishal Kulkarni 			break;
1346de483253SVishal Kulkarni 		case MEM_MC:
1347de483253SVishal Kulkarni 			if (!(em & F_EXT_MEM_ENABLE))
1348de483253SVishal Kulkarni 				return (EINVAL);
1349de483253SVishal Kulkarni 			addr_len = t4_read_reg(sc, A_MA_EXT_MEMORY_BAR);
1350de483253SVishal Kulkarni 			maddr = G_EXT_MEM_BASE(addr_len) << 20;
1351de483253SVishal Kulkarni 			mlen = G_EXT_MEM_SIZE(addr_len) << 20;
1352de483253SVishal Kulkarni 			break;
1353de483253SVishal Kulkarni 		case MEM_MC1:
1354de483253SVishal Kulkarni 			if (is_t4(sc->params.chip) || !(em & F_EXT_MEM1_ENABLE))
1355de483253SVishal Kulkarni 				return (EINVAL);
1356de483253SVishal Kulkarni 			addr_len = t4_read_reg(sc, A_MA_EXT_MEMORY1_BAR);
1357de483253SVishal Kulkarni 			maddr = G_EXT_MEM1_BASE(addr_len) << 20;
1358de483253SVishal Kulkarni 			mlen = G_EXT_MEM1_SIZE(addr_len) << 20;
1359de483253SVishal Kulkarni 			break;
1360de483253SVishal Kulkarni 		default:
1361de483253SVishal Kulkarni 			return (EINVAL);
1362de483253SVishal Kulkarni 	}
1363de483253SVishal Kulkarni 
1364de483253SVishal Kulkarni 	if (mlen > 0 && off < mlen && off + len <= mlen) {
1365de483253SVishal Kulkarni 		*addr = maddr + off;    /* global address */
1366de483253SVishal Kulkarni 		return (0);
1367de483253SVishal Kulkarni 	}
1368de483253SVishal Kulkarni 
1369de483253SVishal Kulkarni 	return (EFAULT);
1370de483253SVishal Kulkarni }
1371de483253SVishal Kulkarni 
1372de483253SVishal Kulkarni void
memwin_info(struct adapter * sc,int win,uint32_t * base,uint32_t * aperture)1373de483253SVishal Kulkarni memwin_info(struct adapter *sc, int win, uint32_t *base, uint32_t *aperture)
1374de483253SVishal Kulkarni {
1375de483253SVishal Kulkarni 	const struct memwin *mw;
1376de483253SVishal Kulkarni 
1377de483253SVishal Kulkarni 	if (is_t4(sc->params.chip)) {
1378de483253SVishal Kulkarni 		mw = &t4_memwin[win];
1379de483253SVishal Kulkarni 	} else {
1380de483253SVishal Kulkarni 		mw = &t5_memwin[win];
1381de483253SVishal Kulkarni 	}
1382de483253SVishal Kulkarni 
1383de483253SVishal Kulkarni 	if (base != NULL)
1384de483253SVishal Kulkarni 		*base = mw->base;
1385de483253SVishal Kulkarni 	if (aperture != NULL)
1386de483253SVishal Kulkarni 		*aperture = mw->aperture;
1387de483253SVishal Kulkarni }
1388de483253SVishal Kulkarni 
138956b2bdd1SGireesh Nagabhushana /*
139056b2bdd1SGireesh Nagabhushana  * Upload configuration file to card's memory.
139156b2bdd1SGireesh Nagabhushana  */
139256b2bdd1SGireesh Nagabhushana static int
upload_config_file(struct adapter * sc,uint32_t * mt,uint32_t * ma)139356b2bdd1SGireesh Nagabhushana upload_config_file(struct adapter *sc, uint32_t *mt, uint32_t *ma)
139456b2bdd1SGireesh Nagabhushana {
1395618f2068SAndy Fiddaman 	int rc = 0;
1396618f2068SAndy Fiddaman 	size_t cflen, cfbaselen;
1397de483253SVishal Kulkarni 	u_int i, n;
1398de483253SVishal Kulkarni 	uint32_t param, val, addr, mtype, maddr;
1399de483253SVishal Kulkarni 	uint32_t off, mw_base, mw_aperture;
1400618f2068SAndy Fiddaman 	uint32_t *cfdata, *cfbase;
1401618f2068SAndy Fiddaman 	firmware_handle_t fw_hdl;
1402618f2068SAndy Fiddaman 	const char *cfg_file = NULL;
140356b2bdd1SGireesh Nagabhushana 
140456b2bdd1SGireesh Nagabhushana 	/* Figure out where the firmware wants us to upload it. */
140556b2bdd1SGireesh Nagabhushana 	param = FW_PARAM_DEV(CF);
140656b2bdd1SGireesh Nagabhushana 	rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 1, &param, &val);
140756b2bdd1SGireesh Nagabhushana 	if (rc != 0) {
140856b2bdd1SGireesh Nagabhushana 		/* Firmwares without config file support will fail this way */
140956b2bdd1SGireesh Nagabhushana 		cxgb_printf(sc->dip, CE_WARN,
141056b2bdd1SGireesh Nagabhushana 		    "failed to query config file location: %d.\n", rc);
141156b2bdd1SGireesh Nagabhushana 		return (rc);
141256b2bdd1SGireesh Nagabhushana 	}
141356b2bdd1SGireesh Nagabhushana 	*mt = mtype = G_FW_PARAMS_PARAM_Y(val);
141456b2bdd1SGireesh Nagabhushana 	*ma = maddr = G_FW_PARAMS_PARAM_Z(val) << 16;
141556b2bdd1SGireesh Nagabhushana 
14163dde7c95SVishal Kulkarni 	switch (CHELSIO_CHIP_VERSION(sc->params.chip)) {
14173dde7c95SVishal Kulkarni 	case CHELSIO_T4:
1418618f2068SAndy Fiddaman 		cfg_file = "t4fw_cfg.txt";
14193dde7c95SVishal Kulkarni 		break;
14203dde7c95SVishal Kulkarni 	case CHELSIO_T5:
1421618f2068SAndy Fiddaman 		cfg_file = "t5fw_cfg.txt";
14223dde7c95SVishal Kulkarni 		break;
14233dde7c95SVishal Kulkarni 	case CHELSIO_T6:
1424618f2068SAndy Fiddaman 		cfg_file = "t6fw_cfg.txt";
14253dde7c95SVishal Kulkarni 		break;
14263dde7c95SVishal Kulkarni 	default:
1427618f2068SAndy Fiddaman 		cxgb_printf(sc->dip, CE_WARN, "Invalid Adapter detected\n");
142894c3dad2SToomas Soome 		return EINVAL;
1429de483253SVishal Kulkarni 	}
1430de483253SVishal Kulkarni 
1431618f2068SAndy Fiddaman 	if (firmware_open(T4_PORT_NAME, cfg_file, &fw_hdl) != 0) {
1432618f2068SAndy Fiddaman 		cxgb_printf(sc->dip, CE_WARN, "Could not open %s\n", cfg_file);
1433618f2068SAndy Fiddaman 		return EINVAL;
1434618f2068SAndy Fiddaman 	}
1435618f2068SAndy Fiddaman 
1436618f2068SAndy Fiddaman 	cflen = firmware_get_size(fw_hdl);
1437618f2068SAndy Fiddaman 	/*
1438618f2068SAndy Fiddaman 	 * Truncate the length to a multiple of uint32_ts. The configuration
1439618f2068SAndy Fiddaman 	 * text files have trailing comments (and hopefully always will) so
1440618f2068SAndy Fiddaman 	 * nothing important is lost.
1441618f2068SAndy Fiddaman 	 */
1442618f2068SAndy Fiddaman 	cflen &= ~3;
1443618f2068SAndy Fiddaman 
1444de483253SVishal Kulkarni 	if (cflen > FLASH_CFG_MAX_SIZE) {
144556b2bdd1SGireesh Nagabhushana 		cxgb_printf(sc->dip, CE_WARN,
1446de483253SVishal Kulkarni 		    "config file too long (%d, max allowed is %d).  ",
1447de483253SVishal Kulkarni 		    cflen, FLASH_CFG_MAX_SIZE);
1448618f2068SAndy Fiddaman 		firmware_close(fw_hdl);
1449de483253SVishal Kulkarni 		return (EFBIG);
145056b2bdd1SGireesh Nagabhushana 	}
145156b2bdd1SGireesh Nagabhushana 
1452de483253SVishal Kulkarni 	rc = validate_mt_off_len(sc, mtype, maddr, cflen, &addr);
1453de483253SVishal Kulkarni 	if (rc != 0) {
145456b2bdd1SGireesh Nagabhushana 		cxgb_printf(sc->dip, CE_WARN,
1455de483253SVishal Kulkarni 		    "%s: addr (%d/0x%x) or len %d is not valid: %d.  "
1456de483253SVishal Kulkarni 		    "Will try to use the config on the card, if any.\n",
1457de483253SVishal Kulkarni 		    __func__, mtype, maddr, cflen, rc);
1458618f2068SAndy Fiddaman 		firmware_close(fw_hdl);
145956b2bdd1SGireesh Nagabhushana 		return (EFAULT);
146056b2bdd1SGireesh Nagabhushana 	}
146156b2bdd1SGireesh Nagabhushana 
1462618f2068SAndy Fiddaman 	cfbaselen = cflen;
1463618f2068SAndy Fiddaman 	cfbase = cfdata = kmem_zalloc(cflen, KM_SLEEP);
1464618f2068SAndy Fiddaman 	if (firmware_read(fw_hdl, 0, cfdata, cflen) != 0) {
1465618f2068SAndy Fiddaman 		cxgb_printf(sc->dip, CE_WARN, "Failed to read from %s\n",
1466618f2068SAndy Fiddaman 		    cfg_file);
1467618f2068SAndy Fiddaman 		firmware_close(fw_hdl);
1468618f2068SAndy Fiddaman 		kmem_free(cfbase, cfbaselen);
1469618f2068SAndy Fiddaman 		return EINVAL;
1470618f2068SAndy Fiddaman 	}
1471618f2068SAndy Fiddaman 	firmware_close(fw_hdl);
1472618f2068SAndy Fiddaman 
1473de483253SVishal Kulkarni 	memwin_info(sc, 2, &mw_base, &mw_aperture);
1474de483253SVishal Kulkarni 	while (cflen) {
1475de483253SVishal Kulkarni 		off = position_memwin(sc, 2, addr);
1476de483253SVishal Kulkarni 		n = min(cflen, mw_aperture - off);
1477de483253SVishal Kulkarni 		for (i = 0; i < n; i += 4)
1478de483253SVishal Kulkarni 			t4_write_reg(sc, mw_base + off + i, *cfdata++);
1479de483253SVishal Kulkarni 		cflen -= n;
1480de483253SVishal Kulkarni 		addr += n;
148156b2bdd1SGireesh Nagabhushana 	}
148256b2bdd1SGireesh Nagabhushana 
1483618f2068SAndy Fiddaman 	kmem_free(cfbase, cfbaselen);
1484618f2068SAndy Fiddaman 
148556b2bdd1SGireesh Nagabhushana 	return (rc);
148656b2bdd1SGireesh Nagabhushana }
148756b2bdd1SGireesh Nagabhushana 
148856b2bdd1SGireesh Nagabhushana /*
148956b2bdd1SGireesh Nagabhushana  * Partition chip resources for use between various PFs, VFs, etc.  This is done
149056b2bdd1SGireesh Nagabhushana  * by uploading the firmware configuration file to the adapter and instructing
149156b2bdd1SGireesh Nagabhushana  * the firmware to process it.
149256b2bdd1SGireesh Nagabhushana  */
149356b2bdd1SGireesh Nagabhushana static int
partition_resources(struct adapter * sc)149456b2bdd1SGireesh Nagabhushana partition_resources(struct adapter *sc)
149556b2bdd1SGireesh Nagabhushana {
149656b2bdd1SGireesh Nagabhushana 	int rc;
149756b2bdd1SGireesh Nagabhushana 	struct fw_caps_config_cmd caps;
149856b2bdd1SGireesh Nagabhushana 	uint32_t mtype, maddr, finicsum, cfcsum;
149956b2bdd1SGireesh Nagabhushana 
150056b2bdd1SGireesh Nagabhushana 	rc = upload_config_file(sc, &mtype, &maddr);
150156b2bdd1SGireesh Nagabhushana 	if (rc != 0) {
150256b2bdd1SGireesh Nagabhushana 		mtype = FW_MEMTYPE_CF_FLASH;
150356b2bdd1SGireesh Nagabhushana 		maddr = t4_flash_cfg_addr(sc);
150456b2bdd1SGireesh Nagabhushana 	}
150556b2bdd1SGireesh Nagabhushana 
150656b2bdd1SGireesh Nagabhushana 	bzero(&caps, sizeof (caps));
150756b2bdd1SGireesh Nagabhushana 	caps.op_to_write = BE_32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
150856b2bdd1SGireesh Nagabhushana 	    F_FW_CMD_REQUEST | F_FW_CMD_READ);
150956b2bdd1SGireesh Nagabhushana 	caps.cfvalid_to_len16 = BE_32(F_FW_CAPS_CONFIG_CMD_CFVALID |
151056b2bdd1SGireesh Nagabhushana 	    V_FW_CAPS_CONFIG_CMD_MEMTYPE_CF(mtype) |
151156b2bdd1SGireesh Nagabhushana 	    V_FW_CAPS_CONFIG_CMD_MEMADDR64K_CF(maddr >> 16) | FW_LEN16(caps));
151256b2bdd1SGireesh Nagabhushana 	rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof (caps), &caps);
151356b2bdd1SGireesh Nagabhushana 	if (rc != 0) {
151456b2bdd1SGireesh Nagabhushana 		cxgb_printf(sc->dip, CE_WARN,
151556b2bdd1SGireesh Nagabhushana 		    "failed to pre-process config file: %d.\n", rc);
151656b2bdd1SGireesh Nagabhushana 		return (rc);
151756b2bdd1SGireesh Nagabhushana 	}
151856b2bdd1SGireesh Nagabhushana 
151956b2bdd1SGireesh Nagabhushana 	finicsum = ntohl(caps.finicsum);
152056b2bdd1SGireesh Nagabhushana 	cfcsum = ntohl(caps.cfcsum);
152156b2bdd1SGireesh Nagabhushana 	if (finicsum != cfcsum) {
152256b2bdd1SGireesh Nagabhushana 		cxgb_printf(sc->dip, CE_WARN,
152356b2bdd1SGireesh Nagabhushana 		    "WARNING: config file checksum mismatch: %08x %08x\n",
152456b2bdd1SGireesh Nagabhushana 		    finicsum, cfcsum);
152556b2bdd1SGireesh Nagabhushana 	}
152656b2bdd1SGireesh Nagabhushana 	sc->cfcsum = cfcsum;
152756b2bdd1SGireesh Nagabhushana 
152856b2bdd1SGireesh Nagabhushana 	/* TODO: Need to configure this correctly */
152956b2bdd1SGireesh Nagabhushana 	caps.toecaps = htons(FW_CAPS_CONFIG_TOE);
153056b2bdd1SGireesh Nagabhushana 	caps.iscsicaps = 0;
153156b2bdd1SGireesh Nagabhushana 	caps.rdmacaps = 0;
153256b2bdd1SGireesh Nagabhushana 	caps.fcoecaps = 0;
153356b2bdd1SGireesh Nagabhushana 	/* TODO: Disable VNIC cap for now */
153456b2bdd1SGireesh Nagabhushana 	caps.niccaps ^= htons(FW_CAPS_CONFIG_NIC_VM);
153556b2bdd1SGireesh Nagabhushana 
153656b2bdd1SGireesh Nagabhushana 	caps.op_to_write = htonl(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
153756b2bdd1SGireesh Nagabhushana 	    F_FW_CMD_REQUEST | F_FW_CMD_WRITE);
153856b2bdd1SGireesh Nagabhushana 	caps.cfvalid_to_len16 = htonl(FW_LEN16(caps));
153956b2bdd1SGireesh Nagabhushana 	rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof (caps), NULL);
154056b2bdd1SGireesh Nagabhushana 	if (rc != 0) {
154156b2bdd1SGireesh Nagabhushana 		cxgb_printf(sc->dip, CE_WARN,
154256b2bdd1SGireesh Nagabhushana 		    "failed to process config file: %d.\n", rc);
154356b2bdd1SGireesh Nagabhushana 		return (rc);
154456b2bdd1SGireesh Nagabhushana 	}
154556b2bdd1SGireesh Nagabhushana 
154656b2bdd1SGireesh Nagabhushana 	return (0);
154756b2bdd1SGireesh Nagabhushana }
154856b2bdd1SGireesh Nagabhushana 
15493dde7c95SVishal Kulkarni /*
15503dde7c95SVishal Kulkarni  * Tweak configuration based on module parameters, etc.  Most of these have
15513dde7c95SVishal Kulkarni  * defaults assigned to them by Firmware Configuration Files (if we're using
15523dde7c95SVishal Kulkarni  * them) but need to be explicitly set if we're using hard-coded
15533dde7c95SVishal Kulkarni  * initialization.  But even in the case of using Firmware Configuration
15543dde7c95SVishal Kulkarni  * Files, we'd like to expose the ability to change these via module
15553dde7c95SVishal Kulkarni  * parameters so these are essentially common tweaks/settings for
15563dde7c95SVishal Kulkarni  * Configuration Files and hard-coded initialization ...
15573dde7c95SVishal Kulkarni  */
15583dde7c95SVishal Kulkarni static int
adap__pre_init_tweaks(struct adapter * sc)15593dde7c95SVishal Kulkarni adap__pre_init_tweaks(struct adapter *sc)
15603dde7c95SVishal Kulkarni {
15613dde7c95SVishal Kulkarni 	int rx_dma_offset = 2; /* Offset of RX packets into DMA buffers */
15623dde7c95SVishal Kulkarni 
15633dde7c95SVishal Kulkarni 	/*
15643dde7c95SVishal Kulkarni 	 * Fix up various Host-Dependent Parameters like Page Size, Cache
15653dde7c95SVishal Kulkarni 	 * Line Size, etc.  The firmware default is for a 4KB Page Size and
15663dde7c95SVishal Kulkarni 	 * 64B Cache Line Size ...
15673dde7c95SVishal Kulkarni 	 */
15683dde7c95SVishal Kulkarni 	(void) t4_fixup_host_params_compat(sc, PAGE_SIZE, CACHE_LINE, T5_LAST_REV);
15693dde7c95SVishal Kulkarni 
15703dde7c95SVishal Kulkarni 	t4_set_reg_field(sc, A_SGE_CONTROL,
15713dde7c95SVishal Kulkarni 			 V_PKTSHIFT(M_PKTSHIFT), V_PKTSHIFT(rx_dma_offset));
15723dde7c95SVishal Kulkarni 
15733dde7c95SVishal Kulkarni 	return 0;
15743dde7c95SVishal Kulkarni }
157556b2bdd1SGireesh Nagabhushana /*
157656b2bdd1SGireesh Nagabhushana  * Retrieve parameters that are needed (or nice to have) prior to calling
157756b2bdd1SGireesh Nagabhushana  * t4_sge_init and t4_fw_initialize.
157856b2bdd1SGireesh Nagabhushana  */
157956b2bdd1SGireesh Nagabhushana static int
get_params__pre_init(struct adapter * sc)158056b2bdd1SGireesh Nagabhushana get_params__pre_init(struct adapter *sc)
158156b2bdd1SGireesh Nagabhushana {
158256b2bdd1SGireesh Nagabhushana 	int rc;
158356b2bdd1SGireesh Nagabhushana 	uint32_t param[2], val[2];
158456b2bdd1SGireesh Nagabhushana 	struct fw_devlog_cmd cmd;
158556b2bdd1SGireesh Nagabhushana 	struct devlog_params *dlog = &sc->params.devlog;
158656b2bdd1SGireesh Nagabhushana 
15873dde7c95SVishal Kulkarni 	/*
15883dde7c95SVishal Kulkarni 	 * Grab the raw VPD parameters.
15893dde7c95SVishal Kulkarni 	 */
15903dde7c95SVishal Kulkarni 	rc = -t4_get_raw_vpd_params(sc, &sc->params.vpd);
15913dde7c95SVishal Kulkarni 	if (rc != 0) {
15923dde7c95SVishal Kulkarni 		cxgb_printf(sc->dip, CE_WARN,
15933dde7c95SVishal Kulkarni 		    "failed to query VPD parameters (pre_init): %d.\n", rc);
15943dde7c95SVishal Kulkarni 		return (rc);
15953dde7c95SVishal Kulkarni 	}
15963dde7c95SVishal Kulkarni 
159756b2bdd1SGireesh Nagabhushana 	param[0] = FW_PARAM_DEV(PORTVEC);
159856b2bdd1SGireesh Nagabhushana 	param[1] = FW_PARAM_DEV(CCLK);
159956b2bdd1SGireesh Nagabhushana 	rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 2, param, val);
160056b2bdd1SGireesh Nagabhushana 	if (rc != 0) {
160156b2bdd1SGireesh Nagabhushana 		cxgb_printf(sc->dip, CE_WARN,
160256b2bdd1SGireesh Nagabhushana 		    "failed to query parameters (pre_init): %d.\n", rc);
160356b2bdd1SGireesh Nagabhushana 		return (rc);
160456b2bdd1SGireesh Nagabhushana 	}
160556b2bdd1SGireesh Nagabhushana 
160656b2bdd1SGireesh Nagabhushana 	sc->params.portvec = val[0];
160756b2bdd1SGireesh Nagabhushana 	sc->params.nports = 0;
160856b2bdd1SGireesh Nagabhushana 	while (val[0]) {
160956b2bdd1SGireesh Nagabhushana 		sc->params.nports++;
161056b2bdd1SGireesh Nagabhushana 		val[0] &= val[0] - 1;
161156b2bdd1SGireesh Nagabhushana 	}
161256b2bdd1SGireesh Nagabhushana 
161356b2bdd1SGireesh Nagabhushana 	sc->params.vpd.cclk = val[1];
161456b2bdd1SGireesh Nagabhushana 
161556b2bdd1SGireesh Nagabhushana 	/* Read device log parameters. */
161656b2bdd1SGireesh Nagabhushana 	bzero(&cmd, sizeof (cmd));
161756b2bdd1SGireesh Nagabhushana 	cmd.op_to_write = htonl(V_FW_CMD_OP(FW_DEVLOG_CMD) |
161856b2bdd1SGireesh Nagabhushana 	    F_FW_CMD_REQUEST | F_FW_CMD_READ);
161956b2bdd1SGireesh Nagabhushana 	cmd.retval_len16 = htonl(FW_LEN16(cmd));
162056b2bdd1SGireesh Nagabhushana 	rc = -t4_wr_mbox(sc, sc->mbox, &cmd, sizeof (cmd), &cmd);
162156b2bdd1SGireesh Nagabhushana 	if (rc != 0) {
162256b2bdd1SGireesh Nagabhushana 		cxgb_printf(sc->dip, CE_WARN,
162356b2bdd1SGireesh Nagabhushana 		    "failed to get devlog parameters: %d.\n", rc);
162456b2bdd1SGireesh Nagabhushana 		bzero(dlog, sizeof (*dlog));
162556b2bdd1SGireesh Nagabhushana 		rc = 0;	/* devlog isn't critical for device operation */
162656b2bdd1SGireesh Nagabhushana 	} else {
162756b2bdd1SGireesh Nagabhushana 		val[0] = ntohl(cmd.memtype_devlog_memaddr16_devlog);
162856b2bdd1SGireesh Nagabhushana 		dlog->memtype = G_FW_DEVLOG_CMD_MEMTYPE_DEVLOG(val[0]);
162956b2bdd1SGireesh Nagabhushana 		dlog->start = G_FW_DEVLOG_CMD_MEMADDR16_DEVLOG(val[0]) << 4;
163056b2bdd1SGireesh Nagabhushana 		dlog->size = ntohl(cmd.memsize_devlog);
163156b2bdd1SGireesh Nagabhushana 	}
163256b2bdd1SGireesh Nagabhushana 
163356b2bdd1SGireesh Nagabhushana 	return (rc);
163456b2bdd1SGireesh Nagabhushana }
163556b2bdd1SGireesh Nagabhushana 
163656b2bdd1SGireesh Nagabhushana /*
163756b2bdd1SGireesh Nagabhushana  * Retrieve various parameters that are of interest to the driver.  The device
163856b2bdd1SGireesh Nagabhushana  * has been initialized by the firmware at this point.
163956b2bdd1SGireesh Nagabhushana  */
164056b2bdd1SGireesh Nagabhushana static int
get_params__post_init(struct adapter * sc)164156b2bdd1SGireesh Nagabhushana get_params__post_init(struct adapter *sc)
164256b2bdd1SGireesh Nagabhushana {
164356b2bdd1SGireesh Nagabhushana 	int rc;
164456b2bdd1SGireesh Nagabhushana 	uint32_t param[7], val[7];
164556b2bdd1SGireesh Nagabhushana 	struct fw_caps_config_cmd caps;
164656b2bdd1SGireesh Nagabhushana 
164756b2bdd1SGireesh Nagabhushana 	param[0] = FW_PARAM_PFVF(IQFLINT_START);
164856b2bdd1SGireesh Nagabhushana 	param[1] = FW_PARAM_PFVF(EQ_START);
164956b2bdd1SGireesh Nagabhushana 	param[2] = FW_PARAM_PFVF(FILTER_START);
165056b2bdd1SGireesh Nagabhushana 	param[3] = FW_PARAM_PFVF(FILTER_END);
1651de483253SVishal Kulkarni 	param[4] = FW_PARAM_PFVF(L2T_START);
1652de483253SVishal Kulkarni 	param[5] = FW_PARAM_PFVF(L2T_END);
1653de483253SVishal Kulkarni 	rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val);
165456b2bdd1SGireesh Nagabhushana 	if (rc != 0) {
165556b2bdd1SGireesh Nagabhushana 		cxgb_printf(sc->dip, CE_WARN,
165656b2bdd1SGireesh Nagabhushana 		    "failed to query parameters (post_init): %d.\n", rc);
165756b2bdd1SGireesh Nagabhushana 		return (rc);
165856b2bdd1SGireesh Nagabhushana 	}
165956b2bdd1SGireesh Nagabhushana 
166056b2bdd1SGireesh Nagabhushana 	/* LINTED: E_ASSIGN_NARROW_CONV */
166156b2bdd1SGireesh Nagabhushana 	sc->sge.iq_start = val[0];
166256b2bdd1SGireesh Nagabhushana 	sc->sge.eq_start = val[1];
166356b2bdd1SGireesh Nagabhushana 	sc->tids.ftid_base = val[2];
166456b2bdd1SGireesh Nagabhushana 	sc->tids.nftids = val[3] - val[2] + 1;
1665de483253SVishal Kulkarni 	sc->vres.l2t.start = val[4];
1666de483253SVishal Kulkarni 	sc->vres.l2t.size = val[5] - val[4] + 1;
166756b2bdd1SGireesh Nagabhushana 
166877ac03cbSRahul Lakkireddy 	param[0] = FW_PARAM_PFVF(IQFLINT_END);
166977ac03cbSRahul Lakkireddy 	param[1] = FW_PARAM_PFVF(EQ_END);
167077ac03cbSRahul Lakkireddy 	rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 2, param, val);
167177ac03cbSRahul Lakkireddy 	if (rc != 0) {
167277ac03cbSRahul Lakkireddy 		cxgb_printf(sc->dip, CE_WARN,
167377ac03cbSRahul Lakkireddy 			    "failed to query eq/iq map size parameters (post_init): %d.\n",
167477ac03cbSRahul Lakkireddy 			    rc);
167577ac03cbSRahul Lakkireddy 		return (rc);
167677ac03cbSRahul Lakkireddy 	}
167777ac03cbSRahul Lakkireddy 
167877ac03cbSRahul Lakkireddy 	sc->sge.iqmap_sz = val[0] - sc->sge.iq_start + 1;
167977ac03cbSRahul Lakkireddy 	sc->sge.eqmap_sz = val[1] - sc->sge.eq_start + 1;
168077ac03cbSRahul Lakkireddy 
168156b2bdd1SGireesh Nagabhushana 	/* get capabilites */
168256b2bdd1SGireesh Nagabhushana 	bzero(&caps, sizeof (caps));
168356b2bdd1SGireesh Nagabhushana 	caps.op_to_write = htonl(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
168456b2bdd1SGireesh Nagabhushana 	    F_FW_CMD_REQUEST | F_FW_CMD_READ);
168556b2bdd1SGireesh Nagabhushana 	caps.cfvalid_to_len16 = htonl(FW_LEN16(caps));
168656b2bdd1SGireesh Nagabhushana 	rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof (caps), &caps);
168756b2bdd1SGireesh Nagabhushana 	if (rc != 0) {
168856b2bdd1SGireesh Nagabhushana 		cxgb_printf(sc->dip, CE_WARN,
168956b2bdd1SGireesh Nagabhushana 		    "failed to get card capabilities: %d.\n", rc);
169056b2bdd1SGireesh Nagabhushana 		return (rc);
169156b2bdd1SGireesh Nagabhushana 	}
169256b2bdd1SGireesh Nagabhushana 
169356b2bdd1SGireesh Nagabhushana 	if (caps.toecaps != 0) {
169456b2bdd1SGireesh Nagabhushana 		/* query offload-related parameters */
169556b2bdd1SGireesh Nagabhushana 		param[0] = FW_PARAM_DEV(NTID);
169656b2bdd1SGireesh Nagabhushana 		param[1] = FW_PARAM_PFVF(SERVER_START);
169756b2bdd1SGireesh Nagabhushana 		param[2] = FW_PARAM_PFVF(SERVER_END);
169856b2bdd1SGireesh Nagabhushana 		param[3] = FW_PARAM_PFVF(TDDP_START);
169956b2bdd1SGireesh Nagabhushana 		param[4] = FW_PARAM_PFVF(TDDP_END);
170056b2bdd1SGireesh Nagabhushana 		param[5] = FW_PARAM_DEV(FLOWC_BUFFIFO_SZ);
170156b2bdd1SGireesh Nagabhushana 		rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val);
170256b2bdd1SGireesh Nagabhushana 		if (rc != 0) {
170356b2bdd1SGireesh Nagabhushana 			cxgb_printf(sc->dip, CE_WARN,
170456b2bdd1SGireesh Nagabhushana 			    "failed to query TOE parameters: %d.\n", rc);
170556b2bdd1SGireesh Nagabhushana 			return (rc);
170656b2bdd1SGireesh Nagabhushana 		}
170756b2bdd1SGireesh Nagabhushana 		sc->tids.ntids = val[0];
170856b2bdd1SGireesh Nagabhushana 		sc->tids.natids = min(sc->tids.ntids / 2, MAX_ATIDS);
170956b2bdd1SGireesh Nagabhushana 		sc->tids.stid_base = val[1];
171056b2bdd1SGireesh Nagabhushana 		sc->tids.nstids = val[2] - val[1] + 1;
171156b2bdd1SGireesh Nagabhushana 		sc->vres.ddp.start = val[3];
171256b2bdd1SGireesh Nagabhushana 		sc->vres.ddp.size = val[4] - val[3] + 1;
171356b2bdd1SGireesh Nagabhushana 		sc->params.ofldq_wr_cred = val[5];
171456b2bdd1SGireesh Nagabhushana 		sc->params.offload = 1;
171556b2bdd1SGireesh Nagabhushana 	}
171656b2bdd1SGireesh Nagabhushana 
171777ac03cbSRahul Lakkireddy 	rc = -t4_get_pfres(sc);
171877ac03cbSRahul Lakkireddy 	if (rc != 0) {
171977ac03cbSRahul Lakkireddy 		cxgb_printf(sc->dip, CE_WARN,
172077ac03cbSRahul Lakkireddy 			    "failed to query PF resource params: %d.\n", rc);
172177ac03cbSRahul Lakkireddy 		return (rc);
172277ac03cbSRahul Lakkireddy 	}
172377ac03cbSRahul Lakkireddy 
172456b2bdd1SGireesh Nagabhushana 	/* These are finalized by FW initialization, load their values now */
172556b2bdd1SGireesh Nagabhushana 	val[0] = t4_read_reg(sc, A_TP_TIMER_RESOLUTION);
172656b2bdd1SGireesh Nagabhushana 	sc->params.tp.tre = G_TIMERRESOLUTION(val[0]);
172756b2bdd1SGireesh Nagabhushana 	sc->params.tp.dack_re = G_DELAYEDACKRESOLUTION(val[0]);
172856b2bdd1SGireesh Nagabhushana 	t4_read_mtu_tbl(sc, sc->params.mtus, NULL);
172956b2bdd1SGireesh Nagabhushana 
173056b2bdd1SGireesh Nagabhushana 	return (rc);
173156b2bdd1SGireesh Nagabhushana }
173256b2bdd1SGireesh Nagabhushana 
1733de483253SVishal Kulkarni static int
set_params__post_init(struct adapter * sc)1734de483253SVishal Kulkarni set_params__post_init(struct adapter *sc)
1735de483253SVishal Kulkarni {
1736de483253SVishal Kulkarni 	uint32_t param, val;
1737de483253SVishal Kulkarni 
1738de483253SVishal Kulkarni 	/* ask for encapsulated CPLs */
1739de483253SVishal Kulkarni 	param = FW_PARAM_PFVF(CPLFW4MSG_ENCAP);
1740de483253SVishal Kulkarni 	val = 1;
1741de483253SVishal Kulkarni 	(void)t4_set_params(sc, sc->mbox, sc->pf, 0, 1, &param, &val);
1742de483253SVishal Kulkarni 
1743de483253SVishal Kulkarni 	return (0);
1744de483253SVishal Kulkarni }
1745de483253SVishal Kulkarni 
174656b2bdd1SGireesh Nagabhushana /* TODO: verify */
174756b2bdd1SGireesh Nagabhushana static void
setup_memwin(struct adapter * sc)174856b2bdd1SGireesh Nagabhushana setup_memwin(struct adapter *sc)
174956b2bdd1SGireesh Nagabhushana {
175056b2bdd1SGireesh Nagabhushana 	pci_regspec_t *data;
175156b2bdd1SGireesh Nagabhushana 	int rc;
175256b2bdd1SGireesh Nagabhushana 	uint_t n;
175356b2bdd1SGireesh Nagabhushana 	uintptr_t bar0;
1754de483253SVishal Kulkarni 	uintptr_t mem_win0_base, mem_win1_base, mem_win2_base;
1755de483253SVishal Kulkarni 	uintptr_t mem_win2_aperture;
175656b2bdd1SGireesh Nagabhushana 
175756b2bdd1SGireesh Nagabhushana 	rc = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, sc->dip,
175856b2bdd1SGireesh Nagabhushana 	    DDI_PROP_DONTPASS, "assigned-addresses", (int **)&data, &n);
175956b2bdd1SGireesh Nagabhushana 	if (rc != DDI_SUCCESS) {
176056b2bdd1SGireesh Nagabhushana 		cxgb_printf(sc->dip, CE_WARN,
176156b2bdd1SGireesh Nagabhushana 		    "failed to lookup \"assigned-addresses\" property: %d", rc);
176256b2bdd1SGireesh Nagabhushana 		return;
176356b2bdd1SGireesh Nagabhushana 	}
176456b2bdd1SGireesh Nagabhushana 	n /= sizeof (*data);
176556b2bdd1SGireesh Nagabhushana 
176656b2bdd1SGireesh Nagabhushana 	bar0 = ((uint64_t)data[0].pci_phys_mid << 32) | data[0].pci_phys_low;
176756b2bdd1SGireesh Nagabhushana 	ddi_prop_free(data);
176856b2bdd1SGireesh Nagabhushana 
1769de483253SVishal Kulkarni 	if (is_t4(sc->params.chip)) {
1770de483253SVishal Kulkarni 		mem_win0_base = bar0 + MEMWIN0_BASE;
1771de483253SVishal Kulkarni 		mem_win1_base = bar0 + MEMWIN1_BASE;
17723dde7c95SVishal Kulkarni 		mem_win2_base = bar0 + MEMWIN2_BASE;
17733dde7c95SVishal Kulkarni 		mem_win2_aperture = MEMWIN2_APERTURE;
1774de483253SVishal Kulkarni 	} else {
1775de483253SVishal Kulkarni 		/* For T5, only relative offset inside the PCIe BAR is passed */
1776de483253SVishal Kulkarni 		mem_win0_base = MEMWIN0_BASE;
1777de483253SVishal Kulkarni 		mem_win1_base = MEMWIN1_BASE;
1778de483253SVishal Kulkarni 		mem_win2_base = MEMWIN2_BASE_T5;
1779de483253SVishal Kulkarni 		mem_win2_aperture = MEMWIN2_APERTURE_T5;
1780de483253SVishal Kulkarni 	}
1781de483253SVishal Kulkarni 
178256b2bdd1SGireesh Nagabhushana 	t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 0),
1783de483253SVishal Kulkarni 	    mem_win0_base | V_BIR(0) |
178456b2bdd1SGireesh Nagabhushana 	    V_WINDOW(ilog2(MEMWIN0_APERTURE) - 10));
178556b2bdd1SGireesh Nagabhushana 
178656b2bdd1SGireesh Nagabhushana 	t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 1),
1787de483253SVishal Kulkarni 	    mem_win1_base | V_BIR(0) |
178856b2bdd1SGireesh Nagabhushana 	    V_WINDOW(ilog2(MEMWIN1_APERTURE) - 10));
178956b2bdd1SGireesh Nagabhushana 
179056b2bdd1SGireesh Nagabhushana 	t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 2),
1791de483253SVishal Kulkarni 	    mem_win2_base | V_BIR(0) |
1792de483253SVishal Kulkarni 	    V_WINDOW(ilog2(mem_win2_aperture) - 10));
1793de483253SVishal Kulkarni 
1794de483253SVishal Kulkarni 	/* flush */
1795de483253SVishal Kulkarni 	(void)t4_read_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 2));
179656b2bdd1SGireesh Nagabhushana }
179756b2bdd1SGireesh Nagabhushana 
1798de483253SVishal Kulkarni /*
1799de483253SVishal Kulkarni  * Positions the memory window such that it can be used to access the specified
1800de483253SVishal Kulkarni  * address in the chip's address space.  The return value is the offset of addr
1801de483253SVishal Kulkarni  * from the start of the window.
1802de483253SVishal Kulkarni  */
1803de483253SVishal Kulkarni uint32_t
position_memwin(struct adapter * sc,int n,uint32_t addr)1804de483253SVishal Kulkarni position_memwin(struct adapter *sc, int n, uint32_t addr)
1805de483253SVishal Kulkarni {
1806de483253SVishal Kulkarni 	uint32_t start, pf;
1807de483253SVishal Kulkarni 	uint32_t reg;
1808de483253SVishal Kulkarni 
1809de483253SVishal Kulkarni 	if (addr & 3) {
1810de483253SVishal Kulkarni 		cxgb_printf(sc->dip, CE_WARN,
1811de483253SVishal Kulkarni 		    "addr (0x%x) is not at a 4B boundary.\n", addr);
1812de483253SVishal Kulkarni 		return (EFAULT);
1813de483253SVishal Kulkarni 	}
1814de483253SVishal Kulkarni 
1815de483253SVishal Kulkarni 	if (is_t4(sc->params.chip)) {
1816de483253SVishal Kulkarni 		pf = 0;
1817de483253SVishal Kulkarni 		start = addr & ~0xf;    /* start must be 16B aligned */
1818de483253SVishal Kulkarni 	} else {
1819de483253SVishal Kulkarni 		pf = V_PFNUM(sc->pf);
1820de483253SVishal Kulkarni 		start = addr & ~0x7f;   /* start must be 128B aligned */
1821de483253SVishal Kulkarni 	}
1822de483253SVishal Kulkarni 	reg = PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, n);
1823de483253SVishal Kulkarni 
1824de483253SVishal Kulkarni 	t4_write_reg(sc, reg, start | pf);
1825de483253SVishal Kulkarni 	(void) t4_read_reg(sc, reg);
1826de483253SVishal Kulkarni 
1827de483253SVishal Kulkarni 	return (addr - start);
1828de483253SVishal Kulkarni }
182994c3dad2SToomas Soome 
1830de483253SVishal Kulkarni 
183156b2bdd1SGireesh Nagabhushana /*
183256b2bdd1SGireesh Nagabhushana  * Reads the named property and fills up the "data" array (which has at least
183356b2bdd1SGireesh Nagabhushana  * "count" elements).  We first try and lookup the property for our dev_t and
183456b2bdd1SGireesh Nagabhushana  * then retry with DDI_DEV_T_ANY if it's not found.
183556b2bdd1SGireesh Nagabhushana  *
183656b2bdd1SGireesh Nagabhushana  * Returns non-zero if the property was found and "data" has been updated.
183756b2bdd1SGireesh Nagabhushana  */
183856b2bdd1SGireesh Nagabhushana static int
prop_lookup_int_array(struct adapter * sc,char * name,int * data,uint_t count)183956b2bdd1SGireesh Nagabhushana prop_lookup_int_array(struct adapter *sc, char *name, int *data, uint_t count)
184056b2bdd1SGireesh Nagabhushana {
184156b2bdd1SGireesh Nagabhushana 	dev_info_t *dip = sc->dip;
184256b2bdd1SGireesh Nagabhushana 	dev_t dev = sc->dev;
184356b2bdd1SGireesh Nagabhushana 	int rc, *d;
184456b2bdd1SGireesh Nagabhushana 	uint_t i, n;
184556b2bdd1SGireesh Nagabhushana 
184656b2bdd1SGireesh Nagabhushana 	rc = ddi_prop_lookup_int_array(dev, dip, DDI_PROP_DONTPASS,
184756b2bdd1SGireesh Nagabhushana 	    name, &d, &n);
184856b2bdd1SGireesh Nagabhushana 	if (rc == DDI_PROP_SUCCESS)
184956b2bdd1SGireesh Nagabhushana 		goto found;
185056b2bdd1SGireesh Nagabhushana 
185156b2bdd1SGireesh Nagabhushana 	if (rc != DDI_PROP_NOT_FOUND) {
185256b2bdd1SGireesh Nagabhushana 		cxgb_printf(dip, CE_WARN,
185356b2bdd1SGireesh Nagabhushana 		    "failed to lookup property %s for minor %d: %d.",
185456b2bdd1SGireesh Nagabhushana 		    name, getminor(dev), rc);
185556b2bdd1SGireesh Nagabhushana 		return (0);
185656b2bdd1SGireesh Nagabhushana 	}
185756b2bdd1SGireesh Nagabhushana 
185856b2bdd1SGireesh Nagabhushana 	rc = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
185956b2bdd1SGireesh Nagabhushana 	    name, &d, &n);
186056b2bdd1SGireesh Nagabhushana 	if (rc == DDI_PROP_SUCCESS)
186156b2bdd1SGireesh Nagabhushana 		goto found;
186256b2bdd1SGireesh Nagabhushana 
186356b2bdd1SGireesh Nagabhushana 	if (rc != DDI_PROP_NOT_FOUND) {
186456b2bdd1SGireesh Nagabhushana 		cxgb_printf(dip, CE_WARN,
186556b2bdd1SGireesh Nagabhushana 		    "failed to lookup property %s: %d.", name, rc);
186656b2bdd1SGireesh Nagabhushana 		return (0);
186756b2bdd1SGireesh Nagabhushana 	}
186856b2bdd1SGireesh Nagabhushana 
186956b2bdd1SGireesh Nagabhushana 	return (0);
187056b2bdd1SGireesh Nagabhushana 
187156b2bdd1SGireesh Nagabhushana found:
187256b2bdd1SGireesh Nagabhushana 	if (n > count) {
187356b2bdd1SGireesh Nagabhushana 		cxgb_printf(dip, CE_NOTE,
187456b2bdd1SGireesh Nagabhushana 		    "property %s has too many elements (%d), ignoring extras",
187556b2bdd1SGireesh Nagabhushana 		    name, n);
187656b2bdd1SGireesh Nagabhushana 	}
187756b2bdd1SGireesh Nagabhushana 
187856b2bdd1SGireesh Nagabhushana 	for (i = 0; i < n && i < count; i++)
187956b2bdd1SGireesh Nagabhushana 		data[i] = d[i];
188056b2bdd1SGireesh Nagabhushana 	ddi_prop_free(d);
188156b2bdd1SGireesh Nagabhushana 
188256b2bdd1SGireesh Nagabhushana 	return (1);
188356b2bdd1SGireesh Nagabhushana }
188456b2bdd1SGireesh Nagabhushana 
188556b2bdd1SGireesh Nagabhushana static int
prop_lookup_int(struct adapter * sc,char * name,int defval)188656b2bdd1SGireesh Nagabhushana prop_lookup_int(struct adapter *sc, char *name, int defval)
188756b2bdd1SGireesh Nagabhushana {
188856b2bdd1SGireesh Nagabhushana 	int rc;
188956b2bdd1SGireesh Nagabhushana 
189056b2bdd1SGireesh Nagabhushana 	rc = ddi_prop_get_int(sc->dev, sc->dip, DDI_PROP_DONTPASS, name, -1);
189156b2bdd1SGireesh Nagabhushana 	if (rc != -1)
189256b2bdd1SGireesh Nagabhushana 		return (rc);
189356b2bdd1SGireesh Nagabhushana 
189456b2bdd1SGireesh Nagabhushana 	return (ddi_prop_get_int(DDI_DEV_T_ANY, sc->dip, DDI_PROP_DONTPASS,
189556b2bdd1SGireesh Nagabhushana 	    name, defval));
189656b2bdd1SGireesh Nagabhushana }
189756b2bdd1SGireesh Nagabhushana 
189856b2bdd1SGireesh Nagabhushana static int
init_driver_props(struct adapter * sc,struct driver_properties * p)189956b2bdd1SGireesh Nagabhushana init_driver_props(struct adapter *sc, struct driver_properties *p)
190056b2bdd1SGireesh Nagabhushana {
190156b2bdd1SGireesh Nagabhushana 	dev_t dev = sc->dev;
190256b2bdd1SGireesh Nagabhushana 	dev_info_t *dip = sc->dip;
190356b2bdd1SGireesh Nagabhushana 	int i, *data;
190456b2bdd1SGireesh Nagabhushana 	uint_t tmr[SGE_NTIMERS] = {5, 10, 20, 50, 100, 200};
190556b2bdd1SGireesh Nagabhushana 	uint_t cnt[SGE_NCOUNTERS] = {1, 8, 16, 32}; /* 63 max */
190656b2bdd1SGireesh Nagabhushana 
190756b2bdd1SGireesh Nagabhushana 	/*
190856b2bdd1SGireesh Nagabhushana 	 * Holdoff timer
190956b2bdd1SGireesh Nagabhushana 	 */
191056b2bdd1SGireesh Nagabhushana 	data = &p->timer_val[0];
191156b2bdd1SGireesh Nagabhushana 	for (i = 0; i < SGE_NTIMERS; i++)
191256b2bdd1SGireesh Nagabhushana 		data[i] = tmr[i];
191356b2bdd1SGireesh Nagabhushana 	(void) prop_lookup_int_array(sc, "holdoff-timer-values", data,
191456b2bdd1SGireesh Nagabhushana 	    SGE_NTIMERS);
191556b2bdd1SGireesh Nagabhushana 	for (i = 0; i < SGE_NTIMERS; i++) {
191656b2bdd1SGireesh Nagabhushana 		int limit = 200U;
191756b2bdd1SGireesh Nagabhushana 		if (data[i] > limit) {
191856b2bdd1SGireesh Nagabhushana 			cxgb_printf(dip, CE_WARN,
191956b2bdd1SGireesh Nagabhushana 			    "holdoff timer %d is too high (%d), lowered to %d.",
192056b2bdd1SGireesh Nagabhushana 			    i, data[i], limit);
192156b2bdd1SGireesh Nagabhushana 			data[i] = limit;
192256b2bdd1SGireesh Nagabhushana 		}
192356b2bdd1SGireesh Nagabhushana 	}
192456b2bdd1SGireesh Nagabhushana 	(void) ddi_prop_update_int_array(dev, dip, "holdoff-timer-values",
192556b2bdd1SGireesh Nagabhushana 	    data, SGE_NTIMERS);
192656b2bdd1SGireesh Nagabhushana 
192756b2bdd1SGireesh Nagabhushana 	/*
192856b2bdd1SGireesh Nagabhushana 	 * Holdoff packet counter
192956b2bdd1SGireesh Nagabhushana 	 */
193056b2bdd1SGireesh Nagabhushana 	data = &p->counter_val[0];
193156b2bdd1SGireesh Nagabhushana 	for (i = 0; i < SGE_NCOUNTERS; i++)
193256b2bdd1SGireesh Nagabhushana 		data[i] = cnt[i];
193356b2bdd1SGireesh Nagabhushana 	(void) prop_lookup_int_array(sc, "holdoff-pkt-counter-values", data,
193456b2bdd1SGireesh Nagabhushana 	    SGE_NCOUNTERS);
193556b2bdd1SGireesh Nagabhushana 	for (i = 0; i < SGE_NCOUNTERS; i++) {
193656b2bdd1SGireesh Nagabhushana 		int limit = M_THRESHOLD_0;
193756b2bdd1SGireesh Nagabhushana 		if (data[i] > limit) {
193856b2bdd1SGireesh Nagabhushana 			cxgb_printf(dip, CE_WARN,
193956b2bdd1SGireesh Nagabhushana 			    "holdoff pkt-counter %d is too high (%d), "
194056b2bdd1SGireesh Nagabhushana 			    "lowered to %d.", i, data[i], limit);
194156b2bdd1SGireesh Nagabhushana 			data[i] = limit;
194256b2bdd1SGireesh Nagabhushana 		}
194356b2bdd1SGireesh Nagabhushana 	}
194456b2bdd1SGireesh Nagabhushana 	(void) ddi_prop_update_int_array(dev, dip, "holdoff-pkt-counter-values",
194556b2bdd1SGireesh Nagabhushana 	    data, SGE_NCOUNTERS);
194656b2bdd1SGireesh Nagabhushana 
194756b2bdd1SGireesh Nagabhushana 	/*
194894c3dad2SToomas Soome 	 * Maximum # of tx and rx queues to use for each
19493dde7c95SVishal Kulkarni 	 * 100G, 40G, 25G, 10G and 1G port.
195056b2bdd1SGireesh Nagabhushana 	 */
195156b2bdd1SGireesh Nagabhushana 	p->max_ntxq_10g = prop_lookup_int(sc, "max-ntxq-10G-port", 8);
195256b2bdd1SGireesh Nagabhushana 	(void) ddi_prop_update_int(dev, dip, "max-ntxq-10G-port",
195356b2bdd1SGireesh Nagabhushana 	    p->max_ntxq_10g);
195456b2bdd1SGireesh Nagabhushana 
195556b2bdd1SGireesh Nagabhushana 	p->max_nrxq_10g = prop_lookup_int(sc, "max-nrxq-10G-port", 8);
195656b2bdd1SGireesh Nagabhushana 	(void) ddi_prop_update_int(dev, dip, "max-nrxq-10G-port",
195756b2bdd1SGireesh Nagabhushana 	    p->max_nrxq_10g);
195856b2bdd1SGireesh Nagabhushana 
195956b2bdd1SGireesh Nagabhushana 	p->max_ntxq_1g = prop_lookup_int(sc, "max-ntxq-1G-port", 2);
196056b2bdd1SGireesh Nagabhushana 	(void) ddi_prop_update_int(dev, dip, "max-ntxq-1G-port",
196156b2bdd1SGireesh Nagabhushana 	    p->max_ntxq_1g);
196256b2bdd1SGireesh Nagabhushana 
196356b2bdd1SGireesh Nagabhushana 	p->max_nrxq_1g = prop_lookup_int(sc, "max-nrxq-1G-port", 2);
196456b2bdd1SGireesh Nagabhushana 	(void) ddi_prop_update_int(dev, dip, "max-nrxq-1G-port",
196556b2bdd1SGireesh Nagabhushana 	    p->max_nrxq_1g);
196656b2bdd1SGireesh Nagabhushana 
19673dde7c95SVishal Kulkarni #ifdef TCP_OFFLOAD_ENABLE
196856b2bdd1SGireesh Nagabhushana 	p->max_nofldtxq_10g = prop_lookup_int(sc, "max-nofldtxq-10G-port", 8);
196956b2bdd1SGireesh Nagabhushana 	(void) ddi_prop_update_int(dev, dip, "max-ntxq-10G-port",
197056b2bdd1SGireesh Nagabhushana 	    p->max_nofldtxq_10g);
197156b2bdd1SGireesh Nagabhushana 
197256b2bdd1SGireesh Nagabhushana 	p->max_nofldrxq_10g = prop_lookup_int(sc, "max-nofldrxq-10G-port", 2);
197356b2bdd1SGireesh Nagabhushana 	(void) ddi_prop_update_int(dev, dip, "max-nrxq-10G-port",
197456b2bdd1SGireesh Nagabhushana 	    p->max_nofldrxq_10g);
197556b2bdd1SGireesh Nagabhushana 
197656b2bdd1SGireesh Nagabhushana 	p->max_nofldtxq_1g = prop_lookup_int(sc, "max-nofldtxq-1G-port", 2);
197756b2bdd1SGireesh Nagabhushana 	(void) ddi_prop_update_int(dev, dip, "max-ntxq-1G-port",
197856b2bdd1SGireesh Nagabhushana 	    p->max_nofldtxq_1g);
197956b2bdd1SGireesh Nagabhushana 
198056b2bdd1SGireesh Nagabhushana 	p->max_nofldrxq_1g = prop_lookup_int(sc, "max-nofldrxq-1G-port", 1);
198156b2bdd1SGireesh Nagabhushana 	(void) ddi_prop_update_int(dev, dip, "max-nrxq-1G-port",
198256b2bdd1SGireesh Nagabhushana 	    p->max_nofldrxq_1g);
198356b2bdd1SGireesh Nagabhushana #endif
198456b2bdd1SGireesh Nagabhushana 
198556b2bdd1SGireesh Nagabhushana 	/*
198656b2bdd1SGireesh Nagabhushana 	 * Holdoff parameters for 10G and 1G ports.
198756b2bdd1SGireesh Nagabhushana 	 */
198856b2bdd1SGireesh Nagabhushana 	p->tmr_idx_10g = prop_lookup_int(sc, "holdoff-timer-idx-10G", 0);
198956b2bdd1SGireesh Nagabhushana 	(void) ddi_prop_update_int(dev, dip, "holdoff-timer-idx-10G",
199056b2bdd1SGireesh Nagabhushana 	    p->tmr_idx_10g);
199156b2bdd1SGireesh Nagabhushana 
199256b2bdd1SGireesh Nagabhushana 	p->pktc_idx_10g = prop_lookup_int(sc, "holdoff-pktc-idx-10G", 2);
199356b2bdd1SGireesh Nagabhushana 	(void) ddi_prop_update_int(dev, dip, "holdoff-pktc-idx-10G",
199456b2bdd1SGireesh Nagabhushana 	    p->pktc_idx_10g);
199556b2bdd1SGireesh Nagabhushana 
199656b2bdd1SGireesh Nagabhushana 	p->tmr_idx_1g = prop_lookup_int(sc, "holdoff-timer-idx-1G", 0);
199756b2bdd1SGireesh Nagabhushana 	(void) ddi_prop_update_int(dev, dip, "holdoff-timer-idx-1G",
199856b2bdd1SGireesh Nagabhushana 	    p->tmr_idx_1g);
199956b2bdd1SGireesh Nagabhushana 
200056b2bdd1SGireesh Nagabhushana 	p->pktc_idx_1g = prop_lookup_int(sc, "holdoff-pktc-idx-1G", 2);
200156b2bdd1SGireesh Nagabhushana 	(void) ddi_prop_update_int(dev, dip, "holdoff-pktc-idx-1G",
200256b2bdd1SGireesh Nagabhushana 	    p->pktc_idx_1g);
200356b2bdd1SGireesh Nagabhushana 
200456b2bdd1SGireesh Nagabhushana 	/*
200556b2bdd1SGireesh Nagabhushana 	 * Size (number of entries) of each tx and rx queue.
200656b2bdd1SGireesh Nagabhushana 	 */
200756b2bdd1SGireesh Nagabhushana 	i = prop_lookup_int(sc, "qsize-txq", TX_EQ_QSIZE);
200856b2bdd1SGireesh Nagabhushana 	p->qsize_txq = max(i, 128);
200956b2bdd1SGireesh Nagabhushana 	if (p->qsize_txq != i) {
201056b2bdd1SGireesh Nagabhushana 		cxgb_printf(dip, CE_WARN,
201156b2bdd1SGireesh Nagabhushana 		    "using %d instead of %d as the tx queue size",
201256b2bdd1SGireesh Nagabhushana 		    p->qsize_txq, i);
201356b2bdd1SGireesh Nagabhushana 	}
201456b2bdd1SGireesh Nagabhushana 	(void) ddi_prop_update_int(dev, dip, "qsize-txq", p->qsize_txq);
201556b2bdd1SGireesh Nagabhushana 
201656b2bdd1SGireesh Nagabhushana 	i = prop_lookup_int(sc, "qsize-rxq", RX_IQ_QSIZE);
201756b2bdd1SGireesh Nagabhushana 	p->qsize_rxq = max(i, 128);
201856b2bdd1SGireesh Nagabhushana 	while (p->qsize_rxq & 7)
201956b2bdd1SGireesh Nagabhushana 		p->qsize_rxq--;
202056b2bdd1SGireesh Nagabhushana 	if (p->qsize_rxq != i) {
202156b2bdd1SGireesh Nagabhushana 		cxgb_printf(dip, CE_WARN,
202256b2bdd1SGireesh Nagabhushana 		    "using %d instead of %d as the rx queue size",
202356b2bdd1SGireesh Nagabhushana 		    p->qsize_rxq, i);
202456b2bdd1SGireesh Nagabhushana 	}
202556b2bdd1SGireesh Nagabhushana 	(void) ddi_prop_update_int(dev, dip, "qsize-rxq", p->qsize_rxq);
202656b2bdd1SGireesh Nagabhushana 
202756b2bdd1SGireesh Nagabhushana 	/*
202856b2bdd1SGireesh Nagabhushana 	 * Interrupt types allowed.
202956b2bdd1SGireesh Nagabhushana 	 * Bits 0, 1, 2 = INTx, MSI, MSI-X respectively.  See sys/ddi_intr.h
203056b2bdd1SGireesh Nagabhushana 	 */
203156b2bdd1SGireesh Nagabhushana 	p->intr_types = prop_lookup_int(sc, "interrupt-types",
203256b2bdd1SGireesh Nagabhushana 	    DDI_INTR_TYPE_MSIX | DDI_INTR_TYPE_MSI | DDI_INTR_TYPE_FIXED);
203356b2bdd1SGireesh Nagabhushana 	(void) ddi_prop_update_int(dev, dip, "interrupt-types", p->intr_types);
203456b2bdd1SGireesh Nagabhushana 
203556b2bdd1SGireesh Nagabhushana 	/*
203656b2bdd1SGireesh Nagabhushana 	 * Forwarded interrupt queues.  Create this property to force the driver
203756b2bdd1SGireesh Nagabhushana 	 * to use forwarded interrupt queues.
203856b2bdd1SGireesh Nagabhushana 	 */
203956b2bdd1SGireesh Nagabhushana 	if (ddi_prop_exists(dev, dip, DDI_PROP_DONTPASS,
204056b2bdd1SGireesh Nagabhushana 	    "interrupt-forwarding") != 0 ||
204156b2bdd1SGireesh Nagabhushana 	    ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
204256b2bdd1SGireesh Nagabhushana 	    "interrupt-forwarding") != 0) {
204356b2bdd1SGireesh Nagabhushana 		UNIMPLEMENTED();
204456b2bdd1SGireesh Nagabhushana 		(void) ddi_prop_create(dev, dip, DDI_PROP_CANSLEEP,
204556b2bdd1SGireesh Nagabhushana 		    "interrupt-forwarding", NULL, 0);
204656b2bdd1SGireesh Nagabhushana 	}
204756b2bdd1SGireesh Nagabhushana 
2048de483253SVishal Kulkarni 	/*
2049de483253SVishal Kulkarni 	 * Write combining
2050de483253SVishal Kulkarni 	 * 0 to disable, 1 to enable
2051de483253SVishal Kulkarni 	 */
2052de483253SVishal Kulkarni 	p->wc = prop_lookup_int(sc, "write-combine", 1);
2053de483253SVishal Kulkarni 	cxgb_printf(dip, CE_WARN, "write-combine: using of %d", p->wc);
2054de483253SVishal Kulkarni 	if (p->wc != 0 && p->wc != 1) {
2055de483253SVishal Kulkarni 		cxgb_printf(dip, CE_WARN,
2056de483253SVishal Kulkarni 		    "write-combine: using 1 instead of %d", p->wc);
2057de483253SVishal Kulkarni 		p->wc = 1;
2058de483253SVishal Kulkarni 	}
2059de483253SVishal Kulkarni 	(void) ddi_prop_update_int(dev, dip, "write-combine", p->wc);
2060de483253SVishal Kulkarni 
20613dde7c95SVishal Kulkarni 	p->t4_fw_install = prop_lookup_int(sc, "t4_fw_install", 1);
20623dde7c95SVishal Kulkarni 	if (p->t4_fw_install != 0 && p->t4_fw_install != 2)
20633dde7c95SVishal Kulkarni 		p->t4_fw_install = 1;
20643dde7c95SVishal Kulkarni 	(void) ddi_prop_update_int(dev, dip, "t4_fw_install", p->t4_fw_install);
20653dde7c95SVishal Kulkarni 
20663dde7c95SVishal Kulkarni 	/* Multiple Rings */
20673dde7c95SVishal Kulkarni 	p->multi_rings = prop_lookup_int(sc, "multi-rings", 1);
20683dde7c95SVishal Kulkarni 	if (p->multi_rings != 0 && p->multi_rings != 1) {
20693dde7c95SVishal Kulkarni 		cxgb_printf(dip, CE_NOTE,
20703dde7c95SVishal Kulkarni 			   "multi-rings: using value 1 instead of %d", p->multi_rings);
20713dde7c95SVishal Kulkarni 		p->multi_rings = 1;
20723dde7c95SVishal Kulkarni 	}
20733dde7c95SVishal Kulkarni 
20743dde7c95SVishal Kulkarni 	(void) ddi_prop_update_int(dev, dip, "multi-rings", p->multi_rings);
20753dde7c95SVishal Kulkarni 
207656b2bdd1SGireesh Nagabhushana 	return (0);
207756b2bdd1SGireesh Nagabhushana }
207856b2bdd1SGireesh Nagabhushana 
207956b2bdd1SGireesh Nagabhushana static int
remove_extra_props(struct adapter * sc,int n10g,int n1g)208056b2bdd1SGireesh Nagabhushana remove_extra_props(struct adapter *sc, int n10g, int n1g)
208156b2bdd1SGireesh Nagabhushana {
208256b2bdd1SGireesh Nagabhushana 	if (n10g == 0) {
208356b2bdd1SGireesh Nagabhushana 		(void) ddi_prop_remove(sc->dev, sc->dip, "max-ntxq-10G-port");
208456b2bdd1SGireesh Nagabhushana 		(void) ddi_prop_remove(sc->dev, sc->dip, "max-nrxq-10G-port");
208556b2bdd1SGireesh Nagabhushana 		(void) ddi_prop_remove(sc->dev, sc->dip,
208656b2bdd1SGireesh Nagabhushana 		    "holdoff-timer-idx-10G");
208756b2bdd1SGireesh Nagabhushana 		(void) ddi_prop_remove(sc->dev, sc->dip,
208856b2bdd1SGireesh Nagabhushana 		    "holdoff-pktc-idx-10G");
208956b2bdd1SGireesh Nagabhushana 	}
209056b2bdd1SGireesh Nagabhushana 
209156b2bdd1SGireesh Nagabhushana 	if (n1g == 0) {
209256b2bdd1SGireesh Nagabhushana 		(void) ddi_prop_remove(sc->dev, sc->dip, "max-ntxq-1G-port");
209356b2bdd1SGireesh Nagabhushana 		(void) ddi_prop_remove(sc->dev, sc->dip, "max-nrxq-1G-port");
209456b2bdd1SGireesh Nagabhushana 		(void) ddi_prop_remove(sc->dev, sc->dip,
209556b2bdd1SGireesh Nagabhushana 		    "holdoff-timer-idx-1G");
209656b2bdd1SGireesh Nagabhushana 		(void) ddi_prop_remove(sc->dev, sc->dip, "holdoff-pktc-idx-1G");
209756b2bdd1SGireesh Nagabhushana 	}
209856b2bdd1SGireesh Nagabhushana 
209956b2bdd1SGireesh Nagabhushana 	return (0);
210056b2bdd1SGireesh Nagabhushana }
210156b2bdd1SGireesh Nagabhushana 
210256b2bdd1SGireesh Nagabhushana static int
cfg_itype_and_nqueues(struct adapter * sc,int n10g,int n1g,struct intrs_and_queues * iaq)210356b2bdd1SGireesh Nagabhushana cfg_itype_and_nqueues(struct adapter *sc, int n10g, int n1g,
210456b2bdd1SGireesh Nagabhushana     struct intrs_and_queues *iaq)
210556b2bdd1SGireesh Nagabhushana {
210656b2bdd1SGireesh Nagabhushana 	struct driver_properties *p = &sc->props;
210777ac03cbSRahul Lakkireddy 	int rc, itype, itypes, navail, nc, n;
210877ac03cbSRahul Lakkireddy 	int pfres_rxq, pfres_txq, pfresq;
210956b2bdd1SGireesh Nagabhushana 
211056b2bdd1SGireesh Nagabhushana 	bzero(iaq, sizeof (*iaq));
211156b2bdd1SGireesh Nagabhushana 	nc = ncpus;	/* our snapshot of the number of CPUs */
211256b2bdd1SGireesh Nagabhushana 	iaq->ntxq10g = min(nc, p->max_ntxq_10g);
211356b2bdd1SGireesh Nagabhushana 	iaq->ntxq1g = min(nc, p->max_ntxq_1g);
211477ac03cbSRahul Lakkireddy 	iaq->nrxq10g = min(nc, p->max_nrxq_10g);
211577ac03cbSRahul Lakkireddy 	iaq->nrxq1g = min(nc, p->max_nrxq_1g);
21163dde7c95SVishal Kulkarni #ifdef TCP_OFFLOAD_ENABLE
211756b2bdd1SGireesh Nagabhushana 	iaq->nofldtxq10g = min(nc, p->max_nofldtxq_10g);
211856b2bdd1SGireesh Nagabhushana 	iaq->nofldtxq1g = min(nc, p->max_nofldtxq_1g);
211977ac03cbSRahul Lakkireddy 	iaq->nofldrxq10g = min(nc, p->max_nofldrxq_10g);
212077ac03cbSRahul Lakkireddy 	iaq->nofldrxq1g = min(nc, p->max_nofldrxq_1g);
212177ac03cbSRahul Lakkireddy #endif
212277ac03cbSRahul Lakkireddy 
212377ac03cbSRahul Lakkireddy 	pfres_rxq = iaq->nrxq10g * n10g + iaq->nrxq1g * n1g;
212477ac03cbSRahul Lakkireddy 	pfres_txq = iaq->ntxq10g * n10g + iaq->ntxq1g * n1g;
212577ac03cbSRahul Lakkireddy #ifdef TCP_OFFLOAD_ENABLE
212677ac03cbSRahul Lakkireddy 	pfres_rxq += iaq->nofldrxq10g * n10g + iaq->nofldrxq1g * n1g;
212777ac03cbSRahul Lakkireddy 	pfres_txq += iaq->nofldtxq10g * n10g + iaq->nofldtxq1g * n1g;
212877ac03cbSRahul Lakkireddy #endif
212977ac03cbSRahul Lakkireddy 
213077ac03cbSRahul Lakkireddy 	/* If current configuration of max number of Rxqs and Txqs exceed
213177ac03cbSRahul Lakkireddy 	 * the max available for all the ports under this PF, then shrink
213277ac03cbSRahul Lakkireddy 	 * the queues to max available. Reduce them in a way that each
213377ac03cbSRahul Lakkireddy 	 * port under this PF has equally distributed number of queues.
213477ac03cbSRahul Lakkireddy 	 * Must guarantee at least 1 queue for each port for both NIC
213577ac03cbSRahul Lakkireddy 	 * and Offload queues.
213677ac03cbSRahul Lakkireddy 	 *
213777ac03cbSRahul Lakkireddy 	 * neq - fixed max number of Egress queues on Tx path and Free List
213877ac03cbSRahul Lakkireddy 	 * queues that hold Rx payload data on Rx path. Half are reserved
213977ac03cbSRahul Lakkireddy 	 * for Egress queues and the other half for Free List queues.
214077ac03cbSRahul Lakkireddy 	 * Hence, the division by 2.
214177ac03cbSRahul Lakkireddy 	 *
214277ac03cbSRahul Lakkireddy 	 * niqflint - max number of Ingress queues with interrupts on Rx
214377ac03cbSRahul Lakkireddy 	 * path to receive completions that indicate Rx payload has been
214477ac03cbSRahul Lakkireddy 	 * posted in its associated Free List queue. Also handles Tx
214577ac03cbSRahul Lakkireddy 	 * completions for packets successfully transmitted on Tx path.
214677ac03cbSRahul Lakkireddy 	 *
214777ac03cbSRahul Lakkireddy 	 * nethctrl - max number of Egress queues only for Tx path. This
214877ac03cbSRahul Lakkireddy 	 * number is usually half of neq. However, if it became less than
214977ac03cbSRahul Lakkireddy 	 * neq due to lack of resources based on firmware configuration,
215077ac03cbSRahul Lakkireddy 	 * then take the lower value.
215177ac03cbSRahul Lakkireddy 	 */
215277ac03cbSRahul Lakkireddy 	while (pfres_rxq >
215377ac03cbSRahul Lakkireddy 	       min(sc->params.pfres.neq / 2, sc->params.pfres.niqflint)) {
215477ac03cbSRahul Lakkireddy 		pfresq = pfres_rxq;
215577ac03cbSRahul Lakkireddy 
215677ac03cbSRahul Lakkireddy 		if (iaq->nrxq10g > 1) {
215777ac03cbSRahul Lakkireddy 			iaq->nrxq10g--;
215877ac03cbSRahul Lakkireddy 			pfres_rxq -= n10g;
215977ac03cbSRahul Lakkireddy 		}
216077ac03cbSRahul Lakkireddy 
216177ac03cbSRahul Lakkireddy 		if (iaq->nrxq1g > 1) {
216277ac03cbSRahul Lakkireddy 			iaq->nrxq1g--;
216377ac03cbSRahul Lakkireddy 			pfres_rxq -= n1g;
216477ac03cbSRahul Lakkireddy 		}
216577ac03cbSRahul Lakkireddy 
216677ac03cbSRahul Lakkireddy #ifdef TCP_OFFLOAD_ENABLE
216777ac03cbSRahul Lakkireddy 		if (iaq->nofldrxq10g > 1) {
216877ac03cbSRahul Lakkireddy 			iaq->nofldrxq10g--;
216977ac03cbSRahul Lakkireddy 			pfres_rxq -= n10g;
217077ac03cbSRahul Lakkireddy 		}
217177ac03cbSRahul Lakkireddy 
217277ac03cbSRahul Lakkireddy 		if (iaq->nofldrxq1g > 1) {
217377ac03cbSRahul Lakkireddy 			iaq->nofldrxq1g--;
217477ac03cbSRahul Lakkireddy 			pfres_rxq -= n1g;
217577ac03cbSRahul Lakkireddy 		}
217656b2bdd1SGireesh Nagabhushana #endif
217756b2bdd1SGireesh Nagabhushana 
217877ac03cbSRahul Lakkireddy 		/* Break if nothing changed */
217977ac03cbSRahul Lakkireddy 		if (pfresq == pfres_rxq)
218077ac03cbSRahul Lakkireddy 			break;
218177ac03cbSRahul Lakkireddy 	}
218277ac03cbSRahul Lakkireddy 
218377ac03cbSRahul Lakkireddy 	while (pfres_txq >
218477ac03cbSRahul Lakkireddy 	       min(sc->params.pfres.neq / 2, sc->params.pfres.nethctrl)) {
218577ac03cbSRahul Lakkireddy 		pfresq = pfres_txq;
218677ac03cbSRahul Lakkireddy 
218777ac03cbSRahul Lakkireddy 		if (iaq->ntxq10g > 1) {
218877ac03cbSRahul Lakkireddy 			iaq->ntxq10g--;
218977ac03cbSRahul Lakkireddy 			pfres_txq -= n10g;
219077ac03cbSRahul Lakkireddy 		}
219177ac03cbSRahul Lakkireddy 
219277ac03cbSRahul Lakkireddy 		if (iaq->ntxq1g > 1) {
219377ac03cbSRahul Lakkireddy 			iaq->ntxq1g--;
219477ac03cbSRahul Lakkireddy 			pfres_txq -= n1g;
219577ac03cbSRahul Lakkireddy 		}
219677ac03cbSRahul Lakkireddy 
219777ac03cbSRahul Lakkireddy #ifdef TCP_OFFLOAD_ENABLE
219877ac03cbSRahul Lakkireddy 		if (iaq->nofldtxq10g > 1) {
219977ac03cbSRahul Lakkireddy 			iaq->nofldtxq10g--;
220077ac03cbSRahul Lakkireddy 			pfres_txq -= n10g;
220177ac03cbSRahul Lakkireddy 		}
220277ac03cbSRahul Lakkireddy 
220377ac03cbSRahul Lakkireddy 		if (iaq->nofldtxq1g > 1) {
220477ac03cbSRahul Lakkireddy 			iaq->nofldtxq1g--;
220577ac03cbSRahul Lakkireddy 			pfres_txq -= n1g;
220677ac03cbSRahul Lakkireddy 		}
220777ac03cbSRahul Lakkireddy #endif
220877ac03cbSRahul Lakkireddy 
220977ac03cbSRahul Lakkireddy 		/* Break if nothing changed */
221077ac03cbSRahul Lakkireddy 		if (pfresq == pfres_txq)
221177ac03cbSRahul Lakkireddy 			break;
221277ac03cbSRahul Lakkireddy 	}
221377ac03cbSRahul Lakkireddy 
221456b2bdd1SGireesh Nagabhushana 	rc = ddi_intr_get_supported_types(sc->dip, &itypes);
221556b2bdd1SGireesh Nagabhushana 	if (rc != DDI_SUCCESS) {
221656b2bdd1SGireesh Nagabhushana 		cxgb_printf(sc->dip, CE_WARN,
221756b2bdd1SGireesh Nagabhushana 		    "failed to determine supported interrupt types: %d", rc);
221856b2bdd1SGireesh Nagabhushana 		return (rc);
221956b2bdd1SGireesh Nagabhushana 	}
222056b2bdd1SGireesh Nagabhushana 
222156b2bdd1SGireesh Nagabhushana 	for (itype = DDI_INTR_TYPE_MSIX; itype; itype >>= 1) {
222256b2bdd1SGireesh Nagabhushana 		ASSERT(itype == DDI_INTR_TYPE_MSIX ||
222356b2bdd1SGireesh Nagabhushana 		    itype == DDI_INTR_TYPE_MSI ||
222456b2bdd1SGireesh Nagabhushana 		    itype == DDI_INTR_TYPE_FIXED);
222556b2bdd1SGireesh Nagabhushana 
222656b2bdd1SGireesh Nagabhushana 		if ((itype & itypes & p->intr_types) == 0)
222756b2bdd1SGireesh Nagabhushana 			continue;	/* not supported or not allowed */
222856b2bdd1SGireesh Nagabhushana 
222956b2bdd1SGireesh Nagabhushana 		navail = 0;
223056b2bdd1SGireesh Nagabhushana 		rc = ddi_intr_get_navail(sc->dip, itype, &navail);
223156b2bdd1SGireesh Nagabhushana 		if (rc != DDI_SUCCESS || navail == 0) {
223256b2bdd1SGireesh Nagabhushana 			cxgb_printf(sc->dip, CE_WARN,
223356b2bdd1SGireesh Nagabhushana 			    "failed to get # of interrupts for type %d: %d",
223456b2bdd1SGireesh Nagabhushana 			    itype, rc);
223556b2bdd1SGireesh Nagabhushana 			continue;	/* carry on */
223656b2bdd1SGireesh Nagabhushana 		}
223756b2bdd1SGireesh Nagabhushana 
223856b2bdd1SGireesh Nagabhushana 		iaq->intr_type = itype;
223956b2bdd1SGireesh Nagabhushana 		if (navail == 0)
224056b2bdd1SGireesh Nagabhushana 			continue;
224156b2bdd1SGireesh Nagabhushana 
224256b2bdd1SGireesh Nagabhushana 		/*
224356b2bdd1SGireesh Nagabhushana 		 * Best option: an interrupt vector for errors, one for the
224456b2bdd1SGireesh Nagabhushana 		 * firmware event queue, and one each for each rxq (NIC as well
224556b2bdd1SGireesh Nagabhushana 		 * as offload).
224656b2bdd1SGireesh Nagabhushana 		 */
224756b2bdd1SGireesh Nagabhushana 		iaq->nirq = T4_EXTRA_INTR;
224877ac03cbSRahul Lakkireddy 		iaq->nirq += n10g * iaq->nrxq10g;
224977ac03cbSRahul Lakkireddy 		iaq->nirq += n1g * iaq->nrxq1g;
225077ac03cbSRahul Lakkireddy #ifdef TCP_OFFLOAD_ENABLE
225177ac03cbSRahul Lakkireddy 		iaq->nirq += n10g * iaq->nofldrxq10g;
225277ac03cbSRahul Lakkireddy 		iaq->nirq += n1g * iaq->nofldrxq1g;
225377ac03cbSRahul Lakkireddy #endif
225456b2bdd1SGireesh Nagabhushana 
225556b2bdd1SGireesh Nagabhushana 		if (iaq->nirq <= navail &&
225656b2bdd1SGireesh Nagabhushana 		    (itype != DDI_INTR_TYPE_MSI || ISP2(iaq->nirq))) {
225756b2bdd1SGireesh Nagabhushana 			iaq->intr_fwd = 0;
225856b2bdd1SGireesh Nagabhushana 			goto allocate;
225956b2bdd1SGireesh Nagabhushana 		}
226056b2bdd1SGireesh Nagabhushana 
226156b2bdd1SGireesh Nagabhushana 		/*
226256b2bdd1SGireesh Nagabhushana 		 * Second best option: an interrupt vector for errors, one for
226356b2bdd1SGireesh Nagabhushana 		 * the firmware event queue, and one each for either NIC or
226456b2bdd1SGireesh Nagabhushana 		 * offload rxq's.
226556b2bdd1SGireesh Nagabhushana 		 */
226656b2bdd1SGireesh Nagabhushana 		iaq->nirq = T4_EXTRA_INTR;
226777ac03cbSRahul Lakkireddy #ifdef TCP_OFFLOAD_ENABLE
226877ac03cbSRahul Lakkireddy 		iaq->nirq += n10g * max(iaq->nrxq10g, iaq->nofldrxq10g);
226977ac03cbSRahul Lakkireddy 		iaq->nirq += n1g * max(iaq->nrxq1g, iaq->nofldrxq1g);
227077ac03cbSRahul Lakkireddy #else
227177ac03cbSRahul Lakkireddy 		iaq->nirq += n10g * iaq->nrxq10g;
227277ac03cbSRahul Lakkireddy 		iaq->nirq += n1g * iaq->nrxq1g;
227377ac03cbSRahul Lakkireddy #endif
227456b2bdd1SGireesh Nagabhushana 		if (iaq->nirq <= navail &&
227556b2bdd1SGireesh Nagabhushana 		    (itype != DDI_INTR_TYPE_MSI || ISP2(iaq->nirq))) {
227656b2bdd1SGireesh Nagabhushana 			iaq->intr_fwd = 1;
227756b2bdd1SGireesh Nagabhushana 			goto allocate;
227856b2bdd1SGireesh Nagabhushana 		}
227956b2bdd1SGireesh Nagabhushana 
228056b2bdd1SGireesh Nagabhushana 		/*
228156b2bdd1SGireesh Nagabhushana 		 * Next best option: an interrupt vector for errors, one for the
228256b2bdd1SGireesh Nagabhushana 		 * firmware event queue, and at least one per port.  At this
228356b2bdd1SGireesh Nagabhushana 		 * point we know we'll have to downsize nrxq or nofldrxq to fit
228456b2bdd1SGireesh Nagabhushana 		 * what's available to us.
228556b2bdd1SGireesh Nagabhushana 		 */
228656b2bdd1SGireesh Nagabhushana 		iaq->nirq = T4_EXTRA_INTR;
228756b2bdd1SGireesh Nagabhushana 		iaq->nirq += n10g + n1g;
228856b2bdd1SGireesh Nagabhushana 		if (iaq->nirq <= navail) {
228956b2bdd1SGireesh Nagabhushana 			int leftover = navail - iaq->nirq;
229056b2bdd1SGireesh Nagabhushana 
229156b2bdd1SGireesh Nagabhushana 			if (n10g > 0) {
229277ac03cbSRahul Lakkireddy 				int target = iaq->nrxq10g;
229356b2bdd1SGireesh Nagabhushana 
229477ac03cbSRahul Lakkireddy #ifdef TCP_OFFLOAD_ENABLE
229577ac03cbSRahul Lakkireddy 				target = max(target, iaq->nofldrxq10g);
229677ac03cbSRahul Lakkireddy #endif
229756b2bdd1SGireesh Nagabhushana 				n = 1;
229856b2bdd1SGireesh Nagabhushana 				while (n < target && leftover >= n10g) {
229956b2bdd1SGireesh Nagabhushana 					leftover -= n10g;
230056b2bdd1SGireesh Nagabhushana 					iaq->nirq += n10g;
230156b2bdd1SGireesh Nagabhushana 					n++;
230256b2bdd1SGireesh Nagabhushana 				}
230377ac03cbSRahul Lakkireddy 				iaq->nrxq10g = min(n, iaq->nrxq10g);
23043dde7c95SVishal Kulkarni #ifdef TCP_OFFLOAD_ENABLE
230577ac03cbSRahul Lakkireddy 				iaq->nofldrxq10g = min(n, iaq->nofldrxq10g);
230656b2bdd1SGireesh Nagabhushana #endif
230756b2bdd1SGireesh Nagabhushana 			}
230856b2bdd1SGireesh Nagabhushana 
230956b2bdd1SGireesh Nagabhushana 			if (n1g > 0) {
231077ac03cbSRahul Lakkireddy 				int target = iaq->nrxq1g;
231156b2bdd1SGireesh Nagabhushana 
231277ac03cbSRahul Lakkireddy #ifdef TCP_OFFLOAD_ENABLE
231377ac03cbSRahul Lakkireddy 				target = max(target, iaq->nofldrxq1g);
231477ac03cbSRahul Lakkireddy #endif
231556b2bdd1SGireesh Nagabhushana 				n = 1;
231656b2bdd1SGireesh Nagabhushana 				while (n < target && leftover >= n1g) {
231756b2bdd1SGireesh Nagabhushana 					leftover -= n1g;
231856b2bdd1SGireesh Nagabhushana 					iaq->nirq += n1g;
231956b2bdd1SGireesh Nagabhushana 					n++;
232056b2bdd1SGireesh Nagabhushana 				}
232177ac03cbSRahul Lakkireddy 				iaq->nrxq1g = min(n, iaq->nrxq1g);
23223dde7c95SVishal Kulkarni #ifdef TCP_OFFLOAD_ENABLE
232377ac03cbSRahul Lakkireddy 				iaq->nofldrxq1g = min(n, iaq->nofldrxq1g);
232456b2bdd1SGireesh Nagabhushana #endif
232556b2bdd1SGireesh Nagabhushana 			}
232656b2bdd1SGireesh Nagabhushana 
23273dde7c95SVishal Kulkarni 			/* We have arrived at a minimum value required to enable
23283dde7c95SVishal Kulkarni 			 * per queue irq(either NIC or offload). Thus for non-
23293dde7c95SVishal Kulkarni 			 * offload case, we will get a vector per queue, while
23303dde7c95SVishal Kulkarni 			 * offload case, we will get a vector per offload/NIC q.
23313dde7c95SVishal Kulkarni 			 * Hence enable Interrupt forwarding only for offload
23323dde7c95SVishal Kulkarni 			 * case.
23333dde7c95SVishal Kulkarni 			 */
23343dde7c95SVishal Kulkarni #ifdef TCP_OFFLOAD_ENABLE
233556b2bdd1SGireesh Nagabhushana 			if (itype != DDI_INTR_TYPE_MSI || ISP2(iaq->nirq)) {
233656b2bdd1SGireesh Nagabhushana 				iaq->intr_fwd = 1;
23373dde7c95SVishal Kulkarni #else
23383dde7c95SVishal Kulkarni 			if (itype != DDI_INTR_TYPE_MSI) {
23393dde7c95SVishal Kulkarni #endif
234056b2bdd1SGireesh Nagabhushana 				goto allocate;
234156b2bdd1SGireesh Nagabhushana 			}
234256b2bdd1SGireesh Nagabhushana 		}
234356b2bdd1SGireesh Nagabhushana 
234456b2bdd1SGireesh Nagabhushana 		/*
234556b2bdd1SGireesh Nagabhushana 		 * Least desirable option: one interrupt vector for everything.
234656b2bdd1SGireesh Nagabhushana 		 */
234756b2bdd1SGireesh Nagabhushana 		iaq->nirq = iaq->nrxq10g = iaq->nrxq1g = 1;
23483dde7c95SVishal Kulkarni #ifdef TCP_OFFLOAD_ENABLE
234956b2bdd1SGireesh Nagabhushana 		iaq->nofldrxq10g = iaq->nofldrxq1g = 1;
235056b2bdd1SGireesh Nagabhushana #endif
235156b2bdd1SGireesh Nagabhushana 		iaq->intr_fwd = 1;
235256b2bdd1SGireesh Nagabhushana 
235356b2bdd1SGireesh Nagabhushana allocate:
235456b2bdd1SGireesh Nagabhushana 		return (0);
235556b2bdd1SGireesh Nagabhushana 	}
235656b2bdd1SGireesh Nagabhushana 
235756b2bdd1SGireesh Nagabhushana 	cxgb_printf(sc->dip, CE_WARN,
235856b2bdd1SGireesh Nagabhushana 	    "failed to find a usable interrupt type.  supported=%d, allowed=%d",
235956b2bdd1SGireesh Nagabhushana 	    itypes, p->intr_types);
236056b2bdd1SGireesh Nagabhushana 	return (DDI_FAILURE);
236156b2bdd1SGireesh Nagabhushana }
236256b2bdd1SGireesh Nagabhushana 
236356b2bdd1SGireesh Nagabhushana static int
236456b2bdd1SGireesh Nagabhushana add_child_node(struct adapter *sc, int idx)
236556b2bdd1SGireesh Nagabhushana {
236656b2bdd1SGireesh Nagabhushana 	int rc;
236756b2bdd1SGireesh Nagabhushana 	struct port_info *pi;
236856b2bdd1SGireesh Nagabhushana 
236956b2bdd1SGireesh Nagabhushana 	if (idx < 0 || idx >= sc->params.nports)
237056b2bdd1SGireesh Nagabhushana 		return (EINVAL);
237156b2bdd1SGireesh Nagabhushana 
237256b2bdd1SGireesh Nagabhushana 	pi = sc->port[idx];
237356b2bdd1SGireesh Nagabhushana 	if (pi == NULL)
237456b2bdd1SGireesh Nagabhushana 		return (ENODEV);	/* t4_port_init failed earlier */
237556b2bdd1SGireesh Nagabhushana 
237656b2bdd1SGireesh Nagabhushana 	PORT_LOCK(pi);
237756b2bdd1SGireesh Nagabhushana 	if (pi->dip != NULL) {
237856b2bdd1SGireesh Nagabhushana 		rc = 0;		/* EEXIST really, but then bus_config fails */
237956b2bdd1SGireesh Nagabhushana 		goto done;
238056b2bdd1SGireesh Nagabhushana 	}
238156b2bdd1SGireesh Nagabhushana 
238256b2bdd1SGireesh Nagabhushana 	rc = ndi_devi_alloc(sc->dip, T4_PORT_NAME, DEVI_SID_NODEID, &pi->dip);
238356b2bdd1SGireesh Nagabhushana 	if (rc != DDI_SUCCESS || pi->dip == NULL) {
238456b2bdd1SGireesh Nagabhushana 		rc = ENOMEM;
238556b2bdd1SGireesh Nagabhushana 		goto done;
238656b2bdd1SGireesh Nagabhushana 	}
238756b2bdd1SGireesh Nagabhushana 
238856b2bdd1SGireesh Nagabhushana 	(void) ddi_set_parent_data(pi->dip, pi);
238956b2bdd1SGireesh Nagabhushana 	(void) ndi_devi_bind_driver(pi->dip, 0);
239056b2bdd1SGireesh Nagabhushana 	rc = 0;
239156b2bdd1SGireesh Nagabhushana done:
239256b2bdd1SGireesh Nagabhushana 	PORT_UNLOCK(pi);
239356b2bdd1SGireesh Nagabhushana 	return (rc);
239456b2bdd1SGireesh Nagabhushana }
239556b2bdd1SGireesh Nagabhushana 
239656b2bdd1SGireesh Nagabhushana static int
239756b2bdd1SGireesh Nagabhushana remove_child_node(struct adapter *sc, int idx)
239856b2bdd1SGireesh Nagabhushana {
239956b2bdd1SGireesh Nagabhushana 	int rc;
240056b2bdd1SGireesh Nagabhushana 	struct port_info *pi;
240156b2bdd1SGireesh Nagabhushana 
240256b2bdd1SGireesh Nagabhushana 	if (idx < 0 || idx >= sc->params.nports)
240356b2bdd1SGireesh Nagabhushana 		return (EINVAL);
240456b2bdd1SGireesh Nagabhushana 
240556b2bdd1SGireesh Nagabhushana 	pi = sc->port[idx];
240656b2bdd1SGireesh Nagabhushana 	if (pi == NULL)
240756b2bdd1SGireesh Nagabhushana 		return (ENODEV);
240856b2bdd1SGireesh Nagabhushana 
240956b2bdd1SGireesh Nagabhushana 	PORT_LOCK(pi);
241056b2bdd1SGireesh Nagabhushana 	if (pi->dip == NULL) {
241156b2bdd1SGireesh Nagabhushana 		rc = ENODEV;
241256b2bdd1SGireesh Nagabhushana 		goto done;
241356b2bdd1SGireesh Nagabhushana 	}
241456b2bdd1SGireesh Nagabhushana 
241556b2bdd1SGireesh Nagabhushana 	rc = ndi_devi_free(pi->dip);
241656b2bdd1SGireesh Nagabhushana 	if (rc == 0)
241756b2bdd1SGireesh Nagabhushana 		pi->dip = NULL;
241856b2bdd1SGireesh Nagabhushana done:
241956b2bdd1SGireesh Nagabhushana 	PORT_UNLOCK(pi);
242056b2bdd1SGireesh Nagabhushana 	return (rc);
242156b2bdd1SGireesh Nagabhushana }
242256b2bdd1SGireesh Nagabhushana 
24236feac2e3SRahul Lakkireddy static char *
24246feac2e3SRahul Lakkireddy print_port_speed(const struct port_info *pi)
24256feac2e3SRahul Lakkireddy {
24266feac2e3SRahul Lakkireddy 	if (!pi)
24276feac2e3SRahul Lakkireddy 		return "-";
24286feac2e3SRahul Lakkireddy 
24296feac2e3SRahul Lakkireddy 	if (is_100G_port(pi))
24306feac2e3SRahul Lakkireddy 		return "100G";
24316feac2e3SRahul Lakkireddy 	else if (is_50G_port(pi))
24326feac2e3SRahul Lakkireddy 		return "50G";
24336feac2e3SRahul Lakkireddy 	else if (is_40G_port(pi))
24346feac2e3SRahul Lakkireddy 		return "40G";
24356feac2e3SRahul Lakkireddy 	else if (is_25G_port(pi))
24366feac2e3SRahul Lakkireddy 		return "25G";
24376feac2e3SRahul Lakkireddy 	else if (is_10G_port(pi))
24386feac2e3SRahul Lakkireddy 		return "10G";
24396feac2e3SRahul Lakkireddy 	else
24406feac2e3SRahul Lakkireddy 		return "1G";
24416feac2e3SRahul Lakkireddy }
24426feac2e3SRahul Lakkireddy 
244356b2bdd1SGireesh Nagabhushana #define	KS_UINIT(x)	kstat_named_init(&kstatp->x, #x, KSTAT_DATA_ULONG)
244456b2bdd1SGireesh Nagabhushana #define	KS_CINIT(x)	kstat_named_init(&kstatp->x, #x, KSTAT_DATA_CHAR)
2445*c990198dSRobert Mustacchi #define	KS_U64INIT(x)	kstat_named_init(&kstatp->x, #x, KSTAT_DATA_UINT64)
244656b2bdd1SGireesh Nagabhushana #define	KS_U_SET(x, y)	kstatp->x.value.ul = (y)
244756b2bdd1SGireesh Nagabhushana #define	KS_C_SET(x, ...)	\
244856b2bdd1SGireesh Nagabhushana 			(void) snprintf(kstatp->x.value.c, 16,  __VA_ARGS__)
244956b2bdd1SGireesh Nagabhushana 
245056b2bdd1SGireesh Nagabhushana /*
245156b2bdd1SGireesh Nagabhushana  * t4nex:X:config
245256b2bdd1SGireesh Nagabhushana  */
245356b2bdd1SGireesh Nagabhushana struct t4_kstats {
245456b2bdd1SGireesh Nagabhushana 	kstat_named_t chip_ver;
245556b2bdd1SGireesh Nagabhushana 	kstat_named_t fw_vers;
245656b2bdd1SGireesh Nagabhushana 	kstat_named_t tp_vers;
245756b2bdd1SGireesh Nagabhushana 	kstat_named_t driver_version;
245856b2bdd1SGireesh Nagabhushana 	kstat_named_t serial_number;
245956b2bdd1SGireesh Nagabhushana 	kstat_named_t ec_level;
246056b2bdd1SGireesh Nagabhushana 	kstat_named_t id;
246156b2bdd1SGireesh Nagabhushana 	kstat_named_t bus_type;
246256b2bdd1SGireesh Nagabhushana 	kstat_named_t bus_width;
246356b2bdd1SGireesh Nagabhushana 	kstat_named_t bus_speed;
246456b2bdd1SGireesh Nagabhushana 	kstat_named_t core_clock;
246556b2bdd1SGireesh Nagabhushana 	kstat_named_t port_cnt;
246656b2bdd1SGireesh Nagabhushana 	kstat_named_t port_type;
246756b2bdd1SGireesh Nagabhushana 	kstat_named_t pci_vendor_id;
246856b2bdd1SGireesh Nagabhushana 	kstat_named_t pci_device_id;
246956b2bdd1SGireesh Nagabhushana };
247056b2bdd1SGireesh Nagabhushana static kstat_t *
247156b2bdd1SGireesh Nagabhushana setup_kstats(struct adapter *sc)
247256b2bdd1SGireesh Nagabhushana {
247356b2bdd1SGireesh Nagabhushana 	kstat_t *ksp;
247456b2bdd1SGireesh Nagabhushana 	struct t4_kstats *kstatp;
247556b2bdd1SGireesh Nagabhushana 	int ndata;
247656b2bdd1SGireesh Nagabhushana 	struct pci_params *p = &sc->params.pci;
247756b2bdd1SGireesh Nagabhushana 	struct vpd_params *v = &sc->params.vpd;
247856b2bdd1SGireesh Nagabhushana 	uint16_t pci_vendor, pci_device;
247956b2bdd1SGireesh Nagabhushana 
248056b2bdd1SGireesh Nagabhushana 	ndata = sizeof (struct t4_kstats) / sizeof (kstat_named_t);
248156b2bdd1SGireesh Nagabhushana 
248256b2bdd1SGireesh Nagabhushana 	ksp = kstat_create(T4_NEXUS_NAME, ddi_get_instance(sc->dip), "config",
248356b2bdd1SGireesh Nagabhushana 	    "nexus", KSTAT_TYPE_NAMED, ndata, 0);
248456b2bdd1SGireesh Nagabhushana 	if (ksp == NULL) {
248556b2bdd1SGireesh Nagabhushana 		cxgb_printf(sc->dip, CE_WARN, "failed to initialize kstats.");
248656b2bdd1SGireesh Nagabhushana 		return (NULL);
248756b2bdd1SGireesh Nagabhushana 	}
248856b2bdd1SGireesh Nagabhushana 
248956b2bdd1SGireesh Nagabhushana 	kstatp = (struct t4_kstats *)ksp->ks_data;
249056b2bdd1SGireesh Nagabhushana 
249156b2bdd1SGireesh Nagabhushana 	KS_UINIT(chip_ver);
249256b2bdd1SGireesh Nagabhushana 	KS_CINIT(fw_vers);
249356b2bdd1SGireesh Nagabhushana 	KS_CINIT(tp_vers);
249456b2bdd1SGireesh Nagabhushana 	KS_CINIT(driver_version);
249556b2bdd1SGireesh Nagabhushana 	KS_CINIT(serial_number);
249656b2bdd1SGireesh Nagabhushana 	KS_CINIT(ec_level);
249756b2bdd1SGireesh Nagabhushana 	KS_CINIT(id);
249856b2bdd1SGireesh Nagabhushana 	KS_CINIT(bus_type);
249956b2bdd1SGireesh Nagabhushana 	KS_CINIT(bus_width);
250056b2bdd1SGireesh Nagabhushana 	KS_CINIT(bus_speed);
250156b2bdd1SGireesh Nagabhushana 	KS_UINIT(core_clock);
250256b2bdd1SGireesh Nagabhushana 	KS_UINIT(port_cnt);
250356b2bdd1SGireesh Nagabhushana 	KS_CINIT(port_type);
250456b2bdd1SGireesh Nagabhushana 	KS_CINIT(pci_vendor_id);
250556b2bdd1SGireesh Nagabhushana 	KS_CINIT(pci_device_id);
250656b2bdd1SGireesh Nagabhushana 
25073dde7c95SVishal Kulkarni 	KS_U_SET(chip_ver, sc->params.chip);
250856b2bdd1SGireesh Nagabhushana 	KS_C_SET(fw_vers, "%d.%d.%d.%d",
250956b2bdd1SGireesh Nagabhushana 	    G_FW_HDR_FW_VER_MAJOR(sc->params.fw_vers),
251056b2bdd1SGireesh Nagabhushana 	    G_FW_HDR_FW_VER_MINOR(sc->params.fw_vers),
251156b2bdd1SGireesh Nagabhushana 	    G_FW_HDR_FW_VER_MICRO(sc->params.fw_vers),
251256b2bdd1SGireesh Nagabhushana 	    G_FW_HDR_FW_VER_BUILD(sc->params.fw_vers));
251356b2bdd1SGireesh Nagabhushana 	KS_C_SET(tp_vers, "%d.%d.%d.%d",
251456b2bdd1SGireesh Nagabhushana 	    G_FW_HDR_FW_VER_MAJOR(sc->params.tp_vers),
251556b2bdd1SGireesh Nagabhushana 	    G_FW_HDR_FW_VER_MINOR(sc->params.tp_vers),
251656b2bdd1SGireesh Nagabhushana 	    G_FW_HDR_FW_VER_MICRO(sc->params.tp_vers),
251756b2bdd1SGireesh Nagabhushana 	    G_FW_HDR_FW_VER_BUILD(sc->params.tp_vers));
251856b2bdd1SGireesh Nagabhushana 	KS_C_SET(driver_version, DRV_VERSION);
251956b2bdd1SGireesh Nagabhushana 	KS_C_SET(serial_number, "%s", v->sn);
252056b2bdd1SGireesh Nagabhushana 	KS_C_SET(ec_level, "%s", v->ec);
252156b2bdd1SGireesh Nagabhushana 	KS_C_SET(id, "%s", v->id);
252256b2bdd1SGireesh Nagabhushana 	KS_C_SET(bus_type, "pci-express");
252356b2bdd1SGireesh Nagabhushana 	KS_C_SET(bus_width, "x%d lanes", p->width);
252456b2bdd1SGireesh Nagabhushana 	KS_C_SET(bus_speed, "%d", p->speed);
252556b2bdd1SGireesh Nagabhushana 	KS_U_SET(core_clock, v->cclk);
252656b2bdd1SGireesh Nagabhushana 	KS_U_SET(port_cnt, sc->params.nports);
252756b2bdd1SGireesh Nagabhushana 
252856b2bdd1SGireesh Nagabhushana 	t4_os_pci_read_cfg2(sc, PCI_CONF_VENID, &pci_vendor);
252956b2bdd1SGireesh Nagabhushana 	KS_C_SET(pci_vendor_id, "0x%x", pci_vendor);
253056b2bdd1SGireesh Nagabhushana 
253156b2bdd1SGireesh Nagabhushana 	t4_os_pci_read_cfg2(sc, PCI_CONF_DEVID, &pci_device);
253256b2bdd1SGireesh Nagabhushana 	KS_C_SET(pci_device_id, "0x%x", pci_device);
253356b2bdd1SGireesh Nagabhushana 
25343dde7c95SVishal Kulkarni 	KS_C_SET(port_type, "%s/%s/%s/%s",
25353dde7c95SVishal Kulkarni 		 print_port_speed(sc->port[0]),
25363dde7c95SVishal Kulkarni 		 print_port_speed(sc->port[1]),
25373dde7c95SVishal Kulkarni 		 print_port_speed(sc->port[2]),
25383dde7c95SVishal Kulkarni 		 print_port_speed(sc->port[3]));
253956b2bdd1SGireesh Nagabhushana 
254056b2bdd1SGireesh Nagabhushana 	/* Do NOT set ksp->ks_update.  These kstats do not change. */
254156b2bdd1SGireesh Nagabhushana 
254256b2bdd1SGireesh Nagabhushana 	/* Install the kstat */
254356b2bdd1SGireesh Nagabhushana 	ksp->ks_private = (void *)sc;
254456b2bdd1SGireesh Nagabhushana 	kstat_install(ksp);
254556b2bdd1SGireesh Nagabhushana 
254656b2bdd1SGireesh Nagabhushana 	return (ksp);
254756b2bdd1SGireesh Nagabhushana }
254856b2bdd1SGireesh Nagabhushana 
2549de483253SVishal Kulkarni /*
2550de483253SVishal Kulkarni  * t4nex:X:stat
2551de483253SVishal Kulkarni  */
2552de483253SVishal Kulkarni struct t4_wc_kstats {
2553de483253SVishal Kulkarni 	kstat_named_t write_coal_success;
2554de483253SVishal Kulkarni 	kstat_named_t write_coal_failure;
2555de483253SVishal Kulkarni };
2556de483253SVishal Kulkarni static kstat_t *
2557de483253SVishal Kulkarni setup_wc_kstats(struct adapter *sc)
2558de483253SVishal Kulkarni {
2559de483253SVishal Kulkarni 	kstat_t *ksp;
2560de483253SVishal Kulkarni 	struct t4_wc_kstats *kstatp;
2561de483253SVishal Kulkarni 	int ndata;
2562de483253SVishal Kulkarni 
2563de483253SVishal Kulkarni 	ndata = sizeof(struct t4_wc_kstats) / sizeof(kstat_named_t);
2564de483253SVishal Kulkarni 	ksp = kstat_create(T4_NEXUS_NAME, ddi_get_instance(sc->dip), "stats",
2565de483253SVishal Kulkarni 	    "nexus", KSTAT_TYPE_NAMED, ndata, 0);
2566de483253SVishal Kulkarni 	if (ksp == NULL) {
2567de483253SVishal Kulkarni 		cxgb_printf(sc->dip, CE_WARN, "failed to initialize kstats.");
2568de483253SVishal Kulkarni 		return (NULL);
2569de483253SVishal Kulkarni 	}
2570de483253SVishal Kulkarni 
2571de483253SVishal Kulkarni 	kstatp = (struct t4_wc_kstats *)ksp->ks_data;
2572de483253SVishal Kulkarni 
2573de483253SVishal Kulkarni 	KS_UINIT(write_coal_success);
2574de483253SVishal Kulkarni 	KS_UINIT(write_coal_failure);
2575de483253SVishal Kulkarni 
2576de483253SVishal Kulkarni 	ksp->ks_update = update_wc_kstats;
2577de483253SVishal Kulkarni 	/* Install the kstat */
2578de483253SVishal Kulkarni 	ksp->ks_private = (void *)sc;
2579de483253SVishal Kulkarni 	kstat_install(ksp);
2580de483253SVishal Kulkarni 
2581de483253SVishal Kulkarni 	return (ksp);
2582de483253SVishal Kulkarni }
2583de483253SVishal Kulkarni 
2584de483253SVishal Kulkarni static int
2585de483253SVishal Kulkarni update_wc_kstats(kstat_t *ksp, int rw)
2586de483253SVishal Kulkarni {
2587de483253SVishal Kulkarni 	struct t4_wc_kstats *kstatp = (struct t4_wc_kstats *)ksp->ks_data;
2588de483253SVishal Kulkarni 	struct adapter *sc = ksp->ks_private;
2589de483253SVishal Kulkarni 	uint32_t wc_total, wc_success, wc_failure;
2590de483253SVishal Kulkarni 
2591de483253SVishal Kulkarni 	if (rw == KSTAT_WRITE)
2592de483253SVishal Kulkarni 		return (0);
2593de483253SVishal Kulkarni 
2594de483253SVishal Kulkarni 	if (is_t5(sc->params.chip)) {
2595de483253SVishal Kulkarni 		wc_total = t4_read_reg(sc, A_SGE_STAT_TOTAL);
2596de483253SVishal Kulkarni 		wc_failure = t4_read_reg(sc, A_SGE_STAT_MATCH);
2597de483253SVishal Kulkarni 		wc_success = wc_total - wc_failure;
2598de483253SVishal Kulkarni 	} else {
2599de483253SVishal Kulkarni 		wc_success = 0;
2600de483253SVishal Kulkarni 		wc_failure = 0;
2601de483253SVishal Kulkarni 	}
2602de483253SVishal Kulkarni 
2603de483253SVishal Kulkarni 	KS_U_SET(write_coal_success, wc_success);
2604de483253SVishal Kulkarni 	KS_U_SET(write_coal_failure, wc_failure);
2605de483253SVishal Kulkarni 
2606de483253SVishal Kulkarni 	return (0);
2607de483253SVishal Kulkarni }
2608de483253SVishal Kulkarni 
2609*c990198dSRobert Mustacchi /*
2610*c990198dSRobert Mustacchi  * cxgbe:X:fec
2611*c990198dSRobert Mustacchi  *
2612*c990198dSRobert Mustacchi  * This provides visibility into the errors that have been found by the
2613*c990198dSRobert Mustacchi  * different FEC subsystems. While it's tempting to combine the two different
2614*c990198dSRobert Mustacchi  * FEC types logically, the data that the errors tell us are pretty different
2615*c990198dSRobert Mustacchi  * between the two. Firecode is strictly per-lane, but RS has parts that are
2616*c990198dSRobert Mustacchi  * related to symbol distribution to lanes and also to the overall channel.
2617*c990198dSRobert Mustacchi  */
2618*c990198dSRobert Mustacchi struct cxgbe_port_fec_kstats {
2619*c990198dSRobert Mustacchi 	kstat_named_t rs_corr;
2620*c990198dSRobert Mustacchi 	kstat_named_t rs_uncorr;
2621*c990198dSRobert Mustacchi 	kstat_named_t rs_sym0_corr;
2622*c990198dSRobert Mustacchi 	kstat_named_t rs_sym1_corr;
2623*c990198dSRobert Mustacchi 	kstat_named_t rs_sym2_corr;
2624*c990198dSRobert Mustacchi 	kstat_named_t rs_sym3_corr;
2625*c990198dSRobert Mustacchi 	kstat_named_t fc_lane0_corr;
2626*c990198dSRobert Mustacchi 	kstat_named_t fc_lane0_uncorr;
2627*c990198dSRobert Mustacchi 	kstat_named_t fc_lane1_corr;
2628*c990198dSRobert Mustacchi 	kstat_named_t fc_lane1_uncorr;
2629*c990198dSRobert Mustacchi 	kstat_named_t fc_lane2_corr;
2630*c990198dSRobert Mustacchi 	kstat_named_t fc_lane2_uncorr;
2631*c990198dSRobert Mustacchi 	kstat_named_t fc_lane3_corr;
2632*c990198dSRobert Mustacchi 	kstat_named_t fc_lane3_uncorr;
2633*c990198dSRobert Mustacchi };
2634*c990198dSRobert Mustacchi 
2635*c990198dSRobert Mustacchi static uint32_t
2636*c990198dSRobert Mustacchi read_fec_pair(struct port_info *pi, uint32_t lo_reg, uint32_t high_reg)
2637*c990198dSRobert Mustacchi {
2638*c990198dSRobert Mustacchi 	struct adapter *sc = pi->adapter;
2639*c990198dSRobert Mustacchi 	uint8_t port = pi->tx_chan;
2640*c990198dSRobert Mustacchi 	uint32_t low, high, ret;
2641*c990198dSRobert Mustacchi 
2642*c990198dSRobert Mustacchi 	low = t4_read_reg32(sc, T5_PORT_REG(port, lo_reg));
2643*c990198dSRobert Mustacchi 	high = t4_read_reg32(sc, T5_PORT_REG(port, high_reg));
2644*c990198dSRobert Mustacchi 	ret = low & 0xffff;
2645*c990198dSRobert Mustacchi 	ret |= (high & 0xffff) << 16;
2646*c990198dSRobert Mustacchi 	return (ret);
2647*c990198dSRobert Mustacchi }
2648*c990198dSRobert Mustacchi 
2649*c990198dSRobert Mustacchi static int
2650*c990198dSRobert Mustacchi update_port_fec_kstats(kstat_t *ksp, int rw)
2651*c990198dSRobert Mustacchi {
2652*c990198dSRobert Mustacchi 	struct cxgbe_port_fec_kstats *fec = ksp->ks_data;
2653*c990198dSRobert Mustacchi 	struct port_info *pi = ksp->ks_private;
2654*c990198dSRobert Mustacchi 
2655*c990198dSRobert Mustacchi 	if (rw == KSTAT_WRITE) {
2656*c990198dSRobert Mustacchi 		return (EACCES);
2657*c990198dSRobert Mustacchi 	}
2658*c990198dSRobert Mustacchi 
2659*c990198dSRobert Mustacchi 	/*
2660*c990198dSRobert Mustacchi 	 * First go ahead and gather RS related stats.
2661*c990198dSRobert Mustacchi 	 */
2662*c990198dSRobert Mustacchi 	fec->rs_corr.value.ui64 += read_fec_pair(pi, T6_RS_FEC_CCW_LO,
2663*c990198dSRobert Mustacchi 	    T6_RS_FEC_CCW_HI);
2664*c990198dSRobert Mustacchi 	fec->rs_uncorr.value.ui64 += read_fec_pair(pi, T6_RS_FEC_NCCW_LO,
2665*c990198dSRobert Mustacchi 	    T6_RS_FEC_NCCW_HI);
2666*c990198dSRobert Mustacchi 	fec->rs_sym0_corr.value.ui64 += read_fec_pair(pi, T6_RS_FEC_SYMERR0_LO,
2667*c990198dSRobert Mustacchi 	    T6_RS_FEC_SYMERR0_HI);
2668*c990198dSRobert Mustacchi 	fec->rs_sym1_corr.value.ui64 += read_fec_pair(pi, T6_RS_FEC_SYMERR1_LO,
2669*c990198dSRobert Mustacchi 	    T6_RS_FEC_SYMERR1_HI);
2670*c990198dSRobert Mustacchi 	fec->rs_sym2_corr.value.ui64 += read_fec_pair(pi, T6_RS_FEC_SYMERR2_LO,
2671*c990198dSRobert Mustacchi 	    T6_RS_FEC_SYMERR2_HI);
2672*c990198dSRobert Mustacchi 	fec->rs_sym3_corr.value.ui64 += read_fec_pair(pi, T6_RS_FEC_SYMERR3_LO,
2673*c990198dSRobert Mustacchi 	    T6_RS_FEC_SYMERR3_HI);
2674*c990198dSRobert Mustacchi 
2675*c990198dSRobert Mustacchi 	/*
2676*c990198dSRobert Mustacchi 	 * Now go through and try to grab Firecode/BASE-R stats.
2677*c990198dSRobert Mustacchi 	 */
2678*c990198dSRobert Mustacchi 	fec->fc_lane0_corr.value.ui64 += read_fec_pair(pi, T6_FC_FEC_L0_CERR_LO,
2679*c990198dSRobert Mustacchi 	    T6_FC_FEC_L0_CERR_HI);
2680*c990198dSRobert Mustacchi 	fec->fc_lane0_uncorr.value.ui64 += read_fec_pair(pi,
2681*c990198dSRobert Mustacchi 	    T6_FC_FEC_L0_NCERR_LO, T6_FC_FEC_L0_NCERR_HI);
2682*c990198dSRobert Mustacchi 	fec->fc_lane1_corr.value.ui64 += read_fec_pair(pi, T6_FC_FEC_L1_CERR_LO,
2683*c990198dSRobert Mustacchi 	    T6_FC_FEC_L1_CERR_HI);
2684*c990198dSRobert Mustacchi 	fec->fc_lane1_uncorr.value.ui64 += read_fec_pair(pi,
2685*c990198dSRobert Mustacchi 	    T6_FC_FEC_L1_NCERR_LO, T6_FC_FEC_L1_NCERR_HI);
2686*c990198dSRobert Mustacchi 	fec->fc_lane2_corr.value.ui64 += read_fec_pair(pi, T6_FC_FEC_L2_CERR_LO,
2687*c990198dSRobert Mustacchi 	    T6_FC_FEC_L2_CERR_HI);
2688*c990198dSRobert Mustacchi 	fec->fc_lane2_uncorr.value.ui64 += read_fec_pair(pi,
2689*c990198dSRobert Mustacchi 	    T6_FC_FEC_L2_NCERR_LO, T6_FC_FEC_L2_NCERR_HI);
2690*c990198dSRobert Mustacchi 	fec->fc_lane3_corr.value.ui64 += read_fec_pair(pi, T6_FC_FEC_L3_CERR_LO,
2691*c990198dSRobert Mustacchi 	    T6_FC_FEC_L3_CERR_HI);
2692*c990198dSRobert Mustacchi 	fec->fc_lane3_uncorr.value.ui64 += read_fec_pair(pi,
2693*c990198dSRobert Mustacchi 	    T6_FC_FEC_L3_NCERR_LO, T6_FC_FEC_L3_NCERR_HI);
2694*c990198dSRobert Mustacchi 
2695*c990198dSRobert Mustacchi 	return (0);
2696*c990198dSRobert Mustacchi }
2697*c990198dSRobert Mustacchi 
2698*c990198dSRobert Mustacchi static kstat_t *
2699*c990198dSRobert Mustacchi setup_port_fec_kstats(struct port_info *pi)
2700*c990198dSRobert Mustacchi {
2701*c990198dSRobert Mustacchi 	kstat_t *ksp;
2702*c990198dSRobert Mustacchi 	struct cxgbe_port_fec_kstats *kstatp;
2703*c990198dSRobert Mustacchi 
2704*c990198dSRobert Mustacchi 	if (!is_t6(pi->adapter->params.chip)) {
2705*c990198dSRobert Mustacchi 		return (NULL);
2706*c990198dSRobert Mustacchi 	}
2707*c990198dSRobert Mustacchi 
2708*c990198dSRobert Mustacchi 	ksp = kstat_create(T4_PORT_NAME, ddi_get_instance(pi->dip), "fec",
2709*c990198dSRobert Mustacchi 	    "net", KSTAT_TYPE_NAMED, sizeof (struct cxgbe_port_fec_kstats) /
2710*c990198dSRobert Mustacchi 	    sizeof (kstat_named_t), 0);
2711*c990198dSRobert Mustacchi 	if (ksp == NULL) {
2712*c990198dSRobert Mustacchi 		cxgb_printf(pi->dip, CE_WARN, "failed to initialize fec "
2713*c990198dSRobert Mustacchi 		    "kstats.");
2714*c990198dSRobert Mustacchi 		return (NULL);
2715*c990198dSRobert Mustacchi 	}
2716*c990198dSRobert Mustacchi 
2717*c990198dSRobert Mustacchi 	kstatp = ksp->ks_data;
2718*c990198dSRobert Mustacchi 	KS_U64INIT(rs_corr);
2719*c990198dSRobert Mustacchi 	KS_U64INIT(rs_uncorr);
2720*c990198dSRobert Mustacchi 	KS_U64INIT(rs_sym0_corr);
2721*c990198dSRobert Mustacchi 	KS_U64INIT(rs_sym1_corr);
2722*c990198dSRobert Mustacchi 	KS_U64INIT(rs_sym2_corr);
2723*c990198dSRobert Mustacchi 	KS_U64INIT(rs_sym3_corr);
2724*c990198dSRobert Mustacchi 	KS_U64INIT(fc_lane0_corr);
2725*c990198dSRobert Mustacchi 	KS_U64INIT(fc_lane0_uncorr);
2726*c990198dSRobert Mustacchi 	KS_U64INIT(fc_lane1_corr);
2727*c990198dSRobert Mustacchi 	KS_U64INIT(fc_lane1_uncorr);
2728*c990198dSRobert Mustacchi 	KS_U64INIT(fc_lane2_corr);
2729*c990198dSRobert Mustacchi 	KS_U64INIT(fc_lane2_uncorr);
2730*c990198dSRobert Mustacchi 	KS_U64INIT(fc_lane3_corr);
2731*c990198dSRobert Mustacchi 	KS_U64INIT(fc_lane3_uncorr);
2732*c990198dSRobert Mustacchi 
2733*c990198dSRobert Mustacchi 	ksp->ks_update = update_port_fec_kstats;
2734*c990198dSRobert Mustacchi 	ksp->ks_private = pi;
2735*c990198dSRobert Mustacchi 	kstat_install(ksp);
2736*c990198dSRobert Mustacchi 
2737*c990198dSRobert Mustacchi 	return (ksp);
2738*c990198dSRobert Mustacchi }
2739*c990198dSRobert Mustacchi 
274056b2bdd1SGireesh Nagabhushana int
274156b2bdd1SGireesh Nagabhushana adapter_full_init(struct adapter *sc)
274256b2bdd1SGireesh Nagabhushana {
274356b2bdd1SGireesh Nagabhushana 	int i, rc = 0;
274456b2bdd1SGireesh Nagabhushana 
274556b2bdd1SGireesh Nagabhushana 	ADAPTER_LOCK_ASSERT_NOTOWNED(sc);
274656b2bdd1SGireesh Nagabhushana 
274756b2bdd1SGireesh Nagabhushana 	rc = t4_setup_adapter_queues(sc);
274856b2bdd1SGireesh Nagabhushana 	if (rc != 0)
274956b2bdd1SGireesh Nagabhushana 		goto done;
275056b2bdd1SGireesh Nagabhushana 
275156b2bdd1SGireesh Nagabhushana 	if (sc->intr_cap & DDI_INTR_FLAG_BLOCK)
275256b2bdd1SGireesh Nagabhushana 		(void) ddi_intr_block_enable(sc->intr_handle, sc->intr_count);
275356b2bdd1SGireesh Nagabhushana 	else {
275456b2bdd1SGireesh Nagabhushana 		for (i = 0; i < sc->intr_count; i++)
275556b2bdd1SGireesh Nagabhushana 			(void) ddi_intr_enable(sc->intr_handle[i]);
275656b2bdd1SGireesh Nagabhushana 	}
275756b2bdd1SGireesh Nagabhushana 	t4_intr_enable(sc);
275856b2bdd1SGireesh Nagabhushana 	sc->flags |= FULL_INIT_DONE;
275956b2bdd1SGireesh Nagabhushana 
27603dde7c95SVishal Kulkarni #ifdef TCP_OFFLOAD_ENABLE
276156b2bdd1SGireesh Nagabhushana 	/* TODO: wrong place to enable TOE capability */
276256b2bdd1SGireesh Nagabhushana 	if (is_offload(sc) != 0) {
276356b2bdd1SGireesh Nagabhushana 		for_each_port(sc, i) {
276456b2bdd1SGireesh Nagabhushana 			struct port_info *pi = sc->port[i];
276556b2bdd1SGireesh Nagabhushana 			rc = toe_capability(pi, 1);
276656b2bdd1SGireesh Nagabhushana 			if (rc != 0) {
276756b2bdd1SGireesh Nagabhushana 				cxgb_printf(pi->dip, CE_WARN,
276856b2bdd1SGireesh Nagabhushana 				    "Failed to activate toe capability: %d",
276956b2bdd1SGireesh Nagabhushana 				    rc);
277056b2bdd1SGireesh Nagabhushana 				rc = 0;		/* not a fatal error */
277156b2bdd1SGireesh Nagabhushana 			}
277256b2bdd1SGireesh Nagabhushana 		}
277356b2bdd1SGireesh Nagabhushana 	}
277456b2bdd1SGireesh Nagabhushana #endif
277556b2bdd1SGireesh Nagabhushana 
277656b2bdd1SGireesh Nagabhushana done:
277756b2bdd1SGireesh Nagabhushana 	if (rc != 0)
277856b2bdd1SGireesh Nagabhushana 		(void) adapter_full_uninit(sc);
277956b2bdd1SGireesh Nagabhushana 
278056b2bdd1SGireesh Nagabhushana 	return (rc);
278156b2bdd1SGireesh Nagabhushana }
278256b2bdd1SGireesh Nagabhushana 
278356b2bdd1SGireesh Nagabhushana int
278456b2bdd1SGireesh Nagabhushana adapter_full_uninit(struct adapter *sc)
278556b2bdd1SGireesh Nagabhushana {
278656b2bdd1SGireesh Nagabhushana 	int i, rc = 0;
278756b2bdd1SGireesh Nagabhushana 
278856b2bdd1SGireesh Nagabhushana 	ADAPTER_LOCK_ASSERT_NOTOWNED(sc);
278956b2bdd1SGireesh Nagabhushana 
279056b2bdd1SGireesh Nagabhushana 	if (sc->intr_cap & DDI_INTR_FLAG_BLOCK)
279156b2bdd1SGireesh Nagabhushana 		(void) ddi_intr_block_disable(sc->intr_handle, sc->intr_count);
279256b2bdd1SGireesh Nagabhushana 	else {
279356b2bdd1SGireesh Nagabhushana 		for (i = 0; i < sc->intr_count; i++)
279456b2bdd1SGireesh Nagabhushana 			(void) ddi_intr_disable(sc->intr_handle[i]);
279556b2bdd1SGireesh Nagabhushana 	}
279656b2bdd1SGireesh Nagabhushana 
279756b2bdd1SGireesh Nagabhushana 	rc = t4_teardown_adapter_queues(sc);
279856b2bdd1SGireesh Nagabhushana 	if (rc != 0)
279956b2bdd1SGireesh Nagabhushana 		return (rc);
280056b2bdd1SGireesh Nagabhushana 
280156b2bdd1SGireesh Nagabhushana 	sc->flags &= ~FULL_INIT_DONE;
280256b2bdd1SGireesh Nagabhushana 
280356b2bdd1SGireesh Nagabhushana 	return (0);
280456b2bdd1SGireesh Nagabhushana }
280556b2bdd1SGireesh Nagabhushana 
280656b2bdd1SGireesh Nagabhushana int
280756b2bdd1SGireesh Nagabhushana port_full_init(struct port_info *pi)
280856b2bdd1SGireesh Nagabhushana {
280956b2bdd1SGireesh Nagabhushana 	struct adapter *sc = pi->adapter;
281056b2bdd1SGireesh Nagabhushana 	uint16_t *rss;
281156b2bdd1SGireesh Nagabhushana 	struct sge_rxq *rxq;
281256b2bdd1SGireesh Nagabhushana 	int rc, i;
281356b2bdd1SGireesh Nagabhushana 
281456b2bdd1SGireesh Nagabhushana 	ADAPTER_LOCK_ASSERT_NOTOWNED(sc);
281556b2bdd1SGireesh Nagabhushana 	ASSERT((pi->flags & PORT_INIT_DONE) == 0);
281656b2bdd1SGireesh Nagabhushana 
281756b2bdd1SGireesh Nagabhushana 	/*
281856b2bdd1SGireesh Nagabhushana 	 * Allocate tx/rx/fl queues for this port.
281956b2bdd1SGireesh Nagabhushana 	 */
282056b2bdd1SGireesh Nagabhushana 	rc = t4_setup_port_queues(pi);
282156b2bdd1SGireesh Nagabhushana 	if (rc != 0)
282256b2bdd1SGireesh Nagabhushana 		goto done;	/* error message displayed already */
282356b2bdd1SGireesh Nagabhushana 
282456b2bdd1SGireesh Nagabhushana 	/*
282556b2bdd1SGireesh Nagabhushana 	 * Setup RSS for this port.
282656b2bdd1SGireesh Nagabhushana 	 */
282756b2bdd1SGireesh Nagabhushana 	rss = kmem_zalloc(pi->nrxq * sizeof (*rss), KM_SLEEP);
282856b2bdd1SGireesh Nagabhushana 	for_each_rxq(pi, i, rxq) {
282956b2bdd1SGireesh Nagabhushana 		rss[i] = rxq->iq.abs_id;
283056b2bdd1SGireesh Nagabhushana 	}
283156b2bdd1SGireesh Nagabhushana 	rc = -t4_config_rss_range(sc, sc->mbox, pi->viid, 0,
283256b2bdd1SGireesh Nagabhushana 	    pi->rss_size, rss, pi->nrxq);
283356b2bdd1SGireesh Nagabhushana 	kmem_free(rss, pi->nrxq * sizeof (*rss));
283456b2bdd1SGireesh Nagabhushana 	if (rc != 0) {
283556b2bdd1SGireesh Nagabhushana 		cxgb_printf(pi->dip, CE_WARN, "rss_config failed: %d", rc);
283656b2bdd1SGireesh Nagabhushana 		goto done;
283756b2bdd1SGireesh Nagabhushana 	}
283856b2bdd1SGireesh Nagabhushana 
2839*c990198dSRobert Mustacchi 	/*
2840*c990198dSRobert Mustacchi 	 * Initialize our per-port FEC kstats.
2841*c990198dSRobert Mustacchi 	 */
2842*c990198dSRobert Mustacchi 	pi->ksp_fec = setup_port_fec_kstats(pi);
2843*c990198dSRobert Mustacchi 
284456b2bdd1SGireesh Nagabhushana 	pi->flags |= PORT_INIT_DONE;
284556b2bdd1SGireesh Nagabhushana done:
284656b2bdd1SGireesh Nagabhushana 	if (rc != 0)
284756b2bdd1SGireesh Nagabhushana 		(void) port_full_uninit(pi);
284856b2bdd1SGireesh Nagabhushana 
284956b2bdd1SGireesh Nagabhushana 	return (rc);
285056b2bdd1SGireesh Nagabhushana }
285156b2bdd1SGireesh Nagabhushana 
285256b2bdd1SGireesh Nagabhushana /*
285356b2bdd1SGireesh Nagabhushana  * Idempotent.
285456b2bdd1SGireesh Nagabhushana  */
285556b2bdd1SGireesh Nagabhushana int
285656b2bdd1SGireesh Nagabhushana port_full_uninit(struct port_info *pi)
285756b2bdd1SGireesh Nagabhushana {
285856b2bdd1SGireesh Nagabhushana 
285956b2bdd1SGireesh Nagabhushana 	ASSERT(pi->flags & PORT_INIT_DONE);
286056b2bdd1SGireesh Nagabhushana 
2861*c990198dSRobert Mustacchi 	if (pi->ksp_fec != NULL) {
2862*c990198dSRobert Mustacchi 		kstat_delete(pi->ksp_fec);
2863*c990198dSRobert Mustacchi 		pi->ksp_fec = NULL;
2864*c990198dSRobert Mustacchi 	}
286556b2bdd1SGireesh Nagabhushana 	(void) t4_teardown_port_queues(pi);
286656b2bdd1SGireesh Nagabhushana 	pi->flags &= ~PORT_INIT_DONE;
286756b2bdd1SGireesh Nagabhushana 
286856b2bdd1SGireesh Nagabhushana 	return (0);
286956b2bdd1SGireesh Nagabhushana }
287056b2bdd1SGireesh Nagabhushana 
287156b2bdd1SGireesh Nagabhushana void
287256b2bdd1SGireesh Nagabhushana enable_port_queues(struct port_info *pi)
287356b2bdd1SGireesh Nagabhushana {
287456b2bdd1SGireesh Nagabhushana 	struct adapter *sc = pi->adapter;
287556b2bdd1SGireesh Nagabhushana 	int i;
287656b2bdd1SGireesh Nagabhushana 	struct sge_iq *iq;
287756b2bdd1SGireesh Nagabhushana 	struct sge_rxq *rxq;
28783dde7c95SVishal Kulkarni #ifdef TCP_OFFLOAD_ENABLE
287956b2bdd1SGireesh Nagabhushana 	struct sge_ofld_rxq *ofld_rxq;
288056b2bdd1SGireesh Nagabhushana #endif
288156b2bdd1SGireesh Nagabhushana 
288256b2bdd1SGireesh Nagabhushana 	ASSERT(pi->flags & PORT_INIT_DONE);
288356b2bdd1SGireesh Nagabhushana 
288456b2bdd1SGireesh Nagabhushana 	/*
288556b2bdd1SGireesh Nagabhushana 	 * TODO: whatever was queued up after we set iq->state to IQS_DISABLED
288656b2bdd1SGireesh Nagabhushana 	 * back in disable_port_queues will be processed now, after an unbounded
288756b2bdd1SGireesh Nagabhushana 	 * delay.  This can't be good.
288856b2bdd1SGireesh Nagabhushana 	 */
288956b2bdd1SGireesh Nagabhushana 
28903dde7c95SVishal Kulkarni #ifdef TCP_OFFLOAD_ENABLE
289156b2bdd1SGireesh Nagabhushana 	for_each_ofld_rxq(pi, i, ofld_rxq) {
289256b2bdd1SGireesh Nagabhushana 		iq = &ofld_rxq->iq;
289356b2bdd1SGireesh Nagabhushana 		if (atomic_cas_uint(&iq->state, IQS_DISABLED, IQS_IDLE) !=
289456b2bdd1SGireesh Nagabhushana 		    IQS_DISABLED)
289556b2bdd1SGireesh Nagabhushana 			panic("%s: iq %p wasn't disabled", __func__,
289656b2bdd1SGireesh Nagabhushana 			    (void *)iq);
289756b2bdd1SGireesh Nagabhushana 		t4_write_reg(sc, MYPF_REG(A_SGE_PF_GTS),
289856b2bdd1SGireesh Nagabhushana 		    V_SEINTARM(iq->intr_params) | V_INGRESSQID(iq->cntxt_id));
289956b2bdd1SGireesh Nagabhushana 	}
290056b2bdd1SGireesh Nagabhushana #endif
290156b2bdd1SGireesh Nagabhushana 
290256b2bdd1SGireesh Nagabhushana 	for_each_rxq(pi, i, rxq) {
290356b2bdd1SGireesh Nagabhushana 		iq = &rxq->iq;
290456b2bdd1SGireesh Nagabhushana 		if (atomic_cas_uint(&iq->state, IQS_DISABLED, IQS_IDLE) !=
290556b2bdd1SGireesh Nagabhushana 		    IQS_DISABLED)
290656b2bdd1SGireesh Nagabhushana 			panic("%s: iq %p wasn't disabled", __func__,
290756b2bdd1SGireesh Nagabhushana 			    (void *) iq);
290856b2bdd1SGireesh Nagabhushana 		t4_write_reg(sc, MYPF_REG(A_SGE_PF_GTS),
290956b2bdd1SGireesh Nagabhushana 		    V_SEINTARM(iq->intr_params) | V_INGRESSQID(iq->cntxt_id));
291056b2bdd1SGireesh Nagabhushana 	}
291156b2bdd1SGireesh Nagabhushana }
291256b2bdd1SGireesh Nagabhushana 
291356b2bdd1SGireesh Nagabhushana void
291456b2bdd1SGireesh Nagabhushana disable_port_queues(struct port_info *pi)
291556b2bdd1SGireesh Nagabhushana {
291656b2bdd1SGireesh Nagabhushana 	int i;
291756b2bdd1SGireesh Nagabhushana 	struct adapter *sc = pi->adapter;
291856b2bdd1SGireesh Nagabhushana 	struct sge_rxq *rxq;
29193dde7c95SVishal Kulkarni #ifdef TCP_OFFLOAD_ENABLE
292056b2bdd1SGireesh Nagabhushana 	struct sge_ofld_rxq *ofld_rxq;
292156b2bdd1SGireesh Nagabhushana #endif
292256b2bdd1SGireesh Nagabhushana 
292356b2bdd1SGireesh Nagabhushana 	ASSERT(pi->flags & PORT_INIT_DONE);
292456b2bdd1SGireesh Nagabhushana 
292556b2bdd1SGireesh Nagabhushana 	/*
292656b2bdd1SGireesh Nagabhushana 	 * TODO: need proper implementation for all tx queues (ctrl, eth, ofld).
292756b2bdd1SGireesh Nagabhushana 	 */
292856b2bdd1SGireesh Nagabhushana 
29293dde7c95SVishal Kulkarni #ifdef TCP_OFFLOAD_ENABLE
293056b2bdd1SGireesh Nagabhushana 	for_each_ofld_rxq(pi, i, ofld_rxq) {
293156b2bdd1SGireesh Nagabhushana 		while (atomic_cas_uint(&ofld_rxq->iq.state, IQS_IDLE,
293256b2bdd1SGireesh Nagabhushana 		    IQS_DISABLED) != IQS_IDLE)
293356b2bdd1SGireesh Nagabhushana 			msleep(1);
293456b2bdd1SGireesh Nagabhushana 	}
293556b2bdd1SGireesh Nagabhushana #endif
293656b2bdd1SGireesh Nagabhushana 
293756b2bdd1SGireesh Nagabhushana 	for_each_rxq(pi, i, rxq) {
293856b2bdd1SGireesh Nagabhushana 		while (atomic_cas_uint(&rxq->iq.state, IQS_IDLE,
293956b2bdd1SGireesh Nagabhushana 		    IQS_DISABLED) != IQS_IDLE)
294056b2bdd1SGireesh Nagabhushana 			msleep(1);
294156b2bdd1SGireesh Nagabhushana 	}
294256b2bdd1SGireesh Nagabhushana 
294356b2bdd1SGireesh Nagabhushana 	mutex_enter(&sc->sfl_lock);
29443dde7c95SVishal Kulkarni #ifdef TCP_OFFLOAD_ENABLE
294556b2bdd1SGireesh Nagabhushana 	for_each_ofld_rxq(pi, i, ofld_rxq)
294656b2bdd1SGireesh Nagabhushana 	    ofld_rxq->fl.flags |= FL_DOOMED;
294756b2bdd1SGireesh Nagabhushana #endif
294856b2bdd1SGireesh Nagabhushana 	for_each_rxq(pi, i, rxq)
294956b2bdd1SGireesh Nagabhushana 	    rxq->fl.flags |= FL_DOOMED;
295056b2bdd1SGireesh Nagabhushana 	mutex_exit(&sc->sfl_lock);
295156b2bdd1SGireesh Nagabhushana 	/* TODO: need to wait for all fl's to be removed from sc->sfl */
295256b2bdd1SGireesh Nagabhushana }
295356b2bdd1SGireesh Nagabhushana 
295456b2bdd1SGireesh Nagabhushana void
295556b2bdd1SGireesh Nagabhushana t4_fatal_err(struct adapter *sc)
295656b2bdd1SGireesh Nagabhushana {
295756b2bdd1SGireesh Nagabhushana 	t4_set_reg_field(sc, A_SGE_CONTROL, F_GLOBALENABLE, 0);
295856b2bdd1SGireesh Nagabhushana 	t4_intr_disable(sc);
295956b2bdd1SGireesh Nagabhushana 	cxgb_printf(sc->dip, CE_WARN,
296056b2bdd1SGireesh Nagabhushana 	    "encountered fatal error, adapter stopped.");
296156b2bdd1SGireesh Nagabhushana }
296256b2bdd1SGireesh Nagabhushana 
296356b2bdd1SGireesh Nagabhushana int
296456b2bdd1SGireesh Nagabhushana t4_os_find_pci_capability(struct adapter *sc, int cap)
296556b2bdd1SGireesh Nagabhushana {
296656b2bdd1SGireesh Nagabhushana 	uint16_t stat;
296756b2bdd1SGireesh Nagabhushana 	uint8_t cap_ptr, cap_id;
296856b2bdd1SGireesh Nagabhushana 
296956b2bdd1SGireesh Nagabhushana 	t4_os_pci_read_cfg2(sc, PCI_CONF_STAT, &stat);
297056b2bdd1SGireesh Nagabhushana 	if ((stat & PCI_STAT_CAP) == 0)
297156b2bdd1SGireesh Nagabhushana 		return (0); /* does not implement capabilities */
297256b2bdd1SGireesh Nagabhushana 
297356b2bdd1SGireesh Nagabhushana 	t4_os_pci_read_cfg1(sc, PCI_CONF_CAP_PTR, &cap_ptr);
297456b2bdd1SGireesh Nagabhushana 	while (cap_ptr) {
297556b2bdd1SGireesh Nagabhushana 		t4_os_pci_read_cfg1(sc, cap_ptr + PCI_CAP_ID, &cap_id);
297656b2bdd1SGireesh Nagabhushana 		if (cap_id == cap)
297756b2bdd1SGireesh Nagabhushana 			return (cap_ptr); /* found */
297856b2bdd1SGireesh Nagabhushana 		t4_os_pci_read_cfg1(sc, cap_ptr + PCI_CAP_NEXT_PTR, &cap_ptr);
297956b2bdd1SGireesh Nagabhushana 	}
298056b2bdd1SGireesh Nagabhushana 
298156b2bdd1SGireesh Nagabhushana 	return (0); /* not found */
298256b2bdd1SGireesh Nagabhushana }
298356b2bdd1SGireesh Nagabhushana 
298456b2bdd1SGireesh Nagabhushana void
29856feac2e3SRahul Lakkireddy t4_os_portmod_changed(struct adapter *sc, int idx)
298656b2bdd1SGireesh Nagabhushana {
298756b2bdd1SGireesh Nagabhushana 	static const char *mod_str[] = {
298856b2bdd1SGireesh Nagabhushana 		NULL, "LR", "SR", "ER", "TWINAX", "active TWINAX", "LRM"
298956b2bdd1SGireesh Nagabhushana 	};
29906feac2e3SRahul Lakkireddy 	struct port_info *pi = sc->port[idx];
299156b2bdd1SGireesh Nagabhushana 
299256b2bdd1SGireesh Nagabhushana 	if (pi->mod_type == FW_PORT_MOD_TYPE_NONE)
299356b2bdd1SGireesh Nagabhushana 		cxgb_printf(pi->dip, CE_NOTE, "transceiver unplugged.");
299456b2bdd1SGireesh Nagabhushana 	else if (pi->mod_type == FW_PORT_MOD_TYPE_UNKNOWN)
299556b2bdd1SGireesh Nagabhushana 		cxgb_printf(pi->dip, CE_NOTE,
299656b2bdd1SGireesh Nagabhushana 		    "unknown transceiver inserted.\n");
299756b2bdd1SGireesh Nagabhushana 	else if (pi->mod_type == FW_PORT_MOD_TYPE_NOTSUPPORTED)
299856b2bdd1SGireesh Nagabhushana 		cxgb_printf(pi->dip, CE_NOTE,
299956b2bdd1SGireesh Nagabhushana 		    "unsupported transceiver inserted.\n");
300056b2bdd1SGireesh Nagabhushana 	else if (pi->mod_type > 0 && pi->mod_type < ARRAY_SIZE(mod_str))
300156b2bdd1SGireesh Nagabhushana 		cxgb_printf(pi->dip, CE_NOTE, "%s transceiver inserted.\n",
300256b2bdd1SGireesh Nagabhushana 		    mod_str[pi->mod_type]);
300356b2bdd1SGireesh Nagabhushana 	else
300456b2bdd1SGireesh Nagabhushana 		cxgb_printf(pi->dip, CE_NOTE, "transceiver (type %d) inserted.",
300556b2bdd1SGireesh Nagabhushana 		    pi->mod_type);
30066feac2e3SRahul Lakkireddy 
30076feac2e3SRahul Lakkireddy 	if ((isset(&sc->open_device_map, pi->port_id) != 0) &&
30086feac2e3SRahul Lakkireddy 	    pi->link_cfg.new_module)
30096feac2e3SRahul Lakkireddy 		pi->link_cfg.redo_l1cfg = true;
301056b2bdd1SGireesh Nagabhushana }
301156b2bdd1SGireesh Nagabhushana 
301256b2bdd1SGireesh Nagabhushana /* ARGSUSED */
301356b2bdd1SGireesh Nagabhushana static int
301456b2bdd1SGireesh Nagabhushana cpl_not_handled(struct sge_iq *iq, const struct rss_header *rss, mblk_t *m)
301556b2bdd1SGireesh Nagabhushana {
301656b2bdd1SGireesh Nagabhushana 	if (m != NULL)
301756b2bdd1SGireesh Nagabhushana 		freemsg(m);
301856b2bdd1SGireesh Nagabhushana 	return (0);
301956b2bdd1SGireesh Nagabhushana }
302056b2bdd1SGireesh Nagabhushana 
302156b2bdd1SGireesh Nagabhushana int
302256b2bdd1SGireesh Nagabhushana t4_register_cpl_handler(struct adapter *sc, int opcode, cpl_handler_t h)
302356b2bdd1SGireesh Nagabhushana {
302456b2bdd1SGireesh Nagabhushana 	uint_t *loc, new;
302556b2bdd1SGireesh Nagabhushana 
302656b2bdd1SGireesh Nagabhushana 	if (opcode >= ARRAY_SIZE(sc->cpl_handler))
302756b2bdd1SGireesh Nagabhushana 		return (EINVAL);
302856b2bdd1SGireesh Nagabhushana 
302956b2bdd1SGireesh Nagabhushana 	new = (uint_t)(unsigned long) (h ? h : cpl_not_handled);
303056b2bdd1SGireesh Nagabhushana 	loc = (uint_t *)&sc->cpl_handler[opcode];
303156b2bdd1SGireesh Nagabhushana 	(void) atomic_swap_uint(loc, new);
303256b2bdd1SGireesh Nagabhushana 
303356b2bdd1SGireesh Nagabhushana 	return (0);
303456b2bdd1SGireesh Nagabhushana }
303556b2bdd1SGireesh Nagabhushana 
3036de483253SVishal Kulkarni static int
3037de483253SVishal Kulkarni fw_msg_not_handled(struct adapter *sc, const __be64 *data)
3038de483253SVishal Kulkarni {
303994c3dad2SToomas Soome 	struct cpl_fw6_msg *cpl;
304094c3dad2SToomas Soome 
304194c3dad2SToomas Soome 	cpl = __containerof((void *)data, struct cpl_fw6_msg, data);
3042de483253SVishal Kulkarni 
3043de483253SVishal Kulkarni 	cxgb_printf(sc->dip, CE_WARN, "%s fw_msg type %d", __func__, cpl->type);
3044de483253SVishal Kulkarni 	return (0);
3045de483253SVishal Kulkarni }
3046de483253SVishal Kulkarni 
3047de483253SVishal Kulkarni int
3048de483253SVishal Kulkarni t4_register_fw_msg_handler(struct adapter *sc, int type, fw_msg_handler_t h)
3049de483253SVishal Kulkarni {
3050de483253SVishal Kulkarni 	fw_msg_handler_t *loc, new;
3051de483253SVishal Kulkarni 
3052de483253SVishal Kulkarni 	if (type >= ARRAY_SIZE(sc->fw_msg_handler))
3053de483253SVishal Kulkarni 		return (EINVAL);
3054de483253SVishal Kulkarni 
3055de483253SVishal Kulkarni 	/*
3056de483253SVishal Kulkarni 	 * These are dispatched by the handler for FW{4|6}_CPL_MSG using the CPL
3057de483253SVishal Kulkarni 	 * handler dispatch table.  Reject any attempt to install a handler for
3058de483253SVishal Kulkarni 	 * this subtype.
3059de483253SVishal Kulkarni 	 */
3060de483253SVishal Kulkarni 	if (type == FW_TYPE_RSSCPL || type == FW6_TYPE_RSSCPL)
3061de483253SVishal Kulkarni 		return (EINVAL);
3062de483253SVishal Kulkarni 
3063de483253SVishal Kulkarni 	new = h ? h : fw_msg_not_handled;
3064de483253SVishal Kulkarni 	loc = &sc->fw_msg_handler[type];
3065de483253SVishal Kulkarni 	(void)atomic_swap_ptr(loc, (void *)new);
3066de483253SVishal Kulkarni 
3067de483253SVishal Kulkarni 	return (0);
3068de483253SVishal Kulkarni }
3069de483253SVishal Kulkarni 
30703dde7c95SVishal Kulkarni #ifdef TCP_OFFLOAD_ENABLE
307156b2bdd1SGireesh Nagabhushana static int
307256b2bdd1SGireesh Nagabhushana toe_capability(struct port_info *pi, int enable)
307356b2bdd1SGireesh Nagabhushana {
307456b2bdd1SGireesh Nagabhushana 	int rc;
307556b2bdd1SGireesh Nagabhushana 	struct adapter *sc = pi->adapter;
307656b2bdd1SGireesh Nagabhushana 
307756b2bdd1SGireesh Nagabhushana 	if (!is_offload(sc))
307856b2bdd1SGireesh Nagabhushana 		return (ENODEV);
307956b2bdd1SGireesh Nagabhushana 
308056b2bdd1SGireesh Nagabhushana 	if (enable != 0) {
308156b2bdd1SGireesh Nagabhushana 		if (isset(&sc->offload_map, pi->port_id) != 0)
308256b2bdd1SGireesh Nagabhushana 			return (0);
308356b2bdd1SGireesh Nagabhushana 
308456b2bdd1SGireesh Nagabhushana 		if (sc->offload_map == 0) {
308556b2bdd1SGireesh Nagabhushana 			rc = activate_uld(sc, ULD_TOM, &sc->tom);
308656b2bdd1SGireesh Nagabhushana 			if (rc != 0)
308756b2bdd1SGireesh Nagabhushana 				return (rc);
308856b2bdd1SGireesh Nagabhushana 		}
308956b2bdd1SGireesh Nagabhushana 
309056b2bdd1SGireesh Nagabhushana 		setbit(&sc->offload_map, pi->port_id);
309156b2bdd1SGireesh Nagabhushana 	} else {
309256b2bdd1SGireesh Nagabhushana 		if (!isset(&sc->offload_map, pi->port_id))
309356b2bdd1SGireesh Nagabhushana 			return (0);
309456b2bdd1SGireesh Nagabhushana 
309556b2bdd1SGireesh Nagabhushana 		clrbit(&sc->offload_map, pi->port_id);
309656b2bdd1SGireesh Nagabhushana 
309756b2bdd1SGireesh Nagabhushana 		if (sc->offload_map == 0) {
309856b2bdd1SGireesh Nagabhushana 			rc = deactivate_uld(&sc->tom);
309956b2bdd1SGireesh Nagabhushana 			if (rc != 0) {
310056b2bdd1SGireesh Nagabhushana 				setbit(&sc->offload_map, pi->port_id);
310156b2bdd1SGireesh Nagabhushana 				return (rc);
310256b2bdd1SGireesh Nagabhushana 			}
310356b2bdd1SGireesh Nagabhushana 		}
310456b2bdd1SGireesh Nagabhushana 	}
310556b2bdd1SGireesh Nagabhushana 
310656b2bdd1SGireesh Nagabhushana 	return (0);
310756b2bdd1SGireesh Nagabhushana }
310856b2bdd1SGireesh Nagabhushana 
310956b2bdd1SGireesh Nagabhushana /*
311056b2bdd1SGireesh Nagabhushana  * Add an upper layer driver to the global list.
311156b2bdd1SGireesh Nagabhushana  */
311256b2bdd1SGireesh Nagabhushana int
311356b2bdd1SGireesh Nagabhushana t4_register_uld(struct uld_info *ui)
311456b2bdd1SGireesh Nagabhushana {
311556b2bdd1SGireesh Nagabhushana 	int rc = 0;
311656b2bdd1SGireesh Nagabhushana 	struct uld_info *u;
311756b2bdd1SGireesh Nagabhushana 
311856b2bdd1SGireesh Nagabhushana 	mutex_enter(&t4_uld_list_lock);
311956b2bdd1SGireesh Nagabhushana 	SLIST_FOREACH(u, &t4_uld_list, link) {
312056b2bdd1SGireesh Nagabhushana 		if (u->uld_id == ui->uld_id) {
312156b2bdd1SGireesh Nagabhushana 			rc = EEXIST;
312256b2bdd1SGireesh Nagabhushana 			goto done;
312356b2bdd1SGireesh Nagabhushana 		}
312456b2bdd1SGireesh Nagabhushana 	}
312556b2bdd1SGireesh Nagabhushana 
312656b2bdd1SGireesh Nagabhushana 	SLIST_INSERT_HEAD(&t4_uld_list, ui, link);
312756b2bdd1SGireesh Nagabhushana 	ui->refcount = 0;
312856b2bdd1SGireesh Nagabhushana done:
312956b2bdd1SGireesh Nagabhushana 	mutex_exit(&t4_uld_list_lock);
313056b2bdd1SGireesh Nagabhushana 	return (rc);
313156b2bdd1SGireesh Nagabhushana }
313256b2bdd1SGireesh Nagabhushana 
313356b2bdd1SGireesh Nagabhushana int
313456b2bdd1SGireesh Nagabhushana t4_unregister_uld(struct uld_info *ui)
313556b2bdd1SGireesh Nagabhushana {
313656b2bdd1SGireesh Nagabhushana 	int rc = EINVAL;
313756b2bdd1SGireesh Nagabhushana 	struct uld_info *u;
313856b2bdd1SGireesh Nagabhushana 
313956b2bdd1SGireesh Nagabhushana 	mutex_enter(&t4_uld_list_lock);
314056b2bdd1SGireesh Nagabhushana 
314156b2bdd1SGireesh Nagabhushana 	SLIST_FOREACH(u, &t4_uld_list, link) {
314256b2bdd1SGireesh Nagabhushana 		if (u == ui) {
314356b2bdd1SGireesh Nagabhushana 			if (ui->refcount > 0) {
314456b2bdd1SGireesh Nagabhushana 				rc = EBUSY;
314556b2bdd1SGireesh Nagabhushana 				goto done;
314656b2bdd1SGireesh Nagabhushana 			}
314756b2bdd1SGireesh Nagabhushana 
314856b2bdd1SGireesh Nagabhushana 			SLIST_REMOVE(&t4_uld_list, ui, uld_info, link);
314956b2bdd1SGireesh Nagabhushana 			rc = 0;
315056b2bdd1SGireesh Nagabhushana 			goto done;
315156b2bdd1SGireesh Nagabhushana 		}
315256b2bdd1SGireesh Nagabhushana 	}
315356b2bdd1SGireesh Nagabhushana done:
315456b2bdd1SGireesh Nagabhushana 	mutex_exit(&t4_uld_list_lock);
315556b2bdd1SGireesh Nagabhushana 	return (rc);
315656b2bdd1SGireesh Nagabhushana }
315756b2bdd1SGireesh Nagabhushana 
315856b2bdd1SGireesh Nagabhushana static int
315956b2bdd1SGireesh Nagabhushana activate_uld(struct adapter *sc, int id, struct uld_softc *usc)
316056b2bdd1SGireesh Nagabhushana {
316156b2bdd1SGireesh Nagabhushana 	int rc = EAGAIN;
316256b2bdd1SGireesh Nagabhushana 	struct uld_info *ui;
316356b2bdd1SGireesh Nagabhushana 
316456b2bdd1SGireesh Nagabhushana 	mutex_enter(&t4_uld_list_lock);
316556b2bdd1SGireesh Nagabhushana 
316656b2bdd1SGireesh Nagabhushana 	SLIST_FOREACH(ui, &t4_uld_list, link) {
316756b2bdd1SGireesh Nagabhushana 		if (ui->uld_id == id) {
316856b2bdd1SGireesh Nagabhushana 			rc = ui->attach(sc, &usc->softc);
316956b2bdd1SGireesh Nagabhushana 			if (rc == 0) {
317056b2bdd1SGireesh Nagabhushana 				ASSERT(usc->softc != NULL);
317156b2bdd1SGireesh Nagabhushana 				ui->refcount++;
317256b2bdd1SGireesh Nagabhushana 				usc->uld = ui;
317356b2bdd1SGireesh Nagabhushana 			}
317456b2bdd1SGireesh Nagabhushana 			goto done;
317556b2bdd1SGireesh Nagabhushana 		}
317656b2bdd1SGireesh Nagabhushana 	}
317756b2bdd1SGireesh Nagabhushana done:
317856b2bdd1SGireesh Nagabhushana 	mutex_exit(&t4_uld_list_lock);
317956b2bdd1SGireesh Nagabhushana 
318056b2bdd1SGireesh Nagabhushana 	return (rc);
318156b2bdd1SGireesh Nagabhushana }
318256b2bdd1SGireesh Nagabhushana 
318356b2bdd1SGireesh Nagabhushana static int
318456b2bdd1SGireesh Nagabhushana deactivate_uld(struct uld_softc *usc)
318556b2bdd1SGireesh Nagabhushana {
318656b2bdd1SGireesh Nagabhushana 	int rc;
318756b2bdd1SGireesh Nagabhushana 
318856b2bdd1SGireesh Nagabhushana 	mutex_enter(&t4_uld_list_lock);
318956b2bdd1SGireesh Nagabhushana 
319056b2bdd1SGireesh Nagabhushana 	if (usc->uld == NULL || usc->softc == NULL) {
319156b2bdd1SGireesh Nagabhushana 		rc = EINVAL;
319256b2bdd1SGireesh Nagabhushana 		goto done;
319356b2bdd1SGireesh Nagabhushana 	}
319456b2bdd1SGireesh Nagabhushana 
319556b2bdd1SGireesh Nagabhushana 	rc = usc->uld->detach(usc->softc);
319656b2bdd1SGireesh Nagabhushana 	if (rc == 0) {
319756b2bdd1SGireesh Nagabhushana 		ASSERT(usc->uld->refcount > 0);
319856b2bdd1SGireesh Nagabhushana 		usc->uld->refcount--;
319956b2bdd1SGireesh Nagabhushana 		usc->uld = NULL;
320056b2bdd1SGireesh Nagabhushana 		usc->softc = NULL;
320156b2bdd1SGireesh Nagabhushana 	}
320256b2bdd1SGireesh Nagabhushana done:
320356b2bdd1SGireesh Nagabhushana 	mutex_exit(&t4_uld_list_lock);
320456b2bdd1SGireesh Nagabhushana 
320556b2bdd1SGireesh Nagabhushana 	return (rc);
320656b2bdd1SGireesh Nagabhushana }
320756b2bdd1SGireesh Nagabhushana 
320856b2bdd1SGireesh Nagabhushana void
320956b2bdd1SGireesh Nagabhushana t4_iterate(void (*func)(int, void *), void *arg)
321056b2bdd1SGireesh Nagabhushana {
321156b2bdd1SGireesh Nagabhushana 	struct adapter *sc;
321256b2bdd1SGireesh Nagabhushana 
321356b2bdd1SGireesh Nagabhushana 	mutex_enter(&t4_adapter_list_lock);
321456b2bdd1SGireesh Nagabhushana 	SLIST_FOREACH(sc, &t4_adapter_list, link) {
321556b2bdd1SGireesh Nagabhushana 		/*
321656b2bdd1SGireesh Nagabhushana 		 * func should not make any assumptions about what state sc is
321756b2bdd1SGireesh Nagabhushana 		 * in - the only guarantee is that sc->sc_lock is a valid lock.
321856b2bdd1SGireesh Nagabhushana 		 */
321956b2bdd1SGireesh Nagabhushana 		func(ddi_get_instance(sc->dip), arg);
322056b2bdd1SGireesh Nagabhushana 	}
322156b2bdd1SGireesh Nagabhushana 	mutex_exit(&t4_adapter_list_lock);
322256b2bdd1SGireesh Nagabhushana }
322356b2bdd1SGireesh Nagabhushana 
322456b2bdd1SGireesh Nagabhushana #endif
322573439c83SRobert Mustacchi 
322673439c83SRobert Mustacchi static int
322773439c83SRobert Mustacchi t4_sensor_read(struct adapter *sc, uint32_t diag, uint32_t *valp)
322873439c83SRobert Mustacchi {
322973439c83SRobert Mustacchi 	int rc;
323073439c83SRobert Mustacchi 	struct port_info *pi = sc->port[0];
323173439c83SRobert Mustacchi 	uint32_t param, val;
323273439c83SRobert Mustacchi 
323373439c83SRobert Mustacchi 	rc = begin_synchronized_op(pi, 1, 1);
323473439c83SRobert Mustacchi 	if (rc != 0) {
323573439c83SRobert Mustacchi 		return (rc);
323673439c83SRobert Mustacchi 	}
323773439c83SRobert Mustacchi 	param = V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) |
323873439c83SRobert Mustacchi 	    V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_DIAG) |
323973439c83SRobert Mustacchi 	    V_FW_PARAMS_PARAM_Y(diag);
324073439c83SRobert Mustacchi 	rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 1, &param, &val);
324173439c83SRobert Mustacchi 	end_synchronized_op(pi, 1);
324273439c83SRobert Mustacchi 
324373439c83SRobert Mustacchi 	if (rc != 0) {
324473439c83SRobert Mustacchi 		return (rc);
324573439c83SRobert Mustacchi 	}
324673439c83SRobert Mustacchi 
324773439c83SRobert Mustacchi 	if (val == 0) {
324873439c83SRobert Mustacchi 		return (EIO);
324973439c83SRobert Mustacchi 	}
325073439c83SRobert Mustacchi 
325173439c83SRobert Mustacchi 	*valp = val;
325273439c83SRobert Mustacchi 	return (0);
325373439c83SRobert Mustacchi }
325473439c83SRobert Mustacchi 
325573439c83SRobert Mustacchi static int
325673439c83SRobert Mustacchi t4_temperature_read(void *arg, sensor_ioctl_scalar_t *scalar)
325773439c83SRobert Mustacchi {
325873439c83SRobert Mustacchi 	int ret;
325973439c83SRobert Mustacchi 	struct adapter *sc = arg;
326073439c83SRobert Mustacchi 	uint32_t val;
326173439c83SRobert Mustacchi 
326273439c83SRobert Mustacchi 	ret = t4_sensor_read(sc, FW_PARAM_DEV_DIAG_TMP, &val);
326373439c83SRobert Mustacchi 	if (ret != 0) {
326473439c83SRobert Mustacchi 		return (ret);
326573439c83SRobert Mustacchi 	}
326673439c83SRobert Mustacchi 
326773439c83SRobert Mustacchi 	/*
326873439c83SRobert Mustacchi 	 * The device measures temperature in units of 1 degree Celsius. We
326973439c83SRobert Mustacchi 	 * don't know its precision.
327073439c83SRobert Mustacchi 	 */
327173439c83SRobert Mustacchi 	scalar->sis_unit = SENSOR_UNIT_CELSIUS;
327273439c83SRobert Mustacchi 	scalar->sis_gran = 1;
327373439c83SRobert Mustacchi 	scalar->sis_prec = 0;
327473439c83SRobert Mustacchi 	scalar->sis_value = val;
327573439c83SRobert Mustacchi 
327673439c83SRobert Mustacchi 	return (0);
327773439c83SRobert Mustacchi }
327873439c83SRobert Mustacchi 
327973439c83SRobert Mustacchi static int
328073439c83SRobert Mustacchi t4_voltage_read(void *arg, sensor_ioctl_scalar_t *scalar)
328173439c83SRobert Mustacchi {
328273439c83SRobert Mustacchi 	int ret;
328373439c83SRobert Mustacchi 	struct adapter *sc = arg;
328473439c83SRobert Mustacchi 	uint32_t val;
328573439c83SRobert Mustacchi 
328673439c83SRobert Mustacchi 	ret = t4_sensor_read(sc, FW_PARAM_DEV_DIAG_VDD, &val);
328773439c83SRobert Mustacchi 	if (ret != 0) {
328873439c83SRobert Mustacchi 		return (ret);
328973439c83SRobert Mustacchi 	}
329073439c83SRobert Mustacchi 
329173439c83SRobert Mustacchi 	scalar->sis_unit = SENSOR_UNIT_VOLTS;
329273439c83SRobert Mustacchi 	scalar->sis_gran = 1000;
329373439c83SRobert Mustacchi 	scalar->sis_prec = 0;
329473439c83SRobert Mustacchi 	scalar->sis_value = val;
329573439c83SRobert Mustacchi 
329673439c83SRobert Mustacchi 	return (0);
329773439c83SRobert Mustacchi }
32982e7b048cSRobert Mustacchi 
32992e7b048cSRobert Mustacchi /*
33002e7b048cSRobert Mustacchi  * While the hardware supports the ability to read and write the flash image,
33012e7b048cSRobert Mustacchi  * this is not currently wired up.
33022e7b048cSRobert Mustacchi  */
33032e7b048cSRobert Mustacchi static int
33042e7b048cSRobert Mustacchi t4_ufm_getcaps(ddi_ufm_handle_t *ufmh, void *arg, ddi_ufm_cap_t *caps)
33052e7b048cSRobert Mustacchi {
33062e7b048cSRobert Mustacchi 	*caps = DDI_UFM_CAP_REPORT;
33072e7b048cSRobert Mustacchi 	return (0);
33082e7b048cSRobert Mustacchi }
33092e7b048cSRobert Mustacchi 
33102e7b048cSRobert Mustacchi static int
33112e7b048cSRobert Mustacchi t4_ufm_fill_image(ddi_ufm_handle_t *ufmh, void *arg, uint_t imgno,
33122e7b048cSRobert Mustacchi     ddi_ufm_image_t *imgp)
33132e7b048cSRobert Mustacchi {
33142e7b048cSRobert Mustacchi 	if (imgno != 0) {
33152e7b048cSRobert Mustacchi 		return (EINVAL);
33162e7b048cSRobert Mustacchi 	}
33172e7b048cSRobert Mustacchi 
33182e7b048cSRobert Mustacchi 	ddi_ufm_image_set_desc(imgp, "Firmware");
33192e7b048cSRobert Mustacchi 	ddi_ufm_image_set_nslots(imgp, 1);
33202e7b048cSRobert Mustacchi 
33212e7b048cSRobert Mustacchi 	return (0);
33222e7b048cSRobert Mustacchi }
33232e7b048cSRobert Mustacchi 
33242e7b048cSRobert Mustacchi static int
33252e7b048cSRobert Mustacchi t4_ufm_fill_slot_version(nvlist_t *nvl, const char *key, uint32_t vers)
33262e7b048cSRobert Mustacchi {
33272e7b048cSRobert Mustacchi 	char buf[128];
33282e7b048cSRobert Mustacchi 
33292e7b048cSRobert Mustacchi 	if (vers == 0) {
33302e7b048cSRobert Mustacchi 		return (0);
33312e7b048cSRobert Mustacchi 	}
33322e7b048cSRobert Mustacchi 
33332e7b048cSRobert Mustacchi 	if (snprintf(buf, sizeof (buf), "%u.%u.%u.%u",
33342e7b048cSRobert Mustacchi 	    G_FW_HDR_FW_VER_MAJOR(vers), G_FW_HDR_FW_VER_MINOR(vers),
33352e7b048cSRobert Mustacchi 	    G_FW_HDR_FW_VER_MICRO(vers), G_FW_HDR_FW_VER_BUILD(vers)) >=
33362e7b048cSRobert Mustacchi 	    sizeof (buf)) {
33372e7b048cSRobert Mustacchi 		return (EOVERFLOW);
33382e7b048cSRobert Mustacchi 	}
33392e7b048cSRobert Mustacchi 
33402e7b048cSRobert Mustacchi 	return (nvlist_add_string(nvl, key, buf));
33412e7b048cSRobert Mustacchi }
33422e7b048cSRobert Mustacchi 
33432e7b048cSRobert Mustacchi static int
33442e7b048cSRobert Mustacchi t4_ufm_fill_slot(ddi_ufm_handle_t *ufmh, void *arg, uint_t imgno, uint_t slotno,
33452e7b048cSRobert Mustacchi     ddi_ufm_slot_t *slotp)
33462e7b048cSRobert Mustacchi {
33472e7b048cSRobert Mustacchi 	int ret;
33482e7b048cSRobert Mustacchi 	struct adapter *sc = arg;
33492e7b048cSRobert Mustacchi 	nvlist_t *misc = NULL;
33502e7b048cSRobert Mustacchi 	char buf[128];
33512e7b048cSRobert Mustacchi 
33522e7b048cSRobert Mustacchi 	if (imgno != 0 || slotno != 0) {
33532e7b048cSRobert Mustacchi 		return (EINVAL);
33542e7b048cSRobert Mustacchi 	}
33552e7b048cSRobert Mustacchi 
33562e7b048cSRobert Mustacchi 	if (snprintf(buf, sizeof (buf), "%u.%u.%u.%u",
33572e7b048cSRobert Mustacchi 	    G_FW_HDR_FW_VER_MAJOR(sc->params.fw_vers),
33582e7b048cSRobert Mustacchi 	    G_FW_HDR_FW_VER_MINOR(sc->params.fw_vers),
33592e7b048cSRobert Mustacchi 	    G_FW_HDR_FW_VER_MICRO(sc->params.fw_vers),
33602e7b048cSRobert Mustacchi 	    G_FW_HDR_FW_VER_BUILD(sc->params.fw_vers)) >= sizeof (buf)) {
33612e7b048cSRobert Mustacchi 		return (EOVERFLOW);
33622e7b048cSRobert Mustacchi 	}
33632e7b048cSRobert Mustacchi 
33642e7b048cSRobert Mustacchi 	ddi_ufm_slot_set_version(slotp, buf);
33652e7b048cSRobert Mustacchi 
33662e7b048cSRobert Mustacchi 	(void) nvlist_alloc(&misc, NV_UNIQUE_NAME, KM_SLEEP);
33672e7b048cSRobert Mustacchi 	if ((ret = t4_ufm_fill_slot_version(misc, "TP Microcode",
33682e7b048cSRobert Mustacchi 	    sc->params.tp_vers)) != 0) {
33692e7b048cSRobert Mustacchi 		goto err;
33702e7b048cSRobert Mustacchi 	}
33712e7b048cSRobert Mustacchi 
33722e7b048cSRobert Mustacchi 	if ((ret = t4_ufm_fill_slot_version(misc, "Bootstrap",
33732e7b048cSRobert Mustacchi 	    sc->params.bs_vers)) != 0) {
33742e7b048cSRobert Mustacchi 		goto err;
33752e7b048cSRobert Mustacchi 	}
33762e7b048cSRobert Mustacchi 
33772e7b048cSRobert Mustacchi 	if ((ret = t4_ufm_fill_slot_version(misc, "Expansion ROM",
33782e7b048cSRobert Mustacchi 	    sc->params.er_vers)) != 0) {
33792e7b048cSRobert Mustacchi 		goto err;
33802e7b048cSRobert Mustacchi 	}
33812e7b048cSRobert Mustacchi 
33822e7b048cSRobert Mustacchi 	if ((ret = nvlist_add_uint32(misc, "Serial Configuration",
33832e7b048cSRobert Mustacchi 	    sc->params.scfg_vers)) != 0) {
33842e7b048cSRobert Mustacchi 		goto err;
33852e7b048cSRobert Mustacchi 	}
33862e7b048cSRobert Mustacchi 
33872e7b048cSRobert Mustacchi 	if ((ret = nvlist_add_uint32(misc, "VPD Version",
33882e7b048cSRobert Mustacchi 	    sc->params.vpd_vers)) != 0) {
33892e7b048cSRobert Mustacchi 		goto err;
33902e7b048cSRobert Mustacchi 	}
33912e7b048cSRobert Mustacchi 
33922e7b048cSRobert Mustacchi 	ddi_ufm_slot_set_misc(slotp, misc);
33932e7b048cSRobert Mustacchi 	ddi_ufm_slot_set_attrs(slotp, DDI_UFM_ATTR_ACTIVE |
33942e7b048cSRobert Mustacchi 	    DDI_UFM_ATTR_WRITEABLE | DDI_UFM_ATTR_READABLE);
33952e7b048cSRobert Mustacchi 	return (0);
33962e7b048cSRobert Mustacchi 
33972e7b048cSRobert Mustacchi err:
33982e7b048cSRobert Mustacchi 	nvlist_free(misc);
33992e7b048cSRobert Mustacchi 	return (ret);
34002e7b048cSRobert Mustacchi 
34012e7b048cSRobert Mustacchi }
3402